diff --git a/.github/workflows/weave-node-tests.yaml b/.github/workflows/weave-node-tests.yaml new file mode 100644 index 00000000000..ad401503879 --- /dev/null +++ b/.github/workflows/weave-node-tests.yaml @@ -0,0 +1,32 @@ +name: Node.js Tests + +on: + push: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20] + steps: + - uses: actions/checkout@v4 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + run_install: false + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'pnpm' + cache-dependency-path: sdks/node/pnpm-lock.yaml + - name: Install dependencies + run: pnpm install + working-directory: sdks/node + - name: Run tests + run: pnpm test + working-directory: sdks/node + env: + WANDB_API_KEY: ${{ secrets.WANDB_API_KEY }} diff --git a/sdks/node/.gitignore b/sdks/node/.gitignore new file mode 100644 index 00000000000..3091757a3b2 --- /dev/null +++ b/sdks/node/.gitignore @@ -0,0 +1,2 @@ +node_modules +coverage \ No newline at end of file diff --git a/sdks/node/.prettierrc b/sdks/node/.prettierrc new file mode 100644 index 00000000000..38e0c860df1 --- /dev/null +++ b/sdks/node/.prettierrc @@ -0,0 +1,16 @@ +{ + "trailingComma": "es5", + "singleQuote": true, + "bracketSpacing": false, + "bracketSameLine": true, + "tabWidth": 2, + "arrowParens": "avoid", + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "options": { + "parser": "typescript" + } + } + ] +} diff --git a/sdks/node/CantinaBand3.wav b/sdks/node/CantinaBand3.wav new file mode 100644 index 00000000000..41f02043846 Binary files /dev/null and b/sdks/node/CantinaBand3.wav differ diff --git a/sdks/node/Makefile b/sdks/node/Makefile new file mode 100644 index 00000000000..a2ab6172b5c --- /dev/null +++ b/sdks/node/Makefile @@ -0,0 +1,7 @@ +install-pnpm: + curl -fsSL https://get.pnpm.io/install.sh | sh - + +bootstrap: install-pnpm + pnpm env use --global 20 + pnpm install + pnpm run generate-api diff --git a/sdks/node/README-DEV.md b/sdks/node/README-DEV.md new file mode 100644 index 00000000000..0a044dc483e --- /dev/null +++ b/sdks/node/README-DEV.md @@ -0,0 +1,23 @@ +# Working notes + +1. Setup your env + + ```sh + make boostrap + + pnpm install + pnpm link --global + pnpm link --global weave + ``` + +2. Run tests + + ```sh + pnpm test + ``` + +3. Format + + ```sh + pnpm format + ``` diff --git a/sdks/node/README.md b/sdks/node/README.md new file mode 100644 index 00000000000..c23dc752cd5 --- /dev/null +++ b/sdks/node/README.md @@ -0,0 +1,202 @@ +# Weave (Alpha) + +Weave is a library for tracing and monitoring AI applications. + +This is an Alpha release, APIs are extremely subject to change. + +## Installation + +You can install Weave via npm: + +```bash +npm install weave +``` + +Ensure you have a wandb API key in ~/.netrc. + +Like + +``` +machine api.wandb.ai + login user + password +``` + +Get your wandb API key from [here](https://wandb.ai/authorize). + +## Quickstart + +Put this in a file called `predict.mjs`: + +```javascript +import { OpenAI } from "openai"; +import { init, op, wrapOpenAI } from "weave"; + +const openai = wrapOpenAI(new OpenAI()); + +async function extractDinos(input) { + const response = await openai.chat.completions.create({ + model: "gpt-4o", + messages: [ + { + role: "user", + content: `In JSON format extract a list of 'dinosaurs', with their 'name', their 'common_name', and whether its 'diet' is a herbivore or carnivore: ${input}`, + }, + ], + }); + return response.choices[0].message.content; +} +const extractDinosOp = op(extractDinos); + +async function main() { + await init("weave-quickstart"); + const result = await extractDinosOp( + "I watched as a Tyrannosaurus rex (T. rex) chased after a Triceratops (Trike), both carnivore and herbivore locked in an ancient dance. Meanwhile, a gentle giant Brachiosaurus (Brachi) calmly munched on treetops, blissfully unaware of the chaos below." + ); + console.log(result); +} + +main(); +``` + +and then run + +``` +node predict.mjs +``` + +## Usage + +### Initializing a Project + +Before you can start tracing operations, you need to initialize a project. This sets up the necessary environment for trace collection. + +```javascript +import { init } from "weave"; + +// Initialize your project with a unique project name +init("my-awesome-ai-project"); +``` + +### Tracing Operations + +You can trace specific operations using the `op` function. This function wraps your existing functions and tracks their execution. + +```javascript +import { op } from "weave"; + +// Define a function you want to trace +async function myFunction(arg1, arg2) { + // Your function logic + return arg1 + arg2; +} + +// Wrap the function with op to enable tracing +const tracedFunction = op(myFunction, "myFunction"); + +// Call the traced function +tracedFunction(5, 10); +``` + +### OpenAI Integration + +Weave provides an integration with OpenAI, allowing you to trace API calls made to OpenAI's services seamlessly. + +```javascript +import { wrapOpenAI } from "weave/integrations/openai"; + +// Create a patched instance of OpenAI +const openai = wrapOpenAI(); + +// Use the OpenAI instance as usual +openai.chat.completions.create({ + model: "text-davinci-003", + prompt: 'Translate the following English text to French: "Hello, world!"', + max_tokens: 60, +}); + +// Weave tracks images too! +openai.images.generate({ + prompt: "A cute baby sea otter", + n: 3, + size: "256x256", + response_format: "b64_json", +}); +``` + +### Evaluations + +```typescript +import { init, op, Dataset, Evaluation } from "weave"; + +async function main() { + await init("weavejsdev-eval6"); + const ds = new Dataset({ + id: "My Dataset", + description: "This is a dataset", + rows: [ + { name: "Alice", age: 25 }, + { name: "Bob", age: 30 }, + { name: "Charlie", age: 34 }, + ], + }); + const evaluation = new Evaluation({ + dataset: ds, + scorers: [ + op( + (modelOutput: any, datasetItem: any) => modelOutput == datasetItem.age, + { name: "isEqual" } + ), + ], + }); + + const model = op(async function myModel(input) { + return input.age; + }); + + const results = await evaluation.evaluate({ model }); + console.log(JSON.stringify(results, null, 2)); +} + +main(); +``` + +## Configuration + +Weave reads API keys from the `.netrc` file located in your home directory. Ensure you have the required API keys configured for seamless integration and tracking. + +``` +machine api.wandb.ai + login user + password +``` + +Get your wandb API key from [here](https://wandb.ai/authorize). + +## License + +This project is licensed under the Apaache2 License - see the [LICENSE](../LICENSE) file for details. + +### Roadmap / TODO + +- [x] Return token counts +- [x] Summary merging +- [x] Image support +- [x] Decide how to handle args in js, since they're not named +- [x] Make sure LLM streaming is handled +- [x] Op versioning / code capture +- [ ] Retry logic +- [ ] Handle other wandb backends (managed / self-hosted) +- [ ] Include system information in call attributes including package version. +- [x] Objects / Datasets / Models / Evaluations +- [ ] Ref tracking +- [ ] More integrations + +## Known Issues + +- [ ] openai choices > 1 and "tools" not handled (function works though) +- [ ] we always inject params.stream_options.include_usage in openai request, need to not send back usage chunk if user didn't ask for it. +- [ ] handle all openai.images.generate formats, and images in inputs. +- [ ] openai.images.generate token counts. +- [ ] if a streaming op with streamReducer returns its iterator instead of iterating within the op, summary rollups won't work. +- [ ] Decide what's in public interface (WeaveClient) diff --git a/sdks/node/examples/classesWithOps.ts b/sdks/node/examples/classesWithOps.ts new file mode 100644 index 00000000000..c0a1ee0e6b5 --- /dev/null +++ b/sdks/node/examples/classesWithOps.ts @@ -0,0 +1,28 @@ +import OpenAI from 'openai'; +import * as weave from 'weave'; + +class ExampleModel { + private oaiClient: OpenAI; + + constructor() { + this.oaiClient = weave.wrapOpenAI(new OpenAI()); + this.invoke = weave.op(this, this.invoke); + } + + async invoke(input: string) { + const response = await this.oaiClient.chat.completions.create({ + model: 'gpt-4o', + messages: [{role: 'user', content: input}], + }); + return response.choices[0].message.content; + } +} + +async function main() { + await weave.init('examples'); + + const model = new ExampleModel(); + await model.invoke('Tell me a joke'); +} + +main(); diff --git a/sdks/node/examples/createDataset.ts b/sdks/node/examples/createDataset.ts new file mode 100644 index 00000000000..e7033c7d800 --- /dev/null +++ b/sdks/node/examples/createDataset.ts @@ -0,0 +1,53 @@ +import fs from 'fs'; +import 'source-map-support/register'; +import * as weave from 'weave'; + +const sentences = [ + 'There are many fruits that were found on the recently discovered planet Goocrux. There are neoskizzles that grow there, which are purple and taste like candy.', + 'Pounits are a bright green color and are more savory than sweet.', + 'Finally, there are fruits called glowls, which have a very sour and bitter taste which is acidic and caustic, and a pale orange tinge to them.', +]; +const labels = [ + {fruit: 'neoskizzles', color: 'purple', flavor: 'candy'}, + {fruit: 'pounits', color: 'bright green', flavor: 'savory'}, + {fruit: 'glowls', color: 'pale orange', flavor: 'sour and bitter'}, +]; +const logsPng = fs.readFileSync('logs.png'); +const audioClip = fs.readFileSync('CantinaBand3.wav'); +const examples = [ + { + id: '0', + sentence: sentences[0], + target: labels[0], + image: weave.weaveImage({data: logsPng, imageType: 'png'}), + audio: weave.weaveAudio({data: audioClip, audioType: 'wav'}), + }, + { + id: '1', + sentence: sentences[1], + target: labels[1], + image: weave.weaveImage({data: logsPng, imageType: 'png'}), + audio: weave.weaveAudio({data: audioClip, audioType: 'wav'}), + }, + { + id: '2', + sentence: sentences[2], + target: labels[2], + image: weave.weaveImage({data: logsPng, imageType: 'png'}), + audio: weave.weaveAudio({data: audioClip, audioType: 'wav'}), + }, +]; + +async function main() { + await weave.init('examples'); + const ds = new weave.Dataset({ + id: 'Fruit Dataset', + rows: examples, + }); + + ds.save(); + const ref = await ds.__savedRef; + console.log(ref); +} + +main(); diff --git a/sdks/node/examples/evaluate.ts b/sdks/node/examples/evaluate.ts new file mode 100644 index 00000000000..da88e506e57 --- /dev/null +++ b/sdks/node/examples/evaluate.ts @@ -0,0 +1,33 @@ +import 'source-map-support/register'; +import * as weave from 'weave'; + +async function main() { + await weave.init('examples'); + + const ds = new weave.Dataset({ + id: 'My Dataset', + description: 'This is a dataset', + rows: [ + {name: 'Alice', age: 25}, + {name: 'Bob', age: 30}, + {name: 'Charlie', age: 34}, + ], + }); + const evaluation = new weave.Evaluation({ + dataset: ds, + scorers: [ + weave.op(({modelOutput, datasetItem}) => modelOutput == datasetItem.age, { + name: 'isEqual', + }), + ], + }); + + const model = weave.op(async function myModel({datasetRow}) { + return datasetRow.age >= 30; + }); + + const results = await evaluation.evaluate({model}); + console.log('Evaluation results:', JSON.stringify(results, null, 2)); +} + +main(); diff --git a/sdks/node/examples/evaluateWithColumnMapping.ts b/sdks/node/examples/evaluateWithColumnMapping.ts new file mode 100644 index 00000000000..44b7f1bf14e --- /dev/null +++ b/sdks/node/examples/evaluateWithColumnMapping.ts @@ -0,0 +1,39 @@ +import 'source-map-support/register'; +import * as weave from 'weave'; + +async function main() { + await weave.init('examples'); + + const ds = new weave.Dataset({ + id: 'My Dataset', + description: 'This is a dataset', + rows: [ + {firstName: 'Alice', yearsOld: 25}, + {firstName: 'Bob', yearsOld: 30}, + {firstName: 'Charlie', yearsOld: 34}, + ], + }); + const evaluation = new weave.Evaluation({ + dataset: ds, + scorers: [ + weave.op(({modelOutput, datasetItem}) => modelOutput == datasetItem.age, { + name: 'isEqual', + }), + ], + // Specify a column mapping to map the model inputs to dataset columns. + // The order is always "model input": "dataset column". + columnMapping: { + name: 'firstName', + age: 'yearsOld', + }, + }); + + const model = weave.op(async function myModel({datasetRow}) { + return datasetRow.age >= 30; + }); + + const results = await evaluation.evaluate({model}); + console.log('Evaluation results:', JSON.stringify(results, null, 2)); +} + +main(); diff --git a/sdks/node/examples/evaluateWithImages.ts b/sdks/node/examples/evaluateWithImages.ts new file mode 100644 index 00000000000..dd12f0afffd --- /dev/null +++ b/sdks/node/examples/evaluateWithImages.ts @@ -0,0 +1,71 @@ +import {OpenAI} from 'openai'; +import 'source-map-support/register'; +import * as weave from 'weave'; + +const sentences = [ + 'There are many fruits that were found on the recently discovered planet Goocrux. There are neoskizzles that grow there, which are purple and taste like candy.', + 'Pounits are a bright green color and are more savory than sweet.', + 'Finally, there are fruits called glowls, which have a very sour and bitter taste which is acidic and caustic, and a pale orange tinge to them.', + 'There are many fruits that were found on the recently discovered planet Goocrux. There are neoskizzles that grow there, which are purple and taste like candy.', +]; +const labels = [ + {fruit: 'neoskizzles', color: 'purple', flavor: 'candy'}, + {fruit: 'pounits', color: 'bright green', flavor: 'savory'}, + {fruit: 'glowls', color: 'pale orange', flavor: 'sour and bitter'}, +]; +const examples = [ + {id: '0', sentence: sentences[0], target: labels[0]}, + {id: '1', sentence: sentences[1], target: labels[1]}, + {id: '2', sentence: sentences[2], target: labels[2]}, +]; + +const openaiClient = weave.wrapOpenAI(new OpenAI()); + +const model = weave.op(async function myModel({datasetRow}) { + const prompt = `Extract fields ("fruit": , "color": , "flavor") from the following text, as json: ${datasetRow.sentence}`; + const response = await openaiClient.chat.completions.create({ + model: 'gpt-3.5-turbo', + messages: [{role: 'user', content: prompt}], + response_format: {type: 'json_object'}, + }); + const result = response.choices[0].message.content; + if (result == null) { + throw new Error('No response from model'); + } + if (datasetRow.id == '3') { + throw new Error('This is an error'); + } + return JSON.parse(result); +}); + +async function main() { + await weave.init('examples'); + const ds = new weave.Dataset({ + id: 'Fruit Dataset', + rows: examples, + }); + const evaluation = new weave.Evaluation({ + dataset: ds, + scorers: [ + weave.op(function fruitEqual({modelOutput, datasetRow}) { + return { + correct: modelOutput.fruit == datasetRow.target.fruit, + }; + }), + weave.op(async function genImage({modelOutput, datasetRow}) { + const result = await openaiClient.images.generate({ + prompt: `A fruit that's ${modelOutput.color} and ${modelOutput.flavor}`, + n: 1, + size: '256x256', + response_format: 'b64_json', + }); + return result.data[0]; + }), + ], + }); + + const results = await evaluation.evaluate({model}); + console.log(JSON.stringify(results, null, 2)); +} + +main(); diff --git a/sdks/node/examples/imageGeneration.ts b/sdks/node/examples/imageGeneration.ts new file mode 100644 index 00000000000..b858dfaf2a5 --- /dev/null +++ b/sdks/node/examples/imageGeneration.ts @@ -0,0 +1,19 @@ +import OpenAI from 'openai'; +import * as weave from 'weave'; + +async function main() { + const client = await weave.init('examples'); + const openai = weave.wrapOpenAI(new OpenAI()); + + // Generate an image + const result = await openai.images.generate({ + prompt: 'A cute baby sea otter', + n: 3, + size: '256x256', + response_format: 'b64_json', + }); + + console.log('Generated image result:', result); +} + +main(); diff --git a/sdks/node/examples/loggingVariousDataTypes.ts b/sdks/node/examples/loggingVariousDataTypes.ts new file mode 100644 index 00000000000..391c209c5cf --- /dev/null +++ b/sdks/node/examples/loggingVariousDataTypes.ts @@ -0,0 +1,53 @@ +import fs from 'fs'; +import * as weave from 'weave'; + +const primitiveOp = weave.op(async function primitive(input: string) { + return `Hi ${input}!`; +}); + +const jsonOp = weave.op(async function json(name: string, age: number) { + return {name, age}; +}); + +const imageOp = weave.op(async function image() { + return weave.weaveImage({ + data: fs.readFileSync('logs.png'), + imageType: 'png', + }); +}); + +const audioOp = weave.op(async function audio() { + return weave.weaveAudio({ + data: fs.readFileSync('CantinaBand3.wav'), + audioType: 'wav', + }); +}); + +const datasetOp = weave.op(async function dataset() { + return new weave.Dataset({ + id: 'my-dataset', + rows: [ + {name: 'Alice', age: 10}, + {name: 'Bob', age: 20}, + {name: 'Charlie', age: 30}, + ], + }); +}); + +async function main() { + await weave.init('examples'); + + const primitivePromise = primitiveOp('world'); + const jsonPromise = jsonOp('Alice', 10); + const imagePromise = imageOp(); + const audioPromise = audioOp(); + const datasetPromise = datasetOp(); + + console.log('Primitive Result:', await primitivePromise); + console.log('JSON Result:', await jsonPromise); + console.log('Image Result:', await imagePromise); + console.log('Audio Result:', await audioPromise); + console.log('Dataset Result:', await datasetPromise); +} + +main(); diff --git a/sdks/node/examples/quickstart.ts b/sdks/node/examples/quickstart.ts new file mode 100644 index 00000000000..500efba3238 --- /dev/null +++ b/sdks/node/examples/quickstart.ts @@ -0,0 +1,28 @@ +import OpenAI from 'openai'; +import * as weave from 'weave'; + +const openai = weave.wrapOpenAI(new OpenAI()); + +async function extractDinos(input: string) { + const response = await openai.chat.completions.create({ + model: 'gpt-4o', + messages: [ + { + role: 'user', + content: `In JSON format extract a list of 'dinosaurs', with their 'name', their 'common_name', and whether its 'diet' is a herbivore or carnivore: ${input}`, + }, + ], + }); + return response.choices[0].message.content; +} +const extractDinosOp = weave.op(extractDinos); + +async function main() { + await weave.init('examples'); + const result = await extractDinosOp( + 'I watched as a Tyrannosaurus rex (T. rex) chased after a Triceratops (Trike), both carnivore and herbivore locked in an ancient dance. Meanwhile, a gentle giant Brachiosaurus (Brachi) calmly munched on treetops, blissfully unaware of the chaos below.' + ); + console.log(result); +} + +main(); diff --git a/sdks/node/examples/quickstartEvaluate.ts b/sdks/node/examples/quickstartEvaluate.ts new file mode 100644 index 00000000000..241cd29a28a --- /dev/null +++ b/sdks/node/examples/quickstartEvaluate.ts @@ -0,0 +1,67 @@ +import {OpenAI} from 'openai'; +import 'source-map-support/register'; +import * as weave from 'weave'; + +const sentences = [ + 'There are many fruits that were found on the recently discovered planet Goocrux. There are neoskizzles that grow there, which are purple and taste like candy.', + 'Pounits are a bright green color and are more savory than sweet.', + 'Finally, there are fruits called glowls, which have a very sour and bitter taste which is acidic and caustic, and a pale orange tinge to them.', +]; +const labels = [ + {fruit: 'neoskizzles', color: 'purple', flavor: 'candy'}, + {fruit: 'pounits', color: 'bright green', flavor: 'savory'}, + {fruit: 'glowls', color: 'pale orange', flavor: 'sour and bitter'}, +]; +const examples = [ + {id: '0', sentence: sentences[0], target: labels[0]}, + {id: '1', sentence: sentences[1], target: labels[1]}, + {id: '2', sentence: sentences[2], target: labels[2]}, + {id: '3', sentence: sentences[0], target: labels[0]}, + {id: '4', sentence: sentences[1], target: labels[1]}, + {id: '5', sentence: sentences[2], target: labels[2]}, + {id: '6', sentence: sentences[0], target: labels[0]}, + {id: '7', sentence: sentences[1], target: labels[1]}, + {id: '8', sentence: sentences[2], target: labels[2]}, + {id: '9', sentence: sentences[0], target: labels[0]}, + {id: '10', sentence: sentences[1], target: labels[1]}, + {id: '11', sentence: sentences[2], target: labels[2]}, +]; + +const openaiClient = weave.wrapOpenAI(new OpenAI()); + +const model = weave.op(async function myModel(input) { + const prompt = `Extract fields ("fruit": , "color": , "flavor") from the following text, as json: ${input.sentence}`; + const response = await openaiClient.chat.completions.create({ + model: 'gpt-3.5-turbo', + messages: [{role: 'user', content: prompt}], + response_format: {type: 'json_object'}, + }); + const result = response.choices[0].message.content; + if (result == null) { + throw new Error('No response from model'); + } + return JSON.parse(result); +}); + +async function main() { + await weave.init('examples'); + const ds = new weave.Dataset({ + id: 'Fruit Dataset', + rows: examples, + }); + const evaluation = new weave.Evaluation({ + dataset: ds, + scorers: [ + weave.op(function fruitEqual({modelOutput, datasetItem}) { + return { + correct: modelOutput.fruit == datasetItem.target.fruit, + }; + }), + ], + }); + + const results = await evaluation.evaluate({model}); + console.log(JSON.stringify(results, null, 2)); +} + +main(); diff --git a/sdks/node/examples/streamFunctionCalls.ts b/sdks/node/examples/streamFunctionCalls.ts new file mode 100644 index 00000000000..21efcd6d4c6 --- /dev/null +++ b/sdks/node/examples/streamFunctionCalls.ts @@ -0,0 +1,63 @@ +import OpenAI from 'openai'; +import * as weave from 'weave'; + +const openai = weave.wrapOpenAI(new OpenAI()); + +async function extractDinos(input: string) { + const functions = [ + { + name: 'get_current_weather', + description: 'Get the current weather for a given location.', + parameters: { + type: 'object', + properties: { + location: { + type: 'string', + description: 'The name of the city or location to get weather for.', + }, + }, + required: ['location'], + }, + }, + { + name: 'get_time_in_location', + description: 'Get the current time for a given location.', + parameters: { + type: 'object', + properties: { + location: { + type: 'string', + description: + 'The name of the city or location to get the current time for.', + }, + }, + required: ['location'], + }, + }, + ]; + const response = await openai.chat.completions.create({ + stream: true, + // stream_options: { "include_usage": true }, + model: 'gpt-4o', + functions: functions, + messages: [ + { + role: 'user', + content: `what is the weather and time in ${input}? Tell me what your'e going to do as you do it.`, + }, + ], + }); + console.log(JSON.stringify(response)); + for await (const chunk of response) { + console.log(JSON.stringify(chunk)); + } +} +const extractDinosOp = weave.op(extractDinos); + +async function main() { + await weave.init('examples'); + const result = await extractDinosOp('London'); + console.log(result); +} + +main(); diff --git a/sdks/node/examples/tsconfig.examples.json b/sdks/node/examples/tsconfig.examples.json new file mode 100644 index 00000000000..0dd447ac548 --- /dev/null +++ b/sdks/node/examples/tsconfig.examples.json @@ -0,0 +1,16 @@ +{ + "extends": "../tsconfig.json", + "exclude": [], + "compilerOptions": { + "rootDir": ".", + "outDir": "../dist/examples", + "paths": { + "weave": ["../dist/src"] + } + }, + "references": [ + { + "path": "../src/tsconfig.src.json" + } + ] +} diff --git a/sdks/node/logs.png b/sdks/node/logs.png new file mode 100644 index 00000000000..5fc54397386 Binary files /dev/null and b/sdks/node/logs.png differ diff --git a/sdks/node/package-lock.json b/sdks/node/package-lock.json new file mode 100644 index 00000000000..2fbfa2dd718 --- /dev/null +++ b/sdks/node/package-lock.json @@ -0,0 +1,4312 @@ +{ + "name": "weave", + "version": "0.6.9", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "weave", + "version": "0.6.9", + "license": "Apache-2.0", + "dependencies": { + "cli-progress": "^3.12.0", + "openai": "^4.57.0", + "uuidv7": "^1.0.1" + }, + "devDependencies": { + "@types/cli-progress": "^3.11.6", + "@types/jest": "^29.5.12", + "@types/node": "^22.5.1", + "jest": "^29.7.0", + "ts-jest": "^29.2.5" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz", + "integrity": "sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": 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, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.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, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "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, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/cli-progress": { + "version": "3.11.6", + "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.6.tgz", + "integrity": "sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/node": { + "version": "22.5.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.1.tgz", + "integrity": "sha512-KkHsxej0j9IW1KKOOAA/XBA0z08UFSrRQHErzEfA3Vgq57eXIMYboIlHJuYIfd+lwCQjtKqUu3UnmKbtUc9yRw==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001655", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz", + "integrity": "sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "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, + "license": "MIT", + "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/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.0.tgz", + "integrity": "sha512-N1NGmowPlGBLsOZLPvm48StN04V4YvQRL0i6b7ctrVY3epjP/ct7hFLOItz6pDIvRjwpfPxi52a2UWV2ziir8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-progress": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", + "license": "MIT", + "dependencies": { + "string-width": "^4.2.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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==", + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/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, + "license": "MIT" + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "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, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "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, + "license": "ISC" + }, + "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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "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, + "license": "ISC", + "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/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "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, + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "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, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/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, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/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, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-circus/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/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, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-runner/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "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, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.63.0.tgz", + "integrity": "sha512-Y9V4KODbmrOpqiOmCDVnPfMxMqKLOx8Hwcdn/r8mePq4yv7FSXGnxCs8/jZKO7zCB/IVPWihpJXwJNAIOEiZ2g==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.47.tgz", + "integrity": "sha512-1f7dB3BL/bpd9tnDJrrHb66Y+cVrhxSOTGorRNdHwYTUlTay3HuTDPKo9a/4vX9pMQkhYBcAbL4jQdNlhCFP9A==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/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==", + "license": "MIT" + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "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/pretty-format/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "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, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-jest": { + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", + "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "^2.1.0", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.6.3", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uuidv7": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uuidv7/-/uuidv7-1.0.1.tgz", + "integrity": "sha512-2noB909GbI352dKfASOY6VHHl59KvevZ1FF8gCAXCwDyrt2kkZhuFbczF9udqTfeejiRYEmO4wzUZ0WhVP+IUA==", + "license": "Apache-2.0", + "bin": { + "uuidv7": "cli.js" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "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, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "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, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "license": "MIT", + "optional": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/sdks/node/package.json b/sdks/node/package.json new file mode 100644 index 00000000000..48c496d1260 --- /dev/null +++ b/sdks/node/package.json @@ -0,0 +1,88 @@ +{ + "name": "weave", + "version": "0.6.9", + "description": "AI development toolkit", + "types": "dist/src/index.d.ts", + "main": "dist/src/index.js", + "type": "commonjs", + "scripts": { + "test": "jest", + "test:coverage": "jest --coverage", + "test:watch": "jest --watch", + "format": "prettier --write \"src/**/*.ts\" \"examples/**/*.ts\"", + "run": "tsx", + "generate-api": "swagger-typescript-api -p ./weave.openapi.json -o ./src/generated -n traceServerApi.ts", + "dev": "nodemon" + }, + "repository": { + "type": "git", + "url": "https://github.com/wandb/weave/js" + }, + "author": "", + "license": "Apache-2.0", + "jest": { + "testEnvironment": "node", + "transform": { + "^.+\\.tsx?$": "ts-jest" + }, + "testMatch": [ + "**/__tests__/**/*.test.ts?(x)", + "**/?(*.)+(spec|test).ts?(x)" + ], + "moduleFileExtensions": [ + "js", + "jsx", + "ts", + "tsx", + "json", + "node" + ], + "moduleNameMapper": { + "^weave$": "/src/index.ts" + }, + "collectCoverage": true, + "coveragePathIgnorePatterns": [ + "/src/generated", + "/src/utils/userAgent.ts", + "/src/inMemoryTraceServer.ts" + ], + "coverageDirectory": "coverage", + "coverageReporters": [ + "text", + "lcov" + ], + "coverageThreshold": { + "global": { + "branches": 80, + "functions": 80, + "lines": 80, + "statements": 80 + } + } + }, + "nodemonConfig": { + "watch": [ + "." + ], + "ext": "ts,json", + "exec": "tsx examples/evaluate.ts" + }, + "dependencies": { + "cli-progress": "^3.12.0", + "openai": "^4.68.4", + "uuidv7": "^1.0.1" + }, + "devDependencies": { + "@types/cli-progress": "^3.11.6", + "@types/jest": "^29.5.13", + "@types/node": "^22.5.1", + "jest": "^29.7.0", + "nyc": "^17.1.0", + "prettier": "^3.3.3", + "source-map-support": "^0.5.21", + "swagger-typescript-api": "^13.0.22", + "ts-jest": "^29.2.5", + "tsconfig-paths": "^4.2.0", + "tsx": "^4.19.1" + } +} diff --git a/sdks/node/pnpm-lock.yaml b/sdks/node/pnpm-lock.yaml new file mode 100644 index 00000000000..e55b4d16df3 --- /dev/null +++ b/sdks/node/pnpm-lock.yaml @@ -0,0 +1,3756 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + cli-progress: + specifier: ^3.12.0 + version: 3.12.0 + openai: + specifier: ^4.68.4 + version: 4.68.4 + uuidv7: + specifier: ^1.0.1 + version: 1.0.2 + devDependencies: + '@types/cli-progress': + specifier: ^3.11.6 + version: 3.11.6 + '@types/jest': + specifier: ^29.5.13 + version: 29.5.14 + '@types/node': + specifier: ^22.5.1 + version: 22.8.0 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@22.8.0) + nyc: + specifier: ^17.1.0 + version: 17.1.0 + prettier: + specifier: ^3.3.3 + version: 3.3.3 + source-map-support: + specifier: ^0.5.21 + version: 0.5.21 + swagger-typescript-api: + specifier: ^13.0.22 + version: 13.0.22 + ts-jest: + specifier: ^29.2.5 + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.0))(typescript@5.5.4) + tsconfig-paths: + specifier: ^4.2.0 + version: 4.2.0 + tsx: + specifier: ^4.19.1 + version: 4.19.1 + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.26.0': + resolution: {integrity: sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.26.0': + resolution: {integrity: sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.26.0': + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.26.0': + resolution: {integrity: sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.25.9': + resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.25.9': + resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.26.0': + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.26.0': + resolution: {integrity: sha512-aP8x5pIw3xvYr/sXT+SEUwyhrXT8rUJRZltK/qN3Db80dcKpTett8cJxHyjk+xYSVXvNnl2SfcJVjbwxpOSscA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.26.0': + resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.25.9': + resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.25.9': + resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.25.9': + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.25.9': + resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.26.0': + resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@exodus/schemasafe@1.3.0': + resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@29.7.0': + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/core@29.7.0': + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@29.7.0': + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@29.7.0': + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/reporters@29.7.0': + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/source-map@29.6.3': + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-result@29.7.0': + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-sequencer@29.7.0': + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.6': + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + + '@types/cli-progress@3.11.6': + resolution: {integrity: sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA==} + + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@29.5.14': + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + + '@types/node-fetch@2.6.11': + resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} + + '@types/node@18.19.59': + resolution: {integrity: sha512-vizm2EqwV/7Zay+A6J3tGl9Lhr7CjZe2HmWS988sefiEmsyP9CeXEleho6i4hJk/8UtZAo0bWN4QPZZr83RxvQ==} + + '@types/node@22.8.0': + resolution: {integrity: sha512-84rafSBHC/z1i1E3p0cJwKA+CfYDNSXX9WSZBRopjIzLET8oNt6ht2tei4C7izwDeEiLLfdeSVBv1egOH916hg==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/swagger-schema-official@2.0.25': + resolution: {integrity: sha512-T92Xav+Gf/Ik1uPW581nA+JftmjWPgskw/WBf4TJzxRG/SJ+DfNnNE+WuZ4mrXuzflQMqMkm1LSYjzYW7MB1Cg==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + agentkeepalive@4.5.0: + resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} + engines: {node: '>= 8.0.0'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + append-transform@2.0.0: + resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==} + engines: {node: '>=8'} + + archy@1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + babel-preset-current-node-syntax@1.1.0: + resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.24.2: + resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + caching-transform@4.0.0: + resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==} + engines: {node: '>=8'} + + call-me-maybe@1.0.2: + resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001669: + resolution: {integrity: sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cjs-module-lexer@1.4.1: + resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} + + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + cli-progress@3.12.0: + resolution: {integrity: sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==} + engines: {node: '>=4'} + + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + consola@3.2.3: + resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} + engines: {node: ^14.18.0 || >=16.10.0} + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + dedent@1.5.3: + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + default-require-extensions@3.0.1: + resolution: {integrity: sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==} + engines: {node: '>=8'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-to-chromium@1.5.45: + resolution: {integrity: sha512-vOzZS6uZwhhbkZbcRyiy99Wg+pYFV5hk+5YaECvx0+Z31NR3Tt5zS6dze2OepT6PCTzVzT0dIJItti+uAW5zmw==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es6-error@4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + + es6-promise@3.3.1: + resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} + + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + eta@2.2.0: + resolution: {integrity: sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==} + engines: {node: '>=6.0.0'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-cache-dir@3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + foreground-child@2.0.0: + resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} + engines: {node: '>=8.0.0'} + + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + + fromentries@1.3.2: + resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hasha@5.2.2: + resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} + engines: {node: '>=8'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http2-client@1.3.5: + resolution: {integrity: sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + inflight@1.0.6: + resolution: {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. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-hook@3.0.0: + resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + + istanbul-lib-processinfo@2.0.3: + resolution: {integrity: sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + + jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: true + + jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + lodash.flattendeep@4.4.0: + resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + + node-fetch-h2@2.3.0: + resolution: {integrity: sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==} + engines: {node: 4.x || >=6.0.0} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-preload@0.2.1: + resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==} + engines: {node: '>=8'} + + node-readfiles@0.2.0: + resolution: {integrity: sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==} + + node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + nyc@17.1.0: + resolution: {integrity: sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==} + engines: {node: '>=18'} + hasBin: true + + oas-kit-common@1.0.8: + resolution: {integrity: sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==} + + oas-linter@3.2.2: + resolution: {integrity: sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==} + + oas-resolver@2.5.6: + resolution: {integrity: sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==} + hasBin: true + + oas-schema-walker@1.1.5: + resolution: {integrity: sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==} + + oas-validator@5.0.8: + resolution: {integrity: sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + openai@4.68.4: + resolution: {integrity: sha512-LRinV8iU9VQplkr25oZlyrsYGPGasIwYN8KFMAAFTHHLHjHhejtJ5BALuLFrkGzY4wfbKhOhuT+7lcHZ+F3iEA==} + hasBin: true + peerDependencies: + zod: ^3.23.8 + peerDependenciesMeta: + zod: + optional: true + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-map@3.0.0: + resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-hash@4.0.0: + resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==} + engines: {node: '>=8'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + process-on-spawn@1.0.0: + resolution: {integrity: sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==} + engines: {node: '>=8'} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + reftools@1.1.9: + resolution: {integrity: sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==} + + release-zalgo@1.0.0: + resolution: {integrity: sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==} + engines: {node: '>=4'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + should-equal@2.0.0: + resolution: {integrity: sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==} + + should-format@3.0.3: + resolution: {integrity: sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==} + + should-type-adaptors@1.1.0: + resolution: {integrity: sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==} + + should-type@1.4.0: + resolution: {integrity: sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==} + + should-util@1.0.1: + resolution: {integrity: sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==} + + should@13.2.3: + resolution: {integrity: sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + spawn-wrap@2.0.0: + resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==} + engines: {node: '>=8'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + swagger-schema-official@2.0.0-bab6bed: + resolution: {integrity: sha512-rCC0NWGKr/IJhtRuPq/t37qvZHI/mH4I4sxflVM+qgVe5Z2uOCivzWaVbuioJaB61kvm5UvB7b49E+oBY0M8jA==} + + swagger-typescript-api@13.0.22: + resolution: {integrity: sha512-LVLOWvozOE3izesDrfmhOpwr6XsCRGsrfJuAXsaHkzQxYPAcpSRIAzodmz1hcGJ8BOPiBCKocH1LQ96F0lmmAw==} + engines: {node: '>=18.0.0'} + hasBin: true + + swagger2openapi@7.0.8: + resolution: {integrity: sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==} + hasBin: true + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + ts-jest@29.2.5: + resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/transform': ^29.0.0 + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/transform': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + + tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + + tsx@4.19.1: + resolution: {integrity: sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA==} + engines: {node: '>=18.0.0'} + hasBin: true + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + + typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + + typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + uuidv7@1.0.2: + resolution: {integrity: sha512-8JQkH4ooXnm1JCIhqTMbtmdnYEn6oKukBxHn1Ic9878jMkL7daTI7anTExfY18VRCX7tcdn5quzvCb6EWrR8PA==} + hasBin: true + + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@3.0.3: + resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@babel/code-frame@7.26.0': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.26.0': {} + + '@babel/core@7.26.0': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.0 + '@babel/generator': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.0 + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + convert-source-map: 2.0.0 + debug: 4.3.7 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.26.0': + dependencies: + '@babel/parser': 7.26.0 + '@babel/types': 7.26.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.0.2 + + '@babel/helper-compilation-targets@7.25.9': + dependencies: + '@babel/compat-data': 7.26.0 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-module-imports@7.25.9': + dependencies: + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.25.9': {} + + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/helper-validator-option@7.25.9': {} + + '@babel/helpers@7.26.0': + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + + '@babel/parser@7.26.0': + dependencies: + '@babel/types': 7.26.0 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/template@7.25.9': + dependencies: + '@babel/code-frame': 7.26.0 + '@babel/parser': 7.26.0 + '@babel/types': 7.26.0 + + '@babel/traverse@7.25.9': + dependencies: + '@babel/code-frame': 7.26.0 + '@babel/generator': 7.26.0 + '@babel/parser': 7.26.0 + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + debug: 4.3.7 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.26.0': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@bcoe/v8-coverage@0.2.3': {} + + '@esbuild/aix-ppc64@0.23.1': + optional: true + + '@esbuild/android-arm64@0.23.1': + optional: true + + '@esbuild/android-arm@0.23.1': + optional: true + + '@esbuild/android-x64@0.23.1': + optional: true + + '@esbuild/darwin-arm64@0.23.1': + optional: true + + '@esbuild/darwin-x64@0.23.1': + optional: true + + '@esbuild/freebsd-arm64@0.23.1': + optional: true + + '@esbuild/freebsd-x64@0.23.1': + optional: true + + '@esbuild/linux-arm64@0.23.1': + optional: true + + '@esbuild/linux-arm@0.23.1': + optional: true + + '@esbuild/linux-ia32@0.23.1': + optional: true + + '@esbuild/linux-loong64@0.23.1': + optional: true + + '@esbuild/linux-mips64el@0.23.1': + optional: true + + '@esbuild/linux-ppc64@0.23.1': + optional: true + + '@esbuild/linux-riscv64@0.23.1': + optional: true + + '@esbuild/linux-s390x@0.23.1': + optional: true + + '@esbuild/linux-x64@0.23.1': + optional: true + + '@esbuild/netbsd-x64@0.23.1': + optional: true + + '@esbuild/openbsd-arm64@0.23.1': + optional: true + + '@esbuild/openbsd-x64@0.23.1': + optional: true + + '@esbuild/sunos-x64@0.23.1': + optional: true + + '@esbuild/win32-arm64@0.23.1': + optional: true + + '@esbuild/win32-ia32@0.23.1': + optional: true + + '@esbuild/win32-x64@0.23.1': + optional: true + + '@exodus/schemasafe@1.3.0': {} + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.8.0 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + + '@jest/core@29.7.0': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.8.0 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@22.8.0) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + + '@jest/environment@29.7.0': + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.8.0 + jest-mock: 29.7.0 + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/expect@29.7.0': + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 22.8.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/globals@29.7.0': + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/reporters@29.7.0': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 22.8.0 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jest/source-map@29.6.3': + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@29.7.0': + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + + '@jest/test-sequencer@29.7.0': + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + + '@jest/transform@29.7.0': + dependencies: + '@babel/core': 7.26.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.8.0 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@sinclair/typebox@0.27.8': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.26.0 + '@babel/types': 7.26.0 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + + '@types/babel__generator@7.6.8': + dependencies: + '@babel/types': 7.26.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.26.0 + '@babel/types': 7.26.0 + + '@types/babel__traverse@7.20.6': + dependencies: + '@babel/types': 7.26.0 + + '@types/cli-progress@3.11.6': + dependencies: + '@types/node': 22.8.0 + + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 22.8.0 + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@29.5.14': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + + '@types/node-fetch@2.6.11': + dependencies: + '@types/node': 22.8.0 + form-data: 4.0.1 + + '@types/node@18.19.59': + dependencies: + undici-types: 5.26.5 + + '@types/node@22.8.0': + dependencies: + undici-types: 6.19.8 + + '@types/stack-utils@2.0.3': {} + + '@types/swagger-schema-official@2.0.25': {} + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + agentkeepalive@4.5.0: + dependencies: + humanize-ms: 1.2.1 + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + append-transform@2.0.0: + dependencies: + default-require-extensions: 3.0.1 + + archy@1.0.0: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + async@3.2.6: {} + + asynckit@0.4.0: {} + + babel-jest@29.7.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.26.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@6.1.1: + dependencies: + '@babel/helper-plugin-utils': 7.25.9 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.6 + + babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.0) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0) + + babel-preset-jest@29.6.3(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) + + balanced-match@1.0.2: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.24.2: + dependencies: + caniuse-lite: 1.0.30001669 + electron-to-chromium: 1.5.45 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.2) + + bs-logger@0.2.6: + dependencies: + fast-json-stable-stringify: 2.1.0 + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + + caching-transform@4.0.0: + dependencies: + hasha: 5.2.2 + make-dir: 3.1.0 + package-hash: 4.0.0 + write-file-atomic: 3.0.3 + + call-me-maybe@1.0.2: {} + + callsites@3.1.0: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001669: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + char-regex@1.0.2: {} + + ci-info@3.9.0: {} + + cjs-module-lexer@1.4.1: {} + + clean-stack@2.2.0: {} + + cli-progress@3.12.0: + dependencies: + string-width: 4.2.3 + + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + co@4.6.0: {} + + collect-v8-coverage@1.0.2: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commondir@1.0.1: {} + + concat-map@0.0.1: {} + + consola@3.2.3: {} + + convert-source-map@1.9.0: {} + + convert-source-map@2.0.0: {} + + cosmiconfig@9.0.0(typescript@5.5.4): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.5.4 + + create-jest@29.7.0(@types/node@22.8.0): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.8.0) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.3.7: + dependencies: + ms: 2.1.3 + + decamelize@1.2.0: {} + + dedent@1.5.3: {} + + deepmerge@4.3.1: {} + + default-require-extensions@3.0.1: + dependencies: + strip-bom: 4.0.0 + + delayed-stream@1.0.0: {} + + detect-newline@3.1.0: {} + + didyoumean@1.2.2: {} + + diff-sequences@29.6.3: {} + + ejs@3.1.10: + dependencies: + jake: 10.9.2 + + electron-to-chromium@1.5.45: {} + + emittery@0.13.1: {} + + emoji-regex@8.0.0: {} + + env-paths@2.2.1: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es6-error@4.1.1: {} + + es6-promise@3.3.1: {} + + esbuild@0.23.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 + + escalade@3.2.0: {} + + escape-string-regexp@2.0.0: {} + + esprima@4.0.1: {} + + eta@2.2.0: {} + + event-target-shim@5.0.1: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit@0.1.2: {} + + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + + fast-json-stable-stringify@2.1.0: {} + + fast-safe-stringify@2.1.1: {} + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-cache-dir@3.3.2: + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + foreground-child@2.0.0: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 3.0.7 + + foreground-child@3.3.0: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + + form-data-encoder@1.7.2: {} + + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + + fromentries@1.3.2: {} + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-package-type@0.1.0: {} + + get-stream@6.0.1: {} + + get-tsconfig@4.8.1: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@11.12.0: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + hasha@5.2.2: + dependencies: + is-stream: 2.0.1 + type-fest: 0.8.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + html-escaper@2.0.2: {} + + http2-client@1.3.5: {} + + human-signals@2.1.0: {} + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-arrayish@0.2.1: {} + + is-core-module@2.15.1: + dependencies: + hasown: 2.0.2 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-fn@2.1.0: {} + + is-number@7.0.0: {} + + is-stream@2.0.1: {} + + is-typedarray@1.0.0: {} + + is-windows@1.0.2: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-hook@3.0.0: + dependencies: + append-transform: 2.0.0 + + istanbul-lib-instrument@5.2.1: + dependencies: + '@babel/core': 7.26.0 + '@babel/parser': 7.26.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.26.0 + '@babel/parser': 7.26.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + + istanbul-lib-processinfo@2.0.3: + dependencies: + archy: 1.0.0 + cross-spawn: 7.0.3 + istanbul-lib-coverage: 3.2.2 + p-map: 3.0.0 + rimraf: 3.0.2 + uuid: 8.3.2 + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.3.7 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jake@10.9.2: + dependencies: + async: 3.2.6 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + + jest-changed-files@29.7.0: + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + + jest-circus@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.8.0 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.3 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@29.7.0(@types/node@22.8.0): + dependencies: + '@jest/core': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.8.0) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.8.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jest-config@29.7.0(@types/node@22.8.0): + dependencies: + '@babel/core': 7.26.0 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.0) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.8.0 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-docblock@29.7.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@29.7.0: + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + + jest-environment-node@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.8.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + jest-get-type@29.6.3: {} + + jest-haste-map@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 22.8.0 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@29.7.0: + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.26.0 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.8.0 + jest-util: 29.7.0 + + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: + jest-resolve: 29.7.0 + + jest-regex-util@29.6.3: {} + + jest-resolve-dependencies@29.7.0: + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@29.7.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.8 + resolve.exports: 2.0.2 + slash: 3.0.0 + + jest-runner@29.7.0: + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.8.0 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.8.0 + chalk: 4.1.2 + cjs-module-lexer: 1.4.1 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@29.7.0: + dependencies: + '@babel/core': 7.26.0 + '@babel/generator': 7.26.0 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + '@babel/types': 7.26.0 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.8.0 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-watcher@29.7.0: + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.8.0 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + + jest-worker@29.7.0: + dependencies: + '@types/node': 22.8.0 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@29.7.0(@types/node@22.8.0): + dependencies: + '@jest/core': 29.7.0 + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.8.0) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + js-tokens@4.0.0: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.0.2: {} + + json-parse-even-better-errors@2.3.1: {} + + json5@2.2.3: {} + + kleur@3.0.3: {} + + leven@3.1.0: {} + + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + lodash.flattendeep@4.4.0: {} + + lodash.memoize@4.1.2: {} + + lodash@4.17.21: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + make-dir@3.1.0: + dependencies: + semver: 6.3.1 + + make-dir@4.0.0: + dependencies: + semver: 7.6.3 + + make-error@1.3.6: {} + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + merge-stream@2.0.0: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@2.1.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + ms@2.1.3: {} + + nanoid@3.3.7: {} + + natural-compare@1.4.0: {} + + node-domexception@1.0.0: {} + + node-fetch-h2@2.3.0: + dependencies: + http2-client: 1.3.5 + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-int64@0.4.0: {} + + node-preload@0.2.1: + dependencies: + process-on-spawn: 1.0.0 + + node-readfiles@0.2.0: + dependencies: + es6-promise: 3.3.1 + + node-releases@2.0.18: {} + + normalize-path@3.0.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + nyc@17.1.0: + dependencies: + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + caching-transform: 4.0.0 + convert-source-map: 1.9.0 + decamelize: 1.2.0 + find-cache-dir: 3.3.2 + find-up: 4.1.0 + foreground-child: 3.3.0 + get-package-type: 0.1.0 + glob: 7.2.3 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-hook: 3.0.0 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-processinfo: 2.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + make-dir: 3.1.0 + node-preload: 0.2.1 + p-map: 3.0.0 + process-on-spawn: 1.0.0 + resolve-from: 5.0.0 + rimraf: 3.0.2 + signal-exit: 3.0.7 + spawn-wrap: 2.0.0 + test-exclude: 6.0.0 + yargs: 15.4.1 + transitivePeerDependencies: + - supports-color + + oas-kit-common@1.0.8: + dependencies: + fast-safe-stringify: 2.1.1 + + oas-linter@3.2.2: + dependencies: + '@exodus/schemasafe': 1.3.0 + should: 13.2.3 + yaml: 1.10.2 + + oas-resolver@2.5.6: + dependencies: + node-fetch-h2: 2.3.0 + oas-kit-common: 1.0.8 + reftools: 1.1.9 + yaml: 1.10.2 + yargs: 17.7.2 + + oas-schema-walker@1.1.5: {} + + oas-validator@5.0.8: + dependencies: + call-me-maybe: 1.0.2 + oas-kit-common: 1.0.8 + oas-linter: 3.2.2 + oas-resolver: 2.5.6 + oas-schema-walker: 1.1.5 + reftools: 1.1.9 + should: 13.2.3 + yaml: 1.10.2 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + openai@4.68.4: + dependencies: + '@types/node': 18.19.59 + '@types/node-fetch': 2.6.11 + abort-controller: 3.0.0 + agentkeepalive: 4.5.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-map@3.0.0: + dependencies: + aggregate-error: 3.1.0 + + p-try@2.2.0: {} + + package-hash@4.0.0: + dependencies: + graceful-fs: 4.2.11 + hasha: 5.2.2 + lodash.flattendeep: 4.4.0 + release-zalgo: 1.0.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.26.0 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pirates@4.0.6: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + prettier@3.3.3: {} + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + process-on-spawn@1.0.0: + dependencies: + fromentries: 1.3.2 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + pure-rand@6.1.0: {} + + react-is@18.3.1: {} + + reftools@1.1.9: {} + + release-zalgo@1.0.0: + dependencies: + es6-error: 4.1.1 + + require-directory@2.1.1: {} + + require-main-filename@2.0.0: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve.exports@2.0.2: {} + + resolve@1.22.8: + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + semver@6.3.1: {} + + semver@7.6.3: {} + + set-blocking@2.0.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + should-equal@2.0.0: + dependencies: + should-type: 1.4.0 + + should-format@3.0.3: + dependencies: + should-type: 1.4.0 + should-type-adaptors: 1.1.0 + + should-type-adaptors@1.1.0: + dependencies: + should-type: 1.4.0 + should-util: 1.0.1 + + should-type@1.4.0: {} + + should-util@1.0.1: {} + + should@13.2.3: + dependencies: + should-equal: 2.0.0 + should-format: 3.0.3 + should-type: 1.4.0 + should-type-adaptors: 1.1.0 + should-util: 1.0.1 + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + sisteransi@1.0.5: {} + + slash@3.0.0: {} + + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + spawn-wrap@2.0.0: + dependencies: + foreground-child: 2.0.0 + is-windows: 1.0.2 + make-dir: 3.1.0 + rimraf: 3.0.2 + signal-exit: 3.0.7 + which: 2.0.2 + + sprintf-js@1.0.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@3.0.0: {} + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + swagger-schema-official@2.0.0-bab6bed: {} + + swagger-typescript-api@13.0.22: + dependencies: + '@types/swagger-schema-official': 2.0.25 + consola: 3.2.3 + cosmiconfig: 9.0.0(typescript@5.5.4) + didyoumean: 1.2.2 + eta: 2.2.0 + js-yaml: 4.1.0 + lodash: 4.17.21 + nanoid: 3.3.7 + prettier: 3.3.3 + swagger-schema-official: 2.0.0-bab6bed + swagger2openapi: 7.0.8 + typescript: 5.5.4 + transitivePeerDependencies: + - encoding + + swagger2openapi@7.0.8: + dependencies: + call-me-maybe: 1.0.2 + node-fetch: 2.7.0 + node-fetch-h2: 2.3.0 + node-readfiles: 0.2.0 + oas-kit-common: 1.0.8 + oas-resolver: 2.5.6 + oas-schema-walker: 1.1.5 + oas-validator: 5.0.8 + reftools: 1.1.9 + yaml: 1.10.2 + yargs: 17.7.2 + transitivePeerDependencies: + - encoding + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + + tmpl@1.0.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tr46@0.0.3: {} + + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.0))(typescript@5.5.4): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@22.8.0) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.3 + typescript: 5.5.4 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.26.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.0) + + tsconfig-paths@4.2.0: + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tsx@4.19.1: + dependencies: + esbuild: 0.23.1 + get-tsconfig: 4.8.1 + optionalDependencies: + fsevents: 2.3.3 + + type-detect@4.0.8: {} + + type-fest@0.21.3: {} + + type-fest@0.8.1: {} + + typedarray-to-buffer@3.1.5: + dependencies: + is-typedarray: 1.0.0 + + typescript@5.5.4: {} + + undici-types@5.26.5: {} + + undici-types@6.19.8: {} + + update-browserslist-db@1.1.1(browserslist@4.24.2): + dependencies: + browserslist: 4.24.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uuid@8.3.2: {} + + uuidv7@1.0.2: {} + + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + web-streams-polyfill@4.0.0-beta.3: {} + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which-module@2.0.1: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + write-file-atomic@3.0.3: + dependencies: + imurmurhash: 0.1.4 + is-typedarray: 1.0.0 + signal-exit: 3.0.7 + typedarray-to-buffer: 3.1.5 + + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + + y18n@4.0.3: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yaml@1.10.2: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs-parser@21.1.1: {} + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} diff --git a/sdks/node/scripts/loadTest.ts b/sdks/node/scripts/loadTest.ts new file mode 100644 index 00000000000..2850b83b232 --- /dev/null +++ b/sdks/node/scripts/loadTest.ts @@ -0,0 +1,39 @@ +import * as weave from 'weave'; + +const func = weave.op(async () => 1); +const myFunction = async (a: number = 1, b: string = 'hello', c: boolean = true) => { + return { first: a, second: b, third: c }; +}; +const func2 = weave.op(myFunction); +const func3 = weave.op(async () => { + throw new Error('hmm'); +}); +const myFunction2 = async ({ a, b = 'wuh' }: { a?: number; b?: string }) => { + return { first: a, second: b }; +}; +const func4 = weave.op(myFunction2, { parameterNames: 'useParam0Object' }); + +async function bench(func: weave.Op, calls: number, client: weave.WeaveClient) { + console.log(`Benchmarking with ${calls} calls...`); + const startTime = Date.now(); + const promises = Array(calls) + .fill(null) + .map(() => func({ a: 3 })); + await Promise.all(promises); + await client.waitForBatchProcessing(); + + const endTime = Date.now(); + const duration = (endTime - startTime) / 1000; // Convert to seconds + console.log(`Completed ${calls} calls in ${duration.toFixed(2)} seconds`); +} + +async function main() { + const client = await weave.init('examples'); + // for (let x = 1; x <= 5; x++) { + // const calls = Math.pow(10, x); + // await bench(calls, client); + // } + await bench(func4, 1, client); +} + +main(); diff --git a/sdks/node/scripts/testApi.ts b/sdks/node/scripts/testApi.ts new file mode 100644 index 00000000000..673c540f2b7 --- /dev/null +++ b/sdks/node/scripts/testApi.ts @@ -0,0 +1,72 @@ +import OpenAI from 'openai'; +import * as weave from 'weave'; + +// Initialize the API +weave.init('examples'); + +// Create OpenAI client +const openai = weave.wrapOpenAI(new OpenAI()); + +// Define a simple function to be wrapped +function add(a: number, b: number): number { + return a + b; +} + +// Wrap the function using op +const wrappedAdd = weave.op(add); + +// Function to demonstrate async behavior +async function delayedMultiply(a: number, b: number): Promise { + await new Promise(resolve => setTimeout(resolve, 1000)); // 1 second delay + return a * b; +} + +// Wrap the async function +const wrappedDelayedMultiply = weave.op(delayedMultiply); + +// Function to call OpenAI +async function callOpenAI(prompt: string): Promise { + const completion = await openai.chat.completions.create({ + model: 'gpt-3.5-turbo', + messages: [{ role: 'user', content: prompt }], + }); + return completion.choices[0].message.content || ''; +} + +// Wrap the OpenAI function +const wrappedCallOpenAI = weave.op(callOpenAI); + +// Function to demonstrate nested calls including OpenAI +async function complexOperationWithAI(a: number, b: number, c: number): Promise { + const sum = await wrappedAdd(a, b); + const product = await wrappedDelayedMultiply(sum, c); + const prompt = `What is an interesting fact about the number ${product}?`; + const aiResponse = await wrappedCallOpenAI(prompt); + return `The result of the calculation is ${product}. ${aiResponse}`; +} + +// Wrap the complex function +const wrappedComplexOperationWithAI = weave.op(complexOperationWithAI); + +// Main async function to run our tests +async function runTests() { + console.log('Starting tests...'); + + // Test the wrapped add function + console.log('\nTesting wrapped add function:'); + console.log('2 + 3 =', await wrappedAdd(2, 3)); + + // Test the wrapped async multiply function + console.log('\nTesting wrapped delayed multiply function:'); + console.log('3 * 4 =', await wrappedDelayedMultiply(3, 4)); + + // Test the complex operation with nested calls including OpenAI + console.log('\nTesting complex operation with nested calls including OpenAI:'); + const result = await wrappedComplexOperationWithAI(2, 3, 4); + console.log(result); + + console.log('\nTests completed.'); +} + +// Run the tests +runTests().catch(error => console.error('An error occurred:', error)); diff --git a/sdks/node/src/__tests__/clientApi.test.ts b/sdks/node/src/__tests__/clientApi.test.ts new file mode 100644 index 00000000000..0a83641f62d --- /dev/null +++ b/sdks/node/src/__tests__/clientApi.test.ts @@ -0,0 +1,54 @@ +import {init, requireGlobalClient} from '../clientApi'; +import {getWandbConfigs} from '../wandb/settings'; +import {WandbServerApi} from '../wandb/wandbServerApi'; + +jest.mock('../wandb/wandbServerApi'); +jest.mock('../wandb/settings'); + +describe('Client API', () => { + beforeEach(() => { + jest.clearAllMocks(); + + // Mock getWandbConfigs + (getWandbConfigs as jest.Mock).mockReturnValue({ + apiKey: 'mock-api-key', + baseUrl: 'https://api.wandb.ai', + traceBaseUrl: 'https://trace.wandb.ai', + domain: 'api.wandb.ai', + host: 'api.wandb.ai', + }); + + // Mock WandbServerApi + (WandbServerApi as jest.Mock).mockImplementation(() => ({ + defaultEntityName: jest.fn().mockResolvedValue('test-entity'), + })); + }); + + describe('initialization', () => { + test('initializes with project name', async () => { + const client = await init('test-project'); + const gottenClient = requireGlobalClient(); + + expect(gottenClient).toBeDefined(); + expect(gottenClient).toBe(client); + expect(WandbServerApi).toHaveBeenCalledWith( + 'https://api.wandb.ai', + 'mock-api-key' + ); + expect(gottenClient.projectId).toBe('test-entity/test-project'); + }); + + test('initializes with entity/project', async () => { + const client = await init('custom-entity/test-project'); + const gottenClient = requireGlobalClient(); + + expect(gottenClient).toBeDefined(); + expect(gottenClient).toBe(client); + expect(WandbServerApi).toHaveBeenCalledWith( + 'https://api.wandb.ai', + 'mock-api-key' + ); + expect(gottenClient.projectId).toBe('custom-entity/test-project'); + }); + }); +}); diff --git a/sdks/node/src/__tests__/clientMock.ts b/sdks/node/src/__tests__/clientMock.ts new file mode 100644 index 00000000000..660eac9e59c --- /dev/null +++ b/sdks/node/src/__tests__/clientMock.ts @@ -0,0 +1,19 @@ +import {setGlobalClient} from '../clientApi'; +import {Api as TraceServerApi} from '../generated/traceServerApi'; +import {InMemoryTraceServer} from '../inMemoryTraceServer'; +import {Settings} from '../settings'; +import {WandbServerApi} from '../wandb/wandbServerApi'; +import {WeaveClient} from '../weaveClient'; + +export function initWithCustomTraceServer( + projectName: string, + customTraceServer: InMemoryTraceServer +) { + const client = new WeaveClient( + customTraceServer as unknown as TraceServerApi, + {} as WandbServerApi, // Placeholder, as we don't use WandbServerApi in this case + projectName, + new Settings(true) + ); + setGlobalClient(client); +} diff --git a/sdks/node/src/__tests__/digest.test.ts b/sdks/node/src/__tests__/digest.test.ts new file mode 100644 index 00000000000..08c2dc20d4a --- /dev/null +++ b/sdks/node/src/__tests__/digest.test.ts @@ -0,0 +1,108 @@ +import {stringifyPythonDumps} from '../digest'; + +describe('stringifyPythonDumps', () => { + test('Basic types', async () => { + const testData1 = { + a: 1, + b: ['a', 'b', 'd,e', ["f',j,y"]], + c: 3, + d: 4, + e: 5, + }; + const expected1 = + '{"a": 1, "b": ["a", "b", "d,e", ["f\',j,y"]], "c": 3, "d": 4, "e": 5}'; + expect(stringifyPythonDumps(testData1)).toBe(expected1); + }); + + test('Special numbers', async () => { + const testData2 = { + int_max: 9007199254740991, // Max safe integer in JS + int_min: -9007199254740991, // Min safe integer in JS + float: 3.14159, + exp_pos: 1e100, + exp_neg: 1e-100, + zero: 0, + neg_zero: -0, + }; + const expected2 = + '{"exp_neg": 1e-100, "exp_pos": 1e+100, "float": 3.14159, "int_max": 9007199254740991, "int_min": -9007199254740991, "neg_zero": 0, "zero": 0}'; + expect(stringifyPythonDumps(testData2)).toBe(expected2); + }); + + test('Special values', async () => { + const testData3 = { + null: null, + bool_true: true, + bool_false: false, + empty_list: [], + empty_dict: {}, + }; + const expected3 = + '{"bool_false": false, "bool_true": true, "empty_dict": {}, "empty_list": [], "null": null}'; + expect(stringifyPythonDumps(testData3)).toBe(expected3); + }); + + test('Unicode and escaping', async () => { + const testData4 = { + unicode: 'こんにちは', + escape_chars: '\b\f\n\r\t', + quotes: '"Hello," she said.', + backslash: 'C:\\path\\to\\file', + }; + const expected4 = + '{"backslash": "C:\\\\path\\\\to\\\\file", "escape_chars": "\\b\\f\\n\\r\\t", "quotes": "\\"Hello,\\" she said.", "unicode": "こんにちは"}'; + expect(stringifyPythonDumps(testData4)).toBe(expected4); + }); + + test('Nested structures', async () => { + const testData5 = { + nested: { + list: [1, [2, [3, [4]]]], + dict: {a: {b: {c: {d: 4}}}}, + }, + }; + const expected5 = + '{"nested": {"dict": {"a": {"b": {"c": {"d": 4}}}}, "list": [1, [2, [3, [4]]]]}}'; + expect(stringifyPythonDumps(testData5)).toBe(expected5); + }); + + test('Array of mixed types', async () => { + const testData6 = [1, 'two', 3, [4, 5], {six: 6}, null, true, false]; + const expected6 = '[1, "two", 3, [4, 5], {"six": 6}, null, true, false]'; + expect(stringifyPythonDumps(testData6)).toBe(expected6); + }); + + test('Empty string keys and values', async () => { + const testData7 = {'': 'empty_key', empty_value: ''}; + const expected7 = '{"": "empty_key", "empty_value": ""}'; + expect(stringifyPythonDumps(testData7)).toBe(expected7); + }); + + // TODO: This is a generated test that fails. I didn't look into what the behavior should actually + // be, because we're not using stringifyPythonDumps anywhere yet. + test.skip('Non-string keys', async () => { + const testData8 = {1: 'one', 2.0: 'two', true: 'true'}; + const expected8 = '{"1": "true", "2.0": "two"}'; + expect(stringifyPythonDumps(testData8)).toBe(expected8); + }); + + test('Special characters in strings', async () => { + const testData9 = { + control_chars: '\u0000\u0001\u0002\u0003', + emoji: '😀🌍🚀', + surrogate_pair: '\uD83D\uDE00', + }; + const expected9 = + '{"control_chars": "\\u0000\\u0001\\u0002\\u0003", "emoji": "😀🌍🚀", "surrogate_pair": "😀"}'; + expect(stringifyPythonDumps(testData9)).toBe(expected9); + }); +}); + +// describe('encodeNumber', () => { +// test('Basic numbers', () => { +// expect(encodeNumber(1)).toBe('1'); +// expect(encodeNumber(1.0)).toBe('1.0'); +// expect(encodeNumber(1.1)).toBe('1.1'); +// expect(encodeNumber(1e9)).toBe('1e9'); +// }); +// }); diff --git a/sdks/node/src/__tests__/evaluation.test.ts b/sdks/node/src/__tests__/evaluation.test.ts new file mode 100644 index 00000000000..86d2bd3170a --- /dev/null +++ b/sdks/node/src/__tests__/evaluation.test.ts @@ -0,0 +1,171 @@ +import {Dataset} from '../dataset'; +import {Evaluation} from '../evaluation'; +import {ColumnMapping} from '../fn'; +import {op} from '../op'; + +const createMockDataset = () => + new Dataset({ + rows: [ + {id: 0, text: 'Example 0'}, + {id: 1, text: 'Example 1'}, + {id: 2, text: 'Example 2'}, + {id: 3, text: 'Example 3'}, + {id: 4, text: 'Example 4'}, + ], + }); + +const createMockDatasetWithDifferentColumnNames = () => + new Dataset({ + rows: [ + {identifier: 0, description: 'Example 0'}, + {identifier: 1, description: 'Example 1'}, + {identifier: 2, description: 'Example 2'}, + {identifier: 3, description: 'Example 3'}, + {identifier: 4, description: 'Example 4'}, + ], + }); + +const createMockModel = (failable: boolean) => { + return op(async function mockPrediction({ + datasetRow, + }: { + datasetRow: {id: number; text: string}; + }) { + if (failable && datasetRow.id === 0) throw new Error('Model failed'); + if (failable && datasetRow.text === undefined) + throw new Error('Model failed'); + return `Prediction for ${datasetRow.text}`; + }); +}; + +const createMockScorers = (failable: boolean) => { + return [ + op(async function lengthScorer({ + datasetRow, + modelOutput, + }: { + datasetRow: {id: number; text: string}; + modelOutput: string; + }) { + if (failable && datasetRow.id === 3) throw new Error('Scorer 1 failed'); + return { + explanation: 'length is ' + modelOutput.length, + length: modelOutput.length, + }; + }), + op(async function inclusionScorer({ + modelOutput, + datasetRow, + }: { + modelOutput: string; + datasetRow: {id: number; text: string}; + }) { + return modelOutput.includes(datasetRow.text); + }), + ]; +}; + +const createMockEvaluation = ( + failable: boolean, + dataset: Dataset = createMockDataset(), + columnMapping?: ColumnMapping +) => { + return new Evaluation({ + dataset, + scorers: createMockScorers(failable), + columnMapping, + }); +}; + +describe('Evaluation', () => { + test('summarizeResults', async () => { + const mockEval = createMockEvaluation(false); + const mockModel = createMockModel(false); + + const results = await mockEval.evaluate({model: mockModel}); + const expectedResults = { + model_success: {true_count: 5, true_fraction: 1}, + inclusionScorer: { + true_count: 5, + true_fraction: 1, + }, + lengthScorer: { + length: { + mean: 24, + }, + }, + model_latency: {mean: expect.any(Number)}, + }; + + expect(results).toEqual(expectedResults); + }); + test('summarizeResults with failed predictions and scorers', async () => { + const mockEval = createMockEvaluation(true); + const mockModel = createMockModel(true); + + const results = await mockEval.evaluate({model: mockModel}); + const expectedResults = { + model_success: {true_count: 4, true_fraction: 0.8}, + inclusionScorer: { + true_count: 4, + true_fraction: 0.8, + }, + lengthScorer: { + length: { + mean: 14.4, + }, + }, + model_latency: {mean: expect.any(Number)}, + }; + + expect(results).toEqual(expectedResults); + }); + + test('evaluate with a valid column mapping', async () => { + const mockEval = createMockEvaluation( + true, + createMockDatasetWithDifferentColumnNames(), + { + id: 'identifier', + text: 'description', + } + ); + const mockModel = createMockModel(true); + const res = await mockEval.evaluate({model: mockModel}); + expect(res).toEqual({ + model_success: { + true_count: 4, + true_fraction: 0.8, + }, + inclusionScorer: { + true_count: 4, + true_fraction: 0.8, + }, + lengthScorer: { + length: { + mean: 14.4, + }, + }, + model_latency: {mean: expect.any(Number)}, + }); + }); + + test('evaluate with an invalid column mapping', async () => { + // These cols dont map as expected, so the model should fail + const mockEval = createMockEvaluation( + true, + createMockDatasetWithDifferentColumnNames(), + { + id: 'totallyNot', + text: 'validMapping', + } + ); + const mockModel = createMockModel(true); + + const res = await mockEval.evaluate({model: mockModel}); + expect(res).toEqual({ + model_success: {true_count: 0, true_fraction: 0}, + model_latency: {mean: expect.any(Number)}, + }); + }); +}); diff --git a/sdks/node/src/__tests__/integrations/integrationOpenAI.test.ts b/sdks/node/src/__tests__/integrations/integrationOpenAI.test.ts new file mode 100644 index 00000000000..e7aec87b2f3 --- /dev/null +++ b/sdks/node/src/__tests__/integrations/integrationOpenAI.test.ts @@ -0,0 +1,303 @@ +import {InMemoryTraceServer} from '../../inMemoryTraceServer'; +import {wrapOpenAI} from '../../integrations/openai'; +import {initWithCustomTraceServer} from '../clientMock'; +import {makeMockOpenAIChat} from '../openaiMock'; + +// Helper function to get calls +async function getCalls(traceServer: InMemoryTraceServer, projectId: string) { + const calls = await traceServer.calls + .callsStreamQueryPost({ + project_id: projectId, + limit: 100, + }) + .then(result => result.calls); + return calls; +} + +const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); + +describe('OpenAI Integration', () => { + let inMemoryTraceServer: InMemoryTraceServer; + const testProjectName = 'test-project'; + let mockOpenAI: any; + let patchedOpenAI: any; + + beforeEach(() => { + inMemoryTraceServer = new InMemoryTraceServer(); + initWithCustomTraceServer(testProjectName, inMemoryTraceServer); + + const mockOpenAIChat = makeMockOpenAIChat(messages => ({ + content: messages[messages.length - 1].content.toUpperCase(), + functionCalls: [], + })); + + mockOpenAI = { + chat: { + completions: {create: mockOpenAIChat}, + }, + beta: { + chat: { + completions: { + parse: () => { + throw new Error('not implemented'); + }, + }, + }, + }, + images: { + generate: () => { + throw new Error('not implemented'); + }, + }, + }; + patchedOpenAI = wrapOpenAI(mockOpenAI); + }); + + test('non-streaming chat completion', async () => { + const messages = [{role: 'user', content: 'Hello, AI!'}]; + + // Direct API call + const directResult = await mockOpenAI.chat.completions.create({messages}); + + // Op-wrapped API call + const opResult = await patchedOpenAI.chat.completions.create({messages}); + + // Wait for any pending batch processing + await wait(300); + + // Check results + expect(opResult).toMatchObject({ + object: directResult.object, + model: directResult.model, + choices: directResult.choices, + usage: directResult.usage, + }); + expect(opResult.id).toMatch(/^chatcmpl-/); + expect(opResult.system_fingerprint).toMatch(/^fp_/); + expect(opResult.created).toBeCloseTo(directResult.created, -2); // Allow 1 second difference + expect(opResult.choices[0].message.content).toBe('HELLO, AI!'); + + // Check logged Call values + const calls = await getCalls(inMemoryTraceServer, testProjectName); + expect(calls).toHaveLength(1); + expect(calls[0].op_name).toContain('openai.chat.completions.create'); + expect(calls[0].inputs).toEqual({messages}); + expect(calls[0].output).toMatchObject({ + object: opResult.object, + model: opResult.model, + choices: opResult.choices, + usage: opResult.usage, + }); + expect(calls[0].output.id).toMatch(/^chatcmpl-/); + expect(calls[0].output.system_fingerprint).toMatch(/^fp_/); + expect(calls[0].output.created).toBeCloseTo(opResult.created, -2); + expect(calls[0].summary).toEqual({ + usage: { + 'gpt-4o-2024-05-13': { + requests: 1, + prompt_tokens: 2, + completion_tokens: 2, + total_tokens: 4, + }, + }, + }); + // Ensure stream_options is not present in the logged call for non-streaming requests + expect(calls[0].inputs).not.toHaveProperty('stream_options'); + }); + + test('streaming chat completion basic', async () => { + const messages = [{role: 'user', content: 'Hello, streaming AI!'}]; + + // Direct API call + const directStream = await mockOpenAI.chat.completions.create({ + messages, + stream: true, + }); + let directContent = ''; + for await (const chunk of directStream) { + if (chunk.choices && chunk.choices[0]?.delta?.content) { + directContent += chunk.choices[0].delta.content; + } + } + + // Op-wrapped API call + const opStream = await patchedOpenAI.chat.completions.create({ + messages, + stream: true, + }); + let opContent = ''; + let usageChunkSeen = false; + for await (const chunk of opStream) { + if (chunk.choices && chunk.choices[0]?.delta?.content) { + opContent += chunk.choices[0].delta.content; + } + if ('usage' in chunk) { + usageChunkSeen = true; + } + } + + // Wait for any pending batch processing + await wait(300); + + // Check results + expect(opContent).toBe(directContent); + expect(opContent).toBe('HELLO, STREAMING AI!'); + + // TOOD: this is broken still! + // expect(usageChunkSeen).toBe(false); // Ensure no usage chunk is seen in the user-facing stream + + // Check logged Call values + const calls = await getCalls(inMemoryTraceServer, testProjectName); + expect(calls).toHaveLength(1); + expect(calls[0].op_name).toContain('openai.chat.completions.create'); + expect(calls[0].inputs).toEqual({messages, stream: true}); + expect(calls[0].output).toMatchObject({ + choices: [ + { + message: { + content: 'HELLO, STREAMING AI!', + }, + }, + ], + }); + expect(calls[0].summary).toEqual({ + usage: { + 'gpt-4o-2024-05-13': { + requests: 1, + prompt_tokens: 3, + completion_tokens: 3, + total_tokens: 6, + }, + }, + }); + }); + + // Add a new test for streaming with explicit usage request + test('streaming chat completion with explicit usage request', async () => { + const messages = [ + {role: 'user', content: 'Hello, streaming AI with usage!'}, + ]; + + // Op-wrapped API call with explicit usage request + const opStream = await patchedOpenAI.chat.completions.create({ + messages, + stream: true, + stream_options: {include_usage: true}, + }); + let opContent = ''; + let usageChunkSeen = false; + for await (const chunk of opStream) { + if (chunk.choices[0]?.delta?.content) { + opContent += chunk.choices[0].delta.content; + } + if ('usage' in chunk) { + usageChunkSeen = true; + } + } + + // Wait for any pending batch processing + await wait(300); + + // Check results + expect(opContent).toBe('HELLO, STREAMING AI WITH USAGE!'); + expect(usageChunkSeen).toBe(true); // Ensure usage chunk is seen when explicitly requested + + // Check logged Call values + const calls = await getCalls(inMemoryTraceServer, testProjectName); + expect(calls).toHaveLength(1); + expect(calls[0].summary).toEqual({ + usage: { + 'gpt-4o-2024-05-13': { + requests: 1, + prompt_tokens: 5, + completion_tokens: 5, + total_tokens: 10, + }, + }, + }); + }); + + test('chat completion with function call', async () => { + const messages = [{role: 'user', content: "What's the weather in London?"}]; + const functions = [ + { + name: 'get_weather', + description: 'Get the weather in a location', + parameters: { + type: 'object', + properties: { + location: {type: 'string'}, + }, + required: ['location'], + }, + }, + ]; + + // Update mock to include function call + const mockOpenAIChat = makeMockOpenAIChat(() => ({ + content: '', + functionCalls: [ + { + name: 'get_weather', + arguments: {location: 'London'}, + }, + ], + })); + mockOpenAI.chat.completions.create = mockOpenAIChat; + + // Direct API call + const directResult = await mockOpenAI.chat.completions.create({ + messages, + functions, + }); + + // Op-wrapped API call + const opResult = await patchedOpenAI.chat.completions.create({ + messages, + functions, + }); + + // Wait for any pending batch processing + await wait(300); + + // Check results + expect(opResult).toMatchObject({ + object: directResult.object, + model: directResult.model, + choices: directResult.choices, + usage: directResult.usage, + }); + expect(opResult.id).toMatch(/^chatcmpl-/); + expect(opResult.system_fingerprint).toMatch(/^fp_/); + expect(opResult.created).toBeCloseTo(directResult.created, -2); // Allow 1 second difference + expect(opResult.choices[0].message.function_call).toEqual({ + name: 'get_weather', + arguments: '{"location":"London"}', + }); + + // Check logged Call values + const calls = await getCalls(inMemoryTraceServer, testProjectName); + expect(calls).toHaveLength(1); + expect(calls[0].op_name).toContain('openai.chat.completions.create'); + expect(calls[0].inputs).toEqual({messages, functions}); + expect(calls[0].output).toMatchObject({ + object: opResult.object, + model: opResult.model, + choices: opResult.choices, + usage: opResult.usage, + }); + expect(calls[0].output.id).toMatch(/^chatcmpl-/); + expect(calls[0].output.system_fingerprint).toMatch(/^fp_/); + expect(calls[0].output.created).toBeCloseTo(opResult.created, -2); + expect(calls[0].summary).toEqual({ + usage: { + 'gpt-4o-2024-05-13': { + requests: 1, + prompt_tokens: 5, + completion_tokens: 3, + total_tokens: 8, + }, + }, + }); + }); +}); diff --git a/sdks/node/src/__tests__/integrations/openai2.test.ts b/sdks/node/src/__tests__/integrations/openai2.test.ts new file mode 100644 index 00000000000..1e2f679c9db --- /dev/null +++ b/sdks/node/src/__tests__/integrations/openai2.test.ts @@ -0,0 +1,241 @@ +import {Api as TraceServerApi} from '../../generated/traceServerApi'; +import { + makeOpenAIImagesGenerateOp, + openAIStreamReducer, + wrapOpenAI, +} from '../../integrations/openai'; +import {isWeaveImage} from '../../media'; +import {WandbServerApi} from '../../wandb/wandbServerApi'; +import {WeaveClient} from '../../weaveClient'; + +// Mock WeaveClient dependencies +jest.mock('../../generated/traceServerApi'); +jest.mock('../../wandb/wandbServerApi'); + +describe('OpenAI Integration', () => { + let mockOpenAI: any; + let wrappedOpenAI: any; + let mockTraceServerApi: jest.Mocked>; + let mockWandbServerApi: jest.Mocked; + let weaveClient: WeaveClient; + + beforeEach(() => { + // Setup mock OpenAI client + mockOpenAI = { + chat: { + completions: { + create: jest.fn(), + }, + }, + images: { + generate: jest.fn(), + }, + beta: { + chat: { + completions: { + parse: jest.fn(), + }, + }, + }, + }; + + // Setup WeaveClient + mockTraceServerApi = { + obj: { + objCreateObjCreatePost: jest.fn().mockResolvedValue({ + data: {digest: 'test-digest'}, + }), + }, + call: { + callStartBatchCallUpsertBatchPost: jest.fn(), + }, + } as any; + mockWandbServerApi = {} as any; + weaveClient = new WeaveClient( + mockTraceServerApi, + mockWandbServerApi, + 'test-project' + ); + + wrappedOpenAI = wrapOpenAI(mockOpenAI); + }); + + describe('openAIStreamReducer', () => { + it('should correctly reduce stream chunks for basic chat completion', () => { + const state = {...openAIStreamReducer.initialState}; + + const chunks = [ + { + id: 'test-id', + object: 'chat.completion.chunk', + created: 1234567890, + model: 'gpt-4', + choices: [ + { + index: 0, + delta: { + role: 'assistant', + content: 'Hello', + }, + }, + ], + }, + { + choices: [ + { + index: 0, + delta: { + content: ' world!', + }, + finish_reason: 'stop', + }, + ], + usage: { + prompt_tokens: 10, + completion_tokens: 20, + total_tokens: 30, + }, + }, + ]; + + let finalState = state; + chunks.forEach(chunk => { + finalState = openAIStreamReducer.reduceFn(finalState, chunk); + }); + + expect(finalState).toEqual({ + id: 'test-id', + object: 'chat.completion.chunk', + created: 1234567890, + model: 'gpt-4', + choices: [ + { + index: 0, + message: { + role: 'assistant', + content: 'Hello world!', + function_call: null, + }, + finish_reason: 'stop', + }, + ], + usage: { + prompt_tokens: 10, + completion_tokens: 20, + total_tokens: 30, + }, + }); + }); + + it('should handle function calls in stream chunks', () => { + const state = {...openAIStreamReducer.initialState}; + + const chunks = [ + { + id: 'func-call-id', + choices: [ + { + delta: { + role: 'assistant', + function_call: { + name: 'test_function', + }, + }, + }, + ], + }, + { + choices: [ + { + delta: { + function_call: { + arguments: '{"arg1":', + }, + }, + }, + ], + }, + { + choices: [ + { + delta: { + function_call: { + arguments: '"value1"}', + }, + }, + finish_reason: 'function_call', + }, + ], + }, + ]; + + let finalState = state; + chunks.forEach(chunk => { + finalState = openAIStreamReducer.reduceFn(finalState, chunk); + }); + + expect(finalState.choices[0].message.function_call).toEqual({ + name: 'test_function', + arguments: '{"arg1":"value1"}', + }); + expect(finalState.choices[0].finish_reason).toBe('function_call'); + }); + }); + + describe('wrapOpenAI', () => { + it('should wrap transparently', async () => { + const mockCreate = jest.fn(async params => ({ + id: 'test-id', + choices: [{message: {content: 'Hello'}}], + })); + + // Test both wrapped and unwrapped versions + mockOpenAI.chat.completions.create = mockCreate; + const unwrappedResult = await mockOpenAI.chat.completions.create({ + model: 'gpt-4', + messages: [{role: 'user', content: 'Hi'}], + }); + + const wrappedResult = await wrappedOpenAI.chat.completions.create({ + model: 'gpt-4', + messages: [{role: 'user', content: 'Hi'}], + }); + + // Verify wrapped matches unwrapped + expect(wrappedResult).toEqual(unwrappedResult); + }); + }); +}); + +describe('makeOpenAIImagesGenerateOp', () => { + it('converts b64_json images to WeaveImage objects and preserves other items', async () => { + const mockGenerate = jest.fn().mockResolvedValue({ + data: [ + { + url: 'https://example.com/image.png', + }, + { + b64_json: + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==', + }, + ], + }); + + const wrappedGenerate = makeOpenAIImagesGenerateOp(mockGenerate); + const result = await wrappedGenerate({prompt: 'draw a picture'}); + + // Verify the result structure + expect(result.data).toHaveLength(2); + + // First item should remain unchanged + expect(result.data[0]).toEqual({url: 'https://example.com/image.png'}); + + // Second item should be converted to WeaveImage + expect(isWeaveImage(result.data[1])).toBe(true); + expect(result.data[1].imageType).toBe('png'); + expect(Buffer.isBuffer(result.data[1].data)).toBe(true); + + // Verify the original function was called with correct args + expect(mockGenerate).toHaveBeenCalledWith({prompt: 'draw a picture'}); + }); +}); diff --git a/sdks/node/src/__tests__/integrations/openaiMock.test.ts b/sdks/node/src/__tests__/integrations/openaiMock.test.ts new file mode 100644 index 00000000000..1b931ea191f --- /dev/null +++ b/sdks/node/src/__tests__/integrations/openaiMock.test.ts @@ -0,0 +1,157 @@ +import {makeMockOpenAIChat} from '../openaiMock'; + +describe('OpenAI Mock', () => { + const mockResponse = (messages: any[]) => ({ + content: messages[0].content.toUpperCase(), + functionCalls: [ + { + name: 'test_function', + arguments: {arg: 'value'}, + }, + ], + }); + + test('non-streaming response', async () => { + const testOpenAIChat = makeMockOpenAIChat(mockResponse); + const response = await testOpenAIChat({ + messages: [{role: 'user', content: 'Hello, AI!'}], + }); + + expect(response).toEqual({ + id: expect.any(String), + object: 'chat.completion', + created: expect.any(Number), + model: 'gpt-4o-2024-05-13', + choices: [ + { + index: 0, + message: { + role: 'assistant', + content: 'HELLO, AI!', + function_call: { + name: 'test_function', + arguments: '{"arg":"value"}', + }, + refusal: null, + }, + logprobs: null, + finish_reason: 'function_call', + }, + ], + usage: { + prompt_tokens: 2, + completion_tokens: 4, // 2 for content + 2 for function call + total_tokens: 6, + }, + system_fingerprint: expect.any(String), + }); + }); + + test('streaming response without include_usage', async () => { + const testOpenAIChat = makeMockOpenAIChat(mockResponse); + const stream = (await testOpenAIChat({ + messages: [{role: 'user', content: 'Hello, AI!'}], + stream: true, + })) as AsyncIterable; + + let chunks = []; + for await (const chunk of stream) { + chunks.push(chunk); + } + + expect(chunks.length).toBeGreaterThan(1); + expect(chunks[0]).toEqual({ + id: expect.any(String), + object: 'chat.completion.chunk', + created: expect.any(Number), + model: 'gpt-4o-2024-05-13', + system_fingerprint: expect.any(String), + choices: [ + { + index: 0, + delta: {role: 'assistant', content: '', refusal: null}, + logprobs: null, + finish_reason: null, + }, + ], + }); + expect(chunks[chunks.length - 1]).toEqual({ + id: expect.any(String), + object: 'chat.completion.chunk', + created: expect.any(Number), + model: 'gpt-4o-2024-05-13', + system_fingerprint: expect.any(String), + choices: [ + { + index: 0, + delta: {}, + logprobs: null, + finish_reason: 'function_call', + }, + ], + }); + expect(chunks.every(chunk => !('usage' in chunk))).toBe(true); + }); + + test('streaming response with include_usage', async () => { + const testOpenAIChat = makeMockOpenAIChat(mockResponse); + const stream = (await testOpenAIChat({ + messages: [{role: 'user', content: 'Hello, AI!'}], + stream: true, + stream_options: {include_usage: true}, + })) as AsyncIterable; + + let chunks = []; + for await (const chunk of stream) { + chunks.push(chunk); + } + + expect(chunks.length).toBeGreaterThan(1); + expect(chunks[0]).toEqual({ + id: expect.any(String), + object: 'chat.completion.chunk', + created: expect.any(Number), + model: 'gpt-4o-2024-05-13', + system_fingerprint: expect.any(String), + choices: [ + { + index: 0, + delta: {role: 'assistant', content: '', refusal: null}, + logprobs: null, + finish_reason: null, + }, + ], + usage: null, + }); + expect(chunks[chunks.length - 2]).toEqual({ + id: expect.any(String), + object: 'chat.completion.chunk', + created: expect.any(Number), + model: 'gpt-4o-2024-05-13', + system_fingerprint: expect.any(String), + choices: [ + { + index: 0, + delta: {}, + logprobs: null, + finish_reason: 'function_call', + }, + ], + usage: null, + }); + expect(chunks[chunks.length - 1]).toEqual({ + id: expect.any(String), + object: 'chat.completion.chunk', + created: expect.any(Number), + model: 'gpt-4o-2024-05-13', + system_fingerprint: expect.any(String), + choices: [], + usage: { + prompt_tokens: 2, + completion_tokens: 4, + total_tokens: 6, + }, + }); + expect(chunks.slice(0, -1).every(chunk => chunk.usage === null)).toBe(true); + }); +}); diff --git a/sdks/node/src/__tests__/live/dataset.test.ts b/sdks/node/src/__tests__/live/dataset.test.ts new file mode 100644 index 00000000000..e2b87f215e8 --- /dev/null +++ b/sdks/node/src/__tests__/live/dataset.test.ts @@ -0,0 +1,39 @@ +import {init, login} from '../../clientApi'; +import {Dataset} from '../../dataset'; + +describe('Dataset', () => { + beforeEach(async () => { + await login({apiKey: process.env.WANDB_API_KEY ?? ''}); + }); + + test('should save a dataset', async () => { + const client = await init('test-project'); + const data = [ + {id: 1, value: 2}, + {id: 2, value: 3}, + {id: 3, value: 4}, + ]; + + const dataset = new Dataset({rows: data}); + const ref = await dataset.save(); + + const [entity, project] = ref.projectId.split('/') ?? []; + expect(project).toBe('test-project'); + + // Dataset has same rows as the original data + expect(dataset.length).toBe(3); + + // TODO: idk why this fails in CI + // let i = 0; + // for await (const row of dataset) { + // expect(row).toEqual(data[i]); + // const rowRef = await row?.__savedRef; + // const [rowEntity, rowProject] = rowRef?.projectId.split('/') ?? []; + + // // Rows have refs back to the table + // expect(rowProject).toBe('test-project'); + // expect(rowRef?.digest).toBe(ref.digest); + // i++; + // } + }); +}); diff --git a/sdks/node/src/__tests__/live/fn.test.ts b/sdks/node/src/__tests__/live/fn.test.ts new file mode 100644 index 00000000000..20488144d89 --- /dev/null +++ b/sdks/node/src/__tests__/live/fn.test.ts @@ -0,0 +1,42 @@ +import {init, login} from '../../clientApi'; +import {CallableObject} from '../../fn'; +import {op} from '../../op'; +import {WeaveObjectParameters} from '../../weaveObject'; + +interface ParametrizedFunctionOptions extends WeaveObjectParameters { + magicNumber?: number; +} + +class ParametrizedFunction extends CallableObject< + {input: number}, + {output: number} +> { + private magicNumber: number; + + constructor(options: ParametrizedFunctionOptions = {}) { + super(options); + this.magicNumber = options.magicNumber ?? 42; + + this.run = op(this, this.run, { + parameterNames: ['input'], + }); + } + + async run(input: {input: number}): Promise<{output: number}> { + return {output: input.input + this.magicNumber}; + } +} + +describe('Fn', () => { + beforeEach(async () => { + await login({apiKey: process.env.WANDB_API_KEY ?? ''}); + }); + + test('use fn', async () => { + const client = await init('test-project'); + + const fn = new ParametrizedFunction({magicNumber: 7}); + const res = await fn.run({input: 1}); + expect(res).toEqual({output: 8}); + }); +}); diff --git a/sdks/node/src/__tests__/live/publish.test.ts b/sdks/node/src/__tests__/live/publish.test.ts new file mode 100644 index 00000000000..67edc1b5066 --- /dev/null +++ b/sdks/node/src/__tests__/live/publish.test.ts @@ -0,0 +1,83 @@ +import {init, login} from '../../clientApi'; +import {Dataset, op, weaveAudio, weaveImage} from '../../index'; + +describe('Publishing Various Data Types', () => { + beforeEach(async () => { + await login({apiKey: process.env.WANDB_API_KEY ?? ''}); + }); + + const primitiveOp = op(async function primitive(input: string) { + return `Hi ${input}!`; + }); + + const jsonOp = op(async function json(name: string, age: number) { + return {name, age}; + }); + + const imageOp = op(async function image() { + const width = 16; + const height = 16; + const buffer = Buffer.alloc(width * height * 4); // 4 bytes per pixel (RGBA) + + for (let i = 0; i < buffer.length; i++) { + buffer[i] = Math.floor(Math.random() * 256); + } + + return weaveImage({ + data: buffer, + imageType: 'png', + }); + }); + + const audioOp = op(async function audio() { + // Create a small audio buffer with random samples + const sampleRate = 44100; // Standard CD quality + const duration = 0.1; // 100ms + const numSamples = Math.floor(sampleRate * duration); + const buffer = Buffer.alloc(numSamples * 2); // 2 bytes per sample for 16-bit audio + + for (let i = 0; i < buffer.length; i += 2) { + // Generate random 16-bit sample between -32768 and 32767 + const sample = Math.floor(Math.random() * 65536 - 32768); + buffer.writeInt16LE(sample, i); + } + + return weaveAudio({ + data: buffer, + audioType: 'wav', + }); + }); + + const datasetOp = op(async function dataset() { + return new Dataset({ + id: 'my-dataset', + rows: [ + {name: 'Alice', age: 10}, + {name: 'Bob', age: 20}, + {name: 'Charlie', age: 30}, + ], + }); + }); + + test('publish various data types', async () => { + const client = await init('test-project'); + + const primitiveResult = await primitiveOp('world'); + expect(primitiveResult).toBe('Hi world!'); + + const jsonResult = await jsonOp('Alice', 10); + expect(jsonResult).toEqual({name: 'Alice', age: 10}); + + const imageResult = await imageOp(); + expect(imageResult).toHaveProperty('data'); + expect(imageResult).toHaveProperty('imageType', 'png'); + + const audioResult = await audioOp(); + expect(audioResult).toHaveProperty('data'); + expect(audioResult).toHaveProperty('audioType', 'wav'); + + const datasetResult = await datasetOp(); + expect(datasetResult).toBeInstanceOf(Dataset); + expect(datasetResult.rows).toHaveLength(3); + }); +}); diff --git a/sdks/node/src/__tests__/live/table.test.ts b/sdks/node/src/__tests__/live/table.test.ts new file mode 100644 index 00000000000..b5a02360b53 --- /dev/null +++ b/sdks/node/src/__tests__/live/table.test.ts @@ -0,0 +1,43 @@ +import {init, login} from '../../clientApi'; +import {Table} from '../../table'; + +describe('table', () => { + beforeEach(async () => { + await login({apiKey: process.env.WANDB_API_KEY ?? ''}); + }); + + test('example', async () => { + // Table behaves like a container of rows + const rows = [ + {a: 1, b: 2}, + {a: 3, b: 4}, + {a: 5, b: 6}, + ]; + + const table = new Table(rows); + expect(table.length).toEqual(rows.length); + let i = 0; + for await (const row of table) { + expect(row).toEqual(rows[i]); + i++; + } + + // Saving the table generates refs for the table and its rows + const client = await init('test-project'); + + (client as any).saveTable(table); // TODO: Saving a Table is not public... but maybe it should be? + const ref = await table.__savedRef; + + // not sure how to test entity here + // test that the ref is for the right entity, project + const [entity, project] = ref?.projectId.split('/') ?? []; + expect(project).toEqual('test-project'); + expect(ref?.uri()).toContain('test-project'); + + const row = table.row(0); + const ref2 = await (row as any).__savedRef; // TODO: This seems wrong... you have to cast to get the ref? I guess users would rarely do this... + const [entity2, project2, digest2] = ref2?.projectId.split('/') ?? []; + expect(project2).toEqual('test-project'); + expect(ref2?.uri()).toContain('test-project'); + }); +}); diff --git a/sdks/node/src/__tests__/live/weaveObject.test.ts b/sdks/node/src/__tests__/live/weaveObject.test.ts new file mode 100644 index 00000000000..fdf48ab95eb --- /dev/null +++ b/sdks/node/src/__tests__/live/weaveObject.test.ts @@ -0,0 +1,48 @@ +import {init, login} from '../../clientApi'; +import {op} from '../../op'; +import {WeaveObject} from '../../weaveObject'; + +class ExampleObject extends WeaveObject { + constructor( + public name: string, + public value: number + ) { + super({}); + + this.method = op(this.method); + } + + async method() { + return this.name + '!'; + } +} + +describe('weaveObject', () => { + beforeEach(async () => { + await login({apiKey: process.env.WANDB_API_KEY ?? ''}); + }); + + test('basic-example', async () => { + // TODO: Do we support saving basic objects? + // const client = await init('test-project'); + // const obj = { name: 'test', value: 1 }; + // client.saveObject(obj as any); + // const ref = await (obj as any).__savedRef; + // console.log(ref); + }); + + test('class-example', async () => { + const client = await init('test-project'); + const obj = new ExampleObject('test', 1); + + // save an object + client.publish(obj); + + const ref = await obj.__savedRef; + const [entity, project] = ref?.projectId.split('/') ?? []; + expect(project).toBe('test-project'); + console.log(ref); + + // also save its ops + }); +}); diff --git a/sdks/node/src/__tests__/login.test.ts b/sdks/node/src/__tests__/login.test.ts new file mode 100644 index 00000000000..8bdfcb19cfa --- /dev/null +++ b/sdks/node/src/__tests__/login.test.ts @@ -0,0 +1,70 @@ +import {login} from '../clientApi'; +import {Api as TraceServerApi} from '../generated/traceServerApi'; +import {getUrls} from '../urls'; +import {Netrc} from '../utils/netrc'; + +// Mock dependencies +jest.mock('../utils/netrc'); +jest.mock('../urls'); +jest.mock('../generated/traceServerApi'); + +describe('login', () => { + beforeEach(() => { + jest.clearAllMocks(); + console.log = jest.fn(); // Mock console.log + }); + + it('should successfully log in and save credentials', async () => { + (getUrls as jest.Mock).mockReturnValue({ + traceBaseUrl: 'https://api.wandb.ai', + domain: 'wandb.ai', + }); + + const mockSetEntry = jest.fn(); + const mockSave = jest.fn(); + (Netrc as jest.Mock).mockImplementation(() => ({ + setEntry: mockSetEntry, + save: mockSave, + })); + + (TraceServerApi as jest.Mock).mockImplementation(() => ({ + health: { + readRootHealthGet: jest.fn().mockResolvedValue({}), + }, + })); + + await login({apiKey: 'test-api-key'}); + + expect(mockSetEntry).toHaveBeenCalledWith('wandb.ai', { + login: 'user', + password: 'test-api-key', + }); + expect(mockSave).toHaveBeenCalled(); + expect(console.log).toHaveBeenCalledWith( + 'Successfully logged in. Credentials saved for wandb.ai' + ); + }); + + it('should throw an error if API key is not provided', async () => { + await expect(login()).rejects.toThrow('API Key must be specified'); + }); + + it('should throw an error if connection verification fails', async () => { + (getUrls as jest.Mock).mockReturnValue({ + traceBaseUrl: 'https://api.wandb.ai', + domain: 'wandb.ai', + }); + + (TraceServerApi as jest.Mock).mockImplementation(() => ({ + health: { + readRootHealthGet: jest + .fn() + .mockRejectedValue(new Error('Connection failed')), + }, + })); + + await expect(login({apiKey: 'test-api-key'})).rejects.toThrow( + 'Unable to verify connection to the weave trace server with given API Key' + ); + }); +}); diff --git a/sdks/node/src/__tests__/media.test.ts b/sdks/node/src/__tests__/media.test.ts new file mode 100644 index 00000000000..84c96833314 --- /dev/null +++ b/sdks/node/src/__tests__/media.test.ts @@ -0,0 +1,21 @@ +import {weaveAudio, weaveImage} from '../media'; + +describe('media', () => { + test('logging weaveImage', () => { + const imageBuffer = Buffer.from('mock image data'); + const image = weaveImage({data: imageBuffer}); + + expect(image).toHaveProperty('_weaveType', 'Image'); + expect(image).toHaveProperty('data', imageBuffer); + expect(image).toHaveProperty('imageType', 'png'); + }); + + test('logging weaveAudio', () => { + const audioBuffer = Buffer.from('mock audio data'); + const audio = weaveAudio({data: audioBuffer}); + + expect(audio).toHaveProperty('_weaveType', 'Audio'); + expect(audio).toHaveProperty('data', audioBuffer); + expect(audio).toHaveProperty('audioType', 'wav'); + }); +}); diff --git a/sdks/node/src/__tests__/opFlow.test.ts b/sdks/node/src/__tests__/opFlow.test.ts new file mode 100644 index 00000000000..39f5d872cd0 --- /dev/null +++ b/sdks/node/src/__tests__/opFlow.test.ts @@ -0,0 +1,354 @@ +import {InMemoryTraceServer} from '../inMemoryTraceServer'; +import {makeOpenAIChatCompletionsOp} from '../integrations/openai'; +import {op} from '../op'; +import {initWithCustomTraceServer} from './clientMock'; +import {makeMockOpenAIChat} from './openaiMock'; + +// Helper function to get calls +async function getCalls( + traceServer: InMemoryTraceServer, + projectId: string, + limit?: number, + filters?: any +) { + return traceServer.calls + .callsStreamQueryPost({ + project_id: projectId, + limit, + filters, + }) + .then(result => result.calls); +} + +describe('Op Flow', () => { + let inMemoryTraceServer: InMemoryTraceServer; + const testProjectName = 'test-project'; + + beforeEach(() => { + inMemoryTraceServer = new InMemoryTraceServer(); + initWithCustomTraceServer(testProjectName, inMemoryTraceServer); + }); + + test('end-to-end op flow', async () => { + // Create an inner op + const innerOp = op((x: number) => x * 2, {name: 'innerOp'}); + + // Create an outer op that calls the inner op + const outerOp = op( + async (x: number) => { + const result1 = await innerOp(x); + const result2 = await innerOp(result1); + return result2; + }, + {name: 'outerOp'} + ); + + // Call the outer op a couple of times + await outerOp(5); + await outerOp(10); + + // Wait for any pending batch processing + await new Promise(resolve => setTimeout(resolve, 300)); + + // Fetch the logged calls using the helper function + const calls = await getCalls(inMemoryTraceServer, testProjectName); + + // Assertions + expect(calls).toHaveLength(6); // 2 outer calls + 4 inner calls + + const outerCalls = calls.filter(call => call.op_name.includes('outerOp')); + const innerCalls = calls.filter(call => call.op_name.includes('innerOp')); + + expect(outerCalls).toHaveLength(2); + expect(innerCalls).toHaveLength(4); + + // Check the first outer call + expect(outerCalls[0].inputs).toEqual({arg0: 5}); + expect(outerCalls[0].output).toBe(20); + + // Check the second outer call + expect(outerCalls[1].inputs).toEqual({arg0: 10}); + expect(outerCalls[1].output).toBe(40); + + // Check that inner calls have correct parent_id + innerCalls.forEach(innerCall => { + expect( + outerCalls.some(outerCall => outerCall.id === innerCall.parent_id) + ).toBeTruthy(); + }); + + // Check that all calls have a trace_id + calls.forEach(call => { + expect(call.trace_id).toBeTruthy(); + }); + }); + + test('end-to-end async op flow with concurrency', async () => { + // Create an inner async op with a random delay + const innerAsyncOp = op( + async (x: number) => { + const delay = Math.random() * 50 + 10; // Random delay between 10-60ms + await new Promise(resolve => setTimeout(resolve, delay)); + return x * 2; + }, + {name: 'innerAsyncOp'} + ); + + // Create an outer async op that calls the inner async op + const outerAsyncOp = op( + async (x: number) => { + const result1 = await innerAsyncOp(x); + const result2 = await innerAsyncOp(result1); + return result2; + }, + {name: 'outerAsyncOp'} + ); + + // Call the outer async op concurrently with a small delay between calls + const [result1, result2] = await Promise.all([ + outerAsyncOp(5), + (async () => { + await new Promise(resolve => setTimeout(resolve, 5)); // 5ms delay + return outerAsyncOp(10); + })(), + ]); + + // Wait for any pending batch processing + await new Promise(resolve => setTimeout(resolve, 300)); + + // Fetch the logged calls using the helper function + const calls = await getCalls(inMemoryTraceServer, testProjectName); + + // Assertions + expect(calls).toHaveLength(6); // 2 outer calls + 4 inner calls + expect(result1).toBe(20); + expect(result2).toBe(40); + + const outerCalls = calls.filter(call => + call.op_name.includes('outerAsyncOp') + ); + const innerCalls = calls.filter(call => + call.op_name.includes('innerAsyncOp') + ); + + expect(outerCalls).toHaveLength(2); + expect(innerCalls).toHaveLength(4); + + // Check that outer calls have different start times + const outerStartTimes = outerCalls.map(call => + new Date(call.started_at).getTime() + ); + expect(outerStartTimes[0]).not.toBe(outerStartTimes[1]); + + // Check that inner calls have correct parent_id + innerCalls.forEach(innerCall => { + expect( + outerCalls.some(outerCall => outerCall.id === innerCall.parent_id) + ).toBeTruthy(); + }); + + // Check that all calls have a trace_id + calls.forEach(call => { + expect(call.trace_id).toBeTruthy(); + }); + + // Check that the duration of async calls is greater than 0 + calls.forEach(call => { + const duration = + new Date(call.ended_at!).getTime() - + new Date(call.started_at).getTime(); + expect(duration).toBeGreaterThan(0); + }); + + // Check that the calls are properly nested + outerCalls.forEach(outerCall => { + const outerStartTime = new Date(outerCall.started_at).getTime(); + const outerEndTime = new Date(outerCall.ended_at!).getTime(); + const relatedInnerCalls = innerCalls.filter( + innerCall => innerCall.parent_id === outerCall.id + ); + expect(relatedInnerCalls).toHaveLength(2); + relatedInnerCalls.forEach(innerCall => { + const innerStartTime = new Date(innerCall.started_at).getTime(); + const innerEndTime = new Date(innerCall.ended_at!).getTime(); + expect(innerStartTime).toBeGreaterThanOrEqual(outerStartTime); + expect(innerEndTime).toBeLessThanOrEqual(outerEndTime); + }); + }); + }); + + test('op with custom summary', async () => { + const customSummaryOp = op((x: number) => x * 2, { + name: 'customSummaryOp', + summarize: result => ({doubledValue: result}), + }); + + await customSummaryOp(5); + + // Wait for any pending batch processing + await new Promise(resolve => setTimeout(resolve, 300)); + + const calls = await getCalls(inMemoryTraceServer, testProjectName); + + expect(calls).toHaveLength(1); + expect(calls[0].op_name).toContain('customSummaryOp'); + expect(calls[0].inputs).toEqual({arg0: 5}); + expect(calls[0].output).toBe(10); + expect(calls[0].summary).toEqual({doubledValue: 10}); + }); + + test('openai-like op with token usage summary', async () => { + const testOpenAIChat = makeMockOpenAIChat(messages => ({ + content: messages[0].content.toUpperCase(), + })); + + const openaiLikeOp = makeOpenAIChatCompletionsOp( + testOpenAIChat, + 'testOpenAIChat' + ); + + await openaiLikeOp({messages: [{role: 'user', content: 'Hello, AI!'}]}); + + // Wait for any pending batch processing + await new Promise(resolve => setTimeout(resolve, 300)); + + const calls = await getCalls(inMemoryTraceServer, testProjectName); + + expect(calls).toHaveLength(1); + expect(calls[0].op_name).toContain('testOpenAIChat'); + expect(calls[0].inputs).toEqual({ + messages: [{role: 'user', content: 'Hello, AI!'}], + }); + expect(calls[0].output).toEqual({ + id: expect.any(String), + object: 'chat.completion', + created: expect.any(Number), + model: 'gpt-4o-2024-05-13', + choices: [ + { + index: 0, + message: { + role: 'assistant', + content: 'HELLO, AI!', + function_call: null, + refusal: null, + }, + logprobs: null, + finish_reason: 'stop', + }, + ], + usage: { + prompt_tokens: 2, + completion_tokens: 2, + total_tokens: 4, + }, + system_fingerprint: expect.any(String), + }); + expect(calls[0].summary).toEqual({ + usage: { + 'gpt-4o-2024-05-13': { + requests: 1, + completion_tokens: 2, + prompt_tokens: 2, + total_tokens: 4, + }, + }, + }); + }); + + test('nested op calls with summaries', async () => { + const leafOp = op((x: number) => x, { + name: 'leafOp', + summarize: result => ({leaf: {count: 1, sum: result}}), + }); + + const midOp = op( + async (x: number, y: number) => { + const [res1, res2] = await Promise.all([leafOp(x), leafOp(y)]); + return res1 + res2; + }, + { + name: 'midOp', + summarize: result => ({mid: {count: 1, sum: result}}), + } + ); + + const rootOp = op( + async (a: number, b: number, c: number) => { + const [res1, res2] = await Promise.all([midOp(a, b), leafOp(c)]); + return res1 + res2; + }, + { + name: 'rootOp', + summarize: result => ({root: {count: 1, sum: result}}), + } + ); + + await rootOp(1, 2, 3); + + // Wait for any pending batch processing + await new Promise(resolve => setTimeout(resolve, 300)); + + const calls = await getCalls(inMemoryTraceServer, testProjectName); + + expect(calls).toHaveLength(5); // 1 root + 1 mid + 3 leaf calls + + const rootCall = calls.find(call => call.op_name.includes('rootOp')); + expect(rootCall).toBeDefined(); + expect(rootCall?.summary).toEqual({ + root: {count: 1, sum: 6}, + mid: {count: 1, sum: 3}, + leaf: {count: 3, sum: 6}, // This is correct: 3 leaf calls, sum of 1+2+3 + }); + + const midCall = calls.find(call => call.op_name.includes('midOp')); + expect(midCall).toBeDefined(); + expect(midCall?.summary).toEqual({ + mid: {count: 1, sum: 3}, + leaf: {count: 2, sum: 3}, // This is correct: 2 leaf calls within midOp, sum of 1+2 + }); + + const leafCalls = calls.filter(call => call.op_name.includes('leafOp')); + expect(leafCalls).toHaveLength(3); + + const leafCallsUnderMid = leafCalls.filter( + call => call.parent_id === midCall?.id + ); + const leafCallUnderRoot = leafCalls.find( + call => call.parent_id === rootCall?.id + ); + + expect(leafCallsUnderMid).toEqual( + expect.arrayContaining([ + expect.objectContaining({summary: {leaf: {count: 1, sum: 1}}}), + expect.objectContaining({summary: {leaf: {count: 1, sum: 2}}}), + ]) + ); + expect(leafCallsUnderMid).toHaveLength(2); + + expect(leafCallUnderRoot).toEqual( + expect.objectContaining({summary: {leaf: {count: 1, sum: 3}}}) + ); + + // Ensure we have exactly these three summaries + expect(leafCalls).toHaveLength(3); + + // Check parent-child relationships + expect(midCall?.parent_id).toBe(rootCall?.id); + expect(leafCallsUnderMid).toHaveLength(2); + expect(leafCallUnderRoot).toBeDefined(); + + // Ensure all leaf calls have either midCall or rootCall as parent + leafCalls.forEach(call => { + expect( + call.parent_id === midCall?.id || call.parent_id === rootCall?.id + ).toBeTruthy(); + }); + + // Check that all calls have the same trace_id + const traceId = rootCall?.trace_id; + calls.forEach(call => { + expect(call.trace_id).toBe(traceId); + }); + }); +}); diff --git a/sdks/node/src/__tests__/openaiMock.ts b/sdks/node/src/__tests__/openaiMock.ts new file mode 100644 index 00000000000..cec6b39dbbb --- /dev/null +++ b/sdks/node/src/__tests__/openaiMock.ts @@ -0,0 +1,217 @@ +function generateId() { + return 'chatcmpl-' + Math.random().toString(36).substr(2, 9); +} + +function generateSystemFingerprint() { + return 'fp_' + Math.random().toString(36).substr(2, 9); +} + +type FunctionCall = { + name: string; + arguments: Record; +}; + +type ResponseFn = (messages: any[]) => { + content: string; + functionCalls?: FunctionCall[]; +}; + +// Simple function to estimate token count +function estimateTokenCount(text: string): number { + return Math.ceil(text.split(/\s+/).length); // 1 token per word for testing +} + +export function makeMockOpenAIChat(responseFn: ResponseFn) { + return function openaiChatCompletionsCreate({ + messages, + stream = false, + model = 'gpt-4o-2024-05-13', + stream_options, + ...otherOptions + }: { + messages: any[]; + stream?: boolean; + model?: string; + stream_options?: {include_usage?: boolean}; + [key: string]: any; + }) { + const response = responseFn(messages); + const {content, functionCalls = []} = response; + + const promptTokens = messages.reduce( + (acc, msg) => acc + estimateTokenCount(msg.content), + 0 + ); + const completionTokens = + estimateTokenCount(content) + + functionCalls.reduce( + (acc, fc) => + acc + + estimateTokenCount(fc.name) + + estimateTokenCount(JSON.stringify(fc.arguments)), + 0 + ); + const totalTokens = promptTokens + completionTokens; + + if (stream) { + return { + [Symbol.asyncIterator]: async function* () { + yield* generateChunks( + content, + functionCalls, + model, + promptTokens, + completionTokens, + totalTokens, + stream_options + ); + }, + }; + } else { + return { + id: generateId(), + object: 'chat.completion', + created: Math.floor(Date.now() / 1000), + model: model, + choices: [ + { + index: 0, + message: { + role: 'assistant', + content: content, + function_call: functionCalls[0] + ? { + name: functionCalls[0].name, + arguments: JSON.stringify(functionCalls[0].arguments), + } + : null, + refusal: null, + }, + logprobs: null, + finish_reason: functionCalls.length > 0 ? 'function_call' : 'stop', + }, + ], + usage: { + prompt_tokens: promptTokens, + completion_tokens: completionTokens, + total_tokens: totalTokens, + }, + system_fingerprint: generateSystemFingerprint(), + }; + } + }; +} + +function* generateChunks( + content: string, + functionCalls: FunctionCall[], + model: string, + promptTokens: number, + completionTokens: number, + totalTokens: number, + stream_options?: {include_usage?: boolean} +) { + const id = generateId(); + const systemFingerprint = generateSystemFingerprint(); + const created = Math.floor(Date.now() / 1000); + + const baseChunk = { + id, + object: 'chat.completion.chunk', + created, + model, + system_fingerprint: systemFingerprint, + }; + + const includeUsage = stream_options?.include_usage; + + // Initial chunk + yield { + ...baseChunk, + choices: [ + { + index: 0, + delta: {role: 'assistant', content: '', refusal: null}, + logprobs: null, + finish_reason: null, + }, + ], + ...(includeUsage && {usage: null}), + }; + + // Content chunks + const words = content.split(' '); + for (let i = 0; i < words.length; i++) { + yield { + ...baseChunk, + choices: [ + { + index: 0, + delta: {content: words[i] + (i < words.length - 1 ? ' ' : '')}, + logprobs: null, + finish_reason: null, + }, + ], + ...(includeUsage && {usage: null}), + }; + } + + // Function call chunks + for (const functionCall of functionCalls) { + yield { + ...baseChunk, + choices: [ + { + index: 0, + delta: {function_call: {name: functionCall.name, arguments: ''}}, + logprobs: null, + finish_reason: null, + }, + ], + ...(includeUsage && {usage: null}), + }; + + const args = JSON.stringify(functionCall.arguments); + for (let i = 0; i < args.length; i += 10) { + yield { + ...baseChunk, + choices: [ + { + index: 0, + delta: {function_call: {arguments: args.slice(i, i + 10)}}, + logprobs: null, + finish_reason: null, + }, + ], + ...(includeUsage && {usage: null}), + }; + } + } + + // Second to last chunk (finish_reason) + yield { + ...baseChunk, + choices: [ + { + index: 0, + delta: {}, + logprobs: null, + finish_reason: functionCalls.length > 0 ? 'function_call' : 'stop', + }, + ], + ...(includeUsage && {usage: null}), + }; + + // Final chunk with usage information (only if include_usage is true) + if (includeUsage) { + yield { + ...baseChunk, + choices: [], + usage: { + prompt_tokens: promptTokens, + completion_tokens: completionTokens, + total_tokens: totalTokens, + }, + }; + } +} diff --git a/sdks/node/src/__tests__/util/concurrentLimit.test.ts b/sdks/node/src/__tests__/util/concurrentLimit.test.ts new file mode 100644 index 00000000000..8b0b518f044 --- /dev/null +++ b/sdks/node/src/__tests__/util/concurrentLimit.test.ts @@ -0,0 +1,30 @@ +import {ConcurrencyLimiter} from '../../utils/concurrencyLimit'; + +describe('concurrency limiting', () => { + test('it works', async () => { + const limit = 2; + const numJobs = 10; + + const limiter = new ConcurrencyLimiter(limit); + let currentlyRunning = 0; + let maxConcurrent = 0; + + const mockJob = jest.fn(async () => { + currentlyRunning++; + expect(currentlyRunning).toBe(limiter.active); + maxConcurrent = Math.max(maxConcurrent, currentlyRunning); + await new Promise(resolve => setTimeout(resolve, 100)); + currentlyRunning--; + }); + + const limitedJob = limiter.limitFunction(mockJob); + + const promises = []; + for (let i = 0; i < numJobs; i++) { + promises.push(limitedJob()); + } + await Promise.all(promises); + + expect(maxConcurrent).toBeLessThanOrEqual(limit); + }); +}); diff --git a/sdks/node/src/__tests__/util/netrc.test.ts b/sdks/node/src/__tests__/util/netrc.test.ts new file mode 100644 index 00000000000..59d01538187 --- /dev/null +++ b/sdks/node/src/__tests__/util/netrc.test.ts @@ -0,0 +1,99 @@ +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import {Netrc} from '../../utils/netrc'; + +jest.mock('fs'); +jest.mock('os'); + +describe('Netrc', () => { + const mockHomedir = '/mock/home'; + const mockNetrcPath = path.join(mockHomedir, '.netrc'); + + beforeEach(() => { + jest.resetAllMocks(); + (os.homedir as jest.Mock).mockReturnValue(mockHomedir); + }); + + test('load parses netrc file correctly', () => { + const mockContent = ` + machine example.com + login user1 + password pass1 + machine api.example.com + login user2 + password pass2 + account acc2 + `; + (fs.readFileSync as jest.Mock).mockReturnValue(mockContent); + + const netrc = new Netrc(); + + expect(netrc.entries.size).toBe(2); + expect(netrc.getEntry('example.com')).toEqual({ + machine: 'example.com', + login: 'user1', + password: 'pass1', + }); + expect(netrc.getEntry('api.example.com')).toEqual({ + machine: 'api.example.com', + login: 'user2', + password: 'pass2', + account: 'acc2', + }); + }); + + test('load handles non-existent file', () => { + (fs.readFileSync as jest.Mock).mockImplementation(() => { + throw new Error('File not found'); + }); + + const netrc = new Netrc(); + expect(netrc.entries.size).toBe(0); + }); + + test('save writes entries correctly', () => { + const netrc = new Netrc(); + netrc.setEntry('example.com', {login: 'user1', password: 'pass1'}); + netrc.setEntry('api.example.com', { + login: 'user2', + password: 'pass2', + account: 'acc2', + }); + + netrc.save(); + + const expectedContent = `machine example.com + login user1 + password pass1 + +machine api.example.com + login user2 + password pass2 + account acc2 +`; + + expect(fs.writeFileSync).toHaveBeenCalledWith( + mockNetrcPath, + expectedContent, + {mode: 0o600} + ); + }); + + test('getLastEntry returns the last entry', () => { + const netrc = new Netrc(); + netrc.setEntry('example1.com', {login: 'user1', password: 'pass1'}); + netrc.setEntry('example2.com', {login: 'user2', password: 'pass2'}); + + expect(netrc.getLastEntry()).toEqual({ + machine: 'example2.com', + login: 'user2', + password: 'pass2', + }); + }); + + test('getLastEntry returns undefined for empty entries', () => { + const netrc = new Netrc(); + expect(netrc.getLastEntry()).toBeUndefined(); + }); +}); diff --git a/sdks/node/src/__tests__/util/retry.test.ts b/sdks/node/src/__tests__/util/retry.test.ts new file mode 100644 index 00000000000..1216c7c87cd --- /dev/null +++ b/sdks/node/src/__tests__/util/retry.test.ts @@ -0,0 +1,65 @@ +import {createFetchWithRetry} from '../../utils/retry'; + +describe('retry', () => { + let originalFetch: typeof global.fetch; + const mockSuccess = {ok: true, status: 200} as Response; + const mockFailure = {ok: false, status: 404} as Response; + const baseDelay = 2; + + beforeEach(() => { + originalFetch = global.fetch; + }); + + afterEach(() => { + jest.resetAllMocks(); + global.fetch = originalFetch; + }); + + test('fetch happy path', async () => { + const mockFetch = jest.fn(() => Promise.resolve(mockSuccess)); + global.fetch = mockFetch; + const fetchWithRetry = createFetchWithRetry({baseDelay}); + + const response = await fetchWithRetry('https://api.test.com'); + expect(response).toEqual(mockSuccess); + }); + + test('fetch intermittent failure then success', async () => { + const mockFetch = jest + .fn() + .mockResolvedValueOnce(mockFailure) + .mockResolvedValueOnce(mockFailure) + .mockResolvedValue(mockSuccess); + global.fetch = mockFetch; + const fetchWithRetry = createFetchWithRetry({baseDelay}); + + const response = await fetchWithRetry('https://api.test.com'); + expect(mockFetch).toHaveBeenCalledTimes(3); + expect(response).toEqual(mockSuccess); + }); + + test('fetch retry failure', async () => { + const maxRetries = 3; + + const mockFetch = jest.fn().mockResolvedValue(mockFailure); + global.fetch = mockFetch; + const fetchWithRetry = createFetchWithRetry({maxRetries, baseDelay}); + + const response = await fetchWithRetry('https://api.test.com'); + expect(mockFetch).toHaveBeenCalledTimes(maxRetries + 1); + expect(response).toEqual(mockFailure); + }); + + test('fetch exception then success', async () => { + const mockFetch = jest + .fn() + .mockRejectedValueOnce(new Error('test')) + .mockResolvedValue(mockSuccess); + global.fetch = mockFetch; + const fetchWithRetry = createFetchWithRetry({baseDelay}); + + const response = await fetchWithRetry('https://api.test.com'); + expect(mockFetch).toHaveBeenCalledTimes(2); + expect(response).toEqual(mockSuccess); + }); +}); diff --git a/sdks/node/src/__tests__/wandb/settings.test.ts b/sdks/node/src/__tests__/wandb/settings.test.ts new file mode 100644 index 00000000000..22b2f6c1b85 --- /dev/null +++ b/sdks/node/src/__tests__/wandb/settings.test.ts @@ -0,0 +1,81 @@ +import {Netrc} from '../../utils/netrc'; +import {getApiKey, getWandbConfigs} from '../../wandb/settings'; + +jest.mock('../../utils/netrc'); +const MockedNetrc = Netrc as jest.MockedClass; + +describe('settings', () => { + beforeEach(() => { + jest.clearAllMocks(); + delete process.env.WANDB_API_KEY; + }); + + describe('getApiKey', () => { + it('returns API key from environment variable', () => { + process.env.WANDB_API_KEY = 'test-api-key'; + expect(getApiKey('api.wandb.ai')).toBe('test-api-key'); + }); + + it('returns API key from netrc file', () => { + MockedNetrc.prototype.entries = new Map([ + [ + 'api.wandb.ai', + {machine: 'api.wandb.ai', login: 'user', password: 'netrc-api-key'}, + ], + ]); + expect(getApiKey('api.wandb.ai')).toBe('netrc-api-key'); + }); + + it('throws error when no API key is found', () => { + MockedNetrc.prototype.entries = new Map(); + expect(() => getApiKey('api.wandb.ai')).toThrow( + 'wandb API key not found' + ); + }); + }); + + describe('getWandbConfigs', () => { + it('returns correct config when netrc has entry', () => { + // Mock successful netrc entry + MockedNetrc.prototype.getLastEntry = jest.fn().mockReturnValue({ + machine: 'api.wandb.ai', + login: 'user', + password: 'test-api-key', + }); + MockedNetrc.prototype.entries = new Map([ + [ + 'api.wandb.ai', + {machine: 'api.wandb.ai', login: 'user', password: 'test-api-key'}, + ], + ]); + + const configs = getWandbConfigs(); + expect(configs).toEqual({ + apiKey: 'test-api-key', + baseUrl: expect.stringContaining('api.wandb.ai'), + traceBaseUrl: expect.stringContaining('https://trace.wandb.ai'), + domain: expect.any(String), + }); + }); + + it('throws error when no netrc entry is found', () => { + // Mock netrc with no entries + MockedNetrc.prototype.getLastEntry = jest.fn().mockReturnValue(null); + + expect(() => getWandbConfigs()).toThrow( + 'Could not find entry in netrc file' + ); + }); + + it('throws error when netrc throws error', () => { + // Mock netrc throwing error + MockedNetrc.prototype.getLastEntry = jest.fn().mockImplementation(() => { + throw new Error('Failed to read netrc'); + }); + + expect(() => getWandbConfigs()).toThrow( + 'Could not find entry in netrc file' + ); + }); + }); +}); diff --git a/sdks/node/src/__tests__/wandb/wandbServerApi.test.ts b/sdks/node/src/__tests__/wandb/wandbServerApi.test.ts new file mode 100644 index 00000000000..9ddf1109209 --- /dev/null +++ b/sdks/node/src/__tests__/wandb/wandbServerApi.test.ts @@ -0,0 +1,47 @@ +import {WandbServerApi} from '../../wandb/wandbServerApi'; + +const originalFetch = global.fetch; +const api = new WandbServerApi('https://api.wandb.ai', 'abcdef123456'); + +const mockGoodResponse = { + ok: true, + json: jest + .fn() + .mockResolvedValue({data: {viewer: {defaultEntity: {name: 'test'}}}}), +}; +const mockInvalidEntityResponse = { + ok: true, + json: jest.fn().mockResolvedValue({data: {viewer: {defaultEntity: {}}}}), +}; +const mockBadGQLResponse = { + ok: true, + json: jest.fn().mockResolvedValue({errors: [{message: 'problem'}]}), +}; + +describe('wandbServerApi', () => { + afterEach(() => { + global.fetch = originalFetch; + }); + + test('default entity happy path', async () => { + const mockFetch = jest.fn().mockResolvedValue(mockGoodResponse); + global.fetch = mockFetch; + + const result = await api.defaultEntityName(); + expect(result).toEqual('test'); + }); + + test('default entity error path', async () => { + const mockFetch = jest.fn().mockResolvedValue(mockInvalidEntityResponse); + global.fetch = mockFetch; + + await expect(api.defaultEntityName()).rejects.toThrow(/name not found/); + }); + + test('gql error path', async () => { + const mockFetch = jest.fn().mockResolvedValue(mockBadGQLResponse); + global.fetch = mockFetch; + + await expect(api.defaultEntityName()).rejects.toThrow(/GraphQL Error/); + }); +}); diff --git a/sdks/node/src/__tests__/weaveClient.test.ts b/sdks/node/src/__tests__/weaveClient.test.ts new file mode 100644 index 00000000000..3a3523daa20 --- /dev/null +++ b/sdks/node/src/__tests__/weaveClient.test.ts @@ -0,0 +1,230 @@ +import {ReadableStream} from 'stream/web'; +import {Api as TraceServerApi} from '../generated/traceServerApi'; +import {WandbServerApi} from '../wandb/wandbServerApi'; +import {WeaveClient} from '../weaveClient'; + +// Mock the TraceServerApi and WandbServerApi +jest.mock('../generated/traceServerApi'); +jest.mock('../wandb/wandbServerApi'); + +describe('WeaveClient', () => { + let client: WeaveClient; + let mockTraceServerApi: jest.Mocked>; + let mockWandbServerApi: jest.Mocked; + + beforeEach(() => { + mockTraceServerApi = { + calls: { + callsQueryStreamCallsStreamQueryPost: jest.fn(), + }, + } as any; + mockWandbServerApi = {} as any; + client = new WeaveClient( + mockTraceServerApi, + mockWandbServerApi, + 'test-project' + ); + }); + + describe('getCalls', () => { + it('should fetch and return calls', async () => { + const mockCalls = [ + {id: '1', name: 'call1'}, + {id: '2', name: 'call2'}, + ]; + const encoder = new TextEncoder(); + const stream = new ReadableStream({ + start(controller) { + mockCalls.forEach(call => { + controller.enqueue(encoder.encode(JSON.stringify(call) + '\n')); + }); + controller.close(); + }, + }); + ( + mockTraceServerApi.calls + .callsQueryStreamCallsStreamQueryPost as jest.Mock + ).mockResolvedValue({ + body: stream, + } as any); + + // Call the method + const filter = {}; + const includeCosts = true; + const limit = 500; + const result = await client.getCalls(filter, includeCosts, limit); + + // Verify the results + expect(result).toEqual(mockCalls); + expect( + mockTraceServerApi.calls.callsQueryStreamCallsStreamQueryPost + ).toHaveBeenCalledWith({ + project_id: 'test-project', + filter, + include_costs: includeCosts, + limit, + }); + }); + + it('should handle remaining buffer data after stream ends', async () => { + const encoder = new TextEncoder(); + const stream = new ReadableStream({ + start(controller) { + // Send data without newline at the end + controller.enqueue(encoder.encode('{"id": "1"}\n{"id": "2"}')); + controller.close(); + }, + }); + + ( + mockTraceServerApi.calls + .callsQueryStreamCallsStreamQueryPost as jest.Mock + ).mockResolvedValue({ + body: stream, + } as any); + + const result = await client.getCalls(); + + // Should process both objects, including the one without newline + expect(result).toEqual([{id: '1'}, {id: '2'}]); + }); + }); + + describe('Batch Processing', () => { + let client: WeaveClient; + let mockTraceServerApi: jest.Mocked>; + let mockWandbServerApi: jest.Mocked; + + beforeEach(() => { + mockTraceServerApi = { + call: { + callStartBatchCallUpsertBatchPost: jest.fn(), + }, + } as any; + mockWandbServerApi = {} as any; + client = new WeaveClient( + mockTraceServerApi, + mockWandbServerApi, + 'test-project' + ); + // Speed up tests by reducing batch interval + (client as any).BATCH_INTERVAL = 10; + }); + + it('should batch multiple calls together', async () => { + // Add test calls to queue + (client as any).callQueue.push( + {mode: 'start', data: {id: '1'}}, + {mode: 'start', data: {id: '2'}} + ); + + await (client as any).processBatch(); + + expect( + mockTraceServerApi.call.callStartBatchCallUpsertBatchPost + ).toHaveBeenCalledWith({ + batch: [ + {mode: 'start', req: {id: '1'}}, + {mode: 'start', req: {id: '2'}}, + ], + }); + expect((client as any).callQueue.length).toBe(0); + + (client as any).callQueue.push( + {mode: 'start', data: {id: '3'}}, + {mode: 'start', data: {id: '4'}}, + {mode: 'start', data: {id: '5'}} + ); + + await (client as any).processBatch(); + + expect( + mockTraceServerApi.call.callStartBatchCallUpsertBatchPost + ).toHaveBeenCalledWith({ + batch: [ + {mode: 'start', req: {id: '3'}}, + {mode: 'start', req: {id: '4'}}, + {mode: 'start', req: {id: '5'}}, + ], + }); + expect((client as any).callQueue.length).toBe(0); + + expect( + mockTraceServerApi.call.callStartBatchCallUpsertBatchPost + ).toHaveBeenCalledTimes(2); + }); + + it('should handle API errors gracefully', async () => { + const mockConsoleError = jest + .spyOn(console, 'error') + .mockImplementation(); + + // Add multiple items to queue + const items = [ + {mode: 'start', data: {id: '1'}}, + {mode: 'start', data: {id: '2'}}, + ]; + (client as any).callQueue.push(...items); + + // First API call fails + ( + mockTraceServerApi.call.callStartBatchCallUpsertBatchPost as jest.Mock + ).mockRejectedValueOnce(new Error('API Error')); + + await (client as any).processBatch(); + + // Should log error but continue processing, with failed items back in queue + expect(mockConsoleError).toHaveBeenCalledWith( + 'Error processing batch:', + expect.any(Error) + ); + expect((client as any).callQueue).toEqual(items); + + // Second API call succeeds + ( + mockTraceServerApi.call.callStartBatchCallUpsertBatchPost as jest.Mock + ).mockResolvedValueOnce({}); + + await (client as any).processBatch(); + + // Verify items were processed in original order + expect( + mockTraceServerApi.call.callStartBatchCallUpsertBatchPost + ).toHaveBeenCalledWith({ + batch: [ + {mode: 'start', req: {id: '1'}}, + {mode: 'start', req: {id: '2'}}, + ], + }); + expect((client as any).callQueue.length).toBe(0); + + mockConsoleError.mockRestore(); + }); + + it('should prevent concurrent batch processing', async () => { + (client as any).isBatchProcessing = true; + (client as any).scheduleBatchProcessing(); + expect((client as any).batchProcessTimeout).toBeNull(); + }); + + it('should wait for all pending batches', async () => { + // Simulate slow API + ( + mockTraceServerApi.call.callStartBatchCallUpsertBatchPost as jest.Mock + ).mockImplementation( + () => new Promise(resolve => setTimeout(resolve, 50)) + ); + + (client as any).callQueue.push( + {mode: 'start', data: {id: '1'}}, + {mode: 'start', data: {id: '2'}} + ); + + (client as any).scheduleBatchProcessing(); + await client.waitForBatchProcessing(); + + expect((client as any).batchProcessingPromises.size).toBe(0); + expect((client as any).callQueue.length).toBe(0); + }); + }); +}); diff --git a/sdks/node/src/clientApi.ts b/sdks/node/src/clientApi.ts new file mode 100644 index 00000000000..499322e8d5b --- /dev/null +++ b/sdks/node/src/clientApi.ts @@ -0,0 +1,159 @@ +import {Api as TraceServerApi} from './generated/traceServerApi'; +import {Settings} from './settings'; +import {getUrls, setGlobalDomain} from './urls'; +import {ConcurrencyLimiter} from './utils/concurrencyLimit'; +import {Netrc} from './utils/netrc'; +import {createFetchWithRetry} from './utils/retry'; +import {getWandbConfigs} from './wandb/settings'; +import {WandbServerApi} from './wandb/wandbServerApi'; +import {CallStackEntry, WeaveClient} from './weaveClient'; + +export interface LoginOptions { + apiKey: string; + host?: string; +} + +// Global client instance +export let globalClient: WeaveClient | null = null; + +/** + * Log in to Weights & Biases (W&B) using the provided API key. + * This function saves the credentials to your netrc file for future use. + * + * @param options - The login options. + * @param options.apiKey - Your W&B API key. + * @param options.host - (Optional) The host name (usually only needed if you're using a custom W&B server). + * @throws {Error} If the API key is not specified or if the connection to the weave trace server cannot be verified. + */ +export async function login(options?: LoginOptions) { + if (!options?.apiKey) { + throw Error('API Key must be specified'); + } + const {traceBaseUrl, domain} = getUrls(options?.host); + + // Test the connection to the traceServerApi + const testTraceServerApi = new TraceServerApi({ + baseUrl: traceBaseUrl, + baseApiParams: { + headers: { + 'User-Agent': `W&B Weave JS Client ${process.env.VERSION || 'unknown'}`, + Authorization: `Basic ${Buffer.from(`api:${options.apiKey}`).toString('base64')}`, + }, + }, + }); + try { + await testTraceServerApi.health.readRootHealthGet({}); + } catch (error) { + throw new Error( + 'Unable to verify connection to the weave trace server with given API Key' + ); + } + + const netrc = new Netrc(); + netrc.setEntry(domain, {login: 'user', password: options.apiKey}); + netrc.save(); + console.log(`Successfully logged in. Credentials saved for ${domain}`); +} + +/** + * Initialize the Weave client, which is required for weave tracing to work. + * + * @param project - The W&B project name (can be project or entity/project). + * @param settings - (Optional) Weave tracing settings + * @returns A promise that resolves to the initialized Weave client. + * @throws {Error} If the initialization fails + */ +export async function init( + project: string, + settings?: Settings +): Promise { + const {apiKey, baseUrl, traceBaseUrl, domain} = getWandbConfigs(); + try { + const wandbServerApi = new WandbServerApi(baseUrl, apiKey); + + let entityName: string | undefined; + let projectName: string; + if (project.includes('/')) { + [entityName, projectName] = project.split('/'); + } else { + entityName = await wandbServerApi.defaultEntityName(); + projectName = project; + } + const projectId = `${entityName}/${projectName}`; + + const retryFetch = createFetchWithRetry({ + baseDelay: 1000, + maxDelay: 5 * 60 * 1000, // 5 minutes + maxRetryTime: 12 * 60 * 60 * 1000, // 12 hours + retryOnStatus: (status: number) => + status === 429 || (status >= 500 && status < 600), + }); + const concurrencyLimiter = new ConcurrencyLimiter(20); + const concurrencyLimitedFetch = concurrencyLimiter.limitFunction( + async (...fetchParams: Parameters) => { + const result = await retryFetch(...fetchParams); + // Useful for debugging + // console.log(`Active: ${concurrencyLimiter.active} Pending: ${concurrencyLimiter.pending}`); + return result; + } + ); + + const traceServerApi = new TraceServerApi({ + baseUrl: traceBaseUrl, + baseApiParams: { + headers: { + 'User-Agent': `W&B Weave JS Client ${process.env.VERSION || 'unknown'}`, + Authorization: `Basic ${Buffer.from(`api:${apiKey}`).toString('base64')}`, + }, + }, + customFetch: concurrencyLimitedFetch, + }); + + const client = new WeaveClient( + traceServerApi, + wandbServerApi, + projectId, + settings + ); + setGlobalClient(client); + setGlobalDomain(domain); + console.log(`Initializing project: ${projectId}`); + return client; + } catch (error) { + console.error('Error during initialization:', error); + throw error; + } +} + +export function requireCurrentCallStackEntry(): CallStackEntry { + const client = getGlobalClient(); + if (!client) { + throw new Error('Weave client not initialized'); + } + const callStackEntry = client.getCallStack().peek(); + if (!callStackEntry) { + throw new Error('No current call stack entry'); + } + return callStackEntry; +} + +export function requireCurrentChildSummary(): {[key: string]: any} { + const callStackEntry = requireCurrentCallStackEntry(); + return callStackEntry.childSummary; +} + +export function getGlobalClient(): WeaveClient | null { + return globalClient; +} + +export function requireGlobalClient(): WeaveClient { + const client = getGlobalClient(); + if (!client) { + throw new Error('Weave client not initialized'); + } + return client; +} + +export function setGlobalClient(client: WeaveClient) { + globalClient = client; +} diff --git a/sdks/node/src/constants.ts b/sdks/node/src/constants.ts new file mode 100644 index 00000000000..726f5343a86 --- /dev/null +++ b/sdks/node/src/constants.ts @@ -0,0 +1,2 @@ +export const TRACE_CALL_EMOJI = '🍩'; +export const TRACE_OBJECT_EMOJI = '📦'; diff --git a/sdks/node/src/dataset.ts b/sdks/node/src/dataset.ts new file mode 100644 index 00000000000..ebcc2addc6d --- /dev/null +++ b/sdks/node/src/dataset.ts @@ -0,0 +1,92 @@ +import {requireGlobalClient} from './clientApi'; +import {Table} from './table'; +import {ObjectRef, WeaveObject, WeaveObjectParameters} from './weaveObject'; + +interface DatasetParameters + extends WeaveObjectParameters { + rows: R[]; +} + +export class DatasetRowRef { + constructor( + public projectId: string, + public objId: string, + public digest: string, + public rowDigest: string + ) {} + + public uri() { + return `weave:///${this.projectId}/object/${this.objId}:${this.digest}/attr/rows/id/${this.rowDigest}`; + } +} + +export type DatasetRow = Record & { + __savedRef?: DatasetRowRef | Promise; +}; + +/** + * Dataset object with easy saving and automatic versioning + * + * @example + * // Create a dataset + * const dataset = new Dataset({ + * id: 'grammar-dataset', + * rows: [ + * { id: '0', sentence: "He no likes ice cream.", correction: "He doesn't like ice cream." }, + * { id: '1', sentence: "She goed to the store.", correction: "She went to the store." }, + * { id: '2', sentence: "They plays video games all day.", correction: "They play video games all day." } + * ] + * }) + * + * // Access a specific example + * const exampleLabel = dataset.getRow(2).sentence; + * + * // Save the dataset + * const ref = await dataset.save() + * + */ +export class Dataset extends WeaveObject { + public rows: Table; + + constructor(parameters: DatasetParameters) { + const baseParameters = { + id: parameters.id, + description: parameters.description, + }; + super(baseParameters); + this.rows = new Table(parameters.rows); + } + + async save(): Promise { + return requireGlobalClient().publish(this); + } + + get length(): number { + return this.rows.length; + } + + async *[Symbol.asyncIterator](): AsyncIterator { + for (let i = 0; i < this.length; i++) { + yield this.getRow(i); + } + } + + getRow(index: number): R { + const tableRow = this.rows.row(index); + const datasetRow: R = {...tableRow, __savedRef: undefined}; + if (this.__savedRef && tableRow.__savedRef) { + datasetRow.__savedRef = Promise.all([ + this.__savedRef, + tableRow.__savedRef, + ]).then(([ref, tableRowRef]) => { + return new DatasetRowRef( + ref.projectId, + ref.objectId, + ref.digest, + tableRowRef.rowDigest + ); + }); + } + return datasetRow; + } +} diff --git a/sdks/node/src/digest.ts b/sdks/node/src/digest.ts new file mode 100644 index 00000000000..0d281a601df --- /dev/null +++ b/sdks/node/src/digest.ts @@ -0,0 +1,49 @@ +import {Buffer} from 'buffer'; +import crypto from 'crypto'; + +export function computeDigest(data: Buffer): string { + // Must match python server algorithm in clickhouse_trace_server_batched.py + const hasher = crypto.createHash('sha256'); + hasher.update(data); + const hashBytes = hasher.digest(); + const base64EncodedHash = hashBytes.toString('base64url'); + return base64EncodedHash + .replace(/-/g, 'X') + .replace(/_/g, 'Y') + .replace(/=/g, ''); +} + +export function stringDigest(data: string): string { + return computeDigest(Buffer.from(data)); +} + +export function encodeNumber(num: number): string { + return String(num); +} + +export function stringifyPythonDumps(obj: any): string { + if (obj === null) { + return 'null'; + } + if (typeof obj === 'string') { + return JSON.stringify(obj); + } + if (typeof obj === 'number' || typeof obj === 'boolean') { + return String(obj); + } + if (Array.isArray(obj)) { + const items = obj.map(stringifyPythonDumps); + return '[' + items.join(', ') + ']'; + } + if (typeof obj === 'object') { + const pairs = Object.keys(obj) + .sort() + .map(key => JSON.stringify(key) + ': ' + stringifyPythonDumps(obj[key])); + return '{' + pairs.join(', ') + '}'; + } + throw new Error('Unsupported type'); +} + +export function valDigest(data: any): string { + return stringDigest(stringifyPythonDumps(data)); +} diff --git a/sdks/node/src/evaluation.ts b/sdks/node/src/evaluation.ts new file mode 100644 index 00000000000..bcbfbc4b1c6 --- /dev/null +++ b/sdks/node/src/evaluation.ts @@ -0,0 +1,345 @@ +import cliProgress from 'cli-progress'; +import {Dataset, DatasetRow} from './dataset'; +import {ColumnMapping, mapArgs} from './fn'; +import {isMedia} from './media'; +import {op} from './op'; +import {Op, getOpName} from './opType'; +import {WeaveObject, WeaveObjectParameters} from './weaveObject'; + +const PROGRESS_BAR = false; + +// Column mapping takes a dataset row of type R and maps it to a scorer's dataset row of type E +interface EvaluationParameters + extends WeaveObjectParameters { + dataset: Dataset; + scorers: WeaveCallable<(...args: [{datasetRow: E; modelOutput: M}]) => any>[]; + maxConcurrency?: number; + columnMapping?: ColumnMapping; +} + +interface Runnable any> { + id: string; + invoke: (...args: Parameters) => ReturnType; +} + +type WeaveCallable any> = Op | Runnable; + +function callWeaveCallable any>( + callable: WeaveCallable, + ...args: Parameters +) { + if (typeof callable === 'function') { + return callable(...args); + } + return callable.invoke(...args); +} + +function weaveCallableName any>( + callable: WeaveCallable +) { + if (typeof callable === 'function') { + return getOpName(callable); + } + return callable.id; +} + +async function* repeatAsyncIterator( + asyncIterator: AsyncIterable, + repeatCount: number +) { + for (let i = 0; i < repeatCount; i++) { + yield* asyncIterator; + } +} + +async function* asyncParallelMap( + asyncIterator: AsyncIterable, + fn: (item: T, ...args: any[]) => Promise, + fnParams: (item: T) => any[], + maxConcurrency: number +) { + const itemPromiseMap: Map< + T, + Promise<{item: T; result: Awaited}> + > = new Map(); + async function runOne(item: T) { + return { + item, + // @ts-ignore + result: await fn(...fnParams(item)), + }; + } + let nDone = 0; + for await (const item of asyncIterator) { + if (itemPromiseMap.size >= maxConcurrency) { + const done = await Promise.race(itemPromiseMap.values()); + itemPromiseMap.delete(done.item); + yield { + ...done, + nRunning: itemPromiseMap.size, + nDone: ++nDone, + }; + } + const prom = runOne(item); + itemPromiseMap.set(item, prom); + } + + // Flush remaining items + while (itemPromiseMap.size > 0) { + const done = await Promise.race(itemPromiseMap.values()); + itemPromiseMap.delete(done.item); + yield { + ...done, + nRunning: itemPromiseMap.size, + nDone: ++nDone, + }; + } +} + +/** + * Sets up an evaluation which includes a set of scorers and a dataset. + * + * Calling evaluation.evaluate(model) will pass in rows form a dataset into a model matching + * the names of the columns of the dataset to the argument names in model.predict. + * + * Then it will call all of the scorers and save the results in weave. + * + * @example + * // Collect your examples into a dataset + * const dataset = new weave.Dataset({ + * id: 'my-dataset', + * rows: [ + * { question: 'What is the capital of France?', expected: 'Paris' }, + * { question: 'Who wrote "To Kill a Mockingbird"?', expected: 'Harper Lee' }, + * { question: 'What is the square root of 64?', expected: '8' }, + * ], + * }); + * + * // Define any custom scoring function + * const scoringFunction = weave.op(function isEqual({ modelOutput, datasetRow }) { + * return modelOutput == datasetRow.expected; + * }); + * + * // Define the function to evaluate + * const model = weave.op(async function alwaysParisModel({ question }) { + * return 'Paris'; + * }); + * + * // Start evaluating + * const evaluation = new weave.Evaluation({ + * id: 'my-evaluation', + * dataset: dataset, + * scorers: [scoringFunction], + * }); + * + * const results = await evaluation.evaluate({ model }); + */ +export class Evaluation< + R extends DatasetRow, + E extends DatasetRow, + M, +> extends WeaveObject { + private dataset: Dataset; + private scorers: WeaveCallable< + (...args: [{datasetRow: E; modelOutput: M}]) => any + >[]; + private columnMapping?: ColumnMapping; + + constructor(parameters: EvaluationParameters) { + super(parameters); + this.dataset = parameters.dataset; + this.scorers = parameters.scorers; + this.evaluate = op(this, this.evaluate, { + parameterNames: 'useParam0Object', + callDisplayName: inputs => + `${this.id}_${weaveCallableName(inputs.model)}`, + }); + this.predictAndScore = op(this, this.predictAndScore, { + parameterNames: 'useParam0Object', + }); + this.columnMapping = parameters.columnMapping; + } + + async evaluate({ + model, + nTrials = 1, + maxConcurrency = 5, + }: { + model: WeaveCallable<(...args: [{datasetRow: R}]) => Promise>; + nTrials?: number; + maxConcurrency?: number; + }) { + const results: Array<{ + model_output: M; + model_success: boolean; + model_latency: number; + [key: string]: any; + }> = []; + + const progressBar = new cliProgress.SingleBar({ + format: + 'Evaluating |{bar}| {percentage}% | ETA: {eta}s | {modelErrors} errors | {value}/{total} examples | {running} running', + barCompleteChar: '\u2588', + barIncompleteChar: '\u2591', + hideCursor: true, + }); + + if (PROGRESS_BAR) { + progressBar.start(this.dataset.length * nTrials, 0, { + running: 0, + modelErrors: 0, + }); + } + + let modelErrors = 0; + let datasetExamples = this.dataset; + if (nTrials > 1) { + // @ts-ignore + datasetExamples = repeatAsyncIterator(this.dataset, nTrials); + } + + for await (const {result, nRunning, nDone} of asyncParallelMap( + datasetExamples, + this.predictAndScore, + item => [{model, example: item, columnMapping: this.columnMapping}], + maxConcurrency + )) { + const {scores} = result; + console.log('>>>result', result); + results.push({ + model_success: result.model_success, + model_output: result.model_output, + ...scores, + model_latency: result.model_latency, + }); + modelErrors += result.model_success ? 0 : 1; + if (PROGRESS_BAR) { + progressBar.update(nDone, {running: nRunning, modelErrors}); + } else { + console.log( + `Evaluating ${nDone}/${this.dataset.length * nTrials} examples (${nRunning} running, ${modelErrors} errors)` + ); + } + } + + if (PROGRESS_BAR) { + progressBar.stop(); + } + + return this.summarizeResults(results); + } + + async predictAndScore({ + model, + example, + columnMapping, + }: { + model: WeaveCallable<(...args: [{datasetRow: E}]) => Promise>; + example: R; + columnMapping?: ColumnMapping; + }) { + const startTime = new Date(); + let modelOutput; + let modelError = false; + let datasetRow: E = example as unknown as E; + if (columnMapping) { + datasetRow = mapArgs(example, columnMapping) as E; + } + try { + modelOutput = await callWeaveCallable(model, {datasetRow}); + } catch (e) { + console.error(e); + modelError = true; + } + const endTime = new Date(); + const modelLatency = (endTime.getTime() - startTime.getTime()) / 1000; // Convert to seconds + + const scores: {[key: string]: any} = {}; + if (!modelError) { + for (const scorer of this.scorers) { + let score = undefined; + try { + score = await callWeaveCallable(scorer, {datasetRow, modelOutput}); + } catch (e) { + console.error(e); + } + scores[weaveCallableName(scorer)] = score; + } + } + + return { + model_success: !modelError, + model_output: modelOutput, + scores, + model_latency: modelLatency, + }; + } + + private summarizeResults( + results: Array<{ + model_output: any; + model_success: boolean; + model_latency: number; + [key: string]: any; + }> + ) { + const summarizeNestedObject = ( + results: Array + ): Record => { + const nestedSummary: Record = {}; + + // Get all unique keys from all results + const allKeys = new Set(results.flatMap(obj => Object.keys(obj ?? {}))); + + for (const key of allKeys) { + const values = results.map(result => + result == null ? null : result[key] + ); + if ( + values.some( + v => + typeof v === 'object' && + v !== null && + !Array.isArray(v) && + !isMedia(v) + ) + ) { + const result = summarizeNestedObject(values); + if (Object.keys(result).length > 0) { + nestedSummary[key] = result; + } + } else { + const columnSummary = this.summarizeColumn(values); + if (Object.keys(columnSummary).length > 0) { + nestedSummary[key] = columnSummary; + } + } + } + + return nestedSummary; + }; + + return summarizeNestedObject(results); + } + + private summarizeColumn(values: any[]): Record { + const nonNilValues = values.filter(v => v != null); + if (nonNilValues.length === 0) { + return {}; // Return an empty object if there are no valid values + } + + if (nonNilValues.every(v => typeof v === 'boolean')) { + const trueCount = nonNilValues.filter(v => v).length; + return { + true_count: trueCount, + true_fraction: values.length > 0 ? trueCount / values.length : 0, + }; + } else if (nonNilValues.every(v => typeof v === 'number')) { + const sum = nonNilValues.reduce((acc, v) => acc + v, 0); + return { + mean: values.length > 0 ? sum / values.length : 0, + }; + } + return {}; + } +} diff --git a/sdks/node/src/fn.ts b/sdks/node/src/fn.ts new file mode 100644 index 00000000000..be8d124e70a --- /dev/null +++ b/sdks/node/src/fn.ts @@ -0,0 +1,36 @@ +import {WeaveObject} from './weaveObject'; + +export type ColumnMapping = { + [K in keyof O]: keyof I; +}; +export type ArgsObject = {[key: string]: any}; +export type Row = {[key: string]: any}; + +export interface Callable { + run: (input: I) => Promise; +} +export type FnInputs> = + T extends Callable ? I : never; +export type FnOutput> = + T extends Callable ? O : never; + +export abstract class CallableObject + extends WeaveObject + implements Callable +{ + abstract run(input: I): Promise; +} + +export function mapArgs< + T extends Record, + M extends Record, +>(input: T, mapping: M): {[K in keyof M]: T[M[K]]} { + const result: Partial<{[K in keyof M]: T[M[K]]}> = {}; + + for (const [newKey, oldKey] of Object.entries(mapping)) { + if (oldKey in input) { + result[newKey as keyof M] = input[oldKey]; + } + } + return result as {[K in keyof M]: T[M[K]]}; +} diff --git a/sdks/node/src/generated/traceServerApi.ts b/sdks/node/src/generated/traceServerApi.ts new file mode 100644 index 00000000000..246a9b39a84 --- /dev/null +++ b/sdks/node/src/generated/traceServerApi.ts @@ -0,0 +1,1530 @@ +/* eslint-disable */ +/* tslint:disable */ +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +/** AndOperation */ +export interface AndOperation { + /** $And */ + $and: ( + | LiteralOperation + | GetFieldOperator + | ConvertOperation + | AndOperation + | OrOperation + | NotOperation + | EqOperation + | GtOperation + | GteOperation + | InOperation + | ContainsOperation + )[]; +} + +/** Body_file_create_file_create_post */ +export interface BodyFileCreateFileCreatePost { + /** Project Id */ + project_id: string; + /** + * File + * @format binary + */ + file: File; +} + +/** CallBatchEndMode */ +export interface CallBatchEndMode { + /** + * Mode + * @default "end" + */ + mode?: string; + req: CallEndReq; +} + +/** CallBatchStartMode */ +export interface CallBatchStartMode { + /** + * Mode + * @default "start" + */ + mode?: string; + req: CallStartReq; +} + +/** CallCreateBatchReq */ +export interface CallCreateBatchReq { + /** Batch */ + batch: (CallBatchStartMode | CallBatchEndMode)[]; +} + +/** CallCreateBatchRes */ +export interface CallCreateBatchRes { + /** Res */ + res: (CallStartRes | CallEndRes)[]; +} + +/** CallEndReq */ +export interface CallEndReq { + end: EndedCallSchemaForInsert; +} + +/** CallEndRes */ +export type CallEndRes = object; + +/** CallReadReq */ +export interface CallReadReq { + /** Project Id */ + project_id: string; + /** Id */ + id: string; + /** + * Include Costs + * @default false + */ + include_costs?: boolean | null; +} + +/** CallReadRes */ +export interface CallReadRes { + call: CallSchema | null; +} + +/** CallSchema */ +export interface CallSchema { + /** Id */ + id: string; + /** Project Id */ + project_id: string; + /** Op Name */ + op_name: string; + /** Display Name */ + display_name?: string | null; + /** Trace Id */ + trace_id: string; + /** Parent Id */ + parent_id?: string | null; + /** + * Started At + * @format date-time + */ + started_at: string; + /** Attributes */ + attributes: object; + /** Inputs */ + inputs: object; + /** Ended At */ + ended_at?: string | null; + /** Exception */ + exception?: string | null; + /** Output */ + output?: null; + summary?: object; + /** Wb User Id */ + wb_user_id?: string | null; + /** Wb Run Id */ + wb_run_id?: string | null; + /** Deleted At */ + deleted_at?: string | null; +} + +/** CallStartReq */ +export interface CallStartReq { + start: StartedCallSchemaForInsert; +} + +/** CallStartRes */ +export interface CallStartRes { + /** Id */ + id: string; + /** Trace Id */ + trace_id: string; +} + +/** CallUpdateReq */ +export interface CallUpdateReq { + /** Project Id */ + project_id: string; + /** Call Id */ + call_id: string; + /** Display Name */ + display_name?: string | null; + /** + * Wb User Id + * Do not set directly. Server will automatically populate this field. + */ + wb_user_id?: string | null; +} + +/** CallUpdateRes */ +export type CallUpdateRes = object; + +/** CallsDeleteReq */ +export interface CallsDeleteReq { + /** Project Id */ + project_id: string; + /** Call Ids */ + call_ids: string[]; + /** + * Wb User Id + * Do not set directly. Server will automatically populate this field. + */ + wb_user_id?: string | null; +} + +/** CallsDeleteRes */ +export type CallsDeleteRes = object; + +/** CallsFilter */ +export interface CallsFilter { + /** Op Names */ + op_names?: string[] | null; + /** Input Refs */ + input_refs?: string[] | null; + /** Output Refs */ + output_refs?: string[] | null; + /** Parent Ids */ + parent_ids?: string[] | null; + /** Trace Ids */ + trace_ids?: string[] | null; + /** Call Ids */ + call_ids?: string[] | null; + /** Trace Roots Only */ + trace_roots_only?: boolean | null; + /** Wb User Ids */ + wb_user_ids?: string[] | null; + /** Wb Run Ids */ + wb_run_ids?: string[] | null; +} + +/** CallsQueryReq */ +export interface CallsQueryReq { + /** Project Id */ + project_id: string; + filter?: CallsFilter | null; + /** Limit */ + limit?: number | null; + /** Offset */ + offset?: number | null; + /** Sort By */ + sort_by?: SortBy[] | null; + query?: Query | null; + /** + * Include Costs + * @default false + */ + include_costs?: boolean | null; + /** Columns */ + columns?: string[] | null; + /** + * Expand Columns + * Columns to expand, i.e. refs to other objects + */ + expand_columns?: string[] | null; +} + +/** CallsQueryStatsReq */ +export interface CallsQueryStatsReq { + /** Project Id */ + project_id: string; + filter?: CallsFilter | null; + query?: Query | null; +} + +/** CallsQueryStatsRes */ +export interface CallsQueryStatsRes { + /** Count */ + count: number; +} + +/** ContainsOperation */ +export interface ContainsOperation { + $contains: ContainsSpec; +} + +/** ContainsSpec */ +export interface ContainsSpec { + /** Input */ + input: + | LiteralOperation + | GetFieldOperator + | ConvertOperation + | AndOperation + | OrOperation + | NotOperation + | EqOperation + | GtOperation + | GteOperation + | InOperation + | ContainsOperation; + /** Substr */ + substr: + | LiteralOperation + | GetFieldOperator + | ConvertOperation + | AndOperation + | OrOperation + | NotOperation + | EqOperation + | GtOperation + | GteOperation + | InOperation + | ContainsOperation; + /** + * Case Insensitive + * @default false + */ + case_insensitive?: boolean | null; +} + +/** ConvertOperation */ +export interface ConvertOperation { + $convert: ConvertSpec; +} + +/** ConvertSpec */ +export interface ConvertSpec { + /** Input */ + input: + | LiteralOperation + | GetFieldOperator + | ConvertOperation + | AndOperation + | OrOperation + | NotOperation + | EqOperation + | GtOperation + | GteOperation + | InOperation + | ContainsOperation; + /** To */ + to: 'double' | 'string' | 'int' | 'bool' | 'exists'; +} + +/** EndedCallSchemaForInsert */ +export interface EndedCallSchemaForInsert { + /** Project Id */ + project_id: string; + /** Id */ + id: string; + /** + * Ended At + * @format date-time + */ + ended_at: string; + /** Exception */ + exception?: string | null; + /** Output */ + output?: null; + summary: SummaryInsertMap; +} + +/** EqOperation */ +export interface EqOperation { + /** + * $Eq + * @maxItems 2 + * @minItems 2 + */ + $eq: any[]; +} + +/** FeedbackCreateReq */ +export interface FeedbackCreateReq { + /** Project Id */ + project_id: string; + /** Weave Ref */ + weave_ref: string; + /** Creator */ + creator?: string | null; + /** Feedback Type */ + feedback_type: string; + /** Payload */ + payload: object; + /** + * Wb User Id + * Do not set directly. Server will automatically populate this field. + */ + wb_user_id?: string | null; +} + +/** FeedbackCreateRes */ +export interface FeedbackCreateRes { + /** Id */ + id: string; + /** + * Created At + * @format date-time + */ + created_at: string; + /** Wb User Id */ + wb_user_id: string; + /** Payload */ + payload: object; +} + +/** FeedbackPurgeReq */ +export interface FeedbackPurgeReq { + /** Project Id */ + project_id: string; + query: Query; +} + +/** FeedbackPurgeRes */ +export type FeedbackPurgeRes = object; + +/** FeedbackQueryReq */ +export interface FeedbackQueryReq { + /** Project Id */ + project_id: string; + /** Fields */ + fields?: string[] | null; + query?: Query | null; + /** Sort By */ + sort_by?: SortBy[] | null; + /** Limit */ + limit?: number | null; + /** Offset */ + offset?: number | null; +} + +/** FeedbackQueryRes */ +export interface FeedbackQueryRes { + /** Result */ + result: object[]; +} + +/** FileContentReadReq */ +export interface FileContentReadReq { + /** Project Id */ + project_id: string; + /** Digest */ + digest: string; +} + +/** FileCreateRes */ +export interface FileCreateRes { + /** Digest */ + digest: string; +} + +/** GetFieldOperator */ +export interface GetFieldOperator { + /** $Getfield */ + $getField: string; +} + +/** GtOperation */ +export interface GtOperation { + /** + * $Gt + * @maxItems 2 + * @minItems 2 + */ + $gt: any[]; +} + +/** GteOperation */ +export interface GteOperation { + /** + * $Gte + * @maxItems 2 + * @minItems 2 + */ + $gte: any[]; +} + +/** HTTPValidationError */ +export interface HTTPValidationError { + /** Detail */ + detail?: ValidationError[]; +} + +/** InOperation */ +export interface InOperation { + /** + * $In + * @maxItems 2 + * @minItems 2 + */ + $in: any[]; +} + +/** LLMUsageSchema */ +export interface LLMUsageSchema { + /** Prompt Tokens */ + prompt_tokens?: number | null; + /** Input Tokens */ + input_tokens?: number | null; + /** Completion Tokens */ + completion_tokens?: number | null; + /** Output Tokens */ + output_tokens?: number | null; + /** Requests */ + requests?: number | null; + /** Total Tokens */ + total_tokens?: number | null; +} + +/** LiteralOperation */ +export interface LiteralOperation { + /** $Literal */ + $literal: + | string + | number + | boolean + | Record + | LiteralOperation[] + | null; +} + +/** NotOperation */ +export interface NotOperation { + /** + * $Not + * @maxItems 1 + * @minItems 1 + */ + $not: any[]; +} + +/** ObjCreateReq */ +export interface ObjCreateReq { + obj: ObjSchemaForInsert; +} + +/** ObjCreateRes */ +export interface ObjCreateRes { + /** Digest */ + digest: string; +} + +/** ObjQueryReq */ +export interface ObjQueryReq { + /** Project Id */ + project_id: string; + filter?: ObjectVersionFilter | null; +} + +/** ObjQueryRes */ +export interface ObjQueryRes { + /** Objs */ + objs: ObjSchema[]; +} + +/** ObjReadReq */ +export interface ObjReadReq { + /** Project Id */ + project_id: string; + /** Object Id */ + object_id: string; + /** Digest */ + digest: string; +} + +/** ObjReadRes */ +export interface ObjReadRes { + obj: ObjSchema; +} + +/** ObjSchema */ +export interface ObjSchema { + /** Project Id */ + project_id: string; + /** Object Id */ + object_id: string; + /** + * Created At + * @format date-time + */ + created_at: string; + /** Deleted At */ + deleted_at?: string | null; + /** Digest */ + digest: string; + /** Version Index */ + version_index: number; + /** Is Latest */ + is_latest: number; + /** Kind */ + kind: string; + /** Base Object Class */ + base_object_class: string | null; + /** Val */ + val: any; +} + +/** ObjSchemaForInsert */ +export interface ObjSchemaForInsert { + /** Project Id */ + project_id: string; + /** Object Id */ + object_id: string; + /** Val */ + val: any; +} + +/** ObjectVersionFilter */ +export interface ObjectVersionFilter { + /** Base Object Classes */ + base_object_classes?: string[] | null; + /** Object Ids */ + object_ids?: string[] | null; + /** Is Op */ + is_op?: boolean | null; + /** Latest Only */ + latest_only?: boolean | null; +} + +/** OrOperation */ +export interface OrOperation { + /** $Or */ + $or: ( + | LiteralOperation + | GetFieldOperator + | ConvertOperation + | AndOperation + | OrOperation + | NotOperation + | EqOperation + | GtOperation + | GteOperation + | InOperation + | ContainsOperation + )[]; +} + +/** Query */ +export interface Query { + /** $Expr */ + $expr: + | AndOperation + | OrOperation + | NotOperation + | EqOperation + | GtOperation + | GteOperation + | InOperation + | ContainsOperation; +} + +/** RefsReadBatchReq */ +export interface RefsReadBatchReq { + /** Refs */ + refs: string[]; +} + +/** RefsReadBatchRes */ +export interface RefsReadBatchRes { + /** Vals */ + vals: any[]; +} + +/** ServerInfoRes */ +export interface ServerInfoRes { + /** Min Required Weave Python Version */ + min_required_weave_python_version: string; +} + +/** SortBy */ +export interface SortBy { + /** Field */ + field: string; + /** Direction */ + direction: 'asc' | 'desc'; +} + +/** StartedCallSchemaForInsert */ +export interface StartedCallSchemaForInsert { + /** Project Id */ + project_id: string; + /** Id */ + id?: string | null; + /** Op Name */ + op_name: string; + /** Display Name */ + display_name?: string | null; + /** Trace Id */ + trace_id?: string | null; + /** Parent Id */ + parent_id?: string | null; + /** + * Started At + * @format date-time + */ + started_at: string; + /** Attributes */ + attributes: object; + /** Inputs */ + inputs: object; + /** + * Wb User Id + * Do not set directly. Server will automatically populate this field. + */ + wb_user_id?: string | null; + /** Wb Run Id */ + wb_run_id?: string | null; +} + +/** SummaryInsertMap */ +export interface SummaryInsertMap { + /** Usage */ + usage?: Record; + [key: string]: any; +} + +/** TableAppendSpec */ +export interface TableAppendSpec { + append: TableAppendSpecPayload; +} + +/** TableAppendSpecPayload */ +export interface TableAppendSpecPayload { + /** Row */ + row: object; +} + +/** TableCreateReq */ +export interface TableCreateReq { + table: TableSchemaForInsert; +} + +/** TableCreateRes */ +export interface TableCreateRes { + /** Digest */ + digest: string; +} + +/** TableInsertSpec */ +export interface TableInsertSpec { + insert: TableInsertSpecPayload; +} + +/** TableInsertSpecPayload */ +export interface TableInsertSpecPayload { + /** Index */ + index: number; + /** Row */ + row: object; +} + +/** TablePopSpec */ +export interface TablePopSpec { + pop: TablePopSpecPayload; +} + +/** TablePopSpecPayload */ +export interface TablePopSpecPayload { + /** Index */ + index: number; +} + +/** TableQueryReq */ +export interface TableQueryReq { + /** Project Id */ + project_id: string; + /** Digest */ + digest: string; + filter?: TableRowFilter | null; + /** Limit */ + limit?: number | null; + /** Offset */ + offset?: number | null; +} + +/** TableQueryRes */ +export interface TableQueryRes { + /** Rows */ + rows: TableRowSchema[]; +} + +/** TableRowFilter */ +export interface TableRowFilter { + /** Row Digests */ + row_digests?: string[] | null; +} + +/** TableRowSchema */ +export interface TableRowSchema { + /** Digest */ + digest: string; + /** Val */ + val: any; +} + +/** TableSchemaForInsert */ +export interface TableSchemaForInsert { + /** Project Id */ + project_id: string; + /** Rows */ + rows: object[]; +} + +/** TableUpdateReq */ +export interface TableUpdateReq { + /** Project Id */ + project_id: string; + /** Base Digest */ + base_digest: string; + /** Updates */ + updates: (TableAppendSpec | TablePopSpec | TableInsertSpec)[]; +} + +/** TableUpdateRes */ +export interface TableUpdateRes { + /** Digest */ + digest: string; +} + +/** ValidationError */ +export interface ValidationError { + /** Location */ + loc: (string | number)[]; + /** Message */ + msg: string; + /** Error Type */ + type: string; +} + +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ + secure?: boolean; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: ResponseFormat; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} + +export type RequestParams = Omit< + FullRequestParams, + 'body' | 'method' | 'query' | 'path' +>; + +export interface ApiConfig { + baseUrl?: string; + baseApiParams?: Omit; + securityWorker?: ( + securityData: SecurityDataType | null + ) => Promise | RequestParams | void; + customFetch?: typeof fetch; +} + +export interface HttpResponse + extends Response { + data: D; + error: E; +} + +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = 'application/json', + FormData = 'multipart/form-data', + UrlEncoded = 'application/x-www-form-urlencoded', + Text = 'text/plain', +} + +export class HttpClient { + public baseUrl: string = ''; + private securityData: SecurityDataType | null = null; + private securityWorker?: ApiConfig['securityWorker']; + private abortControllers = new Map(); + private customFetch = (...fetchParams: Parameters) => + fetch(...fetchParams); + + private baseApiParams: RequestParams = { + credentials: 'same-origin', + headers: {}, + redirect: 'follow', + referrerPolicy: 'no-referrer', + }; + + constructor(apiConfig: ApiConfig = {}) { + Object.assign(this, apiConfig); + } + + public setSecurityData = (data: SecurityDataType | null) => { + this.securityData = data; + }; + + protected encodeQueryParam(key: string, value: any) { + const encodedKey = encodeURIComponent(key); + return `${encodedKey}=${encodeURIComponent(typeof value === 'number' ? value : `${value}`)}`; + } + + protected addQueryParam(query: QueryParamsType, key: string) { + return this.encodeQueryParam(key, query[key]); + } + + protected addArrayQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return value.map((v: any) => this.encodeQueryParam(key, v)).join('&'); + } + + protected toQueryString(rawQuery?: QueryParamsType): string { + const query = rawQuery || {}; + const keys = Object.keys(query).filter( + key => 'undefined' !== typeof query[key] + ); + return keys + .map(key => + Array.isArray(query[key]) + ? this.addArrayQueryParam(query, key) + : this.addQueryParam(query, key) + ) + .join('&'); + } + + protected addQueryParams(rawQuery?: QueryParamsType): string { + const queryString = this.toQueryString(rawQuery); + return queryString ? `?${queryString}` : ''; + } + + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => + input !== null && (typeof input === 'object' || typeof input === 'string') + ? JSON.stringify(input) + : input, + [ContentType.Text]: (input: any) => + input !== null && typeof input !== 'string' + ? JSON.stringify(input) + : input, + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((formData, key) => { + const property = input[key]; + formData.append( + key, + property instanceof Blob + ? property + : typeof property === 'object' && property !== null + ? JSON.stringify(property) + : `${property}` + ); + return formData; + }, new FormData()), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), + }; + + protected mergeRequestParams( + params1: RequestParams, + params2?: RequestParams + ): RequestParams { + return { + ...this.baseApiParams, + ...params1, + ...(params2 || {}), + headers: { + ...(this.baseApiParams.headers || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), + }, + }; + } + + protected createAbortSignal = ( + cancelToken: CancelToken + ): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; + }; + + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = async ({ + body, + secure, + path, + type, + query, + format, + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = + ((typeof secure === 'boolean' ? secure : this.baseApiParams.secure) && + this.securityWorker && + (await this.securityWorker(this.securityData))) || + {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + const responseFormat = format || requestParams.format; + + return this.customFetch( + `${baseUrl || this.baseUrl || ''}${path}${queryString ? `?${queryString}` : ''}`, + { + ...requestParams, + headers: { + ...(requestParams.headers || {}), + ...(type && type !== ContentType.FormData + ? {'Content-Type': type} + : {}), + }, + signal: + (cancelToken + ? this.createAbortSignal(cancelToken) + : requestParams.signal) || null, + body: + typeof body === 'undefined' || body === null + ? null + : payloadFormatter(body), + } + ).then(async response => { + const r = response.clone() as HttpResponse; + r.data = null as unknown as T; + r.error = null as unknown as E; + + const data = !responseFormat + ? r + : await response[responseFormat]() + .then(data => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch(e => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } + + if (!response.ok) throw data; + return data; + }); + }; +} + +/** + * @title FastAPI + * @version 0.1.0 + */ +export class Api< + SecurityDataType extends unknown, +> extends HttpClient { + health = { + /** + * No description + * + * @tags Service + * @name ReadRootHealthGet + * @summary Read Root + * @request GET:/health + */ + readRootHealthGet: (params: RequestParams = {}) => + this.request({ + path: `/health`, + method: 'GET', + format: 'json', + ...params, + }), + }; + serverInfo = { + /** + * No description + * + * @tags Service + * @name ServerInfoServerInfoGet + * @summary Server Info + * @request GET:/server_info + */ + serverInfoServerInfoGet: (params: RequestParams = {}) => + this.request({ + path: `/server_info`, + method: 'GET', + format: 'json', + ...params, + }), + }; + call = { + /** + * No description + * + * @tags Calls + * @name CallStartCallStartPost + * @summary Call Start + * @request POST:/call/start + * @secure + */ + callStartCallStartPost: (data: CallStartReq, params: RequestParams = {}) => + this.request({ + path: `/call/start`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + + /** + * No description + * + * @tags Calls + * @name CallEndCallEndPost + * @summary Call End + * @request POST:/call/end + * @secure + */ + callEndCallEndPost: (data: CallEndReq, params: RequestParams = {}) => + this.request({ + path: `/call/end`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + + /** + * No description + * + * @tags Calls + * @name CallStartBatchCallUpsertBatchPost + * @summary Call Start Batch + * @request POST:/call/upsert_batch + * @secure + */ + callStartBatchCallUpsertBatchPost: ( + data: CallCreateBatchReq, + params: RequestParams = {} + ) => + this.request({ + path: `/call/upsert_batch`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + + /** + * No description + * + * @tags Calls + * @name CallUpdateCallUpdatePost + * @summary Call Update + * @request POST:/call/update + * @secure + */ + callUpdateCallUpdatePost: ( + data: CallUpdateReq, + params: RequestParams = {} + ) => + this.request({ + path: `/call/update`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + + /** + * No description + * + * @tags Calls + * @name CallReadCallReadPost + * @summary Call Read + * @request POST:/call/read + * @secure + */ + callReadCallReadPost: (data: CallReadReq, params: RequestParams = {}) => + this.request({ + path: `/call/read`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + }; + calls = { + /** + * No description + * + * @tags Calls + * @name CallsDeleteCallsDeletePost + * @summary Calls Delete + * @request POST:/calls/delete + * @secure + */ + callsDeleteCallsDeletePost: ( + data: CallsDeleteReq, + params: RequestParams = {} + ) => + this.request({ + path: `/calls/delete`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + + /** + * No description + * + * @tags Calls + * @name CallsQueryStatsCallsQueryStatsPost + * @summary Calls Query Stats + * @request POST:/calls/query_stats + * @secure + */ + callsQueryStatsCallsQueryStatsPost: ( + data: CallsQueryStatsReq, + params: RequestParams = {} + ) => + this.request({ + path: `/calls/query_stats`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + + /** + * No description + * + * @tags Calls + * @name CallsQueryStreamCallsStreamQueryPost + * @summary Calls Query Stream + * @request POST:/calls/stream_query + * @secure + */ + callsQueryStreamCallsStreamQueryPost: ( + data: CallsQueryReq, + params: RequestParams = {} + ) => + this.request({ + path: `/calls/stream_query`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + }; + obj = { + /** + * No description + * + * @tags Objects + * @name ObjCreateObjCreatePost + * @summary Obj Create + * @request POST:/obj/create + * @secure + */ + objCreateObjCreatePost: (data: ObjCreateReq, params: RequestParams = {}) => + this.request({ + path: `/obj/create`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + + /** + * No description + * + * @tags Objects + * @name ObjReadObjReadPost + * @summary Obj Read + * @request POST:/obj/read + * @secure + */ + objReadObjReadPost: (data: ObjReadReq, params: RequestParams = {}) => + this.request({ + path: `/obj/read`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + }; + objs = { + /** + * No description + * + * @tags Objects + * @name ObjsQueryObjsQueryPost + * @summary Objs Query + * @request POST:/objs/query + * @secure + */ + objsQueryObjsQueryPost: (data: ObjQueryReq, params: RequestParams = {}) => + this.request({ + path: `/objs/query`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + }; + table = { + /** + * No description + * + * @tags Tables + * @name TableCreateTableCreatePost + * @summary Table Create + * @request POST:/table/create + * @secure + */ + tableCreateTableCreatePost: ( + data: TableCreateReq, + params: RequestParams = {} + ) => + this.request({ + path: `/table/create`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + + /** + * No description + * + * @tags Tables + * @name TableUpdateTableUpdatePost + * @summary Table Update + * @request POST:/table/update + * @secure + */ + tableUpdateTableUpdatePost: ( + data: TableUpdateReq, + params: RequestParams = {} + ) => + this.request({ + path: `/table/update`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + + /** + * No description + * + * @tags Tables + * @name TableQueryTableQueryPost + * @summary Table Query + * @request POST:/table/query + * @secure + */ + tableQueryTableQueryPost: ( + data: TableQueryReq, + params: RequestParams = {} + ) => + this.request({ + path: `/table/query`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + }; + refs = { + /** + * No description + * + * @tags Refs + * @name RefsReadBatchRefsReadBatchPost + * @summary Refs Read Batch + * @request POST:/refs/read_batch + * @secure + */ + refsReadBatchRefsReadBatchPost: ( + data: RefsReadBatchReq, + params: RequestParams = {} + ) => + this.request({ + path: `/refs/read_batch`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + }; + file = { + /** + * No description + * + * @tags Files + * @name FileCreateFileCreatePost + * @summary File Create + * @request POST:/file/create + * @secure + */ + fileCreateFileCreatePost: ( + data: BodyFileCreateFileCreatePost, + params: RequestParams = {} + ) => + this.request({ + path: `/file/create`, + method: 'POST', + body: data, + secure: true, + type: ContentType.FormData, + format: 'json', + ...params, + }), + + /** + * No description + * + * @tags Files + * @name FileContentFileContentPost + * @summary File Content + * @request POST:/file/content + * @secure + */ + fileContentFileContentPost: ( + data: FileContentReadReq, + params: RequestParams = {} + ) => + this.request({ + path: `/file/content`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + }; + feedback = { + /** + * @description Add feedback to a call or object. + * + * @tags Feedback + * @name FeedbackCreateFeedbackCreatePost + * @summary Feedback Create + * @request POST:/feedback/create + * @secure + */ + feedbackCreateFeedbackCreatePost: ( + data: FeedbackCreateReq, + params: RequestParams = {} + ) => + this.request({ + path: `/feedback/create`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + + /** + * @description Query for feedback. + * + * @tags Feedback + * @name FeedbackQueryFeedbackQueryPost + * @summary Feedback Query + * @request POST:/feedback/query + * @secure + */ + feedbackQueryFeedbackQueryPost: ( + data: FeedbackQueryReq, + params: RequestParams = {} + ) => + this.request({ + path: `/feedback/query`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + + /** + * @description Permanently delete feedback. + * + * @tags Feedback + * @name FeedbackPurgeFeedbackPurgePost + * @summary Feedback Purge + * @request POST:/feedback/purge + * @secure + */ + feedbackPurgeFeedbackPurgePost: ( + data: FeedbackPurgeReq, + params: RequestParams = {} + ) => + this.request({ + path: `/feedback/purge`, + method: 'POST', + body: data, + secure: true, + type: ContentType.Json, + format: 'json', + ...params, + }), + }; +} diff --git a/sdks/node/src/inMemoryTraceServer.ts b/sdks/node/src/inMemoryTraceServer.ts new file mode 100644 index 00000000000..365577cb19b --- /dev/null +++ b/sdks/node/src/inMemoryTraceServer.ts @@ -0,0 +1,176 @@ +import {uuidv7} from 'uuidv7'; + +// This is mostly used for testing +// TODO: Maybe move the interfaces to something like trace_server_interface.py + +interface Call { + project_id: string; + id: string; + op_name: string; + trace_id: string; + parent_id: string | null; + started_at: string; + ended_at?: string; + inputs: any; + output?: any; + exception?: string; + [key: string]: any; // Index signature to allow dynamic property access +} + +interface QueryParams { + project_id: string; + limit?: number; + order_by?: keyof Call; + order_dir?: 'asc' | 'desc'; + filters?: Partial; +} + +interface Obj { + project_id: string; + object_id: string; + created_at: string; + deleted_at: string | null; + digest: string; + version_index: number; + is_latest: number; + kind: string; + base_object_class: string | null; + val: any; +} + +interface File { + project_id: string; + digest: string; + content: Blob; +} + +export class InMemoryTraceServer { + private _calls: Call[] = []; + private _objs: Obj[] = []; + private _files: File[] = []; + + call = { + callStartBatchCallUpsertBatchPost: async (batchReq: { + batch: Array<{mode: 'start' | 'end'; req: any}>; + }) => { + for (const item of batchReq.batch) { + if (item.mode === 'start') { + this._calls.push(item.req.start); + } else if (item.mode === 'end') { + const call = this._calls.find(c => c.id === item.req.end.id); + if (call) { + Object.assign(call, item.req.end); + } + } + } + }, + }; + + calls = { + callsStreamQueryPost: async (queryParams: QueryParams) => { + let filteredCalls = this._calls.filter( + call => call.project_id === queryParams.project_id + ); + + // Apply filters if any + if (queryParams.filters) { + filteredCalls = filteredCalls.filter(call => { + return Object.entries(queryParams.filters || {}).every( + ([key, value]) => call[key] === value + ); + }); + } + + // Apply ordering + if (queryParams.order_by) { + filteredCalls.sort((a, b) => { + if (a[queryParams.order_by!] < b[queryParams.order_by!]) + return queryParams.order_dir === 'asc' ? -1 : 1; + if (a[queryParams.order_by!] > b[queryParams.order_by!]) + return queryParams.order_dir === 'asc' ? 1 : -1; + return 0; + }); + } + + // Apply limit + if (queryParams.limit) { + filteredCalls = filteredCalls.slice(0, queryParams.limit); + } + + return { + calls: filteredCalls, + next_page_token: null, // Simplified: no pagination in this in-memory version + }; + }, + }; + + obj = { + objCreateObjCreatePost: async (req: { + obj: {project_id: string; object_id: string; val: any}; + }) => { + const now = new Date().toISOString(); + const digest = this.generateDigest(req.obj.val); + + const newObj: Obj = { + project_id: req.obj.project_id, + object_id: req.obj.object_id, + created_at: now, + deleted_at: null, + digest: digest, + version_index: 0, + is_latest: 1, + kind: req.obj.val._type || 'unknown', + base_object_class: req.obj.val._bases ? req.obj.val._bases[0] : null, + val: req.obj.val, + }; + + // Update version_index and is_latest for existing objects + const existingObjs = this._objs.filter( + obj => + obj.project_id === req.obj.project_id && + obj.object_id === req.obj.object_id + ); + if (existingObjs.length > 0) { + newObj.version_index = existingObjs.length; + existingObjs.forEach(obj => (obj.is_latest = 0)); + } + + this._objs.push(newObj); + + return { + data: { + digest: digest, + }, + }; + }, + }; + + file = { + fileCreateFileCreatePost: async (data: { + project_id: string; + file: Blob; + }) => { + const digest = this.generateDigest(await data.file.arrayBuffer()); + + const newFile: File = { + project_id: data.project_id, + digest: digest, + content: data.file, + }; + + this._files.push(newFile); + + return { + digest: digest, + }; + }, + }; + + private generateDigest(data: ArrayBuffer): string { + // In a real implementation, you'd want to use a proper hashing algorithm. + // For simplicity, we're using uuidv7 here. + return uuidv7(); + } + + // ... other existing methods ... +} diff --git a/sdks/node/src/index.ts b/sdks/node/src/index.ts new file mode 100644 index 00000000000..664b52f7638 --- /dev/null +++ b/sdks/node/src/index.ts @@ -0,0 +1,14 @@ +export { + init, + login, + requireCurrentCallStackEntry, + requireCurrentChildSummary, +} from './clientApi'; +export {Dataset} from './dataset'; +export {Evaluation} from './evaluation'; +export {CallSchema, CallsFilter} from './generated/traceServerApi'; +export {wrapOpenAI} from './integrations'; +export {weaveAudio, weaveImage} from './media'; +export {op} from './op'; +export * from './types'; +export {WeaveObject} from './weaveObject'; diff --git a/sdks/node/src/integrations/checkOpenai.ts b/sdks/node/src/integrations/checkOpenai.ts new file mode 100644 index 00000000000..a09033e9a61 --- /dev/null +++ b/sdks/node/src/integrations/checkOpenai.ts @@ -0,0 +1,94 @@ +// Manual test for checking openai client + +import {OpenAI} from 'openai'; +import {wrapOpenAI, init} from '..'; +import {z} from 'zod'; +import {zodResponseFormat} from 'openai/helpers/zod'; + +async function betaParseCall(client: OpenAI) { + return await client.beta.chat.completions.parse({ + model: 'gpt-4o-2024-08-06', + temperature: 0.7, + messages: [ + { + role: 'user', + content: 'What is the capital of the US?', + }, + ], + response_format: zodResponseFormat(z.object({name: z.string()}), 'result'), + }); +} + +async function standardCall(client: OpenAI) { + return await client.chat.completions.create({ + model: 'gpt-4o-2024-08-06', + temperature: 0.7, + messages: [ + { + role: 'user', + content: 'What is the capital of the US?', + }, + ], + response_format: zodResponseFormat(z.object({name: z.string()}), 'result'), + }); +} + +async function streamCall(client: OpenAI) { + return await client.chat.completions.create({ + model: 'gpt-4o-2024-08-06', + temperature: 0.7, + messages: [ + { + role: 'user', + content: 'What is the capital of the US?', + }, + ], + stream: true, + response_format: zodResponseFormat(z.object({name: z.string()}), 'result'), + }); +} + +async function callTests(openai: OpenAI) { + try { + console.log(' BETA PARSE CALL'); + const response = await betaParseCall(openai); + console.log(' SUCCESS', JSON.stringify(response).length); + } catch (e) { + console.log(' ERROR', e); + } + try { + console.log(' STANDARD CALL'); + const response = await standardCall(openai); + console.log(' SUCCESS', JSON.stringify(response).length); + } catch (e) { + console.log(' ERROR', e); + } + try { + console.log(' STREAM CALL'); + const response = await streamCall(openai); + let fullRes = ''; + for await (const chunk of response) { + fullRes += JSON.stringify(chunk); + } + // console.log("FULL RESPONSE", fullRes); + console.log(' SUCCESS', fullRes.length); + } catch (e) { + console.log(' ERROR', e); + } +} + +export async function oaiParse() { + const openai = new OpenAI({timeout: 120 * 1000}); + console.log('OPENAI CLIENT TESTS'); + await callTests(openai); + + const client = wrapOpenAI(openai); + console.log('WRAPPED CLIENT TESTS'); + await callTests(client); + + await init('weavejs-dev-asynctest'); + console.log('WEAVE LOGGING TESTS'); + await callTests(client); +} + +oaiParse().then(result => console.log(result)); diff --git a/sdks/node/src/integrations/index.ts b/sdks/node/src/integrations/index.ts new file mode 100644 index 00000000000..5f8031da85f --- /dev/null +++ b/sdks/node/src/integrations/index.ts @@ -0,0 +1 @@ +export {wrapOpenAI} from './openai'; diff --git a/sdks/node/src/integrations/openai.ts b/sdks/node/src/integrations/openai.ts new file mode 100644 index 00000000000..c95587bbc2d --- /dev/null +++ b/sdks/node/src/integrations/openai.ts @@ -0,0 +1,238 @@ +import {weaveImage} from '../media'; +import {op} from '../op'; +import {OpOptions} from '../opType'; + +// exported just for testing +export const openAIStreamReducer = { + initialState: { + id: '', + object: 'chat.completion', + created: 0, + model: '', + choices: [ + { + index: 0, + message: { + role: 'assistant', + content: '', + function_call: null, + }, + finish_reason: null, + }, + ], + usage: null, + }, + reduceFn: (state: any, chunk: any) => { + if (chunk.id) state.id = chunk.id; + if (chunk.object) state.object = chunk.object; + if (chunk.created) state.created = chunk.created; + if (chunk.model) state.model = chunk.model; + + if (chunk.choices && chunk.choices.length > 0) { + const choice = chunk.choices[0]; + if (choice.delta) { + if (choice.delta.role) { + state.choices[0].message.role = choice.delta.role; + } + if (choice.delta.content) { + state.choices[0].message.content += choice.delta.content; + } + if (choice.delta.function_call) { + if (!state.choices[0].message.function_call) { + state.choices[0].message.function_call = { + name: '', + arguments: '', + }; + } + if (choice.delta.function_call.name) { + state.choices[0].message.function_call.name = + choice.delta.function_call.name; + } + if (choice.delta.function_call.arguments) { + state.choices[0].message.function_call.arguments += + choice.delta.function_call.arguments; + } + } + } + if (choice.finish_reason) { + state.choices[0].finish_reason = choice.finish_reason; + } + } + + if (chunk.usage) { + state.usage = chunk.usage; + } + + return state; + }, +}; + +export function makeOpenAIChatCompletionsOp(originalCreate: any, name: string) { + function wrapped(...args: Parameters) { + const [originalParams]: any[] = args; + if (originalParams.stream) { + return originalCreate({ + ...originalParams, + stream_options: {...originalParams.stream_options, include_usage: true}, + }); + } + + return originalCreate(originalParams); + } + + const options: OpOptions = { + name: name, + parameterNames: 'useParam0Object', + summarize: result => ({ + usage: { + [result.model]: result.usage, + }, + }), + streamReducer: openAIStreamReducer, + }; + + return op(wrapped, options); +} + +export function makeOpenAIImagesGenerateOp(originalGenerate: any) { + async function wrapped(...args: Parameters) { + const result = await originalGenerate(...args); + + // Process the result to convert image data to WeaveImage + if (result.data) { + result.data = await Promise.all( + result.data.map(async (item: any) => { + if (item.b64_json) { + const buffer = Buffer.from(item.b64_json, 'base64'); + return weaveImage({data: buffer, imageType: 'png'}); + } + return item; + }) + ); + } + + return result; + } + + const options: OpOptions = { + name: 'openai.images.generate', + summarize: result => ({ + usage: { + 'dall-e': { + images_generated: result.data.length, + }, + }, + }), + }; + + return op(wrapped, options); +} + +interface OpenAIAPI { + chat: { + completions: { + create: any; + }; + }; + images: { + generate: any; + }; + beta: { + chat: { + completions: { + parse: any; + }; + }; + }; +} + +/** + * Wraps the OpenAI API to enable function tracing for OpenAI calls. + * + * @example + * const openai = wrapOpenAI(new OpenAI()); + * const result = await openai.chat.completions.create({ + * model: 'gpt-3.5-turbo', + * messages: [{ role: 'user', content: 'Hello, world!' }] + * }); + */ +export function wrapOpenAI(openai: T): T { + const chatCompletionsProxy = new Proxy(openai.chat.completions, { + get(target, p, receiver) { + const targetVal = Reflect.get(target, p, receiver); + if (p === 'create') { + return makeOpenAIChatCompletionsOp( + targetVal.bind(target), + 'openai.chat.completions.create' + ); + } + return targetVal; + }, + }); + const chatProxy = new Proxy(openai.chat, { + get(target, p, receiver) { + const targetVal = Reflect.get(target, p, receiver); + if (p === 'completions') { + return chatCompletionsProxy; + } + return targetVal; + }, + }); + + const imagesProxy = new Proxy(openai.images, { + get(target, p, receiver) { + const targetVal = Reflect.get(target, p, receiver); + if (p === 'generate') { + return makeOpenAIImagesGenerateOp(targetVal.bind(target)); + } + return targetVal; + }, + }); + + const betaChatCompletionsProxy = new Proxy(openai.beta.chat.completions, { + get(target, p, receiver) { + const targetVal = Reflect.get(target, p, receiver); + if (p === 'parse') { + return makeOpenAIChatCompletionsOp( + targetVal.bind(target), + 'openai.beta.chat.completions.parse' + ); + } + return targetVal; + }, + }); + const betaChatProxy = new Proxy(openai.beta.chat, { + get(target, p, receiver) { + const targetVal = Reflect.get(target, p, receiver); + if (p === 'completions') { + return betaChatCompletionsProxy; + } + return targetVal; + }, + }); + const betaProxy = new Proxy(openai.beta, { + get(target, p, receiver) { + const targetVal = Reflect.get(target, p, receiver); + if (p === 'chat') { + return betaChatProxy; + } + return targetVal; + }, + }); + + return new Proxy(openai, { + get(target, p, receiver) { + const targetVal = Reflect.get(target, p, receiver); + if (p === 'chat') { + return chatProxy; + } + if (p === 'images') { + return imagesProxy; + } + if (p === 'beta') { + return betaProxy; + } + return targetVal; + }, + }); +} diff --git a/sdks/node/src/media.ts b/sdks/node/src/media.ts new file mode 100644 index 00000000000..ca44ae118df --- /dev/null +++ b/sdks/node/src/media.ts @@ -0,0 +1,79 @@ +export const DEFAULT_IMAGE_TYPE = 'png'; +export const DEFAULT_AUDIO_TYPE = 'wav'; + +export type ImageType = 'png'; +export type AudioType = 'wav'; + +// Define WeaveImage type +type WeaveImageInput = { + data: Buffer; + imageType?: ImageType; +}; + +interface WeaveImage extends WeaveImageInput { + _weaveType: 'Image'; +} + +/** + * Create a new WeaveImage object + * + * @param options The options for this media type + * @param options.data The raw image data as a Buffer + * @param options.imageType (Optional) The type of image file, currently only 'png' is supported + * + * @example + * const imageBuffer = fs.readFileSync('path/to/image.png'); + * const weaveImage = weaveImage({ data: imageBuffer }); + */ +export function weaveImage({data, imageType}: WeaveImageInput): WeaveImage { + const resolvedImageType = imageType ?? DEFAULT_IMAGE_TYPE; + return { + _weaveType: 'Image', + data, + imageType: resolvedImageType, + }; +} + +// Function to check if a value is a WeaveImage +export function isWeaveImage(value: any): value is WeaveImage { + return value && value._weaveType === 'Image'; +} + +type WeaveAudioInput = { + data: Buffer; + audioType?: AudioType; +}; + +export interface WeaveAudio extends WeaveAudioInput { + _weaveType: 'Audio'; +} + +/** + * Create a new WeaveAudio object + * + * @param options The options for this media type + * @param options.data The raw audio data as a Buffer + * @param options.audioType (Optional) The type of audio file, currently only 'wav' is supported + * + * @example + * const audioBuffer = fs.readFileSync('path/to/audio.wav'); + * const weaveAudio = weaveAudio({ data: audioBuffer }); + */ +export function weaveAudio({data, audioType}: WeaveAudioInput): WeaveAudio { + const resolvedAudioType = audioType ?? DEFAULT_AUDIO_TYPE; + return { + _weaveType: 'Audio', + data, + audioType: resolvedAudioType, + }; +} + +export function isWeaveAudio(value: any): value is WeaveAudio { + return value && value._weaveType === 'Audio'; +} + +type WeaveMedia = WeaveImage | WeaveAudio; + +export function isMedia(value: any): value is WeaveMedia { + return isWeaveImage(value) || isWeaveAudio(value); +} diff --git a/sdks/node/src/op.ts b/sdks/node/src/op.ts new file mode 100644 index 00000000000..a21a90c30fc --- /dev/null +++ b/sdks/node/src/op.ts @@ -0,0 +1,202 @@ +import {getGlobalClient} from './clientApi'; +import {TRACE_CALL_EMOJI} from './constants'; +import {Op, OpOptions} from './opType'; +import {getGlobalDomain} from './urls'; +import {warnOnce} from './utils/warnOnce'; + +/** + * A wrapper to weave op-ify a function or method that works on sync and async functions. + * + * Wrapped functions: + * 1. Take the same inputs and return the same outputs as the original function. + * 2. Will automatically track calls in the Weave UI. + * + * If you don't call `weave.init` then the function will behave as if it were not wrapped. + * + * @param fn The function to wrap + * @param options Optional configs like call and param naming + * @returns The wrapped function + * + * @example + * // Basic usage + * import OpenAI from 'openai'; + * import * as weave from 'weave'; + * + * const client = await weave.init({ project: 'my-project' }); + * const oaiClient = weave.wrapOpenAI(new OpenAI()); + * + * const extract = weave.op(async function extract() { + * return await oaiClient.chat.completions.create({ + * model: 'gpt-4-turbo', + * messages: [{ role: 'user', content: 'Create a user as JSON' }], + * }); + * }); + * + * await extract(); + * + * // You can also wrap methods by passing the object as the first argument. + * // This will bind the method to the object and wrap it with op. + * class MyModel { + * private oaiClient: OpenAI; + * + * constructor() { + * this.oaiClient = weave.wrapOpenAI(new OpenAI()); + * this.invoke = weave.op(this, this.invoke); + * } + * + * async invoke() { + * return await this.oaiClient.chat.completions.create({ + * model: 'gpt-4-turbo', + * messages: [{ role: 'user', content: 'Create a user as JSON' }], + * }); + * } + * } + * + * const model = new MyModel(); + * const res = await model.invoke(); + */ +export function op any>( + fn: T, + options?: OpOptions +): Op<(...args: Parameters) => Promise>>>; +export function op any>( + thisArg: any, + fn: T, + options?: OpOptions +): Op<(...args: Parameters) => Promise>>>; +export function op any>( + fnOrThis: T | any, + fnOrOptions?: T | OpOptions, + maybeOptions?: OpOptions +): Op<(...args: Parameters) => Promise>>> { + let fn: T; + let options: OpOptions | undefined; + let bindThis: any; + + if (typeof fnOrThis === 'function') { + fn = fnOrThis; + options = fnOrOptions as OpOptions; + } else { + bindThis = fnOrThis; + fn = fnOrOptions as T; + options = maybeOptions; + + const boundFn = fn.bind(bindThis) as T; + return op(boundFn, {originalFunction: fn, bindThis, ...options}); + } + + const opWrapper = async function ( + ...params: Parameters + ): Promise> { + const client = getGlobalClient(); + + if (!client) { + warnOnce( + 'weave-not-initialized', + 'WARNING: Weave is not initialized, so calls wont be tracked. Call `weave.init` to initialize before calling ops. If this is intentional, you can safely ignore this warning.' + ); + return await fn(...params); + } + + const {currentCall, parentCall, newStack} = client.pushNewCall(); + const startTime = new Date(); + if (client.settings.shouldPrintCallLink && parentCall == null) { + const domain = getGlobalDomain(); + console.log( + `${TRACE_CALL_EMOJI} https://${domain}/${client.projectId}/r/call/${currentCall.callId}` + ); + } + const displayName = options?.callDisplayName + ? options.callDisplayName(...params) + : undefined; + const thisArg = options?.bindThis; + const startCallPromise = client.createCall( + opWrapper, + params, + options?.parameterNames, + thisArg, + currentCall, + parentCall, + startTime, + displayName + ); + + try { + let result = await client.runWithCallStack(newStack, async () => { + return await fn(...params); + }); + + if (options?.streamReducer && Symbol.asyncIterator in result) { + const {initialState, reduceFn} = options.streamReducer; + let state = initialState; + + const wrappedIterator = { + [Symbol.asyncIterator]: async function* () { + try { + for await (const chunk of result as AsyncIterable) { + state = reduceFn(state, chunk); + yield chunk; + } + } finally { + if (client) { + // Check if globalClient still exists + const endTime = new Date(); + await client.finishCall( + state, + currentCall, + parentCall, + options?.summarize, + endTime, + startCallPromise + ); + } + } + }, + }; + + return wrappedIterator as unknown as ReturnType; + } else { + const endTime = new Date(); + await client.finishCall( + result, + currentCall, + parentCall, + options?.summarize, + endTime, + startCallPromise + ); + return result; + } + } catch (error) { + // console.error(`Op ${actualOpName} failed:`, error); + const endTime = new Date(); + await client.finishCallWithException( + error, + currentCall, + parentCall, + endTime, + startCallPromise + ); + await client.waitForBatchProcessing(); + throw error; + } + }; + + const fnName = options?.originalFunction?.name || fn.name || 'anonymous'; + const className = + options?.bindThis && + Object.getPrototypeOf(options.bindThis).constructor.name; + const actualOpName = + options?.name || (className ? `${className}.${fnName}` : fnName); + + opWrapper.__name = actualOpName; + opWrapper.__isOp = true as true; + opWrapper.__wrappedFunction = options?.originalFunction ?? fn; + opWrapper.__boundThis = options?.bindThis; + + return opWrapper as Op; +} + +export function isOp(fn: any): fn is Op { + return fn?.__isOp === true; +} diff --git a/sdks/node/src/opType.ts b/sdks/node/src/opType.ts new file mode 100644 index 00000000000..7312aec42e0 --- /dev/null +++ b/sdks/node/src/opType.ts @@ -0,0 +1,68 @@ +import {getGlobalDomain} from './urls'; +import {WeaveObject} from './weaveObject'; + +export type ParameterNamesOption = 'useParam0Object' | string[] | undefined; + +export type Op any> = { + __isOp: true; + __wrappedFunction: T; + __boundThis?: WeaveObject; + __name: string; + __savedRef?: OpRef | Promise; +} & T; + +interface StreamReducer { + initialState: R; + reduceFn: (state: R, chunk: T) => R; +} + +export interface OpOptions any> { + name?: string; + streamReducer?: StreamReducer; + originalFunction?: T; + callDisplayName?: (...args: Parameters) => string; + summarize?: (result: Awaited>) => Record; + bindThis?: WeaveObject; + parameterNames?: ParameterNamesOption; +} + +export function isOp(value: any): value is Op { + return value && value.__isOp === true; +} + +export function getOpWrappedFunction any>( + opValue: Op +): T { + return opValue.__wrappedFunction; +} + +export function getOpName(opValue: Op): string { + return opValue.__name; +} + +export function getOpParameterNames(opValue: Op): ParameterNamesOption { + return opValue.__parameterNames; +} + +export class OpRef { + constructor( + public projectId: string, + public objectId: string, + public digest: string + ) {} + + // TODO: Add extra + + public uri() { + return `weave:///${this.projectId}/op/${this.objectId}:${this.digest}`; + } + + public ui_url() { + const domain = getGlobalDomain(); + return `https://${domain}/${this.projectId}/weave/ops/${this.objectId}/versions/${this.digest}`; + } + + public async get() { + throw new Error('Not implemented'); + } +} diff --git a/sdks/node/src/refs.ts b/sdks/node/src/refs.ts new file mode 100644 index 00000000000..80940feea8b --- /dev/null +++ b/sdks/node/src/refs.ts @@ -0,0 +1,2 @@ +// TODO: Implement parseUri +// TODO: Implement CallRef diff --git a/sdks/node/src/settings.ts b/sdks/node/src/settings.ts new file mode 100644 index 00000000000..f2774832fc7 --- /dev/null +++ b/sdks/node/src/settings.ts @@ -0,0 +1,14 @@ +export class Settings { + constructor(private printCallLink: boolean = true) {} + + get shouldPrintCallLink(): boolean { + if (process.env.WEAVE_PRINT_CALL_LINK === 'true') { + return true; + } + if (process.env.WEAVE_PRINT_CALL_LINK === 'false') { + return false; + } + + return this.printCallLink; + } +} diff --git a/sdks/node/src/summary.ts b/sdks/node/src/summary.ts new file mode 100644 index 00000000000..b57f499cf12 --- /dev/null +++ b/sdks/node/src/summary.ts @@ -0,0 +1,69 @@ +import {CallStackEntry} from './weaveClient'; + +/** + * Represents a summary object with string keys and any type of values. + */ +type Summary = Record; +/** + * Merges two summary objects, combining their values. + * + * @param left - The first summary object to merge. + * @param right - The second summary object to merge. + * @returns A new summary object containing the merged values. + * + * This function performs a deep merge of two summary objects: + * - For numeric values, it adds them together. + * - For nested objects, it recursively merges them. + * - For other types, the left value "wins". + */ +function mergeSummaries(left: Summary, right: Summary): Summary { + const result: Summary = {...right}; + for (const [key, leftValue] of Object.entries(left)) { + if (key in result) { + if (typeof leftValue === 'number' && typeof result[key] === 'number') { + result[key] = leftValue + result[key]; + } else if ( + typeof leftValue === 'object' && + typeof result[key] === 'object' + ) { + result[key] = mergeSummaries(leftValue, result[key]); + } else { + result[key] = leftValue; + } + } else { + result[key] = leftValue; + } + } + return result; +} + +export function processSummary( + result: any, + summarize: ((result: any) => Record) | undefined, + currentCall: CallStackEntry, + parentCall: CallStackEntry | undefined +) { + let ownSummary = summarize ? summarize(result) : {}; + + if (ownSummary.usage) { + for (const model in ownSummary.usage) { + if (typeof ownSummary.usage[model] === 'object') { + ownSummary.usage[model] = { + requests: 1, + ...ownSummary.usage[model], + }; + } + } + } + + const mergedSummary = mergeSummaries(ownSummary, currentCall.childSummary); + + if (parentCall) { + parentCall.childSummary = mergeSummaries( + mergedSummary, + parentCall.childSummary + ); + } + + return mergedSummary; +} diff --git a/sdks/node/src/table.ts b/sdks/node/src/table.ts new file mode 100644 index 00000000000..0bdaff9516f --- /dev/null +++ b/sdks/node/src/table.ts @@ -0,0 +1,46 @@ +export class TableRef { + constructor( + public projectId: string, + public digest: string + ) {} + + public uri() { + return `weave:///${this.projectId}/table/${this.digest}`; + } +} + +export class TableRowRef { + constructor( + public projectId: string, + public digest: string, + public rowDigest: string + ) {} + + public uri() { + return `weave:///${this.projectId}/table/${this.digest}/id/${this.rowDigest}`; + } +} + +type TableRow = Record & { + __savedRef?: TableRowRef | Promise; +}; + +export class Table { + __savedRef?: TableRef | Promise; + + constructor(public rows: R[]) {} + + get length(): number { + return this.rows.length; + } + + async *[Symbol.asyncIterator](): AsyncIterator { + for (let i = 0; i < this.length; i++) { + yield this.row(i); + } + } + + row(index: number): R { + return this.rows[index]; + } +} diff --git a/sdks/node/src/tsconfig.src.json b/sdks/node/src/tsconfig.src.json new file mode 100644 index 00000000000..82e46d097a6 --- /dev/null +++ b/sdks/node/src/tsconfig.src.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "exclude": [], + "compilerOptions": { + "rootDir": ".", + "outDir": "../dist/src" + } +} diff --git a/sdks/node/src/types.ts b/sdks/node/src/types.ts new file mode 100644 index 00000000000..6a98ef72467 --- /dev/null +++ b/sdks/node/src/types.ts @@ -0,0 +1,4 @@ +import {Op} from './opType'; +import {WeaveClient} from './weaveClient'; + +export {Op, WeaveClient}; diff --git a/sdks/node/src/urls.ts b/sdks/node/src/urls.ts new file mode 100644 index 00000000000..c96d0916016 --- /dev/null +++ b/sdks/node/src/urls.ts @@ -0,0 +1,23 @@ +export const defaultHost = 'api.wandb.ai'; +export const defaultDomain = 'wandb.ai'; + +export function getUrls(host?: string) { + const resolvedHost = host ?? defaultHost; + const isDefault = resolvedHost === defaultHost; + + return { + baseUrl: isDefault ? `https://api.wandb.ai` : `https://${resolvedHost}`, + traceBaseUrl: isDefault + ? `https://trace.wandb.ai` + : `https://${resolvedHost}`, + domain: isDefault ? defaultHost : resolvedHost, + }; +} + +let globalDomain: string | undefined = undefined; +export function getGlobalDomain() { + return globalDomain; +} +export function setGlobalDomain(domain: string) { + globalDomain = domain; +} diff --git a/sdks/node/src/utils/concurrencyLimit.ts b/sdks/node/src/utils/concurrencyLimit.ts new file mode 100644 index 00000000000..e675a30f6f9 --- /dev/null +++ b/sdks/node/src/utils/concurrencyLimit.ts @@ -0,0 +1,49 @@ +export class ConcurrencyLimiter { + private activeCount = 0; + private queue: (() => void)[] = []; + + constructor(private limit: number) {} + + get active(): number { + return this.activeCount; + } + + get pending(): number { + return this.queue.length; + } + + private tryExecuteNext() { + if (this.queue.length > 0 && this.activeCount < this.limit) { + const nextTask = this.queue.shift(); + this.activeCount++; + nextTask!(); + } + } + + limitFunction( + asyncFn: (...args: T) => Promise + ): (...args: T) => Promise { + return async (...args: T): Promise => { + return new Promise((resolve, reject) => { + const task = async () => { + try { + const result = await asyncFn(...args); + resolve(result); + } catch (e) { + reject(e); + } finally { + this.activeCount--; + this.tryExecuteNext(); + } + }; + + if (this.activeCount < this.limit) { + this.activeCount++; + task(); + } else { + this.queue.push(task); + } + }); + }; + } +} diff --git a/sdks/node/src/utils/netrc.ts b/sdks/node/src/utils/netrc.ts new file mode 100644 index 00000000000..f878f4b6997 --- /dev/null +++ b/sdks/node/src/utils/netrc.ts @@ -0,0 +1,86 @@ +import {readFileSync, writeFileSync} from 'fs'; +import {homedir} from 'os'; +import {join} from 'path'; + +interface NetrcEntry { + machine: string; + login: string; + password: string; + account?: string; +} + +export class Netrc { + private path: string; + public entries: Map; + + constructor(path: string = join(homedir(), '.netrc')) { + this.path = path; + this.entries = new Map(); + this.load(); + } + + private load(): void { + try { + const content = readFileSync(this.path, 'utf8'); + const lines = content.split('\n'); + let currentMachine: string | null = null; + let currentEntry: Partial = {}; + + for (const line of lines) { + const [key, value] = line.trim().split(/\s+/); + switch (key) { + case 'machine': + if (currentMachine && Object.keys(currentEntry).length) { + this.entries.set(currentMachine, currentEntry as NetrcEntry); + } + currentMachine = value; + currentEntry = {machine: value}; + break; + case 'login': + case 'password': + case 'account': + if (currentMachine) { + currentEntry[key] = value; + } + break; + } + } + + if (currentMachine && Object.keys(currentEntry).length > 1) { + this.entries.set(currentMachine, currentEntry as NetrcEntry); + } + } catch (error) { + // File doesn't exist or can't be read, starting with empty entries + } + } + + save(): void { + const content = Array.from(this.entries.entries()) + .map(([machine, entry]) => { + let str = `machine ${machine}\n`; + if (entry.login) str += ` login ${entry.login}\n`; + if (entry.password) str += ` password ${entry.password}\n`; + if (entry.account) str += ` account ${entry.account}\n`; + return str; + }) + .join('\n'); + + writeFileSync(this.path, content, {mode: 0o600}); + } + + getEntry(machine: string): NetrcEntry | undefined { + return this.entries.get(machine); + } + + setEntry(machine: string, entry: Partial): void { + const existingEntry = this.entries.get(machine) || {machine}; + const updatedEntry = {...existingEntry, ...entry} as NetrcEntry; + this.entries.delete(machine); + this.entries.set(machine, updatedEntry); + } + + getLastEntry(): NetrcEntry | undefined { + const entries = Array.from(this.entries.values()); + return entries[entries.length - 1]; + } +} diff --git a/sdks/node/src/utils/retry.ts b/sdks/node/src/utils/retry.ts new file mode 100644 index 00000000000..29ecf3c206e --- /dev/null +++ b/sdks/node/src/utils/retry.ts @@ -0,0 +1,59 @@ +type RetryOptions = { + maxRetries?: number; + baseDelay?: number; + maxDelay?: number; + maxRetryTime?: number; + retryOnStatus?: (status: number) => boolean; +}; + +export function createFetchWithRetry(options: RetryOptions = {}) { + const { + maxRetries = 5, + baseDelay = 100, + maxDelay = 10000, + maxRetryTime = 10000, + retryOnStatus = (status: number) => status !== 429 && status !== 500, + } = options; + + return async function fetchWithRetry( + ...fetchParams: Parameters + ): Promise { + let attempt = 0; + + while (attempt <= maxRetries) { + const startTime = Date.now(); + try { + const response = await fetch(...fetchParams); + + if ( + response.ok || + !retryOnStatus(response.status) || + attempt === maxRetries || + Date.now() - startTime > maxRetryTime + ) { + // Always return the response, even if it's not ok + return response; + } + + // Exponential backoff delay + const delay = Math.min(baseDelay * 2 ** attempt, maxDelay); + console.log( + `Return code: ${response.status}. Retrying fetch after ${delay}ms` + ); + await new Promise(resolve => setTimeout(resolve, delay)); + attempt++; + } catch (error) { + if (attempt === maxRetries || Date.now() - startTime > maxRetryTime) { + // Rethrow the original error + throw error; + } + // Exponential backoff delay + const delay = Math.min(baseDelay * 2 ** attempt, maxDelay); + console.log(`Exception ${error} Retrying fetch after ${delay}ms`); + await new Promise(resolve => setTimeout(resolve, delay)); + attempt++; + } + } + throw new Error("Failed to fetch. Shouldn't get here"); + }; +} diff --git a/sdks/node/src/utils/userAgent.ts b/sdks/node/src/utils/userAgent.ts new file mode 100644 index 00000000000..b293174c98a --- /dev/null +++ b/sdks/node/src/utils/userAgent.ts @@ -0,0 +1,24 @@ +import {existsSync, readFileSync} from 'fs'; +import {join} from 'path'; + +export let packageVersion: string; + +const twoLevelsUp = join(__dirname, '..', '..', 'package.json'); +const oneLevelUp = join(__dirname, '..', 'package.json'); + +if (existsSync(twoLevelsUp)) { + // This is the case in the built npm package + const packageJson = JSON.parse(readFileSync(twoLevelsUp, 'utf8')); + packageVersion = packageJson.version; +} else if (existsSync(oneLevelUp)) { + // This is the case in dev + const packageJson = JSON.parse(readFileSync(oneLevelUp, 'utf8')); + packageVersion = packageJson.version; +} else { + console.warn('Failed to find package.json'); + packageVersion = 'unknown'; +} + +export function userAgent() { + return `Weave JS Client ${packageVersion}`; +} diff --git a/sdks/node/src/utils/warnOnce.ts b/sdks/node/src/utils/warnOnce.ts new file mode 100644 index 00000000000..be872fb4ee9 --- /dev/null +++ b/sdks/node/src/utils/warnOnce.ts @@ -0,0 +1,8 @@ +const warnedKeys = new Set(); + +export function warnOnce(key: string, message: string): void { + if (!warnedKeys.has(key)) { + console.warn(message); + warnedKeys.add(key); + } +} diff --git a/sdks/node/src/wandb/settings.ts b/sdks/node/src/wandb/settings.ts new file mode 100644 index 00000000000..7b6b8ad7176 --- /dev/null +++ b/sdks/node/src/wandb/settings.ts @@ -0,0 +1,46 @@ +import {defaultDomain, defaultHost, getUrls} from '../urls'; +import {Netrc} from '../utils/netrc'; + +export function getApiKey(host: string): string { + let apiKey = process.env.WANDB_API_KEY; + if (!apiKey) { + const netrc = new Netrc(); + apiKey = netrc.entries.get(host)?.password; + } + if (!apiKey) { + // const domain = getGlobalDomain(); + const domain = defaultHost; + const apiKeyNotFoundMessage = ` + wandb API key not found. + + Go to https://${domain}/authorize to get your API key. + + You can either: + + 1. Set the WANDB_API_KEY environment variable. + 2. Log in using weave.login() + 3. Add your API key to your .netrc file, in a stanza like this: + machine ${domain} + login user + password + `; + throw new Error(apiKeyNotFoundMessage); + } + return apiKey; +} + +export function getWandbConfigs() { + let host; + try { + host = new Netrc().getLastEntry()!.machine; + } catch (error) { + throw new Error( + `Could not find entry in netrc file. + Visit https://${defaultDomain}/authorize to get an API key and run + \`weave.login({apiKey: $YOUR_API_KEY})\` or \`wandb login\` if you have that installed.` + ); + } + const apiKey = getApiKey(host); + const {baseUrl, traceBaseUrl, domain} = getUrls(host); + return {apiKey, baseUrl, traceBaseUrl, domain}; +} diff --git a/sdks/node/src/wandb/wandbServerApi.ts b/sdks/node/src/wandb/wandbServerApi.ts new file mode 100644 index 00000000000..376bc15c2a9 --- /dev/null +++ b/sdks/node/src/wandb/wandbServerApi.ts @@ -0,0 +1,73 @@ +import {userAgent} from '../utils/userAgent'; + +const VIEWER_DEFAULT_ENTITY_QUERY = ` +query DefaultEntity { + viewer { + username + defaultEntity { + name + } + } +} +`; + +export class WandbServerApi { + constructor( + public baseUrl: string, + private apiKey: string + ) {} + + private async graphqlRequest( + query: string, + variables: Record = {} + ) { + try { + const response = await fetch(`${this.baseUrl}/graphql`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'User-Agent': userAgent(), + Authorization: `Basic ${Buffer.from(`api:${this.apiKey}`).toString('base64')}`, + }, + body: JSON.stringify({ + query, + variables, + }), + }); + + if (!response.ok) { + throw new Error( + `HTTP error! status: ${response.status}, statusText: ${response.statusText}` + ); + } + + const result = await response.json(); + + if (result.errors) { + throw new Error(`GraphQL Error: ${JSON.stringify(result.errors)}`); + } + + return result.data; + } catch (error) { + console.error('Error in graphqlRequest:', error); + throw error; + } + } + + async defaultEntityName() { + try { + const result = await this.graphqlRequest(VIEWER_DEFAULT_ENTITY_QUERY); + if ( + !result.viewer || + !result.viewer.defaultEntity || + !result.viewer.defaultEntity.name + ) { + throw new Error('Default entity name not found in the response'); + } + return result.viewer.defaultEntity.name; + } catch (error) { + console.error('Error in defaultEntityName:', error); + throw error; + } + } +} diff --git a/sdks/node/src/weaveClient.ts b/sdks/node/src/weaveClient.ts new file mode 100644 index 00000000000..1a10cb2bec8 --- /dev/null +++ b/sdks/node/src/weaveClient.ts @@ -0,0 +1,781 @@ +import {AsyncLocalStorage} from 'async_hooks'; +import {uuidv7} from 'uuidv7'; + +import {Dataset} from './dataset'; +import {computeDigest} from './digest'; +import { + CallSchema, + CallsFilter, + EndedCallSchemaForInsert, + StartedCallSchemaForInsert, + Api as TraceServerApi, +} from './generated/traceServerApi'; +import { + AudioType, + DEFAULT_AUDIO_TYPE, + DEFAULT_IMAGE_TYPE, + ImageType, + isWeaveAudio, + isWeaveImage, +} from './media'; +import { + Op, + OpRef, + ParameterNamesOption, + getOpName, + getOpWrappedFunction, + isOp, +} from './opType'; +import {Settings} from './settings'; +import {Table, TableRef, TableRowRef} from './table'; +import {packageVersion} from './utils/userAgent'; +import {WandbServerApi} from './wandb/wandbServerApi'; +import {ObjectRef, WeaveObject, getClassChain} from './weaveObject'; + +export type CallStackEntry = { + callId: string; + traceId: string; + childSummary: Record; +}; + +function generateTraceId(): string { + return uuidv7(); +} + +function generateCallId(): string { + return uuidv7(); +} + +class CallStack { + constructor(private stack: CallStackEntry[] = []) {} + + peek(): CallStackEntry | null { + return this.stack[this.stack.length - 1] ?? null; + } + + pushNewCall(): { + currentCall: CallStackEntry; + parentCall?: CallStackEntry; + newStack: CallStack; + } { + const parentCall = this.stack[this.stack.length - 1]; + + const callId = generateCallId(); + const traceId = parentCall?.traceId ?? generateTraceId(); + const newCall: CallStackEntry = {callId, traceId, childSummary: {}}; + const newStack = new CallStack([...this.stack, newCall]); + return {currentCall: newCall, parentCall, newStack}; + } +} + +type CallStartParams = StartedCallSchemaForInsert; +type CallEndParams = EndedCallSchemaForInsert; + +export class WeaveClient { + private stackContext = new AsyncLocalStorage(); + private callQueue: Array<{mode: 'start' | 'end'; data: any}> = []; + private batchProcessTimeout: NodeJS.Timeout | null = null; + private isBatchProcessing: boolean = false; + private batchProcessingPromises: Set> = new Set(); + private readonly BATCH_INTERVAL: number = 200; + + constructor( + public traceServerApi: TraceServerApi, + private wandbServerApi: WandbServerApi, + public projectId: string, + public settings: Settings = new Settings() + ) {} + + private scheduleBatchProcessing() { + if (this.batchProcessTimeout || this.isBatchProcessing) return; + const promise = new Promise(resolve => { + this.batchProcessTimeout = setTimeout( + () => this.processBatch().then(resolve), + this.BATCH_INTERVAL + ); + }); + this.batchProcessingPromises.add(promise); + promise.finally(() => { + this.batchProcessingPromises.delete(promise); + }); + } + + public async waitForBatchProcessing() { + while (this.batchProcessingPromises.size > 0) { + await Promise.all(this.batchProcessingPromises); + } + } + + private async processBatch() { + if (this.isBatchProcessing || this.callQueue.length === 0) { + this.batchProcessTimeout = null; + return; + } + + this.isBatchProcessing = true; + + // We count characters item by item, and try to limit batches to about + // this size. + const maxBatchSizeChars = 5 * 1024 * 1024; + + let batchToProcess = []; + let currentBatchSize = 0; + + while (this.callQueue.length > 0 && currentBatchSize < maxBatchSizeChars) { + const item = this.callQueue[0]; + const itemSize = JSON.stringify(item).length; + + if (currentBatchSize + itemSize <= maxBatchSizeChars) { + batchToProcess.push(this.callQueue.shift()!); + currentBatchSize += itemSize; + } else { + break; + } + } + + const batchReq = { + batch: batchToProcess.map(item => ({ + mode: item.mode, + req: item.data, + })), + }; + + try { + await this.traceServerApi.call.callStartBatchCallUpsertBatchPost( + batchReq + ); + } catch (error) { + console.error('Error processing batch:', error); + // Put failed items back at the front of the queue + this.callQueue.unshift(...batchToProcess); + } finally { + this.isBatchProcessing = false; + this.batchProcessTimeout = null; + if (this.callQueue.length > 0) { + this.scheduleBatchProcessing(); + } + } + } + + public publish(obj: any, objId?: string): Promise { + if (obj.__savedRef) { + return obj.__savedRef; + } else if (obj instanceof WeaveObject) { + return this.saveObject(obj, objId); + } else if (isOp(obj)) { + return this.saveOp(obj); + } else { + return this.saveArbitrary(obj, objId); + } + } + + public async getCalls( + filter: CallsFilter = {}, + includeCosts: boolean = false, + limit: number = 1000 + ) { + const calls: CallSchema[] = []; + const iterator = this.getCallsIterator(filter, includeCosts, limit); + for await (const call of iterator) { + calls.push(call); + } + return calls; + } + public async *getCallsIterator( + filter: CallsFilter = {}, + includeCosts: boolean = false, + limit: number = 1000 + ): AsyncIterableIterator { + const resp = + await this.traceServerApi.calls.callsQueryStreamCallsStreamQueryPost({ + project_id: this.projectId, + filter, + include_costs: includeCosts, + limit, + }); + + const reader = resp.body!.getReader(); + const decoder = new TextDecoder(); + let buffer = ''; + + while (true) { + const {value, done} = await reader.read(); + if (done) break; + + buffer += decoder.decode(value, {stream: true}); + const lines = buffer.split('\n'); + buffer = lines.pop() || ''; + + for (const line of lines) { + if (line.trim()) { + try { + yield JSON.parse(line); + } catch (error) { + console.error('Error parsing JSON:', error, 'Line:', line); + } + } + } + } + + if (buffer.trim()) { + try { + yield JSON.parse(buffer); + } catch (error) { + console.error('Error parsing JSON:', error, 'Remaining data:', buffer); + } + } + } + + public async get(ref: ObjectRef): Promise { + let val: any; + try { + const res = await this.traceServerApi.obj.objReadObjReadPost({ + project_id: ref.projectId, + object_id: ref.objectId, + digest: ref.digest, + }); + val = res.data.obj.val; + } catch (error) { + if (error instanceof Error && error.message.includes('404')) { + throw new Error(`Unable to find object for ref uri: ${ref.uri()}`); + } + throw error; + } + + const t = val?._type; + if (t == 'Dataset') { + const {_baseParameters, rows} = val; + let obj = new Dataset({ + id: _baseParameters.id, + description: _baseParameters.description, + rows, + }); + obj.__savedRef = ref; + // TODO: The table row refs are not correct + return obj; + } else if (t == 'Table') { + const {rows} = val; + let obj = new Table(rows); + obj.__savedRef = ref; + return obj; + } else if (t == 'CustomWeaveType') { + const typeName = val.weave_type.type; + if (typeName == 'PIL.Image.Image') { + let loadedFiles: {[key: string]: Buffer} = {}; + for (const [name, digest] of Object.entries(val.files)) { + try { + const fileContent = + await this.traceServerApi.file.fileContentFileContentPost({ + project_id: this.projectId, + digest: digest as string, + }); + loadedFiles[name] = fileContent.data?.content; + } catch (error) { + console.error('Error loading file:', error); + } + } + // TODO: Implement getting img back as buffer + return 'Coming soon!'; + } else if (typeName == 'wave.Wave_read') { + let loadedFiles: {[key: string]: Buffer} = {}; + for (const [name, digest] of Object.entries(val.files)) { + try { + const fileContent = + await this.traceServerApi.file.fileContentFileContentPost({ + project_id: this.projectId, + digest: digest as string, + }); + loadedFiles[name] = fileContent.data?.content; + } catch (error) { + console.error('Error loading file:', error); + } + } + // TODO: Implement getting audio back as buffer + return 'Coming soon!'; + } + } + return val; + } + + // save* methods attached __savedRef promises to their values. These must + // be synchronous, so we can guarantee that calling savedWeaveValues + // immediately makes __savedRef promises available. + + private saveArbitrary(obj: any, objId?: string): Promise { + if (obj.__savedRef) { + return obj.__savedRef; + } + + const ref = (async () => { + if (!objId) { + objId = uuidv7(); + } + + const serializedObj = await this.serializedVal(obj); + const response = await this.traceServerApi.obj.objCreateObjCreatePost({ + obj: { + project_id: this.projectId, + object_id: objId, + val: serializedObj, + }, + }); + return new ObjectRef(this.projectId, objId, response.data.digest); + })(); + + obj.__savedRef = ref; + return ref; + } + + private saveObject(obj: WeaveObject, objId?: string): Promise { + if (obj.__savedRef) { + return Promise.resolve(obj.__savedRef); + } + for (const [key, value] of Object.entries(obj)) { + this.saveWeaveValues(value); + } + + obj.__savedRef = (async () => { + const classChain = getClassChain(obj); + const className = classChain[0]; + if (!objId) { + objId = obj.id; + } + + let saveAttrs = obj.saveAttrs(); + saveAttrs = await this.serializedVal(saveAttrs); + // Frontend does this overly specific check for datasets, so we need to add both _type and _class_name + // for now. + // data._type === 'Dataset' && + // data._class_name === 'Dataset' && + // _.isEqual(data._bases, ['Object', 'BaseModel']) + const saveValue = { + _type: className, + _class_name: className, + _bases: classChain.slice(1), + ...saveAttrs, + }; + const response = await this.traceServerApi.obj.objCreateObjCreatePost({ + obj: { + project_id: this.projectId, + object_id: objId, + val: saveValue, + }, + }); + const ref = new ObjectRef(this.projectId, objId, response.data.digest); + // console.log(`Saved object: ${ref.ui_url()}`); + return ref; + })(); + + return obj.__savedRef; + } + + private saveTable(table: Table): void { + if (table.__savedRef) { + return; + } + + table.__savedRef = (async () => { + const rowsWithoutRefs = table.rows.map(row => { + return {...row, __savedRef: undefined}; + }); + const rows = await this.serializedVal(rowsWithoutRefs); + const response = + await this.traceServerApi.table.tableCreateTableCreatePost({ + table: { + project_id: this.projectId, + rows, + }, + }); + const ref = new TableRef(this.projectId, response.data.digest); + return ref; + })(); + const tableQueryPromise = (async () => { + const tableRef = await table.__savedRef; + const tableQueryRes = + await this.traceServerApi.table.tableQueryTableQueryPost({ + project_id: this.projectId, + digest: tableRef?.digest!, + }); + return { + tableDigest: tableRef?.digest!, + tableQueryResult: tableQueryRes.data, + }; + })(); + for (let i = 0; i < table.rows.length; i++) { + const row = table.rows[i]; + row.__savedRef = (async () => { + const {tableDigest, tableQueryResult} = await tableQueryPromise; + return new TableRowRef( + this.projectId, + tableDigest, + tableQueryResult.rows[i].digest + ); + })(); + } + } + + /** + * Recursively save a Weave value, attaching __savedRef Promises to + * nested value that gets its own ref. + * + * This function must be synchronous, so that code that does ref-tracking + * (currently only Dataset/DatasetRow in the js client) has refs + * available immediately. + */ + private saveWeaveValues(val: any): void { + if (Array.isArray(val)) { + val.map(item => this.saveWeaveValues(item)); + } else if (val != null && val.__savedRef) { + return; + } else if (val instanceof WeaveObject) { + this.saveObject(val); + } else if (val instanceof Table) { + this.saveTable(val); + } else if (isWeaveImage(val)) { + } else if (isWeaveAudio(val)) { + } else if (isOp(val)) { + this.saveOp(val); + } else if (typeof val === 'object' && val !== null) { + for (const [key, value] of Object.entries(val)) { + this.saveWeaveValues(value); + } + } + } + + // serialize* methods are async, and return the serialized value + // of a Weave value. + + private async serializedFileBlob( + typeName: string, + fileName: string, + fileContent: Blob + ): Promise { + const buffer = await fileContent.arrayBuffer().then(Buffer.from); + const digest = computeDigest(buffer); + + const placeholder = { + _type: 'CustomWeaveType', + weave_type: {type: typeName}, + files: { + [fileName]: digest, + }, + load_op: 'NO_LOAD_OP', + }; + + try { + await this.traceServerApi.file.fileCreateFileCreatePost({ + project_id: this.projectId, + // @ts-ignore + file: fileContent, + }); + } catch (error) { + console.error('Error saving file:', error); + } + + return placeholder; + } + + private async serializedImage( + imageData: Buffer, + imageType: ImageType = DEFAULT_IMAGE_TYPE + ): Promise { + const blob = new Blob([imageData], {type: `image/${imageType}`}); + return this.serializedFileBlob('PIL.Image.Image', 'image.png', blob); + } + + private async serializedAudio( + audioData: Buffer, + audioType: AudioType = DEFAULT_AUDIO_TYPE + ): Promise { + const blob = new Blob([audioData], {type: `audio/${audioType}`}); + return this.serializedFileBlob('wave.Wave_read', 'audio.wav', blob); + } + + /** + * Get the serialized value of a Weave value, by recursively + * resolving any __savedRef promises to their uri(). + * + * This function is asynchronous, and must be called after saveWeaveValues + * has been called on the value. + */ + private async serializedVal(val: any): Promise { + if (Array.isArray(val)) { + return Promise.all(val.map(async item => this.serializedVal(item))); + } else if (val != null && val.__savedRef) { + return (await val.__savedRef).uri(); + } else if (isWeaveImage(val)) { + return await this.serializedImage(val.data, val.imageType); + } else if (isWeaveAudio(val)) { + return await this.serializedAudio(val.data, val.audioType); + } else if (val instanceof WeaveObject) { + throw new Error('Programming error: WeaveObject not saved'); + } else if (val instanceof Table) { + throw new Error('Programming error: Table not saved'); + } else if (isOp(val)) { + throw new Error('Programming error: Op not saved'); + } else if (typeof val === 'object' && val !== null) { + const result: {[key: string]: any} = {}; + for (const [key, value] of Object.entries(val)) { + result[key] = await this.serializedVal(value); + } + return result; + } else { + return val; + } + } + + private saveCallStart(callStart: CallStartParams) { + this.callQueue.push({mode: 'start', data: {start: callStart}}); + this.scheduleBatchProcessing(); + } + + private saveCallEnd(callEnd: CallEndParams) { + this.callQueue.push({mode: 'end', data: {end: callEnd}}); + this.scheduleBatchProcessing(); + } + + public getCallStack(): CallStack { + return this.stackContext.getStore() || new CallStack(); + } + + public pushNewCall() { + return this.getCallStack().pushNewCall(); + } + + public runWithCallStack(callStack: CallStack, fn: () => T): T { + return this.stackContext.run(callStack, fn); + } + + private async paramsToCallInputs( + params: any[], + thisArg: any, + parameterNames: ParameterNamesOption + ) { + let inputs: Record = {}; + + // Add 'self' first if thisArg is a WeaveObject + if (thisArg instanceof WeaveObject) { + inputs['self'] = thisArg; + } + if (parameterNames === 'useParam0Object') { + inputs = {...inputs, ...params[0]}; + } else if (parameterNames) { + params.forEach((arg, index) => { + inputs[parameterNames[index]] = arg; + }); + } else { + params.forEach((arg, index) => { + inputs[`arg${index}`] = arg; + }); + } + this.saveWeaveValues(inputs); + return await this.serializedVal(inputs); + } + + public async saveOp( + op: Op<(...args: any[]) => any>, + objId?: string + ): Promise { + if (op.__savedRef) { + return op.__savedRef; + } + op.__savedRef = (async () => { + const resolvedObjId = objId || getOpName(op); + const opFn = getOpWrappedFunction(op); + const formattedOpFn = await maybeFormatCode(opFn.toString()); + const saveValue = await this.serializedFileBlob( + 'Op', + 'obj.py', + new Blob([formattedOpFn]) + ); + const response = await this.traceServerApi.obj.objCreateObjCreatePost({ + obj: { + project_id: this.projectId, + object_id: resolvedObjId, + val: saveValue, + }, + }); + const ref = new OpRef( + this.projectId, + resolvedObjId, + response.data.digest + ); + + // console.log('Saved op: ', ref.ui_url()); + return ref; + })(); + return op.__savedRef; + } + + public async createCall( + opRef: OpRef | Op, + params: any[], + parameterNames: ParameterNamesOption, + thisArg: any, + currentCall: CallStackEntry, + parentCall: CallStackEntry | undefined, + startTime: Date, + displayName?: string + ) { + const inputs = await this.paramsToCallInputs( + params, + thisArg, + parameterNames + ); + if (isOp(opRef)) { + this.saveOp(opRef); + opRef = await opRef.__savedRef; + } + const startReq = { + project_id: this.projectId, + id: currentCall.callId, + op_name: opRef.uri(), + trace_id: currentCall.traceId, + parent_id: parentCall?.callId, + started_at: startTime.toISOString(), + display_name: displayName, + attributes: { + weave: { + client_version: packageVersion, + source: 'js-sdk', + }, + }, + inputs, + }; + return this.saveCallStart(startReq); + } + + public async finishCall( + result: any, + currentCall: CallStackEntry, + parentCall: CallStackEntry | undefined, + summarize: undefined | ((result: any) => Record), + endTime: Date, + startCallPromise: Promise + ) { + // Important to do this first before any awaiting, so we're guaranteed that children + // summaries are processed before parents! + const mergedSummary = processSummary( + result, + summarize, + currentCall, + parentCall + ); + // ensure end is logged after start is logged + await startCallPromise; + this.saveWeaveValues(result); + result = await this.serializedVal(result); + await this.saveCallEnd({ + project_id: this.projectId, + id: currentCall.callId, + ended_at: endTime.toISOString(), + output: result, + summary: mergedSummary, + }); + } + + public async finishCallWithException( + error: any, + currentCall: CallStackEntry, + parentCall: CallStackEntry | undefined, + endTime: Date, + startCallPromise: Promise + ) { + const mergedSummary = processSummary( + null, + undefined, + currentCall, + parentCall + ); + // ensure end is logged after start is logged + await startCallPromise; + await this.saveCallEnd({ + project_id: this.projectId, + id: currentCall.callId, + ended_at: endTime.toISOString(), + output: null, + summary: mergedSummary, + exception: error instanceof Error ? error.message : String(error), + }); + } +} + +/** + * Represents a summary object with string keys and any type of values. + */ +type Summary = Record; + +/** + * Merges two summary objects, combining their values. + * + * @param left - The first summary object to merge. + * @param right - The second summary object to merge. + * @returns A new summary object containing the merged values. + * + * This function performs a deep merge of two summary objects: + * - For numeric values, it adds them together. + * - For nested objects, it recursively merges them. + * - For other types, the left value "wins". + */ +function mergeSummaries(left: Summary, right: Summary): Summary { + const result: Summary = {...right}; + for (const [key, leftValue] of Object.entries(left)) { + if (key in result) { + if (typeof leftValue === 'number' && typeof result[key] === 'number') { + result[key] = leftValue + result[key]; + } else if ( + typeof leftValue === 'object' && + typeof result[key] === 'object' + ) { + result[key] = mergeSummaries(leftValue, result[key]); + } else { + result[key] = leftValue; + } + } else { + result[key] = leftValue; + } + } + return result; +} + +function processSummary( + result: any, + summarize: ((result: any) => Record) | undefined, + currentCall: CallStackEntry, + parentCall: CallStackEntry | undefined +) { + let ownSummary = summarize && result != null ? summarize(result) : {}; + + if (ownSummary.usage) { + for (const model in ownSummary.usage) { + if (typeof ownSummary.usage[model] === 'object') { + ownSummary.usage[model] = { + requests: 1, + ...ownSummary.usage[model], + }; + } + } + } + + const mergedSummary = mergeSummaries(ownSummary, currentCall.childSummary); + + if (parentCall) { + parentCall.childSummary = mergeSummaries( + mergedSummary, + parentCall.childSummary + ); + } + + return mergedSummary; +} + +async function maybeFormatCode(code: string) { + return code; + // try { + // const prettier = await import('prettier'); + // return prettier.format(code, { parser: 'babel' }); + // } catch (error) { + // // prettier not available or formatting failed, just use the original string + // return code; + // } +} diff --git a/sdks/node/src/weaveObject.ts b/sdks/node/src/weaveObject.ts new file mode 100644 index 00000000000..41a7eb046ef --- /dev/null +++ b/sdks/node/src/weaveObject.ts @@ -0,0 +1,101 @@ +import {requireGlobalClient} from './clientApi'; +import {isOp} from './op'; +import {getGlobalDomain} from './urls'; + +export interface Callable {} + +export interface WeaveObjectParameters { + id?: string; + description?: string; +} + +export class ObjectRef { + constructor( + public projectId: string, + public objectId: string, + public digest: string + ) {} + + // TODO: Add extra + + public uri() { + return `weave:///${this.projectId}/object/${this.objectId}:${this.digest}`; + } + + public ui_url() { + const domain = getGlobalDomain(); + return `https://${domain}/${this.projectId}/weave/objects/${this.objectId}/versions/${this.digest}`; + } + + public async get() { + const client = requireGlobalClient(); + return await client.get(this); + } +} + +export class WeaveObject { + __savedRef?: ObjectRef | Promise; + + constructor(protected _baseParameters: WeaveObjectParameters) {} + + className() { + return Object.getPrototypeOf(this).constructor.name; + } + + saveAttrs() { + const attrs: {[key: string]: any} = {}; + + const nonUnderscoreKeys = Object.keys(this).filter( + key => !key.startsWith('_') + ); + + // Include values first (non-functions) + for (const key of Object.keys(this)) { + // @ts-ignore + const value: any = this[key]; + if (typeof value !== 'function') { + attrs[key] = value; + } + } + + // Then ops + for (const key of nonUnderscoreKeys) { + // @ts-ignore + const value: any = this[key]; + if (isOp(value)) { + attrs[key] = value; + } + } + + return attrs; + } + + get id() { + return this._baseParameters.id ?? this.constructor.name; + } + + get description() { + return this._baseParameters.description; + } +} + +export function getClassChain(instance: WeaveObject): string[] { + const bases: string[] = []; + let currentProto = Object.getPrototypeOf(instance); + + while (currentProto && currentProto.constructor.name !== 'Object') { + const className = + currentProto.constructor.name === 'WeaveObject' + ? 'Object' + : currentProto.constructor.name; + bases.push(className); + currentProto = Object.getPrototypeOf(currentProto); + } + // Frontend does this overly specific check for datasets, so push BaseModel to ensure we pass for now. + // data._type === 'Dataset' && + // data._class_name === 'Dataset' && + // _.isEqual(data._bases, ['Object', 'BaseModel']) + bases.push('BaseModel'); + + return bases; +} diff --git a/sdks/node/tsconfig.json b/sdks/node/tsconfig.json new file mode 100644 index 00000000000..2b676b0408c --- /dev/null +++ b/sdks/node/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "composite": true, + "target": "es2018", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "strict": true, + "esModuleInterop": true, + "outDir": "./dist", + "paths": { + "weave": ["./src/index.ts"] + } + }, + "exclude": ["src", "examples", "dist", "node_modules"], + "references": [ + { + "path": "./src/tsconfig.src.json" + }, + { + "path": "./examples/tsconfig.examples.json" + } + ] +} diff --git a/sdks/node/weave.openapi.json b/sdks/node/weave.openapi.json new file mode 100644 index 00000000000..b0d86f93ea0 --- /dev/null +++ b/sdks/node/weave.openapi.json @@ -0,0 +1,3369 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "FastAPI", + "version": "0.1.0" + }, + "paths": { + "/health": { + "get": { + "tags": ["Service"], + "summary": "Read Root", + "operationId": "read_root_health_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, + "/server_info": { + "get": { + "tags": ["Service"], + "summary": "Server Info", + "operationId": "server_info_server_info_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerInfoRes" + } + } + } + } + } + } + }, + "/call/start": { + "post": { + "tags": ["Calls"], + "summary": "Call Start", + "operationId": "call_start_call_start_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallStartReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallStartRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/call/end": { + "post": { + "tags": ["Calls"], + "summary": "Call End", + "operationId": "call_end_call_end_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallEndReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallEndRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/call/upsert_batch": { + "post": { + "tags": ["Calls"], + "summary": "Call Start Batch", + "operationId": "call_start_batch_call_upsert_batch_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallCreateBatchReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallCreateBatchRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/calls/delete": { + "post": { + "tags": ["Calls"], + "summary": "Calls Delete", + "operationId": "calls_delete_calls_delete_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallsDeleteReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallsDeleteRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/call/update": { + "post": { + "tags": ["Calls"], + "summary": "Call Update", + "operationId": "call_update_call_update_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallUpdateReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallUpdateRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/call/read": { + "post": { + "tags": ["Calls"], + "summary": "Call Read", + "operationId": "call_read_call_read_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallReadReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallReadRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/calls/query_stats": { + "post": { + "tags": ["Calls"], + "summary": "Calls Query Stats", + "operationId": "calls_query_stats_calls_query_stats_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallsQueryStatsReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallsQueryStatsRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/calls/stream_query": { + "post": { + "tags": ["Calls"], + "summary": "Calls Query Stream", + "operationId": "calls_query_stream_calls_stream_query_post", + "security": [ + { + "HTTPBasic": [] + } + ], + "parameters": [ + { + "name": "accept", + "in": "header", + "required": false, + "schema": { + "type": "string", + "default": "application/jsonl", + "title": "Accept" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallsQueryReq" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/obj/create": { + "post": { + "tags": ["Objects"], + "summary": "Obj Create", + "operationId": "obj_create_obj_create_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ObjCreateReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ObjCreateRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/obj/read": { + "post": { + "tags": ["Objects"], + "summary": "Obj Read", + "operationId": "obj_read_obj_read_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ObjReadReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ObjReadRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/objs/query": { + "post": { + "tags": ["Objects"], + "summary": "Objs Query", + "operationId": "objs_query_objs_query_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ObjQueryReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ObjQueryRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/table/create": { + "post": { + "tags": ["Tables"], + "summary": "Table Create", + "operationId": "table_create_table_create_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TableCreateReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TableCreateRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/table/update": { + "post": { + "tags": ["Tables"], + "summary": "Table Update", + "operationId": "table_update_table_update_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TableUpdateReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TableUpdateRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/table/query": { + "post": { + "tags": ["Tables"], + "summary": "Table Query", + "operationId": "table_query_table_query_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TableQueryReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TableQueryRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/refs/read_batch": { + "post": { + "tags": ["Refs"], + "summary": "Refs Read Batch", + "operationId": "refs_read_batch_refs_read_batch_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RefsReadBatchReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RefsReadBatchRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/file/create": { + "post": { + "tags": ["Files"], + "summary": "File Create", + "operationId": "file_create_file_create_post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_file_create_file_create_post" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileCreateRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/file/content": { + "post": { + "tags": ["Files"], + "summary": "File Content", + "operationId": "file_content_file_content_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileContentReadReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/feedback/create": { + "post": { + "tags": ["Feedback"], + "summary": "Feedback Create", + "description": "Add feedback to a call or object.", + "operationId": "feedback_create_feedback_create_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeedbackCreateReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeedbackCreateRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/feedback/query": { + "post": { + "tags": ["Feedback"], + "summary": "Feedback Query", + "description": "Query for feedback.", + "operationId": "feedback_query_feedback_query_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeedbackQueryReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeedbackQueryRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + }, + "/feedback/purge": { + "post": { + "tags": ["Feedback"], + "summary": "Feedback Purge", + "description": "Permanently delete feedback.", + "operationId": "feedback_purge_feedback_purge_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeedbackPurgeReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeedbackPurgeRes" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBasic": [] + } + ] + } + } + }, + "components": { + "schemas": { + "AndOperation": { + "properties": { + "$and": { + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ] + }, + "type": "array", + "title": "$And" + } + }, + "type": "object", + "required": ["$and"], + "title": "AndOperation" + }, + "Body_file_create_file_create_post": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "file": { + "type": "string", + "format": "binary", + "title": "File" + } + }, + "type": "object", + "required": ["project_id", "file"], + "title": "Body_file_create_file_create_post" + }, + "CallBatchEndMode": { + "properties": { + "mode": { + "type": "string", + "title": "Mode", + "default": "end" + }, + "req": { + "$ref": "#/components/schemas/CallEndReq" + } + }, + "type": "object", + "required": ["req"], + "title": "CallBatchEndMode" + }, + "CallBatchStartMode": { + "properties": { + "mode": { + "type": "string", + "title": "Mode", + "default": "start" + }, + "req": { + "$ref": "#/components/schemas/CallStartReq" + } + }, + "type": "object", + "required": ["req"], + "title": "CallBatchStartMode" + }, + "CallCreateBatchReq": { + "properties": { + "batch": { + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/CallBatchStartMode" + }, + { + "$ref": "#/components/schemas/CallBatchEndMode" + } + ] + }, + "type": "array", + "title": "Batch" + } + }, + "type": "object", + "required": ["batch"], + "title": "CallCreateBatchReq" + }, + "CallCreateBatchRes": { + "properties": { + "res": { + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/CallStartRes" + }, + { + "$ref": "#/components/schemas/CallEndRes" + } + ] + }, + "type": "array", + "title": "Res" + } + }, + "type": "object", + "required": ["res"], + "title": "CallCreateBatchRes" + }, + "CallEndReq": { + "properties": { + "end": { + "$ref": "#/components/schemas/EndedCallSchemaForInsert" + } + }, + "type": "object", + "required": ["end"], + "title": "CallEndReq" + }, + "CallEndRes": { + "properties": {}, + "type": "object", + "title": "CallEndRes" + }, + "CallReadReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "id": { + "type": "string", + "title": "Id" + }, + "include_costs": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Include Costs", + "default": false + } + }, + "type": "object", + "required": ["project_id", "id"], + "title": "CallReadReq" + }, + "CallReadRes": { + "properties": { + "call": { + "anyOf": [ + { + "$ref": "#/components/schemas/CallSchema" + }, + { + "type": "null" + } + ] + } + }, + "type": "object", + "required": ["call"], + "title": "CallReadRes" + }, + "CallSchema": { + "properties": { + "id": { + "type": "string", + "title": "Id" + }, + "project_id": { + "type": "string", + "title": "Project Id" + }, + "op_name": { + "type": "string", + "title": "Op Name" + }, + "display_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Display Name" + }, + "trace_id": { + "type": "string", + "title": "Trace Id" + }, + "parent_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Parent Id" + }, + "started_at": { + "type": "string", + "format": "date-time", + "title": "Started At" + }, + "attributes": { + "type": "object", + "title": "Attributes" + }, + "inputs": { + "type": "object", + "title": "Inputs" + }, + "ended_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Ended At" + }, + "exception": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Exception" + }, + "output": { + "anyOf": [ + {}, + { + "type": "null" + } + ], + "title": "Output" + }, + "summary": { + "type": "object" + }, + "wb_user_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Wb User Id" + }, + "wb_run_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Wb Run Id" + }, + "deleted_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Deleted At" + } + }, + "type": "object", + "required": ["id", "project_id", "op_name", "trace_id", "started_at", "attributes", "inputs"], + "title": "CallSchema" + }, + "CallStartReq": { + "properties": { + "start": { + "$ref": "#/components/schemas/StartedCallSchemaForInsert" + } + }, + "type": "object", + "required": ["start"], + "title": "CallStartReq" + }, + "CallStartRes": { + "properties": { + "id": { + "type": "string", + "title": "Id" + }, + "trace_id": { + "type": "string", + "title": "Trace Id" + } + }, + "type": "object", + "required": ["id", "trace_id"], + "title": "CallStartRes" + }, + "CallUpdateReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "call_id": { + "type": "string", + "title": "Call Id" + }, + "display_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Display Name" + }, + "wb_user_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Wb User Id", + "description": "Do not set directly. Server will automatically populate this field." + } + }, + "type": "object", + "required": ["project_id", "call_id"], + "title": "CallUpdateReq" + }, + "CallUpdateRes": { + "properties": {}, + "type": "object", + "title": "CallUpdateRes" + }, + "CallsDeleteReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "call_ids": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Call Ids" + }, + "wb_user_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Wb User Id", + "description": "Do not set directly. Server will automatically populate this field." + } + }, + "type": "object", + "required": ["project_id", "call_ids"], + "title": "CallsDeleteReq" + }, + "CallsDeleteRes": { + "properties": {}, + "type": "object", + "title": "CallsDeleteRes" + }, + "CallsFilter": { + "properties": { + "op_names": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Op Names" + }, + "input_refs": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Input Refs" + }, + "output_refs": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Output Refs" + }, + "parent_ids": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Parent Ids" + }, + "trace_ids": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Trace Ids" + }, + "call_ids": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Call Ids" + }, + "trace_roots_only": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Trace Roots Only" + }, + "wb_user_ids": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Wb User Ids" + }, + "wb_run_ids": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Wb Run Ids" + } + }, + "type": "object", + "title": "CallsFilter" + }, + "CallsQueryReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "filter": { + "anyOf": [ + { + "$ref": "#/components/schemas/CallsFilter" + }, + { + "type": "null" + } + ] + }, + "limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Limit" + }, + "offset": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Offset" + }, + "sort_by": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/SortBy" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Sort By" + }, + "query": { + "anyOf": [ + { + "$ref": "#/components/schemas/Query" + }, + { + "type": "null" + } + ] + }, + "include_costs": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Include Costs", + "default": false + }, + "columns": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Columns" + }, + "expand_columns": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Expand Columns", + "description": "Columns to expand, i.e. refs to other objects", + "examples": [["inputs.self.message", "inputs.model.prompt"]] + } + }, + "type": "object", + "required": ["project_id"], + "title": "CallsQueryReq" + }, + "CallsQueryStatsReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "filter": { + "anyOf": [ + { + "$ref": "#/components/schemas/CallsFilter" + }, + { + "type": "null" + } + ] + }, + "query": { + "anyOf": [ + { + "$ref": "#/components/schemas/Query" + }, + { + "type": "null" + } + ] + } + }, + "type": "object", + "required": ["project_id"], + "title": "CallsQueryStatsReq" + }, + "CallsQueryStatsRes": { + "properties": { + "count": { + "type": "integer", + "title": "Count" + } + }, + "type": "object", + "required": ["count"], + "title": "CallsQueryStatsRes" + }, + "ContainsOperation": { + "properties": { + "$contains": { + "$ref": "#/components/schemas/ContainsSpec" + } + }, + "type": "object", + "required": ["$contains"], + "title": "ContainsOperation" + }, + "ContainsSpec": { + "properties": { + "input": { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ], + "title": "Input" + }, + "substr": { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ], + "title": "Substr" + }, + "case_insensitive": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Case Insensitive", + "default": false + } + }, + "type": "object", + "required": ["input", "substr"], + "title": "ContainsSpec" + }, + "ConvertOperation": { + "properties": { + "$convert": { + "$ref": "#/components/schemas/ConvertSpec" + } + }, + "type": "object", + "required": ["$convert"], + "title": "ConvertOperation" + }, + "ConvertSpec": { + "properties": { + "input": { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ], + "title": "Input" + }, + "to": { + "type": "string", + "enum": ["double", "string", "int", "bool", "exists"], + "title": "To" + } + }, + "type": "object", + "required": ["input", "to"], + "title": "ConvertSpec" + }, + "EndedCallSchemaForInsert": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "id": { + "type": "string", + "title": "Id" + }, + "ended_at": { + "type": "string", + "format": "date-time", + "title": "Ended At" + }, + "exception": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Exception" + }, + "output": { + "anyOf": [ + {}, + { + "type": "null" + } + ], + "title": "Output" + }, + "summary": { + "$ref": "#/components/schemas/SummaryInsertMap" + } + }, + "type": "object", + "required": ["project_id", "id", "ended_at", "summary"], + "title": "EndedCallSchemaForInsert" + }, + "EqOperation": { + "properties": { + "$eq": { + "prefixItems": [ + { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ] + }, + { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ] + } + ], + "type": "array", + "maxItems": 2, + "minItems": 2, + "title": "$Eq" + } + }, + "type": "object", + "required": ["$eq"], + "title": "EqOperation" + }, + "FeedbackCreateReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id", + "examples": ["entity/project"] + }, + "weave_ref": { + "type": "string", + "title": "Weave Ref", + "examples": ["weave:///entity/project/object/name:digest"] + }, + "creator": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Creator", + "examples": ["Jane Smith"] + }, + "feedback_type": { + "type": "string", + "title": "Feedback Type", + "examples": ["custom"] + }, + "payload": { + "type": "object", + "title": "Payload", + "examples": [ + { + "key": "value" + } + ] + }, + "wb_user_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Wb User Id", + "description": "Do not set directly. Server will automatically populate this field." + } + }, + "type": "object", + "required": ["project_id", "weave_ref", "feedback_type", "payload"], + "title": "FeedbackCreateReq" + }, + "FeedbackCreateRes": { + "properties": { + "id": { + "type": "string", + "title": "Id" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At" + }, + "wb_user_id": { + "type": "string", + "title": "Wb User Id" + }, + "payload": { + "type": "object", + "title": "Payload" + } + }, + "type": "object", + "required": ["id", "created_at", "wb_user_id", "payload"], + "title": "FeedbackCreateRes" + }, + "FeedbackPurgeReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id", + "examples": ["entity/project"] + }, + "query": { + "$ref": "#/components/schemas/Query" + } + }, + "type": "object", + "required": ["project_id", "query"], + "title": "FeedbackPurgeReq" + }, + "FeedbackPurgeRes": { + "properties": {}, + "type": "object", + "title": "FeedbackPurgeRes" + }, + "FeedbackQueryReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id", + "examples": ["entity/project"] + }, + "fields": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Fields", + "examples": [["id", "feedback_type", "payload.note"]] + }, + "query": { + "anyOf": [ + { + "$ref": "#/components/schemas/Query" + }, + { + "type": "null" + } + ] + }, + "sort_by": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/SortBy" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Sort By" + }, + "limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Limit", + "examples": [10] + }, + "offset": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Offset", + "examples": [0] + } + }, + "type": "object", + "required": ["project_id"], + "title": "FeedbackQueryReq" + }, + "FeedbackQueryRes": { + "properties": { + "result": { + "items": { + "type": "object" + }, + "type": "array", + "title": "Result" + } + }, + "type": "object", + "required": ["result"], + "title": "FeedbackQueryRes" + }, + "FileContentReadReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "digest": { + "type": "string", + "title": "Digest" + } + }, + "type": "object", + "required": ["project_id", "digest"], + "title": "FileContentReadReq" + }, + "FileCreateRes": { + "properties": { + "digest": { + "type": "string", + "title": "Digest" + } + }, + "type": "object", + "required": ["digest"], + "title": "FileCreateRes" + }, + "GetFieldOperator": { + "properties": { + "$getField": { + "type": "string", + "title": "$Getfield" + } + }, + "type": "object", + "required": ["$getField"], + "title": "GetFieldOperator" + }, + "GtOperation": { + "properties": { + "$gt": { + "prefixItems": [ + { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ] + }, + { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ] + } + ], + "type": "array", + "maxItems": 2, + "minItems": 2, + "title": "$Gt" + } + }, + "type": "object", + "required": ["$gt"], + "title": "GtOperation" + }, + "GteOperation": { + "properties": { + "$gte": { + "prefixItems": [ + { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ] + }, + { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ] + } + ], + "type": "array", + "maxItems": 2, + "minItems": 2, + "title": "$Gte" + } + }, + "type": "object", + "required": ["$gte"], + "title": "GteOperation" + }, + "HTTPValidationError": { + "properties": { + "detail": { + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + "type": "array", + "title": "Detail" + } + }, + "type": "object", + "title": "HTTPValidationError" + }, + "InOperation": { + "properties": { + "$in": { + "prefixItems": [ + { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ] + }, + { + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ] + }, + "type": "array" + } + ], + "type": "array", + "maxItems": 2, + "minItems": 2, + "title": "$In" + } + }, + "type": "object", + "required": ["$in"], + "title": "InOperation" + }, + "LLMUsageSchema": { + "properties": { + "prompt_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Prompt Tokens" + }, + "input_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Input Tokens" + }, + "completion_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Completion Tokens" + }, + "output_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Output Tokens" + }, + "requests": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Requests" + }, + "total_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Total Tokens" + } + }, + "type": "object", + "title": "LLMUsageSchema" + }, + "LiteralOperation": { + "properties": { + "$literal": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "additionalProperties": { + "$ref": "#/components/schemas/LiteralOperation" + }, + "type": "object" + }, + { + "items": { + "$ref": "#/components/schemas/LiteralOperation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "$Literal" + } + }, + "type": "object", + "required": ["$literal"], + "title": "LiteralOperation" + }, + "NotOperation": { + "properties": { + "$not": { + "prefixItems": [ + { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ] + } + ], + "type": "array", + "maxItems": 1, + "minItems": 1, + "title": "$Not" + } + }, + "type": "object", + "required": ["$not"], + "title": "NotOperation" + }, + "ObjCreateReq": { + "properties": { + "obj": { + "$ref": "#/components/schemas/ObjSchemaForInsert" + } + }, + "type": "object", + "required": ["obj"], + "title": "ObjCreateReq" + }, + "ObjCreateRes": { + "properties": { + "digest": { + "type": "string", + "title": "Digest" + } + }, + "type": "object", + "required": ["digest"], + "title": "ObjCreateRes" + }, + "ObjQueryReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "filter": { + "anyOf": [ + { + "$ref": "#/components/schemas/ObjectVersionFilter" + }, + { + "type": "null" + } + ] + } + }, + "type": "object", + "required": ["project_id"], + "title": "ObjQueryReq" + }, + "ObjQueryRes": { + "properties": { + "objs": { + "items": { + "$ref": "#/components/schemas/ObjSchema" + }, + "type": "array", + "title": "Objs" + } + }, + "type": "object", + "required": ["objs"], + "title": "ObjQueryRes" + }, + "ObjReadReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "object_id": { + "type": "string", + "title": "Object Id" + }, + "digest": { + "type": "string", + "title": "Digest" + } + }, + "type": "object", + "required": ["project_id", "object_id", "digest"], + "title": "ObjReadReq" + }, + "ObjReadRes": { + "properties": { + "obj": { + "$ref": "#/components/schemas/ObjSchema" + } + }, + "type": "object", + "required": ["obj"], + "title": "ObjReadRes" + }, + "ObjSchema": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "object_id": { + "type": "string", + "title": "Object Id" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At" + }, + "deleted_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Deleted At" + }, + "digest": { + "type": "string", + "title": "Digest" + }, + "version_index": { + "type": "integer", + "title": "Version Index" + }, + "is_latest": { + "type": "integer", + "title": "Is Latest" + }, + "kind": { + "type": "string", + "title": "Kind" + }, + "base_object_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Base Object Class" + }, + "val": { + "title": "Val" + } + }, + "type": "object", + "required": [ + "project_id", + "object_id", + "created_at", + "digest", + "version_index", + "is_latest", + "kind", + "base_object_class", + "val" + ], + "title": "ObjSchema" + }, + "ObjSchemaForInsert": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "object_id": { + "type": "string", + "title": "Object Id" + }, + "val": { + "title": "Val" + } + }, + "type": "object", + "required": ["project_id", "object_id", "val"], + "title": "ObjSchemaForInsert" + }, + "ObjectVersionFilter": { + "properties": { + "base_object_classes": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Base Object Classes" + }, + "object_ids": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Object Ids" + }, + "is_op": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Op" + }, + "latest_only": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Latest Only" + } + }, + "type": "object", + "title": "ObjectVersionFilter" + }, + "OrOperation": { + "properties": { + "$or": { + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/LiteralOperation" + }, + { + "$ref": "#/components/schemas/GetFieldOperator" + }, + { + "$ref": "#/components/schemas/ConvertOperation" + }, + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ] + }, + "type": "array", + "title": "$Or" + } + }, + "type": "object", + "required": ["$or"], + "title": "OrOperation" + }, + "Query": { + "properties": { + "$expr": { + "anyOf": [ + { + "$ref": "#/components/schemas/AndOperation" + }, + { + "$ref": "#/components/schemas/OrOperation" + }, + { + "$ref": "#/components/schemas/NotOperation" + }, + { + "$ref": "#/components/schemas/EqOperation" + }, + { + "$ref": "#/components/schemas/GtOperation" + }, + { + "$ref": "#/components/schemas/GteOperation" + }, + { + "$ref": "#/components/schemas/InOperation" + }, + { + "$ref": "#/components/schemas/ContainsOperation" + } + ], + "title": "$Expr" + } + }, + "type": "object", + "required": ["$expr"], + "title": "Query" + }, + "RefsReadBatchReq": { + "properties": { + "refs": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Refs" + } + }, + "type": "object", + "required": ["refs"], + "title": "RefsReadBatchReq" + }, + "RefsReadBatchRes": { + "properties": { + "vals": { + "items": {}, + "type": "array", + "title": "Vals" + } + }, + "type": "object", + "required": ["vals"], + "title": "RefsReadBatchRes" + }, + "ServerInfoRes": { + "properties": { + "min_required_weave_python_version": { + "type": "string", + "title": "Min Required Weave Python Version" + } + }, + "type": "object", + "required": ["min_required_weave_python_version"], + "title": "ServerInfoRes" + }, + "SortBy": { + "properties": { + "field": { + "type": "string", + "title": "Field" + }, + "direction": { + "type": "string", + "enum": ["asc", "desc"], + "title": "Direction" + } + }, + "type": "object", + "required": ["field", "direction"], + "title": "SortBy" + }, + "StartedCallSchemaForInsert": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Id" + }, + "op_name": { + "type": "string", + "title": "Op Name" + }, + "display_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Display Name" + }, + "trace_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Trace Id" + }, + "parent_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Parent Id" + }, + "started_at": { + "type": "string", + "format": "date-time", + "title": "Started At" + }, + "attributes": { + "type": "object", + "title": "Attributes" + }, + "inputs": { + "type": "object", + "title": "Inputs" + }, + "wb_user_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Wb User Id", + "description": "Do not set directly. Server will automatically populate this field." + }, + "wb_run_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Wb Run Id" + } + }, + "type": "object", + "required": ["project_id", "op_name", "started_at", "attributes", "inputs"], + "title": "StartedCallSchemaForInsert" + }, + "SummaryInsertMap": { + "properties": { + "usage": { + "additionalProperties": { + "$ref": "#/components/schemas/LLMUsageSchema" + }, + "type": "object", + "title": "Usage" + } + }, + "additionalProperties": true, + "type": "object", + "title": "SummaryInsertMap" + }, + "TableAppendSpec": { + "properties": { + "append": { + "$ref": "#/components/schemas/TableAppendSpecPayload" + } + }, + "type": "object", + "required": ["append"], + "title": "TableAppendSpec" + }, + "TableAppendSpecPayload": { + "properties": { + "row": { + "type": "object", + "title": "Row" + } + }, + "type": "object", + "required": ["row"], + "title": "TableAppendSpecPayload" + }, + "TableCreateReq": { + "properties": { + "table": { + "$ref": "#/components/schemas/TableSchemaForInsert" + } + }, + "type": "object", + "required": ["table"], + "title": "TableCreateReq" + }, + "TableCreateRes": { + "properties": { + "digest": { + "type": "string", + "title": "Digest" + } + }, + "type": "object", + "required": ["digest"], + "title": "TableCreateRes" + }, + "TableInsertSpec": { + "properties": { + "insert": { + "$ref": "#/components/schemas/TableInsertSpecPayload" + } + }, + "type": "object", + "required": ["insert"], + "title": "TableInsertSpec" + }, + "TableInsertSpecPayload": { + "properties": { + "index": { + "type": "integer", + "title": "Index" + }, + "row": { + "type": "object", + "title": "Row" + } + }, + "type": "object", + "required": ["index", "row"], + "title": "TableInsertSpecPayload" + }, + "TablePopSpec": { + "properties": { + "pop": { + "$ref": "#/components/schemas/TablePopSpecPayload" + } + }, + "type": "object", + "required": ["pop"], + "title": "TablePopSpec" + }, + "TablePopSpecPayload": { + "properties": { + "index": { + "type": "integer", + "title": "Index" + } + }, + "type": "object", + "required": ["index"], + "title": "TablePopSpecPayload" + }, + "TableQueryReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "digest": { + "type": "string", + "title": "Digest" + }, + "filter": { + "anyOf": [ + { + "$ref": "#/components/schemas/TableRowFilter" + }, + { + "type": "null" + } + ] + }, + "limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Limit" + }, + "offset": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Offset" + } + }, + "type": "object", + "required": ["project_id", "digest"], + "title": "TableQueryReq" + }, + "TableQueryRes": { + "properties": { + "rows": { + "items": { + "$ref": "#/components/schemas/TableRowSchema" + }, + "type": "array", + "title": "Rows" + } + }, + "type": "object", + "required": ["rows"], + "title": "TableQueryRes" + }, + "TableRowFilter": { + "properties": { + "row_digests": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Row Digests" + } + }, + "type": "object", + "title": "TableRowFilter" + }, + "TableRowSchema": { + "properties": { + "digest": { + "type": "string", + "title": "Digest" + }, + "val": { + "title": "Val" + } + }, + "type": "object", + "required": ["digest", "val"], + "title": "TableRowSchema" + }, + "TableSchemaForInsert": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "rows": { + "items": { + "type": "object" + }, + "type": "array", + "title": "Rows" + } + }, + "type": "object", + "required": ["project_id", "rows"], + "title": "TableSchemaForInsert" + }, + "TableUpdateReq": { + "properties": { + "project_id": { + "type": "string", + "title": "Project Id" + }, + "base_digest": { + "type": "string", + "title": "Base Digest" + }, + "updates": { + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/TableAppendSpec" + }, + { + "$ref": "#/components/schemas/TablePopSpec" + }, + { + "$ref": "#/components/schemas/TableInsertSpec" + } + ] + }, + "type": "array", + "title": "Updates" + } + }, + "type": "object", + "required": ["project_id", "base_digest", "updates"], + "title": "TableUpdateReq" + }, + "TableUpdateRes": { + "properties": { + "digest": { + "type": "string", + "title": "Digest" + } + }, + "type": "object", + "required": ["digest"], + "title": "TableUpdateRes" + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + }, + "type": "array", + "title": "Location" + }, + "msg": { + "type": "string", + "title": "Message" + }, + "type": { + "type": "string", + "title": "Error Type" + } + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError" + } + }, + "securitySchemes": { + "HTTPBasic": { + "type": "http", + "scheme": "basic" + } + } + } +} diff --git a/weave-js/src/assets/icons/icon-enter-return.svg b/weave-js/src/assets/icons/icon-enter-return.svg new file mode 100644 index 00000000000..ffcf6e4f0e5 --- /dev/null +++ b/weave-js/src/assets/icons/icon-enter-return.svg @@ -0,0 +1,3 @@ + + + diff --git a/weave-js/src/assets/icons/icon-marker.svg b/weave-js/src/assets/icons/icon-marker.svg new file mode 100644 index 00000000000..d142990e86a --- /dev/null +++ b/weave-js/src/assets/icons/icon-marker.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/weave-js/src/assets/icons/icon-reload-refresh.svg b/weave-js/src/assets/icons/icon-reload-refresh.svg new file mode 100644 index 00000000000..f6c97a6a71c --- /dev/null +++ b/weave-js/src/assets/icons/icon-reload-refresh.svg @@ -0,0 +1,3 @@ + + + diff --git a/weave-js/src/assets/icons/icon-sandbox-playground.svg b/weave-js/src/assets/icons/icon-sandbox-playground.svg new file mode 100644 index 00000000000..0fe4a7234f9 --- /dev/null +++ b/weave-js/src/assets/icons/icon-sandbox-playground.svg @@ -0,0 +1,3 @@ + + + diff --git a/weave-js/src/assets/icons/icon-swap.svg b/weave-js/src/assets/icons/icon-swap.svg new file mode 100644 index 00000000000..86c8353d4fd --- /dev/null +++ b/weave-js/src/assets/icons/icon-swap.svg @@ -0,0 +1,4 @@ + + + + diff --git a/weave-js/src/components/Icon/Icon.tsx b/weave-js/src/components/Icon/Icon.tsx index 55779a33788..f8cec63146b 100644 --- a/weave-js/src/components/Icon/Icon.tsx +++ b/weave-js/src/components/Icon/Icon.tsx @@ -64,6 +64,7 @@ import {ReactComponent as ImportDragGripHorizontal} from '../../assets/icons/ico import {ReactComponent as ImportEducationAcademic} from '../../assets/icons/icon-education-academic.svg'; import {ReactComponent as ImportEmailAt} from '../../assets/icons/icon-email-at.svg'; import {ReactComponent as ImportEmailEnvelope} from '../../assets/icons/icon-email-envelope.svg'; +import {ReactComponent as ImportEnterReturn} from '../../assets/icons/icon-enter-return.svg'; import {ReactComponent as ImportExpandRight} from '../../assets/icons/icon-expand-right.svg'; import {ReactComponent as ImportExpandUncollapse} from '../../assets/icons/icon-expand-uncollapse.svg'; import {ReactComponent as ImportExportShareUpload} from '../../assets/icons/icon-export-share-upload.svg'; @@ -125,6 +126,7 @@ import {ReactComponent as ImportLogoColab} from '../../assets/icons/icon-logo-co import {ReactComponent as ImportMagicWandStar} from '../../assets/icons/icon-magic-wand-star.svg'; import {ReactComponent as ImportMagicWandStick} from '../../assets/icons/icon-magic-wand-stick.svg'; import {ReactComponent as ImportMarkdown} from '../../assets/icons/icon-markdown.svg'; +import {ReactComponent as ImportMarker} from '../../assets/icons/icon-marker.svg'; import {ReactComponent as ImportMenu} from '../../assets/icons/icon-menu.svg'; import {ReactComponent as ImportMicrophoneAudio} from '../../assets/icons/icon-microphone-audio.svg'; import {ReactComponent as ImportMillerColumns} from '../../assets/icons/icon-miller-columns.svg'; @@ -170,6 +172,7 @@ import {ReactComponent as ImportRedditSocial} from '../../assets/icons/icon-redd import {ReactComponent as ImportRedo} from '../../assets/icons/icon-redo.svg'; import {ReactComponent as ImportRegex} from '../../assets/icons/icon-regex.svg'; import {ReactComponent as ImportRegistries} from '../../assets/icons/icon-registries.svg'; +import {ReactComponent as ImportReloadRefresh} from '../../assets/icons/icon-reload-refresh.svg'; import {ReactComponent as ImportRemove} from '../../assets/icons/icon-remove.svg'; import {ReactComponent as ImportRemoveAlt} from '../../assets/icons/icon-remove-alt.svg'; import {ReactComponent as ImportReport} from '../../assets/icons/icon-report.svg'; @@ -182,6 +185,7 @@ import {ReactComponent as ImportRowHeightSmall} from '../../assets/icons/icon-ro import {ReactComponent as ImportRowHeightXlarge} from '../../assets/icons/icon-row-height-xlarge.svg'; import {ReactComponent as ImportRun} from '../../assets/icons/icon-run.svg'; import {ReactComponent as ImportRunningRepeat} from '../../assets/icons/icon-running-repeat.svg'; +import {ReactComponent as ImportSandboxPlayground} from '../../assets/icons/icon-sandbox-playground.svg'; import {ReactComponent as ImportSave} from '../../assets/icons/icon-save.svg'; import {ReactComponent as ImportScikitLogo} from '../../assets/icons/icon-scikit-logo.svg'; import {ReactComponent as ImportSearch} from '../../assets/icons/icon-search.svg'; @@ -202,6 +206,7 @@ import {ReactComponent as ImportStar} from '../../assets/icons/icon-star.svg'; import {ReactComponent as ImportStarFilled} from '../../assets/icons/icon-star-filled.svg'; import {ReactComponent as ImportStop} from '../../assets/icons/icon-stop.svg'; import {ReactComponent as ImportStopped} from '../../assets/icons/icon-stopped.svg'; +import {ReactComponent as ImportSwap} from '../../assets/icons/icon-swap.svg'; import {ReactComponent as ImportSweepBayes} from '../../assets/icons/icon-sweep-bayes.svg'; import {ReactComponent as ImportSweepGrid} from '../../assets/icons/icon-sweep-grid.svg'; import {ReactComponent as ImportSweepRandomSearch} from '../../assets/icons/icon-sweep-random-search.svg'; @@ -455,6 +460,9 @@ export const IconEmailAt = (props: SVGIconProps) => ( export const IconEmailEnvelope = (props: SVGIconProps) => ( ); +export const IconEnterReturn = (props: SVGIconProps) => ( + +); export const IconExpandRight = (props: SVGIconProps) => ( ); @@ -638,6 +646,9 @@ export const IconMagicWandStick = (props: SVGIconProps) => ( export const IconMarkdown = (props: SVGIconProps) => ( ); +export const IconMarker = (props: SVGIconProps) => ( + +); export const IconMenu = (props: SVGIconProps) => ( ); @@ -773,6 +784,9 @@ export const IconRegex = (props: SVGIconProps) => ( export const IconRegistries = (props: SVGIconProps) => ( ); +export const IconReloadRefresh = (props: SVGIconProps) => ( + +); export const IconRemove = (props: SVGIconProps) => ( ); @@ -809,6 +823,9 @@ export const IconRun = (props: SVGIconProps) => ( export const IconRunningRepeat = (props: SVGIconProps) => ( ); +export const IconSandboxPlayground = (props: SVGIconProps) => ( + +); export const IconSave = (props: SVGIconProps) => ( ); @@ -869,6 +886,9 @@ export const IconStop = (props: SVGIconProps) => ( export const IconStopped = (props: SVGIconProps) => ( ); +export const IconSwap = (props: SVGIconProps) => ( + +); export const IconSweepBayes = (props: SVGIconProps) => ( ); @@ -1076,6 +1096,7 @@ const ICON_NAME_TO_ICON: Record = { 'education-academic': IconEducationAcademic, 'email-at': IconEmailAt, 'email-envelope': IconEmailEnvelope, + 'enter-return': IconEnterReturn, 'expand-right': IconExpandRight, 'expand-uncollapse': IconExpandUncollapse, 'export-share-upload': IconExportShareUpload, @@ -1137,6 +1158,7 @@ const ICON_NAME_TO_ICON: Record = { 'magic-wand-star': IconMagicWandStar, 'magic-wand-stick': IconMagicWandStick, markdown: IconMarkdown, + marker: IconMarker, menu: IconMenu, 'microphone-audio': IconMicrophoneAudio, 'miller-columns': IconMillerColumns, @@ -1182,6 +1204,7 @@ const ICON_NAME_TO_ICON: Record = { redo: IconRedo, regex: IconRegex, registries: IconRegistries, + 'reload-refresh': IconReloadRefresh, remove: IconRemove, 'remove-alt': IconRemoveAlt, report: IconReport, @@ -1194,6 +1217,7 @@ const ICON_NAME_TO_ICON: Record = { 'row-height-xlarge': IconRowHeightXlarge, run: IconRun, 'running-repeat': IconRunningRepeat, + 'sandbox-playground': IconSandboxPlayground, save: IconSave, 'scikit-logo': IconScikitLogo, search: IconSearch, @@ -1214,6 +1238,7 @@ const ICON_NAME_TO_ICON: Record = { 'star-filled': IconStarFilled, stop: IconStop, stopped: IconStopped, + swap: IconSwap, 'sweep-bayes': IconSweepBayes, 'sweep-grid': IconSweepGrid, 'sweep-random-search': IconSweepRandomSearch, diff --git a/weave-js/src/components/Icon/index.ts b/weave-js/src/components/Icon/index.ts index 46908984a07..fa9e1c10454 100644 --- a/weave-js/src/components/Icon/index.ts +++ b/weave-js/src/components/Icon/index.ts @@ -64,6 +64,7 @@ export { IconEducationAcademic, IconEmailAt, IconEmailEnvelope, + IconEnterReturn, IconExpandRight, IconExpandUncollapse, IconExportShareUpload, @@ -125,6 +126,7 @@ export { IconMagicWandStar, IconMagicWandStick, IconMarkdown, + IconMarker, IconMenu, IconMicrophoneAudio, IconMillerColumns, @@ -170,6 +172,7 @@ export { IconRedo, IconRegex, IconRegistries, + IconReloadRefresh, IconRemove, IconRemoveAlt, IconReport, @@ -182,6 +185,7 @@ export { IconRowHeightXlarge, IconRun, IconRunningRepeat, + IconSandboxPlayground, IconSave, IconScikitLogo, IconSearch, @@ -202,6 +206,7 @@ export { IconStarFilled, IconStop, IconStopped, + IconSwap, IconSweepBayes, IconSweepGrid, IconSweepRandomSearch, diff --git a/weave-js/src/components/Icon/types.ts b/weave-js/src/components/Icon/types.ts index c4d343bba17..e536e365157 100644 --- a/weave-js/src/components/Icon/types.ts +++ b/weave-js/src/components/Icon/types.ts @@ -63,6 +63,7 @@ export const IconNames = { EducationAcademic: 'education-academic', EmailAt: 'email-at', EmailEnvelope: 'email-envelope', + EnterReturn: 'enter-return', ExpandRight: 'expand-right', ExpandUncollapse: 'expand-uncollapse', ExportShareUpload: 'export-share-upload', @@ -124,6 +125,7 @@ export const IconNames = { MagicWandStar: 'magic-wand-star', MagicWandStick: 'magic-wand-stick', Markdown: 'markdown', + Marker: 'marker', Menu: 'menu', MicrophoneAudio: 'microphone-audio', MillerColumns: 'miller-columns', @@ -169,6 +171,7 @@ export const IconNames = { Redo: 'redo', Regex: 'regex', Registries: 'registries', + ReloadRefresh: 'reload-refresh', Remove: 'remove', RemoveAlt: 'remove-alt', Report: 'report', @@ -181,6 +184,7 @@ export const IconNames = { RowHeightXlarge: 'row-height-xlarge', Run: 'run', RunningRepeat: 'running-repeat', + SandboxPlayground: 'sandbox-playground', Save: 'save', ScikitLogo: 'scikit-logo', Search: 'search', @@ -201,6 +205,7 @@ export const IconNames = { StarFilled: 'star-filled', Stop: 'stop', Stopped: 'stopped', + Swap: 'swap', SweepBayes: 'sweep-bayes', SweepGrid: 'sweep-grid', SweepRandomSearch: 'sweep-random-search', diff --git a/weave-js/src/components/Loaders/WaveLoader.tsx b/weave-js/src/components/Loaders/WaveLoader.tsx index c07bd291a54..7cddb0a5e75 100644 --- a/weave-js/src/components/Loaders/WaveLoader.tsx +++ b/weave-js/src/components/Loaders/WaveLoader.tsx @@ -12,7 +12,7 @@ const Dot = React.memo( ); const classes = classNames( - 'rounded-full bg-moon-650 dark:bg-moon-350 animate-wave', + 'rounded-full bg-moon-350 dark:bg-moon-650 animate-wave', { 'h-8 w-8': size === 'huge', 'h-6 w-6': size === 'small', diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse2/Browse2OpDefCode.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse2/Browse2OpDefCode.tsx index 38aa07823d8..87b3c8339d8 100644 --- a/weave-js/src/components/PagePanelComponents/Home/Browse2/Browse2OpDefCode.tsx +++ b/weave-js/src/components/PagePanelComponents/Home/Browse2/Browse2OpDefCode.tsx @@ -6,6 +6,23 @@ import React, {FC} from 'react'; import {Alert} from '../../../Alert'; import {useWFHooks} from '../Browse3/pages/wfReactInterface/context'; +function detectLanguage(uri: string, code: string) { + // Simple language detection based on file extension or content + if (uri.endsWith('.py')) { + return 'python'; + } + if (uri.endsWith('.js') || uri.endsWith('.ts')) { + return 'javascript'; + } + if (code.includes('def ') || code.includes('import ')) { + return 'python'; + } + if (code.includes('function ') || code.includes('const ')) { + return 'javascript'; + } + return 'plaintext'; +} + export const Browse2OpDefCode: FC<{uri: string; maxRowsInView?: number}> = ({ uri, maxRowsInView, @@ -37,10 +54,12 @@ export const Browse2OpDefCode: FC<{uri: string; maxRowsInView?: number}> = ({ ); } + const detectedLanguage = detectLanguage(uri, text.result ?? ''); + const inner = (