diff --git a/.cspell.json b/.cspell.json index c2b732e..83a383f 100644 --- a/.cspell.json +++ b/.cspell.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", "version": "0.2", - "ignorePaths": ["**/*.json", "**/*.css", "node_modules", "**/*.log", "./src/adapters/supabase/**/**.ts"], + "ignorePaths": ["**/*.json", "**/*.css", "node_modules", "**/*.log", "./src/adapters/supabase/**/**.ts", "./src/types/database.ts", "./supabase/config.toml"], "useGitignore": true, "language": "en", "words": [ @@ -20,7 +20,9 @@ "Typeguards", "sonarjs", "knip", - "mischeck" + "mischeck", + "commentbody", + "issuebody" ], "dictionaries": ["typescript", "node", "software-terms"], "import": ["@cspell/dict-typescript/cspell-ext.json", "@cspell/dict-node/cspell-ext.json", "@cspell/dict-software-terms"], diff --git a/.dev.vars.example b/.dev.vars.example index e49d79a..6ceaeff 100644 --- a/.dev.vars.example +++ b/.dev.vars.example @@ -1 +1,3 @@ -MY_SECRET="MY_SECRET" +SUPABASE_URL="" +SUPABASE_KEY="" +OPENAI_API_KEY="" \ No newline at end of file diff --git a/.env.example b/.env.example index e49d79a..0272714 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,3 @@ -MY_SECRET="MY_SECRET" +SUPABASE_URL= +SUPABASE_KEY= +OPENAI_API_KEY= \ No newline at end of file diff --git a/.github/knip.ts b/.github/knip.ts index 17857ad..2eb9fdd 100644 --- a/.github/knip.ts +++ b/.github/knip.ts @@ -3,10 +3,10 @@ import type { KnipConfig } from "knip"; const config: KnipConfig = { entry: ["build/index.ts"], project: ["src/**/*.ts"], - ignore: ["src/types/config.ts", "**/__mocks__/**", "**/__fixtures__/**"], + ignore: ["src/types/config.ts", "**/__mocks__/**", "**/__fixtures__/**", "src/types/database.ts"], ignoreExportsUsedInFile: true, // eslint can also be safely ignored as per the docs: https://knip.dev/guides/handling-issues#eslint--jest - ignoreDependencies: ["eslint-config-prettier", "eslint-plugin-prettier", "@mswjs/data"], + ignoreDependencies: ["eslint-config-prettier", "eslint-plugin-prettier"], eslint: true, }; diff --git a/.github/workflows/compute.yml b/.github/workflows/compute.yml index 3d204b1..f83e80c 100644 --- a/.github/workflows/compute.yml +++ b/.github/workflows/compute.yml @@ -1,4 +1,4 @@ -name: "the name of the plugin" +name: "@ubiquity-os/comment-vector-embeddings" on: workflow_dispatch: @@ -18,12 +18,13 @@ on: jobs: compute: - name: "plugin name" + name: "Comment Embedding Store" runs-on: ubuntu-latest permissions: write-all env: SUPABASE_URL: ${{ secrets.SUPABASE_URL }} SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} steps: - uses: actions/checkout@v4 @@ -38,7 +39,8 @@ jobs: - name: execute directive run: npx tsx ./src/main.ts - id: plugin-name + id: issue-comment-embeddings env: SUPABASE_URL: ${{ secrets.SUPABASE_URL }} SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/database.yml b/.github/workflows/database.yml new file mode 100644 index 0000000..5511f5e --- /dev/null +++ b/.github/workflows/database.yml @@ -0,0 +1,67 @@ +name: Database + +on: + push: + branches: + - main + +env: + SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} + SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DB_PASSWORD }} + SUPABASE_PROJECT_ID: ${{ secrets.SUPABASE_PROJECT_ID }} + +jobs: + run-migration: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "20.10.0" + + - uses: supabase/setup-cli@v1 + with: + version: latest + + - name: Link Supabase project + run: supabase link --project-ref $SUPABASE_PROJECT_ID + + - name: Run migrations + run: supabase db push + + generate_types: + runs-on: ubuntu-latest + needs: + - run-migration + permissions: + contents: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "20.10.0" + + - name: Generate Supabase Types + run: | + yarn install + yarn run "supabase:generate:remote" + + - name: Commit and Push generated types + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + git add src/types/database.ts + if [ -n "$(git diff-index --cached --name-only HEAD)" ]; then + git commit -m "chore: updated generated Supabase types" || echo "Lint-staged check failed" + git push origin main + else + echo "No changes to commit" + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 12274bf..40d3396 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +#vscode +.vscode # macOS .DS_Store # node diff --git a/README.md b/README.md index a27db3e..0ee0bbe 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,55 @@ -# `@ubiquibot/plugin-template` - -## Prerequisites - -- A good understanding of how the [kernel](https://github.com/ubiquity/ubiquibot-kernel) works and how to interact with it. -- A basic understanding of the Ubiquibot configuration and how to define your plugin's settings. - -## Getting Started - -1. Create a new repository using this template. -2. Clone the repository to your local machine. -3. Install the dependencies preferably using `yarn` or `bun`. - -## Creating a new plugin - -- If your plugin is to be used as a slash command which should have faster response times as opposed to longer running GitHub action tasks, you should use the `worker` type. - -1. Ensure you understand and have setup the [kernel](https://github.com/ubiquity/ubiquibot-kernel). -2. Update [compute.yml](./.github/workflows/compute.yml) with your plugin's name and update the `id`. -3. Update [context.ts](./src/types/context.ts) with the events that your plugin will fire on. -4. Update [manifest.json](./manifest.json) with a proper description of your plugin. -5. Update [plugin-inputs.ts](./src/types/plugin-inputs.ts) to match the `with:` settings in your org or repo level configuration. - -- Your plugin config should look similar to this: - -```yml -plugins: - - name: hello-world - id: hello-world - uses: - - plugin: http://localhost:4000 - with: - # Define configurable items here and the kernel will pass these to the plugin. - configurableResponse: "Hello, is it me you are looking for?" +# `@ubiquibot/issue-comment-embeddings` + +This is a plugin for [Ubiquibot](https://github.com/ubiquity/ubiquibot-kernel). It listens for issue comments, and adds them to a vector store. It handles comment edits and deletions as well. + +## Configuration +- Host the plugin on a server that Ubiquibot can access. +To set up the `.dev.vars` file, you will need to provide the following variables: +- `SUPABASE_URL`: The URL for your Supabase instance. +- `SUPABASE_KEY`: The key for your Supabase instance. +- `OPENAI_API_KEY`: The API key for OpenAI. + +## Usage +- Add the following to your `.ubiquibot.config.yml` file with the appropriate URL: +```javascript + -plugin: http://127.0.0.1:4000 + runsOn: [ "issue_comment.created", "issue_comment.edited", "issue_comment.deleted" ] ``` -###### At this stage, your plugin will fire on your defined events with the required settings passed in from the kernel. You can now start writing your plugin's logic. - -6. Start building your plugin by adding your logic to the [plugin.ts](./src/plugin.ts) file. - -## Testing a plugin - -### Worker Plugins - -- `yarn/bun worker` - to run the worker locally. -- To trigger the worker, `POST` requests to http://localhost:4000/ with an event payload similar to: - -```ts -await fetch("http://localhost:4000/", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - stateId: "", - eventName: "", - eventPayload: "", - settings: "", - ref: "", - authToken: "", - }), -}); +## Testing Locally +- Run `yarn install` to install the dependencies. +- Run `yarn worker` to start the server. +- Make HTTP requests to the server to test the plugin with content type `Application/JSON` ``` +{ + "stateId": "", + "eventName": "issue_comment.created", + "eventPayload": { + "comment": { + "user": { + "login" : "COMMENTER" + }, + "body": "" , + "id": + }, + "repository" : { + "name" : "REPONAME", + "owner":{ + "login" : "USERNAME" + } + }, + "issue": { + "number": , + "body": "" + } + }, + "env": {}, + "settings": {}, + "ref": "", + "authToken": "" +} +``` +- Replace the placeholders with the appropriate values. -A full example can be found [here](https://github.com/ubiquibot/assistive-pricing/blob/623ea3f950f04842f2d003bda3fc7b7684e41378/tests/http/request.http). - -### Action Plugins - -- Ensure the kernel is running and listening for events. -- Fire an event in/to the repo where the kernel is installed. This can be done in a number of ways, the easiest being via the GitHub UI or using the GitHub API, such as posting a comment, opening an issue, etc in the org/repo where the kernel is installed. -- The kernel will process the event and dispatch it using the settings defined in your `.ubiquibot-config.yml`. -- The `compute.yml` workflow will run and execute your plugin's logic. -- You can view the logs in the Actions tab of your repo. - -[Nektos Act](https://github.com/nektos/act) - a tool for running GitHub Actions locally. - -## More information - -- [Full Ubiquibot Configuration](https://github.com/ubiquity/ubiquibot/blob/0fde7551585499b1e0618ec8ea5e826f11271c9c/src/types/configuration-types.ts#L62) - helpful for defining your plugin's settings as they are strongly typed and will be validated by the kernel. -- [Ubiquibot V1](https://github.com/ubiquity/ubiquibot) - helpful for porting V1 functionality to V2, helper/utility functions, types, etc. Everything is based on the V1 codebase but with a more modular approach. When using V1 code, keep in mind that most all code will need refactored to work with the new V2 architecture. - -## Examples - -- [Start/Stop Slash Command](https://github.com/ubq-testing/start-stop-module) - simple -- [Assistive Pricing Plugin](https://github.com/ubiquibot/assistive-pricing) - complex -- [Conversation Rewards](https://github.com/ubiquibot/conversation-rewards) - really complex +## Testing +- Run `yarn test` to run the tests. \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs index e53d263..f43237a 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -9,7 +9,7 @@ export default tsEslint.config({ "@typescript-eslint": tsEslint.plugin, "check-file": checkFile, }, - ignores: [".github/knip.ts"], + ignores: [".github/knip.ts", "src/types/database.ts"], extends: [eslint.configs.recommended, ...tsEslint.configs.recommended, sonarjs.configs.recommended], languageOptions: { parser: tsEslint.parser, diff --git a/manifest.json b/manifest.json index 83aa3f2..0e83faf 100644 --- a/manifest.json +++ b/manifest.json @@ -1,11 +1,5 @@ { - "name": "ts-template", - "description": "ts-template for Ubiquibot plugins.", - "ubiquity:listeners": ["issue_comment.created"], - "commands": { - "command1": { - "ubiquity:example": "/command1 argument", - "description": "Command 1 with an argument." - } - } + "name": "@ubiquity-os/comment-vector-embeddings", + "description": "Issue comment plugin for Ubiquibot. It enables the storage, updating, and deletion of issue comment embeddings.", + "ubiquity:listeners": ["issue_comment.created", "issue_comment.edited", "issue_comment.deleted"] } diff --git a/package.json b/package.json index 838f3e8..bb43997 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "plugin-template", + "name": "@ubiquibot/issue-comment-embeddings", "version": "1.0.0", - "description": "Ubiquibot plugin template repository with TypeScript support.", + "description": "Generates vector embeddings of GitHub comments and stores them in Supabase.", "author": "Ubiquity DAO", "license": "MIT", "main": "src/worker.ts", @@ -17,7 +17,9 @@ "knip-ci": "knip --no-exit-code --reporter json --config .github/knip.ts", "prepare": "husky install", "test": "jest --setupFiles dotenv/config --coverage", - "worker": "wrangler dev --env dev --port 4000" + "worker": "wrangler dev --env dev --port 4000", + "supabase:generate:local": "supabase gen types typescript --local > src/types/database.ts", + "supabase:generate:remote": "cross-env-shell \"supabase gen types typescript --project-id $SUPABASE_PROJECT_ID --schema public > src/types/database.ts\"" }, "keywords": [ "typescript", @@ -32,8 +34,10 @@ "@octokit/rest": "20.1.1", "@octokit/webhooks": "13.2.7", "@sinclair/typebox": "0.32.33", + "@supabase/supabase-js": "^2.45.2", "@ubiquity-dao/ubiquibot-logger": "^1.3.0", "dotenv": "16.4.5", + "openai": "^4.56.0", "typebox-validators": "0.3.5" }, "devDependencies": { @@ -47,6 +51,7 @@ "@mswjs/data": "0.16.1", "@types/jest": "^29.5.12", "@types/node": "20.14.5", + "cross-env": "7.0.3", "cspell": "8.9.0", "eslint": "9.5.0", "eslint-config-prettier": "9.1.0", @@ -61,11 +66,12 @@ "lint-staged": "15.2.7", "npm-run-all": "4.1.5", "prettier": "3.3.2", + "supabase": "1.191.3", "ts-jest": "29.1.5", "tsx": "4.15.6", "typescript": "5.4.5", "typescript-eslint": "7.13.1", - "wrangler": "3.60.3" + "wrangler": "3.62.0" }, "lint-staged": { "*.ts": [ diff --git a/src/adapters/index.ts b/src/adapters/index.ts new file mode 100644 index 0000000..e5f0346 --- /dev/null +++ b/src/adapters/index.ts @@ -0,0 +1,20 @@ +import { SupabaseClient } from "@supabase/supabase-js"; +import { Context } from "../types"; +import { Comment } from "./supabase/helpers/comment"; +import { SuperSupabase } from "./supabase/helpers/supabase"; +import { SuperOpenAi } from "./openai/helpers/openai"; +import OpenAI from "openai"; +import { Embedding } from "./openai/helpers/embedding"; + +export function createAdapters(supabaseClient: SupabaseClient, openai: OpenAI, context: Context) { + return { + supabase: { + comment: new Comment(supabaseClient, context), + super: new SuperSupabase(supabaseClient, context), + }, + openai: { + embedding: new Embedding(openai, context), + super: new SuperOpenAi(openai, context), + }, + }; +} diff --git a/src/adapters/openai/helpers/embedding.ts b/src/adapters/openai/helpers/embedding.ts new file mode 100644 index 0000000..6b912dd --- /dev/null +++ b/src/adapters/openai/helpers/embedding.ts @@ -0,0 +1,25 @@ +import OpenAI from "openai"; +import { Context } from "../../../types"; +import { SuperOpenAi } from "./openai"; +const VECTOR_SIZE = 3072; + +export class Embedding extends SuperOpenAi { + protected context: Context; + + constructor(client: OpenAI, context: Context) { + super(client, context); + this.context = context; + } + + async createEmbedding(text: string): Promise { + const params: OpenAI.EmbeddingCreateParams = { + model: "text-embedding-3-large", + input: text, + dimensions: VECTOR_SIZE, + }; + const response = await this.client.embeddings.create({ + ...params, + }); + return response.data[0]?.embedding; + } +} diff --git a/src/adapters/openai/helpers/openai.ts b/src/adapters/openai/helpers/openai.ts new file mode 100644 index 0000000..108a3d2 --- /dev/null +++ b/src/adapters/openai/helpers/openai.ts @@ -0,0 +1,12 @@ +import { OpenAI } from "openai"; +import { Context } from "../../../types/context"; + +export class SuperOpenAi { + protected client: OpenAI; + protected context: Context; + + constructor(client: OpenAI, context: Context) { + this.client = client; + this.context = context; + } +} diff --git a/src/adapters/supabase/helpers/comment.ts b/src/adapters/supabase/helpers/comment.ts new file mode 100644 index 0000000..7530c10 --- /dev/null +++ b/src/adapters/supabase/helpers/comment.ts @@ -0,0 +1,63 @@ +import { SupabaseClient } from "@supabase/supabase-js"; +import { SuperSupabase } from "./supabase"; +import { Context } from "../../../types/context"; + +export interface CommentType { + id: number; + body: string; + embedding: number[]; +} + +export class Comment extends SuperSupabase { + constructor(supabase: SupabaseClient, context: Context) { + super(supabase, context); + } + + async createComment(commentBody: string, commentId: number, issueBody: string) { + //First Check if the comment already exists + const { data, error } = await this.supabase.from("issue_comments").select("*").eq("id", commentId); + if (error) { + this.context.logger.error("Error creating comment", error); + return; + } + if (data && data.length > 0) { + this.context.logger.info("Comment already exists"); + return; + } else { + //Create the embedding for this comment + const embedding = await this.context.adapters.openai.embedding.createEmbedding(commentBody); + const { error } = await this.supabase + .from("issue_comments") + .insert([{ id: commentId, commentbody: commentBody, issuebody: issueBody, embedding: embedding }]); + if (error) { + this.context.logger.error("Error creating comment", error); + return; + } + } + this.context.logger.info("Comment created successfully"); + } + + async updateComment(commentBody: string, commentId: number) { + //Create the embedding for this comment + const embedding = Array.from(await this.context.adapters.openai.embedding.createEmbedding(commentBody)); + const { error } = await this.supabase.from("issue_comments").update({ commentbody: commentBody, embedding: embedding }).eq("id", commentId); + if (error) { + this.context.logger.error("Error updating comment", error); + } + } + + async getComment(commentId: number): Promise { + const { data, error } = await this.supabase.from("issue_comments").select("*").eq("id", commentId); + if (error) { + this.context.logger.error("Error getting comment", error); + } + return data; + } + + async deleteComment(commentId: number) { + const { error } = await this.supabase.from("issue_comments").delete().eq("id", commentId); + if (error) { + this.context.logger.error("Error deleting comment", error); + } + } +} diff --git a/src/adapters/supabase/helpers/supabase.ts b/src/adapters/supabase/helpers/supabase.ts new file mode 100644 index 0000000..34e845c --- /dev/null +++ b/src/adapters/supabase/helpers/supabase.ts @@ -0,0 +1,12 @@ +import { SupabaseClient } from "@supabase/supabase-js"; +import { Context } from "../../../types/context"; + +export class SuperSupabase { + protected supabase: SupabaseClient; + protected context: Context; + + constructor(supabase: SupabaseClient, context: Context) { + this.supabase = supabase; + this.context = context; + } +} diff --git a/src/handlers/add-comments.ts b/src/handlers/add-comments.ts new file mode 100644 index 0000000..35bd387 --- /dev/null +++ b/src/handlers/add-comments.ts @@ -0,0 +1,35 @@ +import { Context } from "../types"; + +export async function addComments(context: Context) { + const { + logger, + payload, + adapters: { supabase }, + } = context; + + const sender = payload.comment.user?.login; + const repo = payload.repository.name; + const issueNumber = payload.issue.number; + const issueBody = payload.issue.body || ""; + const owner = payload.repository.owner.login; + const body = payload.comment.body; + + // Log the payload + logger.info(`Executing addComments:`, { sender, repo, issueNumber, owner }); + + // Add the comment to the database + try { + await supabase.comment.createComment(body, payload.comment.id, issueBody); + } catch (error) { + if (error instanceof Error) { + logger.error(`Error creating comment:`, { error: error, stack: error.stack }); + throw error; + } else { + logger.error(`Error creating comment:`, { err: error, error: new Error() }); + throw error; + } + } + + logger.ok(`Successfully created comment!`); + logger.verbose(`Exiting addComments`); +} diff --git a/src/handlers/delete-comments.ts b/src/handlers/delete-comments.ts new file mode 100644 index 0000000..7e9842f --- /dev/null +++ b/src/handlers/delete-comments.ts @@ -0,0 +1,33 @@ +import { Context } from "../types"; + +export async function deleteComment(context: Context) { + const { + logger, + payload, + adapters: { supabase }, + } = context; + + const sender = payload.comment.user?.login; + const repo = payload.repository.name; + const issueNumber = payload.issue.number; + const owner = payload.repository.owner.login; + + // Log the payload + logger.debug(`Executing deleteComment:`, { sender, repo, issueNumber, owner }); + + // Add the comment to the database + try { + await supabase.comment.deleteComment(payload.comment.id); + } catch (error) { + if (error instanceof Error) { + logger.error(`Error deleting comment:`, { error: error, stack: error.stack }); + throw error; + } else { + logger.error(`Error deleting comment:`, { err: error, error: new Error() }); + throw error; + } + } + + logger.ok(`Successfully deleted comment!`); + logger.verbose(`Exiting deleteComments`); +} diff --git a/src/handlers/hello-world.ts b/src/handlers/hello-world.ts deleted file mode 100644 index 4c58ae1..0000000 --- a/src/handlers/hello-world.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Context } from "../types"; - -/** - * NOTICE: Remove this file or use it as a template for your own plugins. - * - * This encapsulates the logic for a plugin if the only thing it does is say "Hello, world!". - * - * Try it out by running your local kernel worker and running the `yarn worker` command. - * Comment on an issue in a repository where your GitHub App is installed and see the magic happen! - * - * Logger examples are provided to show how to log different types of data. - */ -export async function helloWorld(context: Context) { - const { - logger, - payload, - octokit, - config: { configurableResponse }, - } = context; - - const sender = payload.comment.user?.login; - const repo = payload.repository.name; - const issueNumber = payload.issue.number; - const owner = payload.repository.owner.login; - const body = payload.comment.body; - - if (!body.match(/hello/i)) { - logger.error(`Invalid use of slash command, use "/hello".`, { body }); - return; - } - - logger.info("Hello, world!"); - logger.debug(`Executing helloWorld:`, { sender, repo, issueNumber, owner }); - - try { - await octokit.issues.createComment({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number: payload.issue.number, - body: configurableResponse, - }); - } catch (error) { - /** - * logger.fatal should not be used in 9/10 cases. Use logger.error instead. - * - * Below are examples of passing error objects to the logger, only one is needed. - */ - if (error instanceof Error) { - logger.error(`Error creating comment:`, { error: error, stack: error.stack }); - throw error; - } else { - logger.error(`Error creating comment:`, { err: error, error: new Error() }); - throw error; - } - } - - logger.ok(`Successfully created comment!`); - logger.verbose(`Exiting helloWorld`); -} diff --git a/src/handlers/update-comments.ts b/src/handlers/update-comments.ts new file mode 100644 index 0000000..b0c3142 --- /dev/null +++ b/src/handlers/update-comments.ts @@ -0,0 +1,34 @@ +import { Context } from "../types"; + +export async function updateComment(context: Context) { + const { + logger, + payload, + adapters: { supabase }, + } = context; + + const sender = payload.comment.user?.login; + const repo = payload.repository.name; + const issueNumber = payload.issue.number; + const owner = payload.repository.owner.login; + const body = payload.comment.body; + + // Log the payload + logger.debug(`Executing updateComment:`, { sender, repo, issueNumber, owner }); + + // Fetch the previous comment and update it in the db + try { + await supabase.comment.updateComment(body, payload.comment.id); + } catch (error) { + if (error instanceof Error) { + logger.error(`Error updating comment:`, { error: error, stack: error.stack }); + throw error; + } else { + logger.error(`Error updating comment:`, { err: error, error: new Error() }); + throw error; + } + } + + logger.ok(`Successfully updated comment!`); + logger.verbose(`Exiting updateComment`); +} diff --git a/src/main.ts b/src/main.ts index b46765e..34f3e2f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -10,7 +10,6 @@ import { plugin } from "./plugin"; */ export async function run() { const payload = github.context.payload.inputs; - const env = Value.Decode(envSchema, payload.env); const settings = Value.Decode(pluginSettingsSchema, Value.Default(pluginSettingsSchema, JSON.parse(payload.settings))); diff --git a/src/plugin.ts b/src/plugin.ts index b877b2b..4197ff6 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -2,20 +2,33 @@ import { Octokit } from "@octokit/rest"; import { Env, PluginInputs } from "./types"; import { Context } from "./types"; import { isIssueCommentEvent } from "./types/typeguards"; -import { helloWorld } from "./handlers/hello-world"; import { LogLevel, Logs } from "@ubiquity-dao/ubiquibot-logger"; +import { Database } from "./types/database"; +import { createAdapters } from "./adapters"; +import { createClient } from "@supabase/supabase-js"; +import { addComments } from "./handlers/add-comments"; +import { updateComment } from "./handlers/update-comments"; +import { deleteComment } from "./handlers/delete-comments"; +import OpenAI from "openai"; /** * The main plugin function. Split for easier testing. */ export async function runPlugin(context: Context) { const { logger, eventName } = context; - if (isIssueCommentEvent(context)) { - return await helloWorld(context); + switch (eventName) { + case "issue_comment.created": + return await addComments(context); + case "issue_comment.deleted": + return await deleteComment(context); + case "issue_comment.edited": + return await updateComment(context); + } + } else { + logger.error(`Unsupported event: ${eventName}`); } - - logger.error(`Unsupported event: ${eventName}`); + logger.ok(`Exiting plugin`); } /** @@ -23,7 +36,10 @@ export async function runPlugin(context: Context) { */ export async function plugin(inputs: PluginInputs, env: Env) { const octokit = new Octokit({ auth: inputs.authToken }); - + const supabase = createClient(env.SUPABASE_URL, env.SUPABASE_KEY); + const openaiClient = new OpenAI({ + apiKey: env.OPENAI_API_KEY, + }); const context: Context = { eventName: inputs.eventName, payload: inputs.eventPayload, @@ -31,18 +47,8 @@ export async function plugin(inputs: PluginInputs, env: Env) { octokit, env, logger: new Logs("info" as LogLevel), + adapters: {} as ReturnType, }; - - /** - * NOTICE: Consider non-database storage solutions unless necessary - * - * Initialize storage adapters here. For example, to use Supabase: - * - * import { createClient } from "@supabase/supabase-js"; - * - * const supabase = createClient(env.SUPABASE_URL, env.SUPABASE_KEY); - * context.adapters = createAdapters(supabase, context); - */ - + context.adapters = createAdapters(supabase, openaiClient, context); return runPlugin(context); } diff --git a/src/types/context.ts b/src/types/context.ts index 0a59f93..d7e3cff 100644 --- a/src/types/context.ts +++ b/src/types/context.ts @@ -3,13 +3,14 @@ import { EmitterWebhookEvent as WebhookEvent, EmitterWebhookEventName as Webhook import { Env } from "./env"; import { PluginSettings } from "./plugin-inputs"; import { Logs } from "@ubiquity-dao/ubiquibot-logger"; +import { createAdapters } from "../adapters"; /** * Update `manifest.json` with any events you want to support like so: * * ubiquity:listeners: ["issue_comment.created", ...] */ -export type SupportedEventsU = "issue_comment.created"; +export type SupportedEventsU = "issue_comment.created" | "issue_comment.deleted" | "issue_comment.edited"; export type SupportedEvents = { [K in SupportedEventsU]: K extends WebhookEventName ? WebhookEvent : never; @@ -22,4 +23,5 @@ export interface Context; } diff --git a/src/types/database.ts b/src/types/database.ts new file mode 100644 index 0000000..4f00255 --- /dev/null +++ b/src/types/database.ts @@ -0,0 +1,616 @@ +export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]; + +export type Database = { + graphql_public: { + Tables: { + [_ in never]: never; + }; + Views: { + [_ in never]: never; + }; + Functions: { + graphql: { + Args: { + operationName?: string; + query?: string; + variables?: Json; + extensions?: Json; + }; + Returns: Json; + }; + }; + Enums: { + [_ in never]: never; + }; + CompositeTypes: { + [_ in never]: never; + }; + }; + public: { + Tables: { + issue_comments: { + Row: { + commentbody: string; + embedding: string; + id: number; + issuebody: string | null; + }; + Insert: { + commentbody: string; + embedding: string; + id: number; + issuebody?: string | null; + }; + Update: { + commentbody?: string; + embedding?: string; + id?: number; + issuebody?: string | null; + }; + Relationships: []; + }; + }; + Views: { + [_ in never]: never; + }; + Functions: { + binary_quantize: + | { + Args: { + "": string; + }; + Returns: unknown; + } + | { + Args: { + "": unknown; + }; + Returns: unknown; + }; + halfvec_avg: { + Args: { + "": number[]; + }; + Returns: unknown; + }; + halfvec_out: { + Args: { + "": unknown; + }; + Returns: unknown; + }; + halfvec_send: { + Args: { + "": unknown; + }; + Returns: string; + }; + halfvec_typmod_in: { + Args: { + "": unknown[]; + }; + Returns: number; + }; + hnsw_bit_support: { + Args: { + "": unknown; + }; + Returns: unknown; + }; + hnsw_halfvec_support: { + Args: { + "": unknown; + }; + Returns: unknown; + }; + hnsw_sparsevec_support: { + Args: { + "": unknown; + }; + Returns: unknown; + }; + hnswhandler: { + Args: { + "": unknown; + }; + Returns: unknown; + }; + ivfflat_bit_support: { + Args: { + "": unknown; + }; + Returns: unknown; + }; + ivfflat_halfvec_support: { + Args: { + "": unknown; + }; + Returns: unknown; + }; + ivfflathandler: { + Args: { + "": unknown; + }; + Returns: unknown; + }; + l2_norm: + | { + Args: { + "": unknown; + }; + Returns: number; + } + | { + Args: { + "": unknown; + }; + Returns: number; + }; + l2_normalize: + | { + Args: { + "": string; + }; + Returns: string; + } + | { + Args: { + "": unknown; + }; + Returns: unknown; + } + | { + Args: { + "": unknown; + }; + Returns: unknown; + }; + sparsevec_out: { + Args: { + "": unknown; + }; + Returns: unknown; + }; + sparsevec_send: { + Args: { + "": unknown; + }; + Returns: string; + }; + sparsevec_typmod_in: { + Args: { + "": unknown[]; + }; + Returns: number; + }; + vector_avg: { + Args: { + "": number[]; + }; + Returns: string; + }; + vector_dims: + | { + Args: { + "": string; + }; + Returns: number; + } + | { + Args: { + "": unknown; + }; + Returns: number; + }; + vector_norm: { + Args: { + "": string; + }; + Returns: number; + }; + vector_out: { + Args: { + "": string; + }; + Returns: unknown; + }; + vector_send: { + Args: { + "": string; + }; + Returns: string; + }; + vector_typmod_in: { + Args: { + "": unknown[]; + }; + Returns: number; + }; + }; + Enums: { + [_ in never]: never; + }; + CompositeTypes: { + [_ in never]: never; + }; + }; + storage: { + Tables: { + buckets: { + Row: { + allowed_mime_types: string[] | null; + avif_autodetection: boolean | null; + created_at: string | null; + file_size_limit: number | null; + id: string; + name: string; + owner: string | null; + owner_id: string | null; + public: boolean | null; + updated_at: string | null; + }; + Insert: { + allowed_mime_types?: string[] | null; + avif_autodetection?: boolean | null; + created_at?: string | null; + file_size_limit?: number | null; + id: string; + name: string; + owner?: string | null; + owner_id?: string | null; + public?: boolean | null; + updated_at?: string | null; + }; + Update: { + allowed_mime_types?: string[] | null; + avif_autodetection?: boolean | null; + created_at?: string | null; + file_size_limit?: number | null; + id?: string; + name?: string; + owner?: string | null; + owner_id?: string | null; + public?: boolean | null; + updated_at?: string | null; + }; + Relationships: []; + }; + migrations: { + Row: { + executed_at: string | null; + hash: string; + id: number; + name: string; + }; + Insert: { + executed_at?: string | null; + hash: string; + id: number; + name: string; + }; + Update: { + executed_at?: string | null; + hash?: string; + id?: number; + name?: string; + }; + Relationships: []; + }; + objects: { + Row: { + bucket_id: string | null; + created_at: string | null; + id: string; + last_accessed_at: string | null; + metadata: Json | null; + name: string | null; + owner: string | null; + owner_id: string | null; + path_tokens: string[] | null; + updated_at: string | null; + user_metadata: Json | null; + version: string | null; + }; + Insert: { + bucket_id?: string | null; + created_at?: string | null; + id?: string; + last_accessed_at?: string | null; + metadata?: Json | null; + name?: string | null; + owner?: string | null; + owner_id?: string | null; + path_tokens?: string[] | null; + updated_at?: string | null; + user_metadata?: Json | null; + version?: string | null; + }; + Update: { + bucket_id?: string | null; + created_at?: string | null; + id?: string; + last_accessed_at?: string | null; + metadata?: Json | null; + name?: string | null; + owner?: string | null; + owner_id?: string | null; + path_tokens?: string[] | null; + updated_at?: string | null; + user_metadata?: Json | null; + version?: string | null; + }; + Relationships: [ + { + foreignKeyName: "objects_bucketId_fkey"; + columns: ["bucket_id"]; + isOneToOne: false; + referencedRelation: "buckets"; + referencedColumns: ["id"]; + }, + ]; + }; + s3_multipart_uploads: { + Row: { + bucket_id: string; + created_at: string; + id: string; + in_progress_size: number; + key: string; + owner_id: string | null; + upload_signature: string; + user_metadata: Json | null; + version: string; + }; + Insert: { + bucket_id: string; + created_at?: string; + id: string; + in_progress_size?: number; + key: string; + owner_id?: string | null; + upload_signature: string; + user_metadata?: Json | null; + version: string; + }; + Update: { + bucket_id?: string; + created_at?: string; + id?: string; + in_progress_size?: number; + key?: string; + owner_id?: string | null; + upload_signature?: string; + user_metadata?: Json | null; + version?: string; + }; + Relationships: [ + { + foreignKeyName: "s3_multipart_uploads_bucket_id_fkey"; + columns: ["bucket_id"]; + isOneToOne: false; + referencedRelation: "buckets"; + referencedColumns: ["id"]; + }, + ]; + }; + s3_multipart_uploads_parts: { + Row: { + bucket_id: string; + created_at: string; + etag: string; + id: string; + key: string; + owner_id: string | null; + part_number: number; + size: number; + upload_id: string; + version: string; + }; + Insert: { + bucket_id: string; + created_at?: string; + etag: string; + id?: string; + key: string; + owner_id?: string | null; + part_number: number; + size?: number; + upload_id: string; + version: string; + }; + Update: { + bucket_id?: string; + created_at?: string; + etag?: string; + id?: string; + key?: string; + owner_id?: string | null; + part_number?: number; + size?: number; + upload_id?: string; + version?: string; + }; + Relationships: [ + { + foreignKeyName: "s3_multipart_uploads_parts_bucket_id_fkey"; + columns: ["bucket_id"]; + isOneToOne: false; + referencedRelation: "buckets"; + referencedColumns: ["id"]; + }, + { + foreignKeyName: "s3_multipart_uploads_parts_upload_id_fkey"; + columns: ["upload_id"]; + isOneToOne: false; + referencedRelation: "s3_multipart_uploads"; + referencedColumns: ["id"]; + }, + ]; + }; + }; + Views: { + [_ in never]: never; + }; + Functions: { + can_insert_object: { + Args: { + bucketid: string; + name: string; + owner: string; + metadata: Json; + }; + Returns: undefined; + }; + extension: { + Args: { + name: string; + }; + Returns: string; + }; + filename: { + Args: { + name: string; + }; + Returns: string; + }; + foldername: { + Args: { + name: string; + }; + Returns: string[]; + }; + get_size_by_bucket: { + Args: Record; + Returns: { + size: number; + bucket_id: string; + }[]; + }; + list_multipart_uploads_with_delimiter: { + Args: { + bucket_id: string; + prefix_param: string; + delimiter_param: string; + max_keys?: number; + next_key_token?: string; + next_upload_token?: string; + }; + Returns: { + key: string; + id: string; + created_at: string; + }[]; + }; + list_objects_with_delimiter: { + Args: { + bucket_id: string; + prefix_param: string; + delimiter_param: string; + max_keys?: number; + start_after?: string; + next_token?: string; + }; + Returns: { + name: string; + id: string; + metadata: Json; + updated_at: string; + }[]; + }; + operation: { + Args: Record; + Returns: string; + }; + search: { + Args: { + prefix: string; + bucketname: string; + limits?: number; + levels?: number; + offsets?: number; + search?: string; + sortcolumn?: string; + sortorder?: string; + }; + Returns: { + name: string; + id: string; + updated_at: string; + created_at: string; + last_accessed_at: string; + metadata: Json; + }[]; + }; + }; + Enums: { + [_ in never]: never; + }; + CompositeTypes: { + [_ in never]: never; + }; + }; +}; + +type PublicSchema = Database[Extract]; + +export type Tables< + PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] & PublicSchema["Views"]) | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof (Database[PublicTableNameOrOptions["schema"]]["Tables"] & Database[PublicTableNameOrOptions["schema"]]["Views"]) + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? (Database[PublicTableNameOrOptions["schema"]]["Tables"] & Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R; + } + ? R + : never + : PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] & PublicSchema["Views"]) + ? (PublicSchema["Tables"] & PublicSchema["Views"])[PublicTableNameOrOptions] extends { + Row: infer R; + } + ? R + : never + : never; + +export type TablesInsert< + PublicTableNameOrOptions extends keyof PublicSchema["Tables"] | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I; + } + ? I + : never + : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] + ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { + Insert: infer I; + } + ? I + : never + : never; + +export type TablesUpdate< + PublicTableNameOrOptions extends keyof PublicSchema["Tables"] | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U; + } + ? U + : never + : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] + ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { + Update: infer U; + } + ? U + : never + : never; + +export type Enums< + PublicEnumNameOrOptions extends keyof PublicSchema["Enums"] | { schema: keyof Database }, + EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } ? keyof Database[PublicEnumNameOrOptions["schema"]]["Enums"] : never = never, +> = PublicEnumNameOrOptions extends { schema: keyof Database } + ? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName] + : PublicEnumNameOrOptions extends keyof PublicSchema["Enums"] + ? PublicSchema["Enums"][PublicEnumNameOrOptions] + : never; diff --git a/src/types/env.ts b/src/types/env.ts index 45e200e..6f47748 100644 --- a/src/types/env.ts +++ b/src/types/env.ts @@ -10,7 +10,11 @@ import { StandardValidator } from "typebox-validators"; * taken from either `dev.vars` or repository secrets. * They are used with `process.env` but are type-safe. */ -export const envSchema = T.Object({}); +export const envSchema = T.Object({ + SUPABASE_URL: T.String(), + SUPABASE_KEY: T.String(), + OPENAI_API_KEY: T.String(), +}); export const envValidator = new StandardValidator(envSchema); diff --git a/src/types/plugin-inputs.ts b/src/types/plugin-inputs.ts index 1c8a30a..77a40f9 100644 --- a/src/types/plugin-inputs.ts +++ b/src/types/plugin-inputs.ts @@ -18,12 +18,7 @@ export interface PluginInputs { - return context.eventName === "issue_comment.created"; +export function isIssueCommentEvent(context: Context): context is Context<"issue_comment.created" | "issue_comment.deleted" | "issue_comment.edited"> { + return context.eventName === "issue_comment.created" || context.eventName === "issue_comment.deleted" || context.eventName === "issue_comment.edited"; } diff --git a/supabase/.gitignore b/supabase/.gitignore new file mode 100644 index 0000000..a3ad880 --- /dev/null +++ b/supabase/.gitignore @@ -0,0 +1,4 @@ +# Supabase +.branches +.temp +.env diff --git a/supabase/config.toml b/supabase/config.toml new file mode 100644 index 0000000..2db05e5 --- /dev/null +++ b/supabase/config.toml @@ -0,0 +1,161 @@ +# A string used to distinguish different Supabase projects on the same host. Defaults to the +# working directory name when running `supabase init`. +project_id = "issue-comment-embeddings" + +[api] +enabled = true +# Port to use for the API URL. +port = 54321 +# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API +# endpoints. public and storage are always included. +schemas = ["public", "storage", "graphql_public"] +# Extra schemas to add to the search_path of every request. public is always included. +extra_search_path = ["public", "extensions"] +# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size +# for accidental or malicious requests. +max_rows = 1000 + +[db] +# Port to use for the local database URL. +port = 54322 +# Port used by db diff command to initialize the shadow database. +shadow_port = 54320 +# The database major version to use. This has to be the same as your remote database's. Run `SHOW +# server_version;` on the remote database to check. +major_version = 15 + +[db.pooler] +enabled = false +# Port to use for the local connection pooler. +port = 54329 +# Specifies when a server connection can be reused by other clients. +# Configure one of the supported pooler modes: `transaction`, `session`. +pool_mode = "transaction" +# How many server connections to allow per user/database pair. +default_pool_size = 20 +# Maximum number of client connections allowed. +max_client_conn = 100 + +[realtime] +enabled = true +# Bind realtime via either IPv4 or IPv6. (default: IPv6) +# ip_version = "IPv6" +# The maximum length in bytes of HTTP request headers. (default: 4096) +# max_header_length = 4096 + +[studio] +enabled = true +# Port to use for Supabase Studio. +port = 54323 +# External URL of the API server that frontend connects to. +api_url = "http://127.0.0.1" +# OpenAI API Key to use for Supabase AI in the Supabase Studio. +openai_api_key = "env(OPENAI_API_KEY)" + +# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they +# are monitored, and you can view the emails that would have been sent from the web interface. +[inbucket] +enabled = true +# Port to use for the email testing server web interface. +port = 54324 +# Uncomment to expose additional ports for testing user applications that send emails. +# smtp_port = 54325 +# pop3_port = 54326 + +[storage] +enabled = true +# The maximum file size allowed (e.g. "5MB", "500KB"). +file_size_limit = "50MiB" + +[auth] +enabled = true +# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used +# in emails. +site_url = "http://127.0.0.1:3000" +# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. +additional_redirect_urls = ["https://127.0.0.1:3000"] +# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week). +jwt_expiry = 3600 +# If disabled, the refresh token will never expire. +enable_refresh_token_rotation = true +# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds. +# Requires enable_refresh_token_rotation = true. +refresh_token_reuse_interval = 10 +# Allow/disallow new user signups to your project. +enable_signup = true +# Allow/disallow testing manual linking of accounts +enable_manual_linking = false + +[auth.email] +# Allow/disallow new user signups via email to your project. +enable_signup = true +# If enabled, a user will be required to confirm any email change on both the old, and new email +# addresses. If disabled, only the new email is required to confirm. +double_confirm_changes = true +# If enabled, users need to confirm their email address before signing in. +enable_confirmations = false + +# Uncomment to customize email template +# [auth.email.template.invite] +# subject = "You have been invited" +# content_path = "./supabase/templates/invite.html" + +[auth.sms] +# Allow/disallow new user signups via SMS to your project. +enable_signup = true +# If enabled, users need to confirm their phone number before signing in. +enable_confirmations = false +# Template for sending OTP to users +template = "Your code is {{ .Code }} ." + +# Use pre-defined map of phone number to OTP for testing. +[auth.sms.test_otp] +# 4152127777 = "123456" + +# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used. +[auth.hook.custom_access_token] +# enabled = true +# uri = "pg-functions:////" + + +# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`. +[auth.sms.twilio] +enabled = false +account_sid = "" +message_service_sid = "" +# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: +auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" + +# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, +# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`, +# `twitter`, `slack`, `spotify`, `workos`, `zoom`. +[auth.external.apple] +enabled = false +client_id = "" +# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead: +secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)" +# Overrides the default auth redirectUrl. +redirect_uri = "" +# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, +# or any other third-party OIDC providers. +url = "" + +[analytics] +enabled = true +port = 54327 +vector_port = 54328 +# Configure one of the supported backends: `postgres`, `bigquery`. +backend = "postgres" + +# Experimental features may be deprecated any time +[experimental] +# Configures Postgres storage engine to use OrioleDB (S3) +orioledb_version = "" +# Configures S3 bucket URL, eg. .s3-.amazonaws.com +s3_host = "env(S3_HOST)" +# Configures S3 bucket region, eg. us-east-1 +s3_region = "env(S3_REGION)" +# Configures AWS_ACCESS_KEY_ID for S3 bucket +s3_access_key = "env(S3_ACCESS_KEY)" +# Configures AWS_SECRET_ACCESS_KEY for S3 bucket +s3_secret_key = "env(S3_SECRET_KEY)" diff --git a/supabase/migrations/20240828064418_issue_comments.sql b/supabase/migrations/20240828064418_issue_comments.sql new file mode 100644 index 0000000..fe17092 --- /dev/null +++ b/supabase/migrations/20240828064418_issue_comments.sql @@ -0,0 +1,8 @@ +create extension if not exists vector; + +create table if not exists issue_comments ( + id int8 primary key, + issuebody text, + commentbody text not null, + embedding Vector(3072) not null +); \ No newline at end of file diff --git a/supabase/seed.sql b/supabase/seed.sql new file mode 100644 index 0000000..e69de29 diff --git a/tests/__mocks__/adapter.ts b/tests/__mocks__/adapter.ts new file mode 100644 index 0000000..4c7a797 --- /dev/null +++ b/tests/__mocks__/adapter.ts @@ -0,0 +1,62 @@ +import { Context } from "../../src/types"; +import { Comment } from "../../src/adapters/supabase/helpers/comment"; +import { Embedding } from "../../src/adapters/openai/helpers/embedding"; +import { STRINGS } from "./strings"; + +export interface CommentMock { + id: number; + commentbody: string; + issuebody: string; + embedding: number[]; +} + +export function createMockAdapters(context: Context) { + const commentMap: Map = new Map(); + return { + supabase: { + comment: { + createComment: jest.fn(async (commentBody: string, commentId: number, issueBody: string) => { + if (commentMap.has(commentId)) { + throw new Error("Comment already exists"); + } + const embedding = await context.adapters.openai.embedding.createEmbedding(commentBody); + commentMap.set(commentId, { id: commentId, commentbody: commentBody, issuebody: issueBody, embedding }); + }), + updateComment: jest.fn(async (commentBody: string, commentId: number) => { + if (!commentMap.has(commentId)) { + throw new Error(STRINGS.COMMENT_DOES_NOT_EXIST); + } + const originalComment = commentMap.get(commentId); + if (!originalComment) { + throw new Error(STRINGS.COMMENT_DOES_NOT_EXIST); + } + const { id, issuebody } = originalComment; + const embedding = await context.adapters.openai.embedding.createEmbedding(commentBody); + commentMap.set(commentId, { id, commentbody: commentBody, issuebody, embedding }); + }), + deleteComment: jest.fn(async (commentId: number) => { + if (!commentMap.has(commentId)) { + throw new Error(STRINGS.COMMENT_DOES_NOT_EXIST); + } + commentMap.delete(commentId); + }), + getComment: jest.fn(async (commentId: number) => { + if (!commentMap.has(commentId)) { + throw new Error(STRINGS.COMMENT_DOES_NOT_EXIST); + } + return commentMap.get(commentId); + }), + } as unknown as Comment, + }, + openai: { + embedding: { + createEmbedding: jest.fn(async (text: string) => { + if (text && text.length > 0) { + return new Array(3072).fill(1); + } + return new Array(3072).fill(0); + }), + } as unknown as Embedding, + }, + }; +} diff --git a/tests/__mocks__/handlers.ts b/tests/__mocks__/handlers.ts index ab4c73e..f1c494a 100644 --- a/tests/__mocks__/handlers.ts +++ b/tests/__mocks__/handlers.ts @@ -46,6 +46,16 @@ export const handlers = [ db.issueComments.create(newItem); return HttpResponse.json(newItem); }), + // update comment + http.patch("https://api.github.com/repos/:owner/:repo/issues/comments/:comment_id", async ({ params: { comment_id: commentId }, request }) => { + const { body } = await getValue(request.body); + const item = db.issueComments.findFirst({ where: { id: { equals: Number(commentId) } } }); + if (!item) { + return new HttpResponse(null, { status: 404 }); + } + item.body = body; + return HttpResponse.json(item); + }), ]; async function getValue(body: ReadableStream | null) { diff --git a/tests/__mocks__/helpers.ts b/tests/__mocks__/helpers.ts index a9fc8b0..b4c5b14 100644 --- a/tests/__mocks__/helpers.ts +++ b/tests/__mocks__/helpers.ts @@ -36,8 +36,6 @@ export async function setupTests() { number: 2, labels: [], }); - - createComment("/Hello", 1); } export function createComment(comment: string, commentId: number) { diff --git a/tests/__mocks__/strings.ts b/tests/__mocks__/strings.ts index fbd568b..83d7306 100644 --- a/tests/__mocks__/strings.ts +++ b/tests/__mocks__/strings.ts @@ -14,4 +14,5 @@ export const STRINGS = { INVALID_USE_OF_SLASH_COMMAND: 'Invalid use of slash command, use "/hello".', CONFIGURABLE_RESPONSE: "Hello, Code Reviewers!", INVALID_COMMAND: "/Goodbye", + COMMENT_DOES_NOT_EXIST: "Comment does not exist", }; diff --git a/tests/main.test.ts b/tests/main.test.ts index 26e170e..c78ec3d 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -1,3 +1,5 @@ +// cSpell:disable + import { drop } from "@mswjs/data"; import { db } from "./__mocks__/db"; import { server } from "./__mocks__/node"; @@ -11,9 +13,12 @@ import dotenv from "dotenv"; import { Logs } from "@ubiquity-dao/ubiquibot-logger"; import { Env } from "../src/types"; import { runPlugin } from "../src/plugin"; +import { CommentMock, createMockAdapters } from "./__mocks__/adapter"; dotenv.config(); jest.requireActual("@octokit/rest"); +jest.requireActual("@supabase/supabase-js"); +jest.requireActual("openai"); const octokit = new Octokit(); beforeAll(() => { @@ -33,55 +38,60 @@ describe("Plugin tests", () => { it("Should serve the manifest file", async () => { const worker = (await import("../src/worker")).default; - const response = await worker.fetch(new Request("http://localhost/manifest.json"), {}); + const response = await worker.fetch(new Request("http://localhost/manifest.json"), { + SUPABASE_KEY: "test", + SUPABASE_URL: "test", + OPENAI_API_KEY: "test", + }); const content = await response.json(); expect(content).toEqual(manifest); }); - it("Should handle an issue comment event", async () => { - const { context, infoSpy, errorSpy, debugSpy, okSpy, verboseSpy } = createContext(); - - expect(context.eventName).toBe("issue_comment.created"); - expect(context.payload.comment.body).toBe("/Hello"); - - await runPlugin(context); - - expect(errorSpy).not.toHaveBeenCalled(); - expect(debugSpy).toHaveBeenNthCalledWith(1, STRINGS.EXECUTING_HELLO_WORLD, { - caller: STRINGS.CALLER_LOGS_ANON, - sender: STRINGS.USER_1, - repo: STRINGS.TEST_REPO, - issueNumber: 1, - owner: STRINGS.USER_1, - }); - expect(infoSpy).toHaveBeenNthCalledWith(1, STRINGS.HELLO_WORLD); - expect(okSpy).toHaveBeenNthCalledWith(1, STRINGS.SUCCESSFULLY_CREATED_COMMENT); - expect(verboseSpy).toHaveBeenNthCalledWith(1, STRINGS.EXITING_HELLO_WORLD); - }); - - it("Should respond with `Hello, World!` in response to /Hello", async () => { + it("When a comment is created it should add it to the database", async () => { const { context } = createContext(); await runPlugin(context); - const comments = db.issueComments.getAll(); - expect(comments.length).toBe(2); - expect(comments[1].body).toBe(STRINGS.HELLO_WORLD); + const supabase = context.adapters.supabase; + try { + const issueBody = context.payload.issue.body || ""; + await supabase.comment.createComment(STRINGS.HELLO_WORLD, 1, issueBody); + throw new Error("Expected method to reject."); + } catch (error) { + if (error instanceof Error) { + expect(error.message).toBe("Comment already exists"); + } + } + const comment = (await supabase.comment.getComment(1)) as unknown as CommentMock; + expect(comment).toBeDefined(); + expect(comment?.commentbody).toBeDefined(); + expect(comment?.commentbody).toBe(STRINGS.HELLO_WORLD); }); - it("Should respond with `Hello, Code Reviewers` in response to /Hello", async () => { - const { context } = createContext(STRINGS.CONFIGURABLE_RESPONSE); + it("When a comment is updated it should update the database", async () => { + const { context } = createContext("Updated Message", 1, 1, 1, 1, "issue_comment.edited"); + const supabase = context.adapters.supabase; + const issueBody = context.payload.issue.body || ""; + await supabase.comment.createComment(STRINGS.HELLO_WORLD, 1, issueBody); await runPlugin(context); - const comments = db.issueComments.getAll(); - expect(comments.length).toBe(2); - expect(comments[1].body).toBe(STRINGS.CONFIGURABLE_RESPONSE); + const comment = (await supabase.comment.getComment(1)) as unknown as CommentMock; + expect(comment).toBeDefined(); + expect(comment?.commentbody).toBeDefined(); + expect(comment?.commentbody).toBe("Updated Message"); }); - it("Should not respond to a comment that doesn't contain /Hello", async () => { - const { context, errorSpy } = createContext(STRINGS.CONFIGURABLE_RESPONSE, STRINGS.INVALID_COMMAND); + it("When a comment is deleted it should delete it from the database", async () => { + const { context } = createContext("Text Message", 1, 1, 1, 1, "issue_comment.deleted"); + const supabase = context.adapters.supabase; + const issueBody = context.payload.issue.body || ""; + await supabase.comment.createComment(STRINGS.HELLO_WORLD, 1, issueBody); await runPlugin(context); - const comments = db.issueComments.getAll(); - - expect(comments.length).toBe(1); - expect(errorSpy).toHaveBeenNthCalledWith(1, STRINGS.INVALID_USE_OF_SLASH_COMMAND, { caller: STRINGS.CALLER_LOGS_ANON, body: STRINGS.INVALID_COMMAND }); + try { + await supabase.comment.getComment(1); + throw new Error("Expected method to reject."); + } catch (error) { + if (error instanceof Error) { + expect(error.message).toBe("Comment does not exist"); + } + } }); }); @@ -94,12 +104,12 @@ describe("Plugin tests", () => { * Refactor according to your needs. */ function createContext( - configurableResponse: string = "Hello, world!", // we pass the plugin configurable items here - commentBody: string = "/Hello", + commentBody: string = "Hello, world!", repoId: number = 1, payloadSenderId: number = 1, commentId: number = 1, - issueOne: number = 1 + issueOne: number = 1, + eventName: Context["eventName"] = "issue_comment.created" ) { const repo = db.repo.findFirst({ where: { id: { equals: repoId } } }) as unknown as Context["payload"]["repository"]; const sender = db.users.findFirst({ where: { id: { equals: payloadSenderId } } }) as unknown as Context["payload"]["sender"]; @@ -108,7 +118,8 @@ function createContext( createComment(commentBody, commentId); // create it first then pull it from the DB and feed it to _createContext const comment = db.issueComments.findFirst({ where: { id: { equals: commentId } } }) as unknown as Context["payload"]["comment"]; - const context = createContextInner(repo, sender, issue1, comment, configurableResponse); + const context = createContextInner(repo, sender, issue1, comment, eventName); + context.adapters = createMockAdapters(context) as unknown as Context["adapters"]; const infoSpy = jest.spyOn(context.logger, "info"); const errorSpy = jest.spyOn(context.logger, "error"); const debugSpy = jest.spyOn(context.logger, "debug"); @@ -137,10 +148,10 @@ function createContextInner( sender: Context["payload"]["sender"], issue: Context["payload"]["issue"], comment: Context["payload"]["comment"], - configurableResponse: string + eventName: Context["eventName"] = "issue_comment.created" ): Context { return { - eventName: "issue_comment.created", + eventName: eventName, payload: { action: "created", sender: sender, @@ -149,11 +160,10 @@ function createContextInner( comment: comment, installation: { id: 1 } as Context["payload"]["installation"], organization: { login: STRINGS.USER_1 } as Context["payload"]["organization"], - }, + } as Context["payload"], + config: {}, + adapters: {} as Context["adapters"], logger: new Logs("debug"), - config: { - configurableResponse, - }, env: {} as Env, octokit: octokit, }; diff --git a/wrangler.toml b/wrangler.toml index 5a0953a..2189f07 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -1,4 +1,4 @@ -name = "your-plugin-name" +name = "ubiquity-os-comment-vector-embeddings" main = "src/worker.ts" compatibility_date = "2024-05-23" node_compat = true diff --git a/yarn.lock b/yarn.lock index ec04aa0..78b6afa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -344,37 +344,37 @@ dependencies: statuses "^2.0.1" -"@cloudflare/kv-asset-handler@0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.2.tgz#06437b75664729823ac9033b89f06a3b078e4f55" - integrity sha512-EeEjMobfuJrwoctj7FA1y1KEbM0+Q1xSjobIEyie9k4haVEBB7vkDvsasw1pM3rO39mL2akxIAzLMUAtrMHZhA== +"@cloudflare/kv-asset-handler@0.3.4": + version "0.3.4" + resolved "https://registry.yarnpkg.com/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz#5cc152847c8ae4d280ec5d7f4f6ba8c976b585c3" + integrity sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q== dependencies: mime "^3.0.0" -"@cloudflare/workerd-darwin-64@1.20240610.1": - version "1.20240610.1" - resolved "https://registry.yarnpkg.com/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240610.1.tgz#417d18708664ec9662d74280f1f78cd50c209035" - integrity sha512-YanZ1iXgMGaUWlleB5cswSE6qbzyjQ8O7ENWZcPAcZZ6BfuL7q3CWi0t9iM1cv2qx92rRztsRTyjcfq099++XQ== +"@cloudflare/workerd-darwin-64@1.20240620.1": + version "1.20240620.1" + resolved "https://registry.yarnpkg.com/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240620.1.tgz#322bc6350f9649d4a649b62a86165fa12bbdc088" + integrity sha512-YWeS2aE8jAzDefuus/3GmZcFGu3Ef94uCAoxsQuaEXNsiGM9NeAhPpKC1BJAlcv168U/Q1J+6hckcGtipf6ZcQ== -"@cloudflare/workerd-darwin-arm64@1.20240610.1": - version "1.20240610.1" - resolved "https://registry.yarnpkg.com/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240610.1.tgz#740764dc991414c247cb72dd2c74985196937fa2" - integrity sha512-bRe/y/LKjIgp3L2EHjc+CvoCzfHhf4aFTtOBkv2zW+VToNJ4KlXridndf7LvR9urfsFRRo9r4TXCssuKaU+ypQ== +"@cloudflare/workerd-darwin-arm64@1.20240620.1": + version "1.20240620.1" + resolved "https://registry.yarnpkg.com/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240620.1.tgz#25cf37caf77837b8cd40e796f44aad095c39f322" + integrity sha512-3rdND+EHpmCrwYX6hvxIBSBJ0f40tRNxond1Vfw7GiR1MJVi3gragiBx75UDFHCxfRw3J0GZ1qVlkRce2/Xbsg== -"@cloudflare/workerd-linux-64@1.20240610.1": - version "1.20240610.1" - resolved "https://registry.yarnpkg.com/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240610.1.tgz#62ed716e4b216fd9ca5e40c8fcecf20c16d8fb1b" - integrity sha512-2zDcadR7+Gs9SjcMXmwsMji2Xs+yASGNA2cEHDuFc4NMUup+eL1mkzxc/QzvFjyBck98e92rBjMZt2dVscpGKg== +"@cloudflare/workerd-linux-64@1.20240620.1": + version "1.20240620.1" + resolved "https://registry.yarnpkg.com/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240620.1.tgz#4138144341d7c02709c518599ae65cb070d0eb7b" + integrity sha512-tURcTrXGeSbYqeM5ISVcofY20StKbVIcdxjJvNYNZ+qmSV9Fvn+zr7rRE+q64pEloVZfhsEPAlUCnFso5VV4XQ== -"@cloudflare/workerd-linux-arm64@1.20240610.1": - version "1.20240610.1" - resolved "https://registry.yarnpkg.com/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240610.1.tgz#c93d924618d69c8eddfe126da321d2efc3865ed0" - integrity sha512-7y41rPi5xmIYJN8CY+t3RHnjLL0xx/WYmaTd/j552k1qSr02eTE2o/TGyWZmGUC+lWnwdPQJla0mXbvdqgRdQg== +"@cloudflare/workerd-linux-arm64@1.20240620.1": + version "1.20240620.1" + resolved "https://registry.yarnpkg.com/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240620.1.tgz#35eb047c7146075d41ce4ee1af87550de892b95d" + integrity sha512-TThvkwNxaZFKhHZnNjOGqIYCOk05DDWgO+wYMuXg15ymN/KZPnCicRAkuyqiM+R1Fgc4kwe/pehjP8pbmcf6sg== -"@cloudflare/workerd-windows-64@1.20240610.1": - version "1.20240610.1" - resolved "https://registry.yarnpkg.com/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240610.1.tgz#6e55ba3c253e33c94cf0d2e2f0ac8f7e30e072bb" - integrity sha512-B0LyT3DB6rXHWNptnntYHPaoJIy0rXnGfeDBM3nEVV8JIsQrx8MEFn2F2jYioH1FkUVavsaqKO/zUosY3tZXVA== +"@cloudflare/workerd-windows-64@1.20240620.1": + version "1.20240620.1" + resolved "https://registry.yarnpkg.com/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240620.1.tgz#f4c6cb81a474aaf019dcf000bb31e46d3538c3f2" + integrity sha512-Y/BA9Yj0r7Al1HK3nDHcfISgFllw6NR3XMMPChev57vrVT9C9D4erBL3sUBfofHU+2U9L+ShLsl6obBpe3vvUw== "@commitlint/cli@19.3.0": version "19.3.0" @@ -1269,6 +1269,25 @@ resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.3.3.tgz#26b2628630fd2381c7fa1e3ab396feb9bbc575da" integrity sha512-xTUt0NulylX27/zMx04ZYar/kr1raaiFTVvQ5feljQsiAgdm0WPj4S73/ye0fbslh+15QrIuDvfCXTek7pMY5A== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@isaacs/fs-minipass@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" + integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== + dependencies: + minipass "^7.0.4" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -1763,6 +1782,11 @@ resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-2.1.0.tgz#0acf32f470af2ceaf47f095cdecd40d68666efda" integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@pkgr/core@^0.1.0": version "0.1.1" resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" @@ -1801,10 +1825,10 @@ ignore "^5.1.8" p-map "^4.0.0" -"@supabase/auth-js@2.64.2": - version "2.64.2" - resolved "https://registry.yarnpkg.com/@supabase/auth-js/-/auth-js-2.64.2.tgz#fe6828ed2c9844bf2e71b27f88ddfb635f24d1c1" - integrity sha512-s+lkHEdGiczDrzXJ1YWt2y3bxRi+qIUnXcgkpLSrId7yjBeaXBFygNjTaoZLG02KNcYwbuZ9qkEIqmj2hF7svw== +"@supabase/auth-js@2.64.4": + version "2.64.4" + resolved "https://registry.yarnpkg.com/@supabase/auth-js/-/auth-js-2.64.4.tgz#f27fdabf1ebd1b532ceb57e8bbe66969ee09cfba" + integrity sha512-9ITagy4WP4FLl+mke1rchapOH0RQpf++DI+WSG2sO1OFOZ0rW3cwAM0nCrMOxu+Zw4vJ4zObc08uvQrXx590Tg== dependencies: "@supabase/node-fetch" "^2.6.14" @@ -1822,41 +1846,41 @@ dependencies: whatwg-url "^5.0.0" -"@supabase/postgrest-js@1.15.5": - version "1.15.5" - resolved "https://registry.yarnpkg.com/@supabase/postgrest-js/-/postgrest-js-1.15.5.tgz#7fa7744cb0991328bb1a7757861e435a5477f358" - integrity sha512-YR4TiitTE2hizT7mB99Cl3V9i00RAY5sUxS2/NuWWzkreM7OeYlP2OqnqVwwb4z6ILn+j8x9e/igJDepFhjswQ== +"@supabase/postgrest-js@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@supabase/postgrest-js/-/postgrest-js-1.15.8.tgz#827aaa408cdbc89e67d0a758e7a545ac86e34312" + integrity sha512-YunjXpoQjQ0a0/7vGAvGZA2dlMABXFdVI/8TuVKtlePxyT71sl6ERl6ay1fmIeZcqxiuFQuZw/LXUuStUG9bbg== dependencies: "@supabase/node-fetch" "^2.6.14" -"@supabase/realtime-js@2.9.5": - version "2.9.5" - resolved "https://registry.yarnpkg.com/@supabase/realtime-js/-/realtime-js-2.9.5.tgz#22b7de952a7f37868ffc25d32d19f03f27bfcb40" - integrity sha512-TEHlGwNGGmKPdeMtca1lFTYCedrhTAv3nZVoSjrKQ+wkMmaERuCe57zkC5KSWFzLYkb5FVHW8Hrr+PX1DDwplQ== +"@supabase/realtime-js@2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@supabase/realtime-js/-/realtime-js-2.10.2.tgz#c2b42d17d723d2d2a9146cfad61dc3df1ce3127e" + integrity sha512-qyCQaNg90HmJstsvr2aJNxK2zgoKh9ZZA8oqb7UT2LCh3mj9zpa3Iwu167AuyNxsxrUE8eEJ2yH6wLCij4EApA== dependencies: "@supabase/node-fetch" "^2.6.14" "@types/phoenix" "^1.5.4" "@types/ws" "^8.5.10" ws "^8.14.2" -"@supabase/storage-js@2.6.0": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@supabase/storage-js/-/storage-js-2.6.0.tgz#0fa5e04db760ed7f78e4394844a6d409e537adc5" - integrity sha512-REAxr7myf+3utMkI2oOmZ6sdplMZZ71/2NEIEMBZHL9Fkmm3/JnaOZVSRqvG4LStYj2v5WhCruCzuMn6oD/Drw== +"@supabase/storage-js@2.7.0": + version "2.7.0" + resolved "https://registry.yarnpkg.com/@supabase/storage-js/-/storage-js-2.7.0.tgz#9ff322d2c3b141087aa34115cf14205e4980ce75" + integrity sha512-iZenEdO6Mx9iTR6T7wC7sk6KKsoDPLq8rdu5VRy7+JiT1i8fnqfcOr6mfF2Eaqky9VQzhP8zZKQYjzozB65Rig== dependencies: "@supabase/node-fetch" "^2.6.14" -"@supabase/supabase-js@2.43.5": - version "2.43.5" - resolved "https://registry.yarnpkg.com/@supabase/supabase-js/-/supabase-js-2.43.5.tgz#e4d5f9e5e21ef4226e0cb013c7e51fb3c5262581" - integrity sha512-Y4GukjZWW6ouohMaPlYz8tSz9ykf9jY7w9/RhqKuScmla3Xiklce8eLr8TYAtA+oQYCWxo3RgS3B6O4rd/72FA== +"@supabase/supabase-js@^2.45.2": + version "2.45.2" + resolved "https://registry.yarnpkg.com/@supabase/supabase-js/-/supabase-js-2.45.2.tgz#75df2b651942a1aba2ff7e6b02393d5ab3b86d9e" + integrity sha512-kJKY3ISFusVKQWCP8Kqo20Ebxy2WLp6Ry/Suco0aQsPXH7bvn7clswsdhcfcH/5Tr0MYz/jcCjF0n/27SetiCw== dependencies: - "@supabase/auth-js" "2.64.2" + "@supabase/auth-js" "2.64.4" "@supabase/functions-js" "2.4.1" "@supabase/node-fetch" "2.6.15" - "@supabase/postgrest-js" "1.15.5" - "@supabase/realtime-js" "2.9.5" - "@supabase/storage-js" "2.6.0" + "@supabase/postgrest-js" "1.15.8" + "@supabase/realtime-js" "2.10.2" + "@supabase/storage-js" "2.7.0" "@types/babel__core@^7.1.14": version "7.20.5" @@ -1954,6 +1978,14 @@ dependencies: "@types/node" "*" +"@types/node-fetch@^2.6.4": + version "2.6.11" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" + integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== + dependencies: + "@types/node" "*" + form-data "^4.0.0" + "@types/node-forge@^1.3.0": version "1.3.11" resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.11.tgz#0972ea538ddb0f4d9c2fa0ec5db5724773a604da" @@ -1975,10 +2007,17 @@ dependencies: undici-types "~5.26.4" +"@types/node@^18.11.18": + version "18.19.46" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.46.tgz#51801396c01153e0626e36f43386e83bc768b072" + integrity sha512-vnRgMS7W6cKa1/0G3/DTtQYpVrZ8c0Xm6UkLaVFrb9jtcVC3okokW09Ki1Qdrj9ISokszD69nY4WDLRlvHlhAA== + dependencies: + undici-types "~5.26.4" + "@types/phoenix@^1.5.4": - version "1.6.4" - resolved "https://registry.yarnpkg.com/@types/phoenix/-/phoenix-1.6.4.tgz#cceac93a827555473ad38057d1df7d06eef1ed71" - integrity sha512-B34A7uot1Cv0XtaHRYDATltAdKx0BvVKNgYNqE4WjtPUa4VQJM7kxeXcVKaH+KS+kCmZ+6w+QaUdcljiheiBJA== + version "1.6.5" + resolved "https://registry.yarnpkg.com/@types/phoenix/-/phoenix-1.6.5.tgz#5654e14ec7ad25334a157a20015996b6d7d2075e" + integrity sha512-xegpDuR+z0UqG9fwHqNoy3rI7JDlvaPh2TY47Fl80oq6g+hXT+c/LEuE43X48clZ6lOfANl5WrPur9fYO1RJ/w== "@types/pluralize@^0.0.29": version "0.0.29" @@ -2006,9 +2045,9 @@ integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== "@types/ws@^8.5.10": - version "8.5.10" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787" - integrity sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A== + version "8.5.12" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.12.tgz#619475fe98f35ccca2a2f6c137702d85ec247b7e" + integrity sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ== dependencies: "@types/node" "*" @@ -2118,6 +2157,13 @@ JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -2138,6 +2184,20 @@ acorn@^8.8.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +agent-base@^7.0.2: + version "7.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + +agentkeepalive@^4.2.1: + version "4.5.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + dependencies: + humanize-ms "^1.2.1" + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -2215,7 +2275,7 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -ansi-styles@^6.0.0, ansi-styles@^6.2.1: +ansi-styles@^6.0.0, ansi-styles@^6.1.0, ansi-styles@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== @@ -2301,6 +2361,11 @@ async-lock@^1.4.1: resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.4.1.tgz#56b8718915a9b68b10fce2f2a9a3dddf765ef53f" integrity sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + available-typed-arrays@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" @@ -2383,6 +2448,16 @@ before-after-hook@^2.2.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== +bin-links@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-4.0.4.tgz#c3565832b8e287c85f109a02a17027d152a58a63" + integrity sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA== + dependencies: + cmd-shim "^6.0.0" + npm-normalize-package-bin "^3.0.0" + read-cmd-shim "^4.0.0" + write-file-atomic "^5.0.0" + binary-extensions@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" @@ -2537,6 +2612,11 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chownr@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" + integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== + ci-info@^3.2.0: version "3.9.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" @@ -2611,6 +2691,11 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== +cmd-shim@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-6.0.3.tgz#c491e9656594ba17ac83c4bd931590a9d6e26033" + integrity sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA== + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -2650,6 +2735,13 @@ colorette@^2.0.20: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@^12.1.0, commander@~12.1.0: version "12.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" @@ -2770,6 +2862,13 @@ create-jest@^29.7.0: jest-util "^29.7.0" prompts "^2.0.1" +cross-env@7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -2781,7 +2880,7 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -2918,6 +3017,11 @@ data-uri-to-buffer@^2.0.0: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz#d296973d5a4897a5dbe31716d118211921f04770" integrity sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA== +data-uri-to-buffer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" + integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== + data-view-buffer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" @@ -2952,6 +3056,18 @@ date-fns@^2.21.1: dependencies: "@babel/runtime" "^7.21.0" +date-fns@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.6.0.tgz#f20ca4fe94f8b754951b24240676e8618c0206bf" + integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== + +debug@4: + version "4.3.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" + integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== + dependencies: + ms "2.1.2" + debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.4: version "4.3.5" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" @@ -3011,6 +3127,11 @@ defu@^6.1.4: resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + deprecation@^2.0.0: version "2.3.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" @@ -3050,6 +3171,11 @@ dotenv@16.4.5: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + easy-table@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/easy-table/-/easy-table-1.2.0.tgz#ba9225d7138fee307bfd4f0b5bc3c04bdc7c54eb" @@ -3079,6 +3205,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + env-paths@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" @@ -3394,6 +3525,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + eventemitter3@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" @@ -3500,6 +3636,14 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" + integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + file-entry-cache@8.0.0, file-entry-cache@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" @@ -3569,6 +3713,43 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" +foreground-child@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + +form-data-encoder@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" + integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +formdata-node@^4.3.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2" + integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== + dependencies: + node-domexception "1.0.0" + web-streams-polyfill "4.0.0-beta.3" + +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -3702,6 +3883,18 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@^10.3.7: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -3844,6 +4037,14 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== +https-proxy-agent@^7.0.2: + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== + dependencies: + agent-base "^7.0.2" + debug "4" + human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -3854,6 +4055,13 @@ human-signals@^5.0.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + husky@9.0.11: version "9.0.11" resolved "https://registry.yarnpkg.com/husky/-/husky-9.0.11.tgz#fc91df4c756050de41b3e478b2158b87c1e79af9" @@ -4219,6 +4427,15 @@ iterable-lookahead@^1.0.0: resolved "https://registry.yarnpkg.com/iterable-lookahead/-/iterable-lookahead-1.0.0.tgz#896dfcb78680bdb50036e97edb034c8b68a9737f" integrity sha512-hJnEP2Xk4+44DDwJqUQGdXal5VbyeWLaPyDl2AQc242Zr7iqz4DgpQOrEzglWVMGHMDCkguLHEKxd1+rOsmgSQ== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jest-changed-files@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" @@ -4859,6 +5076,11 @@ log-update@^6.0.0: strip-ansi "^7.1.0" wrap-ansi "^9.0.0" +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -4941,6 +5163,18 @@ micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.7, micromatch@~4.0.7: braces "^3.0.3" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mime@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" @@ -4961,10 +5195,10 @@ mimic-response@^3.1.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== -miniflare@3.20240610.0: - version "3.20240610.0" - resolved "https://registry.yarnpkg.com/miniflare/-/miniflare-3.20240610.0.tgz#6efeb60f3ba2e658a3e0395538010228fac0e719" - integrity sha512-J6aXmkII5gcq+kC4TurxKiR4rC++apPST/K8P/YjqoQQgrJ+NRPacBhf6iVh8R3ujnXYXaq+Ae+gm+LM0XHK/w== +miniflare@3.20240620.0: + version "3.20240620.0" + resolved "https://registry.yarnpkg.com/miniflare/-/miniflare-3.20240620.0.tgz#18e0b0755e7755d6830c67937646049fdcb8aa1a" + integrity sha512-NBMzqUE2mMlh/hIdt6U5MP+aFhEjKDq3l8CAajXAQa1WkndJdciWvzB2mfLETwoVFhMl/lphaVzyEN2AgwJpbQ== dependencies: "@cspotcode/source-map-support" "0.8.1" acorn "^8.8.0" @@ -4973,11 +5207,11 @@ miniflare@3.20240610.0: exit-hook "^2.2.1" glob-to-regexp "^0.4.1" stoppable "^1.1.0" - undici "^5.28.2" - workerd "1.20240610.1" - ws "^8.11.0" + undici "^5.28.4" + workerd "1.20240620.1" + ws "^8.14.2" youch "^3.2.2" - zod "^3.20.6" + zod "^3.22.3" minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" @@ -5005,16 +5239,39 @@ minimisted@^2.0.0: dependencies: minimist "^1.2.5" +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4, minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +minizlib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.1.tgz#46d5329d1eb3c83924eff1d3b858ca0a31581012" + integrity sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg== + dependencies: + minipass "^7.0.4" + rimraf "^5.0.5" + mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mkdirp@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.0.0: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + msw@^2.0.8: version "2.3.1" resolved "https://registry.yarnpkg.com/msw/-/msw-2.3.1.tgz#bfc73e256ffc2c74ec4381b604abb258df35f32b" @@ -5063,11 +5320,32 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-domexception@1.0.0, node-domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + node-fetch-native@^1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e" integrity sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ== +node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-fetch@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b" + integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + node-forge@^1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" @@ -5098,6 +5376,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-normalize-package-bin@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" + integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== + npm-run-all@4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" @@ -5178,6 +5461,19 @@ onetime@^6.0.0: dependencies: mimic-fn "^4.0.0" +openai@^4.56.0: + version "4.56.0" + resolved "https://registry.yarnpkg.com/openai/-/openai-4.56.0.tgz#07d3982544cabd5781127288a8dfcceb7319a4cf" + integrity sha512-zcag97+3bG890MNNa0DQD9dGmmTWL8unJdNkulZzWRXrl+QeD+YkBI4H58rJcwErxqGK6a0jVPZ4ReJjhDGcmw== + 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" + optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -5249,6 +5545,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + pako@^1.0.10: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -5326,6 +5627,14 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-to-regexp@^6.2.0: version "6.2.2" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.2.tgz#324377a83e5049cbecadc5554d6a63a9a4866b36" @@ -5471,6 +5780,11 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== +read-cmd-shim@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz#640a08b473a49043e394ae0c7a34dd822c73b9bb" + integrity sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q== + read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -5585,6 +5899,13 @@ rfdc@^1.3.1: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== +rimraf@^5.0.5: + version "5.0.10" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.10.tgz#23b9843d3dc92db71f96e1a2ce92e39fd2a8221c" + integrity sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ== + dependencies: + glob "^10.3.7" + rollup-plugin-inject@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz#e4233855bfba6c0c12a312fd6649dff9a13ee9f4" @@ -5741,7 +6062,7 @@ signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -signal-exit@^4.1.0: +signal-exit@^4.0.1, signal-exit@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== @@ -5799,7 +6120,7 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1: +source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -5888,6 +6209,15 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -5897,6 +6227,15 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string-width@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.1.0.tgz#d994252935224729ea3719c49f7206dc9c46550a" @@ -5956,6 +6295,13 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -5963,7 +6309,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.1.0: +strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== @@ -6005,6 +6351,16 @@ summary@2.1.0: resolved "https://registry.yarnpkg.com/summary/-/summary-2.1.0.tgz#be8a49a0aa34eb6ceea56042cae88f8add4b0885" integrity sha512-nMIjMrd5Z2nuB2RZCKJfFMjgS3fygbeyGk9PxPPaJR1RIcyN9yn4A63Isovzm3ZtQuEkLBVgMdPup8UeLH7aQw== +supabase@1.191.3: + version "1.191.3" + resolved "https://registry.yarnpkg.com/supabase/-/supabase-1.191.3.tgz#9e28643b10bc458f8c13a1e3f3ba9172679093f0" + integrity sha512-5tIG7mPc5lZ9QRbkZssyHiOsx42qGFaVqclauXv+1fJAkZnfA28d0pzEDvfs33+w8YTReO5nNaWAgyzkWQQwfA== + dependencies: + bin-links "^4.0.3" + https-proxy-agent "^7.0.2" + node-fetch "^3.3.2" + tar "7.4.3" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -6039,6 +6395,18 @@ synckit@^0.8.6: "@pkgr/core" "^0.1.0" tslib "^2.6.2" +tar@7.4.3: + version "7.4.3" + resolved "https://registry.yarnpkg.com/tar/-/tar-7.4.3.tgz#88bbe9286a3fcd900e94592cda7a22b192e80571" + integrity sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== + dependencies: + "@isaacs/fs-minipass" "^4.0.0" + chownr "^3.0.0" + minipass "^7.1.2" + minizlib "^3.0.1" + mkdirp "^3.0.1" + yallist "^5.0.0" + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -6257,7 +6625,7 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -undici@^5.25.4, undici@^5.28.2: +undici@^5.25.4, undici@^5.28.4: version "5.28.4" resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== @@ -6364,6 +6732,16 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" +web-streams-polyfill@4.0.0-beta.3: + version "4.0.0-beta.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38" + integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== + +web-streams-polyfill@^3.0.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" + integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -6418,40 +6796,50 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -workerd@1.20240610.1: - version "1.20240610.1" - resolved "https://registry.yarnpkg.com/workerd/-/workerd-1.20240610.1.tgz#a73718a0f2daff39b2c03e0be143ad007d13c60e" - integrity sha512-Rtut5GrsODQMh6YU43b9WZ980Wd05Ov1/ds88pT/SoetmXFBvkBzdRfiHiATv+azmGX8KveE0i/Eqzk/yI01ug== +workerd@1.20240620.1: + version "1.20240620.1" + resolved "https://registry.yarnpkg.com/workerd/-/workerd-1.20240620.1.tgz#1898fc94de8e53289b2eb261d5592474c4bc9f03" + integrity sha512-Qoq+RrFNk4pvEO+kpJVn8uJ5TRE9YJx5jX5pC5LjdKlw1XeD8EdXt5k0TbByvWunZ4qgYIcF9lnVxhcDFo203g== optionalDependencies: - "@cloudflare/workerd-darwin-64" "1.20240610.1" - "@cloudflare/workerd-darwin-arm64" "1.20240610.1" - "@cloudflare/workerd-linux-64" "1.20240610.1" - "@cloudflare/workerd-linux-arm64" "1.20240610.1" - "@cloudflare/workerd-windows-64" "1.20240610.1" - -wrangler@3.60.3: - version "3.60.3" - resolved "https://registry.yarnpkg.com/wrangler/-/wrangler-3.60.3.tgz#1b2ebd2214e10e42a143e47b425480cbe7b7be21" - integrity sha512-a6zn/KFnYaYp3nxJR/aP0TeaBvJDkrrfI89KoxUtx28H7zpya/5/VLu3CxQ3PRspEojJGF0s6f3/pddRy3F+BQ== - dependencies: - "@cloudflare/kv-asset-handler" "0.3.2" + "@cloudflare/workerd-darwin-64" "1.20240620.1" + "@cloudflare/workerd-darwin-arm64" "1.20240620.1" + "@cloudflare/workerd-linux-64" "1.20240620.1" + "@cloudflare/workerd-linux-arm64" "1.20240620.1" + "@cloudflare/workerd-windows-64" "1.20240620.1" + +wrangler@3.62.0: + version "3.62.0" + resolved "https://registry.yarnpkg.com/wrangler/-/wrangler-3.62.0.tgz#2b98e47734af2240e8c3136b1f6eaa90e363e1ed" + integrity sha512-TM1Bd8+GzxFw/JzwsC3i/Oss4LTWvIEWXXo1vZhx+7PHcsxdbnQGBBwPurHNJDSu2Pw22+2pCZiUGKexmgJksw== + dependencies: + "@cloudflare/kv-asset-handler" "0.3.4" "@esbuild-plugins/node-globals-polyfill" "^0.2.3" "@esbuild-plugins/node-modules-polyfill" "^0.2.2" blake3-wasm "^2.1.5" chokidar "^3.5.3" + date-fns "^3.6.0" esbuild "0.17.19" - miniflare "3.20240610.0" + miniflare "3.20240620.0" nanoid "^3.3.3" path-to-regexp "^6.2.0" resolve "^1.22.8" resolve.exports "^2.0.2" selfsigned "^2.0.1" - source-map "0.6.1" + source-map "^0.6.1" unenv "npm:unenv-nightly@1.10.0-1717606461.a117952" xxhash-wasm "^1.0.1" optionalDependencies: fsevents "~2.3.2" +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -6470,6 +6858,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrap-ansi@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.0.tgz#1a3dc8b70d85eeb8398ddfb1e4a02cd186e58b3e" @@ -6492,10 +6889,18 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@^8.11.0, ws@^8.14.2: - version "8.17.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.0.tgz#d145d18eca2ed25aaf791a183903f7be5e295fea" - integrity sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow== +write-file-atomic@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" + integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^4.0.1" + +ws@^8.14.2: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== xdg-basedir@^5.1.0: version "5.1.0" @@ -6522,6 +6927,11 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== +yallist@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" + integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== + yaml@^2.4.5: version "2.4.5" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.5.tgz#60630b206dd6d84df97003d33fc1ddf6296cca5e" @@ -6574,7 +6984,7 @@ zod-validation-error@^3.0.3: resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-3.3.0.tgz#2cfe81b62d044e0453d1aa3ae7c32a2f36dde9af" integrity sha512-Syib9oumw1NTqEv4LT0e6U83Td9aVRk9iTXPUQr1otyV1PuXQKOvOwhMNqZIq5hluzHP2pMgnOmHEo7kPdI2mw== -zod@^3.20.6, zod@^3.22.4: +zod@^3.22.3, zod@^3.22.4: version "3.23.8" resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==