From 6c4456e708c2b77a149a68e29839f67765a67e40 Mon Sep 17 00:00:00 2001 From: Alvin Mei Date: Tue, 7 Apr 2026 14:37:27 -0400 Subject: [PATCH 1/8] bones for chat --- apps/bridge/.env.example | 12 + apps/bridge/package.json | 1 + .../src/modules/chat/origin-validator.ts | 82 ++ apps/bridge/src/modules/chat/routes.ts | 91 ++ apps/bridge/src/modules/chat/service.ts | 71 + apps/bridge/src/shared/plugins/support.ts | 20 - .../bridge/src/shared/schemas/wafir-config.ts | 1 + apps/bridge/swagger.json | 180 ++- apps/bridge/test/chat-routes.test.ts | 143 ++ apps/bridge/test/origin-validator.test.ts | 178 +++ apps/www/public/wafir.yaml | 5 + packages/wafir/src/api/client.ts | 32 + packages/wafir/src/api/index.ts | 1249 +++++++++-------- packages/wafir/src/default-config.ts | 5 - packages/wafir/src/index.ts | 2 + .../wafir/src/styles/wafir-chat-field.css | 187 +++ packages/wafir/src/wafir-chat-field.ts | 238 ++++ packages/wafir/src/wafir-form.ts | 14 + pnpm-lock.yaml | 955 +++++++++++++ 19 files changed, 2789 insertions(+), 677 deletions(-) create mode 100644 apps/bridge/src/modules/chat/origin-validator.ts create mode 100644 apps/bridge/src/modules/chat/routes.ts create mode 100644 apps/bridge/src/modules/chat/service.ts delete mode 100644 apps/bridge/src/shared/plugins/support.ts create mode 100644 apps/bridge/test/chat-routes.test.ts create mode 100644 apps/bridge/test/origin-validator.test.ts create mode 100644 packages/wafir/src/styles/wafir-chat-field.css create mode 100644 packages/wafir/src/wafir-chat-field.ts diff --git a/apps/bridge/.env.example b/apps/bridge/.env.example index 01e0d59..36353d0 100644 --- a/apps/bridge/.env.example +++ b/apps/bridge/.env.example @@ -11,3 +11,15 @@ BASE_URL=http://localhost:3000 # AWS_SECRET_ACCESS_KEY= AWS_REGION= S3_BUCKET_NAME= + +# Chat Configuration +# Comma-separated list of authorized URL origins or domains for chat. +# Supports wildcard subdomains with *. +# Examples: +# https://example.com - exact match only +# https://*.example.com - matches any subdomain (foo.example.com, bar.example.com) +# https://grants.gov,https://*.agency.gov - multiple origins +CHAT_AUTHORIZED_URLS= + +# Bedrock model ID for chat (e.g., anthropic.claude-3-haiku-20240307-v1:0) +CHAT_BEDROCK_MODEL_ID= diff --git a/apps/bridge/package.json b/apps/bridge/package.json index cab1556..d4c8fd4 100644 --- a/apps/bridge/package.json +++ b/apps/bridge/package.json @@ -28,6 +28,7 @@ "author": "", "license": "ISC", "dependencies": { + "@aws-sdk/client-bedrock-runtime": "^3.1025.0", "@aws-sdk/client-s3": "^3.954.0", "@aws-sdk/s3-request-presigner": "^3.954.0", "@fastify/autoload": "^6.0.0", diff --git a/apps/bridge/src/modules/chat/origin-validator.ts b/apps/bridge/src/modules/chat/origin-validator.ts new file mode 100644 index 0000000..384b9e8 --- /dev/null +++ b/apps/bridge/src/modules/chat/origin-validator.ts @@ -0,0 +1,82 @@ +// Copyright (C) 2024 BPS-Consulting - Licensed under AGPLv3 + +/** + * Validates if an origin is authorized for chat based on CHAT_AUTHORIZED_URLS. + * Supports exact matches and wildcard subdomains (e.g., https://*.example.com). + */ + +/** + * Parses the CHAT_AUTHORIZED_URLS environment variable into a list of patterns. + */ +export function getAuthorizedPatterns(): string[] { + const envValue = process.env.CHAT_AUTHORIZED_URLS || ""; + if (!envValue.trim()) { + return []; + } + return envValue + .split(",") + .map((url) => url.trim()) + .filter((url) => url.length > 0); +} + +/** + * Checks if a given origin matches an authorized pattern. + * Supports wildcard subdomains: https://*.example.com matches https://foo.example.com + */ +export function matchesPattern(origin: string, pattern: string): boolean { + // Handle wildcard patterns like https://*.example.com + if (pattern.includes("*.")) { + try { + const patternUrl = new URL(pattern.replace("*.", "placeholder.")); + const originUrl = new URL(origin); + + // Protocol must match exactly + if (patternUrl.protocol !== originUrl.protocol) { + return false; + } + + // Port must match (or both be absent) + if (patternUrl.port !== originUrl.port) { + return false; + } + + // Extract the base domain from pattern (e.g., example.com from *.example.com) + const baseDomain = patternUrl.hostname.replace("placeholder.", ""); + + // Origin hostname must end with .baseDomain or be exactly baseDomain + const originHostname = originUrl.hostname; + if ( + originHostname === baseDomain || + originHostname.endsWith("." + baseDomain) + ) { + return true; + } + + return false; + } catch { + return false; + } + } + + // Exact match (case-sensitive) + return origin === pattern; +} + +/** + * Validates if an origin is authorized for chat. + * @param origin - The Origin header value from the request + * @returns true if the origin is authorized, false otherwise + */ +export function isOriginAuthorized(origin: string | undefined): boolean { + if (!origin) { + return false; + } + + const patterns = getAuthorizedPatterns(); + if (patterns.length === 0) { + // No authorized URLs configured = no origins allowed + return false; + } + + return patterns.some((pattern) => matchesPattern(origin, pattern)); +} diff --git a/apps/bridge/src/modules/chat/routes.ts b/apps/bridge/src/modules/chat/routes.ts new file mode 100644 index 0000000..12ba357 --- /dev/null +++ b/apps/bridge/src/modules/chat/routes.ts @@ -0,0 +1,91 @@ +// Copyright (C) 2024 BPS-Consulting - Licensed under AGPLv3 +import { FastifyPluginAsync } from "fastify"; +import { isOriginAuthorized } from "./origin-validator.js"; +import { ChatService } from "./service.js"; + +interface ChatBody { + message: string; +} + +const chatRoute: FastifyPluginAsync = async (fastify, opts): Promise => { + const chatService = new ChatService(); + + fastify.post<{ Body: ChatBody }>( + "/", + { + schema: { + tags: ["Chat"], + summary: "Send a chat message", + description: + "Sends a message to the AI chat service and returns a response. Only authorized origins can use this endpoint.", + body: { + type: "object", + required: ["message"], + properties: { + message: { + type: "string", + description: "The user's message to send to the chat service", + }, + }, + }, + response: { + 200: { + type: "object", + properties: { + reply: { + type: "string", + description: "The AI's response", + }, + }, + }, + 403: { + type: "object", + properties: { + error: { + type: "string", + description: "Error message for unauthorized access", + }, + }, + }, + }, + }, + }, + async (request, reply) => { + // Check origin authorization + const origin = request.headers.origin; + + if (!isOriginAuthorized(origin)) { + request.log.warn({ origin }, "Unauthorized chat origin"); + return reply.code(403).send({ + error: "not authorized", + }); + } + + try { + const { message } = request.body; + + if (!message || typeof message !== "string" || message.trim() === "") { + return reply.code(400).send({ + error: "Message is required", + }); + } + + const chatReply = await chatService.chat(message.trim()); + + return reply.send({ + reply: chatReply, + }); + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + request.log.error({ error: errorMessage }, "Chat request failed"); + + return reply.code(500).send({ + error: "Chat service unavailable", + }); + } + }, + ); +}; + +export default chatRoute; diff --git a/apps/bridge/src/modules/chat/service.ts b/apps/bridge/src/modules/chat/service.ts new file mode 100644 index 0000000..8922ae7 --- /dev/null +++ b/apps/bridge/src/modules/chat/service.ts @@ -0,0 +1,71 @@ +// Copyright (C) 2024 BPS-Consulting - Licensed under AGPLv3 +import { + BedrockRuntimeClient, + InvokeModelCommand, +} from "@aws-sdk/client-bedrock-runtime"; + +export interface ChatRequest { + message: string; +} + +export interface ChatResponse { + reply: string; +} + +/** + * Service for interacting with Amazon Bedrock chat models. + */ +export class ChatService { + private client: BedrockRuntimeClient; + private modelId: string; + + constructor() { + this.client = new BedrockRuntimeClient({ + region: process.env.AWS_REGION || "us-east-1", + }); + this.modelId = + process.env.CHAT_BEDROCK_MODEL_ID || + "anthropic.claude-3-haiku-20240307-v1:0"; + } + + /** + * Sends a message to Bedrock and returns the response. + * @param message - The user's message + * @returns The AI's reply + */ + async chat(message: string): Promise { + // Format for Claude models on Bedrock + const payload = { + anthropic_version: "bedrock-2023-05-31", + max_tokens: 1024, + messages: [ + { + role: "user", + content: message, + }, + ], + }; + + const command = new InvokeModelCommand({ + modelId: this.modelId, + contentType: "application/json", + accept: "application/json", + body: JSON.stringify(payload), + }); + + const response = await this.client.send(command); + const responseBody = JSON.parse(new TextDecoder().decode(response.body)); + + // Extract text from Claude response format + if (responseBody.content && Array.isArray(responseBody.content)) { + const textContent = responseBody.content.find( + (c: { type: string }) => c.type === "text", + ); + if (textContent && textContent.text) { + return textContent.text; + } + } + + return responseBody.completion || "No response generated"; + } +} diff --git a/apps/bridge/src/shared/plugins/support.ts b/apps/bridge/src/shared/plugins/support.ts deleted file mode 100644 index c49c733..0000000 --- a/apps/bridge/src/shared/plugins/support.ts +++ /dev/null @@ -1,20 +0,0 @@ -import fp from "fastify-plugin"; - -export interface SupportPluginOptions { - // Specify Support plugin options here -} - -// The use of fastify-plugin is required to be able -// to export the decorators to the outer scope -export default fp(async (fastify, opts) => { - fastify.decorate("someSupport", function () { - return "hugs"; - }); -}); - -// When using .decorate you have to specify added properties for Typescript -declare module "fastify" { - export interface FastifyInstance { - someSupport(): string; - } -} diff --git a/apps/bridge/src/shared/schemas/wafir-config.ts b/apps/bridge/src/shared/schemas/wafir-config.ts index 3a1c02d..0923517 100644 --- a/apps/bridge/src/shared/schemas/wafir-config.ts +++ b/apps/bridge/src/shared/schemas/wafir-config.ts @@ -13,6 +13,7 @@ const fieldSchema = { "markdown", "rating", "date", + "chat", ], description: "Field input type. Matches GitHub Form Schema types plus Wafir extensions.", diff --git a/apps/bridge/swagger.json b/apps/bridge/swagger.json index 1cf8747..b506bb2 100644 --- a/apps/bridge/swagger.json +++ b/apps/bridge/swagger.json @@ -12,7 +12,9 @@ "/auth/github": { "get": { "summary": "Initiate GitHub OAuth", - "tags": ["Auth"], + "tags": [ + "Auth" + ], "description": "Redirects to GitHub OAuth for user authorization", "parameters": [ { @@ -42,7 +44,9 @@ "/auth/github/callback": { "get": { "summary": "GitHub OAuth Callback", - "tags": ["Auth"], + "tags": [ + "Auth" + ], "description": "Handles OAuth callback from GitHub", "parameters": [ { @@ -72,7 +76,9 @@ "/auth/status/{installationId}": { "get": { "summary": "Check Auth Status", - "tags": ["Auth"], + "tags": [ + "Auth" + ], "description": "Check if user token exists for installation", "parameters": [ { @@ -109,7 +115,9 @@ "/auth/{installationId}": { "delete": { "summary": "Disconnect Auth", - "tags": ["Auth"], + "tags": [ + "Auth" + ], "description": "Remove stored user token for installation", "parameters": [ { @@ -128,10 +136,74 @@ } } }, + "/chat/": { + "post": { + "summary": "Send a chat message", + "tags": [ + "Chat" + ], + "description": "Sends a message to the AI chat service and returns a response. Only authorized origins can use this endpoint.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "The user's message to send to the chat service" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "reply": { + "type": "string", + "description": "The AI's response" + } + } + } + } + } + }, + "403": { + "description": "Default Response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "Error message for unauthorized access" + } + } + } + } + } + } + } + } + }, "/config/": { "get": { "summary": "Get WAFIR Configuration", - "tags": ["WAFIR"], + "tags": [ + "WAFIR" + ], "description": "Fetches and parses a wafir configuration file from a user-provided URL. The URL should point to a raw YAML or JSON configuration file.", "parameters": [ { @@ -152,7 +224,9 @@ "application/json": { "schema": { "type": "object", - "required": ["targets"], + "required": [ + "targets" + ], "properties": { "title": { "type": "string", @@ -165,7 +239,12 @@ "description": "Target destinations for form submissions. Each target defines where and how submissions are stored.", "items": { "type": "object", - "required": ["id", "type", "target", "authRef"], + "required": [ + "id", + "type", + "target", + "authRef" + ], "properties": { "id": { "type": "string", @@ -173,7 +252,10 @@ }, "type": { "type": "string", - "enum": ["github/issues", "github/project"], + "enum": [ + "github/issues", + "github/project" + ], "description": "Target type using MIME-type convention. Currently supported: github/issues, github/project." }, "target": { @@ -188,32 +270,13 @@ "additionalProperties": false } }, - "telemetry": { - "type": "object", - "description": "Automatic data collection settings", - "properties": { - "screenshot": { - "type": "boolean", - "default": true, - "description": "Enable screenshot capture" - }, - "browserInfo": { - "type": "boolean", - "default": true, - "description": "Collect URL, user agent, viewport, language" - }, - "consoleLog": { - "type": "boolean", - "default": false, - "description": "Capture console messages" - } - } - }, "forms": { "type": "array", "items": { "type": "object", - "required": ["id"], + "required": [ + "id" + ], "properties": { "id": { "type": "string", @@ -231,7 +294,9 @@ "type": "array", "items": { "type": "object", - "required": ["type"], + "required": [ + "type" + ], "properties": { "type": { "type": "string", @@ -243,7 +308,8 @@ "checkboxes", "markdown", "rating", - "date" + "date", + "chat" ], "description": "Field input type. Matches GitHub Form Schema types plus Wafir extensions." }, @@ -253,7 +319,10 @@ }, "display": { "type": "string", - "enum": ["visible", "none"], + "enum": [ + "visible", + "none" + ], "default": "visible", "description": "Controls field visibility. 'none' hides the field from the UI but still includes its value in submissions. Defaults to 'visible'." }, @@ -302,7 +371,9 @@ "type": "array", "items": { "type": "object", - "required": ["label"], + "required": [ + "label" + ], "properties": { "label": { "type": "string" @@ -432,7 +503,9 @@ "/config/template": { "get": { "summary": "Get GitHub Issue Form Template", - "tags": ["WAFIR"], + "tags": [ + "WAFIR" + ], "description": "Fetches and parses a GitHub Issue Form template from a user-provided URL. Returns the body (fields) and labels from the template.", "parameters": [ { @@ -470,7 +543,9 @@ "description": "Labels from the template" } }, - "required": ["body"] + "required": [ + "body" + ] } } } @@ -517,14 +592,19 @@ "/generate/": { "post": { "summary": "Generate Sample Config", - "tags": ["WAFIR"], + "tags": [ + "WAFIR" + ], "description": "Generates a sample wafir.yaml configuration file based on GitHub repository labels and project fields. Provide your installation ID and an array of targets to analyze. Returns the config as plain text YAML.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", - "required": ["installationId", "targets"], + "required": [ + "installationId", + "targets" + ], "properties": { "installationId": { "type": "number", @@ -535,11 +615,17 @@ "description": "Array of targets to analyze", "items": { "type": "object", - "required": ["type", "target"], + "required": [ + "type", + "target" + ], "properties": { "type": { "type": "string", - "enum": ["github/issues", "github/project"], + "enum": [ + "github/issues", + "github/project" + ], "description": "Target type" }, "target": { @@ -610,7 +696,9 @@ "/health/": { "get": { "summary": "Health Check", - "tags": ["Health"], + "tags": [ + "Health" + ], "description": "Returns the health status of the bridge service", "responses": { "200": { @@ -637,7 +725,9 @@ "/notifications/": { "post": { "summary": "Store Notification", - "tags": ["WAFIR"], + "tags": [ + "WAFIR" + ], "description": "Accepts a JSON payload and stores it in S3 in the notifications folder.", "requestBody": { "content": { @@ -695,7 +785,9 @@ "/submit/": { "post": { "summary": "Submit Feedback/Issue", - "tags": ["WAFIR"], + "tags": [ + "WAFIR" + ], "description": "Creates a GitHub issue or project draft from form fields. Supports multipart/form-data.", "responses": { "200": { @@ -711,4 +803,4 @@ "description": "Local Development Server" } ] -} +} \ No newline at end of file diff --git a/apps/bridge/test/chat-routes.test.ts b/apps/bridge/test/chat-routes.test.ts new file mode 100644 index 0000000..19d54cc --- /dev/null +++ b/apps/bridge/test/chat-routes.test.ts @@ -0,0 +1,143 @@ +// Copyright (C) 2024 BPS-Consulting - Licensed under AGPLv3 +import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; +import Fastify, { FastifyInstance } from "fastify"; +import chatRoute from "../src/modules/chat/routes.js"; + +// Mock the ChatService class properly +vi.mock("../src/modules/chat/service.js", () => { + return { + ChatService: class MockChatService { + chat = vi.fn().mockResolvedValue("Hello! How can I help you?"); + }, + }; +}); + +describe("POST /chat", () => { + let app: FastifyInstance; + const originalEnv = process.env.CHAT_AUTHORIZED_URLS; + + beforeEach(async () => { + // Set up authorized URLs + process.env.CHAT_AUTHORIZED_URLS = + "https://example.com,https://*.agency.gov"; + + app = Fastify({ logger: false }); + await app.register(chatRoute, { prefix: "/chat" }); + await app.ready(); + }); + + afterEach(async () => { + await app.close(); + if (originalEnv === undefined) { + delete process.env.CHAT_AUTHORIZED_URLS; + } else { + process.env.CHAT_AUTHORIZED_URLS = originalEnv; + } + }); + + it("should return 403 for unauthorized origin", async () => { + const response = await app.inject({ + method: "POST", + url: "/chat/", + headers: { + origin: "https://malicious.com", + "content-type": "application/json", + }, + payload: { message: "Hello" }, + }); + + expect(response.statusCode).toBe(403); + expect(response.json()).toEqual({ error: "not authorized" }); + }); + + it("should return 403 when origin header is missing", async () => { + const response = await app.inject({ + method: "POST", + url: "/chat/", + headers: { + "content-type": "application/json", + }, + payload: { message: "Hello" }, + }); + + expect(response.statusCode).toBe(403); + expect(response.json()).toEqual({ error: "not authorized" }); + }); + + it("should return 200 for authorized exact match origin", async () => { + const response = await app.inject({ + method: "POST", + url: "/chat/", + headers: { + origin: "https://example.com", + "content-type": "application/json", + }, + payload: { message: "Hello" }, + }); + + expect(response.statusCode).toBe(200); + expect(response.json()).toHaveProperty("reply"); + }); + + it("should return 200 for authorized wildcard match origin", async () => { + const response = await app.inject({ + method: "POST", + url: "/chat/", + headers: { + origin: "https://sub.agency.gov", + "content-type": "application/json", + }, + payload: { message: "Hello" }, + }); + + expect(response.statusCode).toBe(200); + expect(response.json()).toHaveProperty("reply"); + }); + + it("should return 400 when message is missing", async () => { + const response = await app.inject({ + method: "POST", + url: "/chat/", + headers: { + origin: "https://example.com", + "content-type": "application/json", + }, + payload: {}, + }); + + expect(response.statusCode).toBe(400); + expect(response.json()).toHaveProperty("error"); + }); + + it("should return 400 when message is empty", async () => { + const response = await app.inject({ + method: "POST", + url: "/chat/", + headers: { + origin: "https://example.com", + "content-type": "application/json", + }, + payload: { message: "" }, + }); + + expect(response.statusCode).toBe(400); + expect(response.json()).toHaveProperty("error"); + }); + + it("should return 403 when no authorized URLs are configured", async () => { + delete process.env.CHAT_AUTHORIZED_URLS; + + const response = await app.inject({ + method: "POST", + url: "/chat/", + headers: { + origin: "https://example.com", + "content-type": "application/json", + }, + payload: { message: "Hello" }, + }); + + expect(response.statusCode).toBe(403); + expect(response.json()).toEqual({ error: "not authorized" }); + }); +}); diff --git a/apps/bridge/test/origin-validator.test.ts b/apps/bridge/test/origin-validator.test.ts new file mode 100644 index 0000000..09724a8 --- /dev/null +++ b/apps/bridge/test/origin-validator.test.ts @@ -0,0 +1,178 @@ +// Copyright (C) 2024 BPS-Consulting - Licensed under AGPLv3 +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { + getAuthorizedPatterns, + matchesPattern, + isOriginAuthorized, +} from "../src/modules/chat/origin-validator.js"; + +describe("Chat Origin Validator", () => { + const originalEnv = process.env.CHAT_AUTHORIZED_URLS; + + afterEach(() => { + // Restore original env + if (originalEnv === undefined) { + delete process.env.CHAT_AUTHORIZED_URLS; + } else { + process.env.CHAT_AUTHORIZED_URLS = originalEnv; + } + }); + + describe("getAuthorizedPatterns", () => { + it("should return empty array when env var is not set", () => { + delete process.env.CHAT_AUTHORIZED_URLS; + const patterns = getAuthorizedPatterns(); + expect(patterns).toEqual([]); + }); + + it("should return empty array when env var is empty", () => { + process.env.CHAT_AUTHORIZED_URLS = ""; + const patterns = getAuthorizedPatterns(); + expect(patterns).toEqual([]); + }); + + it("should parse single URL", () => { + process.env.CHAT_AUTHORIZED_URLS = "https://example.com"; + const patterns = getAuthorizedPatterns(); + expect(patterns).toEqual(["https://example.com"]); + }); + + it("should parse multiple URLs", () => { + process.env.CHAT_AUTHORIZED_URLS = + "https://example.com,https://test.org,https://*.agency.gov"; + const patterns = getAuthorizedPatterns(); + expect(patterns).toEqual([ + "https://example.com", + "https://test.org", + "https://*.agency.gov", + ]); + }); + + it("should trim whitespace from URLs", () => { + process.env.CHAT_AUTHORIZED_URLS = + " https://example.com , https://test.org "; + const patterns = getAuthorizedPatterns(); + expect(patterns).toEqual(["https://example.com", "https://test.org"]); + }); + + it("should filter out empty entries", () => { + process.env.CHAT_AUTHORIZED_URLS = + "https://example.com,,https://test.org"; + const patterns = getAuthorizedPatterns(); + expect(patterns).toEqual(["https://example.com", "https://test.org"]); + }); + }); + + describe("matchesPattern", () => { + describe("exact matches", () => { + it("should match exact URL", () => { + expect( + matchesPattern("https://example.com", "https://example.com"), + ).toBe(true); + }); + + it("should not match different protocol", () => { + expect( + matchesPattern("http://example.com", "https://example.com"), + ).toBe(false); + }); + + it("should not match different domain", () => { + expect(matchesPattern("https://other.com", "https://example.com")).toBe( + false, + ); + }); + + it("should not match subdomain against exact domain", () => { + expect( + matchesPattern("https://sub.example.com", "https://example.com"), + ).toBe(false); + }); + }); + + describe("wildcard matches", () => { + it("should match subdomain with wildcard pattern", () => { + expect( + matchesPattern("https://sub.example.com", "https://*.example.com"), + ).toBe(true); + }); + + it("should match deep subdomain with wildcard pattern", () => { + expect( + matchesPattern( + "https://deep.sub.example.com", + "https://*.example.com", + ), + ).toBe(true); + }); + + it("should match exact domain with wildcard pattern", () => { + expect( + matchesPattern("https://example.com", "https://*.example.com"), + ).toBe(true); + }); + + it("should not match different protocol with wildcard", () => { + expect( + matchesPattern("http://sub.example.com", "https://*.example.com"), + ).toBe(false); + }); + + it("should not match different base domain with wildcard", () => { + expect( + matchesPattern("https://sub.other.com", "https://*.example.com"), + ).toBe(false); + }); + + it("should handle wildcard with port", () => { + expect( + matchesPattern( + "https://sub.example.com:8080", + "https://*.example.com:8080", + ), + ).toBe(true); + }); + + it("should not match when port differs", () => { + expect( + matchesPattern( + "https://sub.example.com:8080", + "https://*.example.com", + ), + ).toBe(false); + }); + }); + }); + + describe("isOriginAuthorized", () => { + beforeEach(() => { + process.env.CHAT_AUTHORIZED_URLS = + "https://example.com,https://*.agency.gov"; + }); + + it("should return false when origin is undefined", () => { + expect(isOriginAuthorized(undefined)).toBe(false); + }); + + it("should return false when origin is empty string", () => { + expect(isOriginAuthorized("")).toBe(false); + }); + + it("should return true for exact match", () => { + expect(isOriginAuthorized("https://example.com")).toBe(true); + }); + + it("should return true for wildcard match", () => { + expect(isOriginAuthorized("https://sub.agency.gov")).toBe(true); + }); + + it("should return false for unauthorized origin", () => { + expect(isOriginAuthorized("https://malicious.com")).toBe(false); + }); + + it("should return false when no patterns are configured", () => { + delete process.env.CHAT_AUTHORIZED_URLS; + expect(isOriginAuthorized("https://example.com")).toBe(false); + }); + }); +}); diff --git a/apps/www/public/wafir.yaml b/apps/www/public/wafir.yaml index 5966ca4..ba04e11 100644 --- a/apps/www/public/wafir.yaml +++ b/apps/www/public/wafir.yaml @@ -124,3 +124,8 @@ forms: type: markdown attributes: value: "Please ask your question in our [GitHub Discussions forum](https://github.com/BPS-Consulting/wafir/discussions)." + - id: chat + type: chat + attributes: + label: "Chat with us" + placeholder: "Type your message here..." diff --git a/packages/wafir/src/api/client.ts b/packages/wafir/src/api/client.ts index 64ade5f..4c5888c 100644 --- a/packages/wafir/src/api/client.ts +++ b/packages/wafir/src/api/client.ts @@ -213,3 +213,35 @@ export const submitIssue = async (params: SubmitIssueParams) => { return response.data; }; + +/** + * Sends a chat message to the Bridge API. + * @param message - The user's message + * @param bridgeUrl - Optional custom bridge URL + * @returns The AI's reply or an error + */ +export const sendChatMessage = async ( + message: string, + bridgeUrl?: string, +): Promise<{ reply?: string; error?: string }> => { + const urlToUse = bridgeUrl || currentBridgeUrl; + + const response = await fetch(`${urlToUse}/chat/`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ message }), + }); + + if (response.status === 403) { + return { error: "not authorized" }; + } + + if (!response.ok) { + return { error: `Chat request failed: ${response.status}` }; + } + + const data = (await response.json()) as { reply?: string; error?: string }; + return data; +}; diff --git a/packages/wafir/src/api/index.ts b/packages/wafir/src/api/index.ts index d7b9bdd..415696f 100644 --- a/packages/wafir/src/api/index.ts +++ b/packages/wafir/src/api/index.ts @@ -4,658 +4,691 @@ */ export interface paths { - "/auth/github": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** - * Initiate GitHub OAuth - * @description Redirects to GitHub OAuth for user authorization - */ - get: { - parameters: { - query: { - installationId: string; - returnUrl?: string; + "/auth/github": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; + /** + * Initiate GitHub OAuth + * @description Redirects to GitHub OAuth for user authorization + */ + get: { + parameters: { + query: { + installationId: string; + returnUrl?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; }; - }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/auth/github/callback": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** - * GitHub OAuth Callback - * @description Handles OAuth callback from GitHub - */ - get: { - parameters: { - query: { - code: string; - state: string; + "/auth/github/callback": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; + /** + * GitHub OAuth Callback + * @description Handles OAuth callback from GitHub + */ + get: { + parameters: { + query: { + code: string; + state: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; }; - }; - }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/auth/status/{installationId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - /** - * Check Auth Status - * @description Check if user token exists for installation - */ - get: { - parameters: { - query?: never; - header?: never; - path: { - installationId: string; + "/auth/status/{installationId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - connected?: boolean; - installationId?: number; + /** + * Check Auth Status + * @description Check if user token exists for installation + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + installationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + connected?: boolean; + installationId?: number; + }; + }; + }; }; - }; }; - }; - }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/auth/{installationId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - get?: never; - put?: never; - post?: never; - /** - * Disconnect Auth - * @description Remove stored user token for installation - */ - delete: { - parameters: { - query?: never; - header?: never; - path: { - installationId: string; + "/auth/{installationId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; + get?: never; + put?: never; + post?: never; + /** + * Disconnect Auth + * @description Remove stored user token for installation + */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + installationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; }; - }; - }; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/config/": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - /** - * Get WAFIR Configuration - * @description Fetches and parses a wafir configuration file from a user-provided URL. The URL should point to a raw YAML or JSON configuration file. - */ - get: { - parameters: { - query: { - /** @description URL to the raw configuration file (YAML or JSON format) */ - configUrl: string; + "/chat/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - /** - * @description Modal title - * @default Contact Us - */ - title: string; - /** @description Target destinations for form submissions. Each target defines where and how submissions are stored. */ - targets: { - /** @description Unique identifier for this target, referenced by forms to route submissions. */ - id: string; - /** - * @description Target type using MIME-type convention. Currently supported: github/issues, github/project. - * @enum {string} - */ - type: "github/issues" | "github/project"; - /** @description Target identifier. Format depends on type: 'owner/repo' for github/issues, 'owner/projectNum' for github/project. */ - target: string; - /** @description Authentication reference used to authorize communication with the target. For GitHub types, this is the installation ID. */ - authRef: string; - }[]; - /** @description Automatic data collection settings */ - telemetry?: { - /** - * @description Enable screenshot capture - * @default true - */ - screenshot: boolean; - /** - * @description Collect URL, user agent, viewport, language - * @default true - */ - browserInfo: boolean; - /** - * @description Capture console messages - * @default false - */ - consoleLog: boolean; - }; - /** @description Widget forms configuration. Forms are displayed as tabs in the UI. Defaults to feedback, suggestion, issue if omitted. */ - forms?: { - /** @description Unique form identifier */ - id: string; - /** @description Display label (defaults to capitalized id) */ - label?: string; - /** @description Form icon (displayed in tab UI). Can be any unicode character or emoji. Examples: 'πŸ‘', 'πŸ’‘', '🐞', '⭐', 'πŸ˜€'. */ - icon?: string; - /** @description Form body (fields) for this form. If omitted, defaults are used for known form IDs. */ - body?: { - /** - * @description Field input type. Matches GitHub Form Schema types plus Wafir extensions. - * @enum {string} - */ - type: - | "input" - | "email" - | "textarea" - | "dropdown" - | "checkboxes" - | "markdown" - | "rating" - | "date"; - /** @description Unique identifier for the field (used as key in JSON output/issue body). */ - id?: string; - /** - * @description Controls field visibility. 'none' hides the field from the UI but still includes its value in submissions. Defaults to 'visible'. - * @default visible - * @enum {string} - */ - display: "visible" | "none"; - /** @description Visual and behavioral attributes for the field. */ - attributes?: { - /** @description Display label for the field. */ - label?: string; - /** @description Helper text displayed below the label. */ - description?: string; - /** @description Placeholder text (input, textarea, email only). */ - placeholder?: string; - /** @description Default value or the Markdown content (markdown type). */ - value?: string; - /** @description Syntax highlighting style for textarea (e.g., 'shell', 'javascript'). */ - render?: string; - /** @description Allow multiple selections (dropdown type only). */ - multiple?: boolean; - /** @description Index of the pre-selected option in the options array (dropdown type only). */ - default?: number; - /** @description Options for dropdown, checkboxes, or rating fields. */ - options?: - | string[] - | { - label: string; - required?: boolean; - }[]; - /** @description Unicode character/emoji used as the rating icon (rating type only). Defaults to ⭐. */ - icon?: string; - /** - * @description Auto-fill the field with telemetry data. When specified, renders an opt-in checkbox. Values: browserInfo (URL, user agent, viewport), screenshot (captured screenshot), consoleLog (recent console messages). - * @enum {string} - */ - autofill?: "browserInfo" | "screenshot" | "consoleLog"; - }; - validations?: { - /** @description Whether the field is required. */ - required?: boolean; - }; - }[]; - /** @description IDs of target(s) for this form. If omitted, all targets will be used. If an empty array ([]), no target is selectable and submissions will be disabled for this form (submissionless). Each ID must reference a valid target from the top-level targets array. */ - targets?: string[]; - /** @description Labels automatically added to issues created from this form. Similar to GitHub issue form templates. */ - labels?: string[]; - /** - * Format: uri - * @description URL to a GitHub issue form template YAML file. When provided, the form fields will be fetched from this template. - */ - templateUrl?: string; - }[]; - /** @description Available issue types from the organization (auto-populated) */ - issueTypes?: { - id?: number; - name?: string; - color?: string; - }[]; + get?: never; + put?: never; + /** + * Send a chat message + * @description Sends a message to the AI chat service and returns a response. Only authorized origins can use this endpoint. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - }; - }; - /** @description Default Response */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; + requestBody: { + content: { + "application/json": { + /** @description The user's message to send to the chat service */ + message: string; + }; + }; }; - }; - }; - /** @description Default Response */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description The AI's response */ + reply?: string; + }; + }; + }; + /** @description Default Response */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error message for unauthorized access */ + error?: string; + }; + }; + }; }; - }; }; - }; - }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/config/template": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - /** - * Get GitHub Issue Form Template - * @description Fetches and parses a GitHub Issue Form template from a user-provided URL. Returns the body (fields) and labels from the template. - */ - get: { - parameters: { - query: { - /** @description URL to the raw template file (YAML format) */ - templateUrl: string; + "/config/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - /** @description Array of form fields from the template */ - body: { - [key: string]: unknown; - }[]; - /** @description Labels from the template */ - labels?: string[]; + /** + * Get WAFIR Configuration + * @description Fetches and parses a wafir configuration file from a user-provided URL. The URL should point to a raw YAML or JSON configuration file. + */ + get: { + parameters: { + query: { + /** @description URL to the raw configuration file (YAML or JSON format) */ + configUrl: string; + }; + header?: never; + path?: never; + cookie?: never; }; - }; - }; - /** @description Default Response */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description Modal title + * @default Contact Us + */ + title: string; + /** @description Target destinations for form submissions. Each target defines where and how submissions are stored. */ + targets: { + /** @description Unique identifier for this target, referenced by forms to route submissions. */ + id: string; + /** + * @description Target type using MIME-type convention. Currently supported: github/issues, github/project. + * @enum {string} + */ + type: "github/issues" | "github/project"; + /** @description Target identifier. Format depends on type: 'owner/repo' for github/issues, 'owner/projectNum' for github/project. */ + target: string; + /** @description Authentication reference used to authorize communication with the target. For GitHub types, this is the installation ID. */ + authRef: string; + }[]; + /** @description Widget forms configuration. Forms are displayed as tabs in the UI. Defaults to feedback, suggestion, issue if omitted. */ + forms?: { + /** @description Unique form identifier */ + id: string; + /** @description Display label (defaults to capitalized id) */ + label?: string; + /** @description Form icon (displayed in tab UI). Can be any unicode character or emoji. Examples: 'πŸ‘', 'πŸ’‘', '🐞', '⭐', 'πŸ˜€'. */ + icon?: string; + /** @description Form body (fields) for this form. If omitted, defaults are used for known form IDs. */ + body?: { + /** + * @description Field input type. Matches GitHub Form Schema types plus Wafir extensions. + * @enum {string} + */ + type: "input" | "email" | "textarea" | "dropdown" | "checkboxes" | "markdown" | "rating" | "date" | "chat"; + /** @description Unique identifier for the field (used as key in JSON output/issue body). */ + id?: string; + /** + * @description Controls field visibility. 'none' hides the field from the UI but still includes its value in submissions. Defaults to 'visible'. + * @default visible + * @enum {string} + */ + display: "visible" | "none"; + /** @description Visual and behavioral attributes for the field. */ + attributes?: { + /** @description Display label for the field. */ + label?: string; + /** @description Helper text displayed below the label. */ + description?: string; + /** @description Placeholder text (input, textarea, email only). */ + placeholder?: string; + /** @description Default value or the Markdown content (markdown type). */ + value?: string; + /** @description Syntax highlighting style for textarea (e.g., 'shell', 'javascript'). */ + render?: string; + /** @description Allow multiple selections (dropdown type only). */ + multiple?: boolean; + /** @description Index of the pre-selected option in the options array (dropdown type only). */ + default?: number; + /** @description Options for dropdown, checkboxes, or rating fields. */ + options?: string[] | { + label: string; + required?: boolean; + }[]; + /** @description Unicode character/emoji used as the rating icon (rating type only). Defaults to ⭐. */ + icon?: string; + /** + * @description Auto-fill the field with telemetry data. When specified, renders an opt-in checkbox. Values: browserInfo (URL, user agent, viewport), screenshot (captured screenshot), consoleLog (recent console messages). + * @enum {string} + */ + autofill?: "browserInfo" | "screenshot" | "consoleLog"; + }; + validations?: { + /** @description Whether the field is required. */ + required?: boolean; + }; + }[]; + /** @description IDs of target(s) for this form. If omitted, all targets will be used. If an empty array ([]), no target is selectable and submissions will be disabled for this form (submissionless). Each ID must reference a valid target from the top-level targets array. */ + targets?: string[]; + /** @description Labels automatically added to issues created from this form. Similar to GitHub issue form templates. */ + labels?: string[]; + /** + * Format: uri + * @description URL to a GitHub issue form template YAML file. When provided, the form fields will be fetched from this template. + */ + templateUrl?: string; + }[]; + /** @description Available issue types from the organization (auto-populated) */ + issueTypes?: { + id?: number; + name?: string; + color?: string; + }[]; + }; + }; + }; + /** @description Default Response */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; + }; + }; + }; + /** @description Default Response */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; + }; + }; + }; }; - }; }; - /** @description Default Response */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/config/template": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get GitHub Issue Form Template + * @description Fetches and parses a GitHub Issue Form template from a user-provided URL. Returns the body (fields) and labels from the template. + */ + get: { + parameters: { + query: { + /** @description URL to the raw template file (YAML format) */ + templateUrl: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Array of form fields from the template */ + body: { + [key: string]: unknown; + }[]; + /** @description Labels from the template */ + labels?: string[]; + }; + }; + }; + /** @description Default Response */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; + }; + }; + }; + /** @description Default Response */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; + }; + }; + }; }; - }; }; - }; - }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/generate/": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - get?: never; - put?: never; - /** - * Generate Sample Config - * @description Generates a sample wafir.yaml configuration file based on GitHub repository labels and project fields. Provide your installation ID and an array of targets to analyze. Returns the config as plain text YAML. - */ - post: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - /** @description Your GitHub App installation ID */ - installationId: number; - /** @description Array of targets to analyze */ - targets: { - /** - * @description Target type - * @enum {string} - */ - type: "github/issues" | "github/project"; - /** @description Target identifier: "owner/repo" for issues, "owner/projectNumber" for projects */ - target: string; - }[]; - }; + "/generate/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - }; - responses: { - /** @description Generated wafir.yaml configuration content */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": string; - }; - }; - /** @description Default Response */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; + get?: never; + put?: never; + /** + * Generate Sample Config + * @description Generates a sample wafir.yaml configuration file based on GitHub repository labels and project fields. Provide your installation ID and an array of targets to analyze. Returns the config as plain text YAML. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - }; - }; - /** @description Default Response */ - 500: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; + requestBody: { + content: { + "application/json": { + /** @description Your GitHub App installation ID */ + installationId: number; + /** @description Array of targets to analyze */ + targets: { + /** + * @description Target type + * @enum {string} + */ + type: "github/issues" | "github/project"; + /** @description Target identifier: "owner/repo" for issues, "owner/projectNumber" for projects */ + target: string; + }[]; + }; + }; + }; + responses: { + /** @description Generated wafir.yaml configuration content */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": string; + }; + }; + /** @description Default Response */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; + }; + }; + }; + /** @description Default Response */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; + }; + }; + }; }; - }; }; - }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/health/": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** - * Health Check - * @description Returns the health status of the bridge service - */ - get: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - status?: string; - timestamp?: string; + "/health/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Health Check + * @description Returns the health status of the bridge service + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + status?: string; + timestamp?: string; + }; + }; + }; }; - }; }; - }; - }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/notifications/": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - get?: never; - put?: never; - /** - * Store Notification - * @description Accepts a JSON payload and stores it in S3 in the notifications folder. - */ - post: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: { - content: { - "application/json": { - [key: string]: unknown; - }; + "/notifications/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - }; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - success?: boolean; - filename?: string; - message?: string; + get?: never; + put?: never; + /** + * Store Notification + * @description Accepts a JSON payload and stores it in S3 in the notifications folder. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - }; - }; - /** @description Default Response */ - 500: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; + requestBody?: { + content: { + "application/json": { + [key: string]: unknown; + }; + }; + }; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + success?: boolean; + filename?: string; + message?: string; + }; + }; + }; + /** @description Default Response */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; + }; + }; + }; }; - }; }; - }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/submit/": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - /** - * Submit Feedback/Issue - * @description Creates a GitHub issue or project draft from form fields. Supports multipart/form-data. - */ - post: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; + "/submit/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit Feedback/Issue + * @description Creates a GitHub issue or project draft from form fields. Supports multipart/form-data. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; }; - }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; } export type webhooks = Record; export interface components { - schemas: never; - responses: never; - parameters: never; - requestBodies: never; - headers: never; - pathItems: never; + schemas: never; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; } export type $defs = Record; export type operations = Record; diff --git a/packages/wafir/src/default-config.ts b/packages/wafir/src/default-config.ts index 31a2024..5ac5c48 100644 --- a/packages/wafir/src/default-config.ts +++ b/packages/wafir/src/default-config.ts @@ -138,11 +138,6 @@ export function getDefaultConfig(): WafirConfig { authRef: "0", }, ], - telemetry: { - screenshot: true, - browserInfo: true, - consoleLog: false, - }, forms: DEFAULT_FORMS, }; } diff --git a/packages/wafir/src/index.ts b/packages/wafir/src/index.ts index 2cb6a97..3fe1656 100644 --- a/packages/wafir/src/index.ts +++ b/packages/wafir/src/index.ts @@ -1,6 +1,7 @@ import "./wafir-widget.js"; import "./wafir-form.js"; import "./wafir-highlighter.js"; +import "./wafir-chat-field.js"; import type { WafirWidget } from "./wafir-widget.js"; import type { WafirWidgetAPI, @@ -13,6 +14,7 @@ export type { WafirWidgetOpenOptions, } from "./api-interface.js"; export type { WafirWidget } from "./wafir-widget.js"; +export type { WafirChatField } from "./wafir-chat-field.js"; /** * Queue for open requests that occur before the widget is ready diff --git a/packages/wafir/src/styles/wafir-chat-field.css b/packages/wafir/src/styles/wafir-chat-field.css new file mode 100644 index 0000000..eec5f98 --- /dev/null +++ b/packages/wafir/src/styles/wafir-chat-field.css @@ -0,0 +1,187 @@ +/* Wafir Chat Field Component Styles */ + +@import "./reset.css"; + +:host { + display: block; + color: var(--wafir-form-text-color, #374151); + background-color: var(--wafir-form-bg, transparent); + line-height: 1.5; +} + +.chat-container { + display: flex; + flex-direction: column; + height: 300px; + border: 1px solid var(--wafir-form-border-color, #d1d5db); + border-radius: var(--wafir-form-border-radius, 6px); + overflow: hidden; + background: var(--wafir-form-input-bg, #ffffff); +} + +.chat-messages { + flex: 1; + overflow-y: auto; + padding: 12px; + display: flex; + flex-direction: column; + gap: 12px; +} + +.chat-message { + max-width: 85%; + padding: 10px 14px; + border-radius: 12px; + font-size: 14px; + line-height: 1.4; + word-wrap: break-word; +} + +.chat-message.user { + align-self: flex-end; + background: var(--wafir-form-primary-color, #2563eb); + color: white; + border-bottom-right-radius: 4px; +} + +.chat-message.assistant { + align-self: flex-start; + background: var(--wafir-form-bg-secondary, #f3f4f6); + color: var(--wafir-form-text-color, #374151); + border-bottom-left-radius: 4px; +} + +.chat-message.error { + align-self: center; + background: var(--wafir-error-bg, #fef2f2); + color: var(--wafir-error-color, #dc2626); + border: 1px solid var(--wafir-error-border, #fecaca); + text-align: center; + max-width: 100%; +} + +.chat-input-container { + display: flex; + gap: 8px; + padding: 12px; + border-top: 1px solid var(--wafir-form-border-color, #d1d5db); + background: var(--wafir-form-bg-tertiary, #f9fafb); +} + +.chat-input { + flex: 1; + padding: var(--wafir-form-input-padding, 10px 12px); + border: 1px solid var(--wafir-form-border-color, #d1d5db); + border-radius: var(--wafir-form-border-radius, 6px); + font-size: 14px; + font-family: inherit; + color: var(--wafir-form-input-color, #111827); + background-color: var(--wafir-form-input-bg, #ffffff); + resize: none; + min-height: 40px; + max-height: 100px; +} + +.chat-input:focus { + outline: none; + border-color: var(--wafir-form-primary-color, #2563eb); + box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1); +} + +.chat-input:disabled { + background: var(--wafir-form-bg-secondary, #f3f4f6); + color: var(--wafir-form-text-secondary, #6b7280); + cursor: not-allowed; +} + +.chat-send-button { + padding: 10px 16px; + background: var(--wafir-form-primary-color, #2563eb); + color: white; + border: none; + border-radius: var(--wafir-form-border-radius, 6px); + font-size: 14px; + font-weight: 500; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.2s ease; +} + +.chat-send-button:hover:not(:disabled) { + background: var(--wafir-form-primary-hover, #1d4ed8); +} + +.chat-send-button:disabled { + background: var(--wafir-form-disabled-color, #9ca3af); + cursor: not-allowed; +} + +.chat-loading { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 14px; + color: var(--wafir-form-text-secondary, #6b7280); + font-size: 14px; +} + +.chat-loading .spinner { + display: inline-block; + width: 14px; + height: 14px; + border: 2px solid var(--wafir-form-border-color, #d1d5db); + border-top-color: var(--wafir-form-primary-color, #2563eb); + border-radius: 50%; + animation: spin 0.8s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +.chat-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + color: var(--wafir-form-text-secondary, #6b7280); + font-size: 14px; + text-align: center; + padding: 20px; +} + +.chat-empty-icon { + font-size: 32px; + margin-bottom: 8px; + opacity: 0.5; +} + +/* Not authorized state */ +.chat-not-authorized { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 300px; + padding: 24px; + text-align: center; + background: var(--wafir-form-bg-secondary, #f3f4f6); + border: 1px solid var(--wafir-form-border-color, #d1d5db); + border-radius: var(--wafir-form-border-radius, 6px); +} + +.chat-not-authorized-icon { + font-size: 48px; + margin-bottom: 12px; + opacity: 0.5; +} + +.chat-not-authorized-message { + color: var(--wafir-form-text-secondary, #6b7280); + font-size: 14px; +} diff --git a/packages/wafir/src/wafir-chat-field.ts b/packages/wafir/src/wafir-chat-field.ts new file mode 100644 index 0000000..fed1f20 --- /dev/null +++ b/packages/wafir/src/wafir-chat-field.ts @@ -0,0 +1,238 @@ +// Copyright (c) BPS-Consulting. Licensed under the AGPLv3 License. +import { LitElement, html, unsafeCSS } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; +import chatFieldStyles from "./styles/wafir-chat-field.css?inline"; + +interface ChatMessage { + role: "user" | "assistant" | "error"; + content: string; +} + +/** + * A chat field component that connects to a chat service via REST API. + * Renders an interactive chat interface with message history. + */ +@customElement("wafir-chat-field") +export class WafirChatField extends LitElement { + /** + * The Bridge API URL for chat requests. + */ + @property({ type: String, attribute: "bridge-url" }) + bridgeUrl = ""; + + /** + * Placeholder text for the input field. + */ + @property({ type: String }) + placeholder = "Type your message..."; + + /** + * Chat messages history. + */ + @state() + private _messages: ChatMessage[] = []; + + /** + * Current input value. + */ + @state() + private _inputValue = ""; + + /** + * Whether a request is in progress. + */ + @state() + private _isLoading = false; + + /** + * Whether the user is authorized to use chat. + */ + @state() + private _isAuthorized = true; + + static styles = [unsafeCSS(chatFieldStyles)]; + + /** + * Gets the effective Bridge URL. + */ + private _getBridgeUrl(): string { + return ( + this.bridgeUrl || + (import.meta as any).env?.VITE_WAFIR_API_URL || + "https://v6hvmahyx2.execute-api.us-east-2.amazonaws.com" + ); + } + + /** + * Sends a message to the chat API. + */ + private async _sendMessage(): Promise { + const message = this._inputValue.trim(); + if (!message || this._isLoading) { + return; + } + + // Add user message to history + this._messages = [...this._messages, { role: "user", content: message }]; + this._inputValue = ""; + this._isLoading = true; + + // Scroll to bottom + this._scrollToBottom(); + + try { + const response = await fetch(`${this._getBridgeUrl()}/chat/`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ message }), + }); + + if (response.status === 403) { + // Not authorized + this._isAuthorized = false; + this._messages = []; // Clear messages + return; + } + + if (!response.ok) { + throw new Error(`Chat request failed: ${response.status}`); + } + + const data = (await response.json()) as { reply: string; error?: string }; + + if (data.error) { + this._messages = [ + ...this._messages, + { role: "error", content: data.error }, + ]; + } else { + this._messages = [ + ...this._messages, + { role: "assistant", content: data.reply }, + ]; + } + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : "Failed to send message"; + this._messages = [ + ...this._messages, + { role: "error", content: errorMessage }, + ]; + } finally { + this._isLoading = false; + this._scrollToBottom(); + } + } + + /** + * Scrolls the message container to the bottom. + */ + private _scrollToBottom(): void { + this.updateComplete.then(() => { + const container = this.shadowRoot?.querySelector(".chat-messages"); + if (container) { + container.scrollTop = container.scrollHeight; + } + }); + } + + /** + * Handles input change. + */ + private _handleInput(e: Event): void { + const target = e.target as HTMLTextAreaElement; + this._inputValue = target.value; + } + + /** + * Handles keydown for sending message with Enter. + */ + private _handleKeydown(e: KeyboardEvent): void { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + this._sendMessage(); + } + } + + /** + * Renders the not authorized state. + */ + private _renderNotAuthorized() { + return html` +
+
πŸ”’
+
+ The configured site is not authorized for chat. +
+
+ `; + } + + /** + * Renders the chat messages. + */ + private _renderMessages() { + if (this._messages.length === 0 && !this._isLoading) { + return html` +
+
πŸ’¬
+
Send a message to start chatting
+
+ `; + } + + return html` + ${this._messages.map( + (msg) => html` +
${msg.content}
+ `, + )} + ${this._isLoading + ? html` +
+ + Thinking... +
+ ` + : ""} + `; + } + + render() { + if (!this._isAuthorized) { + return this._renderNotAuthorized(); + } + + return html` +
+
${this._renderMessages()}
+
+ + +
+
+ `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "wafir-chat-field": WafirChatField; + } +} diff --git a/packages/wafir/src/wafir-form.ts b/packages/wafir/src/wafir-form.ts index 51918f7..55ca6d9 100644 --- a/packages/wafir/src/wafir-form.ts +++ b/packages/wafir/src/wafir-form.ts @@ -2,6 +2,7 @@ import { LitElement, html, unsafeCSS } from "lit"; import formStyles from "./styles/wafir-form.css?inline"; import "./rating"; +import "./wafir-chat-field"; import { RATING_OPTIONS, RATING_ICON } from "./default-config.js"; import { customElement, property } from "lit/decorators.js"; import { StoreController } from "@nanostores/lit"; @@ -600,6 +601,15 @@ export class WafirForm extends LitElement { /> `; + case "chat": + return html` + + `; + case "input": case "email": default: @@ -636,6 +646,10 @@ export class WafirForm extends LitElement { return html`
${this._renderFieldInput(field)}
`; + if (field.type === "chat") + return html`
+ ${this._renderFieldInput(field)} +
`; // Check for autofill attribute on textarea fields const autofill = (field.attributes as any)?.autofill; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1b79775..d58599e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,6 +30,9 @@ importers: apps/bridge: dependencies: + '@aws-sdk/client-bedrock-runtime': + specifier: ^3.1025.0 + version: 3.1025.0 '@aws-sdk/client-s3': specifier: ^3.954.0 version: 3.954.0 @@ -301,6 +304,10 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + '@aws-sdk/client-bedrock-runtime@3.1025.0': + resolution: {integrity: sha512-+ATojo49AZAd9IPHTYiRgv5kiPZcZkgkznENl7lK+Hg0W4RCs48bMjlJDVgN9QKPk3VfQUUPq1KjAtX98ggBtw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/client-s3@3.954.0': resolution: {integrity: sha512-DoeySsljzjuWRzqoETLszHGKKOOWlzuGZh3oAF7TkYRsrwbuYYmttrWomb9koogaF0S5YSPwCMCUbKbpF0lbTA==} engines: {node: '>=18.0.0'} @@ -313,42 +320,86 @@ packages: resolution: {integrity: sha512-5oYO5RP+mvCNXNj8XnF9jZo0EP0LTseYOJVNQYcii1D9DJqzHL3HJWurYh7cXxz7G7eDyvVYA01O9Xpt34TdoA==} engines: {node: '>=18.0.0'} + '@aws-sdk/core@3.973.26': + resolution: {integrity: sha512-A/E6n2W42ruU+sfWk+mMUOyVXbsSgGrY3MJ9/0Az5qUdG67y8I6HYzzoAa+e/lzxxl1uCYmEL6BTMi9ZiZnplQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-env@3.954.0': resolution: {integrity: sha512-2HNkqBjfsvyoRuPAiFh86JBFMFyaCNhL4VyH6XqwTGKZffjG7hdBmzXPy7AT7G3oFh1k/1Zc27v0qxaKoK7mBA==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-env@3.972.24': + resolution: {integrity: sha512-FWg8uFmT6vQM7VuzELzwVo5bzExGaKHdubn0StjgrcU5FvuLExUe+k06kn/40uKv59rYzhez8eFNM4yYE/Yb/w==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-http@3.954.0': resolution: {integrity: sha512-CrWD5300+NE1OYRnSVDxoG7G0b5cLIZb7yp+rNQ5Jq/kqnTmyJXpVAsivq+bQIDaGzPXhadzpAMIoo7K/aHaag==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-http@3.972.26': + resolution: {integrity: sha512-CY4ppZ+qHYqcXqBVi//sdHST1QK3KzOEiLtpLsc9W2k2vfZPKExGaQIsOwcyvjpjUEolotitmd3mUNY56IwDEA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-ini@3.954.0': resolution: {integrity: sha512-WAFD8pVwRSoBsuXcoD+s/hrdsP9Z0PNUedSgkOGExuJVAabpM2cIIMzYNsdHio9XFZUSqHkv8mF5mQXuIZvuzg==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-ini@3.972.28': + resolution: {integrity: sha512-wXYvq3+uQcZV7k+bE4yDXCTBdzWTU9x/nMiKBfzInmv6yYK1veMK0AKvRfRBd72nGWYKcL6AxwiPg9z/pYlgpw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-login@3.954.0': resolution: {integrity: sha512-EYqaBWwdVbVK7prmsmgTWLPptoWREplPkFMFscOpVmseDvf/0IjYNbNLLtfuhy/6L7ZBGI9wat2k4u0MRivvxA==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-login@3.972.28': + resolution: {integrity: sha512-ZSTfO6jqUTCysbdBPtEX5OUR//3rbD0lN7jO3sQeS2Gjr/Y+DT6SbIJ0oT2cemNw3UzKu97sNONd1CwNMthuZQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-node@3.954.0': resolution: {integrity: sha512-UPBjw7Lnly5i+/rES8Z5U+nPaumzEUYOE/wrHkxyH6JjwFWn8w7R07fE5Z5cgYlIq1U1lQ7sxYwB3wHPpQ65Aw==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-node@3.972.29': + resolution: {integrity: sha512-clSzDcvndpFJAggLDnDb36sPdlZYyEs5Zm6zgZjjUhwsJgSWiWKwFIXUVBcbruidNyBdbpOv2tNDL9sX8y3/0g==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-process@3.954.0': resolution: {integrity: sha512-Y1/0O2LgbKM8iIgcVj/GNEQW6p90LVTCOzF2CI1pouoKqxmZ/1F7F66WHoa6XUOfKaCRj/R6nuMR3om9ThaM5A==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-process@3.972.24': + resolution: {integrity: sha512-Q2k/XLrFXhEztPHqj4SLCNID3hEPdlhh1CDLBpNnM+1L8fq7P+yON9/9M1IGN/dA5W45v44ylERfXtDAlmMNmw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-sso@3.954.0': resolution: {integrity: sha512-UXxGfkp/plFRdyidMLvNul5zoLKmHhVQOCrD2OgR/lg9jNqNmJ7abF+Qu8abo902iDkhU21Qj4M398cx6l8Kng==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-sso@3.972.28': + resolution: {integrity: sha512-IoUlmKMLEITFn1SiCTjPfR6KrE799FBo5baWyk/5Ppar2yXZoUdaRqZzJzK6TcJxx450M8m8DbpddRVYlp5R/A==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-web-identity@3.954.0': resolution: {integrity: sha512-XEyf1T08q1tG4zkTS4Dnf1cAQyrJUo/xlvi6XNpqGhY3bOmKUYE2h/K6eITIdytDL9VuCpWYQ6YRcIVtL29E0w==} engines: {node: '>=18.0.0'} + '@aws-sdk/credential-provider-web-identity@3.972.28': + resolution: {integrity: sha512-d+6h0SD8GGERzKe27v5rOzNGKOl0D+l0bWJdqrxH8WSQzHzjsQFIAPgIeOTUwBHVsKKwtSxc91K/SWax6XgswQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/eventstream-handler-node@3.972.12': + resolution: {integrity: sha512-ruyc/MNR6e+cUrGCth7fLQ12RXBZDy/bV06tgqB9Z5n/0SN/C0m6bsQEV8FF9zPI6VSAOaRd0rNgmpYVnGawrQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-bucket-endpoint@3.953.0': resolution: {integrity: sha512-YHVRIOowtGIl/L2WuS83FgRlm31tU0aL1yryWaFtF+AFjA5BIeiFkxIZqaRGxJpJvFEBdohsyq6Ipv5mgWfezg==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-eventstream@3.972.8': + resolution: {integrity: sha512-r+oP+tbCxgqXVC3pu3MUVePgSY0ILMjA+aEwOosS77m3/DRbtvHrHwqvMcw+cjANMeGzJ+i0ar+n77KXpRA8RQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-expect-continue@3.953.0': resolution: {integrity: sha512-BQTVXrypQ0rbb7au/Hk4IS5GaJZlwk6O44Rjk6Kxb0IvGQhSurNTuesFiJx1sLbf+w+T31saPtODcfQQERqhCQ==} engines: {node: '>=18.0.0'} @@ -361,6 +412,10 @@ packages: resolution: {integrity: sha512-jTGhfkONav+r4E6HLOrl5SzBqDmPByUYCkyB/c/3TVb8jX3wAZx8/q9bphKpCh+G5ARi3IdbSisgkZrJYqQ19Q==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-host-header@3.972.8': + resolution: {integrity: sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-location-constraint@3.953.0': resolution: {integrity: sha512-h0urrbteIQEybyIISaJfQLZ/+/lJPRzPWAQT4epvzfgv/4MKZI7K83dK7SfTwAooVKFBHiCMok2Cf0iHDt07Kw==} engines: {node: '>=18.0.0'} @@ -369,10 +424,18 @@ packages: resolution: {integrity: sha512-PlWdVYgcuptkIC0ZKqVUhWNtSHXJSx7U9V8J7dJjRmsXC40X7zpEycvrkzDMJjeTDGcCceYbyYAg/4X1lkcIMw==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-logger@3.972.8': + resolution: {integrity: sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-recursion-detection@3.953.0': resolution: {integrity: sha512-cmIJx0gWeesUKK4YwgE+VQL3mpACr3/J24fbwnc1Z5tntC86b+HQFzU5vsBDw6lLwyD46dBgWdsXFh1jL+ZaFw==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-recursion-detection@3.972.9': + resolution: {integrity: sha512-/Wt5+CT8dpTFQxEJ9iGy/UGrXr7p2wlIOEHvIr/YcHYByzoLjrqkYqXdJjd9UIgWjv7eqV2HnFJen93UTuwfTQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-sdk-s3@3.954.0': resolution: {integrity: sha512-274CNmnRjknmfFb2o0Azxic54fnujaA8AYSeRUOho3lN48TVzx85eAFWj2kLgvUJO88pE3jBDPWboKQiQdXeUQ==} engines: {node: '>=18.0.0'} @@ -385,14 +448,30 @@ packages: resolution: {integrity: sha512-5PX8JDe3dB2+MqXeGIhmgFnm2rbVsSxhz+Xyuu1oxLtbOn+a9UDA+sNBufEBjt3UxWy5qwEEY1fxdbXXayjlGg==} engines: {node: '>=18.0.0'} + '@aws-sdk/middleware-user-agent@3.972.28': + resolution: {integrity: sha512-cfWZFlVh7Va9lRay4PN2A9ARFzaBYcA097InT5M2CdRS05ECF5yaz86jET8Wsl2WcyKYEvVr/QNmKtYtafUHtQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-websocket@3.972.14': + resolution: {integrity: sha512-qnfDlIHjm6DrTYNvWOUbnZdVKgtoKbO/Qzj+C0Wp5Y7VUrsvBRQtGKxD+hc+mRTS4N0kBJ6iZ3+zxm4N1OSyjg==} + engines: {node: '>= 14.0.0'} + '@aws-sdk/nested-clients@3.954.0': resolution: {integrity: sha512-JLUhf35fTQIDPLk6G5KPggL9tV//Hjhy6+N2zZeis76LuBRNhKDq8z1CFyKhjf00vXi/tDYdn9D7y9emI+5Y/g==} engines: {node: '>=18.0.0'} + '@aws-sdk/nested-clients@3.996.18': + resolution: {integrity: sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/region-config-resolver@3.953.0': resolution: {integrity: sha512-5MJgnsc+HLO+le0EK1cy92yrC7kyhGZSpaq8PcQvKs9qtXCXT5Tb6tMdkr5Y07JxYsYOV1omWBynvL6PWh08tQ==} engines: {node: '>=18.0.0'} + '@aws-sdk/region-config-resolver@3.972.10': + resolution: {integrity: sha512-1dq9ToC6e070QvnVhhbAs3bb5r6cQ10gTVc6cyRV5uvQe7P138TV2uG2i6+Yok4bAkVAcx5AqkTEBUvWEtBlsQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/s3-request-presigner@3.954.0': resolution: {integrity: sha512-ypFOt8JK/x6p2hD9Jd5ctStw8h32KdgSBV+eXAMvcMP4DFt7wp6f7StwbjAblehZnPwNolFJE4Hz2F08nh4VdA==} engines: {node: '>=18.0.0'} @@ -401,6 +480,14 @@ packages: resolution: {integrity: sha512-GJJbUaSlGrMSRWui3Oz8ByygpQlzDGm195yTKirgGyu4tfYrFr/QWrWT42EUktY/L4Irev1pdHTuLS+AGHO1gw==} engines: {node: '>=18.0.0'} + '@aws-sdk/token-providers@3.1021.0': + resolution: {integrity: sha512-TKY6h9spUk3OLs5v1oAgW9mAeBE3LAGNBwJokLy96wwmd4W2v/tYlXseProyed9ValDj2u1jK/4Rg1T+1NXyJA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1025.0': + resolution: {integrity: sha512-sbEnN8VbDFCmf1NbGHpWDQ9llwOYkPeEs8NLZ2+uYO7l97s+x6X58XTnM6XG/DBe9LZm5ddObvsK1CVlW2N4hg==} + engines: {node: '>=20.0.0'} + '@aws-sdk/token-providers@3.954.0': resolution: {integrity: sha512-rDyN3oQQKMOJgyQ9/LNbh4fAGAj8ePMGOAQzSP/kyzizmViI6STpBW1o/VRqiTgMNi1bvA9ZasDtfrJqcVt0iA==} engines: {node: '>=18.0.0'} @@ -409,6 +496,10 @@ packages: resolution: {integrity: sha512-M9Iwg9kTyqTErI0vOTVVpcnTHWzS3VplQppy8MuL02EE+mJ0BIwpWfsaAPQW+/XnVpdNpWZTsHcNE29f1+hR8g==} engines: {node: '>=18.0.0'} + '@aws-sdk/types@3.973.6': + resolution: {integrity: sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/util-arn-parser@3.953.0': resolution: {integrity: sha512-9hqdKkn4OvYzzaLryq2xnwcrPc8ziY34i9szUdgBfSqEC6pBxbY9/lLXmrgzfwMSL2Z7/v2go4Od0p5eukKLMQ==} engines: {node: '>=18.0.0'} @@ -417,10 +508,18 @@ packages: resolution: {integrity: sha512-rjaS6jrFksopXvNg6YeN+D1lYwhcByORNlFuYesFvaQNtPOufbE5tJL4GJ3TMXyaY0uFR28N5BHHITPyWWfH/g==} engines: {node: '>=18.0.0'} + '@aws-sdk/util-endpoints@3.996.5': + resolution: {integrity: sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/util-format-url@3.953.0': resolution: {integrity: sha512-fs70vtTiBhp/T9ss52OuW2LGJqPoNBbd1+wxqh82CMdzkOvCzI3qa/cK8tR0jCFeIjGeiV74lAskImRxu/V4lg==} engines: {node: '>=18.0.0'} + '@aws-sdk/util-format-url@3.972.8': + resolution: {integrity: sha512-J6DS9oocrgxM8xlUTTmQOuwRF6rnAGEujAN9SAzllcrQmwn5iJ58ogxy3SEhD0Q7JZvlA5jvIXBkpQRqEqlE9A==} + engines: {node: '>=20.0.0'} + '@aws-sdk/util-locate-window@3.953.0': resolution: {integrity: sha512-mPxK+I1LcrgC/RSa3G5AMAn8eN2Ay0VOgw8lSRmV1jCtO+iYvNeCqOdxoJUjOW6I5BA4niIRWqVORuRP07776Q==} engines: {node: '>=18.0.0'} @@ -428,6 +527,9 @@ packages: '@aws-sdk/util-user-agent-browser@3.953.0': resolution: {integrity: sha512-UF5NeqYesWuFao+u7LJvpV1SJCaLml5BtFZKUdTnNNMeN6jvV+dW/eQoFGpXF94RCqguX0XESmRuRRPQp+/rzQ==} + '@aws-sdk/util-user-agent-browser@3.972.8': + resolution: {integrity: sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA==} + '@aws-sdk/util-user-agent-node@3.954.0': resolution: {integrity: sha512-fB5S5VOu7OFkeNzcblQlez4AjO5hgDFaa7phYt7716YWisY3RjAaQPlxgv+G3GltHHDJIfzEC5aRxdf62B9zMg==} engines: {node: '>=18.0.0'} @@ -437,10 +539,23 @@ packages: aws-crt: optional: true + '@aws-sdk/util-user-agent-node@3.973.14': + resolution: {integrity: sha512-vNSB/DYaPOyujVZBg/zUznH9QC142MaTHVmaFlF7uzzfg3CgT9f/l4C0Yi+vU/tbBhxVcXVB90Oohk5+o+ZbWw==} + engines: {node: '>=20.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + '@aws-sdk/xml-builder@3.953.0': resolution: {integrity: sha512-Zmrj21jQ2OeOJGr9spPiN00aQvXa/WUqRXcTVENhrMt+OFoSOfDFpYhUj9NQ09QmQ8KMWFoWuWW6iKurNqLvAA==} engines: {node: '>=18.0.0'} + '@aws-sdk/xml-builder@3.972.16': + resolution: {integrity: sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A==} + engines: {node: '>=20.0.0'} + '@aws/lambda-invoke-store@0.2.2': resolution: {integrity: sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg==} engines: {node: '>=18.0.0'} @@ -1485,6 +1600,10 @@ packages: resolution: {integrity: sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==} engines: {node: '>=18.0.0'} + '@smithy/config-resolver@4.4.14': + resolution: {integrity: sha512-N55f8mPEccpzKetUagdvmAy8oohf0J5cuj9jLI1TaSceRlq0pJsIZepY3kmAXAhyxqXPV6hDerDQhqQPKWgAoQ==} + engines: {node: '>=18.0.0'} + '@smithy/config-resolver@4.4.4': resolution: {integrity: sha512-s3U5ChS21DwU54kMmZ0UJumoS5cg0+rGVZvN6f5Lp6EbAVi0ZyP+qDSHdewfmXKUgNK1j3z45JyzulkDukrjAA==} engines: {node: '>=18.0.0'} @@ -1493,30 +1612,62 @@ packages: resolution: {integrity: sha512-Y9oHXpBcXQgYHOcAEmxjkDilUbSTkgKjoHYed3WaYUH8jngq8lPWDBSpjHblJ9uOgBdy5mh3pzebrScDdYr29w==} engines: {node: '>=18.0.0'} + '@smithy/core@3.23.14': + resolution: {integrity: sha512-vJ0IhpZxZAkFYOegMKSrxw7ujhhT2pass/1UEcZ4kfl5srTAqtPU5I7MdYQoreVas3204ykCiNhY1o7Xlz6Yyg==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.2.13': + resolution: {integrity: sha512-wboCPijzf6RJKLOvnjDAiBxGSmSnGXj35o5ZAWKDaHa/cvQ5U3ZJ13D4tMCE8JG4dxVAZFy/P0x/V9CwwdfULQ==} + engines: {node: '>=18.0.0'} + '@smithy/credential-provider-imds@4.2.6': resolution: {integrity: sha512-xBmawExyTzOjbhzkZwg+vVm/khg28kG+rj2sbGlULjFd1jI70sv/cbpaR0Ev4Yfd6CpDUDRMe64cTqR//wAOyA==} engines: {node: '>=18.0.0'} + '@smithy/eventstream-codec@4.2.13': + resolution: {integrity: sha512-vYahwBAtRaAcFbOmE9aLr12z7RiHYDSLcnogSdxfm7kKfsNa3wH+NU5r7vTeB5rKvLsWyPjVX8iH94brP7umiQ==} + engines: {node: '>=18.0.0'} + '@smithy/eventstream-codec@4.2.6': resolution: {integrity: sha512-OZfsI+YRG26XZik/jKMMg37acnBSbUiK/8nETW3uM3mLj+0tMmFXdHQw1e5WEd/IHN8BGOh3te91SNDe2o4RHg==} engines: {node: '>=18.0.0'} + '@smithy/eventstream-serde-browser@4.2.13': + resolution: {integrity: sha512-wwybfcOX0tLqCcBP378TIU9IqrDuZq/tDV48LlZNydMpCnqnYr+hWBAYbRE+rFFf/p7IkDJySM3bgiMKP2ihPg==} + engines: {node: '>=18.0.0'} + '@smithy/eventstream-serde-browser@4.2.6': resolution: {integrity: sha512-6OiaAaEbLB6dEkRbQyNzFSJv5HDvly3Mc6q/qcPd2uS/g3szR8wAIkh7UndAFKfMypNSTuZ6eCBmgCLR5LacTg==} engines: {node: '>=18.0.0'} + '@smithy/eventstream-serde-config-resolver@4.3.13': + resolution: {integrity: sha512-ied1lO559PtAsMJzg2TKRlctLnEi1PfkNeMMpdwXDImk1zV9uvS/Oxoy/vcy9uv1GKZAjDAB5xT6ziE9fzm5wA==} + engines: {node: '>=18.0.0'} + '@smithy/eventstream-serde-config-resolver@4.3.6': resolution: {integrity: sha512-xP5YXbOVRVN8A4pDnSUkEUsL9fYFU6VNhxo8tgr13YnMbf3Pn4xVr+hSyLVjS1Frfi1Uk03ET5Bwml4+0CeYEw==} engines: {node: '>=18.0.0'} + '@smithy/eventstream-serde-node@4.2.13': + resolution: {integrity: sha512-hFyK+ORJrxAN3RYoaD6+gsGDQjeix8HOEkosoajvXYZ4VeqonM3G4jd9IIRm/sWGXUKmudkY9KdYjzosUqdM8A==} + engines: {node: '>=18.0.0'} + '@smithy/eventstream-serde-node@4.2.6': resolution: {integrity: sha512-jhH7nJuaOpnTFcuZpWK9dqb6Ge2yGi1okTo0W6wkJrfwAm2vwmO74tF1v07JmrSyHBcKLQATEexclJw9K1Vj7w==} engines: {node: '>=18.0.0'} + '@smithy/eventstream-serde-universal@4.2.13': + resolution: {integrity: sha512-kRrq4EKLGeOxhC2CBEhRNcu1KSzNJzYY7RK3S7CxMPgB5dRrv55WqQOtRwQxQLC04xqORFLUgnDlc6xrNUULaA==} + engines: {node: '>=18.0.0'} + '@smithy/eventstream-serde-universal@4.2.6': resolution: {integrity: sha512-olIfZ230B64TvPD6b0tPvrEp2eB0FkyL3KvDlqF4RVmIc/kn3orzXnV6DTQdOOW5UU+M5zKY3/BU47X420/oPw==} engines: {node: '>=18.0.0'} + '@smithy/fetch-http-handler@5.3.16': + resolution: {integrity: sha512-nYDRUIvNd4mFmuXraRWt6w5UsZTNqtj4hXJA/iiOD4tuseIdLP9Lq38teH/SZTcIFCa2f+27o7hYpIsWktJKEQ==} + engines: {node: '>=18.0.0'} + '@smithy/fetch-http-handler@5.3.7': resolution: {integrity: sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ==} engines: {node: '>=18.0.0'} @@ -1525,6 +1676,10 @@ packages: resolution: {integrity: sha512-CIbCTGGX5CI7tfewBPSYD9ycp2Vb2GW5xnXD1n7GcO9mu37EN7A6DvCHM9MX7pOeS1adMn5D+1yRwI3eABVbcA==} engines: {node: '>=18.0.0'} + '@smithy/hash-node@4.2.13': + resolution: {integrity: sha512-4/oy9h0jjmY80a2gOIo75iLl8TOPhmtx4E2Hz+PfMjvx/vLtGY4TMU/35WRyH2JHPfT5CVB38u4JRow7gnmzJA==} + engines: {node: '>=18.0.0'} + '@smithy/hash-node@4.2.6': resolution: {integrity: sha512-k3Dy9VNR37wfMh2/1RHkFf/e0rMyN0pjY0FdyY6ItJRjENYyVPRMwad6ZR1S9HFm6tTuIOd9pqKBmtJ4VHxvxg==} engines: {node: '>=18.0.0'} @@ -1533,6 +1688,10 @@ packages: resolution: {integrity: sha512-+3T8LkH39YIhYHsv/Ec8lF+92nykZpU+XMBvAyXF/uLcTp86pxa5oSJk1vzaRY9N++qgDLYjzJ6OVbtAgDGwfw==} engines: {node: '>=18.0.0'} + '@smithy/invalid-dependency@4.2.13': + resolution: {integrity: sha512-jvC0RB/8BLj2SMIkY0Npl425IdnxZJxInpZJbu563zIRnVjpDMXevU3VMCRSabaLB0kf/eFIOusdGstrLJ8IDg==} + engines: {node: '>=18.0.0'} + '@smithy/invalid-dependency@4.2.6': resolution: {integrity: sha512-E4t/V/q2T46RY21fpfznd1iSLTvCXKNKo4zJ1QuEFN4SE9gKfu2vb6bgq35LpufkQ+SETWIC7ZAf2GGvTlBaMQ==} engines: {node: '>=18.0.0'} @@ -1545,10 +1704,18 @@ packages: resolution: {integrity: sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==} engines: {node: '>=18.0.0'} + '@smithy/is-array-buffer@4.2.2': + resolution: {integrity: sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==} + engines: {node: '>=18.0.0'} + '@smithy/md5-js@4.2.6': resolution: {integrity: sha512-ZXeh8UmH31JdcNsrQ1o9v1IVuva9JFwxIc6zTMxWX7wcmWvVR7Ai9aUEw5LraNKqdkAsb06clpM2sRH4Iy55Sg==} engines: {node: '>=18.0.0'} + '@smithy/middleware-content-length@4.2.13': + resolution: {integrity: sha512-IPMLm/LE4AZwu6qiE8Rr8vJsWhs9AtOdySRXrOM7xnvclp77Tyh7hMs/FRrMf26kgIe67vFJXXOSmVxS7oKeig==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-content-length@4.2.6': resolution: {integrity: sha512-0cjqjyfj+Gls30ntq45SsBtqF3dfJQCeqQPyGz58Pk8OgrAr5YiB7ZvDzjCA94p4r6DCI4qLm7FKobqBjf515w==} engines: {node: '>=18.0.0'} @@ -1557,18 +1724,38 @@ packages: resolution: {integrity: sha512-M6qWfUNny6NFNy8amrCGIb9TfOMUkHVtg9bHtEFGRgfH7A7AtPpn/fcrToGPjVDK1ECuMVvqGQOXcZxmu9K+7A==} engines: {node: '>=18.0.0'} + '@smithy/middleware-endpoint@4.4.29': + resolution: {integrity: sha512-R9Q/58U+qBiSARGWbAbFLczECg/RmysRksX6Q8BaQEpt75I7LI6WGDZnjuC9GXSGKljEbA7N118LhGaMbfrTXw==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-retry@4.4.16': resolution: {integrity: sha512-XPpNhNRzm3vhYm7YCsyw3AtmWggJbg1wNGAoqb7NBYr5XA5isMRv14jgbYyUV6IvbTBFZQdf2QpeW43LrRdStQ==} engines: {node: '>=18.0.0'} + '@smithy/middleware-retry@4.5.0': + resolution: {integrity: sha512-/NzISn4grj/BRFVua/xnQwF+7fakYZgimpw2dfmlPgcqecBMKxpB9g5mLYRrmBD5OrPoODokw4Vi1hrSR4zRyw==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@4.2.17': + resolution: {integrity: sha512-0T2mcaM6v9W1xku86Dk0bEW7aEseG6KenFkPK98XNw0ZhOqOiD1MrMsdnQw9QsL3/Oa85T53iSMlm0SZdSuIEQ==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-serde@4.2.7': resolution: {integrity: sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA==} engines: {node: '>=18.0.0'} + '@smithy/middleware-stack@4.2.13': + resolution: {integrity: sha512-g72jN/sGDLyTanrCLH9fhg3oysO3f7tQa6eWWsMyn2BiYNCgjF24n4/I9wff/5XidFvjj9ilipAoQrurTUrLvw==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-stack@4.2.6': resolution: {integrity: sha512-JSbALU3G+JS4kyBZPqnJ3hxIYwOVRV7r9GNQMS6j5VsQDo5+Es5nddLfr9TQlxZLNHPvKSh+XSB0OuWGfSWFcA==} engines: {node: '>=18.0.0'} + '@smithy/node-config-provider@4.3.13': + resolution: {integrity: sha512-iGxQ04DsKXLckbgnX4ipElrOTk+IHgTyu0q0WssZfYhDm9CQWHmu6cOeI5wmWRxpXbBDhIIfXMWz5tPEtcVqbw==} + engines: {node: '>=18.0.0'} + '@smithy/node-config-provider@4.3.6': resolution: {integrity: sha512-fYEyL59Qe82Ha1p97YQTMEQPJYmBS+ux76foqluaTVWoG9Px5J53w6NvXZNE3wP7lIicLDF7Vj1Em18XTX7fsA==} engines: {node: '>=18.0.0'} @@ -1577,22 +1764,46 @@ packages: resolution: {integrity: sha512-Gsb9jf4ido5BhPfani4ggyrKDd3ZK+vTFWmUaZeFg5G3E5nhFmqiTzAIbHqmPs1sARuJawDiGMGR/nY+Gw6+aQ==} engines: {node: '>=18.0.0'} + '@smithy/node-http-handler@4.5.2': + resolution: {integrity: sha512-/oD7u8M0oj2ZTFw7GkuuHWpIxtWdLlnyNkbrWcyVYhd5RJNDuczdkb0wfnQICyNFrVPlr8YHOhamjNy3zidhmA==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@4.2.13': + resolution: {integrity: sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ==} + engines: {node: '>=18.0.0'} + '@smithy/property-provider@4.2.6': resolution: {integrity: sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA==} engines: {node: '>=18.0.0'} + '@smithy/protocol-http@5.3.13': + resolution: {integrity: sha512-+HsmuJUF4u8POo6s8/a2Yb/AQ5t/YgLovCuHF9oxbocqv+SZ6gd8lC2duBFiCA/vFHoHQhoq7QjqJqZC6xOxxg==} + engines: {node: '>=18.0.0'} + '@smithy/protocol-http@5.3.6': resolution: {integrity: sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ==} engines: {node: '>=18.0.0'} + '@smithy/querystring-builder@4.2.13': + resolution: {integrity: sha512-tG4aOYFCZdPMjbgfhnIQ322H//ojujldp1SrHPHpBSb3NqgUp3dwiUGRJzie87hS1DYwWGqDuPaowoDF+rYCbQ==} + engines: {node: '>=18.0.0'} + '@smithy/querystring-builder@4.2.6': resolution: {integrity: sha512-MeM9fTAiD3HvoInK/aA8mgJaKQDvm8N0dKy6EiFaCfgpovQr4CaOkJC28XqlSRABM+sHdSQXbC8NZ0DShBMHqg==} engines: {node: '>=18.0.0'} + '@smithy/querystring-parser@4.2.13': + resolution: {integrity: sha512-hqW3Q4P+CDzUyQ87GrboGMeD7XYNMOF+CuTwu936UQRB/zeYn3jys8C3w+wMkDfY7CyyyVwZQ5cNFoG0x1pYmA==} + engines: {node: '>=18.0.0'} + '@smithy/querystring-parser@4.2.6': resolution: {integrity: sha512-YmWxl32SQRw/kIRccSOxzS/Ib8/b5/f9ex0r5PR40jRJg8X1wgM3KrR2In+8zvOGVhRSXgvyQpw9yOSlmfmSnA==} engines: {node: '>=18.0.0'} + '@smithy/service-error-classification@4.2.13': + resolution: {integrity: sha512-a0s8XZMfOC/qpqq7RCPvJlk93rWFrElH6O++8WJKz0FqnA4Y7fkNi/0mnGgSH1C4x6MFsuBA8VKu4zxFrMe5Vw==} + engines: {node: '>=18.0.0'} + '@smithy/service-error-classification@4.2.6': resolution: {integrity: sha512-Q73XBrzJlGTut2nf5RglSntHKgAG0+KiTJdO5QQblLfr4TdliGwIAha1iZIjwisc3rA5ulzqwwsYC6xrclxVQg==} engines: {node: '>=18.0.0'} @@ -1601,6 +1812,14 @@ packages: resolution: {integrity: sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA==} engines: {node: '>=18.0.0'} + '@smithy/shared-ini-file-loader@4.4.8': + resolution: {integrity: sha512-VZCZx2bZasxdqxVgEAhREvDSlkatTPnkdWy1+Kiy8w7kYPBosW0V5IeDwzDUMvWBt56zpK658rx1cOBFOYaPaw==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.3.13': + resolution: {integrity: sha512-YpYSyM0vMDwKbHD/JA7bVOF6kToVRpa+FM5ateEVRpsTNu564g1muBlkTubXhSKKYXInhpADF46FPyrZcTLpXg==} + engines: {node: '>=18.0.0'} + '@smithy/signature-v4@5.3.6': resolution: {integrity: sha512-P1TXDHuQMadTMTOBv4oElZMURU4uyEhxhHfn+qOc2iofW9Rd4sZtBGx58Lzk112rIGVEYZT8eUMK4NftpewpRA==} engines: {node: '>=18.0.0'} @@ -1609,10 +1828,22 @@ packages: resolution: {integrity: sha512-1ovWdxzYprhq+mWqiGZlt3kF69LJthuQcfY9BIyHx9MywTFKzFapluku1QXoaBB43GCsLDxNqS+1v30ure69AA==} engines: {node: '>=18.0.0'} + '@smithy/smithy-client@4.12.9': + resolution: {integrity: sha512-ovaLEcTU5olSeHcRXcxV6viaKtpkHZumn6Ps0yn7dRf2rRSfy794vpjOtrWDO0d1auDSvAqxO+lyhERSXQ03EQ==} + engines: {node: '>=18.0.0'} + '@smithy/types@4.10.0': resolution: {integrity: sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ==} engines: {node: '>=18.0.0'} + '@smithy/types@4.14.0': + resolution: {integrity: sha512-OWgntFLW88kx2qvf/c/67Vno1yuXm/f9M7QFAtVkkO29IJXGBIg0ycEaBTH0kvCtwmvZxRujrgP5a86RvsXJAQ==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@4.2.13': + resolution: {integrity: sha512-2G03yoboIRZlZze2+PT4GZEjgwQsJjUgn6iTsvxA02bVceHR6vp4Cuk7TUnPFWKF+ffNUk3kj4COwkENS2K3vw==} + engines: {node: '>=18.0.0'} + '@smithy/url-parser@4.2.6': resolution: {integrity: sha512-tVoyzJ2vXp4R3/aeV4EQjBDmCuWxRa8eo3KybL7Xv4wEM16nObYh7H1sNfcuLWHAAAzb0RVyxUz1S3sGj4X+Tg==} engines: {node: '>=18.0.0'} @@ -1621,14 +1852,26 @@ packages: resolution: {integrity: sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==} engines: {node: '>=18.0.0'} + '@smithy/util-base64@4.3.2': + resolution: {integrity: sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ==} + engines: {node: '>=18.0.0'} + '@smithy/util-body-length-browser@4.2.0': resolution: {integrity: sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==} engines: {node: '>=18.0.0'} + '@smithy/util-body-length-browser@4.2.2': + resolution: {integrity: sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==} + engines: {node: '>=18.0.0'} + '@smithy/util-body-length-node@4.2.1': resolution: {integrity: sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==} engines: {node: '>=18.0.0'} + '@smithy/util-body-length-node@4.2.3': + resolution: {integrity: sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==} + engines: {node: '>=18.0.0'} + '@smithy/util-buffer-from@2.2.0': resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} engines: {node: '>=14.0.0'} @@ -1637,26 +1880,54 @@ packages: resolution: {integrity: sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==} engines: {node: '>=18.0.0'} + '@smithy/util-buffer-from@4.2.2': + resolution: {integrity: sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q==} + engines: {node: '>=18.0.0'} + '@smithy/util-config-provider@4.2.0': resolution: {integrity: sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==} engines: {node: '>=18.0.0'} + '@smithy/util-config-provider@4.2.2': + resolution: {integrity: sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==} + engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-browser@4.3.15': resolution: {integrity: sha512-LiZQVAg/oO8kueX4c+oMls5njaD2cRLXRfcjlTYjhIqmwHnCwkQO5B3dMQH0c5PACILxGAQf6Mxsq7CjlDc76A==} engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-browser@4.3.45': + resolution: {integrity: sha512-ag9sWc6/nWZAuK3Wm9KlFJUnRkXLrXn33RFjIAmCTFThqLHY+7wCst10BGq56FxslsDrjhSie46c8OULS+BiIw==} + engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-node@4.2.18': resolution: {integrity: sha512-Kw2J+KzYm9C9Z9nY6+W0tEnoZOofstVCMTshli9jhQbQCy64rueGfKzPfuFBnVUqZD9JobxTh2DzHmPkp/Va/Q==} engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-node@4.2.49': + resolution: {integrity: sha512-jlN6vHwE8gY5AfiFBavtD3QtCX2f7lM3BKkz7nFKSNfFR5nXLXLg6sqXTJEEyDwtxbztIDBQCfjsGVXlIru2lQ==} + engines: {node: '>=18.0.0'} + '@smithy/util-endpoints@3.2.6': resolution: {integrity: sha512-v60VNM2+mPvgHCBXEfMCYrQ0RepP6u6xvbAkMenfe4Mi872CqNkJzgcnQL837e8NdeDxBgrWQRTluKq5Lqdhfg==} engines: {node: '>=18.0.0'} + '@smithy/util-endpoints@3.3.4': + resolution: {integrity: sha512-BKoR/ubPp9KNKFxPpg1J28N1+bgu8NGAtJblBP7yHy8yQPBWhIAv9+l92SlQLpolGm71CVO+btB60gTgzT0wog==} + engines: {node: '>=18.0.0'} + '@smithy/util-hex-encoding@4.2.0': resolution: {integrity: sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==} engines: {node: '>=18.0.0'} + '@smithy/util-hex-encoding@4.2.2': + resolution: {integrity: sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-middleware@4.2.13': + resolution: {integrity: sha512-GTooyrlmRTqvUen4eK7/K1p6kryF7bnDfq6XsAbIsf2mo51B/utaH+XThY6dKgNCWzMAaH/+OLmqaBuLhLWRow==} + engines: {node: '>=18.0.0'} + '@smithy/util-middleware@4.2.6': resolution: {integrity: sha512-qrvXUkxBSAFomM3/OEMuDVwjh4wtqK8D2uDZPShzIqOylPst6gor2Cdp6+XrH4dyksAWq/bE2aSDYBTTnj0Rxg==} engines: {node: '>=18.0.0'} @@ -1665,6 +1936,14 @@ packages: resolution: {integrity: sha512-x7CeDQLPQ9cb6xN7fRJEjlP9NyGW/YeXWc4j/RUhg4I+H60F0PEeRc2c/z3rm9zmsdiMFzpV/rT+4UHW6KM1SA==} engines: {node: '>=18.0.0'} + '@smithy/util-retry@4.3.0': + resolution: {integrity: sha512-tSOPQNT/4KfbvqeMovWC3g23KSYy8czHd3tlN+tOYVNIDLSfxIsrPJihYi5TpNcoV789KWtgChUVedh2y6dDPg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-stream@4.5.22': + resolution: {integrity: sha512-3H8iq/0BfQjUs2/4fbHZ9aG9yNzcuZs24LPkcX1Q7Z+qpqaGM8+qbGmE8zo9m2nCRgamyvS98cHdcWvR6YUsew==} + engines: {node: '>=18.0.0'} + '@smithy/util-stream@4.5.7': resolution: {integrity: sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A==} engines: {node: '>=18.0.0'} @@ -1673,6 +1952,10 @@ packages: resolution: {integrity: sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==} engines: {node: '>=18.0.0'} + '@smithy/util-uri-escape@4.2.2': + resolution: {integrity: sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==} + engines: {node: '>=18.0.0'} + '@smithy/util-utf8@2.3.0': resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} engines: {node: '>=14.0.0'} @@ -1681,6 +1964,10 @@ packages: resolution: {integrity: sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==} engines: {node: '>=18.0.0'} + '@smithy/util-utf8@4.2.2': + resolution: {integrity: sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==} + engines: {node: '>=18.0.0'} + '@smithy/util-waiter@4.2.6': resolution: {integrity: sha512-xU9HwUSik9UUCJmm530yvBy0AwlQFICveKmqvaaTukKkXEAhyiBdHtSrhPrH3rH+uz0ykyaE3LdgsX86C6mDCQ==} engines: {node: '>=18.0.0'} @@ -1689,6 +1976,10 @@ packages: resolution: {integrity: sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==} engines: {node: '>=18.0.0'} + '@smithy/uuid@1.1.2': + resolution: {integrity: sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==} + engines: {node: '>=18.0.0'} + '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} @@ -2701,10 +2992,17 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-xml-builder@1.1.4: + resolution: {integrity: sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==} + fast-xml-parser@5.2.5: resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} hasBin: true + fast-xml-parser@5.5.8: + resolution: {integrity: sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==} + hasBin: true + fastify-cli@7.4.1: resolution: {integrity: sha512-7Jsfj2uLuGWvnxjrGDrHWpSm65+OcVx0ZbTD2wwkz6Wt6KjGm6+ZYwwpdXdwAlzbJYq+LCEMNvDJc4485AQ1vQ==} hasBin: true @@ -3618,6 +3916,10 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-expression-matcher@1.4.0: + resolution: {integrity: sha512-s4DQMxIdhj3jLFWd9LxHOplj4p9yQ4ffMGowFf3cpEgrrJjEhN0V5nxw4Ye1EViAGDoL4/1AeO6qHpqYPOzE4Q==} + engines: {node: '>=14.0.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -4056,6 +4358,9 @@ packages: strnum@2.1.2: resolution: {integrity: sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==} + strnum@2.2.3: + resolution: {integrity: sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==} + supports-color@10.2.2: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} @@ -4918,6 +5223,58 @@ snapshots: '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 + '@aws-sdk/client-bedrock-runtime@3.1025.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.26 + '@aws-sdk/credential-provider-node': 3.972.29 + '@aws-sdk/eventstream-handler-node': 3.972.12 + '@aws-sdk/middleware-eventstream': 3.972.8 + '@aws-sdk/middleware-host-header': 3.972.8 + '@aws-sdk/middleware-logger': 3.972.8 + '@aws-sdk/middleware-recursion-detection': 3.972.9 + '@aws-sdk/middleware-user-agent': 3.972.28 + '@aws-sdk/middleware-websocket': 3.972.14 + '@aws-sdk/region-config-resolver': 3.972.10 + '@aws-sdk/token-providers': 3.1025.0 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/util-user-agent-browser': 3.972.8 + '@aws-sdk/util-user-agent-node': 3.973.14 + '@smithy/config-resolver': 4.4.14 + '@smithy/core': 3.23.14 + '@smithy/eventstream-serde-browser': 4.2.13 + '@smithy/eventstream-serde-config-resolver': 4.3.13 + '@smithy/eventstream-serde-node': 4.2.13 + '@smithy/fetch-http-handler': 5.3.16 + '@smithy/hash-node': 4.2.13 + '@smithy/invalid-dependency': 4.2.13 + '@smithy/middleware-content-length': 4.2.13 + '@smithy/middleware-endpoint': 4.4.29 + '@smithy/middleware-retry': 4.5.0 + '@smithy/middleware-serde': 4.2.17 + '@smithy/middleware-stack': 4.2.13 + '@smithy/node-config-provider': 4.3.13 + '@smithy/node-http-handler': 4.5.2 + '@smithy/protocol-http': 5.3.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-body-length-node': 4.2.3 + '@smithy/util-defaults-mode-browser': 4.3.45 + '@smithy/util-defaults-mode-node': 4.2.49 + '@smithy/util-endpoints': 3.3.4 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-retry': 4.3.0 + '@smithy/util-stream': 4.5.22 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/client-s3@3.954.0': dependencies: '@aws-crypto/sha1-browser': 5.2.0 @@ -5037,6 +5394,22 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@aws-sdk/core@3.973.26': + dependencies: + '@aws-sdk/types': 3.973.6 + '@aws-sdk/xml-builder': 3.972.16 + '@smithy/core': 3.23.14 + '@smithy/node-config-provider': 4.3.13 + '@smithy/property-provider': 4.2.13 + '@smithy/protocol-http': 5.3.13 + '@smithy/signature-v4': 5.3.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + '@smithy/util-base64': 4.3.2 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + '@aws-sdk/credential-provider-env@3.954.0': dependencies: '@aws-sdk/core': 3.954.0 @@ -5045,6 +5418,14 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@aws-sdk/credential-provider-env@3.972.24': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.954.0': dependencies: '@aws-sdk/core': 3.954.0 @@ -5058,6 +5439,19 @@ snapshots: '@smithy/util-stream': 4.5.7 tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.972.26': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/fetch-http-handler': 5.3.16 + '@smithy/node-http-handler': 4.5.2 + '@smithy/property-provider': 4.2.13 + '@smithy/protocol-http': 5.3.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + '@smithy/util-stream': 4.5.22 + tslib: 2.8.1 + '@aws-sdk/credential-provider-ini@3.954.0': dependencies: '@aws-sdk/core': 3.954.0 @@ -5077,6 +5471,25 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-ini@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/credential-provider-env': 3.972.24 + '@aws-sdk/credential-provider-http': 3.972.26 + '@aws-sdk/credential-provider-login': 3.972.28 + '@aws-sdk/credential-provider-process': 3.972.24 + '@aws-sdk/credential-provider-sso': 3.972.28 + '@aws-sdk/credential-provider-web-identity': 3.972.28 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/credential-provider-imds': 4.2.13 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-login@3.954.0': dependencies: '@aws-sdk/core': 3.954.0 @@ -5090,6 +5503,19 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-login@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/protocol-http': 5.3.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-node@3.954.0': dependencies: '@aws-sdk/credential-provider-env': 3.954.0 @@ -5107,6 +5533,23 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-node@3.972.29': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.24 + '@aws-sdk/credential-provider-http': 3.972.26 + '@aws-sdk/credential-provider-ini': 3.972.28 + '@aws-sdk/credential-provider-process': 3.972.24 + '@aws-sdk/credential-provider-sso': 3.972.28 + '@aws-sdk/credential-provider-web-identity': 3.972.28 + '@aws-sdk/types': 3.973.6 + '@smithy/credential-provider-imds': 4.2.13 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-process@3.954.0': dependencies: '@aws-sdk/core': 3.954.0 @@ -5116,6 +5559,15 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@aws-sdk/credential-provider-process@3.972.24': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-sso@3.954.0': dependencies: '@aws-sdk/client-sso': 3.954.0 @@ -5129,6 +5581,19 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-sso@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/token-providers': 3.1021.0 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-web-identity@3.954.0': dependencies: '@aws-sdk/core': 3.954.0 @@ -5141,6 +5606,25 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-web-identity@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/eventstream-handler-node@3.972.12': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/eventstream-codec': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@aws-sdk/middleware-bucket-endpoint@3.953.0': dependencies: '@aws-sdk/types': 3.953.0 @@ -5151,6 +5635,13 @@ snapshots: '@smithy/util-config-provider': 4.2.0 tslib: 2.8.1 + '@aws-sdk/middleware-eventstream@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@aws-sdk/middleware-expect-continue@3.953.0': dependencies: '@aws-sdk/types': 3.953.0 @@ -5181,6 +5672,13 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@aws-sdk/middleware-host-header@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@aws-sdk/middleware-location-constraint@3.953.0': dependencies: '@aws-sdk/types': 3.953.0 @@ -5193,6 +5691,12 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@aws-sdk/middleware-logger@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@aws-sdk/middleware-recursion-detection@3.953.0': dependencies: '@aws-sdk/types': 3.953.0 @@ -5201,6 +5705,14 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@aws-sdk/middleware-recursion-detection@3.972.9': + dependencies: + '@aws-sdk/types': 3.973.6 + '@aws/lambda-invoke-store': 0.2.2 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@aws-sdk/middleware-sdk-s3@3.954.0': dependencies: '@aws-sdk/core': 3.954.0 @@ -5234,6 +5746,32 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@aws-sdk/middleware-user-agent@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@smithy/core': 3.23.14 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-retry': 4.3.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-websocket@3.972.14': + dependencies: + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-format-url': 3.972.8 + '@smithy/eventstream-codec': 4.2.13 + '@smithy/eventstream-serde-browser': 4.2.13 + '@smithy/fetch-http-handler': 5.3.16 + '@smithy/protocol-http': 5.3.13 + '@smithy/signature-v4': 5.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-base64': 4.3.2 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + '@aws-sdk/nested-clients@3.954.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -5277,6 +5815,49 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/nested-clients@3.996.18': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.26 + '@aws-sdk/middleware-host-header': 3.972.8 + '@aws-sdk/middleware-logger': 3.972.8 + '@aws-sdk/middleware-recursion-detection': 3.972.9 + '@aws-sdk/middleware-user-agent': 3.972.28 + '@aws-sdk/region-config-resolver': 3.972.10 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/util-user-agent-browser': 3.972.8 + '@aws-sdk/util-user-agent-node': 3.973.14 + '@smithy/config-resolver': 4.4.14 + '@smithy/core': 3.23.14 + '@smithy/fetch-http-handler': 5.3.16 + '@smithy/hash-node': 4.2.13 + '@smithy/invalid-dependency': 4.2.13 + '@smithy/middleware-content-length': 4.2.13 + '@smithy/middleware-endpoint': 4.4.29 + '@smithy/middleware-retry': 4.5.0 + '@smithy/middleware-serde': 4.2.17 + '@smithy/middleware-stack': 4.2.13 + '@smithy/node-config-provider': 4.3.13 + '@smithy/node-http-handler': 4.5.2 + '@smithy/protocol-http': 5.3.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-body-length-node': 4.2.3 + '@smithy/util-defaults-mode-browser': 4.3.45 + '@smithy/util-defaults-mode-node': 4.2.49 + '@smithy/util-endpoints': 3.3.4 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-retry': 4.3.0 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/region-config-resolver@3.953.0': dependencies: '@aws-sdk/types': 3.953.0 @@ -5285,6 +5866,14 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@aws-sdk/region-config-resolver@3.972.10': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/config-resolver': 4.4.14 + '@smithy/node-config-provider': 4.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@aws-sdk/s3-request-presigner@3.954.0': dependencies: '@aws-sdk/signature-v4-multi-region': 3.954.0 @@ -5305,6 +5894,30 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@aws-sdk/token-providers@3.1021.0': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/token-providers@3.1025.0': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/token-providers@3.954.0': dependencies: '@aws-sdk/core': 3.954.0 @@ -5322,6 +5935,11 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@aws-sdk/types@3.973.6': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@aws-sdk/util-arn-parser@3.953.0': dependencies: tslib: 2.8.1 @@ -5334,6 +5952,14 @@ snapshots: '@smithy/util-endpoints': 3.2.6 tslib: 2.8.1 + '@aws-sdk/util-endpoints@3.996.5': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + '@smithy/util-endpoints': 3.3.4 + tslib: 2.8.1 + '@aws-sdk/util-format-url@3.953.0': dependencies: '@aws-sdk/types': 3.953.0 @@ -5341,6 +5967,13 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@aws-sdk/util-format-url@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/querystring-builder': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@aws-sdk/util-locate-window@3.953.0': dependencies: tslib: 2.8.1 @@ -5352,6 +5985,13 @@ snapshots: bowser: 2.13.1 tslib: 2.8.1 + '@aws-sdk/util-user-agent-browser@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/types': 4.14.0 + bowser: 2.13.1 + tslib: 2.8.1 + '@aws-sdk/util-user-agent-node@3.954.0': dependencies: '@aws-sdk/middleware-user-agent': 3.954.0 @@ -5360,12 +6000,27 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@aws-sdk/util-user-agent-node@3.973.14': + dependencies: + '@aws-sdk/middleware-user-agent': 3.972.28 + '@aws-sdk/types': 3.973.6 + '@smithy/node-config-provider': 4.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-config-provider': 4.2.2 + tslib: 2.8.1 + '@aws-sdk/xml-builder@3.953.0': dependencies: '@smithy/types': 4.10.0 fast-xml-parser: 5.2.5 tslib: 2.8.1 + '@aws-sdk/xml-builder@3.972.16': + dependencies: + '@smithy/types': 4.14.0 + fast-xml-parser: 5.5.8 + tslib: 2.8.1 + '@aws/lambda-invoke-store@0.2.2': {} '@babel/code-frame@7.27.1': @@ -6332,6 +6987,15 @@ snapshots: dependencies: tslib: 2.8.1 + '@smithy/config-resolver@4.4.14': + dependencies: + '@smithy/node-config-provider': 4.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-config-provider': 4.2.2 + '@smithy/util-endpoints': 3.3.4 + '@smithy/util-middleware': 4.2.13 + tslib: 2.8.1 + '@smithy/config-resolver@4.4.4': dependencies: '@smithy/node-config-provider': 4.3.6 @@ -6354,6 +7018,27 @@ snapshots: '@smithy/uuid': 1.1.0 tslib: 2.8.1 + '@smithy/core@3.23.14': + dependencies: + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-stream': 4.5.22 + '@smithy/util-utf8': 4.2.2 + '@smithy/uuid': 1.1.2 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.2.13': + dependencies: + '@smithy/node-config-provider': 4.3.13 + '@smithy/property-provider': 4.2.13 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + tslib: 2.8.1 + '@smithy/credential-provider-imds@4.2.6': dependencies: '@smithy/node-config-provider': 4.3.6 @@ -6362,6 +7047,13 @@ snapshots: '@smithy/url-parser': 4.2.6 tslib: 2.8.1 + '@smithy/eventstream-codec@4.2.13': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.14.0 + '@smithy/util-hex-encoding': 4.2.2 + tslib: 2.8.1 + '@smithy/eventstream-codec@4.2.6': dependencies: '@aws-crypto/crc32': 5.2.0 @@ -6369,29 +7061,60 @@ snapshots: '@smithy/util-hex-encoding': 4.2.0 tslib: 2.8.1 + '@smithy/eventstream-serde-browser@4.2.13': + dependencies: + '@smithy/eventstream-serde-universal': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/eventstream-serde-browser@4.2.6': dependencies: '@smithy/eventstream-serde-universal': 4.2.6 '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/eventstream-serde-config-resolver@4.3.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/eventstream-serde-config-resolver@4.3.6': dependencies: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/eventstream-serde-node@4.2.13': + dependencies: + '@smithy/eventstream-serde-universal': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/eventstream-serde-node@4.2.6': dependencies: '@smithy/eventstream-serde-universal': 4.2.6 '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/eventstream-serde-universal@4.2.13': + dependencies: + '@smithy/eventstream-codec': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/eventstream-serde-universal@4.2.6': dependencies: '@smithy/eventstream-codec': 4.2.6 '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/fetch-http-handler@5.3.16': + dependencies: + '@smithy/protocol-http': 5.3.13 + '@smithy/querystring-builder': 4.2.13 + '@smithy/types': 4.14.0 + '@smithy/util-base64': 4.3.2 + tslib: 2.8.1 + '@smithy/fetch-http-handler@5.3.7': dependencies: '@smithy/protocol-http': 5.3.6 @@ -6407,6 +7130,13 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/hash-node@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + '@smithy/hash-node@4.2.6': dependencies: '@smithy/types': 4.10.0 @@ -6420,6 +7150,11 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@smithy/invalid-dependency@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/invalid-dependency@4.2.6': dependencies: '@smithy/types': 4.10.0 @@ -6433,12 +7168,22 @@ snapshots: dependencies: tslib: 2.8.1 + '@smithy/is-array-buffer@4.2.2': + dependencies: + tslib: 2.8.1 + '@smithy/md5-js@4.2.6': dependencies: '@smithy/types': 4.10.0 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@smithy/middleware-content-length@4.2.13': + dependencies: + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/middleware-content-length@4.2.6': dependencies: '@smithy/protocol-http': 5.3.6 @@ -6456,6 +7201,17 @@ snapshots: '@smithy/util-middleware': 4.2.6 tslib: 2.8.1 + '@smithy/middleware-endpoint@4.4.29': + dependencies: + '@smithy/core': 3.23.14 + '@smithy/middleware-serde': 4.2.17 + '@smithy/node-config-provider': 4.3.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + '@smithy/util-middleware': 4.2.13 + tslib: 2.8.1 + '@smithy/middleware-retry@4.4.16': dependencies: '@smithy/node-config-provider': 4.3.6 @@ -6468,17 +7224,49 @@ snapshots: '@smithy/uuid': 1.1.0 tslib: 2.8.1 + '@smithy/middleware-retry@4.5.0': + dependencies: + '@smithy/core': 3.23.14 + '@smithy/node-config-provider': 4.3.13 + '@smithy/protocol-http': 5.3.13 + '@smithy/service-error-classification': 4.2.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-retry': 4.3.0 + '@smithy/uuid': 1.1.2 + tslib: 2.8.1 + + '@smithy/middleware-serde@4.2.17': + dependencies: + '@smithy/core': 3.23.14 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/middleware-serde@4.2.7': dependencies: '@smithy/protocol-http': 5.3.6 '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/middleware-stack@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/middleware-stack@4.2.6': dependencies: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/node-config-provider@4.3.13': + dependencies: + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/node-config-provider@4.3.6': dependencies: '@smithy/property-provider': 4.2.6 @@ -6494,27 +7282,59 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/node-http-handler@4.5.2': + dependencies: + '@smithy/protocol-http': 5.3.13 + '@smithy/querystring-builder': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/property-provider@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/property-provider@4.2.6': dependencies: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/protocol-http@5.3.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/protocol-http@5.3.6': dependencies: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/querystring-builder@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + '@smithy/util-uri-escape': 4.2.2 + tslib: 2.8.1 + '@smithy/querystring-builder@4.2.6': dependencies: '@smithy/types': 4.10.0 '@smithy/util-uri-escape': 4.2.0 tslib: 2.8.1 + '@smithy/querystring-parser@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/querystring-parser@4.2.6': dependencies: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/service-error-classification@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + '@smithy/service-error-classification@4.2.6': dependencies: '@smithy/types': 4.10.0 @@ -6524,6 +7344,22 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/shared-ini-file-loader@4.4.8': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.3.13': + dependencies: + '@smithy/is-array-buffer': 4.2.2 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-uri-escape': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + '@smithy/signature-v4@5.3.6': dependencies: '@smithy/is-array-buffer': 4.2.0 @@ -6545,10 +7381,30 @@ snapshots: '@smithy/util-stream': 4.5.7 tslib: 2.8.1 + '@smithy/smithy-client@4.12.9': + dependencies: + '@smithy/core': 3.23.14 + '@smithy/middleware-endpoint': 4.4.29 + '@smithy/middleware-stack': 4.2.13 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-stream': 4.5.22 + tslib: 2.8.1 + '@smithy/types@4.10.0': dependencies: tslib: 2.8.1 + '@smithy/types@4.14.0': + dependencies: + tslib: 2.8.1 + + '@smithy/url-parser@4.2.13': + dependencies: + '@smithy/querystring-parser': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/url-parser@4.2.6': dependencies: '@smithy/querystring-parser': 4.2.6 @@ -6561,14 +7417,28 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@smithy/util-base64@4.3.2': + dependencies: + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + '@smithy/util-body-length-browser@4.2.0': dependencies: tslib: 2.8.1 + '@smithy/util-body-length-browser@4.2.2': + dependencies: + tslib: 2.8.1 + '@smithy/util-body-length-node@4.2.1': dependencies: tslib: 2.8.1 + '@smithy/util-body-length-node@4.2.3': + dependencies: + tslib: 2.8.1 + '@smithy/util-buffer-from@2.2.0': dependencies: '@smithy/is-array-buffer': 2.2.0 @@ -6579,10 +7449,19 @@ snapshots: '@smithy/is-array-buffer': 4.2.0 tslib: 2.8.1 + '@smithy/util-buffer-from@4.2.2': + dependencies: + '@smithy/is-array-buffer': 4.2.2 + tslib: 2.8.1 + '@smithy/util-config-provider@4.2.0': dependencies: tslib: 2.8.1 + '@smithy/util-config-provider@4.2.2': + dependencies: + tslib: 2.8.1 + '@smithy/util-defaults-mode-browser@4.3.15': dependencies: '@smithy/property-provider': 4.2.6 @@ -6590,6 +7469,13 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/util-defaults-mode-browser@4.3.45': + dependencies: + '@smithy/property-provider': 4.2.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/util-defaults-mode-node@4.2.18': dependencies: '@smithy/config-resolver': 4.4.4 @@ -6600,16 +7486,41 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/util-defaults-mode-node@4.2.49': + dependencies: + '@smithy/config-resolver': 4.4.14 + '@smithy/credential-provider-imds': 4.2.13 + '@smithy/node-config-provider': 4.3.13 + '@smithy/property-provider': 4.2.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/util-endpoints@3.2.6': dependencies: '@smithy/node-config-provider': 4.3.6 '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/util-endpoints@3.3.4': + dependencies: + '@smithy/node-config-provider': 4.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/util-hex-encoding@4.2.0': dependencies: tslib: 2.8.1 + '@smithy/util-hex-encoding@4.2.2': + dependencies: + tslib: 2.8.1 + + '@smithy/util-middleware@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + '@smithy/util-middleware@4.2.6': dependencies: '@smithy/types': 4.10.0 @@ -6621,6 +7532,23 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 + '@smithy/util-retry@4.3.0': + dependencies: + '@smithy/service-error-classification': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/util-stream@4.5.22': + dependencies: + '@smithy/fetch-http-handler': 5.3.16 + '@smithy/node-http-handler': 4.5.2 + '@smithy/types': 4.14.0 + '@smithy/util-base64': 4.3.2 + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + '@smithy/util-stream@4.5.7': dependencies: '@smithy/fetch-http-handler': 5.3.7 @@ -6636,6 +7564,10 @@ snapshots: dependencies: tslib: 2.8.1 + '@smithy/util-uri-escape@4.2.2': + dependencies: + tslib: 2.8.1 + '@smithy/util-utf8@2.3.0': dependencies: '@smithy/util-buffer-from': 2.2.0 @@ -6646,6 +7578,11 @@ snapshots: '@smithy/util-buffer-from': 4.2.0 tslib: 2.8.1 + '@smithy/util-utf8@4.2.2': + dependencies: + '@smithy/util-buffer-from': 4.2.2 + tslib: 2.8.1 + '@smithy/util-waiter@4.2.6': dependencies: '@smithy/abort-controller': 4.2.6 @@ -6656,6 +7593,10 @@ snapshots: dependencies: tslib: 2.8.1 + '@smithy/uuid@1.1.2': + dependencies: + tslib: 2.8.1 + '@standard-schema/spec@1.0.0': {} '@swc/helpers@0.5.18': @@ -7809,10 +8750,20 @@ snapshots: fast-uri@3.1.0: {} + fast-xml-builder@1.1.4: + dependencies: + path-expression-matcher: 1.4.0 + fast-xml-parser@5.2.5: dependencies: strnum: 2.1.2 + fast-xml-parser@5.5.8: + dependencies: + fast-xml-builder: 1.1.4 + path-expression-matcher: 1.4.0 + strnum: 2.2.3 + fastify-cli@7.4.1: dependencies: '@fastify/deepmerge': 3.1.0 @@ -8971,6 +9922,8 @@ snapshots: path-exists@4.0.0: {} + path-expression-matcher@1.4.0: {} + path-key@3.1.1: {} path-parse@1.0.7: {} @@ -9508,6 +10461,8 @@ snapshots: strnum@2.1.2: {} + strnum@2.2.3: {} + supports-color@10.2.2: {} supports-color@7.2.0: From e9f1efd23e35114c9a8daed2f3dfd2bba7f8a51f Mon Sep 17 00:00:00 2001 From: Alvin Mei Date: Tue, 7 Apr 2026 16:25:35 -0400 Subject: [PATCH 2/8] working chat field --- apps/bridge/src/modules/chat/index.ts | 3 ++ packages/wafir/src/api/client.ts | 18 +++----- .../wafir/src/styles/wafir-chat-field.css | 1 + packages/wafir/src/wafir-chat-field.ts | 44 ++++--------------- 4 files changed, 17 insertions(+), 49 deletions(-) create mode 100644 apps/bridge/src/modules/chat/index.ts diff --git a/apps/bridge/src/modules/chat/index.ts b/apps/bridge/src/modules/chat/index.ts new file mode 100644 index 0000000..0032de1 --- /dev/null +++ b/apps/bridge/src/modules/chat/index.ts @@ -0,0 +1,3 @@ +// Copyright (C) 2024 BPS-Consulting - Licensed under AGPLv3 +export { default } from "./routes.js"; +export * from "./service.js"; diff --git a/packages/wafir/src/api/client.ts b/packages/wafir/src/api/client.ts index 4c5888c..d01d0bb 100644 --- a/packages/wafir/src/api/client.ts +++ b/packages/wafir/src/api/client.ts @@ -216,32 +216,24 @@ export const submitIssue = async (params: SubmitIssueParams) => { /** * Sends a chat message to the Bridge API. + * Uses the globally configured API base URL. * @param message - The user's message - * @param bridgeUrl - Optional custom bridge URL * @returns The AI's reply or an error */ export const sendChatMessage = async ( message: string, - bridgeUrl?: string, ): Promise<{ reply?: string; error?: string }> => { - const urlToUse = bridgeUrl || currentBridgeUrl; - - const response = await fetch(`${urlToUse}/chat/`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ message }), + const { data, error, response } = await getClient().POST("/chat/", { + body: { message }, }); if (response.status === 403) { return { error: "not authorized" }; } - if (!response.ok) { + if (error || !response.ok) { return { error: `Chat request failed: ${response.status}` }; } - const data = (await response.json()) as { reply?: string; error?: string }; - return data; + return { reply: data?.reply }; }; diff --git a/packages/wafir/src/styles/wafir-chat-field.css b/packages/wafir/src/styles/wafir-chat-field.css index eec5f98..f0faa7c 100644 --- a/packages/wafir/src/styles/wafir-chat-field.css +++ b/packages/wafir/src/styles/wafir-chat-field.css @@ -12,6 +12,7 @@ .chat-container { display: flex; flex-direction: column; + margin-top: 16px; height: 300px; border: 1px solid var(--wafir-form-border-color, #d1d5db); border-radius: var(--wafir-form-border-radius, 6px); diff --git a/packages/wafir/src/wafir-chat-field.ts b/packages/wafir/src/wafir-chat-field.ts index fed1f20..45164d3 100644 --- a/packages/wafir/src/wafir-chat-field.ts +++ b/packages/wafir/src/wafir-chat-field.ts @@ -2,6 +2,7 @@ import { LitElement, html, unsafeCSS } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import chatFieldStyles from "./styles/wafir-chat-field.css?inline"; +import { sendChatMessage } from "./api/client.js"; interface ChatMessage { role: "user" | "assistant" | "error"; @@ -14,12 +15,6 @@ interface ChatMessage { */ @customElement("wafir-chat-field") export class WafirChatField extends LitElement { - /** - * The Bridge API URL for chat requests. - */ - @property({ type: String, attribute: "bridge-url" }) - bridgeUrl = ""; - /** * Placeholder text for the input field. */ @@ -52,17 +47,6 @@ export class WafirChatField extends LitElement { static styles = [unsafeCSS(chatFieldStyles)]; - /** - * Gets the effective Bridge URL. - */ - private _getBridgeUrl(): string { - return ( - this.bridgeUrl || - (import.meta as any).env?.VITE_WAFIR_API_URL || - "https://v6hvmahyx2.execute-api.us-east-2.amazonaws.com" - ); - } - /** * Sends a message to the chat API. */ @@ -81,36 +65,24 @@ export class WafirChatField extends LitElement { this._scrollToBottom(); try { - const response = await fetch(`${this._getBridgeUrl()}/chat/`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ message }), - }); - - if (response.status === 403) { + const result = await sendChatMessage(message); + + if (result.error === "not authorized") { // Not authorized this._isAuthorized = false; this._messages = []; // Clear messages return; } - if (!response.ok) { - throw new Error(`Chat request failed: ${response.status}`); - } - - const data = (await response.json()) as { reply: string; error?: string }; - - if (data.error) { + if (result.error) { this._messages = [ ...this._messages, - { role: "error", content: data.error }, + { role: "error", content: result.error }, ]; - } else { + } else if (result.reply) { this._messages = [ ...this._messages, - { role: "assistant", content: data.reply }, + { role: "assistant", content: result.reply }, ]; } } catch (error) { From b5318ea50984c3750be0816bcd2013dbe1c03882 Mon Sep 17 00:00:00 2001 From: Alvin Mei Date: Wed, 8 Apr 2026 16:16:59 -0400 Subject: [PATCH 3/8] use agent runtime instead --- apps/bridge/.env.example | 17 +- apps/bridge/package.json | 2 +- apps/bridge/src/modules/chat/service.ts | 81 +++--- pnpm-lock.yaml | 351 ++++++++++-------------- 4 files changed, 189 insertions(+), 262 deletions(-) diff --git a/apps/bridge/.env.example b/apps/bridge/.env.example index 36353d0..90e3e6b 100644 --- a/apps/bridge/.env.example +++ b/apps/bridge/.env.example @@ -9,17 +9,18 @@ BASE_URL=http://localhost:3000 # AWS Configuration # AWS_ACCESS_KEY_ID= # AWS_SECRET_ACCESS_KEY= -AWS_REGION= +AWS_REGION=us-east-1 S3_BUCKET_NAME= # Chat Configuration # Comma-separated list of authorized URL origins or domains for chat. -# Supports wildcard subdomains with *. -# Examples: -# https://example.com - exact match only -# https://*.example.com - matches any subdomain (foo.example.com, bar.example.com) -# https://grants.gov,https://*.agency.gov - multiple origins CHAT_AUTHORIZED_URLS= -# Bedrock model ID for chat (e.g., anthropic.claude-3-haiku-20240307-v1:0) -CHAT_BEDROCK_MODEL_ID= +# Bedrock Agent Configuration +# The unique ID of your Bedrock Agent (found in the Bedrock Console > Agents) +BEDROCK_AGENT_ID= + +# The Alias ID of your Agent. +# Use 'TSTALIASID' for the Working Draft (Draft Version). +# Use a specific Alias ID (e.g., ABC123DEFG) for a published version. +BEDROCK_AGENT_ALIAS_ID=TSTALIASID \ No newline at end of file diff --git a/apps/bridge/package.json b/apps/bridge/package.json index d4c8fd4..3177690 100644 --- a/apps/bridge/package.json +++ b/apps/bridge/package.json @@ -28,7 +28,7 @@ "author": "", "license": "ISC", "dependencies": { - "@aws-sdk/client-bedrock-runtime": "^3.1025.0", + "@aws-sdk/client-bedrock-agent-runtime": "^3.1027.0", "@aws-sdk/client-s3": "^3.954.0", "@aws-sdk/s3-request-presigner": "^3.954.0", "@fastify/autoload": "^6.0.0", diff --git a/apps/bridge/src/modules/chat/service.ts b/apps/bridge/src/modules/chat/service.ts index 8922ae7..07d915a 100644 --- a/apps/bridge/src/modules/chat/service.ts +++ b/apps/bridge/src/modules/chat/service.ts @@ -1,8 +1,8 @@ // Copyright (C) 2024 BPS-Consulting - Licensed under AGPLv3 import { - BedrockRuntimeClient, - InvokeModelCommand, -} from "@aws-sdk/client-bedrock-runtime"; + BedrockAgentRuntimeClient, + InvokeAgentCommand, +} from "@aws-sdk/client-bedrock-agent-runtime"; export interface ChatRequest { message: string; @@ -13,59 +13,58 @@ export interface ChatResponse { } /** - * Service for interacting with Amazon Bedrock chat models. + * Service for interacting with Amazon Bedrock Agents. */ export class ChatService { - private client: BedrockRuntimeClient; - private modelId: string; + private client: BedrockAgentRuntimeClient; + private agentId: string; + private agentAliasId: string; constructor() { - this.client = new BedrockRuntimeClient({ + this.client = new BedrockAgentRuntimeClient({ region: process.env.AWS_REGION || "us-east-1", }); - this.modelId = - process.env.CHAT_BEDROCK_MODEL_ID || - "anthropic.claude-3-haiku-20240307-v1:0"; + // These IDs are found in the AWS Console under Bedrock > Agents + this.agentId = process.env.BEDROCK_AGENT_ID || ""; + this.agentAliasId = process.env.BEDROCK_AGENT_ALIAS_ID || "TSTALIASID"; // "TSTALIASID" is default for draft } /** - * Sends a message to Bedrock and returns the response. + * Sends a message to a Bedrock Agent and returns the aggregated response. * @param message - The user's message - * @returns The AI's reply + * @param sessionId - Optional session ID to maintain conversation context + * @returns The Agent's reply */ - async chat(message: string): Promise { - // Format for Claude models on Bedrock - const payload = { - anthropic_version: "bedrock-2023-05-31", - max_tokens: 1024, - messages: [ - { - role: "user", - content: message, - }, - ], - }; - - const command = new InvokeModelCommand({ - modelId: this.modelId, - contentType: "application/json", - accept: "application/json", - body: JSON.stringify(payload), + async chat( + message: string, + sessionId: string = "default-session", + ): Promise { + const command = new InvokeAgentCommand({ + agentId: this.agentId, + agentAliasId: this.agentAliasId, + sessionId: sessionId, + inputText: message, }); - const response = await this.client.send(command); - const responseBody = JSON.parse(new TextDecoder().decode(response.body)); + try { + const response = await this.client.send(command); + let fullResponse = ""; - // Extract text from Claude response format - if (responseBody.content && Array.isArray(responseBody.content)) { - const textContent = responseBody.content.find( - (c: { type: string }) => c.type === "text", - ); - if (textContent && textContent.text) { - return textContent.text; + // Bedrock Agents return a stream of events + if (response.completion) { + for await (const chunk of response.completion) { + if (chunk.chunk && chunk.chunk.bytes) { + // Decode the binary chunk into text + const text = new TextDecoder("utf-8").decode(chunk.chunk.bytes); + fullResponse += text; + } + } } - } - return responseBody.completion || "No response generated"; + return fullResponse || "No response generated"; + } catch (error) { + console.error("Error invoking Bedrock Agent:", error); + throw new Error("Failed to get response from AI Agent"); + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d58599e..a087d14 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,9 +30,9 @@ importers: apps/bridge: dependencies: - '@aws-sdk/client-bedrock-runtime': - specifier: ^3.1025.0 - version: 3.1025.0 + '@aws-sdk/client-bedrock-agent-runtime': + specifier: ^3.1027.0 + version: 3.1027.0 '@aws-sdk/client-s3': specifier: ^3.954.0 version: 3.954.0 @@ -304,8 +304,8 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-sdk/client-bedrock-runtime@3.1025.0': - resolution: {integrity: sha512-+ATojo49AZAd9IPHTYiRgv5kiPZcZkgkznENl7lK+Hg0W4RCs48bMjlJDVgN9QKPk3VfQUUPq1KjAtX98ggBtw==} + '@aws-sdk/client-bedrock-agent-runtime@3.1027.0': + resolution: {integrity: sha512-hUv3MKoLsC6veNIFx4ewqXHC+4TlTz76wakG7qY/HHHh++8qwpE9d1wmvyYwuM1CFAMMsxQWr8CKfw/auJdahg==} engines: {node: '>=20.0.0'} '@aws-sdk/client-s3@3.954.0': @@ -320,86 +320,78 @@ packages: resolution: {integrity: sha512-5oYO5RP+mvCNXNj8XnF9jZo0EP0LTseYOJVNQYcii1D9DJqzHL3HJWurYh7cXxz7G7eDyvVYA01O9Xpt34TdoA==} engines: {node: '>=18.0.0'} - '@aws-sdk/core@3.973.26': - resolution: {integrity: sha512-A/E6n2W42ruU+sfWk+mMUOyVXbsSgGrY3MJ9/0Az5qUdG67y8I6HYzzoAa+e/lzxxl1uCYmEL6BTMi9ZiZnplQ==} + '@aws-sdk/core@3.973.27': + resolution: {integrity: sha512-CUZ5m8hwMCH6OYI4Li/WgMfIEx10Q2PLI9Y3XOUTPGZJ53aZ0007jCv+X/ywsaERyKPdw5MRZWk877roQksQ4A==} engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-env@3.954.0': resolution: {integrity: sha512-2HNkqBjfsvyoRuPAiFh86JBFMFyaCNhL4VyH6XqwTGKZffjG7hdBmzXPy7AT7G3oFh1k/1Zc27v0qxaKoK7mBA==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-env@3.972.24': - resolution: {integrity: sha512-FWg8uFmT6vQM7VuzELzwVo5bzExGaKHdubn0StjgrcU5FvuLExUe+k06kn/40uKv59rYzhez8eFNM4yYE/Yb/w==} + '@aws-sdk/credential-provider-env@3.972.25': + resolution: {integrity: sha512-6QfI0wv4jpG5CrdO/AO0JfZ2ux+tKwJPrUwmvxXF50vI5KIypKVGNF6b4vlkYEnKumDTI1NX2zUBi8JoU5QU3A==} engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-http@3.954.0': resolution: {integrity: sha512-CrWD5300+NE1OYRnSVDxoG7G0b5cLIZb7yp+rNQ5Jq/kqnTmyJXpVAsivq+bQIDaGzPXhadzpAMIoo7K/aHaag==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-http@3.972.26': - resolution: {integrity: sha512-CY4ppZ+qHYqcXqBVi//sdHST1QK3KzOEiLtpLsc9W2k2vfZPKExGaQIsOwcyvjpjUEolotitmd3mUNY56IwDEA==} + '@aws-sdk/credential-provider-http@3.972.27': + resolution: {integrity: sha512-3V3Usj9Gs93h865DqN4M2NWJhC5kXU9BvZskfN3+69omuYlE3TZxOEcVQtBGLOloJB7BVfJKXVLqeNhOzHqSlQ==} engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-ini@3.954.0': resolution: {integrity: sha512-WAFD8pVwRSoBsuXcoD+s/hrdsP9Z0PNUedSgkOGExuJVAabpM2cIIMzYNsdHio9XFZUSqHkv8mF5mQXuIZvuzg==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-ini@3.972.28': - resolution: {integrity: sha512-wXYvq3+uQcZV7k+bE4yDXCTBdzWTU9x/nMiKBfzInmv6yYK1veMK0AKvRfRBd72nGWYKcL6AxwiPg9z/pYlgpw==} + '@aws-sdk/credential-provider-ini@3.972.29': + resolution: {integrity: sha512-SiBuAnXecCbT/OpAf3vqyI/AVE3mTaYr9ShXLybxZiPLBiPCCOIWSGAtYYGQWMRvobBTiqOewaB+wcgMMZI2Aw==} engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-login@3.954.0': resolution: {integrity: sha512-EYqaBWwdVbVK7prmsmgTWLPptoWREplPkFMFscOpVmseDvf/0IjYNbNLLtfuhy/6L7ZBGI9wat2k4u0MRivvxA==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-login@3.972.28': - resolution: {integrity: sha512-ZSTfO6jqUTCysbdBPtEX5OUR//3rbD0lN7jO3sQeS2Gjr/Y+DT6SbIJ0oT2cemNw3UzKu97sNONd1CwNMthuZQ==} + '@aws-sdk/credential-provider-login@3.972.29': + resolution: {integrity: sha512-OGOslTbOlxXexKMqhxCEbBQbUIfuhGxU5UXw3Fm56ypXHvrXH4aTt/xb5Y884LOoteP1QST1lVZzHfcTnWhiPQ==} engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-node@3.954.0': resolution: {integrity: sha512-UPBjw7Lnly5i+/rES8Z5U+nPaumzEUYOE/wrHkxyH6JjwFWn8w7R07fE5Z5cgYlIq1U1lQ7sxYwB3wHPpQ65Aw==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-node@3.972.29': - resolution: {integrity: sha512-clSzDcvndpFJAggLDnDb36sPdlZYyEs5Zm6zgZjjUhwsJgSWiWKwFIXUVBcbruidNyBdbpOv2tNDL9sX8y3/0g==} + '@aws-sdk/credential-provider-node@3.972.30': + resolution: {integrity: sha512-FMnAnWxc8PG+ZrZ2OBKzY4luCUJhe9CG0B9YwYr4pzrYGLXBS2rl+UoUvjGbAwiptxRL6hyA3lFn03Bv1TLqTw==} engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-process@3.954.0': resolution: {integrity: sha512-Y1/0O2LgbKM8iIgcVj/GNEQW6p90LVTCOzF2CI1pouoKqxmZ/1F7F66WHoa6XUOfKaCRj/R6nuMR3om9ThaM5A==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-process@3.972.24': - resolution: {integrity: sha512-Q2k/XLrFXhEztPHqj4SLCNID3hEPdlhh1CDLBpNnM+1L8fq7P+yON9/9M1IGN/dA5W45v44ylERfXtDAlmMNmw==} + '@aws-sdk/credential-provider-process@3.972.25': + resolution: {integrity: sha512-HR7ynNRdNhNsdVCOCegy1HsfsRzozCOPtD3RzzT1JouuaHobWyRfJzCBue/3jP7gECHt+kQyZUvwg/cYLWurNQ==} engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-sso@3.954.0': resolution: {integrity: sha512-UXxGfkp/plFRdyidMLvNul5zoLKmHhVQOCrD2OgR/lg9jNqNmJ7abF+Qu8abo902iDkhU21Qj4M398cx6l8Kng==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-sso@3.972.28': - resolution: {integrity: sha512-IoUlmKMLEITFn1SiCTjPfR6KrE799FBo5baWyk/5Ppar2yXZoUdaRqZzJzK6TcJxx450M8m8DbpddRVYlp5R/A==} + '@aws-sdk/credential-provider-sso@3.972.29': + resolution: {integrity: sha512-HWv4SEq3jZDYPlwryZVef97+U8CxxRos5mK8sgGO1dQaFZpV5giZLzqGE5hkDmh2csYcBO2uf5XHjPTpZcJlig==} engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-web-identity@3.954.0': resolution: {integrity: sha512-XEyf1T08q1tG4zkTS4Dnf1cAQyrJUo/xlvi6XNpqGhY3bOmKUYE2h/K6eITIdytDL9VuCpWYQ6YRcIVtL29E0w==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-web-identity@3.972.28': - resolution: {integrity: sha512-d+6h0SD8GGERzKe27v5rOzNGKOl0D+l0bWJdqrxH8WSQzHzjsQFIAPgIeOTUwBHVsKKwtSxc91K/SWax6XgswQ==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/eventstream-handler-node@3.972.12': - resolution: {integrity: sha512-ruyc/MNR6e+cUrGCth7fLQ12RXBZDy/bV06tgqB9Z5n/0SN/C0m6bsQEV8FF9zPI6VSAOaRd0rNgmpYVnGawrQ==} + '@aws-sdk/credential-provider-web-identity@3.972.29': + resolution: {integrity: sha512-PdMBza1WEKEUPFEmMGCfnU2RYCz9MskU2e8JxjyUOsMKku7j9YaDKvbDi2dzC0ihFoM6ods2SbhfAAro+Gwlew==} engines: {node: '>=20.0.0'} '@aws-sdk/middleware-bucket-endpoint@3.953.0': resolution: {integrity: sha512-YHVRIOowtGIl/L2WuS83FgRlm31tU0aL1yryWaFtF+AFjA5BIeiFkxIZqaRGxJpJvFEBdohsyq6Ipv5mgWfezg==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-eventstream@3.972.8': - resolution: {integrity: sha512-r+oP+tbCxgqXVC3pu3MUVePgSY0ILMjA+aEwOosS77m3/DRbtvHrHwqvMcw+cjANMeGzJ+i0ar+n77KXpRA8RQ==} - engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-expect-continue@3.953.0': resolution: {integrity: sha512-BQTVXrypQ0rbb7au/Hk4IS5GaJZlwk6O44Rjk6Kxb0IvGQhSurNTuesFiJx1sLbf+w+T31saPtODcfQQERqhCQ==} engines: {node: '>=18.0.0'} @@ -412,8 +404,8 @@ packages: resolution: {integrity: sha512-jTGhfkONav+r4E6HLOrl5SzBqDmPByUYCkyB/c/3TVb8jX3wAZx8/q9bphKpCh+G5ARi3IdbSisgkZrJYqQ19Q==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-host-header@3.972.8': - resolution: {integrity: sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ==} + '@aws-sdk/middleware-host-header@3.972.9': + resolution: {integrity: sha512-je5vRdNw4SkuTnmRbFZLdye4sQ0faLt8kwka5wnnSU30q1mHO4X+idGEJOOE+Tn1ME7Oryn05xxkDvIb3UaLaQ==} engines: {node: '>=20.0.0'} '@aws-sdk/middleware-location-constraint@3.953.0': @@ -424,16 +416,16 @@ packages: resolution: {integrity: sha512-PlWdVYgcuptkIC0ZKqVUhWNtSHXJSx7U9V8J7dJjRmsXC40X7zpEycvrkzDMJjeTDGcCceYbyYAg/4X1lkcIMw==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-logger@3.972.8': - resolution: {integrity: sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA==} + '@aws-sdk/middleware-logger@3.972.9': + resolution: {integrity: sha512-HsVgDrruhqI28RkaXALm8grJ7Agc1wF6Et0xh6pom8NdO2VdO/SD9U/tPwUjewwK/pVoka+EShBxyCvgsPCtog==} engines: {node: '>=20.0.0'} '@aws-sdk/middleware-recursion-detection@3.953.0': resolution: {integrity: sha512-cmIJx0gWeesUKK4YwgE+VQL3mpACr3/J24fbwnc1Z5tntC86b+HQFzU5vsBDw6lLwyD46dBgWdsXFh1jL+ZaFw==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-recursion-detection@3.972.9': - resolution: {integrity: sha512-/Wt5+CT8dpTFQxEJ9iGy/UGrXr7p2wlIOEHvIr/YcHYByzoLjrqkYqXdJjd9UIgWjv7eqV2HnFJen93UTuwfTQ==} + '@aws-sdk/middleware-recursion-detection@3.972.10': + resolution: {integrity: sha512-RVQQbq5orQ/GHUnXvqEOj2HHPBJm+mM+ySwZKS5UaLBwra5ugRtiH09PLUoOZRl7a1YzaOzXSuGbn9iD5j60WQ==} engines: {node: '>=20.0.0'} '@aws-sdk/middleware-sdk-s3@3.954.0': @@ -448,28 +440,24 @@ packages: resolution: {integrity: sha512-5PX8JDe3dB2+MqXeGIhmgFnm2rbVsSxhz+Xyuu1oxLtbOn+a9UDA+sNBufEBjt3UxWy5qwEEY1fxdbXXayjlGg==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-user-agent@3.972.28': - resolution: {integrity: sha512-cfWZFlVh7Va9lRay4PN2A9ARFzaBYcA097InT5M2CdRS05ECF5yaz86jET8Wsl2WcyKYEvVr/QNmKtYtafUHtQ==} + '@aws-sdk/middleware-user-agent@3.972.29': + resolution: {integrity: sha512-f/sIRzuTfEjg6NsbMYvye2VsmnQoNgntntleQyx5uGacUYzszbfIlO3GcI6G6daWUmTm0IDZc11qMHWwF0o0mQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-websocket@3.972.14': - resolution: {integrity: sha512-qnfDlIHjm6DrTYNvWOUbnZdVKgtoKbO/Qzj+C0Wp5Y7VUrsvBRQtGKxD+hc+mRTS4N0kBJ6iZ3+zxm4N1OSyjg==} - engines: {node: '>= 14.0.0'} - '@aws-sdk/nested-clients@3.954.0': resolution: {integrity: sha512-JLUhf35fTQIDPLk6G5KPggL9tV//Hjhy6+N2zZeis76LuBRNhKDq8z1CFyKhjf00vXi/tDYdn9D7y9emI+5Y/g==} engines: {node: '>=18.0.0'} - '@aws-sdk/nested-clients@3.996.18': - resolution: {integrity: sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA==} + '@aws-sdk/nested-clients@3.996.19': + resolution: {integrity: sha512-uFkmCDXvmQYLanlYdOFS0+MQWkrj9wPMt/ZCc/0J0fjPim6F5jBVBmEomvGY/j77ILW6GTPwN22Jc174Mhkw6Q==} engines: {node: '>=20.0.0'} '@aws-sdk/region-config-resolver@3.953.0': resolution: {integrity: sha512-5MJgnsc+HLO+le0EK1cy92yrC7kyhGZSpaq8PcQvKs9qtXCXT5Tb6tMdkr5Y07JxYsYOV1omWBynvL6PWh08tQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/region-config-resolver@3.972.10': - resolution: {integrity: sha512-1dq9ToC6e070QvnVhhbAs3bb5r6cQ10gTVc6cyRV5uvQe7P138TV2uG2i6+Yok4bAkVAcx5AqkTEBUvWEtBlsQ==} + '@aws-sdk/region-config-resolver@3.972.11': + resolution: {integrity: sha512-6Q8B1dcx6BBqUTY1Mc/eROKA0FImEEY5VPSd6AGPEUf0ErjExz4snVqa9kNJSoVDV1rKaNf3qrWojgcKW+SdDg==} engines: {node: '>=20.0.0'} '@aws-sdk/s3-request-presigner@3.954.0': @@ -480,12 +468,8 @@ packages: resolution: {integrity: sha512-GJJbUaSlGrMSRWui3Oz8ByygpQlzDGm195yTKirgGyu4tfYrFr/QWrWT42EUktY/L4Irev1pdHTuLS+AGHO1gw==} engines: {node: '>=18.0.0'} - '@aws-sdk/token-providers@3.1021.0': - resolution: {integrity: sha512-TKY6h9spUk3OLs5v1oAgW9mAeBE3LAGNBwJokLy96wwmd4W2v/tYlXseProyed9ValDj2u1jK/4Rg1T+1NXyJA==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/token-providers@3.1025.0': - resolution: {integrity: sha512-sbEnN8VbDFCmf1NbGHpWDQ9llwOYkPeEs8NLZ2+uYO7l97s+x6X58XTnM6XG/DBe9LZm5ddObvsK1CVlW2N4hg==} + '@aws-sdk/token-providers@3.1026.0': + resolution: {integrity: sha512-Ieq/HiRrbEtrYP387Nes0XlR7H1pJiJOZKv+QyQzMYpvTiDs0VKy2ZB3E2Zf+aFovWmeE7lRE4lXyF7dYM6GgA==} engines: {node: '>=20.0.0'} '@aws-sdk/token-providers@3.954.0': @@ -496,8 +480,8 @@ packages: resolution: {integrity: sha512-M9Iwg9kTyqTErI0vOTVVpcnTHWzS3VplQppy8MuL02EE+mJ0BIwpWfsaAPQW+/XnVpdNpWZTsHcNE29f1+hR8g==} engines: {node: '>=18.0.0'} - '@aws-sdk/types@3.973.6': - resolution: {integrity: sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==} + '@aws-sdk/types@3.973.7': + resolution: {integrity: sha512-reXRwoJ6CfChoqAsBszUYajAF8Z2LRE+CRcKocvFSMpIiLOtYU3aJ9trmn6VVPAzbbY5LXF+FfmUslbXk1SYFg==} engines: {node: '>=20.0.0'} '@aws-sdk/util-arn-parser@3.953.0': @@ -508,18 +492,14 @@ packages: resolution: {integrity: sha512-rjaS6jrFksopXvNg6YeN+D1lYwhcByORNlFuYesFvaQNtPOufbE5tJL4GJ3TMXyaY0uFR28N5BHHITPyWWfH/g==} engines: {node: '>=18.0.0'} - '@aws-sdk/util-endpoints@3.996.5': - resolution: {integrity: sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw==} + '@aws-sdk/util-endpoints@3.996.6': + resolution: {integrity: sha512-2nUQ+2ih7CShuKHpGSIYvvAIOHy52dOZguYG36zptBukhw6iFwcvGfG0tes0oZFWQqEWvgZe9HLWaNlvXGdOrg==} engines: {node: '>=20.0.0'} '@aws-sdk/util-format-url@3.953.0': resolution: {integrity: sha512-fs70vtTiBhp/T9ss52OuW2LGJqPoNBbd1+wxqh82CMdzkOvCzI3qa/cK8tR0jCFeIjGeiV74lAskImRxu/V4lg==} engines: {node: '>=18.0.0'} - '@aws-sdk/util-format-url@3.972.8': - resolution: {integrity: sha512-J6DS9oocrgxM8xlUTTmQOuwRF6rnAGEujAN9SAzllcrQmwn5iJ58ogxy3SEhD0Q7JZvlA5jvIXBkpQRqEqlE9A==} - engines: {node: '>=20.0.0'} - '@aws-sdk/util-locate-window@3.953.0': resolution: {integrity: sha512-mPxK+I1LcrgC/RSa3G5AMAn8eN2Ay0VOgw8lSRmV1jCtO+iYvNeCqOdxoJUjOW6I5BA4niIRWqVORuRP07776Q==} engines: {node: '>=18.0.0'} @@ -527,8 +507,8 @@ packages: '@aws-sdk/util-user-agent-browser@3.953.0': resolution: {integrity: sha512-UF5NeqYesWuFao+u7LJvpV1SJCaLml5BtFZKUdTnNNMeN6jvV+dW/eQoFGpXF94RCqguX0XESmRuRRPQp+/rzQ==} - '@aws-sdk/util-user-agent-browser@3.972.8': - resolution: {integrity: sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA==} + '@aws-sdk/util-user-agent-browser@3.972.9': + resolution: {integrity: sha512-sn/LMzTbGjYqCCF24390WxPd6hkpoSptiUn5DzVp4cD71yqw+yGEGm1YCxyEoPXyc8qciM8UzLJcZBFslxo5Uw==} '@aws-sdk/util-user-agent-node@3.954.0': resolution: {integrity: sha512-fB5S5VOu7OFkeNzcblQlez4AjO5hgDFaa7phYt7716YWisY3RjAaQPlxgv+G3GltHHDJIfzEC5aRxdf62B9zMg==} @@ -539,8 +519,8 @@ packages: aws-crt: optional: true - '@aws-sdk/util-user-agent-node@3.973.14': - resolution: {integrity: sha512-vNSB/DYaPOyujVZBg/zUznH9QC142MaTHVmaFlF7uzzfg3CgT9f/l4C0Yi+vU/tbBhxVcXVB90Oohk5+o+ZbWw==} + '@aws-sdk/util-user-agent-node@3.973.15': + resolution: {integrity: sha512-fYn3s9PtKdgQkczGZCFMgkNEe8aq1JCVbnRqjqN9RSVW43xn2RV9xdcZ3z01a48Jpkuh/xCmBKJxdLOo4Ozg7w==} engines: {node: '>=20.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -552,8 +532,8 @@ packages: resolution: {integrity: sha512-Zmrj21jQ2OeOJGr9spPiN00aQvXa/WUqRXcTVENhrMt+OFoSOfDFpYhUj9NQ09QmQ8KMWFoWuWW6iKurNqLvAA==} engines: {node: '>=18.0.0'} - '@aws-sdk/xml-builder@3.972.16': - resolution: {integrity: sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A==} + '@aws-sdk/xml-builder@3.972.17': + resolution: {integrity: sha512-Ra7hjqAZf1OXRRMueB13qex7mFJRDK/pgCvdSFemXBT8KCGnQDPoKzHY1SjN+TjJVmnpSF14W5tJ1vDamFu+Gg==} engines: {node: '>=20.0.0'} '@aws/lambda-invoke-store@0.2.2': @@ -5223,25 +5203,21 @@ snapshots: '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@aws-sdk/client-bedrock-runtime@3.1025.0': + '@aws-sdk/client-bedrock-agent-runtime@3.1027.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.26 - '@aws-sdk/credential-provider-node': 3.972.29 - '@aws-sdk/eventstream-handler-node': 3.972.12 - '@aws-sdk/middleware-eventstream': 3.972.8 - '@aws-sdk/middleware-host-header': 3.972.8 - '@aws-sdk/middleware-logger': 3.972.8 - '@aws-sdk/middleware-recursion-detection': 3.972.9 - '@aws-sdk/middleware-user-agent': 3.972.28 - '@aws-sdk/middleware-websocket': 3.972.14 - '@aws-sdk/region-config-resolver': 3.972.10 - '@aws-sdk/token-providers': 3.1025.0 - '@aws-sdk/types': 3.973.6 - '@aws-sdk/util-endpoints': 3.996.5 - '@aws-sdk/util-user-agent-browser': 3.972.8 - '@aws-sdk/util-user-agent-node': 3.973.14 + '@aws-sdk/core': 3.973.27 + '@aws-sdk/credential-provider-node': 3.972.30 + '@aws-sdk/middleware-host-header': 3.972.9 + '@aws-sdk/middleware-logger': 3.972.9 + '@aws-sdk/middleware-recursion-detection': 3.972.10 + '@aws-sdk/middleware-user-agent': 3.972.29 + '@aws-sdk/region-config-resolver': 3.972.11 + '@aws-sdk/types': 3.973.7 + '@aws-sdk/util-endpoints': 3.996.6 + '@aws-sdk/util-user-agent-browser': 3.972.9 + '@aws-sdk/util-user-agent-node': 3.973.15 '@smithy/config-resolver': 4.4.14 '@smithy/core': 3.23.14 '@smithy/eventstream-serde-browser': 4.2.13 @@ -5269,7 +5245,6 @@ snapshots: '@smithy/util-endpoints': 3.3.4 '@smithy/util-middleware': 4.2.13 '@smithy/util-retry': 4.3.0 - '@smithy/util-stream': 4.5.22 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 transitivePeerDependencies: @@ -5394,10 +5369,10 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@aws-sdk/core@3.973.26': + '@aws-sdk/core@3.973.27': dependencies: - '@aws-sdk/types': 3.973.6 - '@aws-sdk/xml-builder': 3.972.16 + '@aws-sdk/types': 3.973.7 + '@aws-sdk/xml-builder': 3.972.17 '@smithy/core': 3.23.14 '@smithy/node-config-provider': 4.3.13 '@smithy/property-provider': 4.2.13 @@ -5418,10 +5393,10 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.972.24': + '@aws-sdk/credential-provider-env@3.972.25': dependencies: - '@aws-sdk/core': 3.973.26 - '@aws-sdk/types': 3.973.6 + '@aws-sdk/core': 3.973.27 + '@aws-sdk/types': 3.973.7 '@smithy/property-provider': 4.2.13 '@smithy/types': 4.14.0 tslib: 2.8.1 @@ -5439,10 +5414,10 @@ snapshots: '@smithy/util-stream': 4.5.7 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.972.26': + '@aws-sdk/credential-provider-http@3.972.27': dependencies: - '@aws-sdk/core': 3.973.26 - '@aws-sdk/types': 3.973.6 + '@aws-sdk/core': 3.973.27 + '@aws-sdk/types': 3.973.7 '@smithy/fetch-http-handler': 5.3.16 '@smithy/node-http-handler': 4.5.2 '@smithy/property-provider': 4.2.13 @@ -5471,17 +5446,17 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-ini@3.972.28': - dependencies: - '@aws-sdk/core': 3.973.26 - '@aws-sdk/credential-provider-env': 3.972.24 - '@aws-sdk/credential-provider-http': 3.972.26 - '@aws-sdk/credential-provider-login': 3.972.28 - '@aws-sdk/credential-provider-process': 3.972.24 - '@aws-sdk/credential-provider-sso': 3.972.28 - '@aws-sdk/credential-provider-web-identity': 3.972.28 - '@aws-sdk/nested-clients': 3.996.18 - '@aws-sdk/types': 3.973.6 + '@aws-sdk/credential-provider-ini@3.972.29': + dependencies: + '@aws-sdk/core': 3.973.27 + '@aws-sdk/credential-provider-env': 3.972.25 + '@aws-sdk/credential-provider-http': 3.972.27 + '@aws-sdk/credential-provider-login': 3.972.29 + '@aws-sdk/credential-provider-process': 3.972.25 + '@aws-sdk/credential-provider-sso': 3.972.29 + '@aws-sdk/credential-provider-web-identity': 3.972.29 + '@aws-sdk/nested-clients': 3.996.19 + '@aws-sdk/types': 3.973.7 '@smithy/credential-provider-imds': 4.2.13 '@smithy/property-provider': 4.2.13 '@smithy/shared-ini-file-loader': 4.4.8 @@ -5503,11 +5478,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-login@3.972.28': + '@aws-sdk/credential-provider-login@3.972.29': dependencies: - '@aws-sdk/core': 3.973.26 - '@aws-sdk/nested-clients': 3.996.18 - '@aws-sdk/types': 3.973.6 + '@aws-sdk/core': 3.973.27 + '@aws-sdk/nested-clients': 3.996.19 + '@aws-sdk/types': 3.973.7 '@smithy/property-provider': 4.2.13 '@smithy/protocol-http': 5.3.13 '@smithy/shared-ini-file-loader': 4.4.8 @@ -5533,15 +5508,15 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.972.29': + '@aws-sdk/credential-provider-node@3.972.30': dependencies: - '@aws-sdk/credential-provider-env': 3.972.24 - '@aws-sdk/credential-provider-http': 3.972.26 - '@aws-sdk/credential-provider-ini': 3.972.28 - '@aws-sdk/credential-provider-process': 3.972.24 - '@aws-sdk/credential-provider-sso': 3.972.28 - '@aws-sdk/credential-provider-web-identity': 3.972.28 - '@aws-sdk/types': 3.973.6 + '@aws-sdk/credential-provider-env': 3.972.25 + '@aws-sdk/credential-provider-http': 3.972.27 + '@aws-sdk/credential-provider-ini': 3.972.29 + '@aws-sdk/credential-provider-process': 3.972.25 + '@aws-sdk/credential-provider-sso': 3.972.29 + '@aws-sdk/credential-provider-web-identity': 3.972.29 + '@aws-sdk/types': 3.973.7 '@smithy/credential-provider-imds': 4.2.13 '@smithy/property-provider': 4.2.13 '@smithy/shared-ini-file-loader': 4.4.8 @@ -5559,10 +5534,10 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-process@3.972.24': + '@aws-sdk/credential-provider-process@3.972.25': dependencies: - '@aws-sdk/core': 3.973.26 - '@aws-sdk/types': 3.973.6 + '@aws-sdk/core': 3.973.27 + '@aws-sdk/types': 3.973.7 '@smithy/property-provider': 4.2.13 '@smithy/shared-ini-file-loader': 4.4.8 '@smithy/types': 4.14.0 @@ -5581,12 +5556,12 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-sso@3.972.28': + '@aws-sdk/credential-provider-sso@3.972.29': dependencies: - '@aws-sdk/core': 3.973.26 - '@aws-sdk/nested-clients': 3.996.18 - '@aws-sdk/token-providers': 3.1021.0 - '@aws-sdk/types': 3.973.6 + '@aws-sdk/core': 3.973.27 + '@aws-sdk/nested-clients': 3.996.19 + '@aws-sdk/token-providers': 3.1026.0 + '@aws-sdk/types': 3.973.7 '@smithy/property-provider': 4.2.13 '@smithy/shared-ini-file-loader': 4.4.8 '@smithy/types': 4.14.0 @@ -5606,11 +5581,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-web-identity@3.972.28': + '@aws-sdk/credential-provider-web-identity@3.972.29': dependencies: - '@aws-sdk/core': 3.973.26 - '@aws-sdk/nested-clients': 3.996.18 - '@aws-sdk/types': 3.973.6 + '@aws-sdk/core': 3.973.27 + '@aws-sdk/nested-clients': 3.996.19 + '@aws-sdk/types': 3.973.7 '@smithy/property-provider': 4.2.13 '@smithy/shared-ini-file-loader': 4.4.8 '@smithy/types': 4.14.0 @@ -5618,13 +5593,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/eventstream-handler-node@3.972.12': - dependencies: - '@aws-sdk/types': 3.973.6 - '@smithy/eventstream-codec': 4.2.13 - '@smithy/types': 4.14.0 - tslib: 2.8.1 - '@aws-sdk/middleware-bucket-endpoint@3.953.0': dependencies: '@aws-sdk/types': 3.953.0 @@ -5635,13 +5603,6 @@ snapshots: '@smithy/util-config-provider': 4.2.0 tslib: 2.8.1 - '@aws-sdk/middleware-eventstream@3.972.8': - dependencies: - '@aws-sdk/types': 3.973.6 - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 - tslib: 2.8.1 - '@aws-sdk/middleware-expect-continue@3.953.0': dependencies: '@aws-sdk/types': 3.953.0 @@ -5672,9 +5633,9 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.972.8': + '@aws-sdk/middleware-host-header@3.972.9': dependencies: - '@aws-sdk/types': 3.973.6 + '@aws-sdk/types': 3.973.7 '@smithy/protocol-http': 5.3.13 '@smithy/types': 4.14.0 tslib: 2.8.1 @@ -5691,9 +5652,9 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.972.8': + '@aws-sdk/middleware-logger@3.972.9': dependencies: - '@aws-sdk/types': 3.973.6 + '@aws-sdk/types': 3.973.7 '@smithy/types': 4.14.0 tslib: 2.8.1 @@ -5705,9 +5666,9 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.972.9': + '@aws-sdk/middleware-recursion-detection@3.972.10': dependencies: - '@aws-sdk/types': 3.973.6 + '@aws-sdk/types': 3.973.7 '@aws/lambda-invoke-store': 0.2.2 '@smithy/protocol-http': 5.3.13 '@smithy/types': 4.14.0 @@ -5746,32 +5707,17 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.972.28': + '@aws-sdk/middleware-user-agent@3.972.29': dependencies: - '@aws-sdk/core': 3.973.26 - '@aws-sdk/types': 3.973.6 - '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/core': 3.973.27 + '@aws-sdk/types': 3.973.7 + '@aws-sdk/util-endpoints': 3.996.6 '@smithy/core': 3.23.14 '@smithy/protocol-http': 5.3.13 '@smithy/types': 4.14.0 '@smithy/util-retry': 4.3.0 tslib: 2.8.1 - '@aws-sdk/middleware-websocket@3.972.14': - dependencies: - '@aws-sdk/types': 3.973.6 - '@aws-sdk/util-format-url': 3.972.8 - '@smithy/eventstream-codec': 4.2.13 - '@smithy/eventstream-serde-browser': 4.2.13 - '@smithy/fetch-http-handler': 5.3.16 - '@smithy/protocol-http': 5.3.13 - '@smithy/signature-v4': 5.3.13 - '@smithy/types': 4.14.0 - '@smithy/util-base64': 4.3.2 - '@smithy/util-hex-encoding': 4.2.2 - '@smithy/util-utf8': 4.2.2 - tslib: 2.8.1 - '@aws-sdk/nested-clients@3.954.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -5815,20 +5761,20 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/nested-clients@3.996.18': + '@aws-sdk/nested-clients@3.996.19': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.26 - '@aws-sdk/middleware-host-header': 3.972.8 - '@aws-sdk/middleware-logger': 3.972.8 - '@aws-sdk/middleware-recursion-detection': 3.972.9 - '@aws-sdk/middleware-user-agent': 3.972.28 - '@aws-sdk/region-config-resolver': 3.972.10 - '@aws-sdk/types': 3.973.6 - '@aws-sdk/util-endpoints': 3.996.5 - '@aws-sdk/util-user-agent-browser': 3.972.8 - '@aws-sdk/util-user-agent-node': 3.973.14 + '@aws-sdk/core': 3.973.27 + '@aws-sdk/middleware-host-header': 3.972.9 + '@aws-sdk/middleware-logger': 3.972.9 + '@aws-sdk/middleware-recursion-detection': 3.972.10 + '@aws-sdk/middleware-user-agent': 3.972.29 + '@aws-sdk/region-config-resolver': 3.972.11 + '@aws-sdk/types': 3.973.7 + '@aws-sdk/util-endpoints': 3.996.6 + '@aws-sdk/util-user-agent-browser': 3.972.9 + '@aws-sdk/util-user-agent-node': 3.973.15 '@smithy/config-resolver': 4.4.14 '@smithy/core': 3.23.14 '@smithy/fetch-http-handler': 5.3.16 @@ -5866,9 +5812,9 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 - '@aws-sdk/region-config-resolver@3.972.10': + '@aws-sdk/region-config-resolver@3.972.11': dependencies: - '@aws-sdk/types': 3.973.6 + '@aws-sdk/types': 3.973.7 '@smithy/config-resolver': 4.4.14 '@smithy/node-config-provider': 4.3.13 '@smithy/types': 4.14.0 @@ -5894,23 +5840,11 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 - '@aws-sdk/token-providers@3.1021.0': - dependencies: - '@aws-sdk/core': 3.973.26 - '@aws-sdk/nested-clients': 3.996.18 - '@aws-sdk/types': 3.973.6 - '@smithy/property-provider': 4.2.13 - '@smithy/shared-ini-file-loader': 4.4.8 - '@smithy/types': 4.14.0 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/token-providers@3.1025.0': + '@aws-sdk/token-providers@3.1026.0': dependencies: - '@aws-sdk/core': 3.973.26 - '@aws-sdk/nested-clients': 3.996.18 - '@aws-sdk/types': 3.973.6 + '@aws-sdk/core': 3.973.27 + '@aws-sdk/nested-clients': 3.996.19 + '@aws-sdk/types': 3.973.7 '@smithy/property-provider': 4.2.13 '@smithy/shared-ini-file-loader': 4.4.8 '@smithy/types': 4.14.0 @@ -5935,7 +5869,7 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 - '@aws-sdk/types@3.973.6': + '@aws-sdk/types@3.973.7': dependencies: '@smithy/types': 4.14.0 tslib: 2.8.1 @@ -5952,9 +5886,9 @@ snapshots: '@smithy/util-endpoints': 3.2.6 tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.996.5': + '@aws-sdk/util-endpoints@3.996.6': dependencies: - '@aws-sdk/types': 3.973.6 + '@aws-sdk/types': 3.973.7 '@smithy/types': 4.14.0 '@smithy/url-parser': 4.2.13 '@smithy/util-endpoints': 3.3.4 @@ -5967,13 +5901,6 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 - '@aws-sdk/util-format-url@3.972.8': - dependencies: - '@aws-sdk/types': 3.973.6 - '@smithy/querystring-builder': 4.2.13 - '@smithy/types': 4.14.0 - tslib: 2.8.1 - '@aws-sdk/util-locate-window@3.953.0': dependencies: tslib: 2.8.1 @@ -5985,9 +5912,9 @@ snapshots: bowser: 2.13.1 tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.972.8': + '@aws-sdk/util-user-agent-browser@3.972.9': dependencies: - '@aws-sdk/types': 3.973.6 + '@aws-sdk/types': 3.973.7 '@smithy/types': 4.14.0 bowser: 2.13.1 tslib: 2.8.1 @@ -6000,10 +5927,10 @@ snapshots: '@smithy/types': 4.10.0 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.973.14': + '@aws-sdk/util-user-agent-node@3.973.15': dependencies: - '@aws-sdk/middleware-user-agent': 3.972.28 - '@aws-sdk/types': 3.973.6 + '@aws-sdk/middleware-user-agent': 3.972.29 + '@aws-sdk/types': 3.973.7 '@smithy/node-config-provider': 4.3.13 '@smithy/types': 4.14.0 '@smithy/util-config-provider': 4.2.2 @@ -6015,7 +5942,7 @@ snapshots: fast-xml-parser: 5.2.5 tslib: 2.8.1 - '@aws-sdk/xml-builder@3.972.16': + '@aws-sdk/xml-builder@3.972.17': dependencies: '@smithy/types': 4.14.0 fast-xml-parser: 5.5.8 From 8b3adf60c8bc91a9d33c3ec157754bcb9fcbcb86 Mon Sep 17 00:00:00 2001 From: Alvin Mei Date: Thu, 9 Apr 2026 15:57:22 -0400 Subject: [PATCH 4/8] verified working chat --- apps/www/public/wafir.yaml | 5 -- internal/wafir-dev/public/wafir.yaml | 74 ++++++++++++++-------------- 2 files changed, 36 insertions(+), 43 deletions(-) diff --git a/apps/www/public/wafir.yaml b/apps/www/public/wafir.yaml index ba04e11..5966ca4 100644 --- a/apps/www/public/wafir.yaml +++ b/apps/www/public/wafir.yaml @@ -124,8 +124,3 @@ forms: type: markdown attributes: value: "Please ask your question in our [GitHub Discussions forum](https://github.com/BPS-Consulting/wafir/discussions)." - - id: chat - type: chat - attributes: - label: "Chat with us" - placeholder: "Type your message here..." diff --git a/internal/wafir-dev/public/wafir.yaml b/internal/wafir-dev/public/wafir.yaml index fbc2fc0..ba04e11 100644 --- a/internal/wafir-dev/public/wafir.yaml +++ b/internal/wafir-dev/public/wafir.yaml @@ -1,4 +1,4 @@ -# Wafir config for internal testing. Targets Wafir repo. +# Wafir widget configuration for the public Wafir GitHub Pages site title: "Contact Us" @@ -15,13 +15,21 @@ targets: forms: - id: feedback label: Feedback - icon: πŸ‘ + icon: "πŸ‘" + labels: + - feedback targets: [project] body: - id: rating type: rating attributes: - label: "How satisfied are you with our website?" + label: "How satisfied are you with Wafir?" + options: + - "Very Unsatisfied" + - "Unsatisfied" + - "Neutral" + - "Satisfied" + - "Excellent" validations: required: true - id: description @@ -30,17 +38,12 @@ forms: label: "What is the main reason for this rating?" validations: required: false - - id: submitted - type: date - display: none - attributes: - value: "today" - validations: - required: true - - id: feature + - id: suggestion label: Suggestion - icon: πŸ’‘ + icon: "πŸ’‘" + labels: + - enhancement targets: [project] body: - id: title @@ -61,12 +64,9 @@ forms: attributes: label: "Business value" options: - - label: "Low" - value: "Low" - - label: "Medium" - value: "Medium" - - label: "High" - value: "High" + - "Low" + - "Medium" + - "High" validations: required: false - id: needed @@ -74,33 +74,32 @@ forms: attributes: label: "Needed" options: - - label: "Later" - value: "Later" - - label: "Soon" - value: "Soon" - - label: "Now" - value: "Now" + - "Later" + - "Soon" + - "Now" validations: required: false - - id: bug + - id: issue label: Issue - icon: πŸ› + icon: "🐞" + labels: + - bug targets: [default] body: - id: title type: input attributes: - label: "Issue Title" + label: "What issue did you encounter?" validations: required: true - id: description type: textarea attributes: - label: "Describe the issue" + label: "Additional information:" + placeholder: "Please include steps to reproduce and expected vs actual behavior" validations: required: true - # Opt-in telemetry fields - id: browser-info type: textarea attributes: @@ -108,13 +107,6 @@ forms: autofill: browserInfo validations: required: false - - id: console-logs - type: textarea - attributes: - label: "Console Logs" - autofill: consoleLog - validations: - required: false - id: screenshot type: textarea attributes: @@ -124,10 +116,16 @@ forms: required: false - id: question - label: ❓Question + label: Question + icon: "❓" targets: [] body: - id: info type: markdown attributes: - value: "Please ask your question in our GitHub Discussions forum: https://github.com/BPS-Consulting/wafir/discussions" + value: "Please ask your question in our [GitHub Discussions forum](https://github.com/BPS-Consulting/wafir/discussions)." + - id: chat + type: chat + attributes: + label: "Chat with us" + placeholder: "Type your message here..." From da890fb203655e20f0a294c7244265d8e442ee90 Mon Sep 17 00:00:00 2001 From: Alvin Mei Date: Thu, 9 Apr 2026 15:58:14 -0400 Subject: [PATCH 5/8] added wafir example --- examples/chat/wafir.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 examples/chat/wafir.yaml diff --git a/examples/chat/wafir.yaml b/examples/chat/wafir.yaml new file mode 100644 index 0000000..ef9c9c1 --- /dev/null +++ b/examples/chat/wafir.yaml @@ -0,0 +1,25 @@ +# WAFIR Configuration Example - Chat + +title: "Submit Feedback" + +targets: + - id: default + type: github/project + target: your-username/1 + authRef: "YOUR_INSTALLATION_ID" # Replace with your installation ID + +forms: + - id: question + label: Question + icon: "❓" + targets: [] + body: + - id: info + type: markdown + attributes: + value: "Please ask your question in our [GitHub Discussions forum](https://github.com/BPS-Consulting/wafir/discussions)." + - id: chat + type: chat + attributes: + label: "Chat with us" + placeholder: "Type your message here..." From e9a3f178348ba7cbfc72d7b7998a9a263e40250d Mon Sep 17 00:00:00 2001 From: Alvin Mei Date: Thu, 9 Apr 2026 17:16:00 -0400 Subject: [PATCH 6/8] format --- apps/bridge/swagger.json | 102 +-- packages/wafir/src/api/index.ts | 1287 ++++++++++++++++--------------- 2 files changed, 673 insertions(+), 716 deletions(-) diff --git a/apps/bridge/swagger.json b/apps/bridge/swagger.json index b506bb2..74e0c09 100644 --- a/apps/bridge/swagger.json +++ b/apps/bridge/swagger.json @@ -12,9 +12,7 @@ "/auth/github": { "get": { "summary": "Initiate GitHub OAuth", - "tags": [ - "Auth" - ], + "tags": ["Auth"], "description": "Redirects to GitHub OAuth for user authorization", "parameters": [ { @@ -44,9 +42,7 @@ "/auth/github/callback": { "get": { "summary": "GitHub OAuth Callback", - "tags": [ - "Auth" - ], + "tags": ["Auth"], "description": "Handles OAuth callback from GitHub", "parameters": [ { @@ -76,9 +72,7 @@ "/auth/status/{installationId}": { "get": { "summary": "Check Auth Status", - "tags": [ - "Auth" - ], + "tags": ["Auth"], "description": "Check if user token exists for installation", "parameters": [ { @@ -115,9 +109,7 @@ "/auth/{installationId}": { "delete": { "summary": "Disconnect Auth", - "tags": [ - "Auth" - ], + "tags": ["Auth"], "description": "Remove stored user token for installation", "parameters": [ { @@ -139,18 +131,14 @@ "/chat/": { "post": { "summary": "Send a chat message", - "tags": [ - "Chat" - ], + "tags": ["Chat"], "description": "Sends a message to the AI chat service and returns a response. Only authorized origins can use this endpoint.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", - "required": [ - "message" - ], + "required": ["message"], "properties": { "message": { "type": "string", @@ -201,9 +189,7 @@ "/config/": { "get": { "summary": "Get WAFIR Configuration", - "tags": [ - "WAFIR" - ], + "tags": ["WAFIR"], "description": "Fetches and parses a wafir configuration file from a user-provided URL. The URL should point to a raw YAML or JSON configuration file.", "parameters": [ { @@ -224,9 +210,7 @@ "application/json": { "schema": { "type": "object", - "required": [ - "targets" - ], + "required": ["targets"], "properties": { "title": { "type": "string", @@ -239,12 +223,7 @@ "description": "Target destinations for form submissions. Each target defines where and how submissions are stored.", "items": { "type": "object", - "required": [ - "id", - "type", - "target", - "authRef" - ], + "required": ["id", "type", "target", "authRef"], "properties": { "id": { "type": "string", @@ -252,10 +231,7 @@ }, "type": { "type": "string", - "enum": [ - "github/issues", - "github/project" - ], + "enum": ["github/issues", "github/project"], "description": "Target type using MIME-type convention. Currently supported: github/issues, github/project." }, "target": { @@ -274,9 +250,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "id" - ], + "required": ["id"], "properties": { "id": { "type": "string", @@ -294,9 +268,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "type" - ], + "required": ["type"], "properties": { "type": { "type": "string", @@ -319,10 +291,7 @@ }, "display": { "type": "string", - "enum": [ - "visible", - "none" - ], + "enum": ["visible", "none"], "default": "visible", "description": "Controls field visibility. 'none' hides the field from the UI but still includes its value in submissions. Defaults to 'visible'." }, @@ -371,9 +340,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "label" - ], + "required": ["label"], "properties": { "label": { "type": "string" @@ -503,9 +470,7 @@ "/config/template": { "get": { "summary": "Get GitHub Issue Form Template", - "tags": [ - "WAFIR" - ], + "tags": ["WAFIR"], "description": "Fetches and parses a GitHub Issue Form template from a user-provided URL. Returns the body (fields) and labels from the template.", "parameters": [ { @@ -543,9 +508,7 @@ "description": "Labels from the template" } }, - "required": [ - "body" - ] + "required": ["body"] } } } @@ -592,19 +555,14 @@ "/generate/": { "post": { "summary": "Generate Sample Config", - "tags": [ - "WAFIR" - ], + "tags": ["WAFIR"], "description": "Generates a sample wafir.yaml configuration file based on GitHub repository labels and project fields. Provide your installation ID and an array of targets to analyze. Returns the config as plain text YAML.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", - "required": [ - "installationId", - "targets" - ], + "required": ["installationId", "targets"], "properties": { "installationId": { "type": "number", @@ -615,17 +573,11 @@ "description": "Array of targets to analyze", "items": { "type": "object", - "required": [ - "type", - "target" - ], + "required": ["type", "target"], "properties": { "type": { "type": "string", - "enum": [ - "github/issues", - "github/project" - ], + "enum": ["github/issues", "github/project"], "description": "Target type" }, "target": { @@ -696,9 +648,7 @@ "/health/": { "get": { "summary": "Health Check", - "tags": [ - "Health" - ], + "tags": ["Health"], "description": "Returns the health status of the bridge service", "responses": { "200": { @@ -725,9 +675,7 @@ "/notifications/": { "post": { "summary": "Store Notification", - "tags": [ - "WAFIR" - ], + "tags": ["WAFIR"], "description": "Accepts a JSON payload and stores it in S3 in the notifications folder.", "requestBody": { "content": { @@ -785,9 +733,7 @@ "/submit/": { "post": { "summary": "Submit Feedback/Issue", - "tags": [ - "WAFIR" - ], + "tags": ["WAFIR"], "description": "Creates a GitHub issue or project draft from form fields. Supports multipart/form-data.", "responses": { "200": { @@ -803,4 +749,4 @@ "description": "Local Development Server" } ] -} \ No newline at end of file +} diff --git a/packages/wafir/src/api/index.ts b/packages/wafir/src/api/index.ts index 415696f..55b5893 100644 --- a/packages/wafir/src/api/index.ts +++ b/packages/wafir/src/api/index.ts @@ -4,691 +4,702 @@ */ export interface paths { - "/auth/github": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + "/auth/github": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Initiate GitHub OAuth + * @description Redirects to GitHub OAuth for user authorization + */ + get: { + parameters: { + query: { + installationId: string; + returnUrl?: string; }; - /** - * Initiate GitHub OAuth - * @description Redirects to GitHub OAuth for user authorization - */ - get: { - parameters: { - query: { - installationId: string; - returnUrl?: string; - }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; }; - "/auth/github/callback": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/auth/github/callback": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * GitHub OAuth Callback + * @description Handles OAuth callback from GitHub + */ + get: { + parameters: { + query: { + code: string; + state: string; }; - /** - * GitHub OAuth Callback - * @description Handles OAuth callback from GitHub - */ - get: { - parameters: { - query: { - code: string; - state: string; - }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/auth/status/{installationId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/auth/status/{installationId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + /** + * Check Auth Status + * @description Check if user token exists for installation + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + installationId: string; }; - /** - * Check Auth Status - * @description Check if user token exists for installation - */ - get: { - parameters: { - query?: never; - header?: never; - path: { - installationId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - connected?: boolean; - installationId?: number; - }; - }; - }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + connected?: boolean; + installationId?: number; }; + }; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/auth/{installationId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/auth/{installationId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + get?: never; + put?: never; + post?: never; + /** + * Disconnect Auth + * @description Remove stored user token for installation + */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + installationId: string; }; - get?: never; - put?: never; - post?: never; - /** - * Disconnect Auth - * @description Remove stored user token for installation - */ - delete: { - parameters: { - query?: never; - header?: never; - path: { - installationId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/chat/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/chat/": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + get?: never; + put?: never; + /** + * Send a chat message + * @description Sends a message to the AI chat service and returns a response. Only authorized origins can use this endpoint. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description The user's message to send to the chat service */ + message: string; + }; }; - get?: never; - put?: never; - /** - * Send a chat message - * @description Sends a message to the AI chat service and returns a response. Only authorized origins can use this endpoint. - */ - post: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + }; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description The AI's response */ + reply?: string; }; - requestBody: { - content: { - "application/json": { - /** @description The user's message to send to the chat service */ - message: string; - }; - }; - }; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - /** @description The AI's response */ - reply?: string; - }; - }; - }; - /** @description Default Response */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - /** @description Error message for unauthorized access */ - error?: string; - }; - }; - }; + }; + }; + /** @description Default Response */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error message for unauthorized access */ + error?: string; }; + }; }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; }; - "/config/": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/config/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get WAFIR Configuration + * @description Fetches and parses a wafir configuration file from a user-provided URL. The URL should point to a raw YAML or JSON configuration file. + */ + get: { + parameters: { + query: { + /** @description URL to the raw configuration file (YAML or JSON format) */ + configUrl: string; }; - /** - * Get WAFIR Configuration - * @description Fetches and parses a wafir configuration file from a user-provided URL. The URL should point to a raw YAML or JSON configuration file. - */ - get: { - parameters: { - query: { - /** @description URL to the raw configuration file (YAML or JSON format) */ - configUrl: string; - }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - /** - * @description Modal title - * @default Contact Us - */ - title: string; - /** @description Target destinations for form submissions. Each target defines where and how submissions are stored. */ - targets: { - /** @description Unique identifier for this target, referenced by forms to route submissions. */ - id: string; - /** - * @description Target type using MIME-type convention. Currently supported: github/issues, github/project. - * @enum {string} - */ - type: "github/issues" | "github/project"; - /** @description Target identifier. Format depends on type: 'owner/repo' for github/issues, 'owner/projectNum' for github/project. */ - target: string; - /** @description Authentication reference used to authorize communication with the target. For GitHub types, this is the installation ID. */ - authRef: string; - }[]; - /** @description Widget forms configuration. Forms are displayed as tabs in the UI. Defaults to feedback, suggestion, issue if omitted. */ - forms?: { - /** @description Unique form identifier */ - id: string; - /** @description Display label (defaults to capitalized id) */ - label?: string; - /** @description Form icon (displayed in tab UI). Can be any unicode character or emoji. Examples: 'πŸ‘', 'πŸ’‘', '🐞', '⭐', 'πŸ˜€'. */ - icon?: string; - /** @description Form body (fields) for this form. If omitted, defaults are used for known form IDs. */ - body?: { - /** - * @description Field input type. Matches GitHub Form Schema types plus Wafir extensions. - * @enum {string} - */ - type: "input" | "email" | "textarea" | "dropdown" | "checkboxes" | "markdown" | "rating" | "date" | "chat"; - /** @description Unique identifier for the field (used as key in JSON output/issue body). */ - id?: string; - /** - * @description Controls field visibility. 'none' hides the field from the UI but still includes its value in submissions. Defaults to 'visible'. - * @default visible - * @enum {string} - */ - display: "visible" | "none"; - /** @description Visual and behavioral attributes for the field. */ - attributes?: { - /** @description Display label for the field. */ - label?: string; - /** @description Helper text displayed below the label. */ - description?: string; - /** @description Placeholder text (input, textarea, email only). */ - placeholder?: string; - /** @description Default value or the Markdown content (markdown type). */ - value?: string; - /** @description Syntax highlighting style for textarea (e.g., 'shell', 'javascript'). */ - render?: string; - /** @description Allow multiple selections (dropdown type only). */ - multiple?: boolean; - /** @description Index of the pre-selected option in the options array (dropdown type only). */ - default?: number; - /** @description Options for dropdown, checkboxes, or rating fields. */ - options?: string[] | { - label: string; - required?: boolean; - }[]; - /** @description Unicode character/emoji used as the rating icon (rating type only). Defaults to ⭐. */ - icon?: string; - /** - * @description Auto-fill the field with telemetry data. When specified, renders an opt-in checkbox. Values: browserInfo (URL, user agent, viewport), screenshot (captured screenshot), consoleLog (recent console messages). - * @enum {string} - */ - autofill?: "browserInfo" | "screenshot" | "consoleLog"; - }; - validations?: { - /** @description Whether the field is required. */ - required?: boolean; - }; - }[]; - /** @description IDs of target(s) for this form. If omitted, all targets will be used. If an empty array ([]), no target is selectable and submissions will be disabled for this form (submissionless). Each ID must reference a valid target from the top-level targets array. */ - targets?: string[]; - /** @description Labels automatically added to issues created from this form. Similar to GitHub issue form templates. */ - labels?: string[]; - /** - * Format: uri - * @description URL to a GitHub issue form template YAML file. When provided, the form fields will be fetched from this template. - */ - templateUrl?: string; - }[]; - /** @description Available issue types from the organization (auto-populated) */ - issueTypes?: { - id?: number; - name?: string; - color?: string; - }[]; - }; - }; - }; - /** @description Default Response */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; - }; - }; - }; - /** @description Default Response */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; - }; - }; - }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description Modal title + * @default Contact Us + */ + title: string; + /** @description Target destinations for form submissions. Each target defines where and how submissions are stored. */ + targets: { + /** @description Unique identifier for this target, referenced by forms to route submissions. */ + id: string; + /** + * @description Target type using MIME-type convention. Currently supported: github/issues, github/project. + * @enum {string} + */ + type: "github/issues" | "github/project"; + /** @description Target identifier. Format depends on type: 'owner/repo' for github/issues, 'owner/projectNum' for github/project. */ + target: string; + /** @description Authentication reference used to authorize communication with the target. For GitHub types, this is the installation ID. */ + authRef: string; + }[]; + /** @description Widget forms configuration. Forms are displayed as tabs in the UI. Defaults to feedback, suggestion, issue if omitted. */ + forms?: { + /** @description Unique form identifier */ + id: string; + /** @description Display label (defaults to capitalized id) */ + label?: string; + /** @description Form icon (displayed in tab UI). Can be any unicode character or emoji. Examples: 'πŸ‘', 'πŸ’‘', '🐞', '⭐', 'πŸ˜€'. */ + icon?: string; + /** @description Form body (fields) for this form. If omitted, defaults are used for known form IDs. */ + body?: { + /** + * @description Field input type. Matches GitHub Form Schema types plus Wafir extensions. + * @enum {string} + */ + type: + | "input" + | "email" + | "textarea" + | "dropdown" + | "checkboxes" + | "markdown" + | "rating" + | "date" + | "chat"; + /** @description Unique identifier for the field (used as key in JSON output/issue body). */ + id?: string; + /** + * @description Controls field visibility. 'none' hides the field from the UI but still includes its value in submissions. Defaults to 'visible'. + * @default visible + * @enum {string} + */ + display: "visible" | "none"; + /** @description Visual and behavioral attributes for the field. */ + attributes?: { + /** @description Display label for the field. */ + label?: string; + /** @description Helper text displayed below the label. */ + description?: string; + /** @description Placeholder text (input, textarea, email only). */ + placeholder?: string; + /** @description Default value or the Markdown content (markdown type). */ + value?: string; + /** @description Syntax highlighting style for textarea (e.g., 'shell', 'javascript'). */ + render?: string; + /** @description Allow multiple selections (dropdown type only). */ + multiple?: boolean; + /** @description Index of the pre-selected option in the options array (dropdown type only). */ + default?: number; + /** @description Options for dropdown, checkboxes, or rating fields. */ + options?: + | string[] + | { + label: string; + required?: boolean; + }[]; + /** @description Unicode character/emoji used as the rating icon (rating type only). Defaults to ⭐. */ + icon?: string; + /** + * @description Auto-fill the field with telemetry data. When specified, renders an opt-in checkbox. Values: browserInfo (URL, user agent, viewport), screenshot (captured screenshot), consoleLog (recent console messages). + * @enum {string} + */ + autofill?: "browserInfo" | "screenshot" | "consoleLog"; + }; + validations?: { + /** @description Whether the field is required. */ + required?: boolean; + }; + }[]; + /** @description IDs of target(s) for this form. If omitted, all targets will be used. If an empty array ([]), no target is selectable and submissions will be disabled for this form (submissionless). Each ID must reference a valid target from the top-level targets array. */ + targets?: string[]; + /** @description Labels automatically added to issues created from this form. Similar to GitHub issue form templates. */ + labels?: string[]; + /** + * Format: uri + * @description URL to a GitHub issue form template YAML file. When provided, the form fields will be fetched from this template. + */ + templateUrl?: string; + }[]; + /** @description Available issue types from the organization (auto-populated) */ + issueTypes?: { + id?: number; + name?: string; + color?: string; + }[]; }; + }; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/config/template": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** - * Get GitHub Issue Form Template - * @description Fetches and parses a GitHub Issue Form template from a user-provided URL. Returns the body (fields) and labels from the template. - */ - get: { - parameters: { - query: { - /** @description URL to the raw template file (YAML format) */ - templateUrl: string; - }; - header?: never; - path?: never; - cookie?: never; + /** @description Default Response */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - /** @description Array of form fields from the template */ - body: { - [key: string]: unknown; - }[]; - /** @description Labels from the template */ - labels?: string[]; - }; - }; - }; - /** @description Default Response */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; - }; - }; - }; - /** @description Default Response */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; - }; - }; - }; + }; + }; + /** @description Default Response */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; }; + }; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/config/template": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/generate/": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + /** + * Get GitHub Issue Form Template + * @description Fetches and parses a GitHub Issue Form template from a user-provided URL. Returns the body (fields) and labels from the template. + */ + get: { + parameters: { + query: { + /** @description URL to the raw template file (YAML format) */ + templateUrl: string; }; - get?: never; - put?: never; - /** - * Generate Sample Config - * @description Generates a sample wafir.yaml configuration file based on GitHub repository labels and project fields. Provide your installation ID and an array of targets to analyze. Returns the config as plain text YAML. - */ - post: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Array of form fields from the template */ + body: { + [key: string]: unknown; + }[]; + /** @description Labels from the template */ + labels?: string[]; }; - requestBody: { - content: { - "application/json": { - /** @description Your GitHub App installation ID */ - installationId: number; - /** @description Array of targets to analyze */ - targets: { - /** - * @description Target type - * @enum {string} - */ - type: "github/issues" | "github/project"; - /** @description Target identifier: "owner/repo" for issues, "owner/projectNumber" for projects */ - target: string; - }[]; - }; - }; + }; + }; + /** @description Default Response */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; }; - responses: { - /** @description Generated wafir.yaml configuration content */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": string; - }; - }; - /** @description Default Response */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; - }; - }; - }; - /** @description Default Response */ - 500: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; - }; - }; - }; + }; + }; + /** @description Default Response */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; }; + }; }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/generate/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/health/": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + get?: never; + put?: never; + /** + * Generate Sample Config + * @description Generates a sample wafir.yaml configuration file based on GitHub repository labels and project fields. Provide your installation ID and an array of targets to analyze. Returns the config as plain text YAML. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Your GitHub App installation ID */ + installationId: number; + /** @description Array of targets to analyze */ + targets: { + /** + * @description Target type + * @enum {string} + */ + type: "github/issues" | "github/project"; + /** @description Target identifier: "owner/repo" for issues, "owner/projectNumber" for projects */ + target: string; + }[]; + }; }; - /** - * Health Check - * @description Returns the health status of the bridge service - */ - get: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + }; + responses: { + /** @description Generated wafir.yaml configuration content */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": string; + }; + }; + /** @description Default Response */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - status?: string; - timestamp?: string; - }; - }; - }; + }; + }; + /** @description Default Response */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; }; + }; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; }; - "/notifications/": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - /** - * Store Notification - * @description Accepts a JSON payload and stores it in S3 in the notifications folder. - */ - post: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: { - content: { - "application/json": { - [key: string]: unknown; - }; - }; - }; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - success?: boolean; - filename?: string; - message?: string; - }; - }; - }; - /** @description Default Response */ - 500: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error?: string; - message?: string; - }; - }; - }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/health/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Health Check + * @description Returns the health status of the bridge service + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + status?: string; + timestamp?: string; }; + }; }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/notifications/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/submit/": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + get?: never; + put?: never; + /** + * Store Notification + * @description Accepts a JSON payload and stores it in S3 in the notifications folder. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + [key: string]: unknown; + }; }; - get?: never; - put?: never; - /** - * Submit Feedback/Issue - * @description Creates a GitHub issue or project draft from form fields. Supports multipart/form-data. - */ - post: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + }; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + success?: boolean; + filename?: string; + message?: string; }; - requestBody?: never; - responses: { - /** @description Default Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; + }; + }; + /** @description Default Response */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error?: string; + message?: string; }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/submit/": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit Feedback/Issue + * @description Creates a GitHub issue or project draft from form fields. Supports multipart/form-data. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; } export type webhooks = Record; export interface components { - schemas: never; - responses: never; - parameters: never; - requestBodies: never; - headers: never; - pathItems: never; + schemas: never; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; } export type $defs = Record; export type operations = Record; From c400c6e3f2ea7394e78bd280229317a1389156cc Mon Sep 17 00:00:00 2001 From: Alvin Mei Date: Fri, 10 Apr 2026 11:19:14 -0400 Subject: [PATCH 7/8] parses markdown from agent --- packages/wafir/src/utils/markdown.ts | 47 +++++++++++++------------- packages/wafir/src/wafir-chat-field.ts | 6 +++- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/packages/wafir/src/utils/markdown.ts b/packages/wafir/src/utils/markdown.ts index bfce8d5..8909bc6 100644 --- a/packages/wafir/src/utils/markdown.ts +++ b/packages/wafir/src/utils/markdown.ts @@ -1,15 +1,12 @@ /** * Lightweight markdown parser for basic formatting. - * Supports: headings, bold, italic, links, lists, code blocks, inline code. - * This is a minimal alternative to marked (~40KB) for simple use cases. */ - export function parseMarkdown(markdown: string): string { if (!markdown) return ""; let html = markdown; - // Escape HTML to prevent XSS (basic sanitization) + // Escape HTML to prevent XSS html = html .replace(/&/g, "&") .replace(/ { return `
${code.trim()}
`; }); @@ -25,7 +22,7 @@ export function parseMarkdown(markdown: string): string { // Inline code html = html.replace(/`([^`]+)`/g, "$1"); - // Headers (h1-h6) + // Headers html = html.replace(/^######\s+(.+)$/gm, "
$1
"); html = html.replace(/^#####\s+(.+)$/gm, "
$1
"); html = html.replace(/^####\s+(.+)$/gm, "

$1

"); @@ -33,31 +30,33 @@ export function parseMarkdown(markdown: string): string { html = html.replace(/^##\s+(.+)$/gm, "

$1

"); html = html.replace(/^#\s+(.+)$/gm, "

$1

"); - // Bold (**text** or __text__) + // Lists + // Process Unordered Lists: wrap each line in
  • ...
+ html = html.replace(/^[\*\-]\s+(.+)$/gm, "
  • $1
"); + + // Process Ordered Lists: capture the number and wrap in
  1. ...
+ html = html.replace(/^(\d+)\.\s+(.+)$/gm, (match, num, content) => { + return `
  1. ${content}
`; + }); + + // Merge adjacent
    tags + html = html.replace(/<\/ul>\s?
      /g, ""); + + // Merge adjacent
        tags + // This logic keeps the 'start' attribute of the FIRST list item in a sequence + html = html.replace(/<\/ol>\s?
          /g, ""); + + // Bold & Italic html = html.replace(/\*\*(.+?)\*\*/g, "$1"); html = html.replace(/__(.+?)__/g, "$1"); - - // Italic (*text* or _text_) html = html.replace(/\*(.+?)\*/g, "$1"); html = html.replace(/_(.+?)_/g, "$1"); - // Links [text](url) + // Links html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); - // Unordered lists - html = html.replace(/^[\*\-]\s+(.+)$/gm, "
        1. $1
        2. "); - html = html.replace(/(
        3. .*<\/li>\n?)+/g, "
            $&
          "); - - // Ordered lists - html = html.replace(/^\d+\.\s+(.+)$/gm, "
        4. $1
        5. "); - html = html.replace(/(
        6. .*<\/li>\n?)+/g, (match) => { - if (!match.includes("
            ")) { - return `
              ${match}
            `; - } - return match; - }); - - // Line breaks (double newline ->
            ) + // Line breaks (Double newline to

            ) + // We exclude breaks inside list tags or pre tags to keep formatting clean html = html.replace(/\n\n/g, "

            "); return html; diff --git a/packages/wafir/src/wafir-chat-field.ts b/packages/wafir/src/wafir-chat-field.ts index 45164d3..5cc7637 100644 --- a/packages/wafir/src/wafir-chat-field.ts +++ b/packages/wafir/src/wafir-chat-field.ts @@ -3,6 +3,8 @@ import { LitElement, html, unsafeCSS } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import chatFieldStyles from "./styles/wafir-chat-field.css?inline"; import { sendChatMessage } from "./api/client.js"; +import { unsafeHTML } from "lit/directives/unsafe-html.js"; +import { parseMarkdown } from "./utils/markdown.js"; interface ChatMessage { role: "user" | "assistant" | "error"; @@ -158,7 +160,9 @@ export class WafirChatField extends LitElement { return html` ${this._messages.map( (msg) => html` -
            ${msg.content}
            +
            + ${unsafeHTML(parseMarkdown(msg.content))} +
            `, )} ${this._isLoading From 6bb18fc1543c43bbf91d87c9c428e154bb51b448 Mon Sep 17 00:00:00 2001 From: Alvin Mei Date: Fri, 10 Apr 2026 11:23:50 -0400 Subject: [PATCH 8/8] fixed linting problem --- packages/wafir/src/utils/markdown.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wafir/src/utils/markdown.ts b/packages/wafir/src/utils/markdown.ts index 8909bc6..71d618f 100644 --- a/packages/wafir/src/utils/markdown.ts +++ b/packages/wafir/src/utils/markdown.ts @@ -35,7 +35,7 @@ export function parseMarkdown(markdown: string): string { html = html.replace(/^[\*\-]\s+(.+)$/gm, "
            • $1
            "); // Process Ordered Lists: capture the number and wrap in
            1. ...
            - html = html.replace(/^(\d+)\.\s+(.+)$/gm, (match, num, content) => { + html = html.replace(/^(\d+)\.\s+(.+)$/gm, (_match, num, content) => { return `
            1. ${content}
            `; });