diff --git a/.github/workflows/update-configuration.yml b/.github/workflows/update-configuration.yml new file mode 100644 index 0000000..2490c49 --- /dev/null +++ b/.github/workflows/update-configuration.yml @@ -0,0 +1,58 @@ +name: "Update Configuration" + +on: + workflow_dispatch: + push: + +jobs: + update: + name: "Update Configuration in manifest.json" + runs-on: ubuntu-latest + permissions: write-all + + steps: + - uses: actions/checkout@v4 + + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: "20.10.0" + + - name: Install deps and run configuration update + run: | + yarn install --immutable --immutable-cache --check-cache + yarn tsc --noCheck --project tsconfig.json + + - name: Update manifest configuration using GitHub Script + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = require('path'); + + const { pluginSettingsSchema } = require('./src/types'); + + const manifestPath = path.resolve("${{ github.workspace }}", './manifest.json'); + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); + + const configuration = JSON.stringify(pluginSettingsSchema); + + manifest["configuration"] = JSON.parse(configuration); + + const updatedManifest = JSON.stringify(manifest, null, 2) + console.log('Updated manifest:', updatedManifest); + fs.writeFileSync(manifestPath, updatedManifest); + + - name: Commit and Push generated types + run: | + git config --global user.name 'ubiquity-os[bot]' + git config --global user.email 'ubiquity-os[bot]@users.noreply.github.com' + git add ./manifest.json + if [ -n "$(git diff-index --cached --name-only HEAD)" ]; then + git commit -m "chore: updated generated configuration" || echo "Lint-staged check failed" + git push origin HEAD:${{ github.ref_name }} + else + echo "No changes to commit" + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/manifest.json b/manifest.json index 39df377..3768f7a 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,36 @@ { "name": "Generate vector embeddings", "description": "Enables the storage, updating, and deletion of issue comment embeddings.", - "ubiquity:listeners": ["issue_comment.created", "issue_comment.edited", "issue_comment.deleted", "issues.opened", "issues.edited", "issues.deleted", "issues.labeled"] -} + "ubiquity:listeners": [ + "issue_comment.created", + "issue_comment.edited", + "issue_comment.deleted", + "issues.opened", + "issues.edited", + "issues.deleted", + "issues.labeled" + ], + "configuration": { + "default": {}, + "type": "object", + "properties": { + "matchThreshold": { + "default": 0.95, + "type": "number" + }, + "warningThreshold": { + "default": 0.75, + "type": "number" + }, + "jobMatchingThreshold": { + "default": 0.75, + "type": "number" + } + }, + "required": [ + "matchThreshold", + "warningThreshold", + "jobMatchingThreshold" + ] + } +} \ No newline at end of file diff --git a/package.json b/package.json index 869d1c3..e1916ce 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "supabase": "1.200.3", "ts-jest": "29.1.5", "tsx": "4.15.6", - "typescript": "5.4.5", + "typescript": "5.6.2", "typescript-eslint": "7.13.1", "wrangler": "3.78.12" }, diff --git a/src/handlers/validator.ts b/src/handlers/validator.ts new file mode 100644 index 0000000..6438455 --- /dev/null +++ b/src/handlers/validator.ts @@ -0,0 +1,36 @@ +import { TransformDecodeCheckError, TransformDecodeError, Value, ValueError } from "@sinclair/typebox/value"; +import { Env, envValidator, PluginSettings, pluginSettingsSchema, pluginSettingsValidator } from "../types"; + +export function validateAndDecodeSchemas(env: Env, rawSettings: object) { + const errors: ValueError[] = []; + const settings = Value.Default(pluginSettingsSchema, rawSettings) as PluginSettings; + + if (!pluginSettingsValidator.test(settings)) { + for (const error of pluginSettingsValidator.errors(settings)) { + console.error(error); + errors.push(error); + } + } + + if (!envValidator.test(env)) { + for (const error of envValidator.errors(env)) { + console.error(error); + errors.push(error); + } + } + + if (errors.length) { + throw { errors }; + } + + try { + const decodedEnv = Value.Decode(envValidator.schema, env); + const decodedSettings = Value.Decode(pluginSettingsSchema, settings); + return { decodedEnv, decodedSettings }; + } catch (e) { + if (e instanceof TransformDecodeCheckError || e instanceof TransformDecodeError) { + throw { errors: [e.error] }; + } + throw e; + } +} diff --git a/src/worker.ts b/src/worker.ts index 40df400..33370a1 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -1,17 +1,21 @@ -import { Value } from "@sinclair/typebox/value"; -import { plugin } from "./plugin"; -import { Env, envValidator, pluginSettingsSchema, pluginSettingsValidator } from "./types"; import manifest from "../manifest.json"; +import { validateAndDecodeSchemas } from "./handlers/validator"; +import { plugin } from "./plugin"; +import { Env } from "./types"; export default { async fetch(request: Request, env: Env): Promise { try { - if (request.method === "GET") { - const url = new URL(request.url); - if (url.pathname === "/manifest.json") { + const url = new URL(request.url); + if (url.pathname === "/manifest") { + if (request.method === "GET") { return new Response(JSON.stringify(manifest), { headers: { "content-type": "application/json" }, }); + } else if (request.method === "POST") { + const webhookPayload = await request.json(); + validateAndDecodeSchemas(env, webhookPayload.settings); + return new Response(JSON.stringify({ message: "Schema is valid" }), { status: 200, headers: { "content-type": "application/json" } }); } } if (request.method !== "POST") { @@ -29,33 +33,10 @@ export default { } const webhookPayload = await request.json(); - const settings = Value.Decode(pluginSettingsSchema, Value.Default(pluginSettingsSchema, webhookPayload.settings)); - - if (!pluginSettingsValidator.test(settings)) { - const errors: string[] = []; - for (const error of pluginSettingsValidator.errors(settings)) { - console.error(error); - errors.push(`${error.path}: ${error.message}`); - } - return new Response(JSON.stringify({ error: `Error: "Invalid settings provided. ${errors.join("; ")}"` }), { - status: 400, - headers: { "content-type": "application/json" }, - }); - } - if (!envValidator.test(env)) { - const errors: string[] = []; - for (const error of envValidator.errors(env)) { - console.error(error); - errors.push(`${error.path}: ${error.message}`); - } - return new Response(JSON.stringify({ error: `Error: "Invalid environment provided. ${errors.join("; ")}"` }), { - status: 400, - headers: { "content-type": "application/json" }, - }); - } + const { decodedSettings, decodedEnv } = validateAndDecodeSchemas(env, webhookPayload.settings); - webhookPayload.settings = settings; - await plugin(webhookPayload, env); + webhookPayload.settings = decodedSettings; + await plugin(webhookPayload, decodedEnv); return new Response(JSON.stringify("OK"), { status: 200, headers: { "content-type": "application/json" } }); } catch (error) { return handleUncaughtError(error); @@ -63,8 +44,8 @@ export default { }, }; -function handleUncaughtError(error: unknown) { - console.error(error); +function handleUncaughtError(errors: unknown) { + console.error(errors); const status = 500; - return new Response(JSON.stringify({ error }), { status: status, headers: { "content-type": "application/json" } }); + return new Response(JSON.stringify(errors), { status: status, headers: { "content-type": "application/json" } }); } diff --git a/tests/main.test.ts b/tests/main.test.ts index 78de1fd..905b786 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -37,7 +37,7 @@ 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"), { SUPABASE_KEY: "test", SUPABASE_URL: "test", VOYAGEAI_API_KEY: "test", diff --git a/yarn.lock b/yarn.lock index ebaf74d..ac66d8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6656,10 +6656,10 @@ typescript-eslint@7.13.1: "@typescript-eslint/parser" "7.13.1" "@typescript-eslint/utils" "7.13.1" -typescript@5.4.5: - version "5.4.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" - integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== +typescript@5.6.2: + version "5.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0" + integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw== uc.micro@^2.0.0, uc.micro@^2.1.0: version "2.1.0"