From d0d3581605188caf544422467bf9e0264d3803e4 Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Tue, 7 Apr 2026 15:30:46 -0700 Subject: [PATCH 01/15] feat(posthog): Add tracking on mothership abort (#4023) Co-authored-by: Theodore Li --- .../app/workspace/[workspaceId]/home/home.tsx | 12 ++++++++++-- .../w/[workflowId]/components/panel/panel.tsx | 19 ++++++++++++++++++- apps/sim/lib/posthog/events.ts | 5 +++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/home/home.tsx b/apps/sim/app/workspace/[workspaceId]/home/home.tsx index d76f17ff454..38367339197 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/home.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/home.tsx @@ -223,6 +223,14 @@ export function Home({ chatId }: HomeProps = {}) { posthogRef.current = posthog }, [posthog]) + const handleStopGeneration = useCallback(() => { + captureEvent(posthogRef.current, 'task_generation_aborted', { + workspace_id: workspaceId, + view: 'mothership', + }) + stopGeneration() + }, [stopGeneration, workspaceId]) + const handleSubmit = useCallback( (text: string, fileAttachments?: FileAttachmentForApi[], contexts?: ChatContext[]) => { const trimmed = text.trim() @@ -334,7 +342,7 @@ export function Home({ chatId }: HomeProps = {}) { defaultValue={initialPrompt} onSubmit={handleSubmit} isSending={isSending} - onStopGeneration={stopGeneration} + onStopGeneration={handleStopGeneration} userId={session?.user?.id} onContextAdd={handleContextAdd} /> @@ -359,7 +367,7 @@ export function Home({ chatId }: HomeProps = {}) { isSending={isSending} isReconnecting={isReconnecting} onSubmit={handleSubmit} - onStopGeneration={stopGeneration} + onStopGeneration={handleStopGeneration} messageQueue={messageQueue} onRemoveQueuedMessage={removeFromQueue} onSendQueuedMessage={sendNow} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx index 4d485c763ce..da51910789b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx @@ -4,6 +4,7 @@ import { memo, useCallback, useEffect, useRef, useState } from 'react' import { createLogger } from '@sim/logger' import { History, Plus, Square } from 'lucide-react' import { useParams, useRouter } from 'next/navigation' +import { usePostHog } from 'posthog-js/react' import { useShallow } from 'zustand/react/shallow' import { BubbleChatClose, @@ -33,6 +34,7 @@ import { import { Lock, Unlock, Upload } from '@/components/emcn/icons' import { VariableIcon } from '@/components/icons' import { useSession } from '@/lib/auth/auth-client' +import { captureEvent } from '@/lib/posthog/client' import { generateWorkflowJson } from '@/lib/workflows/operations/import-export' import { ConversationListItem } from '@/app/workspace/[workspaceId]/components' import { MothershipChat } from '@/app/workspace/[workspaceId]/home/components' @@ -101,6 +103,9 @@ export const Panel = memo(function Panel({ workspaceId: propWorkspaceId }: Panel const params = useParams() const workspaceId = propWorkspaceId ?? (params.workspaceId as string) + const posthog = usePostHog() + const posthogRef = useRef(posthog) + const panelRef = useRef(null) const fileInputRef = useRef(null) const { activeTab, setActiveTab, panelWidth, _hasHydrated, setHasHydrated } = usePanelStore( @@ -264,6 +269,10 @@ export const Panel = memo(function Panel({ workspaceId: propWorkspaceId }: Panel loadCopilotChats() }, [loadCopilotChats]) + useEffect(() => { + posthogRef.current = posthog + }, [posthog]) + const handleCopilotSelectChat = useCallback((chat: { id: string; title: string | null }) => { setCopilotChatId(chat.id) setCopilotChatTitle(chat.title) @@ -394,6 +403,14 @@ export const Panel = memo(function Panel({ workspaceId: propWorkspaceId }: Panel [copilotEditQueuedMessage] ) + const handleCopilotStopGeneration = useCallback(() => { + captureEvent(posthogRef.current, 'task_generation_aborted', { + workspace_id: workspaceId, + view: 'copilot', + }) + copilotStopGeneration() + }, [copilotStopGeneration, workspaceId]) + const handleCopilotSubmit = useCallback( (text: string, fileAttachments?: FileAttachmentForApi[], contexts?: ChatContext[]) => { const trimmed = text.trim() @@ -833,7 +850,7 @@ export const Panel = memo(function Panel({ workspaceId: propWorkspaceId }: Panel isSending={copilotIsSending} isReconnecting={copilotIsReconnecting} onSubmit={handleCopilotSubmit} - onStopGeneration={copilotStopGeneration} + onStopGeneration={handleCopilotStopGeneration} messageQueue={copilotMessageQueue} onRemoveQueuedMessage={copilotRemoveFromQueue} onSendQueuedMessage={copilotSendNow} diff --git a/apps/sim/lib/posthog/events.ts b/apps/sim/lib/posthog/events.ts index 537a9864282..faf9895bf62 100644 --- a/apps/sim/lib/posthog/events.ts +++ b/apps/sim/lib/posthog/events.ts @@ -378,6 +378,11 @@ export interface PostHogEventMap { workspace_id: string } + task_generation_aborted: { + workspace_id: string + view: 'mothership' | 'copilot' + } + task_message_sent: { workspace_id: string has_attachments: boolean From 0f602f79a4e08ada517f4eb4b6b509a6b615e6f3 Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Tue, 7 Apr 2026 15:32:33 -0700 Subject: [PATCH 02/15] fix(login): fix captcha headers for manual login (#4025) * fix(signup): fix turnstile key loading * fix(login): fix captcha header passing * Catch user already exists, remove login form captcha --------- Co-authored-by: Theodore Li --- apps/sim/app/(auth)/signup/signup-form.tsx | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/sim/app/(auth)/signup/signup-form.tsx b/apps/sim/app/(auth)/signup/signup-form.tsx index 55a0508ec1b..afb27cd729a 100644 --- a/apps/sim/app/(auth)/signup/signup-form.tsx +++ b/apps/sim/app/(auth)/signup/signup-form.tsx @@ -270,10 +270,8 @@ function SignupFormContent({ name: sanitizedName, }, { - fetchOptions: { - headers: { - ...(token ? { 'x-captcha-response': token } : {}), - }, + headers: { + ...(token ? { 'x-captcha-response': token } : {}), }, onError: (ctx) => { logger.error('Signup error:', ctx.error) @@ -282,10 +280,7 @@ function SignupFormContent({ let errorCode = 'unknown' if (ctx.error.code?.includes('USER_ALREADY_EXISTS')) { errorCode = 'user_already_exists' - errorMessage.push( - 'An account with this email already exists. Please sign in instead.' - ) - setEmailError(errorMessage[0]) + setEmailError('An account with this email already exists. Please sign in instead.') } else if ( ctx.error.code?.includes('BAD_REQUEST') || ctx.error.message?.includes('Email and password sign up is not enabled') From e0f5cf880aaa855429baf87451498739008fb576 Mon Sep 17 00:00:00 2001 From: Waleed Date: Tue, 7 Apr 2026 18:13:26 -0700 Subject: [PATCH 03/15] feat(slack): add subtype field and signature verification to Slack trigger (#4030) * feat(slack): add subtype field and signature verification to Slack trigger * fix(slack): guard against NaN timestamp and align null/empty-string convention --- apps/sim/blocks/blocks/slack.ts | 13 ++++ apps/sim/lib/webhooks/providers/slack.ts | 82 ++++++++++++++++++++++++ apps/sim/triggers/slack/webhook.ts | 16 ++++- 3 files changed, 110 insertions(+), 1 deletion(-) diff --git a/apps/sim/blocks/blocks/slack.ts b/apps/sim/blocks/blocks/slack.ts index 70ece5a0e88..84d903c1754 100644 --- a/apps/sim/blocks/blocks/slack.ts +++ b/apps/sim/blocks/blocks/slack.ts @@ -1634,8 +1634,21 @@ Do not include any explanations, markdown formatting, or other text outside the // Trigger outputs (when used as webhook trigger) event_type: { type: 'string', description: 'Type of Slack event that triggered the workflow' }, + subtype: { + type: 'string', + description: + 'Message subtype (e.g., channel_join, channel_leave, bot_message). Null for regular user messages', + }, channel_name: { type: 'string', description: 'Human-readable channel name' }, + channel_type: { + type: 'string', + description: 'Type of channel (e.g., channel, group, im, mpim)', + }, user_name: { type: 'string', description: 'Username who triggered the event' }, + bot_id: { + type: 'string', + description: 'Bot ID if the message was sent by a bot. Null for human users', + }, timestamp: { type: 'string', description: 'Message timestamp from the triggering event' }, thread_ts: { type: 'string', diff --git a/apps/sim/lib/webhooks/providers/slack.ts b/apps/sim/lib/webhooks/providers/slack.ts index 1bcedd628b9..d645fd791ef 100644 --- a/apps/sim/lib/webhooks/providers/slack.ts +++ b/apps/sim/lib/webhooks/providers/slack.ts @@ -1,10 +1,13 @@ +import crypto from 'crypto' import { createLogger } from '@sim/logger' import { NextResponse } from 'next/server' +import { safeCompare } from '@/lib/core/security/encryption' import { secureFetchWithPinnedIP, validateUrlWithDNS, } from '@/lib/core/security/input-validation.server' import type { + AuthContext, FormatInputContext, FormatInputResult, WebhookProviderHandler, @@ -177,6 +180,44 @@ async function fetchSlackMessageText( } } +/** Maximum allowed timestamp skew (5 minutes) per Slack docs. */ +const SLACK_TIMESTAMP_MAX_SKEW = 300 + +/** + * Validate Slack request signature using HMAC-SHA256. + * Basestring format: `v0:{timestamp}:{rawBody}` + * Signature header format: `v0={hex}` + */ +function validateSlackSignature( + signingSecret: string, + signature: string, + timestamp: string, + rawBody: string +): boolean { + try { + if (!signingSecret || !signature || !rawBody) { + return false + } + + if (!signature.startsWith('v0=')) { + logger.warn('Slack signature has invalid format (missing v0= prefix)') + return false + } + + const providedSignature = signature.substring(3) + const basestring = `v0:${timestamp}:${rawBody}` + const computedHash = crypto + .createHmac('sha256', signingSecret) + .update(basestring, 'utf8') + .digest('hex') + + return safeCompare(computedHash, providedSignature) + } catch (error) { + logger.error('Error validating Slack signature:', error) + return false + } +} + /** * Handle Slack verification challenges */ @@ -190,6 +231,44 @@ export function handleSlackChallenge(body: unknown): NextResponse | null { } export const slackHandler: WebhookProviderHandler = { + verifyAuth({ request, rawBody, requestId, providerConfig }: AuthContext) { + const signingSecret = providerConfig.signingSecret as string | undefined + if (!signingSecret) { + return null + } + + const signature = request.headers.get('x-slack-signature') + const timestamp = request.headers.get('x-slack-request-timestamp') + + if (!signature || !timestamp) { + logger.warn(`[${requestId}] Slack webhook missing signature or timestamp header`) + return new NextResponse('Unauthorized - Missing Slack signature', { status: 401 }) + } + + const now = Math.floor(Date.now() / 1000) + const parsedTimestamp = Number(timestamp) + if (Number.isNaN(parsedTimestamp)) { + logger.warn(`[${requestId}] Slack webhook timestamp is not a valid number`, { timestamp }) + return new NextResponse('Unauthorized - Invalid timestamp', { status: 401 }) + } + const skew = Math.abs(now - parsedTimestamp) + if (skew > SLACK_TIMESTAMP_MAX_SKEW) { + logger.warn(`[${requestId}] Slack webhook timestamp too old`, { + timestamp, + now, + skew, + }) + return new NextResponse('Unauthorized - Request timestamp too old', { status: 401 }) + } + + if (!validateSlackSignature(signingSecret, signature, timestamp, rawBody)) { + logger.warn(`[${requestId}] Slack signature verification failed`) + return new NextResponse('Unauthorized - Invalid Slack signature', { status: 401 }) + } + + return null + }, + handleChallenge(body: unknown) { return handleSlackChallenge(body) }, @@ -262,10 +341,13 @@ export const slackHandler: WebhookProviderHandler = { input: { event: { event_type: eventType, + subtype: (rawEvent?.subtype as string) ?? '', channel, channel_name: '', + channel_type: (rawEvent?.channel_type as string) ?? '', user: (rawEvent?.user as string) || '', user_name: '', + bot_id: (rawEvent?.bot_id as string) ?? '', text, timestamp: messageTs, thread_ts: (rawEvent?.thread_ts as string) || '', diff --git a/apps/sim/triggers/slack/webhook.ts b/apps/sim/triggers/slack/webhook.ts index 3f1bbe2c0f7..2fa8966ae63 100644 --- a/apps/sim/triggers/slack/webhook.ts +++ b/apps/sim/triggers/slack/webhook.ts @@ -68,7 +68,7 @@ export const slackWebhookTrigger: TriggerConfig = { 'If you don\'t have an app:
  • Create an app from scratch
  • Give it a name and select your workspace
', 'Go to "Basic Information", find the "Signing Secret", and paste it in the field above.', 'Go to "OAuth & Permissions" and add bot token scopes:
  • app_mentions:read - For viewing messages that tag your bot with an @
  • chat:write - To send messages to channels your bot is a part of
  • files:read - To access files and images shared in messages
  • reactions:read - For listening to emoji reactions and fetching reacted-to message text
', - 'Go to "Event Subscriptions":
  • Enable events
  • Under "Subscribe to Bot Events", add app_mention to listen to messages that mention your bot
  • For reaction events, also add reaction_added and/or reaction_removed
  • Paste the Webhook URL above into the "Request URL" field
', + 'Go to "Event Subscriptions":
  • Enable events
  • Under "Subscribe to Bot Events", add app_mention to listen to messages that mention your bot
  • To receive all channel messages, add message.channels. For DMs add message.im, for group DMs add message.mpim, for private channels add message.groups
  • For reaction events, also add reaction_added and/or reaction_removed
  • Paste the Webhook URL above into the "Request URL" field
', 'Go to "Install App" in the left sidebar and install the app into your desired Slack workspace and channel.', 'Copy the "Bot User OAuth Token" (starts with xoxb-) and paste it in the Bot Token field above to enable file downloads.', 'Save changes in both Slack and here.', @@ -92,6 +92,11 @@ export const slackWebhookTrigger: TriggerConfig = { type: 'string', description: 'Type of Slack event (e.g., app_mention, message)', }, + subtype: { + type: 'string', + description: + 'Message subtype (e.g., channel_join, channel_leave, bot_message, file_share). Null for regular user messages', + }, channel: { type: 'string', description: 'Slack channel ID where the event occurred', @@ -100,6 +105,11 @@ export const slackWebhookTrigger: TriggerConfig = { type: 'string', description: 'Human-readable channel name', }, + channel_type: { + type: 'string', + description: + 'Type of channel (e.g., channel, group, im, mpim). Useful for distinguishing DMs from public channels', + }, user: { type: 'string', description: 'User ID who triggered the event', @@ -108,6 +118,10 @@ export const slackWebhookTrigger: TriggerConfig = { type: 'string', description: 'Username who triggered the event', }, + bot_id: { + type: 'string', + description: 'Bot ID if the message was sent by a bot. Null for human users', + }, text: { type: 'string', description: 'Message text content', From 98be968b547688e7d1b188274c934bb59c1b5c9c Mon Sep 17 00:00:00 2001 From: Waleed Date: Tue, 7 Apr 2026 18:30:26 -0700 Subject: [PATCH 04/15] improvement(secrets): parallelize save mutations and add admin visibility for workspace secrets (#4032) * improvement(secrets): parallelize save mutations and add admin visibility for workspace secrets * fix(secrets): sequence workspace upsert/delete to avoid read-modify-write race * fix(secrets): use Promise.allSettled to ensure credential invalidation after all mutations settle --- .../credentials/credentials-manager.tsx | 81 ++++++++++++++----- apps/sim/hooks/queries/environment.ts | 31 +------ 2 files changed, 65 insertions(+), 47 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/settings/components/credentials/credentials-manager.tsx b/apps/sim/app/workspace/[workspaceId]/settings/components/credentials/credentials-manager.tsx index d3916265d72..e87f0ee5cf4 100644 --- a/apps/sim/app/workspace/[workspaceId]/settings/components/credentials/credentials-manager.tsx +++ b/apps/sim/app/workspace/[workspaceId]/settings/components/credentials/credentials-manager.tsx @@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { createLogger } from '@sim/logger' +import { useQueryClient } from '@tanstack/react-query' import { Check, Clipboard, Key, Search } from 'lucide-react' import { useParams, useRouter } from 'next/navigation' import { @@ -42,6 +43,7 @@ import { useWorkspaceCredentials, type WorkspaceCredential, type WorkspaceCredentialRole, + workspaceCredentialKeys, } from '@/hooks/queries/credentials' import { usePersonalEnvironment, @@ -125,6 +127,7 @@ interface WorkspaceVariableRowProps { renamingKey: string | null pendingKeyValue: string hasCredential: boolean + isAdmin: boolean onRenameStart: (key: string) => void onPendingKeyChange: (value: string) => void onRenameEnd: (key: string, value: string) => void @@ -138,12 +141,18 @@ function WorkspaceVariableRow({ renamingKey, pendingKeyValue, hasCredential, + isAdmin, onRenameStart, onPendingKeyChange, onRenameEnd, onDelete, onViewDetails, }: WorkspaceVariableRowProps) { + const [valueFocused, setValueFocused] = useState(false) + + const maskedValueStyle = + isAdmin && !valueFocused ? ({ WebkitTextSecurity: 'disc' } as React.CSSProperties) : undefined + return (
{ + if (isAdmin) setValueFocused(true) + }} + onBlur={() => { + if (isAdmin) setValueFocused(false) + }} autoComplete='off' autoCorrect='off' autoCapitalize='off' spellCheck='false' + style={maskedValueStyle} className='h-9' />
@@ -375,6 +367,7 @@ export function Home({ chatId }: HomeProps = {}) { userId={session?.user?.id} chatId={resolvedChatId} onContextAdd={handleContextAdd} + onContextRemove={handleContextRemove} editValue={editingInputValue} onEditValueConsumed={clearEditingValue} animateInput={isInputEntering} diff --git a/apps/sim/app/workspace/[workspaceId]/home/types.ts b/apps/sim/app/workspace/[workspaceId]/home/types.ts index d4f812cc25a..e6ae3c9f0a9 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/types.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/types.ts @@ -6,6 +6,9 @@ export type { MothershipResourceType, } from '@/lib/copilot/resource-types' +/** Union of all valid context kind strings, derived from {@link ChatContext}. */ +export type ChatContextKind = ChatContext['kind'] + export interface FileAttachmentForApi { id: string key: string @@ -260,13 +263,14 @@ export interface ChatMessageAttachment { } export interface ChatMessageContext { - kind: string + kind: ChatContextKind label: string workflowId?: string knowledgeId?: string tableId?: string fileId?: string folderId?: string + chatId?: string } export interface ChatMessage { diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/workflows-list/workflows-list.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/workflows-list/workflows-list.tsx index ee52e0fa0bc..2f7b7f38cd9 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/workflows-list/workflows-list.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/workflows-list/workflows-list.tsx @@ -1,6 +1,7 @@ import { memo } from 'react' import { useParams } from 'next/navigation' import { cn } from '@/lib/core/utils/cn' +import { workflowBorderColor } from '@/lib/workspaces/colors' import { DELETED_WORKFLOW_COLOR, DELETED_WORKFLOW_LABEL, @@ -93,7 +94,7 @@ function WorkflowsListInner({ className='h-[10px] w-[10px] flex-shrink-0 rounded-[3px] border-[1.5px]' style={{ backgroundColor: workflowColor, - borderColor: `${workflowColor}60`, + borderColor: workflowBorderColor(workflowColor), backgroundClip: 'padding-box', }} /> diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx index 0289e4d9280..4307d40b5c5 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx @@ -20,6 +20,7 @@ import { BASE_EXECUTION_CHARGE } from '@/lib/billing/constants' import { cn } from '@/lib/core/utils/cn' import { formatDuration } from '@/lib/core/utils/formatting' import { filterHiddenOutputKeys } from '@/lib/logs/execution/trace-spans/trace-spans' +import { workflowBorderColor } from '@/lib/workspaces/colors' import { ExecutionSnapshot, FileCards, @@ -431,7 +432,7 @@ export const LogDetails = memo(function LogDetails({ className='h-[10px] w-[10px] flex-shrink-0 rounded-[3px] border-[1.5px]' style={{ backgroundColor: c, - borderColor: c ? `${c}60` : undefined, + borderColor: c ? workflowBorderColor(c) : undefined, backgroundClip: 'padding-box', }} /> diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-list/logs-list.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-list/logs-list.tsx index c99a59988fa..3d1aba93508 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-list/logs-list.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-list/logs-list.tsx @@ -8,6 +8,7 @@ import { Badge, buttonVariants } from '@/components/emcn' import { dollarsToCredits } from '@/lib/billing/credits/conversion' import { cn } from '@/lib/core/utils/cn' import { formatDuration } from '@/lib/core/utils/formatting' +import { workflowBorderColor } from '@/lib/workspaces/colors' import { DELETED_WORKFLOW_COLOR, DELETED_WORKFLOW_LABEL, @@ -90,7 +91,7 @@ const LogRow = memo( className='h-[10px] w-[10px] flex-shrink-0 rounded-[3px] border-[1.5px]' style={{ backgroundColor: workflowColor, - borderColor: `${workflowColor}60`, + borderColor: workflowBorderColor(workflowColor), backgroundClip: 'padding-box', }} /> diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx index bcaf5d3019a..518ad67654b 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx @@ -20,6 +20,7 @@ import { cn } from '@/lib/core/utils/cn' import { hasActiveFilters } from '@/lib/logs/filters' import { getTriggerOptions } from '@/lib/logs/get-trigger-options' import { captureEvent } from '@/lib/posthog/client' +import { workflowBorderColor } from '@/lib/workspaces/colors' import { type LogStatus, STATUS_CONFIG } from '@/app/workspace/[workspaceId]/logs/utils' import { getBlock } from '@/blocks/registry' import { useFolderMap } from '@/hooks/queries/folders' @@ -124,7 +125,7 @@ function getColorIcon( width: 10, height: 10, ...(withRing && { - borderColor: `${color}60`, + borderColor: workflowBorderColor(color), backgroundClip: 'padding-box' as const, }), }} @@ -604,7 +605,7 @@ export const LogsToolbar = memo(function LogsToolbar({ className='h-[8px] w-[8px] flex-shrink-0 rounded-xs border-[1.5px]' style={{ backgroundColor: selectedWorkflow.color, - borderColor: `${selectedWorkflow.color}60`, + borderColor: workflowBorderColor(selectedWorkflow.color), backgroundClip: 'padding-box', }} /> @@ -735,7 +736,7 @@ export const LogsToolbar = memo(function LogsToolbar({ className='h-[8px] w-[8px] flex-shrink-0 rounded-xs border-[1.5px]' style={{ backgroundColor: selectedWorkflow.color, - borderColor: `${selectedWorkflow.color}60`, + borderColor: workflowBorderColor(selectedWorkflow.color), backgroundClip: 'padding-box', }} /> diff --git a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx index a939a859c1b..f8708263c76 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx @@ -33,6 +33,7 @@ import { type TriggerData, type WorkflowData, } from '@/lib/logs/search-suggestions' +import { workflowBorderColor } from '@/lib/workspaces/colors' import type { FilterTag, HeaderAction, @@ -157,7 +158,7 @@ function getColorIcon( width: 10, height: 10, ...(withRing && { - borderColor: `${color}60`, + borderColor: workflowBorderColor(color), backgroundClip: 'padding-box' as const, }), }} @@ -742,7 +743,7 @@ export default function Logs() { className='h-[10px] w-[10px] rounded-[3px] border-[1.5px]' style={{ backgroundColor: workflowColor, - borderColor: `${workflowColor}60`, + borderColor: workflowBorderColor(workflowColor), backgroundClip: 'padding-box', }} /> @@ -1441,7 +1442,7 @@ function LogsFilterPanel({ searchQuery, onSearchQueryChange }: LogsFilterPanelPr className='h-[8px] w-[8px] flex-shrink-0 rounded-xs border-[1.5px]' style={{ backgroundColor: selectedWorkflow.color, - borderColor: `${selectedWorkflow.color}60`, + borderColor: workflowBorderColor(selectedWorkflow.color), backgroundClip: 'padding-box', }} /> diff --git a/apps/sim/app/workspace/[workspaceId]/settings/components/recently-deleted/recently-deleted.tsx b/apps/sim/app/workspace/[workspaceId]/settings/components/recently-deleted/recently-deleted.tsx index 3cd6d051ca7..48c5dbbc5fd 100644 --- a/apps/sim/app/workspace/[workspaceId]/settings/components/recently-deleted/recently-deleted.tsx +++ b/apps/sim/app/workspace/[workspaceId]/settings/components/recently-deleted/recently-deleted.tsx @@ -6,6 +6,7 @@ import { useParams, useRouter } from 'next/navigation' import { Button, Combobox, SModalTabs, SModalTabsList, SModalTabsTrigger } from '@/components/emcn' import { Input } from '@/components/ui' import { formatDate } from '@/lib/core/utils/formatting' +import { workflowBorderColor } from '@/lib/workspaces/colors' import { RESOURCE_REGISTRY } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-registry' import type { MothershipResourceType } from '@/app/workspace/[workspaceId]/home/types' import { DeletedItemSkeleton } from '@/app/workspace/[workspaceId]/settings/components/recently-deleted/deleted-item-skeleton' @@ -97,7 +98,7 @@ function ResourceIcon({ resource }: { resource: DeletedResource }) { className='h-[14px] w-[14px] shrink-0 rounded-[3px] border-[2px]' style={{ backgroundColor: color, - borderColor: `${color}60`, + borderColor: workflowBorderColor(color), backgroundClip: 'padding-box', }} /> diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/collapsed-sidebar-menu/collapsed-sidebar-menu.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/collapsed-sidebar-menu/collapsed-sidebar-menu.tsx index 7a64c8e0392..e5f869a8057 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/collapsed-sidebar-menu/collapsed-sidebar-menu.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/collapsed-sidebar-menu/collapsed-sidebar-menu.tsx @@ -14,6 +14,7 @@ import { } from '@/components/emcn' import { Pencil, SquareArrowUpRight } from '@/components/emcn/icons' import { cn } from '@/lib/core/utils/cn' +import { workflowBorderColor } from '@/lib/workspaces/colors' import { ConversationListItem } from '@/app/workspace/[workspaceId]/components' import type { useHoverMenu } from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks' import type { FolderTreeNode } from '@/stores/folders/types' @@ -131,7 +132,7 @@ function WorkflowColorSwatch({ color }: { color: string }) { className='h-[16px] w-[16px] flex-shrink-0 rounded-sm border-[2.5px]' style={{ backgroundColor: color, - borderColor: `${color}60`, + borderColor: workflowBorderColor(color), backgroundClip: 'padding-box', }} /> diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items.tsx index 7cdffe5bd57..d5c81dcf55a 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items.tsx @@ -5,6 +5,7 @@ import { memo } from 'react' import { Command } from 'cmdk' import { Blimp } from '@/components/emcn' import { cn } from '@/lib/core/utils/cn' +import { workflowBorderColor } from '@/lib/workspaces/colors' import type { CommandItemProps } from '../utils' import { COMMAND_ITEM_CLASSNAME } from '../utils' @@ -64,7 +65,7 @@ export const MemoizedWorkflowItem = memo( className='h-[14px] w-[14px] flex-shrink-0 rounded-sm border-[2px]' style={{ backgroundColor: color, - borderColor: `${color}60`, + borderColor: workflowBorderColor(color), backgroundClip: 'padding-box', }} /> diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/folder-item/folder-item.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/folder-item/folder-item.tsx index afae818c6ac..d179568c316 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/folder-item/folder-item.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/folder-item/folder-item.tsx @@ -5,6 +5,7 @@ import { createLogger } from '@sim/logger' import clsx from 'clsx' import { ChevronRight, Folder, FolderOpen, MoreHorizontal } from 'lucide-react' import { useParams, useRouter } from 'next/navigation' +import { SIM_RESOURCES_DRAG_TYPE } from '@/lib/copilot/resource-types' import { generateId } from '@/lib/core/utils/uuid' import { getNextWorkflowColor } from '@/lib/workflows/colors' import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider' @@ -18,6 +19,10 @@ import { useSidebarDragContext, } from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks' import { SIDEBAR_SCROLL_EVENT } from '@/app/workspace/[workspaceId]/w/components/sidebar/sidebar' +import { + buildDragResources, + createSidebarDragGhost, +} from '@/app/workspace/[workspaceId]/w/components/sidebar/utils' import { useCanDelete, useDeleteFolder, @@ -136,6 +141,7 @@ export function FolderItem({ }) const isEditingRef = useRef(false) + const dragGhostRef = useRef(null) const handleCreateWorkflowInFolder = useCallback(() => { const name = generateCreativeWorkflowName() @@ -196,10 +202,24 @@ export function FolderItem({ } e.dataTransfer.setData('sidebar-selection', JSON.stringify(selection)) - e.dataTransfer.effectAllowed = 'move' + e.dataTransfer.effectAllowed = 'copyMove' + + const resources = buildDragResources(selection, workspaceId) + if (resources.length > 0) { + e.dataTransfer.setData(SIM_RESOURCES_DRAG_TYPE, JSON.stringify(resources)) + } + + const total = selection.folderIds.length + selection.workflowIds.length + const ghostLabel = total > 1 ? `${folder.name} +${total - 1} more` : folder.name + const icon = total === 1 ? { kind: 'folder' as const } : undefined + const ghost = createSidebarDragGhost(ghostLabel, icon) + void ghost.offsetHeight + e.dataTransfer.setDragImage(ghost, ghost.offsetWidth / 2, ghost.offsetHeight / 2) + dragGhostRef.current = ghost + onDragStartProp?.() }, - [folder.id, onDragStartProp] + [folder.id, folder.name, workspaceId, onDragStartProp] ) const { @@ -212,6 +232,10 @@ export function FolderItem({ }) const handleDragEnd = useCallback(() => { + if (dragGhostRef.current) { + dragGhostRef.current.remove() + dragGhostRef.current = null + } handleDragEndBase() onDragEndProp?.() }, [handleDragEndBase, onDragEndProp]) diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/workflow-item.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/workflow-item.tsx index 32a58343029..3727779a43b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/workflow-item.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/workflow-item.tsx @@ -5,6 +5,8 @@ import clsx from 'clsx' import { MoreHorizontal } from 'lucide-react' import Link from 'next/link' import { useParams } from 'next/navigation' +import { SIM_RESOURCES_DRAG_TYPE } from '@/lib/copilot/resource-types' +import { workflowBorderColor } from '@/lib/workspaces/colors' import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider' import { getWorkflowLockToggleIds } from '@/app/workspace/[workspaceId]/w/[workflowId]/utils' import { ContextMenu } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/context-menu/context-menu' @@ -16,6 +18,10 @@ import { useItemRename, useSidebarDragContext, } from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks' +import { + buildDragResources, + createSidebarDragGhost, +} from '@/app/workspace/[workspaceId]/w/components/sidebar/utils' import { useCanDelete, useDeleteSelection, @@ -198,6 +204,7 @@ export function WorkflowItem({ }, [isActiveWorkflow, isWorkflowLocked]) const isEditingRef = useRef(false) + const dragGhostRef = useRef(null) const { isOpen: isContextMenuOpen, @@ -337,10 +344,25 @@ export function WorkflowItem({ } e.dataTransfer.setData('sidebar-selection', JSON.stringify(selection)) - e.dataTransfer.effectAllowed = 'move' + e.dataTransfer.effectAllowed = 'copyMove' + + const resources = buildDragResources(selection, workspaceId) + if (resources.length > 0) { + e.dataTransfer.setData(SIM_RESOURCES_DRAG_TYPE, JSON.stringify(resources)) + } + + const total = selection.workflowIds.length + selection.folderIds.length + const ghostLabel = total > 1 ? `${workflow.name} +${total - 1} more` : workflow.name + const icon = total === 1 ? { kind: 'workflow' as const, color: workflow.color } : undefined + const ghost = createSidebarDragGhost(ghostLabel, icon) + // Force reflow so the browser can capture the rendered element + void ghost.offsetHeight + e.dataTransfer.setDragImage(ghost, ghost.offsetWidth / 2, ghost.offsetHeight / 2) + dragGhostRef.current = ghost + onDragStartProp?.() }, - [workflow.id, onDragStartProp] + [workflow.id, workflow.name, workflow.color, workspaceId, onDragStartProp] ) const { @@ -353,6 +375,10 @@ export function WorkflowItem({ }) const handleDragEnd = useCallback(() => { + if (dragGhostRef.current) { + dragGhostRef.current.remove() + dragGhostRef.current = null + } handleDragEndBase() onDragEndProp?.() }, [handleDragEndBase, onDragEndProp]) @@ -414,7 +440,7 @@ export function WorkflowItem({ className='h-[16px] w-[16px] flex-shrink-0 rounded-sm border-[2.5px]' style={{ backgroundColor: workflow.color, - borderColor: `${workflow.color}60`, + borderColor: workflowBorderColor(workflow.color), backgroundClip: 'padding-box', }} /> diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx index 02f0bca42e8..1a9dcb4765c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx @@ -37,6 +37,7 @@ import { Wordmark, } from '@/components/emcn/icons' import { useSession } from '@/lib/auth/auth-client' +import { SIM_RESOURCES_DRAG_TYPE } from '@/lib/copilot/resource-types' import { cn } from '@/lib/core/utils/cn' import { isMacPlatform } from '@/lib/core/utils/platform' import { buildFolderTree } from '@/lib/folders/tree' @@ -72,7 +73,10 @@ import { useWorkflowOperations, useWorkspaceManagement, } from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks' -import { groupWorkflowsByFolder } from '@/app/workspace/[workspaceId]/w/components/sidebar/utils' +import { + createSidebarDragGhost, + groupWorkflowsByFolder, +} from '@/app/workspace/[workspaceId]/w/components/sidebar/utils' import { useDuplicateWorkspace, useExportWorkspace, @@ -159,6 +163,30 @@ const SidebarTaskItem = memo(function SidebarTaskItem({ onMorePointerDown: () => void onMoreClick: (e: React.MouseEvent, taskId: string) => void }) { + const dragGhostRef = useRef(null) + + const handleDragStart = useCallback( + (e: React.DragEvent) => { + e.dataTransfer.effectAllowed = 'copyMove' + e.dataTransfer.setData( + SIM_RESOURCES_DRAG_TYPE, + JSON.stringify([{ type: 'task', id: task.id, title: task.name }]) + ) + const ghost = createSidebarDragGhost(task.name, { kind: 'task' }) + void ghost.offsetHeight + e.dataTransfer.setDragImage(ghost, ghost.offsetWidth / 2, ghost.offsetHeight / 2) + dragGhostRef.current = ghost + }, + [task.id, task.name] + ) + + const handleDragEnd = useCallback(() => { + if (dragGhostRef.current) { + dragGhostRef.current.remove() + dragGhostRef.current = null + } + }, []) + return ( onContextMenu(e, task.id) : undefined} + draggable={task.id !== 'new'} + onDragStart={task.id !== 'new' ? handleDragStart : undefined} + onDragEnd={task.id !== 'new' ? handleDragEnd : undefined} >
{task.name}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/utils.ts b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/utils.ts index ecabf89b452..848f0771cb0 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/utils.ts @@ -1,5 +1,96 @@ +import type { MothershipResource } from '@/lib/copilot/resource-types' +import { workflowBorderColor } from '@/lib/workspaces/colors' +import { getFolderMap } from '@/hooks/queries/utils/folder-cache' +import { getWorkflows } from '@/hooks/queries/utils/workflow-cache' import type { WorkflowMetadata } from '@/stores/workflows/registry/types' +/** + * Builds a `MothershipResource` array from a sidebar drag selection so it can + * be set as `application/x-sim-resources` drag data and dropped into the chat. + */ +export function buildDragResources( + selection: { workflowIds: string[]; folderIds: string[] }, + workspaceId: string +): MothershipResource[] { + const allWorkflows = getWorkflows(workspaceId) + const workflowMap = Object.fromEntries(allWorkflows.map((w) => [w.id, w])) + const folderMap = getFolderMap(workspaceId) + return [ + ...selection.workflowIds.map((id) => ({ + type: 'workflow' as const, + id, + title: workflowMap[id]?.name ?? id, + })), + ...selection.folderIds.map((id) => ({ + type: 'folder' as const, + id, + title: folderMap[id]?.name ?? id, + })), + ] +} + +export type SidebarDragGhostIcon = + | { kind: 'workflow'; color: string } + | { kind: 'folder' } + | { kind: 'task' } + +const FOLDER_SVG = `` + +const BLIMP_SVG = `` + +/** + * Creates a lightweight drag ghost pill showing an icon and label for the item(s) being dragged. + * Append to `document.body`, pass to `e.dataTransfer.setDragImage`, then remove on dragend. + */ +export function createSidebarDragGhost(label: string, icon?: SidebarDragGhostIcon): HTMLElement { + const ghost = document.createElement('div') + ghost.style.cssText = ` + position: fixed; + top: -500px; + left: 0; + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 10px; + background: var(--surface-active); + border: 1px solid rgba(255,255,255,0.08); + border-radius: 8px; + font-family: system-ui, -apple-system, sans-serif; + font-size: 13px; + color: var(--text-body); + white-space: nowrap; + pointer-events: none; + box-shadow: 0 4px 12px rgba(0,0,0,0.4); + z-index: 9999; + ` + + if (icon) { + if (icon.kind === 'workflow') { + const square = document.createElement('div') + square.style.cssText = ` + width: 14px; height: 14px; flex-shrink: 0; + border-radius: 3px; border: 2px solid ${workflowBorderColor(icon.color)}; + background: ${icon.color}; background-clip: padding-box; + ` + ghost.appendChild(square) + } else { + const iconWrapper = document.createElement('div') + iconWrapper.style.cssText = + 'display: flex; align-items: center; flex-shrink: 0; color: var(--text-icon);' + iconWrapper.innerHTML = icon.kind === 'folder' ? FOLDER_SVG : BLIMP_SVG + ghost.appendChild(iconWrapper) + } + } + + const text = document.createElement('span') + text.style.cssText = 'max-width: 200px; overflow: hidden; text-overflow: ellipsis;' + text.textContent = label + ghost.appendChild(text) + + document.body.appendChild(ghost) + return ghost +} + export function compareByOrder( a: T, b: T diff --git a/apps/sim/hooks/queries/tasks.ts b/apps/sim/hooks/queries/tasks.ts index 2c38f339558..9cd1eab999a 100644 --- a/apps/sim/hooks/queries/tasks.ts +++ b/apps/sim/hooks/queries/tasks.ts @@ -1,5 +1,5 @@ import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query' -import type { MothershipResource } from '@/app/workspace/[workspaceId]/home/types' +import type { ChatContextKind, MothershipResource } from '@/app/workspace/[workspaceId]/home/types' export interface TaskMetadata { id: string @@ -42,13 +42,14 @@ export interface TaskStoredFileAttachment { } export interface TaskStoredMessageContext { - kind: string + kind: ChatContextKind label: string workflowId?: string knowledgeId?: string tableId?: string fileId?: string folderId?: string + chatId?: string } export interface TaskStoredMessage { diff --git a/apps/sim/lib/copilot/resource-types.ts b/apps/sim/lib/copilot/resource-types.ts index c0e83fe8a46..a223536925c 100644 --- a/apps/sim/lib/copilot/resource-types.ts +++ b/apps/sim/lib/copilot/resource-types.ts @@ -4,6 +4,7 @@ export type MothershipResourceType = | 'workflow' | 'knowledgebase' | 'folder' + | 'task' | 'generic' export interface MothershipResource { @@ -19,3 +20,9 @@ export const VFS_DIR_TO_RESOURCE: Record = { knowledgebases: 'knowledgebase', folders: 'folder', } as const + +/** MIME type for a single dragged resource (used by resource-tabs internal reordering). */ +export const SIM_RESOURCE_DRAG_TYPE = 'application/x-sim-resource' as const + +/** MIME type for an array of dragged resources (used by sidebar drag-to-chat). */ +export const SIM_RESOURCES_DRAG_TYPE = 'application/x-sim-resources' as const diff --git a/apps/sim/lib/workspaces/colors.ts b/apps/sim/lib/workspaces/colors.ts index 3a0b80af93a..b652ebd36d9 100644 --- a/apps/sim/lib/workspaces/colors.ts +++ b/apps/sim/lib/workspaces/colors.ts @@ -77,6 +77,14 @@ function withAlpha(hexColor: string, alpha: number): string { return `rgba(${r}, ${g}, ${b}, ${Math.min(Math.max(alpha, 0), 1)})` } +/** + * Returns the hex color with 60/ff (~38%) alpha — used for workflow color border accents. + * Returns `undefined` when `color` is undefined so callers can pass it directly to `borderColor`. + */ +export function workflowBorderColor(color: string | undefined): string | undefined { + return color ? `${color}60` : undefined +} + function buildGradient(fromColor: string, toColor: string, rotationSeed: number): string { const rotation = (rotationSeed * 25) % 360 return `linear-gradient(${rotation}deg, ${fromColor}, ${toColor})` From 2504bfbaf864a9e561960b5a1ec28591cfc52ce5 Mon Sep 17 00:00:00 2001 From: Waleed Date: Tue, 7 Apr 2026 20:20:53 -0700 Subject: [PATCH 06/15] feat(athena): add AWS Athena integration (#4034) * feat(athena): add AWS Athena integration * fix(athena): address PR review comments - Fix variable shadowing: rename inner `data` to `rowData` in row mapper - Fix first-page maxResults off-by-one: request maxResults+1 to compensate for header row - Add missing runtime guard for queryString in create_named_query - Move athena registry entries to correct alphabetical position * fix(athena): alphabetize registry keys and add type re-exports - Reorder athena_* registry keys to strict alphabetical order - Add type re-exports from index.ts barrel * fix(athena): cap maxResults at 999 to prevent overflow with header row adjustment The +1 adjustment for the header row on first-page requests could produce MaxResults=1001 when user requests 1000, exceeding the AWS API hard cap of 1000. --- apps/docs/components/icons.tsx | 27 + apps/docs/components/ui/icon-mapping.ts | 2 + apps/docs/content/docs/en/tools/athena.mdx | 238 ++++++ apps/docs/content/docs/en/tools/meta.json | 1 + .../integrations/data/icon-mapping.ts | 2 + .../integrations/data/integrations.json | 51 ++ .../tools/athena/create-named-query/route.ts | 63 ++ .../api/tools/athena/get-named-query/route.ts | 60 ++ .../tools/athena/get-query-execution/route.ts | 71 ++ .../tools/athena/get-query-results/route.ts | 82 +++ .../tools/athena/list-named-queries/route.ts | 59 ++ .../athena/list-query-executions/route.ts | 59 ++ .../app/api/tools/athena/start-query/route.ts | 74 ++ .../app/api/tools/athena/stop-query/route.ts | 50 ++ apps/sim/app/api/tools/athena/utils.ts | 17 + apps/sim/blocks/blocks/athena.ts | 469 ++++++++++++ apps/sim/blocks/registry.ts | 2 + apps/sim/components/icons.tsx | 27 + apps/sim/tools/athena/create_named_query.ts | 102 +++ apps/sim/tools/athena/get_named_query.ts | 76 ++ apps/sim/tools/athena/get_query_execution.ts | 144 ++++ apps/sim/tools/athena/get_query_results.ts | 105 +++ apps/sim/tools/athena/index.ts | 19 + apps/sim/tools/athena/list_named_queries.ts | 94 +++ .../sim/tools/athena/list_query_executions.ts | 94 +++ apps/sim/tools/athena/start_query.ts | 96 +++ apps/sim/tools/athena/stop_query.ts | 68 ++ apps/sim/tools/athena/types.ts | 126 ++++ apps/sim/tools/registry.ts | 18 + bun.lock | 687 +++++++++++++++--- package.json | 5 +- 31 files changed, 2871 insertions(+), 117 deletions(-) create mode 100644 apps/docs/content/docs/en/tools/athena.mdx create mode 100644 apps/sim/app/api/tools/athena/create-named-query/route.ts create mode 100644 apps/sim/app/api/tools/athena/get-named-query/route.ts create mode 100644 apps/sim/app/api/tools/athena/get-query-execution/route.ts create mode 100644 apps/sim/app/api/tools/athena/get-query-results/route.ts create mode 100644 apps/sim/app/api/tools/athena/list-named-queries/route.ts create mode 100644 apps/sim/app/api/tools/athena/list-query-executions/route.ts create mode 100644 apps/sim/app/api/tools/athena/start-query/route.ts create mode 100644 apps/sim/app/api/tools/athena/stop-query/route.ts create mode 100644 apps/sim/app/api/tools/athena/utils.ts create mode 100644 apps/sim/blocks/blocks/athena.ts create mode 100644 apps/sim/tools/athena/create_named_query.ts create mode 100644 apps/sim/tools/athena/get_named_query.ts create mode 100644 apps/sim/tools/athena/get_query_execution.ts create mode 100644 apps/sim/tools/athena/get_query_results.ts create mode 100644 apps/sim/tools/athena/index.ts create mode 100644 apps/sim/tools/athena/list_named_queries.ts create mode 100644 apps/sim/tools/athena/list_query_executions.ts create mode 100644 apps/sim/tools/athena/start_query.ts create mode 100644 apps/sim/tools/athena/stop_query.ts create mode 100644 apps/sim/tools/athena/types.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 8b0ed3aabb1..2806cd4d314 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -4687,6 +4687,33 @@ export function CloudFormationIcon(props: SVGProps) { ) } +export function AthenaIcon(props: SVGProps) { + return ( + + + + + + ) +} + export function CloudWatchIcon(props: SVGProps) { return ( = { arxiv: ArxivIcon, asana: AsanaIcon, ashby: AshbyIcon, + athena: AthenaIcon, attio: AttioIcon, box: BoxCompanyIcon, brandfetch: BrandfetchIcon, diff --git a/apps/docs/content/docs/en/tools/athena.mdx b/apps/docs/content/docs/en/tools/athena.mdx new file mode 100644 index 00000000000..d77394bcefc --- /dev/null +++ b/apps/docs/content/docs/en/tools/athena.mdx @@ -0,0 +1,238 @@ +--- +title: Athena +description: Run SQL queries on data in Amazon S3 using AWS Athena +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[Amazon Athena](https://aws.amazon.com/athena/) is an interactive query service from AWS that makes it easy to analyze data directly in Amazon S3 using standard SQL. Athena is serverless, so there is no infrastructure to manage, and you pay only for the queries you run. + +With Athena, you can: + +- **Query data in S3**: Run SQL queries directly against data stored in Amazon S3 without loading it into a database +- **Support multiple formats**: Query CSV, JSON, Parquet, ORC, Avro, and other common data formats +- **Integrate with AWS Glue**: Use the AWS Glue Data Catalog to manage table metadata and schemas +- **Scale automatically**: Handle queries of any size without provisioning servers or clusters +- **Save and reuse queries**: Create named queries for frequently used SQL statements + +In Sim, the Athena integration enables your agents to run SQL queries against data in S3, check query execution status, retrieve results, and manage saved queries — all within your agent workflows. Supported operations include: + +- **Start Query**: Execute SQL queries against your S3 data +- **Get Query Execution**: Check the status and details of a running or completed query +- **Get Query Results**: Retrieve the results of a completed query +- **Stop Query**: Cancel a running query execution +- **List Query Executions**: View recent query execution IDs +- **Create Named Query**: Save a query for reuse +- **Get Named Query**: Retrieve details of a saved query +- **List Named Queries**: View all saved query IDs + +This integration empowers Sim agents to automate data analysis tasks using AWS Athena, enabling workflows that query, monitor, and manage large-scale data in S3 without manual effort or infrastructure management. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Integrate AWS Athena into workflows. Execute SQL queries against data in S3, check query status, retrieve results, manage named queries, and list executions. Requires AWS access key and secret access key. + + + +## Tools + +### `athena_start_query` + +Start an SQL query execution in AWS Athena + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `awsRegion` | string | Yes | AWS region \(e.g., us-east-1\) | +| `awsAccessKeyId` | string | Yes | AWS access key ID | +| `awsSecretAccessKey` | string | Yes | AWS secret access key | +| `queryString` | string | Yes | SQL query string to execute | +| `database` | string | No | Database name within the catalog | +| `catalog` | string | No | Data catalog name \(default: AwsDataCatalog\) | +| `outputLocation` | string | No | S3 output location for query results \(e.g., s3://bucket/path/\) | +| `workGroup` | string | No | Workgroup to execute the query in \(default: primary\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `queryExecutionId` | string | Unique ID of the started query execution | + +### `athena_get_query_execution` + +Get the status and details of an Athena query execution + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `awsRegion` | string | Yes | AWS region \(e.g., us-east-1\) | +| `awsAccessKeyId` | string | Yes | AWS access key ID | +| `awsSecretAccessKey` | string | Yes | AWS secret access key | +| `queryExecutionId` | string | Yes | Query execution ID to check | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `queryExecutionId` | string | Query execution ID | +| `query` | string | SQL query string | +| `state` | string | Query state \(QUEUED, RUNNING, SUCCEEDED, FAILED, CANCELLED\) | +| `stateChangeReason` | string | Reason for state change \(e.g., error message\) | +| `statementType` | string | Statement type \(DDL, DML, UTILITY\) | +| `database` | string | Database name | +| `catalog` | string | Data catalog name | +| `workGroup` | string | Workgroup name | +| `submissionDateTime` | number | Query submission time \(Unix epoch ms\) | +| `completionDateTime` | number | Query completion time \(Unix epoch ms\) | +| `dataScannedInBytes` | number | Amount of data scanned in bytes | +| `engineExecutionTimeInMillis` | number | Engine execution time in milliseconds | +| `queryPlanningTimeInMillis` | number | Query planning time in milliseconds | +| `queryQueueTimeInMillis` | number | Time the query spent in queue in milliseconds | +| `totalExecutionTimeInMillis` | number | Total execution time in milliseconds | +| `outputLocation` | string | S3 location of query results | + +### `athena_get_query_results` + +Retrieve the results of a completed Athena query execution + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `awsRegion` | string | Yes | AWS region \(e.g., us-east-1\) | +| `awsAccessKeyId` | string | Yes | AWS access key ID | +| `awsSecretAccessKey` | string | Yes | AWS secret access key | +| `queryExecutionId` | string | Yes | Query execution ID to get results for | +| `maxResults` | number | No | Maximum number of rows to return \(1-1000\) | +| `nextToken` | string | No | Pagination token from a previous request | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `columns` | array | Column metadata \(name and type\) | +| `rows` | array | Result rows as key-value objects | +| `nextToken` | string | Pagination token for next page of results | +| `updateCount` | number | Number of rows affected \(for INSERT/UPDATE statements\) | + +### `athena_stop_query` + +Stop a running Athena query execution + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `awsRegion` | string | Yes | AWS region \(e.g., us-east-1\) | +| `awsAccessKeyId` | string | Yes | AWS access key ID | +| `awsSecretAccessKey` | string | Yes | AWS secret access key | +| `queryExecutionId` | string | Yes | Query execution ID to stop | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether the query was successfully stopped | + +### `athena_list_query_executions` + +List recent Athena query execution IDs + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `awsRegion` | string | Yes | AWS region \(e.g., us-east-1\) | +| `awsAccessKeyId` | string | Yes | AWS access key ID | +| `awsSecretAccessKey` | string | Yes | AWS secret access key | +| `workGroup` | string | No | Workgroup to list executions for \(default: primary\) | +| `maxResults` | number | No | Maximum number of results \(0-50\) | +| `nextToken` | string | No | Pagination token from a previous request | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `queryExecutionIds` | array | List of query execution IDs | +| `nextToken` | string | Pagination token for next page | + +### `athena_create_named_query` + +Create a saved/named query in AWS Athena + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `awsRegion` | string | Yes | AWS region \(e.g., us-east-1\) | +| `awsAccessKeyId` | string | Yes | AWS access key ID | +| `awsSecretAccessKey` | string | Yes | AWS secret access key | +| `name` | string | Yes | Name for the saved query | +| `database` | string | Yes | Database the query runs against | +| `queryString` | string | Yes | SQL query string to save | +| `description` | string | No | Description of the named query | +| `workGroup` | string | No | Workgroup to create the named query in | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `namedQueryId` | string | ID of the created named query | + +### `athena_get_named_query` + +Get details of a saved/named query in AWS Athena + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `awsRegion` | string | Yes | AWS region \(e.g., us-east-1\) | +| `awsAccessKeyId` | string | Yes | AWS access key ID | +| `awsSecretAccessKey` | string | Yes | AWS secret access key | +| `namedQueryId` | string | Yes | Named query ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `namedQueryId` | string | Named query ID | +| `name` | string | Name of the saved query | +| `description` | string | Query description | +| `database` | string | Database the query runs against | +| `queryString` | string | SQL query string | +| `workGroup` | string | Workgroup name | + +### `athena_list_named_queries` + +List saved/named query IDs in AWS Athena + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `awsRegion` | string | Yes | AWS region \(e.g., us-east-1\) | +| `awsAccessKeyId` | string | Yes | AWS access key ID | +| `awsSecretAccessKey` | string | Yes | AWS secret access key | +| `workGroup` | string | No | Workgroup to list named queries for | +| `maxResults` | number | No | Maximum number of results \(0-50\) | +| `nextToken` | string | No | Pagination token from a previous request | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `namedQueryIds` | array | List of named query IDs | +| `nextToken` | string | Pagination token for next page | + + diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index e413b867f71..2a8e6ba0c89 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -13,6 +13,7 @@ "arxiv", "asana", "ashby", + "athena", "attio", "box", "brandfetch", diff --git a/apps/sim/app/(landing)/integrations/data/icon-mapping.ts b/apps/sim/app/(landing)/integrations/data/icon-mapping.ts index 898ee4287ee..ddf28d4d7a6 100644 --- a/apps/sim/app/(landing)/integrations/data/icon-mapping.ts +++ b/apps/sim/app/(landing)/integrations/data/icon-mapping.ts @@ -16,6 +16,7 @@ import { ArxivIcon, AsanaIcon, AshbyIcon, + AthenaIcon, AttioIcon, AzureIcon, BoxCompanyIcon, @@ -205,6 +206,7 @@ export const blockTypeToIconMap: Record = { arxiv: ArxivIcon, asana: AsanaIcon, ashby: AshbyIcon, + athena: AthenaIcon, attio: AttioIcon, box: BoxCompanyIcon, brandfetch: BrandfetchIcon, diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index 7108dacc096..e6658415998 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -971,6 +971,57 @@ "integrationType": "hr", "tags": ["hiring"] }, + { + "type": "athena", + "slug": "athena", + "name": "Athena", + "description": "Run SQL queries on data in Amazon S3 using AWS Athena", + "longDescription": "Integrate AWS Athena into workflows. Execute SQL queries against data in S3, check query status, retrieve results, manage named queries, and list executions. Requires AWS access key and secret access key.", + "bgColor": "linear-gradient(45deg, #4D27A8 0%, #A166FF 100%)", + "iconName": "AthenaIcon", + "docsUrl": "https://docs.sim.ai/tools/athena", + "operations": [ + { + "name": "Start Query", + "description": "Start an SQL query execution in AWS Athena" + }, + { + "name": "Get Query Execution", + "description": "Get the status and details of an Athena query execution" + }, + { + "name": "Get Query Results", + "description": "Retrieve the results of a completed Athena query execution" + }, + { + "name": "Stop Query", + "description": "Stop a running Athena query execution" + }, + { + "name": "List Query Executions", + "description": "List recent Athena query execution IDs" + }, + { + "name": "Create Named Query", + "description": "Create a saved/named query in AWS Athena" + }, + { + "name": "Get Named Query", + "description": "Get details of a saved/named query in AWS Athena" + }, + { + "name": "List Named Queries", + "description": "List saved/named query IDs in AWS Athena" + } + ], + "operationCount": 8, + "triggers": [], + "triggerCount": 0, + "authType": "none", + "category": "tools", + "integrationType": "analytics", + "tags": ["cloud", "data-analytics"] + }, { "type": "attio", "slug": "attio", diff --git a/apps/sim/app/api/tools/athena/create-named-query/route.ts b/apps/sim/app/api/tools/athena/create-named-query/route.ts new file mode 100644 index 00000000000..f9f997d618e --- /dev/null +++ b/apps/sim/app/api/tools/athena/create-named-query/route.ts @@ -0,0 +1,63 @@ +import { CreateNamedQueryCommand } from '@aws-sdk/client-athena' +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { createAthenaClient } from '@/app/api/tools/athena/utils' + +const logger = createLogger('AthenaCreateNamedQuery') + +const CreateNamedQuerySchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + name: z.string().min(1, 'Query name is required'), + database: z.string().min(1, 'Database is required'), + queryString: z.string().min(1, 'Query string is required'), + description: z.string().optional(), + workGroup: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + try { + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + const body = await request.json() + const data = CreateNamedQuerySchema.parse(body) + + const client = createAthenaClient({ + region: data.region, + accessKeyId: data.accessKeyId, + secretAccessKey: data.secretAccessKey, + }) + + const command = new CreateNamedQueryCommand({ + Name: data.name, + Database: data.database, + QueryString: data.queryString, + ...(data.description && { Description: data.description }), + ...(data.workGroup && { WorkGroup: data.workGroup }), + }) + + const response = await client.send(command) + + if (!response.NamedQueryId) { + throw new Error('No named query ID returned') + } + + return NextResponse.json({ + success: true, + output: { + namedQueryId: response.NamedQueryId, + }, + }) + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : 'Failed to create Athena named query' + logger.error('CreateNamedQuery failed', { error: errorMessage }) + return NextResponse.json({ error: errorMessage }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/athena/get-named-query/route.ts b/apps/sim/app/api/tools/athena/get-named-query/route.ts new file mode 100644 index 00000000000..83e9845b75c --- /dev/null +++ b/apps/sim/app/api/tools/athena/get-named-query/route.ts @@ -0,0 +1,60 @@ +import { GetNamedQueryCommand } from '@aws-sdk/client-athena' +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { createAthenaClient } from '@/app/api/tools/athena/utils' + +const logger = createLogger('AthenaGetNamedQuery') + +const GetNamedQuerySchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + namedQueryId: z.string().min(1, 'Named query ID is required'), +}) + +export async function POST(request: NextRequest) { + try { + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + const body = await request.json() + const data = GetNamedQuerySchema.parse(body) + + const client = createAthenaClient({ + region: data.region, + accessKeyId: data.accessKeyId, + secretAccessKey: data.secretAccessKey, + }) + + const command = new GetNamedQueryCommand({ + NamedQueryId: data.namedQueryId, + }) + + const response = await client.send(command) + const namedQuery = response.NamedQuery + + if (!namedQuery) { + throw new Error('No named query data returned') + } + + return NextResponse.json({ + success: true, + output: { + namedQueryId: namedQuery.NamedQueryId ?? data.namedQueryId, + name: namedQuery.Name ?? '', + description: namedQuery.Description ?? null, + database: namedQuery.Database ?? '', + queryString: namedQuery.QueryString ?? '', + workGroup: namedQuery.WorkGroup ?? null, + }, + }) + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Failed to get Athena named query' + logger.error('GetNamedQuery failed', { error: errorMessage }) + return NextResponse.json({ error: errorMessage }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/athena/get-query-execution/route.ts b/apps/sim/app/api/tools/athena/get-query-execution/route.ts new file mode 100644 index 00000000000..b043db11414 --- /dev/null +++ b/apps/sim/app/api/tools/athena/get-query-execution/route.ts @@ -0,0 +1,71 @@ +import { GetQueryExecutionCommand } from '@aws-sdk/client-athena' +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { createAthenaClient } from '@/app/api/tools/athena/utils' + +const logger = createLogger('AthenaGetQueryExecution') + +const GetQueryExecutionSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + queryExecutionId: z.string().min(1, 'Query execution ID is required'), +}) + +export async function POST(request: NextRequest) { + try { + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + const body = await request.json() + const data = GetQueryExecutionSchema.parse(body) + + const client = createAthenaClient({ + region: data.region, + accessKeyId: data.accessKeyId, + secretAccessKey: data.secretAccessKey, + }) + + const command = new GetQueryExecutionCommand({ + QueryExecutionId: data.queryExecutionId, + }) + + const response = await client.send(command) + const execution = response.QueryExecution + + if (!execution) { + throw new Error('No query execution data returned') + } + + return NextResponse.json({ + success: true, + output: { + queryExecutionId: execution.QueryExecutionId ?? data.queryExecutionId, + query: execution.Query ?? '', + state: execution.Status?.State ?? 'UNKNOWN', + stateChangeReason: execution.Status?.StateChangeReason ?? null, + statementType: execution.StatementType ?? null, + database: execution.QueryExecutionContext?.Database ?? null, + catalog: execution.QueryExecutionContext?.Catalog ?? null, + workGroup: execution.WorkGroup ?? null, + submissionDateTime: execution.Status?.SubmissionDateTime?.getTime() ?? null, + completionDateTime: execution.Status?.CompletionDateTime?.getTime() ?? null, + dataScannedInBytes: execution.Statistics?.DataScannedInBytes ?? null, + engineExecutionTimeInMillis: execution.Statistics?.EngineExecutionTimeInMillis ?? null, + queryPlanningTimeInMillis: execution.Statistics?.QueryPlanningTimeInMillis ?? null, + queryQueueTimeInMillis: execution.Statistics?.QueryQueueTimeInMillis ?? null, + totalExecutionTimeInMillis: execution.Statistics?.TotalExecutionTimeInMillis ?? null, + outputLocation: execution.ResultConfiguration?.OutputLocation ?? null, + }, + }) + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : 'Failed to get Athena query execution' + logger.error('GetQueryExecution failed', { error: errorMessage }) + return NextResponse.json({ error: errorMessage }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/athena/get-query-results/route.ts b/apps/sim/app/api/tools/athena/get-query-results/route.ts new file mode 100644 index 00000000000..d89488371db --- /dev/null +++ b/apps/sim/app/api/tools/athena/get-query-results/route.ts @@ -0,0 +1,82 @@ +import { GetQueryResultsCommand } from '@aws-sdk/client-athena' +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { createAthenaClient } from '@/app/api/tools/athena/utils' + +const logger = createLogger('AthenaGetQueryResults') + +const GetQueryResultsSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + queryExecutionId: z.string().min(1, 'Query execution ID is required'), + maxResults: z.preprocess( + (v) => (v === '' || v === undefined || v === null ? undefined : v), + z.number({ coerce: true }).int().positive().max(999).optional() + ), + nextToken: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + try { + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + const body = await request.json() + const data = GetQueryResultsSchema.parse(body) + + const client = createAthenaClient({ + region: data.region, + accessKeyId: data.accessKeyId, + secretAccessKey: data.secretAccessKey, + }) + + const isFirstPage = !data.nextToken + const adjustedMaxResults = + data.maxResults !== undefined && isFirstPage ? data.maxResults + 1 : data.maxResults + + const command = new GetQueryResultsCommand({ + QueryExecutionId: data.queryExecutionId, + ...(adjustedMaxResults !== undefined && { MaxResults: adjustedMaxResults }), + ...(data.nextToken && { NextToken: data.nextToken }), + }) + + const response = await client.send(command) + + const columnInfo = response.ResultSet?.ResultSetMetadata?.ColumnInfo ?? [] + const columns = columnInfo.map((col) => ({ + name: col.Name ?? '', + type: col.Type ?? 'varchar', + })) + + const rawRows = response.ResultSet?.Rows ?? [] + const dataRows = data.nextToken ? rawRows : rawRows.slice(1) + const rows = dataRows.map((row) => { + const record: Record = {} + const rowData = row.Data ?? [] + for (let i = 0; i < columns.length; i++) { + record[columns[i].name] = rowData[i]?.VarCharValue ?? '' + } + return record + }) + + return NextResponse.json({ + success: true, + output: { + columns, + rows, + nextToken: response.NextToken ?? null, + updateCount: response.UpdateCount ?? null, + }, + }) + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : 'Failed to get Athena query results' + logger.error('GetQueryResults failed', { error: errorMessage }) + return NextResponse.json({ error: errorMessage }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/athena/list-named-queries/route.ts b/apps/sim/app/api/tools/athena/list-named-queries/route.ts new file mode 100644 index 00000000000..c9f74ca2161 --- /dev/null +++ b/apps/sim/app/api/tools/athena/list-named-queries/route.ts @@ -0,0 +1,59 @@ +import { ListNamedQueriesCommand } from '@aws-sdk/client-athena' +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { createAthenaClient } from '@/app/api/tools/athena/utils' + +const logger = createLogger('AthenaListNamedQueries') + +const ListNamedQueriesSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + workGroup: z.string().optional(), + maxResults: z.preprocess( + (v) => (v === '' || v === undefined || v === null ? undefined : v), + z.number({ coerce: true }).int().min(0).max(50).optional() + ), + nextToken: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + try { + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + const body = await request.json() + const data = ListNamedQueriesSchema.parse(body) + + const client = createAthenaClient({ + region: data.region, + accessKeyId: data.accessKeyId, + secretAccessKey: data.secretAccessKey, + }) + + const command = new ListNamedQueriesCommand({ + ...(data.workGroup && { WorkGroup: data.workGroup }), + ...(data.maxResults !== undefined && { MaxResults: data.maxResults }), + ...(data.nextToken && { NextToken: data.nextToken }), + }) + + const response = await client.send(command) + + return NextResponse.json({ + success: true, + output: { + namedQueryIds: response.NamedQueryIds ?? [], + nextToken: response.NextToken ?? null, + }, + }) + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : 'Failed to list Athena named queries' + logger.error('ListNamedQueries failed', { error: errorMessage }) + return NextResponse.json({ error: errorMessage }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/athena/list-query-executions/route.ts b/apps/sim/app/api/tools/athena/list-query-executions/route.ts new file mode 100644 index 00000000000..096afee99cb --- /dev/null +++ b/apps/sim/app/api/tools/athena/list-query-executions/route.ts @@ -0,0 +1,59 @@ +import { ListQueryExecutionsCommand } from '@aws-sdk/client-athena' +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { createAthenaClient } from '@/app/api/tools/athena/utils' + +const logger = createLogger('AthenaListQueryExecutions') + +const ListQueryExecutionsSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + workGroup: z.string().optional(), + maxResults: z.preprocess( + (v) => (v === '' || v === undefined || v === null ? undefined : v), + z.number({ coerce: true }).int().min(0).max(50).optional() + ), + nextToken: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + try { + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + const body = await request.json() + const data = ListQueryExecutionsSchema.parse(body) + + const client = createAthenaClient({ + region: data.region, + accessKeyId: data.accessKeyId, + secretAccessKey: data.secretAccessKey, + }) + + const command = new ListQueryExecutionsCommand({ + ...(data.workGroup && { WorkGroup: data.workGroup }), + ...(data.maxResults !== undefined && { MaxResults: data.maxResults }), + ...(data.nextToken && { NextToken: data.nextToken }), + }) + + const response = await client.send(command) + + return NextResponse.json({ + success: true, + output: { + queryExecutionIds: response.QueryExecutionIds ?? [], + nextToken: response.NextToken ?? null, + }, + }) + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : 'Failed to list Athena query executions' + logger.error('ListQueryExecutions failed', { error: errorMessage }) + return NextResponse.json({ error: errorMessage }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/athena/start-query/route.ts b/apps/sim/app/api/tools/athena/start-query/route.ts new file mode 100644 index 00000000000..6af793cbe01 --- /dev/null +++ b/apps/sim/app/api/tools/athena/start-query/route.ts @@ -0,0 +1,74 @@ +import { StartQueryExecutionCommand } from '@aws-sdk/client-athena' +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { createAthenaClient } from '@/app/api/tools/athena/utils' + +const logger = createLogger('AthenaStartQuery') + +const StartQuerySchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + queryString: z.string().min(1, 'Query string is required'), + database: z.string().optional(), + catalog: z.string().optional(), + outputLocation: z.string().optional(), + workGroup: z.string().optional(), +}) + +export async function POST(request: NextRequest) { + try { + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + const body = await request.json() + const data = StartQuerySchema.parse(body) + + const client = createAthenaClient({ + region: data.region, + accessKeyId: data.accessKeyId, + secretAccessKey: data.secretAccessKey, + }) + + const command = new StartQueryExecutionCommand({ + QueryString: data.queryString, + ...(data.database || data.catalog + ? { + QueryExecutionContext: { + ...(data.database && { Database: data.database }), + ...(data.catalog && { Catalog: data.catalog }), + }, + } + : {}), + ...(data.outputLocation + ? { + ResultConfiguration: { + OutputLocation: data.outputLocation, + }, + } + : {}), + ...(data.workGroup && { WorkGroup: data.workGroup }), + }) + + const response = await client.send(command) + + if (!response.QueryExecutionId) { + throw new Error('No query execution ID returned') + } + + return NextResponse.json({ + success: true, + output: { + queryExecutionId: response.QueryExecutionId, + }, + }) + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Failed to start Athena query' + logger.error('StartQuery failed', { error: errorMessage }) + return NextResponse.json({ error: errorMessage }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/athena/stop-query/route.ts b/apps/sim/app/api/tools/athena/stop-query/route.ts new file mode 100644 index 00000000000..2f3422b36e2 --- /dev/null +++ b/apps/sim/app/api/tools/athena/stop-query/route.ts @@ -0,0 +1,50 @@ +import { StopQueryExecutionCommand } from '@aws-sdk/client-athena' +import { createLogger } from '@sim/logger' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { createAthenaClient } from '@/app/api/tools/athena/utils' + +const logger = createLogger('AthenaStopQuery') + +const StopQuerySchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + queryExecutionId: z.string().min(1, 'Query execution ID is required'), +}) + +export async function POST(request: NextRequest) { + try { + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + const body = await request.json() + const data = StopQuerySchema.parse(body) + + const client = createAthenaClient({ + region: data.region, + accessKeyId: data.accessKeyId, + secretAccessKey: data.secretAccessKey, + }) + + const command = new StopQueryExecutionCommand({ + QueryExecutionId: data.queryExecutionId, + }) + + await client.send(command) + + return NextResponse.json({ + success: true, + output: { + success: true, + }, + }) + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Failed to stop Athena query' + logger.error('StopQuery failed', { error: errorMessage }) + return NextResponse.json({ error: errorMessage }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/athena/utils.ts b/apps/sim/app/api/tools/athena/utils.ts new file mode 100644 index 00000000000..1d52a2ffe64 --- /dev/null +++ b/apps/sim/app/api/tools/athena/utils.ts @@ -0,0 +1,17 @@ +import { AthenaClient } from '@aws-sdk/client-athena' + +interface AwsCredentials { + region: string + accessKeyId: string + secretAccessKey: string +} + +export function createAthenaClient(config: AwsCredentials): AthenaClient { + return new AthenaClient({ + region: config.region, + credentials: { + accessKeyId: config.accessKeyId, + secretAccessKey: config.secretAccessKey, + }, + }) +} diff --git a/apps/sim/blocks/blocks/athena.ts b/apps/sim/blocks/blocks/athena.ts new file mode 100644 index 00000000000..8952586db61 --- /dev/null +++ b/apps/sim/blocks/blocks/athena.ts @@ -0,0 +1,469 @@ +import { AthenaIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' +import type { + AthenaCreateNamedQueryResponse, + AthenaGetNamedQueryResponse, + AthenaGetQueryExecutionResponse, + AthenaGetQueryResultsResponse, + AthenaListNamedQueriesResponse, + AthenaListQueryExecutionsResponse, + AthenaStartQueryResponse, + AthenaStopQueryResponse, +} from '@/tools/athena/types' + +export const AthenaBlock: BlockConfig< + | AthenaStartQueryResponse + | AthenaGetQueryExecutionResponse + | AthenaGetQueryResultsResponse + | AthenaStopQueryResponse + | AthenaListQueryExecutionsResponse + | AthenaCreateNamedQueryResponse + | AthenaGetNamedQueryResponse + | AthenaListNamedQueriesResponse +> = { + type: 'athena', + name: 'Athena', + description: 'Run SQL queries on data in Amazon S3 using AWS Athena', + longDescription: + 'Integrate AWS Athena into workflows. Execute SQL queries against data in S3, check query status, retrieve results, manage named queries, and list executions. Requires AWS access key and secret access key.', + docsLink: 'https://docs.sim.ai/tools/athena', + category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['cloud', 'data-analytics'], + bgColor: 'linear-gradient(45deg, #4D27A8 0%, #A166FF 100%)', + icon: AthenaIcon, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'Start Query', id: 'start_query' }, + { label: 'Get Query Execution', id: 'get_query_execution' }, + { label: 'Get Query Results', id: 'get_query_results' }, + { label: 'Stop Query', id: 'stop_query' }, + { label: 'List Query Executions', id: 'list_query_executions' }, + { label: 'Create Named Query', id: 'create_named_query' }, + { label: 'Get Named Query', id: 'get_named_query' }, + { label: 'List Named Queries', id: 'list_named_queries' }, + ], + value: () => 'start_query', + }, + { + id: 'awsRegion', + title: 'AWS Region', + type: 'short-input', + placeholder: 'us-east-1', + required: true, + }, + { + id: 'awsAccessKeyId', + title: 'AWS Access Key ID', + type: 'short-input', + placeholder: 'AKIA...', + password: true, + required: true, + }, + { + id: 'awsSecretAccessKey', + title: 'AWS Secret Access Key', + type: 'short-input', + placeholder: 'Your secret access key', + password: true, + required: true, + }, + { + id: 'queryString', + title: 'SQL Query', + type: 'code', + placeholder: 'SELECT * FROM my_table LIMIT 10', + condition: { field: 'operation', value: ['start_query', 'create_named_query'] }, + required: { field: 'operation', value: ['start_query', 'create_named_query'] }, + wandConfig: { + enabled: true, + prompt: `Generate an SQL query for AWS Athena based on the user's description. +Athena uses Trino/Presto SQL syntax. Common patterns: +- SELECT * FROM "database"."table" LIMIT 10 +- SELECT column1, COUNT(*) FROM table GROUP BY column1 +- SELECT * FROM table WHERE date_column > DATE '2024-01-01' +- CREATE TABLE new_table AS SELECT ... FROM source_table +- SELECT * FROM table WHERE column IN ('value1', 'value2') + +Return ONLY the SQL query — no explanations, no markdown code blocks.`, + placeholder: 'Describe what data you want to query...', + }, + }, + { + id: 'database', + title: 'Database', + type: 'short-input', + placeholder: 'my_database', + condition: { field: 'operation', value: ['start_query', 'create_named_query'] }, + required: { field: 'operation', value: 'create_named_query' }, + }, + { + id: 'catalog', + title: 'Data Catalog', + type: 'short-input', + placeholder: 'AwsDataCatalog', + condition: { field: 'operation', value: 'start_query' }, + mode: 'advanced', + }, + { + id: 'outputLocation', + title: 'Output Location (S3)', + type: 'short-input', + placeholder: 's3://my-bucket/athena-results/', + condition: { field: 'operation', value: 'start_query' }, + mode: 'advanced', + }, + { + id: 'workGroup', + title: 'Workgroup', + type: 'short-input', + placeholder: 'primary', + condition: { + field: 'operation', + value: ['start_query', 'list_query_executions', 'create_named_query', 'list_named_queries'], + }, + mode: 'advanced', + }, + { + id: 'queryExecutionId', + title: 'Query Execution ID', + type: 'short-input', + placeholder: 'e.g., a1b2c3d4-5678-90ab-cdef-example11111', + condition: { + field: 'operation', + value: ['get_query_execution', 'get_query_results', 'stop_query'], + }, + required: { + field: 'operation', + value: ['get_query_execution', 'get_query_results', 'stop_query'], + }, + }, + { + id: 'namedQueryId', + title: 'Named Query ID', + type: 'short-input', + placeholder: 'e.g., a1b2c3d4-5678-90ab-cdef-example11111', + condition: { field: 'operation', value: 'get_named_query' }, + required: { field: 'operation', value: 'get_named_query' }, + }, + { + id: 'queryName', + title: 'Query Name', + type: 'short-input', + placeholder: 'My Saved Query', + condition: { field: 'operation', value: 'create_named_query' }, + required: { field: 'operation', value: 'create_named_query' }, + }, + { + id: 'queryDescription', + title: 'Description', + type: 'short-input', + placeholder: 'Description of what this query does', + condition: { field: 'operation', value: 'create_named_query' }, + mode: 'advanced', + }, + { + id: 'maxResults', + title: 'Max Results', + type: 'short-input', + placeholder: '50', + condition: { + field: 'operation', + value: ['get_query_results', 'list_query_executions', 'list_named_queries'], + }, + mode: 'advanced', + }, + { + id: 'nextToken', + title: 'Pagination Token', + type: 'short-input', + placeholder: 'Token from previous request', + condition: { + field: 'operation', + value: ['get_query_results', 'list_query_executions', 'list_named_queries'], + }, + mode: 'advanced', + }, + ], + tools: { + access: [ + 'athena_start_query', + 'athena_get_query_execution', + 'athena_get_query_results', + 'athena_stop_query', + 'athena_list_query_executions', + 'athena_create_named_query', + 'athena_get_named_query', + 'athena_list_named_queries', + ], + config: { + tool: (params) => { + switch (params.operation) { + case 'start_query': + return 'athena_start_query' + case 'get_query_execution': + return 'athena_get_query_execution' + case 'get_query_results': + return 'athena_get_query_results' + case 'stop_query': + return 'athena_stop_query' + case 'list_query_executions': + return 'athena_list_query_executions' + case 'create_named_query': + return 'athena_create_named_query' + case 'get_named_query': + return 'athena_get_named_query' + case 'list_named_queries': + return 'athena_list_named_queries' + default: + throw new Error(`Invalid Athena operation: ${params.operation}`) + } + }, + params: (params) => { + const { operation, maxResults, ...rest } = params + + const awsRegion = rest.awsRegion + const awsAccessKeyId = rest.awsAccessKeyId + const awsSecretAccessKey = rest.awsSecretAccessKey + const parsedMaxResults = maxResults ? Number.parseInt(String(maxResults), 10) : undefined + + switch (operation) { + case 'start_query': + return { + awsRegion, + awsAccessKeyId, + awsSecretAccessKey, + queryString: rest.queryString, + ...(rest.database && { database: rest.database }), + ...(rest.catalog && { catalog: rest.catalog }), + ...(rest.outputLocation && { outputLocation: rest.outputLocation }), + ...(rest.workGroup && { workGroup: rest.workGroup }), + } + + case 'get_query_execution': + if (!rest.queryExecutionId) { + throw new Error('Query execution ID is required') + } + return { + awsRegion, + awsAccessKeyId, + awsSecretAccessKey, + queryExecutionId: rest.queryExecutionId, + } + + case 'get_query_results': + if (!rest.queryExecutionId) { + throw new Error('Query execution ID is required') + } + return { + awsRegion, + awsAccessKeyId, + awsSecretAccessKey, + queryExecutionId: rest.queryExecutionId, + ...(parsedMaxResults !== undefined && { maxResults: parsedMaxResults }), + ...(rest.nextToken && { nextToken: rest.nextToken }), + } + + case 'stop_query': + if (!rest.queryExecutionId) { + throw new Error('Query execution ID is required') + } + return { + awsRegion, + awsAccessKeyId, + awsSecretAccessKey, + queryExecutionId: rest.queryExecutionId, + } + + case 'list_query_executions': + return { + awsRegion, + awsAccessKeyId, + awsSecretAccessKey, + ...(rest.workGroup && { workGroup: rest.workGroup }), + ...(parsedMaxResults !== undefined && { maxResults: parsedMaxResults }), + ...(rest.nextToken && { nextToken: rest.nextToken }), + } + + case 'create_named_query': { + if (!rest.queryName) { + throw new Error('Query name is required') + } + if (!rest.database) { + throw new Error('Database is required') + } + if (!rest.queryString) { + throw new Error('SQL query string is required') + } + return { + awsRegion, + awsAccessKeyId, + awsSecretAccessKey, + name: rest.queryName, + database: rest.database, + queryString: rest.queryString, + ...(rest.queryDescription && { description: rest.queryDescription }), + ...(rest.workGroup && { workGroup: rest.workGroup }), + } + } + + case 'get_named_query': + if (!rest.namedQueryId) { + throw new Error('Named query ID is required') + } + return { + awsRegion, + awsAccessKeyId, + awsSecretAccessKey, + namedQueryId: rest.namedQueryId, + } + + case 'list_named_queries': + return { + awsRegion, + awsAccessKeyId, + awsSecretAccessKey, + ...(rest.workGroup && { workGroup: rest.workGroup }), + ...(parsedMaxResults !== undefined && { maxResults: parsedMaxResults }), + ...(rest.nextToken && { nextToken: rest.nextToken }), + } + + default: + throw new Error(`Invalid Athena operation: ${operation}`) + } + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'Athena operation to perform' }, + awsRegion: { type: 'string', description: 'AWS region' }, + awsAccessKeyId: { type: 'string', description: 'AWS access key ID' }, + awsSecretAccessKey: { type: 'string', description: 'AWS secret access key' }, + queryString: { type: 'string', description: 'SQL query string' }, + database: { type: 'string', description: 'Database name' }, + catalog: { type: 'string', description: 'Data catalog name' }, + outputLocation: { type: 'string', description: 'S3 output location for results' }, + workGroup: { type: 'string', description: 'Athena workgroup name' }, + queryExecutionId: { type: 'string', description: 'Query execution ID' }, + namedQueryId: { type: 'string', description: 'Named query ID' }, + queryName: { type: 'string', description: 'Name for a saved query' }, + queryDescription: { type: 'string', description: 'Description for a saved query' }, + maxResults: { type: 'number', description: 'Maximum number of results' }, + nextToken: { type: 'string', description: 'Pagination token' }, + }, + outputs: { + queryExecutionId: { + type: 'string', + description: 'Query execution ID', + }, + query: { + type: 'string', + description: 'SQL query string', + }, + state: { + type: 'string', + description: 'Query state (QUEUED, RUNNING, SUCCEEDED, FAILED, CANCELLED)', + }, + stateChangeReason: { + type: 'string', + description: 'Reason for state change', + }, + statementType: { + type: 'string', + description: 'Statement type (DDL, DML, UTILITY)', + }, + database: { + type: 'string', + description: 'Database name', + }, + catalog: { + type: 'string', + description: 'Data catalog name', + }, + workGroup: { + type: 'string', + description: 'Workgroup name', + }, + submissionDateTime: { + type: 'number', + description: 'Query submission time (Unix epoch ms)', + }, + completionDateTime: { + type: 'number', + description: 'Query completion time (Unix epoch ms)', + }, + dataScannedInBytes: { + type: 'number', + description: 'Data scanned in bytes', + }, + engineExecutionTimeInMillis: { + type: 'number', + description: 'Engine execution time in ms', + }, + queryPlanningTimeInMillis: { + type: 'number', + description: 'Query planning time in ms', + }, + queryQueueTimeInMillis: { + type: 'number', + description: 'Time spent in queue in ms', + }, + totalExecutionTimeInMillis: { + type: 'number', + description: 'Total execution time in ms', + }, + outputLocation: { + type: 'string', + description: 'S3 location of query results', + }, + columns: { + type: 'array', + description: 'Column metadata (name and type)', + }, + rows: { + type: 'array', + description: 'Result rows as key-value objects', + }, + nextToken: { + type: 'string', + description: 'Pagination token for next page', + }, + updateCount: { + type: 'number', + description: 'Rows affected by INSERT/UPDATE', + }, + success: { + type: 'boolean', + description: 'Whether the operation succeeded', + }, + queryExecutionIds: { + type: 'array', + description: 'List of query execution IDs', + }, + namedQueryId: { + type: 'string', + description: 'Named query ID', + }, + name: { + type: 'string', + description: 'Named query name', + }, + description: { + type: 'string', + description: 'Named query description', + }, + queryString: { + type: 'string', + description: 'Named query SQL string', + }, + namedQueryIds: { + type: 'array', + description: 'List of named query IDs', + }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index d37f90edfcf..aa915441d73 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -13,6 +13,7 @@ import { ApolloBlock } from '@/blocks/blocks/apollo' import { ArxivBlock } from '@/blocks/blocks/arxiv' import { AsanaBlock } from '@/blocks/blocks/asana' import { AshbyBlock } from '@/blocks/blocks/ashby' +import { AthenaBlock } from '@/blocks/blocks/athena' import { AttioBlock } from '@/blocks/blocks/attio' import { BoxBlock } from '@/blocks/blocks/box' import { BrandfetchBlock } from '@/blocks/blocks/brandfetch' @@ -236,6 +237,7 @@ export const registry: Record = { arxiv: ArxivBlock, asana: AsanaBlock, ashby: AshbyBlock, + athena: AthenaBlock, attio: AttioBlock, brandfetch: BrandfetchBlock, box: BoxBlock, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 8b0ed3aabb1..2806cd4d314 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -4687,6 +4687,33 @@ export function CloudFormationIcon(props: SVGProps) { ) } +export function AthenaIcon(props: SVGProps) { + return ( + + + + + + ) +} + export function CloudWatchIcon(props: SVGProps) { return ( = { + id: 'athena_create_named_query', + name: 'Athena Create Named Query', + description: 'Create a saved/named query in AWS Athena', + version: '1.0', + + params: { + awsRegion: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + awsAccessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + awsSecretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + name: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name for the saved query', + }, + database: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Database the query runs against', + }, + queryString: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'SQL query string to save', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Description of the named query', + }, + workGroup: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Workgroup to create the named query in', + }, + }, + + request: { + url: '/api/tools/athena/create-named-query', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.awsRegion, + accessKeyId: params.awsAccessKeyId, + secretAccessKey: params.awsSecretAccessKey, + name: params.name, + database: params.database, + queryString: params.queryString, + ...(params.description && { description: params.description }), + ...(params.workGroup && { workGroup: params.workGroup }), + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.error || 'Failed to create Athena named query') + } + return { + success: true, + output: { + namedQueryId: data.output.namedQueryId, + }, + } + }, + + outputs: { + namedQueryId: { + type: 'string', + description: 'ID of the created named query', + }, + }, +} diff --git a/apps/sim/tools/athena/get_named_query.ts b/apps/sim/tools/athena/get_named_query.ts new file mode 100644 index 00000000000..28cafac4579 --- /dev/null +++ b/apps/sim/tools/athena/get_named_query.ts @@ -0,0 +1,76 @@ +import type { AthenaGetNamedQueryParams, AthenaGetNamedQueryResponse } from '@/tools/athena/types' +import type { ToolConfig } from '@/tools/types' + +export const getNamedQueryTool: ToolConfig = + { + id: 'athena_get_named_query', + name: 'Athena Get Named Query', + description: 'Get details of a saved/named query in AWS Athena', + version: '1.0', + + params: { + awsRegion: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + awsAccessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + awsSecretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + namedQueryId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Named query ID to retrieve', + }, + }, + + request: { + url: '/api/tools/athena/get-named-query', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.awsRegion, + accessKeyId: params.awsAccessKeyId, + secretAccessKey: params.awsSecretAccessKey, + namedQueryId: params.namedQueryId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.error || 'Failed to get Athena named query') + } + return { + success: true, + output: { + namedQueryId: data.output.namedQueryId, + name: data.output.name, + description: data.output.description ?? null, + database: data.output.database, + queryString: data.output.queryString, + workGroup: data.output.workGroup ?? null, + }, + } + }, + + outputs: { + namedQueryId: { type: 'string', description: 'Named query ID' }, + name: { type: 'string', description: 'Name of the saved query' }, + description: { type: 'string', description: 'Query description', optional: true }, + database: { type: 'string', description: 'Database the query runs against' }, + queryString: { type: 'string', description: 'SQL query string' }, + workGroup: { type: 'string', description: 'Workgroup name', optional: true }, + }, + } diff --git a/apps/sim/tools/athena/get_query_execution.ts b/apps/sim/tools/athena/get_query_execution.ts new file mode 100644 index 00000000000..8ebe407813a --- /dev/null +++ b/apps/sim/tools/athena/get_query_execution.ts @@ -0,0 +1,144 @@ +import type { + AthenaGetQueryExecutionParams, + AthenaGetQueryExecutionResponse, +} from '@/tools/athena/types' +import type { ToolConfig } from '@/tools/types' + +export const getQueryExecutionTool: ToolConfig< + AthenaGetQueryExecutionParams, + AthenaGetQueryExecutionResponse +> = { + id: 'athena_get_query_execution', + name: 'Athena Get Query Execution', + description: 'Get the status and details of an Athena query execution', + version: '1.0', + + params: { + awsRegion: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + awsAccessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + awsSecretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + queryExecutionId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Query execution ID to check', + }, + }, + + request: { + url: '/api/tools/athena/get-query-execution', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.awsRegion, + accessKeyId: params.awsAccessKeyId, + secretAccessKey: params.awsSecretAccessKey, + queryExecutionId: params.queryExecutionId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.error || 'Failed to get Athena query execution') + } + return { + success: true, + output: { + queryExecutionId: data.output.queryExecutionId, + query: data.output.query, + state: data.output.state, + stateChangeReason: data.output.stateChangeReason ?? null, + statementType: data.output.statementType ?? null, + database: data.output.database ?? null, + catalog: data.output.catalog ?? null, + workGroup: data.output.workGroup ?? null, + submissionDateTime: data.output.submissionDateTime ?? null, + completionDateTime: data.output.completionDateTime ?? null, + dataScannedInBytes: data.output.dataScannedInBytes ?? null, + engineExecutionTimeInMillis: data.output.engineExecutionTimeInMillis ?? null, + queryPlanningTimeInMillis: data.output.queryPlanningTimeInMillis ?? null, + queryQueueTimeInMillis: data.output.queryQueueTimeInMillis ?? null, + totalExecutionTimeInMillis: data.output.totalExecutionTimeInMillis ?? null, + outputLocation: data.output.outputLocation ?? null, + }, + } + }, + + outputs: { + queryExecutionId: { type: 'string', description: 'Query execution ID' }, + query: { type: 'string', description: 'SQL query string' }, + state: { + type: 'string', + description: 'Query state (QUEUED, RUNNING, SUCCEEDED, FAILED, CANCELLED)', + }, + stateChangeReason: { + type: 'string', + description: 'Reason for state change (e.g., error message)', + optional: true, + }, + statementType: { + type: 'string', + description: 'Statement type (DDL, DML, UTILITY)', + optional: true, + }, + database: { type: 'string', description: 'Database name', optional: true }, + catalog: { type: 'string', description: 'Data catalog name', optional: true }, + workGroup: { type: 'string', description: 'Workgroup name', optional: true }, + submissionDateTime: { + type: 'number', + description: 'Query submission time (Unix epoch ms)', + optional: true, + }, + completionDateTime: { + type: 'number', + description: 'Query completion time (Unix epoch ms)', + optional: true, + }, + dataScannedInBytes: { + type: 'number', + description: 'Amount of data scanned in bytes', + optional: true, + }, + engineExecutionTimeInMillis: { + type: 'number', + description: 'Engine execution time in milliseconds', + optional: true, + }, + queryPlanningTimeInMillis: { + type: 'number', + description: 'Query planning time in milliseconds', + optional: true, + }, + queryQueueTimeInMillis: { + type: 'number', + description: 'Time the query spent in queue in milliseconds', + optional: true, + }, + totalExecutionTimeInMillis: { + type: 'number', + description: 'Total execution time in milliseconds', + optional: true, + }, + outputLocation: { + type: 'string', + description: 'S3 location of query results', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/athena/get_query_results.ts b/apps/sim/tools/athena/get_query_results.ts new file mode 100644 index 00000000000..8e53af03530 --- /dev/null +++ b/apps/sim/tools/athena/get_query_results.ts @@ -0,0 +1,105 @@ +import type { + AthenaGetQueryResultsParams, + AthenaGetQueryResultsResponse, +} from '@/tools/athena/types' +import type { ToolConfig } from '@/tools/types' + +export const getQueryResultsTool: ToolConfig< + AthenaGetQueryResultsParams, + AthenaGetQueryResultsResponse +> = { + id: 'athena_get_query_results', + name: 'Athena Get Query Results', + description: 'Retrieve the results of a completed Athena query execution', + version: '1.0', + + params: { + awsRegion: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + awsAccessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + awsSecretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + queryExecutionId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Query execution ID to get results for', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of rows to return (1-999)', + }, + nextToken: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination token from a previous request', + }, + }, + + request: { + url: '/api/tools/athena/get-query-results', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.awsRegion, + accessKeyId: params.awsAccessKeyId, + secretAccessKey: params.awsSecretAccessKey, + queryExecutionId: params.queryExecutionId, + ...(params.maxResults !== undefined && { maxResults: params.maxResults }), + ...(params.nextToken && { nextToken: params.nextToken }), + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.error || 'Failed to get Athena query results') + } + return { + success: true, + output: { + columns: data.output.columns ?? [], + rows: data.output.rows ?? [], + nextToken: data.output.nextToken ?? null, + updateCount: data.output.updateCount ?? null, + }, + } + }, + + outputs: { + columns: { + type: 'array', + description: 'Column metadata (name and type)', + }, + rows: { + type: 'array', + description: 'Result rows as key-value objects', + }, + nextToken: { + type: 'string', + description: 'Pagination token for next page of results', + optional: true, + }, + updateCount: { + type: 'number', + description: 'Number of rows affected (for INSERT/UPDATE statements)', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/athena/index.ts b/apps/sim/tools/athena/index.ts new file mode 100644 index 00000000000..5461e01117f --- /dev/null +++ b/apps/sim/tools/athena/index.ts @@ -0,0 +1,19 @@ +import { createNamedQueryTool } from '@/tools/athena/create_named_query' +import { getNamedQueryTool } from '@/tools/athena/get_named_query' +import { getQueryExecutionTool } from '@/tools/athena/get_query_execution' +import { getQueryResultsTool } from '@/tools/athena/get_query_results' +import { listNamedQueriesTool } from '@/tools/athena/list_named_queries' +import { listQueryExecutionsTool } from '@/tools/athena/list_query_executions' +import { startQueryTool } from '@/tools/athena/start_query' +import { stopQueryTool } from '@/tools/athena/stop_query' + +export const athenaCreateNamedQueryTool = createNamedQueryTool +export const athenaGetNamedQueryTool = getNamedQueryTool +export const athenaGetQueryExecutionTool = getQueryExecutionTool +export const athenaGetQueryResultsTool = getQueryResultsTool +export const athenaListNamedQueriesTool = listNamedQueriesTool +export const athenaListQueryExecutionsTool = listQueryExecutionsTool +export const athenaStartQueryTool = startQueryTool +export const athenaStopQueryTool = stopQueryTool + +export * from '@/tools/athena/types' diff --git a/apps/sim/tools/athena/list_named_queries.ts b/apps/sim/tools/athena/list_named_queries.ts new file mode 100644 index 00000000000..33ce7d48615 --- /dev/null +++ b/apps/sim/tools/athena/list_named_queries.ts @@ -0,0 +1,94 @@ +import type { + AthenaListNamedQueriesParams, + AthenaListNamedQueriesResponse, +} from '@/tools/athena/types' +import type { ToolConfig } from '@/tools/types' + +export const listNamedQueriesTool: ToolConfig< + AthenaListNamedQueriesParams, + AthenaListNamedQueriesResponse +> = { + id: 'athena_list_named_queries', + name: 'Athena List Named Queries', + description: 'List saved/named query IDs in AWS Athena', + version: '1.0', + + params: { + awsRegion: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + awsAccessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + awsSecretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + workGroup: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Workgroup to list named queries for', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results (0-50)', + }, + nextToken: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination token from a previous request', + }, + }, + + request: { + url: '/api/tools/athena/list-named-queries', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.awsRegion, + accessKeyId: params.awsAccessKeyId, + secretAccessKey: params.awsSecretAccessKey, + ...(params.workGroup && { workGroup: params.workGroup }), + ...(params.maxResults !== undefined && { maxResults: params.maxResults }), + ...(params.nextToken && { nextToken: params.nextToken }), + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.error || 'Failed to list Athena named queries') + } + return { + success: true, + output: { + namedQueryIds: data.output.namedQueryIds ?? [], + nextToken: data.output.nextToken ?? null, + }, + } + }, + + outputs: { + namedQueryIds: { + type: 'array', + description: 'List of named query IDs', + }, + nextToken: { + type: 'string', + description: 'Pagination token for next page', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/athena/list_query_executions.ts b/apps/sim/tools/athena/list_query_executions.ts new file mode 100644 index 00000000000..89c03d997f7 --- /dev/null +++ b/apps/sim/tools/athena/list_query_executions.ts @@ -0,0 +1,94 @@ +import type { + AthenaListQueryExecutionsParams, + AthenaListQueryExecutionsResponse, +} from '@/tools/athena/types' +import type { ToolConfig } from '@/tools/types' + +export const listQueryExecutionsTool: ToolConfig< + AthenaListQueryExecutionsParams, + AthenaListQueryExecutionsResponse +> = { + id: 'athena_list_query_executions', + name: 'Athena List Query Executions', + description: 'List recent Athena query execution IDs', + version: '1.0', + + params: { + awsRegion: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + awsAccessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + awsSecretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + workGroup: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Workgroup to list executions for (default: primary)', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results (0-50)', + }, + nextToken: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination token from a previous request', + }, + }, + + request: { + url: '/api/tools/athena/list-query-executions', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.awsRegion, + accessKeyId: params.awsAccessKeyId, + secretAccessKey: params.awsSecretAccessKey, + ...(params.workGroup && { workGroup: params.workGroup }), + ...(params.maxResults !== undefined && { maxResults: params.maxResults }), + ...(params.nextToken && { nextToken: params.nextToken }), + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.error || 'Failed to list Athena query executions') + } + return { + success: true, + output: { + queryExecutionIds: data.output.queryExecutionIds ?? [], + nextToken: data.output.nextToken ?? null, + }, + } + }, + + outputs: { + queryExecutionIds: { + type: 'array', + description: 'List of query execution IDs', + }, + nextToken: { + type: 'string', + description: 'Pagination token for next page', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/athena/start_query.ts b/apps/sim/tools/athena/start_query.ts new file mode 100644 index 00000000000..efaf0554a6e --- /dev/null +++ b/apps/sim/tools/athena/start_query.ts @@ -0,0 +1,96 @@ +import type { AthenaStartQueryParams, AthenaStartQueryResponse } from '@/tools/athena/types' +import type { ToolConfig } from '@/tools/types' + +export const startQueryTool: ToolConfig = { + id: 'athena_start_query', + name: 'Athena Start Query', + description: 'Start an SQL query execution in AWS Athena', + version: '1.0', + + params: { + awsRegion: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + awsAccessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + awsSecretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + queryString: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'SQL query string to execute', + }, + database: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Database name within the catalog', + }, + catalog: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Data catalog name (default: AwsDataCatalog)', + }, + outputLocation: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'S3 output location for query results (e.g., s3://bucket/path/)', + }, + workGroup: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Workgroup to execute the query in (default: primary)', + }, + }, + + request: { + url: '/api/tools/athena/start-query', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.awsRegion, + accessKeyId: params.awsAccessKeyId, + secretAccessKey: params.awsSecretAccessKey, + queryString: params.queryString, + ...(params.database && { database: params.database }), + ...(params.catalog && { catalog: params.catalog }), + ...(params.outputLocation && { outputLocation: params.outputLocation }), + ...(params.workGroup && { workGroup: params.workGroup }), + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.error || 'Failed to start Athena query') + } + return { + success: true, + output: { + queryExecutionId: data.output.queryExecutionId, + }, + } + }, + + outputs: { + queryExecutionId: { + type: 'string', + description: 'Unique ID of the started query execution', + }, + }, +} diff --git a/apps/sim/tools/athena/stop_query.ts b/apps/sim/tools/athena/stop_query.ts new file mode 100644 index 00000000000..94f88eb61e0 --- /dev/null +++ b/apps/sim/tools/athena/stop_query.ts @@ -0,0 +1,68 @@ +import type { AthenaStopQueryParams, AthenaStopQueryResponse } from '@/tools/athena/types' +import type { ToolConfig } from '@/tools/types' + +export const stopQueryTool: ToolConfig = { + id: 'athena_stop_query', + name: 'Athena Stop Query', + description: 'Stop a running Athena query execution', + version: '1.0', + + params: { + awsRegion: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + awsAccessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + awsSecretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + queryExecutionId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Query execution ID to stop', + }, + }, + + request: { + url: '/api/tools/athena/stop-query', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.awsRegion, + accessKeyId: params.awsAccessKeyId, + secretAccessKey: params.awsSecretAccessKey, + queryExecutionId: params.queryExecutionId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.error || 'Failed to stop Athena query') + } + return { + success: true, + output: { + success: true, + }, + } + }, + + outputs: { + success: { + type: 'boolean', + description: 'Whether the query was successfully stopped', + }, + }, +} diff --git a/apps/sim/tools/athena/types.ts b/apps/sim/tools/athena/types.ts new file mode 100644 index 00000000000..4b7a1a6d319 --- /dev/null +++ b/apps/sim/tools/athena/types.ts @@ -0,0 +1,126 @@ +import type { ToolResponse } from '@/tools/types' + +export interface AthenaConnectionConfig { + awsRegion: string + awsAccessKeyId: string + awsSecretAccessKey: string +} + +export interface AthenaStartQueryParams extends AthenaConnectionConfig { + queryString: string + database?: string + catalog?: string + outputLocation?: string + workGroup?: string +} + +export interface AthenaStartQueryResponse extends ToolResponse { + output: { + queryExecutionId: string + } +} + +export interface AthenaGetQueryExecutionParams extends AthenaConnectionConfig { + queryExecutionId: string +} + +export interface AthenaGetQueryExecutionResponse extends ToolResponse { + output: { + queryExecutionId: string + query: string + state: string + stateChangeReason: string | null + statementType: string | null + database: string | null + catalog: string | null + workGroup: string | null + submissionDateTime: number | null + completionDateTime: number | null + dataScannedInBytes: number | null + engineExecutionTimeInMillis: number | null + queryPlanningTimeInMillis: number | null + queryQueueTimeInMillis: number | null + totalExecutionTimeInMillis: number | null + outputLocation: string | null + } +} + +export interface AthenaGetQueryResultsParams extends AthenaConnectionConfig { + queryExecutionId: string + maxResults?: number + nextToken?: string +} + +export interface AthenaGetQueryResultsResponse extends ToolResponse { + output: { + columns: { name: string; type: string }[] + rows: Record[] + nextToken: string | null + updateCount: number | null + } +} + +export interface AthenaStopQueryParams extends AthenaConnectionConfig { + queryExecutionId: string +} + +export interface AthenaStopQueryResponse extends ToolResponse { + output: { + success: boolean + } +} + +export interface AthenaListQueryExecutionsParams extends AthenaConnectionConfig { + workGroup?: string + maxResults?: number + nextToken?: string +} + +export interface AthenaListQueryExecutionsResponse extends ToolResponse { + output: { + queryExecutionIds: string[] + nextToken: string | null + } +} + +export interface AthenaCreateNamedQueryParams extends AthenaConnectionConfig { + name: string + database: string + queryString: string + description?: string + workGroup?: string +} + +export interface AthenaCreateNamedQueryResponse extends ToolResponse { + output: { + namedQueryId: string + } +} + +export interface AthenaGetNamedQueryParams extends AthenaConnectionConfig { + namedQueryId: string +} + +export interface AthenaGetNamedQueryResponse extends ToolResponse { + output: { + namedQueryId: string + name: string + description: string | null + database: string + queryString: string + workGroup: string | null + } +} + +export interface AthenaListNamedQueriesParams extends AthenaConnectionConfig { + workGroup?: string + maxResults?: number + nextToken?: string +} + +export interface AthenaListNamedQueriesResponse extends ToolResponse { + output: { + namedQueryIds: string[] + nextToken: string | null + } +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 85d08da46c5..f094eddcdf9 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -149,6 +149,16 @@ import { ashbySearchCandidatesTool, ashbyUpdateCandidateTool, } from '@/tools/ashby' +import { + athenaCreateNamedQueryTool, + athenaGetNamedQueryTool, + athenaGetQueryExecutionTool, + athenaGetQueryResultsTool, + athenaListNamedQueriesTool, + athenaListQueryExecutionsTool, + athenaStartQueryTool, + athenaStopQueryTool, +} from '@/tools/athena' import { attioAssertRecordTool, attioCreateCommentTool, @@ -2830,6 +2840,14 @@ export const tools: Record = { ashby_remove_candidate_tag: ashbyRemoveCandidateTagTool, ashby_search_candidates: ashbySearchCandidatesTool, ashby_update_candidate: ashbyUpdateCandidateTool, + athena_create_named_query: athenaCreateNamedQueryTool, + athena_get_named_query: athenaGetNamedQueryTool, + athena_get_query_execution: athenaGetQueryExecutionTool, + athena_get_query_results: athenaGetQueryResultsTool, + athena_list_named_queries: athenaListNamedQueriesTool, + athena_list_query_executions: athenaListQueryExecutionsTool, + athena_start_query: athenaStartQueryTool, + athena_stop_query: athenaStopQueryTool, brandfetch_get_brand: brandfetchGetBrandTool, brandfetch_search: brandfetchSearchTool, box_copy_file: boxCopyFileTool, diff --git a/bun.lock b/bun.lock index 44ba1a838c9..e05bc532f5e 100644 --- a/bun.lock +++ b/bun.lock @@ -4,6 +4,9 @@ "workspaces": { "": { "name": "simstudio", + "dependencies": { + "@aws-sdk/client-athena": "3.1024.0", + }, "devDependencies": { "@biomejs/biome": "2.0.0-beta.5", "@octokit/rest": "^21.0.0", @@ -411,6 +414,8 @@ "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], + "@aws-sdk/client-athena": ["@aws-sdk/client-athena@3.1024.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/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.13", "@smithy/core": "^3.23.13", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-retry": "^4.4.46", "@smithy/middleware-serde": "^4.2.16", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.1", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@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.44", "@smithy/util-defaults-mode-node": "^4.2.48", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-kKnsdeh58Se7GL+9HX56KWtjS55W3OuzZwGVXq20PXgY2N53d6+NI9I1w+X0cZJo2pz3JijiJ+3S76YYCBoprw=="], + "@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-node": "3.940.0", "@aws-sdk/eventstream-handler-node": "3.936.0", "@aws-sdk/middleware-eventstream": "3.936.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/middleware-websocket": "3.936.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/eventstream-serde-config-resolver": "^4.3.5", "@smithy/eventstream-serde-node": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Gs6UUQP1zt8vahOxJ3BADcb3B+2KldUNA3bKa+KdK58de7N7tLJFJfZuXhFGGtwyNPh1aw6phtdP6dauq3OLWA=="], "@aws-sdk/client-cloudformation": ["@aws-sdk/client-cloudformation@3.1019.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.25", "@aws-sdk/credential-provider-node": "^3.972.27", "@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.26", "@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.12", "@smithy/config-resolver": "^4.4.13", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-retry": "^4.4.44", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@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.43", "@smithy/util-defaults-mode-node": "^4.2.47", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "@smithy/util-waiter": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-RNBtkQQ5IUqTdxaAe7ADwlJ/1qqW5kONLD1Mxr7PUWteEQwYR9ZJYscDul2qNkCWhu/vMKhk+qwJKPkdu2TNzA=="], @@ -433,25 +438,25 @@ "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A=="], - "@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], + "@aws-sdk/core": ["@aws-sdk/core@3.973.26", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.16", "@smithy/core": "^3.23.13", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-A/E6n2W42ruU+sfWk+mMUOyVXbsSgGrY3MJ9/0Az5qUdG67y8I6HYzzoAa+e/lzxxl1uCYmEL6BTMi9ZiZnplQ=="], "@aws-sdk/crc64-nvme": ["@aws-sdk/crc64-nvme@3.972.5", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-2VbTstbjKdT+yKi8m7b3a9CiVac+pL/IY2PHJwsaGkkHmuuqkJZIErPck1h6P3T9ghQMLSdMPyW6Qp7Di5swFg=="], - "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw=="], + "@aws-sdk/credential-provider-env": ["@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.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-FWg8uFmT6vQM7VuzELzwVo5bzExGaKHdubn0StjgrcU5FvuLExUe+k06kn/40uKv59rYzhez8eFNM4yYE/Yb/w=="], - "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ=="], + "@aws-sdk/credential-provider-http": ["@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.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.21", "tslib": "^2.6.2" } }, "sha512-CY4ppZ+qHYqcXqBVi//sdHST1QK3KzOEiLtpLsc9W2k2vfZPKExGaQIsOwcyvjpjUEolotitmd3mUNY56IwDEA=="], - "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-login": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw=="], + "@aws-sdk/credential-provider-ini": ["@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.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wXYvq3+uQcZV7k+bE4yDXCTBdzWTU9x/nMiKBfzInmv6yYK1veMK0AKvRfRBd72nGWYKcL6AxwiPg9z/pYlgpw=="], - "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], + "@aws-sdk/credential-provider-login": ["@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.12", "@smithy/protocol-http": "^5.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ZSTfO6jqUTCysbdBPtEX5OUR//3rbD0lN7jO3sQeS2Gjr/Y+DT6SbIJ0oT2cemNw3UzKu97sNONd1CwNMthuZQ=="], - "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.940.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-ini": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g=="], + "@aws-sdk/credential-provider-node": ["@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.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-clSzDcvndpFJAggLDnDb36sPdlZYyEs5Zm6zgZjjUhwsJgSWiWKwFIXUVBcbruidNyBdbpOv2tNDL9sX8y3/0g=="], - "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ=="], + "@aws-sdk/credential-provider-process": ["@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.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Q2k/XLrFXhEztPHqj4SLCNID3hEPdlhh1CDLBpNnM+1L8fq7P+yON9/9M1IGN/dA5W45v44ylERfXtDAlmMNmw=="], - "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.940.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.940.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw=="], + "@aws-sdk/credential-provider-sso": ["@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.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-IoUlmKMLEITFn1SiCTjPfR6KrE799FBo5baWyk/5Ppar2yXZoUdaRqZzJzK6TcJxx450M8m8DbpddRVYlp5R/A=="], - "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w=="], + "@aws-sdk/credential-provider-web-identity": ["@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.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-d+6h0SD8GGERzKe27v5rOzNGKOl0D+l0bWJdqrxH8WSQzHzjsQFIAPgIeOTUwBHVsKKwtSxc91K/SWax6XgswQ=="], "@aws-sdk/endpoint-cache": ["@aws-sdk/endpoint-cache@3.893.0", "", { "dependencies": { "mnemonist": "0.38.3", "tslib": "^2.6.2" } }, "sha512-KSwTfyLZyNLszz5f/yoLC+LC+CRKpeJii/+zVAy7JUOQsKhSykiRUPYUx7o2Sdc4oJfqqUl26A/jSttKYnYtAA=="], @@ -469,13 +474,13 @@ "@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.974.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "^3.973.24", "@aws-sdk/crc64-nvme": "^3.972.5", "@aws-sdk/types": "^3.973.6", "@smithy/is-array-buffer": "^4.2.2", "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-fhCbZXPAyy8btnNbnBlR7Cc1nD54cETSvGn2wey71ehsM89AKPO8Dpco9DBAAgvrUdLrdHQepBXcyX4vxC5OwA=="], - "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], + "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], "@aws-sdk/middleware-location-constraint": ["@aws-sdk/middleware-location-constraint@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-KaUoFuoFPziIa98DSQsTPeke1gvGXlc5ZGMhy+b+nLxZ4A7jmJgLzjEF95l8aOQN2T/qlPP3MrAyELm8ExXucw=="], - "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], + "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], - "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], + "@aws-sdk/middleware-recursion-detection": ["@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.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-/Wt5+CT8dpTFQxEJ9iGy/UGrXr7p2wlIOEHvIr/YcHYByzoLjrqkYqXdJjd9UIgWjv7eqV2HnFJen93UTuwfTQ=="], "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.972.24", "", { "dependencies": { "@aws-sdk/core": "^3.973.24", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-arn-parser": "^3.972.3", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-4sXxVC/enYgMkZefNMOzU6C6KtAXEvwVJLgNcUx1dvROH6GvKB5Sm2RGnGzTp0/PwkibIyMw4kOzF8tbLfaBAQ=="], @@ -483,13 +488,13 @@ "@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wqlK0yO/TxEC2UsY9wIlqeeutF6jjLe0f96Pbm40XscTo57nImUk9lBcw0dPgsm0sppFtAkSlDrfpK+pC30Wqw=="], - "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], + "@aws-sdk/middleware-user-agent": ["@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.13", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-retry": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-cfWZFlVh7Va9lRay4PN2A9ARFzaBYcA097InT5M2CdRS05ECF5yaz86jET8Wsl2WcyKYEvVr/QNmKtYtafUHtQ=="], "@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/util-format-url": "3.936.0", "@smithy/eventstream-codec": "^4.2.5", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-bPe3rqeugyj/MmjP0yBSZox2v1Wa8Dv39KN+RxVbQroLO8VUitBo6xyZ0oZebhZ5sASwSg58aDcMlX0uFLQnTA=="], "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw=="], - "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], + "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.13", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1dq9ToC6e070QvnVhhbAs3bb5r6cQ10gTVc6cyRV5uvQe7P138TV2uG2i6+Yok4bAkVAcx5AqkTEBUvWEtBlsQ=="], "@aws-sdk/s3-request-presigner": ["@aws-sdk/s3-request-presigner@3.1015.0", "", { "dependencies": { "@aws-sdk/signature-v4-multi-region": "^3.996.12", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-format-url": "^3.972.8", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-N8Axxt3VNXPPnujakUfwm5SvyoE+4dqeIdfPr2EXLgV8vruerHuH9fb9/Dr1lGYeaRjM161ye2d3Ko4TB7oZLg=="], @@ -497,23 +502,23 @@ "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg=="], - "@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + "@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], "@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.972.3", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA=="], "@aws-sdk/util-dynamodb": ["@aws-sdk/util-dynamodb@3.940.0", "", { "dependencies": { "tslib": "^2.6.2" }, "peerDependencies": { "@aws-sdk/client-dynamodb": "^3.940.0" } }, "sha512-T8UTYtCYSPxktnk68fKBdWztnqdTQItJwi/8N9lsvp20alJ15wCQsvQR+GKB5p4TCKxOPyNEirkcrNlf5TKppA=="], - "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], + "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], "@aws-sdk/util-format-url": ["@aws-sdk/util-format-url@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-J6DS9oocrgxM8xlUTTmQOuwRF6rnAGEujAN9SAzllcrQmwn5iJ58ogxy3SEhD0Q7JZvlA5jvIXBkpQRqEqlE9A=="], "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.5", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ=="], - "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], + "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], - "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], + "@aws-sdk/util-user-agent-node": ["@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.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-vNSB/DYaPOyujVZBg/zUznH9QC142MaTHVmaFlF7uzzfg3CgT9f/l4C0Yi+vU/tbBhxVcXVB90Oohk5+o+ZbWw=="], - "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.16", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.8", "tslib": "^2.6.2" } }, "sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A=="], "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="], @@ -1325,7 +1330,7 @@ "@smithy/config-resolver": ["@smithy/config-resolver@4.4.13", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-iIzMC5NmOUP6WL6o8iPBjFhUhBZ9pPjpUpQYWMUFQqKyXXzOftbfK8zcQCz/jFV1Psmf05BK5ypx4K2r4Tnwdg=="], - "@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + "@smithy/core": ["@smithy/core@3.23.13", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.21", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-J+2TT9D6oGsUVXVEMvz8h2EmdVnkBiy2auCie4aSJMvKlzUtO5hqjEzXhoCUkIMo7gAYjbQcN0g/MMSXEhDs1Q=="], "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.12", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg=="], @@ -1357,17 +1362,17 @@ "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA=="], - "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.28", "", { "dependencies": { "@smithy/core": "^3.23.13", "@smithy/middleware-serde": "^4.2.16", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-p1gfYpi91CHcs5cBq982UlGlDrxoYUX6XdHSo91cQ2KFuz6QloHosO7Jc60pJiVmkWrKOV8kFYlGFFbQ2WUKKQ=="], - "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], + "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.46", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-SpvWNNOPOrKQGUqZbEPO+es+FRXMWvIyzUKUOYdDgdlA6BdZj/R58p4umoQ76c2oJC44PiM7mKizyyex1IJzow=="], - "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.16", "", { "dependencies": { "@smithy/core": "^3.23.13", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-beqfV+RZ9RSv+sQqor3xroUUYgRFCGRw6niGstPG8zO9LgTl0B0MCucxjmrH/2WwksQN7UUgI7KNANoZv+KALA=="], "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw=="], "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.12", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw=="], - "@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + "@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.1", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ejjxdAXjkPIs9lyYyVutOGNOraqUE9v/NjGMKwwFrfOM354wfSD8lmlj8hVwUzQmlLLF4+udhfCX9Exnbmvfzw=="], "@smithy/property-provider": ["@smithy/property-provider@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A=="], @@ -1383,7 +1388,7 @@ "@smithy/signature-v4": ["@smithy/signature-v4@5.3.12", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-uri-escape": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw=="], - "@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + "@smithy/smithy-client": ["@smithy/smithy-client@4.12.8", "", { "dependencies": { "@smithy/core": "^3.23.13", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.21", "tslib": "^2.6.2" } }, "sha512-aJaAX7vHe5i66smoSSID7t4rKY08PbD8EBU7DOloixvhOozfYWdcSYE4l6/tjkZ0vBZhGjheWzB2mh31sLgCMA=="], "@smithy/types": ["@smithy/types@4.13.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g=="], @@ -1399,9 +1404,9 @@ "@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ=="], - "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], + "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.44", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-eZg6XzaCbVr2S5cAErU5eGBDaOVTuTo1I65i4tQcHENRcZ8rMWhQy1DaIYUSLyZjsfXvmCqZrstSMYyGFocvHA=="], - "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], + "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.48", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-FqOKTlqSaoV3nzO55pMs5NBnZX8EhoI0DGmn9kbYeXWppgHD6dchyuj2HLqp4INJDJbSrj6OFYJkAh/WhSzZPg=="], "@smithy/util-endpoints": ["@smithy/util-endpoints@3.3.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig=="], @@ -1409,7 +1414,7 @@ "@smithy/util-middleware": ["@smithy/util-middleware@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Er805uFUOvgc0l8nv0e0su0VFISoxhJ/AwOn3gL2NWNY2LUEldP5WtVcRYSQBcjg0y9NfG8JYrCJaYDpupBHJQ=="], - "@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], + "@smithy/util-retry": ["@smithy/util-retry@4.2.13", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qQQsIvL0MGIbUjeSrg0/VlQ3jGNKyM3/2iU3FPNgy01z+Sp4OvcaxbgIoFOTvB61ZoohtutuOvOcgmhbD0katQ=="], "@smithy/util-stream": ["@smithy/util-stream@4.5.20", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.0", "@smithy/types": "^4.13.1", "@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.6.2" } }, "sha512-4yXLm5n/B5SRBR2p8cZ90Sbv4zL4NKsgxdzCzp/83cXw2KxLEumt5p+GAVyRNZgQOSrzXn9ARpO0lUe8XSlSDw=="], @@ -3833,71 +3838,215 @@ "@authenio/xml-encryption/xpath": ["xpath@0.0.32", "", {}, "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw=="], - "@aws-crypto/crc32/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], - "@aws-crypto/crc32c/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], - "@aws-crypto/sha1-browser/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], - "@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], - "@aws-crypto/sha256-browser/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.940.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-ini": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g=="], - "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], - "@aws-crypto/sha256-js/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], - "@aws-crypto/util/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], - "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], - "@aws-sdk/client-cloudformation/@aws-sdk/core": ["@aws-sdk/core@3.973.26", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.16", "@smithy/core": "^3.23.13", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-A/E6n2W42ruU+sfWk+mMUOyVXbsSgGrY3MJ9/0Az5qUdG67y8I6HYzzoAa+e/lzxxl1uCYmEL6BTMi9ZiZnplQ=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node": ["@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.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-clSzDcvndpFJAggLDnDb36sPdlZYyEs5Zm6zgZjjUhwsJgSWiWKwFIXUVBcbruidNyBdbpOv2tNDL9sX8y3/0g=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], - "@aws-sdk/client-cloudformation/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], - "@aws-sdk/client-cloudformation/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], - "@aws-sdk/client-cloudformation/@aws-sdk/middleware-recursion-detection": ["@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.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-/Wt5+CT8dpTFQxEJ9iGy/UGrXr7p2wlIOEHvIr/YcHYByzoLjrqkYqXdJjd9UIgWjv7eqV2HnFJen93UTuwfTQ=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], - "@aws-sdk/client-cloudformation/@aws-sdk/middleware-user-agent": ["@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.13", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-retry": "^4.2.13", "tslib": "^2.6.2" } }, "sha512-cfWZFlVh7Va9lRay4PN2A9ARFzaBYcA097InT5M2CdRS05ECF5yaz86jET8Wsl2WcyKYEvVr/QNmKtYtafUHtQ=="], + "@aws-sdk/client-bedrock-runtime/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], - "@aws-sdk/client-cloudformation/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.13", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1dq9ToC6e070QvnVhhbAs3bb5r6cQ10gTVc6cyRV5uvQe7P138TV2uG2i6+Yok4bAkVAcx5AqkTEBUvWEtBlsQ=="], + "@aws-sdk/client-bedrock-runtime/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], - "@aws-sdk/client-cloudformation/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/client-bedrock-runtime/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], - "@aws-sdk/client-cloudformation/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], + "@aws-sdk/client-bedrock-runtime/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], - "@aws-sdk/client-cloudformation/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], + "@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], - "@aws-sdk/client-cloudformation/@aws-sdk/util-user-agent-node": ["@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.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-vNSB/DYaPOyujVZBg/zUznH9QC142MaTHVmaFlF7uzzfg3CgT9f/l4C0Yi+vU/tbBhxVcXVB90Oohk5+o+ZbWw=="], + "@aws-sdk/client-bedrock-runtime/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], - "@aws-sdk/client-cloudformation/@smithy/core": ["@smithy/core@3.23.13", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.21", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-J+2TT9D6oGsUVXVEMvz8h2EmdVnkBiy2auCie4aSJMvKlzUtO5hqjEzXhoCUkIMo7gAYjbQcN0g/MMSXEhDs1Q=="], + "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], - "@aws-sdk/client-cloudformation/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.28", "", { "dependencies": { "@smithy/core": "^3.23.13", "@smithy/middleware-serde": "^4.2.16", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-p1gfYpi91CHcs5cBq982UlGlDrxoYUX6XdHSo91cQ2KFuz6QloHosO7Jc60pJiVmkWrKOV8kFYlGFFbQ2WUKKQ=="], + "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], - "@aws-sdk/client-cloudformation/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.46", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-SpvWNNOPOrKQGUqZbEPO+es+FRXMWvIyzUKUOYdDgdlA6BdZj/R58p4umoQ76c2oJC44PiM7mKizyyex1IJzow=="], + "@aws-sdk/client-bedrock-runtime/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], - "@aws-sdk/client-cloudformation/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.16", "", { "dependencies": { "@smithy/core": "^3.23.13", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-beqfV+RZ9RSv+sQqor3xroUUYgRFCGRw6niGstPG8zO9LgTl0B0MCucxjmrH/2WwksQN7UUgI7KNANoZv+KALA=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], - "@aws-sdk/client-cloudformation/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.1", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ejjxdAXjkPIs9lyYyVutOGNOraqUE9v/NjGMKwwFrfOM354wfSD8lmlj8hVwUzQmlLLF4+udhfCX9Exnbmvfzw=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.940.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-ini": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g=="], - "@aws-sdk/client-cloudformation/@smithy/smithy-client": ["@smithy/smithy-client@4.12.8", "", { "dependencies": { "@smithy/core": "^3.23.13", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.21", "tslib": "^2.6.2" } }, "sha512-aJaAX7vHe5i66smoSSID7t4rKY08PbD8EBU7DOloixvhOozfYWdcSYE4l6/tjkZ0vBZhGjheWzB2mh31sLgCMA=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], - "@aws-sdk/client-cloudformation/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.44", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-eZg6XzaCbVr2S5cAErU5eGBDaOVTuTo1I65i4tQcHENRcZ8rMWhQy1DaIYUSLyZjsfXvmCqZrstSMYyGFocvHA=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], - "@aws-sdk/client-cloudformation/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.48", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-FqOKTlqSaoV3nzO55pMs5NBnZX8EhoI0DGmn9kbYeXWppgHD6dchyuj2HLqp4INJDJbSrj6OFYJkAh/WhSzZPg=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], - "@aws-sdk/client-cloudformation/@smithy/util-retry": ["@smithy/util-retry@4.2.13", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qQQsIvL0MGIbUjeSrg0/VlQ3jGNKyM3/2iU3FPNgy01z+Sp4OvcaxbgIoFOTvB61ZoohtutuOvOcgmhbD0katQ=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], - "@aws-sdk/client-s3/@aws-sdk/core": ["@aws-sdk/core@3.973.24", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.15", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-vvf82RYQu2GidWAuQq+uIzaPz9V0gSCXVqdVzRosgl5rXcspXOpSD3wFreGGW6AYymPr97Z69kjVnLePBxloDw=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], - "@aws-sdk/client-s3/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.25", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.22", "@aws-sdk/credential-provider-http": "^3.972.24", "@aws-sdk/credential-provider-ini": "^3.972.24", "@aws-sdk/credential-provider-process": "^3.972.22", "@aws-sdk/credential-provider-sso": "^3.972.24", "@aws-sdk/credential-provider-web-identity": "^3.972.24", "@aws-sdk/types": "^3.973.6", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-m7dR0Dsva2P+VUpL+VkC0WwiDby5pgmWXkRVDB5rlwv0jXJrQJf7YMtCoM8Wjk0H9jPeCYOxOXXcIgp/qp5Alg=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/client-cloudwatch/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], + + "@aws-sdk/client-cloudwatch/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], + + "@aws-sdk/client-cloudwatch/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], + + "@aws-sdk/client-cloudwatch/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/client-cloudwatch/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + + "@aws-sdk/client-cloudwatch/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], + + "@aws-sdk/client-cloudwatch/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/client-cloudwatch/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + + "@aws-sdk/client-cloudwatch/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/client-cloudwatch/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], + + "@aws-sdk/client-cloudwatch/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], + + "@aws-sdk/client-cloudwatch/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.940.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-ini": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], + + "@aws-sdk/client-cloudwatch-logs/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/client-cloudwatch-logs/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + + "@aws-sdk/client-cloudwatch-logs/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], + + "@aws-sdk/client-cloudwatch-logs/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/client-cloudwatch-logs/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + + "@aws-sdk/client-cloudwatch-logs/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/client-cloudwatch-logs/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], + + "@aws-sdk/client-cloudwatch-logs/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], + + "@aws-sdk/client-cloudwatch-logs/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.940.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-ini": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], + + "@aws-sdk/client-dynamodb/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/client-dynamodb/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + + "@aws-sdk/client-dynamodb/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], + + "@aws-sdk/client-dynamodb/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/client-dynamodb/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + + "@aws-sdk/client-dynamodb/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/client-dynamodb/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], + + "@aws-sdk/client-dynamodb/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], + + "@aws-sdk/client-dynamodb/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], - "@aws-sdk/client-s3/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], + "@aws-sdk/client-rds-data/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], - "@aws-sdk/client-s3/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], + "@aws-sdk/client-rds-data/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.940.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-ini": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g=="], + + "@aws-sdk/client-rds-data/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], + + "@aws-sdk/client-rds-data/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], + + "@aws-sdk/client-rds-data/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], + + "@aws-sdk/client-rds-data/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], + + "@aws-sdk/client-rds-data/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], + + "@aws-sdk/client-rds-data/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/client-rds-data/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], + + "@aws-sdk/client-rds-data/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], + + "@aws-sdk/client-rds-data/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], + + "@aws-sdk/client-rds-data/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/client-rds-data/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + + "@aws-sdk/client-rds-data/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], + + "@aws-sdk/client-rds-data/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/client-rds-data/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + + "@aws-sdk/client-rds-data/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/client-rds-data/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], + + "@aws-sdk/client-rds-data/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], + + "@aws-sdk/client-rds-data/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], + + "@aws-sdk/client-s3/@aws-sdk/core": ["@aws-sdk/core@3.973.24", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.15", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-vvf82RYQu2GidWAuQq+uIzaPz9V0gSCXVqdVzRosgl5rXcspXOpSD3wFreGGW6AYymPr97Z69kjVnLePBxloDw=="], + + "@aws-sdk/client-s3/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.25", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.22", "@aws-sdk/credential-provider-http": "^3.972.24", "@aws-sdk/credential-provider-ini": "^3.972.24", "@aws-sdk/credential-provider-process": "^3.972.22", "@aws-sdk/credential-provider-sso": "^3.972.24", "@aws-sdk/credential-provider-web-identity": "^3.972.24", "@aws-sdk/types": "^3.973.6", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-m7dR0Dsva2P+VUpL+VkC0WwiDby5pgmWXkRVDB5rlwv0jXJrQJf7YMtCoM8Wjk0H9jPeCYOxOXXcIgp/qp5Alg=="], "@aws-sdk/client-s3/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA=="], @@ -3905,39 +4054,51 @@ "@aws-sdk/client-s3/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.9", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.13", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-eQ+dFU05ZRC/lC2XpYlYSPlXtX3VT8sn5toxN2Fv7EXlMoA2p9V7vUBKqHunfD4TRLpxUq8Y8Ol/nCqiv327Ng=="], - "@aws-sdk/client-s3/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/client-s3/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.11", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.25", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-1qdXbXo2s5MMLpUvw00284LsbhtlQ4ul7Zzdn5n+7p4WVgCMLqhxImpHIrjSoc72E/fyc4Wq8dLtUld2Gsh+lA=="], - "@aws-sdk/client-s3/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], + "@aws-sdk/client-s3/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], - "@aws-sdk/client-s3/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], + "@aws-sdk/client-s3/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], - "@aws-sdk/client-s3/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.11", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.25", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-1qdXbXo2s5MMLpUvw00284LsbhtlQ4ul7Zzdn5n+7p4WVgCMLqhxImpHIrjSoc72E/fyc4Wq8dLtUld2Gsh+lA=="], + "@aws-sdk/client-s3/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], - "@aws-sdk/client-secrets-manager/@smithy/core": ["@smithy/core@3.23.13", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.21", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-J+2TT9D6oGsUVXVEMvz8h2EmdVnkBiy2auCie4aSJMvKlzUtO5hqjEzXhoCUkIMo7gAYjbQcN0g/MMSXEhDs1Q=="], + "@aws-sdk/client-s3/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], - "@aws-sdk/client-secrets-manager/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.28", "", { "dependencies": { "@smithy/core": "^3.23.13", "@smithy/middleware-serde": "^4.2.16", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-p1gfYpi91CHcs5cBq982UlGlDrxoYUX6XdHSo91cQ2KFuz6QloHosO7Jc60pJiVmkWrKOV8kFYlGFFbQ2WUKKQ=="], + "@aws-sdk/client-s3/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], - "@aws-sdk/client-secrets-manager/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.46", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-SpvWNNOPOrKQGUqZbEPO+es+FRXMWvIyzUKUOYdDgdlA6BdZj/R58p4umoQ76c2oJC44PiM7mKizyyex1IJzow=="], + "@aws-sdk/client-s3/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], - "@aws-sdk/client-secrets-manager/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.16", "", { "dependencies": { "@smithy/core": "^3.23.13", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-beqfV+RZ9RSv+sQqor3xroUUYgRFCGRw6niGstPG8zO9LgTl0B0MCucxjmrH/2WwksQN7UUgI7KNANoZv+KALA=="], + "@aws-sdk/client-s3/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], - "@aws-sdk/client-secrets-manager/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.1", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ejjxdAXjkPIs9lyYyVutOGNOraqUE9v/NjGMKwwFrfOM354wfSD8lmlj8hVwUzQmlLLF4+udhfCX9Exnbmvfzw=="], + "@aws-sdk/client-s3/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], - "@aws-sdk/client-secrets-manager/@smithy/smithy-client": ["@smithy/smithy-client@4.12.8", "", { "dependencies": { "@smithy/core": "^3.23.13", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.21", "tslib": "^2.6.2" } }, "sha512-aJaAX7vHe5i66smoSSID7t4rKY08PbD8EBU7DOloixvhOozfYWdcSYE4l6/tjkZ0vBZhGjheWzB2mh31sLgCMA=="], + "@aws-sdk/client-s3/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], - "@aws-sdk/client-secrets-manager/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.44", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-eZg6XzaCbVr2S5cAErU5eGBDaOVTuTo1I65i4tQcHENRcZ8rMWhQy1DaIYUSLyZjsfXvmCqZrstSMYyGFocvHA=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], - "@aws-sdk/client-secrets-manager/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.48", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-FqOKTlqSaoV3nzO55pMs5NBnZX8EhoI0DGmn9kbYeXWppgHD6dchyuj2HLqp4INJDJbSrj6OFYJkAh/WhSzZPg=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.940.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-ini": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g=="], - "@aws-sdk/client-secrets-manager/@smithy/util-retry": ["@smithy/util-retry@4.2.13", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qQQsIvL0MGIbUjeSrg0/VlQ3jGNKyM3/2iU3FPNgy01z+Sp4OvcaxbgIoFOTvB61ZoohtutuOvOcgmhbD0katQ=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], - "@aws-sdk/client-sesv2/@aws-sdk/core": ["@aws-sdk/core@3.973.24", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.15", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-vvf82RYQu2GidWAuQq+uIzaPz9V0gSCXVqdVzRosgl5rXcspXOpSD3wFreGGW6AYymPr97Z69kjVnLePBxloDw=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], - "@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.25", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.22", "@aws-sdk/credential-provider-http": "^3.972.24", "@aws-sdk/credential-provider-ini": "^3.972.24", "@aws-sdk/credential-provider-process": "^3.972.22", "@aws-sdk/credential-provider-sso": "^3.972.24", "@aws-sdk/credential-provider-web-identity": "^3.972.24", "@aws-sdk/types": "^3.973.6", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-m7dR0Dsva2P+VUpL+VkC0WwiDby5pgmWXkRVDB5rlwv0jXJrQJf7YMtCoM8Wjk0H9jPeCYOxOXXcIgp/qp5Alg=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], - "@aws-sdk/client-sesv2/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], - "@aws-sdk/client-sesv2/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], + + "@aws-sdk/client-sesv2/@aws-sdk/core": ["@aws-sdk/core@3.973.24", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.15", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-vvf82RYQu2GidWAuQq+uIzaPz9V0gSCXVqdVzRosgl5rXcspXOpSD3wFreGGW6AYymPr97Z69kjVnLePBxloDw=="], + + "@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.25", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.22", "@aws-sdk/credential-provider-http": "^3.972.24", "@aws-sdk/credential-provider-ini": "^3.972.24", "@aws-sdk/credential-provider-process": "^3.972.22", "@aws-sdk/credential-provider-sso": "^3.972.24", "@aws-sdk/credential-provider-web-identity": "^3.972.24", "@aws-sdk/types": "^3.973.6", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-m7dR0Dsva2P+VUpL+VkC0WwiDby5pgmWXkRVDB5rlwv0jXJrQJf7YMtCoM8Wjk0H9jPeCYOxOXXcIgp/qp5Alg=="], "@aws-sdk/client-sesv2/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA=="], @@ -3945,47 +4106,191 @@ "@aws-sdk/client-sesv2/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.9", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.13", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-eQ+dFU05ZRC/lC2XpYlYSPlXtX3VT8sn5toxN2Fv7EXlMoA2p9V7vUBKqHunfD4TRLpxUq8Y8Ol/nCqiv327Ng=="], - "@aws-sdk/client-sesv2/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/client-sesv2/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.11", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.25", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-1qdXbXo2s5MMLpUvw00284LsbhtlQ4ul7Zzdn5n+7p4WVgCMLqhxImpHIrjSoc72E/fyc4Wq8dLtUld2Gsh+lA=="], - "@aws-sdk/client-sesv2/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="], + "@aws-sdk/client-sesv2/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], - "@aws-sdk/client-sesv2/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="], + "@aws-sdk/client-sesv2/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], - "@aws-sdk/client-sesv2/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.11", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.25", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-1qdXbXo2s5MMLpUvw00284LsbhtlQ4ul7Zzdn5n+7p4WVgCMLqhxImpHIrjSoc72E/fyc4Wq8dLtUld2Gsh+lA=="], + "@aws-sdk/client-sesv2/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], + + "@aws-sdk/client-sesv2/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/client-sesv2/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + + "@aws-sdk/client-sesv2/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/client-sesv2/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], + + "@aws-sdk/client-sesv2/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], + + "@aws-sdk/client-sesv2/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], "@aws-sdk/client-sqs/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="], "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.947.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-ini": "3.947.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.947.0", "@aws-sdk/credential-provider-web-identity": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-S0Zqebr71KyrT6J4uYPhwV65g4V5uDPHnd7dt2W34FcyPu+hVC7Hx4MFmsPyVLeT5cMCkkZvmY3kAoEzgUPJJg=="], + "@aws-sdk/client-sqs/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], + + "@aws-sdk/client-sqs/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], + + "@aws-sdk/client-sqs/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], + "@aws-sdk/client-sqs/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.7", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA=="], + "@aws-sdk/client-sqs/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], + + "@aws-sdk/client-sqs/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/client-sqs/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], + + "@aws-sdk/client-sqs/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], + "@aws-sdk/client-sqs/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.947.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ=="], - "@aws-sdk/middleware-bucket-endpoint/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/client-sqs/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], - "@aws-sdk/middleware-expect-continue/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/client-sqs/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], - "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core": ["@aws-sdk/core@3.973.24", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.15", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-vvf82RYQu2GidWAuQq+uIzaPz9V0gSCXVqdVzRosgl5rXcspXOpSD3wFreGGW6AYymPr97Z69kjVnLePBxloDw=="], + "@aws-sdk/client-sqs/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], + + "@aws-sdk/client-sqs/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/client-sqs/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + + "@aws-sdk/client-sqs/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/client-sqs/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], + + "@aws-sdk/client-sqs/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], + + "@aws-sdk/client-sqs/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], + + "@aws-sdk/client-sso/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], + + "@aws-sdk/client-sso/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], + + "@aws-sdk/client-sso/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], + + "@aws-sdk/client-sso/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], + + "@aws-sdk/client-sso/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], + + "@aws-sdk/client-sso/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], + + "@aws-sdk/client-sso/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], - "@aws-sdk/middleware-flexible-checksums/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/client-sso/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], - "@aws-sdk/middleware-location-constraint/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/client-sso/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], + + "@aws-sdk/client-sso/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], + + "@aws-sdk/client-sso/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/client-sso/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + + "@aws-sdk/client-sso/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], + + "@aws-sdk/client-sso/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/client-sso/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + + "@aws-sdk/client-sso/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/client-sso/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], + + "@aws-sdk/client-sso/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], + + "@aws-sdk/client-sso/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], + + "@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.21", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/types": "^4.13.1", "@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.6.2" } }, "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q=="], + + "@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@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.13", "@smithy/core": "^3.23.13", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-retry": "^4.4.46", "@smithy/middleware-serde": "^4.2.16", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.1", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@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.44", "@smithy/util-defaults-mode-node": "^4.2.48", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA=="], + + "@aws-sdk/credential-provider-login/@aws-sdk/nested-clients": ["@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.13", "@smithy/core": "^3.23.13", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-retry": "^4.4.46", "@smithy/middleware-serde": "^4.2.16", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.1", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@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.44", "@smithy/util-defaults-mode-node": "^4.2.48", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients": ["@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.13", "@smithy/core": "^3.23.13", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-retry": "^4.4.46", "@smithy/middleware-serde": "^4.2.16", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.1", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@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.44", "@smithy/util-defaults-mode-node": "^4.2.48", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA=="], + + "@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@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.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-TKY6h9spUk3OLs5v1oAgW9mAeBE3LAGNBwJokLy96wwmd4W2v/tYlXseProyed9ValDj2u1jK/4Rg1T+1NXyJA=="], + + "@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@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.13", "@smithy/core": "^3.23.13", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-retry": "^4.4.46", "@smithy/middleware-serde": "^4.2.16", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.1", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@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.44", "@smithy/util-defaults-mode-node": "^4.2.48", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA=="], + + "@aws-sdk/eventstream-handler-node/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/lib-dynamodb/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], + + "@aws-sdk/lib-dynamodb/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/lib-dynamodb/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/middleware-endpoint-discovery/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/middleware-eventstream/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core": ["@aws-sdk/core@3.973.24", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.15", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-vvf82RYQu2GidWAuQq+uIzaPz9V0gSCXVqdVzRosgl5rXcspXOpSD3wFreGGW6AYymPr97Z69kjVnLePBxloDw=="], "@aws-sdk/middleware-sdk-s3/@aws-sdk/core": ["@aws-sdk/core@3.973.24", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.15", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-vvf82RYQu2GidWAuQq+uIzaPz9V0gSCXVqdVzRosgl5rXcspXOpSD3wFreGGW6AYymPr97Z69kjVnLePBxloDw=="], - "@aws-sdk/middleware-sdk-s3/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/middleware-sdk-s3/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], - "@aws-sdk/middleware-ssec/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/middleware-sdk-s3/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/middleware-sdk-sqs/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/middleware-sdk-sqs/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/middleware-websocket/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], "@aws-sdk/middleware-websocket/@aws-sdk/util-format-url": ["@aws-sdk/util-format-url@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/querystring-builder": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-MS5eSEtDUFIAMHrJaMERiHAvDPdfxc/T869ZjDNFAIiZhyc037REw0aoTNeimNXDNy2txRNZJaAUn/kE4RwN+g=="], - "@aws-sdk/s3-request-presigner/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/nested-clients/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], + + "@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], + + "@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], + + "@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], + + "@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], + + "@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], - "@aws-sdk/signature-v4-multi-region/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/nested-clients/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], - "@aws-sdk/util-format-url/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="], + "@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], - "@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], + "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], + + "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], + + "@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + + "@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], + + "@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + + "@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], + + "@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], + + "@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], + + "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + + "@aws-sdk/s3-request-presigner/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/token-providers/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], + + "@aws-sdk/token-providers/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.8", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="], "@azure/communication-email/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], @@ -4169,10 +4474,14 @@ "@shuding/opentype.js/fflate": ["fflate@0.7.4", "", {}, "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw=="], - "@smithy/middleware-compression/@smithy/core": ["@smithy/core@3.23.13", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.21", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-J+2TT9D6oGsUVXVEMvz8h2EmdVnkBiy2auCie4aSJMvKlzUtO5hqjEzXhoCUkIMo7gAYjbQcN0g/MMSXEhDs1Q=="], + "@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.21", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/types": "^4.13.1", "@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.6.2" } }, "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q=="], "@smithy/middleware-compression/fflate": ["fflate@0.8.1", "", {}, "sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ=="], + "@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.21", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/types": "^4.13.1", "@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.6.2" } }, "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q=="], + + "@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + "@socket.io/redis-adapter/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], "@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], @@ -4569,23 +4878,75 @@ "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], - "@aws-sdk/client-cloudformation/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.16", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.8", "tslib": "^2.6.2" } }, "sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + + "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw=="], + + "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ=="], + + "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-login": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw=="], + + "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ=="], + + "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.940.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.940.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw=="], + + "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-login": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.940.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.940.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w=="], + + "@aws-sdk/client-cloudwatch/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@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.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-FWg8uFmT6vQM7VuzELzwVo5bzExGaKHdubn0StjgrcU5FvuLExUe+k06kn/40uKv59rYzhez8eFNM4yYE/Yb/w=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@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.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.21", "tslib": "^2.6.2" } }, "sha512-CY4ppZ+qHYqcXqBVi//sdHST1QK3KzOEiLtpLsc9W2k2vfZPKExGaQIsOwcyvjpjUEolotitmd3mUNY56IwDEA=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@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.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wXYvq3+uQcZV7k+bE4yDXCTBdzWTU9x/nMiKBfzInmv6yYK1veMK0AKvRfRBd72nGWYKcL6AxwiPg9z/pYlgpw=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-login": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@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.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Q2k/XLrFXhEztPHqj4SLCNID3hEPdlhh1CDLBpNnM+1L8fq7P+yON9/9M1IGN/dA5W45v44ylERfXtDAlmMNmw=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@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.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-IoUlmKMLEITFn1SiCTjPfR6KrE799FBo5baWyk/5Ppar2yXZoUdaRqZzJzK6TcJxx450M8m8DbpddRVYlp5R/A=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.940.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.940.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@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.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-d+6h0SD8GGERzKe27v5rOzNGKOl0D+l0bWJdqrxH8WSQzHzjsQFIAPgIeOTUwBHVsKKwtSxc91K/SWax6XgswQ=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w=="], - "@aws-sdk/client-cloudformation/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.21", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/types": "^4.13.1", "@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.6.2" } }, "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q=="], + "@aws-sdk/client-dynamodb/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], - "@aws-sdk/client-cloudformation/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.21", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/types": "^4.13.1", "@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.6.2" } }, "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q=="], + "@aws-sdk/client-dynamodb/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-login": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.940.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.940.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw=="], + + "@aws-sdk/client-dynamodb/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w=="], + + "@aws-sdk/client-rds-data/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + + "@aws-sdk/client-rds-data/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw=="], + + "@aws-sdk/client-rds-data/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ=="], + + "@aws-sdk/client-rds-data/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-login": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw=="], + + "@aws-sdk/client-rds-data/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ=="], + + "@aws-sdk/client-rds-data/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.940.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.940.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw=="], + + "@aws-sdk/client-rds-data/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w=="], "@aws-sdk/client-s3/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.15", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.8", "tslib": "^2.6.2" } }, "sha512-PxMRlCFNiQnke9YR29vjFQwz4jq+6Q04rOVFeTDR2K7Qpv9h9FOWOxG+zJjageimYbWqE3bTuLjmryWHAWbvaA=="], @@ -4601,9 +4962,25 @@ "@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.24", "", { "dependencies": { "@aws-sdk/core": "^3.973.24", "@aws-sdk/nested-clients": "^3.996.14", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-J6H4R1nvr3uBTqD/EeIPAskrBtET4WFfNhpFySr2xW7bVZOXpQfPjrLSIx65jcNjBmLXzWq8QFLdVoGxiGG/SA=="], - "@aws-sdk/client-secrets-manager/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.21", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/types": "^4.13.1", "@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.6.2" } }, "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/core/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ=="], - "@aws-sdk/client-secrets-manager/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.21", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/types": "^4.13.1", "@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.6.2" } }, "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-login": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.940.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.940.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/middleware-user-agent/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], "@aws-sdk/client-sesv2/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.15", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.8", "tslib": "^2.6.2" } }, "sha512-PxMRlCFNiQnke9YR29vjFQwz4jq+6Q04rOVFeTDR2K7Qpv9h9FOWOxG+zJjageimYbWqE3bTuLjmryWHAWbvaA=="], @@ -4619,6 +4996,8 @@ "@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.24", "", { "dependencies": { "@aws-sdk/core": "^3.973.24", "@aws-sdk/nested-clients": "^3.996.14", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-J6H4R1nvr3uBTqD/EeIPAskrBtET4WFfNhpFySr2xW7bVZOXpQfPjrLSIx65jcNjBmLXzWq8QFLdVoGxiGG/SA=="], + "@aws-sdk/client-sqs/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VR2V6dRELmzwAsCpK4GqxUi6UW5WNhAXS9F9AzWi5jvijwJo3nH92YNJUP4quMpgFZxJHEWyXLWgPjh9u0zYOA=="], "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-inF09lh9SlHj63Vmr5d+LmwPXZc2IbK8lAruhOr3KLsZAIHEgHgGPXWDC2ukTEMzg0pkexQ6FOhXXad6klK4RA=="], @@ -4631,10 +5010,42 @@ "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gokm/e/YHiHLrZgLq4j8tNAn8RJDPbIcglFRKgy08q8DmAqHQ8MXAKW3eS0QjAuRXU9mcMmUo1NrX6FRNBCCPw=="], + "@aws-sdk/client-sso/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + + "@aws-sdk/lib-dynamodb/@aws-sdk/core/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/lib-dynamodb/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + + "@aws-sdk/lib-dynamodb/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.15", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.8", "tslib": "^2.6.2" } }, "sha512-PxMRlCFNiQnke9YR29vjFQwz4jq+6Q04rOVFeTDR2K7Qpv9h9FOWOxG+zJjageimYbWqE3bTuLjmryWHAWbvaA=="], + "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + "@aws-sdk/middleware-sdk-s3/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.15", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.8", "tslib": "^2.6.2" } }, "sha512-PxMRlCFNiQnke9YR29vjFQwz4jq+6Q04rOVFeTDR2K7Qpv9h9FOWOxG+zJjageimYbWqE3bTuLjmryWHAWbvaA=="], + "@aws-sdk/middleware-sdk-s3/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + + "@aws-sdk/middleware-sdk-sqs/@smithy/smithy-client/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/middleware-sdk-sqs/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + + "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + + "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], "@browserbasehq/sdk/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], @@ -4725,8 +5136,6 @@ "@shikijs/rehype/shiki/@shikijs/themes": ["@shikijs/themes@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA=="], - "@smithy/middleware-compression/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.21", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/types": "^4.13.1", "@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.6.2" } }, "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q=="], - "@trigger.dev/core/@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="], "@trigger.dev/core/@opentelemetry/exporter-logs-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-transformer": "0.203.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Wbxf7k+87KyvxFr5D7uOiSq/vHXWommvdnNE7vECO3tAhsA2GfOlpWINCMWUEPdHZ7tCXxw6Epp3vgx3jU7llQ=="], @@ -5143,19 +5552,25 @@ "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], - "@aws-sdk/client-cloudformation/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.8", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="], + "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], + + "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], + + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.21", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.1", "@smithy/types": "^4.13.1", "@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.6.2" } }, "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q=="], + "@aws-sdk/client-cloudwatch-logs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@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.12", "@smithy/protocol-http": "^5.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ZSTfO6jqUTCysbdBPtEX5OUR//3rbD0lN7jO3sQeS2Gjr/Y+DT6SbIJ0oT2cemNw3UzKu97sNONd1CwNMthuZQ=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@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.13", "@smithy/core": "^3.23.13", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-retry": "^4.4.46", "@smithy/middleware-serde": "^4.2.16", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.1", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@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.44", "@smithy/util-defaults-mode-node": "^4.2.48", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA=="], + "@aws-sdk/client-cloudwatch/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients": ["@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.13", "@smithy/core": "^3.23.13", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-retry": "^4.4.46", "@smithy/middleware-serde": "^4.2.16", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.1", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@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.44", "@smithy/util-defaults-mode-node": "^4.2.48", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA=="], + "@aws-sdk/client-dynamodb/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@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.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-TKY6h9spUk3OLs5v1oAgW9mAeBE3LAGNBwJokLy96wwmd4W2v/tYlXseProyed9ValDj2u1jK/4Rg1T+1NXyJA=="], + "@aws-sdk/client-dynamodb/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], - "@aws-sdk/client-cloudformation/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@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.13", "@smithy/core": "^3.23.13", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.28", "@smithy/middleware-retry": "^4.4.46", "@smithy/middleware-serde": "^4.2.16", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.1", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.8", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@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.44", "@smithy/util-defaults-mode-node": "^4.2.48", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.13", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA=="], + "@aws-sdk/client-rds-data/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], + + "@aws-sdk/client-rds-data/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], "@aws-sdk/client-s3/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.8", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="], @@ -5169,6 +5584,16 @@ "@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.14", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.24", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.25", "@aws-sdk/region-config-resolver": "^3.972.9", "@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.11", "@smithy/config-resolver": "^4.4.13", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-retry": "^4.4.44", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@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.43", "@smithy/util-defaults-mode-node": "^4.2.47", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-fSESKvh1VbfjtV3QMnRkCPZWkUbQof6T/DOpiLp33yP2wA+rbwwnZeG3XT3Ekljgw2I8X4XaQPnw+zSR8yxJ5Q=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], + "@aws-sdk/client-sesv2/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.8", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="], "@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.24", "", { "dependencies": { "@aws-sdk/core": "^3.973.24", "@aws-sdk/nested-clients": "^3.996.14", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-sIk8oa6AzDoUhxsR11svZESqvzGuXesw62Rl2oW6wguZx8i9cdGCvkFg+h5K7iucUZP8wyWibUbJMc+J66cu5g=="], @@ -5181,6 +5606,8 @@ "@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.14", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.24", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.25", "@aws-sdk/region-config-resolver": "^3.972.9", "@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.11", "@smithy/config-resolver": "^4.4.13", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-retry": "^4.4.44", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@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.43", "@smithy/util-defaults-mode-node": "^4.2.47", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-fSESKvh1VbfjtV3QMnRkCPZWkUbQof6T/DOpiLp33yP2wA+rbwwnZeG3XT3Ekljgw2I8X4XaQPnw+zSR8yxJ5Q=="], + "@aws-sdk/client-sqs/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-u7M3hazcB7aJiVwosNdJRbIJDzbwQ861NTtl6S0HmvWpixaVb7iyhJZWg8/plyUznboZGBm7JVEdxtxv3u0bTA=="], "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.947.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DjRJEYNnHUTu9kGPPQDTSXquwSEd6myKR4ssI4FaYLFhdT3ldWpj73yYt807H3tdmhS7vPmdVqchSJnjurUQAw=="], @@ -5191,10 +5618,28 @@ "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.947.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DjRJEYNnHUTu9kGPPQDTSXquwSEd6myKR4ssI4FaYLFhdT3ldWpj73yYt807H3tdmhS7vPmdVqchSJnjurUQAw=="], + "@aws-sdk/client-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], + + "@aws-sdk/lib-dynamodb/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], + + "@aws-sdk/lib-dynamodb/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.8", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="], + "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + "@aws-sdk/middleware-sdk-s3/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.8", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="], + "@aws-sdk/middleware-sdk-s3/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/middleware-sdk-sqs/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + "@browserbasehq/sdk/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "@browserbasehq/sdk/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -5207,8 +5652,6 @@ "@cerebras/cerebras_cloud_sdk/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], - "@smithy/middleware-compression/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.1", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ejjxdAXjkPIs9lyYyVutOGNOraqUE9v/NjGMKwwFrfOM354wfSD8lmlj8hVwUzQmlLLF4+udhfCX9Exnbmvfzw=="], - "@trigger.dev/core/socket.io-client/engine.io-client/ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="], "@trigger.dev/core/socket.io-client/engine.io-client/xmlhttprequest-ssl": ["xmlhttprequest-ssl@2.0.0", "", {}, "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A=="], @@ -5289,8 +5732,18 @@ "test-exclude/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.947.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DjRJEYNnHUTu9kGPPQDTSXquwSEd6myKR4ssI4FaYLFhdT3ldWpj73yYt807H3tdmhS7vPmdVqchSJnjurUQAw=="], + "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + + "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + "@browserbasehq/stagehand/@anthropic-ai/sdk/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "@browserbasehq/stagehand/@anthropic-ai/sdk/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -5323,6 +5776,8 @@ "test-exclude/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "@aws-sdk/client-secrets-manager/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + "lint-staged/listr2/cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], "lint-staged/listr2/log-update/cli-cursor/restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], diff --git a/package.json b/package.json index 9cd7279b997..c7ff404e8c2 100644 --- a/package.json +++ b/package.json @@ -48,5 +48,8 @@ }, "trustedDependencies": [ "sharp" - ] + ], + "dependencies": { + "@aws-sdk/client-athena": "3.1024.0" + } } From 712e58a7b559faafb6adb79dfe2b9348cd24ec56 Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Tue, 7 Apr 2026 20:21:43 -0700 Subject: [PATCH 07/15] fix(admin): delete workspaces on ban (#4029) * fix(admin): delete workspaces on ban * Fix lint * Wait until workspace deletion to return ban success --------- Co-authored-by: Theodore Li --- .../settings/components/admin/admin.tsx | 193 +++++++++--------- apps/sim/lib/auth/auth.ts | 8 + apps/sim/lib/workflows/lifecycle.ts | 29 +++ 3 files changed, 136 insertions(+), 94 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/settings/components/admin/admin.tsx b/apps/sim/app/workspace/[workspaceId]/settings/components/admin/admin.tsx index 5105cb404f3..f316f1f1294 100644 --- a/apps/sim/app/workspace/[workspaceId]/settings/components/admin/admin.tsx +++ b/apps/sim/app/workspace/[workspaceId]/settings/components/admin/admin.tsx @@ -227,123 +227,128 @@ export function Admin() {
- - {u.name || '—'} - - {u.email} - - {u.role || 'user'} - - - {u.banned ? ( - Banned - ) : ( - Active - )} - - - {u.id !== session?.user?.id && ( - <> - - - {u.banned ? ( +
+ + {u.name || '—'} + + {u.email} + + + {u.role || 'user'} + + + + {u.banned ? ( + Banned + ) : ( + Active + )} + + + {u.id !== session?.user?.id && ( + <> + - ) : banUserId === u.id ? ( -
- setBanReason(e.target.value)} - placeholder='Reason (optional)' - className='h-[28px] w-[120px] text-caption' - /> + {u.banned ? ( + ) : ( -
- ) : ( - - )} - - )} -
+ )} + + )} + +
+ {banUserId === u.id && !u.banned && ( +
+ setBanReason(e.target.value)} + placeholder='Reason (optional)' + className='h-[28px] flex-1 text-caption' + /> + +
+ )}
))}
diff --git a/apps/sim/lib/auth/auth.ts b/apps/sim/lib/auth/auth.ts index 6c51ab2d16b..98e48bd7803 100644 --- a/apps/sim/lib/auth/auth.ts +++ b/apps/sim/lib/auth/auth.ts @@ -82,6 +82,7 @@ import { quickValidateEmail } from '@/lib/messaging/email/validation' import { scheduleLifecycleEmail } from '@/lib/messaging/lifecycle' import { captureServerEvent } from '@/lib/posthog/server' import { syncAllWebhooksForCredentialSet } from '@/lib/webhooks/utils.server' +import { disableUserResources } from '@/lib/workflows/lifecycle' import { SSO_TRUSTED_PROVIDERS } from '@/ee/sso/constants' import { createAnonymousSession, ensureAnonymousUserExists } from './anonymous' @@ -243,6 +244,13 @@ export const auth = betterAuth({ } }, }, + update: { + after: async (user) => { + if (user.banned) { + await disableUserResources(user.id) + } + }, + }, }, account: { create: { diff --git a/apps/sim/lib/workflows/lifecycle.ts b/apps/sim/lib/workflows/lifecycle.ts index 8867816da21..c9ff0a9bcfa 100644 --- a/apps/sim/lib/workflows/lifecycle.ts +++ b/apps/sim/lib/workflows/lifecycle.ts @@ -1,6 +1,7 @@ import { db } from '@sim/db' import { a2aAgent, + apiKey, chat, form, webhook, @@ -9,12 +10,14 @@ import { workflowFolder, workflowMcpTool, workflowSchedule, + workspace, } from '@sim/db/schema' import { createLogger } from '@sim/logger' import { and, eq, inArray, isNull } from 'drizzle-orm' import { env } from '@/lib/core/config/env' import { getRedisClient } from '@/lib/core/config/redis' import { PlatformEvents } from '@/lib/core/telemetry' +import { generateRequestId } from '@/lib/core/utils/request' import { mcpPubSub } from '@/lib/mcp/pubsub' import { getWorkflowById } from '@/lib/workflows/utils' @@ -379,3 +382,29 @@ export async function archiveWorkflowsByIdsInWorkspace( options ) } + +/** + * Disables all resources owned by a banned user by archiving every workspace + * they own (cascading to workflows, chats, forms, KBs, tables, files, etc.) + * and deleting their personal API keys. + */ +export async function disableUserResources(userId: string): Promise { + const requestId = generateRequestId() + logger.info(`[${requestId}] Disabling resources for banned user ${userId}`) + + const { archiveWorkspace } = await import('@/lib/workspaces/lifecycle') + + const ownedWorkspaces = await db + .select({ id: workspace.id }) + .from(workspace) + .where(and(eq(workspace.ownerId, userId), isNull(workspace.archivedAt))) + + await Promise.all([ + ...ownedWorkspaces.map((w) => archiveWorkspace(w.id, { requestId })), + db.delete(apiKey).where(eq(apiKey.userId, userId)), + ]) + + logger.info( + `[${requestId}] Disabled resources for user ${userId}: archived ${ownedWorkspaces.length} workspaces, deleted API keys` + ) +} From 6f9f336f16a9a75a3731cf36f107e2cc860ffd02 Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Tue, 7 Apr 2026 20:33:04 -0700 Subject: [PATCH 08/15] feat(ui): Add copy button for code blocks in mothership (#4033) * Add copy button for code blocks in mothership * Move to shared copy code button * Handle react node case for copy * fix(copy-button): address PR review feedback - Await clipboard write and clear timeout on unmount in CopyCodeButton - Fix hover bg color matching container bg (surface-4 -> surface-5) - Extract extractTextContent to shared util at lib/core/utils/react-node-text.ts Co-Authored-By: Claude Opus 4.6 (1M context) * Fix lint --------- Co-authored-by: Theodore Li Co-authored-by: Claude Opus 4.6 (1M context) --- .../message/components/markdown-renderer.tsx | 6 +++ .../components/chat-content/chat-content.tsx | 24 ++++------- apps/sim/components/ui/copy-code-button.tsx | 42 +++++++++++++++++++ apps/sim/lib/core/utils/react-node-text.ts | 14 +++++++ 4 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 apps/sim/components/ui/copy-code-button.tsx create mode 100644 apps/sim/lib/core/utils/react-node-text.ts diff --git a/apps/sim/app/chat/components/message/components/markdown-renderer.tsx b/apps/sim/app/chat/components/message/components/markdown-renderer.tsx index 88a34da84e8..a62c901ae2f 100644 --- a/apps/sim/app/chat/components/message/components/markdown-renderer.tsx +++ b/apps/sim/app/chat/components/message/components/markdown-renderer.tsx @@ -2,6 +2,8 @@ import React, { type HTMLAttributes, memo, type ReactNode, useMemo } from 'react import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' import { Tooltip } from '@/components/emcn' +import { CopyCodeButton } from '@/components/ui/copy-code-button' +import { extractTextContent } from '@/lib/core/utils/react-node-text' export function LinkWithPreview({ href, children }: { href: string; children: React.ReactNode }) { return ( @@ -102,6 +104,10 @@ function createCustomComponents(LinkComponent: typeof LinkWithPreview) { {codeProps.className?.replace('language-', '') || 'code'} +
             {codeContent}
diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx
index 8249422b73b..018967deae2 100644
--- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx
@@ -9,7 +9,9 @@ import 'prismjs/components/prism-css'
 import 'prismjs/components/prism-markup'
 import '@/components/emcn/components/code/code.css'
 import { Checkbox, highlight, languages } from '@/components/emcn'
+import { CopyCodeButton } from '@/components/ui/copy-code-button'
 import { cn } from '@/lib/core/utils/cn'
+import { extractTextContent } from '@/lib/core/utils/react-node-text'
 import {
   PendingTagIndicator,
   parseSpecialTags,
@@ -33,16 +35,6 @@ const LANG_ALIASES: Record = {
   py: 'python',
 }
 
-function extractTextContent(node: React.ReactNode): string {
-  if (typeof node === 'string') return node
-  if (typeof node === 'number') return String(node)
-  if (!node) return ''
-  if (Array.isArray(node)) return node.map(extractTextContent).join('')
-  if (isValidElement(node))
-    return extractTextContent((node.props as { children?: React.ReactNode }).children)
-  return ''
-}
-
 const PROSE_CLASSES = cn(
   'prose prose-base dark:prose-invert max-w-none',
   'font-[family-name:var(--font-inter)] antialiased break-words font-[430] tracking-[0]',
@@ -125,11 +117,13 @@ const MARKDOWN_COMPONENTS: React.ComponentProps['component
 
     return (
       
- {language && ( -
- {language} -
- )} +
+ {language || 'code'} + +
 | null>(null)
+
+  const handleCopy = useCallback(async () => {
+    await navigator.clipboard.writeText(code)
+    setCopied(true)
+    if (timerRef.current) clearTimeout(timerRef.current)
+    timerRef.current = setTimeout(() => setCopied(false), 2000)
+  }, [code])
+
+  useEffect(
+    () => () => {
+      if (timerRef.current) clearTimeout(timerRef.current)
+    },
+    []
+  )
+
+  return (
+    
+  )
+}
diff --git a/apps/sim/lib/core/utils/react-node-text.ts b/apps/sim/lib/core/utils/react-node-text.ts
new file mode 100644
index 00000000000..c59e865a9b2
--- /dev/null
+++ b/apps/sim/lib/core/utils/react-node-text.ts
@@ -0,0 +1,14 @@
+import { isValidElement, type ReactNode } from 'react'
+
+/**
+ * Recursively extracts plain text content from a React node tree.
+ */
+export function extractTextContent(node: ReactNode): string {
+  if (typeof node === 'string') return node
+  if (typeof node === 'number') return String(node)
+  if (!node) return ''
+  if (Array.isArray(node)) return node.map(extractTextContent).join('')
+  if (isValidElement(node))
+    return extractTextContent((node.props as { children?: ReactNode }).children)
+  return ''
+}

From 2760b4bff112ddbc5aa46c8e27b4fc132b3d72fa Mon Sep 17 00:00:00 2001
From: Vikhyath Mondreti 
Date: Tue, 7 Apr 2026 20:43:52 -0700
Subject: [PATCH 09/15] Revert "fix(sockets): joining currently deleted
 workflow (#4004)" (#4036)

This reverts commit 609ba619bc631d0e9efc08932367fd9291f7455c.
---
 .../workspace/providers/socket-provider.tsx   | 22 ++-----------------
 1 file changed, 2 insertions(+), 20 deletions(-)

diff --git a/apps/sim/app/workspace/providers/socket-provider.tsx b/apps/sim/app/workspace/providers/socket-provider.tsx
index d04cc6e0fe2..b2257280c10 100644
--- a/apps/sim/app/workspace/providers/socket-provider.tsx
+++ b/apps/sim/app/workspace/providers/socket-provider.tsx
@@ -166,7 +166,6 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
   const positionUpdateTimeouts = useRef>(new Map())
   const isRejoiningRef = useRef(false)
   const pendingPositionUpdates = useRef>(new Map())
-  const deletedWorkflowIdRef = useRef(null)
 
   const generateSocketToken = async (): Promise => {
     const res = await fetch('/api/auth/socket-token', {
@@ -372,7 +371,6 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
 
         socketInstance.on('workflow-deleted', (data) => {
           logger.warn(`Workflow ${data.workflowId} has been deleted`)
-          deletedWorkflowIdRef.current = data.workflowId
           setCurrentWorkflowId((current) => {
             if (current === data.workflowId) {
               setPresenceUsers([])
@@ -502,11 +500,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
           if (error?.type === 'SESSION_ERROR') {
             const workflowId = urlWorkflowIdRef.current
 
-            if (
-              workflowId &&
-              !isRejoiningRef.current &&
-              deletedWorkflowIdRef.current !== workflowId
-            ) {
+            if (workflowId && !isRejoiningRef.current) {
               isRejoiningRef.current = true
               logger.info(`Session expired, rejoining workflow: ${workflowId}`)
               socketInstance.emit('join-workflow', {
@@ -558,25 +552,13 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
   const hydrationPhase = useWorkflowRegistryStore((s) => s.hydration.phase)
 
   useEffect(() => {
-    if (!socket || !isConnected || !urlWorkflowId) {
-      if (!urlWorkflowId) {
-        deletedWorkflowIdRef.current = null
-      }
-      return
-    }
+    if (!socket || !isConnected || !urlWorkflowId) return
 
     if (hydrationPhase === 'creating') return
 
     // Skip if already in the correct room
     if (currentWorkflowId === urlWorkflowId) return
 
-    // Prevent rejoining a workflow that was just deleted. The URL param may
-    // still reference the old workflow while router.push() propagates.
-    if (deletedWorkflowIdRef.current === urlWorkflowId) {
-      return
-    }
-    deletedWorkflowIdRef.current = null
-
     logger.info(
       `URL workflow changed from ${currentWorkflowId} to ${urlWorkflowId}, switching rooms`
     )

From 086b7d9ca12292b089b23322345d6300fae741f6 Mon Sep 17 00:00:00 2001
From: Waleed 
Date: Tue, 7 Apr 2026 20:55:20 -0700
Subject: [PATCH 10/15] refactor(polling): consolidate polling services into
 provider handler pattern (#4035)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* refactor(polling): consolidate polling services into provider handler pattern

Eliminate self-POST anti-pattern and extract shared boilerplate from 4 polling
services into a clean handler registry mirroring lib/webhooks/providers/.

- Add processPolledWebhookEvent() to processor.ts for direct in-process webhook
  execution, removing HTTP round-trips that caused Lambda 403/timeout errors
- Extract shared utilities (markWebhookFailed/Success, fetchActiveWebhooks,
  runWithConcurrency, resolveOAuthCredential, updateWebhookProviderConfig)
- Create PollingProviderHandler interface with per-provider implementations
- Consolidate 4 identical route files into single dynamic [provider] route
- Standardize concurrency to 10 across all providers
- No infra changes needed — Helm cron paths resolve via dynamic route

Co-Authored-By: Claude Opus 4.6 

* polish(polling): extract lock TTL constant and remove unnecessary type casts

- Widen processPolledWebhookEvent body param to accept object, eliminating
  `as unknown as Record` double casts in all 4 handlers
- Extract LOCK_TTL_SECONDS constant in route, tying maxDuration and lock TTL
  to a single value

Co-Authored-By: Claude Opus 4.6 

* fix(polling): address PR review feedback

- Add archivedAt filters to fetchActiveWebhooks query, matching
  findWebhookAndWorkflow in processor.ts to prevent polling archived
  webhooks/workflows
- Move provider validation after auth check to prevent provider
  enumeration by unauthenticated callers
- Fix inconsistent pollingIdempotency import path in outlook.ts to
  match other handlers

Co-Authored-By: Claude Opus 4.6 

* fix(polling): use literal for maxDuration segment config

Next.js requires segment config exports to be statically analyzable
literals. Using a variable reference caused build failure.

Co-Authored-By: Claude Opus 4.6 

---------

Co-authored-by: Claude Opus 4.6 
---
 .../poll/{rss => [provider]}/route.ts         |  37 +-
 apps/sim/app/api/webhooks/poll/gmail/route.ts |  68 --
 apps/sim/app/api/webhooks/poll/imap/route.ts  |  68 --
 .../app/api/webhooks/poll/outlook/route.ts    |  68 --
 .../sim/lib/webhooks/gmail-polling-service.ts | 791 ------------------
 apps/sim/lib/webhooks/polling/gmail.ts        | 553 ++++++++++++
 .../imap.ts}                                  | 416 +++------
 apps/sim/lib/webhooks/polling/index.ts        |   9 +
 apps/sim/lib/webhooks/polling/orchestrator.ts |  46 +
 .../outlook.ts}                               | 458 +++-------
 apps/sim/lib/webhooks/polling/registry.ts     |  19 +
 apps/sim/lib/webhooks/polling/rss.ts          | 307 +++++++
 apps/sim/lib/webhooks/polling/types.ts        |  58 ++
 apps/sim/lib/webhooks/polling/utils.ts        | 242 ++++++
 apps/sim/lib/webhooks/processor.ts            | 216 ++++-
 apps/sim/lib/webhooks/rss-polling-service.ts  | 442 ----------
 16 files changed, 1701 insertions(+), 2097 deletions(-)
 rename apps/sim/app/api/webhooks/poll/{rss => [provider]}/route.ts (55%)
 delete mode 100644 apps/sim/app/api/webhooks/poll/gmail/route.ts
 delete mode 100644 apps/sim/app/api/webhooks/poll/imap/route.ts
 delete mode 100644 apps/sim/app/api/webhooks/poll/outlook/route.ts
 delete mode 100644 apps/sim/lib/webhooks/gmail-polling-service.ts
 create mode 100644 apps/sim/lib/webhooks/polling/gmail.ts
 rename apps/sim/lib/webhooks/{imap-polling-service.ts => polling/imap.ts} (57%)
 create mode 100644 apps/sim/lib/webhooks/polling/index.ts
 create mode 100644 apps/sim/lib/webhooks/polling/orchestrator.ts
 rename apps/sim/lib/webhooks/{outlook-polling-service.ts => polling/outlook.ts} (50%)
 create mode 100644 apps/sim/lib/webhooks/polling/registry.ts
 create mode 100644 apps/sim/lib/webhooks/polling/rss.ts
 create mode 100644 apps/sim/lib/webhooks/polling/types.ts
 create mode 100644 apps/sim/lib/webhooks/polling/utils.ts
 delete mode 100644 apps/sim/lib/webhooks/rss-polling-service.ts

diff --git a/apps/sim/app/api/webhooks/poll/rss/route.ts b/apps/sim/app/api/webhooks/poll/[provider]/route.ts
similarity index 55%
rename from apps/sim/app/api/webhooks/poll/rss/route.ts
rename to apps/sim/app/api/webhooks/poll/[provider]/route.ts
index cd221abe394..d314e8563bb 100644
--- a/apps/sim/app/api/webhooks/poll/rss/route.ts
+++ b/apps/sim/app/api/webhooks/poll/[provider]/route.ts
@@ -3,31 +3,36 @@ import { type NextRequest, NextResponse } from 'next/server'
 import { verifyCronAuth } from '@/lib/auth/internal'
 import { acquireLock, releaseLock } from '@/lib/core/config/redis'
 import { generateShortId } from '@/lib/core/utils/uuid'
-import { pollRssWebhooks } from '@/lib/webhooks/rss-polling-service'
+import { pollProvider, VALID_POLLING_PROVIDERS } from '@/lib/webhooks/polling'
 
-const logger = createLogger('RssPollingAPI')
+const logger = createLogger('PollingAPI')
 
-export const dynamic = 'force-dynamic'
-export const maxDuration = 180 // Allow up to 3 minutes for polling to complete
+/** Lock TTL in seconds — must match maxDuration so the lock auto-expires if the function times out. */
+const LOCK_TTL_SECONDS = 180
 
-const LOCK_KEY = 'rss-polling-lock'
-const LOCK_TTL_SECONDS = 180 // Same as maxDuration (3 min)
+export const dynamic = 'force-dynamic'
+export const maxDuration = 180
 
-export async function GET(request: NextRequest) {
+export async function GET(
+  request: NextRequest,
+  { params }: { params: Promise<{ provider: string }> }
+) {
+  const { provider } = await params
   const requestId = generateShortId()
-  logger.info(`RSS webhook polling triggered (${requestId})`)
 
+  const LOCK_KEY = `${provider}-polling-lock`
   let lockValue: string | undefined
 
   try {
-    const authError = verifyCronAuth(request, 'RSS webhook polling')
-    if (authError) {
-      return authError
+    const authError = verifyCronAuth(request, `${provider} webhook polling`)
+    if (authError) return authError
+
+    if (!VALID_POLLING_PROVIDERS.has(provider)) {
+      return NextResponse.json({ error: `Unknown polling provider: ${provider}` }, { status: 404 })
     }
 
     lockValue = requestId
     const locked = await acquireLock(LOCK_KEY, lockValue, LOCK_TTL_SECONDS)
-
     if (!locked) {
       return NextResponse.json(
         {
@@ -40,21 +45,21 @@ export async function GET(request: NextRequest) {
       )
     }
 
-    const results = await pollRssWebhooks()
+    const results = await pollProvider(provider)
 
     return NextResponse.json({
       success: true,
-      message: 'RSS polling completed',
+      message: `${provider} polling completed`,
       requestId,
       status: 'completed',
       ...results,
     })
   } catch (error) {
-    logger.error(`Error during RSS polling (${requestId}):`, error)
+    logger.error(`Error during ${provider} polling (${requestId}):`, error)
     return NextResponse.json(
       {
         success: false,
-        message: 'RSS polling failed',
+        message: `${provider} polling failed`,
         error: error instanceof Error ? error.message : 'Unknown error',
         requestId,
       },
diff --git a/apps/sim/app/api/webhooks/poll/gmail/route.ts b/apps/sim/app/api/webhooks/poll/gmail/route.ts
deleted file mode 100644
index 5eabf8b9b63..00000000000
--- a/apps/sim/app/api/webhooks/poll/gmail/route.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { createLogger } from '@sim/logger'
-import { type NextRequest, NextResponse } from 'next/server'
-import { verifyCronAuth } from '@/lib/auth/internal'
-import { acquireLock, releaseLock } from '@/lib/core/config/redis'
-import { generateShortId } from '@/lib/core/utils/uuid'
-import { pollGmailWebhooks } from '@/lib/webhooks/gmail-polling-service'
-
-const logger = createLogger('GmailPollingAPI')
-
-export const dynamic = 'force-dynamic'
-export const maxDuration = 180 // Allow up to 3 minutes for polling to complete
-
-const LOCK_KEY = 'gmail-polling-lock'
-const LOCK_TTL_SECONDS = 180 // Same as maxDuration (3 min)
-
-export async function GET(request: NextRequest) {
-  const requestId = generateShortId()
-  logger.info(`Gmail webhook polling triggered (${requestId})`)
-
-  let lockValue: string | undefined
-
-  try {
-    const authError = verifyCronAuth(request, 'Gmail webhook polling')
-    if (authError) {
-      return authError
-    }
-
-    lockValue = requestId // unique value to identify the holder
-    const locked = await acquireLock(LOCK_KEY, lockValue, LOCK_TTL_SECONDS)
-
-    if (!locked) {
-      return NextResponse.json(
-        {
-          success: true,
-          message: 'Polling already in progress – skipped',
-          requestId,
-          status: 'skip',
-        },
-        { status: 202 }
-      )
-    }
-
-    const results = await pollGmailWebhooks()
-
-    return NextResponse.json({
-      success: true,
-      message: 'Gmail polling completed',
-      requestId,
-      status: 'completed',
-      ...results,
-    })
-  } catch (error) {
-    logger.error(`Error during Gmail polling (${requestId}):`, error)
-    return NextResponse.json(
-      {
-        success: false,
-        message: 'Gmail polling failed',
-        error: error instanceof Error ? error.message : 'Unknown error',
-        requestId,
-      },
-      { status: 500 }
-    )
-  } finally {
-    if (lockValue) {
-      await releaseLock(LOCK_KEY, lockValue).catch(() => {})
-    }
-  }
-}
diff --git a/apps/sim/app/api/webhooks/poll/imap/route.ts b/apps/sim/app/api/webhooks/poll/imap/route.ts
deleted file mode 100644
index 29826e04bff..00000000000
--- a/apps/sim/app/api/webhooks/poll/imap/route.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { createLogger } from '@sim/logger'
-import { type NextRequest, NextResponse } from 'next/server'
-import { verifyCronAuth } from '@/lib/auth/internal'
-import { acquireLock, releaseLock } from '@/lib/core/config/redis'
-import { generateShortId } from '@/lib/core/utils/uuid'
-import { pollImapWebhooks } from '@/lib/webhooks/imap-polling-service'
-
-const logger = createLogger('ImapPollingAPI')
-
-export const dynamic = 'force-dynamic'
-export const maxDuration = 180 // Allow up to 3 minutes for polling to complete
-
-const LOCK_KEY = 'imap-polling-lock'
-const LOCK_TTL_SECONDS = 180 // Same as maxDuration (3 min)
-
-export async function GET(request: NextRequest) {
-  const requestId = generateShortId()
-  logger.info(`IMAP webhook polling triggered (${requestId})`)
-
-  let lockValue: string | undefined
-
-  try {
-    const authError = verifyCronAuth(request, 'IMAP webhook polling')
-    if (authError) {
-      return authError
-    }
-
-    lockValue = requestId // unique value to identify the holder
-    const locked = await acquireLock(LOCK_KEY, lockValue, LOCK_TTL_SECONDS)
-
-    if (!locked) {
-      return NextResponse.json(
-        {
-          success: true,
-          message: 'Polling already in progress – skipped',
-          requestId,
-          status: 'skip',
-        },
-        { status: 202 }
-      )
-    }
-
-    const results = await pollImapWebhooks()
-
-    return NextResponse.json({
-      success: true,
-      message: 'IMAP polling completed',
-      requestId,
-      status: 'completed',
-      ...results,
-    })
-  } catch (error) {
-    logger.error(`Error during IMAP polling (${requestId}):`, error)
-    return NextResponse.json(
-      {
-        success: false,
-        message: 'IMAP polling failed',
-        error: error instanceof Error ? error.message : 'Unknown error',
-        requestId,
-      },
-      { status: 500 }
-    )
-  } finally {
-    if (lockValue) {
-      await releaseLock(LOCK_KEY, lockValue).catch(() => {})
-    }
-  }
-}
diff --git a/apps/sim/app/api/webhooks/poll/outlook/route.ts b/apps/sim/app/api/webhooks/poll/outlook/route.ts
deleted file mode 100644
index 2a72c34f86a..00000000000
--- a/apps/sim/app/api/webhooks/poll/outlook/route.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { createLogger } from '@sim/logger'
-import { type NextRequest, NextResponse } from 'next/server'
-import { verifyCronAuth } from '@/lib/auth/internal'
-import { acquireLock, releaseLock } from '@/lib/core/config/redis'
-import { generateShortId } from '@/lib/core/utils/uuid'
-import { pollOutlookWebhooks } from '@/lib/webhooks/outlook-polling-service'
-
-const logger = createLogger('OutlookPollingAPI')
-
-export const dynamic = 'force-dynamic'
-export const maxDuration = 180 // Allow up to 3 minutes for polling to complete
-
-const LOCK_KEY = 'outlook-polling-lock'
-const LOCK_TTL_SECONDS = 180 // Same as maxDuration (3 min)
-
-export async function GET(request: NextRequest) {
-  const requestId = generateShortId()
-  logger.info(`Outlook webhook polling triggered (${requestId})`)
-
-  let lockValue: string | undefined
-
-  try {
-    const authError = verifyCronAuth(request, 'Outlook webhook polling')
-    if (authError) {
-      return authError
-    }
-
-    lockValue = requestId // unique value to identify the holder
-    const locked = await acquireLock(LOCK_KEY, lockValue, LOCK_TTL_SECONDS)
-
-    if (!locked) {
-      return NextResponse.json(
-        {
-          success: true,
-          message: 'Polling already in progress – skipped',
-          requestId,
-          status: 'skip',
-        },
-        { status: 202 }
-      )
-    }
-
-    const results = await pollOutlookWebhooks()
-
-    return NextResponse.json({
-      success: true,
-      message: 'Outlook polling completed',
-      requestId,
-      status: 'completed',
-      ...results,
-    })
-  } catch (error) {
-    logger.error(`Error during Outlook polling (${requestId}):`, error)
-    return NextResponse.json(
-      {
-        success: false,
-        message: 'Outlook polling failed',
-        error: error instanceof Error ? error.message : 'Unknown error',
-        requestId,
-      },
-      { status: 500 }
-    )
-  } finally {
-    if (lockValue) {
-      await releaseLock(LOCK_KEY, lockValue).catch(() => {})
-    }
-  }
-}
diff --git a/apps/sim/lib/webhooks/gmail-polling-service.ts b/apps/sim/lib/webhooks/gmail-polling-service.ts
deleted file mode 100644
index 6c916cc3cf8..00000000000
--- a/apps/sim/lib/webhooks/gmail-polling-service.ts
+++ /dev/null
@@ -1,791 +0,0 @@
-import { db } from '@sim/db'
-import {
-  account,
-  credentialSet,
-  webhook,
-  workflow,
-  workflowDeploymentVersion,
-} from '@sim/db/schema'
-import { createLogger } from '@sim/logger'
-import { and, eq, isNull, or, sql } from 'drizzle-orm'
-import { isOrganizationOnTeamOrEnterprisePlan } from '@/lib/billing'
-import { pollingIdempotency } from '@/lib/core/idempotency/service'
-import { getInternalApiBaseUrl } from '@/lib/core/utils/urls'
-import { generateShortId } from '@/lib/core/utils/uuid'
-import {
-  getOAuthToken,
-  refreshAccessTokenIfNeeded,
-  resolveOAuthAccountId,
-} from '@/app/api/auth/oauth/utils'
-import type { GmailAttachment } from '@/tools/gmail/types'
-import { downloadAttachments, extractAttachmentInfo } from '@/tools/gmail/utils'
-import { MAX_CONSECUTIVE_FAILURES } from '@/triggers/constants'
-
-const logger = createLogger('GmailPollingService')
-
-interface GmailWebhookConfig {
-  labelIds: string[]
-  labelFilterBehavior: 'INCLUDE' | 'EXCLUDE'
-  markAsRead: boolean
-  searchQuery?: string
-  maxEmailsPerPoll?: number
-  lastCheckedTimestamp?: string
-  historyId?: string
-  includeAttachments?: boolean
-  includeRawEmail?: boolean
-}
-
-interface GmailEmail {
-  id: string
-  threadId: string
-  historyId?: string
-  labelIds?: string[]
-  payload?: any
-  snippet?: string
-  internalDate?: string
-}
-
-export interface SimplifiedEmail {
-  id: string
-  threadId: string
-  subject: string
-  from: string
-  to: string
-  cc: string
-  date: string | null
-  bodyText: string
-  bodyHtml: string
-  labels: string[]
-  hasAttachments: boolean
-  attachments: GmailAttachment[]
-}
-
-export interface GmailWebhookPayload {
-  email: SimplifiedEmail
-  timestamp: string
-  rawEmail?: GmailEmail // Only included when includeRawEmail is true
-}
-
-async function markWebhookFailed(webhookId: string) {
-  try {
-    const result = await db
-      .update(webhook)
-      .set({
-        failedCount: sql`COALESCE(${webhook.failedCount}, 0) + 1`,
-        lastFailedAt: new Date(),
-        updatedAt: new Date(),
-      })
-      .where(eq(webhook.id, webhookId))
-      .returning({ failedCount: webhook.failedCount })
-
-    const newFailedCount = result[0]?.failedCount || 0
-    const shouldDisable = newFailedCount >= MAX_CONSECUTIVE_FAILURES
-
-    if (shouldDisable) {
-      await db
-        .update(webhook)
-        .set({
-          isActive: false,
-          updatedAt: new Date(),
-        })
-        .where(eq(webhook.id, webhookId))
-
-      logger.warn(
-        `Webhook ${webhookId} auto-disabled after ${MAX_CONSECUTIVE_FAILURES} consecutive failures`
-      )
-    }
-  } catch (err) {
-    logger.error(`Failed to mark webhook ${webhookId} as failed:`, err)
-  }
-}
-
-async function markWebhookSuccess(webhookId: string) {
-  try {
-    await db
-      .update(webhook)
-      .set({
-        failedCount: 0, // Reset on success
-        updatedAt: new Date(),
-      })
-      .where(eq(webhook.id, webhookId))
-  } catch (err) {
-    logger.error(`Failed to mark webhook ${webhookId} as successful:`, err)
-  }
-}
-
-export async function pollGmailWebhooks() {
-  logger.info('Starting Gmail webhook polling')
-
-  try {
-    const activeWebhooksResult = await db
-      .select({ webhook })
-      .from(webhook)
-      .innerJoin(workflow, eq(webhook.workflowId, workflow.id))
-      .leftJoin(
-        workflowDeploymentVersion,
-        and(
-          eq(workflowDeploymentVersion.workflowId, workflow.id),
-          eq(workflowDeploymentVersion.isActive, true)
-        )
-      )
-      .where(
-        and(
-          eq(webhook.provider, 'gmail'),
-          eq(webhook.isActive, true),
-          eq(workflow.isDeployed, true),
-          or(
-            eq(webhook.deploymentVersionId, workflowDeploymentVersion.id),
-            and(isNull(workflowDeploymentVersion.id), isNull(webhook.deploymentVersionId))
-          )
-        )
-      )
-
-    const activeWebhooks = activeWebhooksResult.map((r) => r.webhook)
-
-    if (!activeWebhooks.length) {
-      logger.info('No active Gmail webhooks found')
-      return { total: 0, successful: 0, failed: 0, details: [] }
-    }
-
-    logger.info(`Found ${activeWebhooks.length} active Gmail webhooks`)
-
-    // Limit the number of webhooks processed in parallel to avoid
-    // exhausting Postgres or Gmail API connections when many users exist.
-    const CONCURRENCY = 10
-
-    const running: Promise[] = []
-    let successCount = 0
-    let failureCount = 0
-
-    const enqueue = async (webhookData: (typeof activeWebhooks)[number]) => {
-      const webhookId = webhookData.id
-      const requestId = generateShortId()
-
-      try {
-        const metadata = webhookData.providerConfig as any
-        const credentialId: string | undefined = metadata?.credentialId
-        const userId: string | undefined = metadata?.userId
-        const credentialSetId: string | undefined = webhookData.credentialSetId ?? undefined
-
-        if (!credentialId && !userId) {
-          logger.error(`[${requestId}] Missing credential info for webhook ${webhookId}`)
-          await markWebhookFailed(webhookId)
-          failureCount++
-          return
-        }
-
-        if (credentialSetId) {
-          const [cs] = await db
-            .select({ organizationId: credentialSet.organizationId })
-            .from(credentialSet)
-            .where(eq(credentialSet.id, credentialSetId))
-            .limit(1)
-
-          if (cs?.organizationId) {
-            const hasAccess = await isOrganizationOnTeamOrEnterprisePlan(cs.organizationId)
-            if (!hasAccess) {
-              logger.error(
-                `[${requestId}] Polling Group plan restriction: Your current plan does not support Polling Groups. Upgrade to Team or Enterprise to use this feature.`,
-                {
-                  webhookId,
-                  credentialSetId,
-                  organizationId: cs.organizationId,
-                }
-              )
-              await markWebhookFailed(webhookId)
-              failureCount++
-              return
-            }
-          }
-        }
-
-        let accessToken: string | null = null
-
-        if (credentialId) {
-          const resolved = await resolveOAuthAccountId(credentialId)
-          if (!resolved) {
-            logger.error(
-              `[${requestId}] Failed to resolve OAuth account for credential ${credentialId}, webhook ${webhookId}`
-            )
-            await markWebhookFailed(webhookId)
-            failureCount++
-            return
-          }
-          const rows = await db
-            .select()
-            .from(account)
-            .where(eq(account.id, resolved.accountId))
-            .limit(1)
-          if (rows.length === 0) {
-            logger.error(
-              `[${requestId}] Credential ${credentialId} not found for webhook ${webhookId}`
-            )
-            await markWebhookFailed(webhookId)
-            failureCount++
-            return
-          }
-          const ownerUserId = rows[0].userId
-          accessToken = await refreshAccessTokenIfNeeded(resolved.accountId, ownerUserId, requestId)
-        } else if (userId) {
-          // Legacy fallback for webhooks without credentialId
-          accessToken = await getOAuthToken(userId, 'google-email')
-        }
-
-        if (!accessToken) {
-          logger.error(`[${requestId}] Failed to get Gmail access token for webhook ${webhookId}`)
-          await markWebhookFailed(webhookId)
-          failureCount++
-          return
-        }
-
-        const config = webhookData.providerConfig as unknown as GmailWebhookConfig
-
-        const now = new Date()
-
-        const fetchResult = await fetchNewEmails(accessToken, config, requestId)
-
-        const { emails, latestHistoryId } = fetchResult
-
-        if (!emails || !emails.length) {
-          await updateWebhookLastChecked(
-            webhookId,
-            now.toISOString(),
-            latestHistoryId || config.historyId
-          )
-          await markWebhookSuccess(webhookId)
-          logger.info(`[${requestId}] No new emails found for webhook ${webhookId}`)
-          successCount++
-          return
-        }
-
-        logger.info(`[${requestId}] Found ${emails.length} new emails for webhook ${webhookId}`)
-
-        logger.info(`[${requestId}] Processing ${emails.length} emails for webhook ${webhookId}`)
-
-        const emailsToProcess = emails
-
-        const { processedCount, failedCount } = await processEmails(
-          emailsToProcess,
-          webhookData,
-          config,
-          accessToken,
-          requestId
-        )
-
-        await updateWebhookLastChecked(
-          webhookId,
-          now.toISOString(),
-          latestHistoryId || config.historyId
-        )
-
-        if (failedCount > 0 && processedCount === 0) {
-          await markWebhookFailed(webhookId)
-          failureCount++
-          logger.warn(
-            `[${requestId}] All ${failedCount} emails failed to process for webhook ${webhookId}`
-          )
-        } else {
-          await markWebhookSuccess(webhookId)
-          successCount++
-          logger.info(
-            `[${requestId}] Successfully processed ${processedCount} emails for webhook ${webhookId}${failedCount > 0 ? ` (${failedCount} failed)` : ''}`
-          )
-        }
-      } catch (error) {
-        logger.error(`[${requestId}] Error processing Gmail webhook ${webhookId}:`, error)
-        await markWebhookFailed(webhookId)
-        failureCount++
-      }
-    }
-
-    for (const webhookData of activeWebhooks) {
-      const promise: Promise = enqueue(webhookData)
-        .catch((err) => {
-          logger.error('Unexpected error in webhook processing:', err)
-          failureCount++
-        })
-        .finally(() => {
-          const idx = running.indexOf(promise)
-          if (idx !== -1) running.splice(idx, 1)
-        })
-
-      running.push(promise)
-
-      if (running.length >= CONCURRENCY) {
-        await Promise.race(running)
-      }
-    }
-
-    await Promise.allSettled(running)
-
-    const summary = {
-      total: activeWebhooks.length,
-      successful: successCount,
-      failed: failureCount,
-      details: [],
-    }
-
-    logger.info('Gmail polling completed', {
-      total: summary.total,
-      successful: summary.successful,
-      failed: summary.failed,
-    })
-
-    return summary
-  } catch (error) {
-    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
-    logger.error('Error in Gmail polling service:', errorMessage)
-    throw error
-  }
-}
-
-async function fetchNewEmails(accessToken: string, config: GmailWebhookConfig, requestId: string) {
-  try {
-    const useHistoryApi = !!config.historyId
-    let emails = []
-    let latestHistoryId = config.historyId
-
-    if (useHistoryApi) {
-      const historyUrl = `https://gmail.googleapis.com/gmail/v1/users/me/history?startHistoryId=${config.historyId}`
-
-      const historyResponse = await fetch(historyUrl, {
-        headers: {
-          Authorization: `Bearer ${accessToken}`,
-        },
-      })
-
-      if (!historyResponse.ok) {
-        const errorData = await historyResponse.json()
-        logger.error(`[${requestId}] Gmail history API error:`, {
-          status: historyResponse.status,
-          statusText: historyResponse.statusText,
-          error: errorData,
-        })
-
-        logger.info(`[${requestId}] Falling back to search API after history API failure`)
-        const searchResult = await searchEmails(accessToken, config, requestId)
-        return {
-          emails: searchResult.emails,
-          latestHistoryId: searchResult.latestHistoryId,
-        }
-      }
-
-      const historyData = await historyResponse.json()
-
-      if (!historyData.history || !historyData.history.length) {
-        return { emails: [], latestHistoryId }
-      }
-
-      if (historyData.historyId) {
-        latestHistoryId = historyData.historyId
-      }
-
-      const messageIds = new Set()
-
-      for (const history of historyData.history) {
-        if (history.messagesAdded) {
-          for (const messageAdded of history.messagesAdded) {
-            messageIds.add(messageAdded.message.id)
-          }
-        }
-      }
-
-      if (messageIds.size === 0) {
-        return { emails: [], latestHistoryId }
-      }
-
-      const sortedIds = [...messageIds].sort().reverse()
-
-      const idsToFetch = sortedIds.slice(0, config.maxEmailsPerPoll || 25)
-      logger.info(`[${requestId}] Processing ${idsToFetch.length} emails from history API`)
-
-      const emailPromises = idsToFetch.map(async (messageId) => {
-        return getEmailDetails(accessToken, messageId)
-      })
-
-      const emailResults = await Promise.allSettled(emailPromises)
-      const rejected = emailResults.filter((r) => r.status === 'rejected')
-      if (rejected.length > 0) {
-        logger.warn(`[${requestId}] Failed to fetch ${rejected.length} email details`)
-      }
-      emails = emailResults
-        .filter(
-          (result): result is PromiseFulfilledResult => result.status === 'fulfilled'
-        )
-        .map((result) => result.value)
-
-      emails = filterEmailsByLabels(emails, config)
-    } else {
-      const searchResult = await searchEmails(accessToken, config, requestId)
-      return searchResult
-    }
-
-    return { emails, latestHistoryId }
-  } catch (error) {
-    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
-    logger.error(`[${requestId}] Error fetching new emails:`, errorMessage)
-    throw error
-  }
-}
-
-/**
- * Builds a Gmail search query from label and search configuration
- */
-function buildGmailSearchQuery(config: {
-  labelIds?: string[]
-  labelFilterBehavior?: 'INCLUDE' | 'EXCLUDE'
-  searchQuery?: string
-}): string {
-  let labelQuery = ''
-  if (config.labelIds && config.labelIds.length > 0) {
-    const labelParts = config.labelIds.map((label) => `label:${label}`).join(' OR ')
-    labelQuery =
-      config.labelFilterBehavior === 'INCLUDE'
-        ? config.labelIds.length > 1
-          ? `(${labelParts})`
-          : labelParts
-        : config.labelIds.length > 1
-          ? `-(${labelParts})`
-          : `-${labelParts}`
-  }
-
-  let searchQueryPart = ''
-  if (config.searchQuery?.trim()) {
-    searchQueryPart = config.searchQuery.trim()
-    if (searchQueryPart.includes(' OR ') || searchQueryPart.includes(' AND ')) {
-      searchQueryPart = `(${searchQueryPart})`
-    }
-  }
-
-  let baseQuery = ''
-  if (labelQuery && searchQueryPart) {
-    baseQuery = `${labelQuery} ${searchQueryPart}`
-  } else if (searchQueryPart) {
-    baseQuery = searchQueryPart
-  } else if (labelQuery) {
-    baseQuery = labelQuery
-  } else {
-    baseQuery = 'in:inbox'
-  }
-
-  return baseQuery
-}
-
-async function searchEmails(accessToken: string, config: GmailWebhookConfig, requestId: string) {
-  try {
-    const baseQuery = buildGmailSearchQuery(config)
-
-    let timeConstraint = ''
-
-    if (config.lastCheckedTimestamp) {
-      const lastCheckedTime = new Date(config.lastCheckedTimestamp)
-      const now = new Date()
-      const minutesSinceLastCheck = (now.getTime() - lastCheckedTime.getTime()) / (60 * 1000)
-
-      if (minutesSinceLastCheck < 60) {
-        const bufferSeconds = Math.max(1 * 60 * 2, 180)
-
-        const cutoffTime = new Date(lastCheckedTime.getTime() - bufferSeconds * 1000)
-
-        const timestamp = Math.floor(cutoffTime.getTime() / 1000)
-
-        timeConstraint = ` after:${timestamp}`
-      } else if (minutesSinceLastCheck < 24 * 60) {
-        const hours = Math.ceil(minutesSinceLastCheck / 60) + 1 // Round up and add 1 hour buffer
-        timeConstraint = ` newer_than:${hours}h`
-      } else {
-        const days = Math.min(Math.ceil(minutesSinceLastCheck / (24 * 60)), 7) + 1
-        timeConstraint = ` newer_than:${days}d`
-      }
-    } else {
-      timeConstraint = ' newer_than:1d'
-    }
-
-    const query = `${baseQuery}${timeConstraint}`
-
-    const searchUrl = `https://gmail.googleapis.com/gmail/v1/users/me/messages?q=${encodeURIComponent(query)}&maxResults=${config.maxEmailsPerPoll || 25}`
-
-    const searchResponse = await fetch(searchUrl, {
-      headers: {
-        Authorization: `Bearer ${accessToken}`,
-      },
-    })
-
-    if (!searchResponse.ok) {
-      const errorData = await searchResponse.json()
-      logger.error(`[${requestId}] Gmail search API error:`, {
-        status: searchResponse.status,
-        statusText: searchResponse.statusText,
-        query: query,
-        error: errorData,
-      })
-      throw new Error(
-        `Gmail API error: ${searchResponse.status} ${searchResponse.statusText} - ${JSON.stringify(errorData)}`
-      )
-    }
-
-    const searchData = await searchResponse.json()
-
-    if (!searchData.messages || !searchData.messages.length) {
-      logger.info(`[${requestId}] No emails found matching query: ${query}`)
-      return { emails: [], latestHistoryId: config.historyId }
-    }
-
-    const idsToFetch = searchData.messages.slice(0, config.maxEmailsPerPoll || 25)
-    let latestHistoryId = config.historyId
-
-    logger.info(
-      `[${requestId}] Processing ${idsToFetch.length} emails from search API (total matches: ${searchData.messages.length})`
-    )
-
-    const emailPromises = idsToFetch.map(async (message: { id: string }) => {
-      return getEmailDetails(accessToken, message.id)
-    })
-
-    const emailResults = await Promise.allSettled(emailPromises)
-    const rejected = emailResults.filter((r) => r.status === 'rejected')
-    if (rejected.length > 0) {
-      logger.warn(`[${requestId}] Failed to fetch ${rejected.length} email details`)
-    }
-    const emails = emailResults
-      .filter(
-        (result): result is PromiseFulfilledResult => result.status === 'fulfilled'
-      )
-      .map((result) => result.value)
-
-    if (emails.length > 0 && emails[0].historyId) {
-      latestHistoryId = emails[0].historyId
-    }
-
-    return { emails, latestHistoryId }
-  } catch (error) {
-    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
-    logger.error(`[${requestId}] Error searching emails:`, errorMessage)
-    throw error
-  }
-}
-
-async function getEmailDetails(accessToken: string, messageId: string): Promise {
-  const messageUrl = `https://gmail.googleapis.com/gmail/v1/users/me/messages/${messageId}?format=full`
-
-  const messageResponse = await fetch(messageUrl, {
-    headers: {
-      Authorization: `Bearer ${accessToken}`,
-    },
-  })
-
-  if (!messageResponse.ok) {
-    const errorData = await messageResponse.json().catch(() => ({}))
-    throw new Error(
-      `Failed to fetch email details for message ${messageId}: ${messageResponse.status} ${messageResponse.statusText} - ${JSON.stringify(errorData)}`
-    )
-  }
-
-  return await messageResponse.json()
-}
-
-function filterEmailsByLabels(emails: GmailEmail[], config: GmailWebhookConfig): GmailEmail[] {
-  if (!config.labelIds.length) {
-    return emails
-  }
-
-  return emails.filter((email) => {
-    const emailLabels = email.labelIds || []
-    const hasMatchingLabel = config.labelIds.some((configLabel) =>
-      emailLabels.includes(configLabel)
-    )
-
-    return config.labelFilterBehavior === 'INCLUDE'
-      ? hasMatchingLabel // Include emails with matching labels
-      : !hasMatchingLabel // Exclude emails with matching labels
-  })
-}
-
-async function processEmails(
-  emails: any[],
-  webhookData: any,
-  config: GmailWebhookConfig,
-  accessToken: string,
-  requestId: string
-) {
-  let processedCount = 0
-  let failedCount = 0
-
-  for (const email of emails) {
-    try {
-      await pollingIdempotency.executeWithIdempotency(
-        'gmail',
-        `${webhookData.id}:${email.id}`,
-        async () => {
-          const headers: Record = {}
-          if (email.payload?.headers) {
-            for (const header of email.payload.headers) {
-              headers[header.name.toLowerCase()] = header.value
-            }
-          }
-
-          let textContent = ''
-          let htmlContent = ''
-
-          const extractContent = (part: any) => {
-            if (!part) return
-
-            if (part.mimeType === 'text/plain' && part.body?.data) {
-              textContent = Buffer.from(part.body.data, 'base64').toString('utf-8')
-            } else if (part.mimeType === 'text/html' && part.body?.data) {
-              htmlContent = Buffer.from(part.body.data, 'base64').toString('utf-8')
-            }
-
-            if (part.parts && Array.isArray(part.parts)) {
-              for (const subPart of part.parts) {
-                extractContent(subPart)
-              }
-            }
-          }
-
-          if (email.payload) {
-            extractContent(email.payload)
-          }
-
-          let date: string | null = null
-          if (headers.date) {
-            try {
-              date = new Date(headers.date).toISOString()
-            } catch (_e) {
-              // Keep date as null if parsing fails
-            }
-          } else if (email.internalDate) {
-            date = new Date(Number.parseInt(email.internalDate)).toISOString()
-          }
-
-          let attachments: GmailAttachment[] = []
-          const hasAttachments = email.payload
-            ? extractAttachmentInfo(email.payload).length > 0
-            : false
-
-          if (config.includeAttachments && hasAttachments && email.payload) {
-            try {
-              const attachmentInfo = extractAttachmentInfo(email.payload)
-              attachments = await downloadAttachments(email.id, attachmentInfo, accessToken)
-            } catch (error) {
-              logger.error(
-                `[${requestId}] Error downloading attachments for email ${email.id}:`,
-                error
-              )
-            }
-          }
-
-          const simplifiedEmail: SimplifiedEmail = {
-            id: email.id,
-            threadId: email.threadId,
-            subject: headers.subject || '[No Subject]',
-            from: headers.from || '',
-            to: headers.to || '',
-            cc: headers.cc || '',
-            date: date,
-            bodyText: textContent,
-            bodyHtml: htmlContent,
-            labels: email.labelIds || [],
-            hasAttachments,
-            attachments,
-          }
-
-          const payload: GmailWebhookPayload = {
-            email: simplifiedEmail,
-            timestamp: new Date().toISOString(),
-            ...(config.includeRawEmail ? { rawEmail: email } : {}),
-          }
-
-          const webhookUrl = `${getInternalApiBaseUrl()}/api/webhooks/trigger/${webhookData.path}`
-
-          const response = await fetch(webhookUrl, {
-            method: 'POST',
-            headers: {
-              'Content-Type': 'application/json',
-              'User-Agent': 'Sim/1.0',
-            },
-            body: JSON.stringify(payload),
-          })
-
-          if (!response.ok) {
-            const errorText = await response.text()
-            logger.error(
-              `[${requestId}] Failed to trigger webhook for email ${email.id}:`,
-              response.status,
-              errorText
-            )
-            throw new Error(`Webhook request failed: ${response.status} - ${errorText}`)
-          }
-
-          if (config.markAsRead) {
-            await markEmailAsRead(accessToken, email.id)
-          }
-
-          return {
-            emailId: email.id,
-            webhookStatus: response.status,
-            processed: true,
-          }
-        }
-      )
-
-      logger.info(
-        `[${requestId}] Successfully processed email ${email.id} for webhook ${webhookData.id}`
-      )
-      processedCount++
-    } catch (error) {
-      const errorMessage = error instanceof Error ? error.message : 'Unknown error'
-      logger.error(`[${requestId}] Error processing email ${email.id}:`, errorMessage)
-      failedCount++
-    }
-  }
-
-  return { processedCount, failedCount }
-}
-
-async function markEmailAsRead(accessToken: string, messageId: string) {
-  const modifyUrl = `https://gmail.googleapis.com/gmail/v1/users/me/messages/${messageId}/modify`
-
-  try {
-    const response = await fetch(modifyUrl, {
-      method: 'POST',
-      headers: {
-        Authorization: `Bearer ${accessToken}`,
-        'Content-Type': 'application/json',
-      },
-      body: JSON.stringify({
-        removeLabelIds: ['UNREAD'],
-      }),
-    })
-
-    if (!response.ok) {
-      await response.body?.cancel().catch(() => {})
-      throw new Error(
-        `Failed to mark email ${messageId} as read: ${response.status} ${response.statusText}`
-      )
-    }
-  } catch (error) {
-    logger.error(`Error marking email ${messageId} as read:`, error)
-    throw error
-  }
-}
-
-async function updateWebhookLastChecked(webhookId: string, timestamp: string, historyId?: string) {
-  try {
-    const result = await db.select().from(webhook).where(eq(webhook.id, webhookId))
-    const existingConfig = (result[0]?.providerConfig as Record) || {}
-    await db
-      .update(webhook)
-      .set({
-        providerConfig: {
-          ...existingConfig,
-          lastCheckedTimestamp: timestamp,
-          ...(historyId ? { historyId } : {}),
-        } as any,
-        updatedAt: new Date(),
-      })
-      .where(eq(webhook.id, webhookId))
-  } catch (error) {
-    logger.error(`Error updating webhook ${webhookId} last checked timestamp:`, error)
-  }
-}
diff --git a/apps/sim/lib/webhooks/polling/gmail.ts b/apps/sim/lib/webhooks/polling/gmail.ts
new file mode 100644
index 00000000000..7db8587d2c2
--- /dev/null
+++ b/apps/sim/lib/webhooks/polling/gmail.ts
@@ -0,0 +1,553 @@
+import { pollingIdempotency } from '@/lib/core/idempotency/service'
+import type { PollingProviderHandler, PollWebhookContext } from '@/lib/webhooks/polling/types'
+import {
+  markWebhookFailed,
+  markWebhookSuccess,
+  resolveOAuthCredential,
+  updateWebhookProviderConfig,
+} from '@/lib/webhooks/polling/utils'
+import { processPolledWebhookEvent } from '@/lib/webhooks/processor'
+import type { GmailAttachment } from '@/tools/gmail/types'
+import { downloadAttachments, extractAttachmentInfo } from '@/tools/gmail/utils'
+
+interface GmailWebhookConfig {
+  labelIds: string[]
+  labelFilterBehavior: 'INCLUDE' | 'EXCLUDE'
+  markAsRead: boolean
+  searchQuery?: string
+  maxEmailsPerPoll?: number
+  lastCheckedTimestamp?: string
+  historyId?: string
+  includeAttachments?: boolean
+  includeRawEmail?: boolean
+}
+
+interface GmailEmail {
+  id: string
+  threadId: string
+  historyId?: string
+  labelIds?: string[]
+  payload?: Record
+  snippet?: string
+  internalDate?: string
+}
+
+export interface SimplifiedEmail {
+  id: string
+  threadId: string
+  subject: string
+  from: string
+  to: string
+  cc: string
+  date: string | null
+  bodyText: string
+  bodyHtml: string
+  labels: string[]
+  hasAttachments: boolean
+  attachments: GmailAttachment[]
+}
+
+export interface GmailWebhookPayload {
+  email: SimplifiedEmail
+  timestamp: string
+  rawEmail?: GmailEmail
+}
+
+export const gmailPollingHandler: PollingProviderHandler = {
+  provider: 'gmail',
+  label: 'Gmail',
+
+  async pollWebhook(ctx: PollWebhookContext): Promise<'success' | 'failure'> {
+    const { webhookData, workflowData, requestId, logger } = ctx
+    const webhookId = webhookData.id
+
+    try {
+      const accessToken = await resolveOAuthCredential(
+        webhookData,
+        'google-email',
+        requestId,
+        logger
+      )
+
+      const config = webhookData.providerConfig as unknown as GmailWebhookConfig
+      const now = new Date()
+
+      const { emails, latestHistoryId } = await fetchNewEmails(
+        accessToken,
+        config,
+        requestId,
+        logger
+      )
+
+      if (!emails || !emails.length) {
+        await updateWebhookProviderConfig(
+          webhookId,
+          {
+            lastCheckedTimestamp: now.toISOString(),
+            ...(latestHistoryId || config.historyId
+              ? { historyId: latestHistoryId || config.historyId }
+              : {}),
+          },
+          logger
+        )
+        await markWebhookSuccess(webhookId, logger)
+        logger.info(`[${requestId}] No new emails found for webhook ${webhookId}`)
+        return 'success'
+      }
+
+      logger.info(`[${requestId}] Found ${emails.length} new emails for webhook ${webhookId}`)
+
+      const { processedCount, failedCount } = await processEmails(
+        emails,
+        webhookData,
+        workflowData,
+        config,
+        accessToken,
+        requestId,
+        logger
+      )
+
+      await updateWebhookProviderConfig(
+        webhookId,
+        {
+          lastCheckedTimestamp: now.toISOString(),
+          ...(latestHistoryId || config.historyId
+            ? { historyId: latestHistoryId || config.historyId }
+            : {}),
+        },
+        logger
+      )
+
+      if (failedCount > 0 && processedCount === 0) {
+        await markWebhookFailed(webhookId, logger)
+        logger.warn(
+          `[${requestId}] All ${failedCount} emails failed to process for webhook ${webhookId}`
+        )
+        return 'failure'
+      }
+
+      await markWebhookSuccess(webhookId, logger)
+      logger.info(
+        `[${requestId}] Successfully processed ${processedCount} emails for webhook ${webhookId}${failedCount > 0 ? ` (${failedCount} failed)` : ''}`
+      )
+      return 'success'
+    } catch (error) {
+      logger.error(`[${requestId}] Error processing Gmail webhook ${webhookId}:`, error)
+      await markWebhookFailed(webhookId, logger)
+      return 'failure'
+    }
+  },
+}
+
+async function fetchNewEmails(
+  accessToken: string,
+  config: GmailWebhookConfig,
+  requestId: string,
+  logger: ReturnType
+) {
+  try {
+    const useHistoryApi = !!config.historyId
+    let emails: GmailEmail[] = []
+    let latestHistoryId = config.historyId
+
+    if (useHistoryApi) {
+      const historyUrl = `https://gmail.googleapis.com/gmail/v1/users/me/history?startHistoryId=${config.historyId}`
+
+      const historyResponse = await fetch(historyUrl, {
+        headers: { Authorization: `Bearer ${accessToken}` },
+      })
+
+      if (!historyResponse.ok) {
+        const errorData = await historyResponse.json()
+        logger.error(`[${requestId}] Gmail history API error:`, {
+          status: historyResponse.status,
+          statusText: historyResponse.statusText,
+          error: errorData,
+        })
+
+        logger.info(`[${requestId}] Falling back to search API after history API failure`)
+        return searchEmails(accessToken, config, requestId, logger)
+      }
+
+      const historyData = await historyResponse.json()
+
+      if (!historyData.history || !historyData.history.length) {
+        return { emails: [], latestHistoryId }
+      }
+
+      if (historyData.historyId) {
+        latestHistoryId = historyData.historyId
+      }
+
+      const messageIds = new Set()
+      for (const history of historyData.history) {
+        if (history.messagesAdded) {
+          for (const messageAdded of history.messagesAdded) {
+            messageIds.add(messageAdded.message.id)
+          }
+        }
+      }
+
+      if (messageIds.size === 0) {
+        return { emails: [], latestHistoryId }
+      }
+
+      const sortedIds = [...messageIds].sort().reverse()
+      const idsToFetch = sortedIds.slice(0, config.maxEmailsPerPoll || 25)
+      logger.info(`[${requestId}] Processing ${idsToFetch.length} emails from history API`)
+
+      const emailResults = await Promise.allSettled(
+        idsToFetch.map((messageId) => getEmailDetails(accessToken, messageId))
+      )
+      const rejected = emailResults.filter((r) => r.status === 'rejected')
+      if (rejected.length > 0) {
+        logger.warn(`[${requestId}] Failed to fetch ${rejected.length} email details`)
+      }
+      emails = emailResults
+        .filter(
+          (result): result is PromiseFulfilledResult => result.status === 'fulfilled'
+        )
+        .map((result) => result.value)
+
+      emails = filterEmailsByLabels(emails, config)
+    } else {
+      return searchEmails(accessToken, config, requestId, logger)
+    }
+
+    return { emails, latestHistoryId }
+  } catch (error) {
+    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
+    logger.error(`[${requestId}] Error fetching new emails:`, errorMessage)
+    throw error
+  }
+}
+
+function buildGmailSearchQuery(config: {
+  labelIds?: string[]
+  labelFilterBehavior?: 'INCLUDE' | 'EXCLUDE'
+  searchQuery?: string
+}): string {
+  let labelQuery = ''
+  if (config.labelIds && config.labelIds.length > 0) {
+    const labelParts = config.labelIds.map((label) => `label:${label}`).join(' OR ')
+    labelQuery =
+      config.labelFilterBehavior === 'INCLUDE'
+        ? config.labelIds.length > 1
+          ? `(${labelParts})`
+          : labelParts
+        : config.labelIds.length > 1
+          ? `-(${labelParts})`
+          : `-${labelParts}`
+  }
+
+  let searchQueryPart = ''
+  if (config.searchQuery?.trim()) {
+    searchQueryPart = config.searchQuery.trim()
+    if (searchQueryPart.includes(' OR ') || searchQueryPart.includes(' AND ')) {
+      searchQueryPart = `(${searchQueryPart})`
+    }
+  }
+
+  let baseQuery = ''
+  if (labelQuery && searchQueryPart) {
+    baseQuery = `${labelQuery} ${searchQueryPart}`
+  } else if (searchQueryPart) {
+    baseQuery = searchQueryPart
+  } else if (labelQuery) {
+    baseQuery = labelQuery
+  } else {
+    baseQuery = 'in:inbox'
+  }
+
+  return baseQuery
+}
+
+async function searchEmails(
+  accessToken: string,
+  config: GmailWebhookConfig,
+  requestId: string,
+  logger: ReturnType
+) {
+  try {
+    const baseQuery = buildGmailSearchQuery(config)
+    let timeConstraint = ''
+
+    if (config.lastCheckedTimestamp) {
+      const lastCheckedTime = new Date(config.lastCheckedTimestamp)
+      const now = new Date()
+      const minutesSinceLastCheck = (now.getTime() - lastCheckedTime.getTime()) / (60 * 1000)
+
+      if (minutesSinceLastCheck < 60) {
+        const bufferSeconds = Math.max(1 * 60 * 2, 180)
+        const cutoffTime = new Date(lastCheckedTime.getTime() - bufferSeconds * 1000)
+        const timestamp = Math.floor(cutoffTime.getTime() / 1000)
+        timeConstraint = ` after:${timestamp}`
+      } else if (minutesSinceLastCheck < 24 * 60) {
+        const hours = Math.ceil(minutesSinceLastCheck / 60) + 1
+        timeConstraint = ` newer_than:${hours}h`
+      } else {
+        const days = Math.min(Math.ceil(minutesSinceLastCheck / (24 * 60)), 7) + 1
+        timeConstraint = ` newer_than:${days}d`
+      }
+    } else {
+      timeConstraint = ' newer_than:1d'
+    }
+
+    const query = `${baseQuery}${timeConstraint}`
+    const searchUrl = `https://gmail.googleapis.com/gmail/v1/users/me/messages?q=${encodeURIComponent(query)}&maxResults=${config.maxEmailsPerPoll || 25}`
+
+    const searchResponse = await fetch(searchUrl, {
+      headers: { Authorization: `Bearer ${accessToken}` },
+    })
+
+    if (!searchResponse.ok) {
+      const errorData = await searchResponse.json()
+      logger.error(`[${requestId}] Gmail search API error:`, {
+        status: searchResponse.status,
+        statusText: searchResponse.statusText,
+        query,
+        error: errorData,
+      })
+      throw new Error(
+        `Gmail API error: ${searchResponse.status} ${searchResponse.statusText} - ${JSON.stringify(errorData)}`
+      )
+    }
+
+    const searchData = await searchResponse.json()
+
+    if (!searchData.messages || !searchData.messages.length) {
+      logger.info(`[${requestId}] No emails found matching query: ${query}`)
+      return { emails: [], latestHistoryId: config.historyId }
+    }
+
+    const idsToFetch = searchData.messages.slice(0, config.maxEmailsPerPoll || 25)
+    let latestHistoryId = config.historyId
+
+    logger.info(
+      `[${requestId}] Processing ${idsToFetch.length} emails from search API (total matches: ${searchData.messages.length})`
+    )
+
+    const emailResults = await Promise.allSettled(
+      idsToFetch.map((message: { id: string }) => getEmailDetails(accessToken, message.id))
+    )
+    const rejected = emailResults.filter((r) => r.status === 'rejected')
+    if (rejected.length > 0) {
+      logger.warn(`[${requestId}] Failed to fetch ${rejected.length} email details`)
+    }
+    const emails = emailResults
+      .filter(
+        (result): result is PromiseFulfilledResult => result.status === 'fulfilled'
+      )
+      .map((result) => result.value)
+
+    if (emails.length > 0 && emails[0].historyId) {
+      latestHistoryId = emails[0].historyId
+    }
+
+    return { emails, latestHistoryId }
+  } catch (error) {
+    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
+    logger.error(`[${requestId}] Error searching emails:`, errorMessage)
+    throw error
+  }
+}
+
+async function getEmailDetails(accessToken: string, messageId: string): Promise {
+  const messageUrl = `https://gmail.googleapis.com/gmail/v1/users/me/messages/${messageId}?format=full`
+
+  const messageResponse = await fetch(messageUrl, {
+    headers: { Authorization: `Bearer ${accessToken}` },
+  })
+
+  if (!messageResponse.ok) {
+    const errorData = await messageResponse.json().catch(() => ({}))
+    throw new Error(
+      `Failed to fetch email details for message ${messageId}: ${messageResponse.status} ${messageResponse.statusText} - ${JSON.stringify(errorData)}`
+    )
+  }
+
+  return await messageResponse.json()
+}
+
+function filterEmailsByLabels(emails: GmailEmail[], config: GmailWebhookConfig): GmailEmail[] {
+  if (!config.labelIds.length) {
+    return emails
+  }
+
+  return emails.filter((email) => {
+    const emailLabels = email.labelIds || []
+    const hasMatchingLabel = config.labelIds.some((configLabel) =>
+      emailLabels.includes(configLabel)
+    )
+    return config.labelFilterBehavior === 'INCLUDE' ? hasMatchingLabel : !hasMatchingLabel
+  })
+}
+
+async function processEmails(
+  emails: GmailEmail[],
+  webhookData: PollWebhookContext['webhookData'],
+  workflowData: PollWebhookContext['workflowData'],
+  config: GmailWebhookConfig,
+  accessToken: string,
+  requestId: string,
+  logger: ReturnType
+) {
+  let processedCount = 0
+  let failedCount = 0
+
+  for (const email of emails) {
+    try {
+      await pollingIdempotency.executeWithIdempotency(
+        'gmail',
+        `${webhookData.id}:${email.id}`,
+        async () => {
+          const headers: Record = {}
+          const payload = email.payload as Record | undefined
+          if (payload?.headers && Array.isArray(payload.headers)) {
+            for (const header of payload.headers as { name: string; value: string }[]) {
+              headers[header.name.toLowerCase()] = header.value
+            }
+          }
+
+          let textContent = ''
+          let htmlContent = ''
+
+          const extractContent = (part: Record) => {
+            if (!part) return
+
+            if (part.mimeType === 'text/plain') {
+              const body = part.body as { data?: string } | undefined
+              if (body?.data) {
+                textContent = Buffer.from(body.data, 'base64').toString('utf-8')
+              }
+            } else if (part.mimeType === 'text/html') {
+              const body = part.body as { data?: string } | undefined
+              if (body?.data) {
+                htmlContent = Buffer.from(body.data, 'base64').toString('utf-8')
+              }
+            }
+
+            if (part.parts && Array.isArray(part.parts)) {
+              for (const subPart of part.parts) {
+                extractContent(subPart as Record)
+              }
+            }
+          }
+
+          if (payload) {
+            extractContent(payload)
+          }
+
+          let date: string | null = null
+          if (headers.date) {
+            try {
+              date = new Date(headers.date).toISOString()
+            } catch (_e) {
+              // Keep date as null if parsing fails
+            }
+          } else if (email.internalDate) {
+            date = new Date(Number.parseInt(email.internalDate)).toISOString()
+          }
+
+          let attachments: GmailAttachment[] = []
+          const hasAttachments = payload ? extractAttachmentInfo(payload).length > 0 : false
+
+          if (config.includeAttachments && hasAttachments && payload) {
+            try {
+              const attachmentInfo = extractAttachmentInfo(payload)
+              attachments = await downloadAttachments(email.id, attachmentInfo, accessToken)
+            } catch (error) {
+              logger.error(
+                `[${requestId}] Error downloading attachments for email ${email.id}:`,
+                error
+              )
+            }
+          }
+
+          const simplifiedEmail: SimplifiedEmail = {
+            id: email.id,
+            threadId: email.threadId,
+            subject: headers.subject || '[No Subject]',
+            from: headers.from || '',
+            to: headers.to || '',
+            cc: headers.cc || '',
+            date,
+            bodyText: textContent,
+            bodyHtml: htmlContent,
+            labels: email.labelIds || [],
+            hasAttachments,
+            attachments,
+          }
+
+          const webhookPayload: GmailWebhookPayload = {
+            email: simplifiedEmail,
+            timestamp: new Date().toISOString(),
+            ...(config.includeRawEmail ? { rawEmail: email } : {}),
+          }
+
+          const result = await processPolledWebhookEvent(
+            webhookData,
+            workflowData,
+            webhookPayload,
+            requestId
+          )
+
+          if (!result.success) {
+            logger.error(
+              `[${requestId}] Failed to process webhook for email ${email.id}:`,
+              result.statusCode,
+              result.error
+            )
+            throw new Error(`Webhook processing failed (${result.statusCode}): ${result.error}`)
+          }
+
+          if (config.markAsRead) {
+            await markEmailAsRead(accessToken, email.id, logger)
+          }
+
+          return { emailId: email.id, processed: true }
+        }
+      )
+
+      logger.info(
+        `[${requestId}] Successfully processed email ${email.id} for webhook ${webhookData.id}`
+      )
+      processedCount++
+    } catch (error) {
+      const errorMessage = error instanceof Error ? error.message : 'Unknown error'
+      logger.error(`[${requestId}] Error processing email ${email.id}:`, errorMessage)
+      failedCount++
+    }
+  }
+
+  return { processedCount, failedCount }
+}
+
+async function markEmailAsRead(
+  accessToken: string,
+  messageId: string,
+  logger: ReturnType
+) {
+  const modifyUrl = `https://gmail.googleapis.com/gmail/v1/users/me/messages/${messageId}/modify`
+
+  try {
+    const response = await fetch(modifyUrl, {
+      method: 'POST',
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify({ removeLabelIds: ['UNREAD'] }),
+    })
+
+    if (!response.ok) {
+      await response.body?.cancel().catch(() => {})
+      throw new Error(
+        `Failed to mark email ${messageId} as read: ${response.status} ${response.statusText}`
+      )
+    }
+  } catch (error) {
+    logger.error(`Error marking email ${messageId} as read:`, error)
+    throw error
+  }
+}
diff --git a/apps/sim/lib/webhooks/imap-polling-service.ts b/apps/sim/lib/webhooks/polling/imap.ts
similarity index 57%
rename from apps/sim/lib/webhooks/imap-polling-service.ts
rename to apps/sim/lib/webhooks/polling/imap.ts
index 73219f72353..e5822aa8882 100644
--- a/apps/sim/lib/webhooks/imap-polling-service.ts
+++ b/apps/sim/lib/webhooks/polling/imap.ts
@@ -1,19 +1,14 @@
-import { db } from '@sim/db'
-import { webhook, workflow, workflowDeploymentVersion } from '@sim/db/schema'
-import { createLogger } from '@sim/logger'
-import type { InferSelectModel } from 'drizzle-orm'
-import { and, eq, isNull, or, sql } from 'drizzle-orm'
 import type { FetchMessageObject, MailboxLockObject } from 'imapflow'
 import { ImapFlow } from 'imapflow'
 import { pollingIdempotency } from '@/lib/core/idempotency/service'
 import { validateDatabaseHost } from '@/lib/core/security/input-validation.server'
-import { getInternalApiBaseUrl } from '@/lib/core/utils/urls'
-import { generateShortId } from '@/lib/core/utils/uuid'
-import { MAX_CONSECUTIVE_FAILURES } from '@/triggers/constants'
-
-const logger = createLogger('ImapPollingService')
-
-type WebhookRecord = InferSelectModel
+import type { PollingProviderHandler, PollWebhookContext } from '@/lib/webhooks/polling/types'
+import {
+  markWebhookFailed,
+  markWebhookSuccess,
+  updateWebhookProviderConfig,
+} from '@/lib/webhooks/polling/utils'
+import { processPolledWebhookEvent } from '@/lib/webhooks/processor'
 
 interface ImapWebhookConfig {
   host: string
@@ -21,13 +16,13 @@ interface ImapWebhookConfig {
   secure: boolean
   username: string
   password: string
-  mailbox: string | string[] // Can be single mailbox or array of mailboxes
+  mailbox: string | string[]
   searchCriteria: string
   markAsRead: boolean
   includeAttachments: boolean
   lastProcessedUid?: number
-  lastProcessedUidByMailbox?: Record // Track UID per mailbox for multi-mailbox
-  lastCheckedTimestamp?: string // ISO timestamp of last successful poll
+  lastProcessedUidByMailbox?: Record
+  lastCheckedTimestamp?: string
   maxEmailsPerPoll?: number
 }
 
@@ -69,206 +64,112 @@ export interface ImapWebhookPayload {
   timestamp: string
 }
 
-async function markWebhookFailed(webhookId: string) {
-  try {
-    const result = await db
-      .update(webhook)
-      .set({
-        failedCount: sql`COALESCE(${webhook.failedCount}, 0) + 1`,
-        lastFailedAt: new Date(),
-        updatedAt: new Date(),
-      })
-      .where(eq(webhook.id, webhookId))
-      .returning({ failedCount: webhook.failedCount })
-
-    const newFailedCount = result[0]?.failedCount || 0
-    const shouldDisable = newFailedCount >= MAX_CONSECUTIVE_FAILURES
-
-    if (shouldDisable) {
-      await db
-        .update(webhook)
-        .set({
-          isActive: false,
-          updatedAt: new Date(),
-        })
-        .where(eq(webhook.id, webhookId))
-
-      logger.warn(
-        `Webhook ${webhookId} auto-disabled after ${MAX_CONSECUTIVE_FAILURES} consecutive failures`
-      )
-    }
-  } catch (err) {
-    logger.error(`Failed to mark webhook ${webhookId} as failed:`, err)
-  }
-}
-
-async function markWebhookSuccess(webhookId: string) {
-  try {
-    await db
-      .update(webhook)
-      .set({
-        failedCount: 0,
-        updatedAt: new Date(),
-      })
-      .where(eq(webhook.id, webhookId))
-  } catch (err) {
-    logger.error(`Failed to mark webhook ${webhookId} as successful:`, err)
-  }
-}
-
-export async function pollImapWebhooks() {
-  logger.info('Starting IMAP webhook polling')
-
-  try {
-    const activeWebhooksResult = await db
-      .select({ webhook })
-      .from(webhook)
-      .innerJoin(workflow, eq(webhook.workflowId, workflow.id))
-      .leftJoin(
-        workflowDeploymentVersion,
-        and(
-          eq(workflowDeploymentVersion.workflowId, workflow.id),
-          eq(workflowDeploymentVersion.isActive, true)
-        )
-      )
-      .where(
-        and(
-          eq(webhook.provider, 'imap'),
-          eq(webhook.isActive, true),
-          eq(workflow.isDeployed, true),
-          or(
-            eq(webhook.deploymentVersionId, workflowDeploymentVersion.id),
-            and(isNull(workflowDeploymentVersion.id), isNull(webhook.deploymentVersionId))
-          )
-        )
-      )
-
-    const activeWebhooks = activeWebhooksResult.map((r) => r.webhook)
-
-    if (!activeWebhooks.length) {
-      logger.info('No active IMAP webhooks found')
-      return { total: 0, successful: 0, failed: 0, details: [] }
-    }
-
-    logger.info(`Found ${activeWebhooks.length} active IMAP webhooks`)
+export const imapPollingHandler: PollingProviderHandler = {
+  provider: 'imap',
+  label: 'IMAP',
 
-    const CONCURRENCY = 5
+  async pollWebhook(ctx: PollWebhookContext): Promise<'success' | 'failure'> {
+    const { webhookData, workflowData, requestId, logger } = ctx
+    const webhookId = webhookData.id
 
-    const running: Promise[] = []
-    let successCount = 0
-    let failureCount = 0
+    try {
+      const config = webhookData.providerConfig as unknown as ImapWebhookConfig
 
-    const enqueue = async (webhookData: (typeof activeWebhooks)[number]) => {
-      const webhookId = webhookData.id
-      const requestId = generateShortId()
+      if (!config.host || !config.username || !config.password) {
+        logger.error(`[${requestId}] Missing IMAP credentials for webhook ${webhookId}`)
+        await markWebhookFailed(webhookId, logger)
+        return 'failure'
+      }
 
-      try {
-        const config = webhookData.providerConfig as unknown as ImapWebhookConfig
+      const hostValidation = await validateDatabaseHost(config.host, 'host')
+      if (!hostValidation.isValid) {
+        logger.error(
+          `[${requestId}] IMAP host validation failed for webhook ${webhookId}: ${hostValidation.error}`
+        )
+        await markWebhookFailed(webhookId, logger)
+        return 'failure'
+      }
 
-        if (!config.host || !config.username || !config.password) {
-          logger.error(`[${requestId}] Missing IMAP credentials for webhook ${webhookId}`)
-          await markWebhookFailed(webhookId)
-          failureCount++
-          return
-        }
+      const { emails, latestUidByMailbox } = await fetchNewEmails(
+        config,
+        requestId,
+        hostValidation.resolvedIP!,
+        logger
+      )
+      const pollTimestamp = new Date().toISOString()
 
-        const hostValidation = await validateDatabaseHost(config.host, 'host')
-        if (!hostValidation.isValid) {
-          logger.error(
-            `[${requestId}] IMAP host validation failed for webhook ${webhookId}: ${hostValidation.error}`
-          )
-          await markWebhookFailed(webhookId)
-          failureCount++
-          return
-        }
+      if (!emails || !emails.length) {
+        await updateImapState(webhookId, latestUidByMailbox, pollTimestamp, config, logger)
+        await markWebhookSuccess(webhookId, logger)
+        logger.info(`[${requestId}] No new emails found for webhook ${webhookId}`)
+        return 'success'
+      }
 
-        const fetchResult = await fetchNewEmails(config, requestId, hostValidation.resolvedIP!)
-        const { emails, latestUidByMailbox } = fetchResult
-        const pollTimestamp = new Date().toISOString()
+      logger.info(`[${requestId}] Found ${emails.length} new emails for webhook ${webhookId}`)
 
-        if (!emails || !emails.length) {
-          await updateWebhookLastProcessedUids(webhookId, latestUidByMailbox, pollTimestamp)
-          await markWebhookSuccess(webhookId)
-          logger.info(`[${requestId}] No new emails found for webhook ${webhookId}`)
-          successCount++
-          return
-        }
+      const { processedCount, failedCount } = await processEmails(
+        emails,
+        webhookData,
+        workflowData,
+        config,
+        requestId,
+        hostValidation.resolvedIP!,
+        logger
+      )
 
-        logger.info(`[${requestId}] Found ${emails.length} new emails for webhook ${webhookId}`)
+      await updateImapState(webhookId, latestUidByMailbox, pollTimestamp, config, logger)
 
-        const { processedCount, failedCount: emailFailedCount } = await processEmails(
-          emails,
-          webhookData,
-          config,
-          requestId,
-          hostValidation.resolvedIP!
+      if (failedCount > 0 && processedCount === 0) {
+        await markWebhookFailed(webhookId, logger)
+        logger.warn(
+          `[${requestId}] All ${failedCount} emails failed to process for webhook ${webhookId}`
         )
-
-        await updateWebhookLastProcessedUids(webhookId, latestUidByMailbox, pollTimestamp)
-
-        if (emailFailedCount > 0 && processedCount === 0) {
-          await markWebhookFailed(webhookId)
-          failureCount++
-          logger.warn(
-            `[${requestId}] All ${emailFailedCount} emails failed to process for webhook ${webhookId}`
-          )
-        } else {
-          await markWebhookSuccess(webhookId)
-          successCount++
-          logger.info(
-            `[${requestId}] Successfully processed ${processedCount} emails for webhook ${webhookId}${emailFailedCount > 0 ? ` (${emailFailedCount} failed)` : ''}`
-          )
-        }
-      } catch (error) {
-        logger.error(`[${requestId}] Error processing IMAP webhook ${webhookId}:`, error)
-        await markWebhookFailed(webhookId)
-        failureCount++
+        return 'failure'
       }
-    }
-
-    for (const webhookData of activeWebhooks) {
-      const promise: Promise = enqueue(webhookData)
-        .catch((err) => {
-          logger.error('Unexpected error in webhook processing:', err)
-          failureCount++
-        })
-        .finally(() => {
-          // Self-remove from running array when completed
-          const idx = running.indexOf(promise)
-          if (idx !== -1) running.splice(idx, 1)
-        })
-
-      running.push(promise)
-
-      if (running.length >= CONCURRENCY) {
-        await Promise.race(running)
-      }
-    }
 
-    await Promise.allSettled(running)
-
-    const summary = {
-      total: activeWebhooks.length,
-      successful: successCount,
-      failed: failureCount,
-      details: [],
+      await markWebhookSuccess(webhookId, logger)
+      logger.info(
+        `[${requestId}] Successfully processed ${processedCount} emails for webhook ${webhookId}${failedCount > 0 ? ` (${failedCount} failed)` : ''}`
+      )
+      return 'success'
+    } catch (error) {
+      logger.error(`[${requestId}] Error processing IMAP webhook ${webhookId}:`, error)
+      await markWebhookFailed(webhookId, logger)
+      return 'failure'
     }
+  },
+}
 
-    logger.info('IMAP polling completed', {
-      total: summary.total,
-      successful: summary.successful,
-      failed: summary.failed,
-    })
+async function updateImapState(
+  webhookId: string,
+  uidByMailbox: Record,
+  timestamp: string,
+  config: ImapWebhookConfig,
+  logger: ReturnType
+) {
+  const existingUidByMailbox = config.lastProcessedUidByMailbox || {}
+  const mergedUidByMailbox = { ...existingUidByMailbox }
 
-    return summary
-  } catch (error) {
-    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
-    logger.error('Error in IMAP polling service:', errorMessage)
-    throw error
+  for (const [mailbox, uid] of Object.entries(uidByMailbox)) {
+    mergedUidByMailbox[mailbox] = Math.max(uid, mergedUidByMailbox[mailbox] || 0)
   }
+
+  await updateWebhookProviderConfig(
+    webhookId,
+    {
+      lastProcessedUidByMailbox: mergedUidByMailbox,
+      lastCheckedTimestamp: timestamp,
+    },
+    logger
+  )
 }
 
-async function fetchNewEmails(config: ImapWebhookConfig, requestId: string, resolvedIP: string) {
+async function fetchNewEmails(
+  config: ImapWebhookConfig,
+  requestId: string,
+  resolvedIP: string,
+  logger: ReturnType
+) {
   const client = new ImapFlow({
     host: resolvedIP,
     servername: config.host,
@@ -278,15 +179,13 @@ async function fetchNewEmails(config: ImapWebhookConfig, requestId: string, reso
       user: config.username,
       pass: config.password,
     },
-    tls: {
-      rejectUnauthorized: true,
-    },
+    tls: { rejectUnauthorized: true },
     logger: false,
   })
 
   const emails: Array<{
     uid: number
-    mailboxPath: string // Track which mailbox this email came from
+    mailboxPath: string
     envelope: FetchMessageObject['envelope']
     bodyStructure: FetchMessageObject['bodyStructure']
     source?: Buffer
@@ -305,13 +204,12 @@ async function fetchNewEmails(config: ImapWebhookConfig, requestId: string, reso
       if (totalEmailsCollected >= maxEmails) break
 
       try {
-        const mailbox = await client.mailboxOpen(mailboxPath)
+        await client.mailboxOpen(mailboxPath)
 
-        // Parse search criteria - expects JSON object from UI
-        let searchCriteria: any = { unseen: true }
+        let searchCriteria: Record = { unseen: true }
         if (config.searchCriteria) {
           if (typeof config.searchCriteria === 'object') {
-            searchCriteria = config.searchCriteria
+            searchCriteria = config.searchCriteria as unknown as Record
           } else if (typeof config.searchCriteria === 'string') {
             try {
               searchCriteria = JSON.parse(config.searchCriteria)
@@ -327,15 +225,11 @@ async function fetchNewEmails(config: ImapWebhookConfig, requestId: string, reso
           searchCriteria = { ...searchCriteria, uid: `${lastUidForMailbox + 1}:*` }
         }
 
-        // Add time-based filtering similar to Gmail
-        // If lastCheckedTimestamp exists, use it with 1 minute buffer
-        // If first poll (no timestamp), default to last 24 hours to avoid processing ALL unseen emails
         if (config.lastCheckedTimestamp) {
           const lastChecked = new Date(config.lastCheckedTimestamp)
           const bufferTime = new Date(lastChecked.getTime() - 60000)
           searchCriteria = { ...searchCriteria, since: bufferTime }
         } else {
-          // First poll: only get emails from last 24 hours to avoid overwhelming first run
           const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000)
           searchCriteria = { ...searchCriteria, since: oneDayAgo }
         }
@@ -344,15 +238,13 @@ async function fetchNewEmails(config: ImapWebhookConfig, requestId: string, reso
         try {
           const searchResult = await client.search(searchCriteria, { uid: true })
           messageUids = searchResult === false ? [] : searchResult
-        } catch (searchError) {
+        } catch {
           continue
         }
 
-        if (messageUids.length === 0) {
-          continue
-        }
+        if (messageUids.length === 0) continue
 
-        messageUids.sort((a, b) => a - b) // Sort ascending to process oldest first
+        messageUids.sort((a, b) => a - b)
         const remainingSlots = maxEmails - totalEmailsCollected
         const uidsToProcess = messageUids.slice(0, remainingSlots)
 
@@ -365,12 +257,7 @@ async function fetchNewEmails(config: ImapWebhookConfig, requestId: string, reso
 
         for await (const msg of client.fetch(
           uidsToProcess,
-          {
-            uid: true,
-            envelope: true,
-            bodyStructure: true,
-            source: true,
-          },
+          { uid: true, envelope: true, bodyStructure: true, source: true },
           { uid: true }
         )) {
           emails.push({
@@ -388,7 +275,6 @@ async function fetchNewEmails(config: ImapWebhookConfig, requestId: string, reso
     }
 
     await client.logout()
-
     return { emails, latestUidByMailbox }
   } catch (error) {
     try {
@@ -400,9 +286,6 @@ async function fetchNewEmails(config: ImapWebhookConfig, requestId: string, reso
   }
 }
 
-/**
- * Get the list of mailboxes to check based on config
- */
 function getMailboxesToCheck(config: ImapWebhookConfig): string[] {
   if (!config.mailbox || (Array.isArray(config.mailbox) && config.mailbox.length === 0)) {
     return ['INBOX']
@@ -488,7 +371,6 @@ function extractAttachmentsFromSource(
   bodyStructure: FetchMessageObject['bodyStructure']
 ): ImapAttachment[] {
   const attachments: ImapAttachment[] = []
-
   if (!bodyStructure) return attachments
 
   const content = source.toString('utf-8')
@@ -534,24 +416,13 @@ function extractAttachmentsFromSource(
   return attachments
 }
 
-/**
- * Checks if a body structure contains attachments by examining disposition
- */
 function hasAttachmentsInBodyStructure(structure: FetchMessageObject['bodyStructure']): boolean {
   if (!structure) return false
-
-  if (structure.disposition === 'attachment') {
-    return true
-  }
-
-  if (structure.disposition === 'inline' && structure.dispositionParameters?.filename) {
-    return true
-  }
-
+  if (structure.disposition === 'attachment') return true
+  if (structure.disposition === 'inline' && structure.dispositionParameters?.filename) return true
   if (structure.childNodes && Array.isArray(structure.childNodes)) {
     return structure.childNodes.some((child) => hasAttachmentsInBodyStructure(child))
   }
-
   return false
 }
 
@@ -563,10 +434,12 @@ async function processEmails(
     bodyStructure: FetchMessageObject['bodyStructure']
     source?: Buffer
   }>,
-  webhookData: WebhookRecord,
+  webhookData: PollWebhookContext['webhookData'],
+  workflowData: PollWebhookContext['workflowData'],
   config: ImapWebhookConfig,
   requestId: string,
-  resolvedIP: string
+  resolvedIP: string,
+  logger: ReturnType
 ) {
   let processedCount = 0
   let failedCount = 0
@@ -580,9 +453,7 @@ async function processEmails(
       user: config.username,
       pass: config.password,
     },
-    tls: {
-      rejectUnauthorized: true,
-    },
+    tls: { rejectUnauthorized: true },
     logger: false,
   })
 
@@ -644,25 +515,20 @@ async function processEmails(
               timestamp: new Date().toISOString(),
             }
 
-            const webhookUrl = `${getInternalApiBaseUrl()}/api/webhooks/trigger/${webhookData.path}`
-
-            const response = await fetch(webhookUrl, {
-              method: 'POST',
-              headers: {
-                'Content-Type': 'application/json',
-                'User-Agent': 'Sim/1.0',
-              },
-              body: JSON.stringify(payload),
-            })
+            const result = await processPolledWebhookEvent(
+              webhookData,
+              workflowData,
+              payload,
+              requestId
+            )
 
-            if (!response.ok) {
-              const errorText = await response.text()
+            if (!result.success) {
               logger.error(
-                `[${requestId}] Failed to trigger webhook for email ${email.uid}:`,
-                response.status,
-                errorText
+                `[${requestId}] Failed to process webhook for email ${email.uid}:`,
+                result.statusCode,
+                result.error
               )
-              throw new Error(`Webhook request failed: ${response.status} - ${errorText}`)
+              throw new Error(`Webhook processing failed (${result.statusCode}): ${result.error}`)
             }
 
             if (config.markAsRead) {
@@ -684,11 +550,7 @@ async function processEmails(
               }
             }
 
-            return {
-              emailUid: email.uid,
-              webhookStatus: response.status,
-              processed: true,
-            }
+            return { emailUid: email.uid, processed: true }
           }
         )
 
@@ -717,31 +579,3 @@ async function processEmails(
 
   return { processedCount, failedCount }
 }
-
-async function updateWebhookLastProcessedUids(
-  webhookId: string,
-  uidByMailbox: Record,
-  timestamp: string
-) {
-  const result = await db.select().from(webhook).where(eq(webhook.id, webhookId))
-  const existingConfig = (result[0]?.providerConfig as Record) || {}
-
-  const existingUidByMailbox = existingConfig.lastProcessedUidByMailbox || {}
-  const mergedUidByMailbox = { ...existingUidByMailbox }
-
-  for (const [mailbox, uid] of Object.entries(uidByMailbox)) {
-    mergedUidByMailbox[mailbox] = Math.max(uid, mergedUidByMailbox[mailbox] || 0)
-  }
-
-  await db
-    .update(webhook)
-    .set({
-      providerConfig: {
-        ...existingConfig,
-        lastProcessedUidByMailbox: mergedUidByMailbox,
-        lastCheckedTimestamp: timestamp,
-      } as any,
-      updatedAt: new Date(),
-    })
-    .where(eq(webhook.id, webhookId))
-}
diff --git a/apps/sim/lib/webhooks/polling/index.ts b/apps/sim/lib/webhooks/polling/index.ts
new file mode 100644
index 00000000000..4d0ba2df0de
--- /dev/null
+++ b/apps/sim/lib/webhooks/polling/index.ts
@@ -0,0 +1,9 @@
+export { pollProvider } from '@/lib/webhooks/polling/orchestrator'
+export { getPollingHandler, VALID_POLLING_PROVIDERS } from '@/lib/webhooks/polling/registry'
+export type {
+  PollingProviderHandler,
+  PollSummary,
+  PollWebhookContext,
+  WebhookRecord,
+  WorkflowRecord,
+} from '@/lib/webhooks/polling/types'
diff --git a/apps/sim/lib/webhooks/polling/orchestrator.ts b/apps/sim/lib/webhooks/polling/orchestrator.ts
new file mode 100644
index 00000000000..508ff91972f
--- /dev/null
+++ b/apps/sim/lib/webhooks/polling/orchestrator.ts
@@ -0,0 +1,46 @@
+import { createLogger } from '@sim/logger'
+import { generateShortId } from '@/lib/core/utils/uuid'
+import { getPollingHandler } from '@/lib/webhooks/polling/registry'
+import type { PollSummary, WebhookRecord, WorkflowRecord } from '@/lib/webhooks/polling/types'
+import { fetchActiveWebhooks, runWithConcurrency } from '@/lib/webhooks/polling/utils'
+
+/** Poll all active webhooks for a given provider. */
+export async function pollProvider(providerName: string): Promise {
+  const handler = getPollingHandler(providerName)
+  if (!handler) {
+    throw new Error(`Unknown polling provider: ${providerName}`)
+  }
+
+  const logger = createLogger(`${handler.label}PollingService`)
+  logger.info(`Starting ${handler.label} webhook polling`)
+
+  const activeWebhooks = await fetchActiveWebhooks(handler.provider)
+  if (!activeWebhooks.length) {
+    logger.info(`No active ${handler.label} webhooks found`)
+    return { total: 0, successful: 0, failed: 0 }
+  }
+
+  logger.info(`Found ${activeWebhooks.length} active ${handler.label} webhooks`)
+
+  const { successCount, failureCount } = await runWithConcurrency(
+    activeWebhooks,
+    async (entry) => {
+      const requestId = generateShortId()
+      return handler.pollWebhook({
+        webhookData: entry.webhook as WebhookRecord,
+        workflowData: entry.workflow as WorkflowRecord,
+        requestId,
+        logger,
+      })
+    },
+    logger
+  )
+
+  const summary: PollSummary = {
+    total: activeWebhooks.length,
+    successful: successCount,
+    failed: failureCount,
+  }
+  logger.info(`${handler.label} polling completed`, summary)
+  return summary
+}
diff --git a/apps/sim/lib/webhooks/outlook-polling-service.ts b/apps/sim/lib/webhooks/polling/outlook.ts
similarity index 50%
rename from apps/sim/lib/webhooks/outlook-polling-service.ts
rename to apps/sim/lib/webhooks/polling/outlook.ts
index 7cf87f1707c..e6874940c61 100644
--- a/apps/sim/lib/webhooks/outlook-polling-service.ts
+++ b/apps/sim/lib/webhooks/polling/outlook.ts
@@ -1,77 +1,17 @@
-import { db } from '@sim/db'
-import {
-  account,
-  credentialSet,
-  webhook,
-  workflow,
-  workflowDeploymentVersion,
-} from '@sim/db/schema'
-import { createLogger } from '@sim/logger'
-import { and, eq, isNull, or, sql } from 'drizzle-orm'
 import { htmlToText } from 'html-to-text'
-import { isOrganizationOnTeamOrEnterprisePlan } from '@/lib/billing'
-import { pollingIdempotency } from '@/lib/core/idempotency'
-import { getInternalApiBaseUrl } from '@/lib/core/utils/urls'
-import { generateShortId } from '@/lib/core/utils/uuid'
+import { pollingIdempotency } from '@/lib/core/idempotency/service'
+import type { PollingProviderHandler, PollWebhookContext } from '@/lib/webhooks/polling/types'
 import {
-  getOAuthToken,
-  refreshAccessTokenIfNeeded,
-  resolveOAuthAccountId,
-} from '@/app/api/auth/oauth/utils'
-import { MAX_CONSECUTIVE_FAILURES } from '@/triggers/constants'
-
-const logger = createLogger('OutlookPollingService')
-
-async function markWebhookFailed(webhookId: string) {
-  try {
-    const result = await db
-      .update(webhook)
-      .set({
-        failedCount: sql`COALESCE(${webhook.failedCount}, 0) + 1`,
-        lastFailedAt: new Date(),
-        updatedAt: new Date(),
-      })
-      .where(eq(webhook.id, webhookId))
-      .returning({ failedCount: webhook.failedCount })
-
-    const newFailedCount = result[0]?.failedCount || 0
-    const shouldDisable = newFailedCount >= MAX_CONSECUTIVE_FAILURES
-
-    if (shouldDisable) {
-      await db
-        .update(webhook)
-        .set({
-          isActive: false,
-          updatedAt: new Date(),
-        })
-        .where(eq(webhook.id, webhookId))
-
-      logger.warn(
-        `Webhook ${webhookId} auto-disabled after ${MAX_CONSECUTIVE_FAILURES} consecutive failures`
-      )
-    }
-  } catch (err) {
-    logger.error(`Failed to mark webhook ${webhookId} as failed:`, err)
-  }
-}
-
-async function markWebhookSuccess(webhookId: string) {
-  try {
-    await db
-      .update(webhook)
-      .set({
-        failedCount: 0, // Reset on success
-        updatedAt: new Date(),
-      })
-      .where(eq(webhook.id, webhookId))
-  } catch (err) {
-    logger.error(`Failed to mark webhook ${webhookId} as successful:`, err)
-  }
-}
+  markWebhookFailed,
+  markWebhookSuccess,
+  resolveOAuthCredential,
+  updateWebhookProviderConfig,
+} from '@/lib/webhooks/polling/utils'
+import { processPolledWebhookEvent } from '@/lib/webhooks/processor'
 
 interface OutlookWebhookConfig {
   credentialId: string
-  folderIds?: string[] // e.g., ['inbox', 'sent']
+  folderIds?: string[]
   folderFilterBehavior?: 'INCLUDE' | 'EXCLUDE'
   markAsRead?: boolean
   maxEmailsPerPoll?: number
@@ -145,10 +85,6 @@ export interface OutlookWebhookPayload {
   rawEmail?: OutlookEmail
 }
 
-/**
- * Convert HTML content to a readable plain-text representation.
- * Keeps reasonable newlines and decodes common HTML entities.
- */
 function convertHtmlToPlainText(html: string): string {
   if (!html) return ''
   return htmlToText(html, {
@@ -163,217 +99,78 @@ function convertHtmlToPlainText(html: string): string {
   })
 }
 
-export async function pollOutlookWebhooks() {
-  logger.info('Starting Outlook webhook polling')
+export const outlookPollingHandler: PollingProviderHandler = {
+  provider: 'outlook',
+  label: 'Outlook',
 
-  try {
-    const activeWebhooksResult = await db
-      .select({ webhook })
-      .from(webhook)
-      .innerJoin(workflow, eq(webhook.workflowId, workflow.id))
-      .leftJoin(
-        workflowDeploymentVersion,
-        and(
-          eq(workflowDeploymentVersion.workflowId, workflow.id),
-          eq(workflowDeploymentVersion.isActive, true)
-        )
-      )
-      .where(
-        and(
-          eq(webhook.provider, 'outlook'),
-          eq(webhook.isActive, true),
-          eq(workflow.isDeployed, true),
-          or(
-            eq(webhook.deploymentVersionId, workflowDeploymentVersion.id),
-            and(isNull(workflowDeploymentVersion.id), isNull(webhook.deploymentVersionId))
-          )
-        )
-      )
-
-    const activeWebhooks = activeWebhooksResult.map((r) => r.webhook)
+  async pollWebhook(ctx: PollWebhookContext): Promise<'success' | 'failure'> {
+    const { webhookData, workflowData, requestId, logger } = ctx
+    const webhookId = webhookData.id
 
-    if (!activeWebhooks.length) {
-      logger.info('No active Outlook webhooks found')
-      return { total: 0, successful: 0, failed: 0, details: [] }
-    }
-
-    logger.info(`Found ${activeWebhooks.length} active Outlook webhooks`)
-
-    const CONCURRENCY = 10
-    const running: Promise[] = []
-    let successCount = 0
-    let failureCount = 0
-
-    const enqueue = async (webhookData: (typeof activeWebhooks)[number]) => {
-      const webhookId = webhookData.id
-      const requestId = generateShortId()
-
-      try {
-        logger.info(`[${requestId}] Processing Outlook webhook: ${webhookId}`)
-
-        const metadata = webhookData.providerConfig as any
-        const credentialId: string | undefined = metadata?.credentialId
-        const userId: string | undefined = metadata?.userId
-        const credentialSetId: string | undefined = webhookData.credentialSetId ?? undefined
-
-        if (!credentialId && !userId) {
-          logger.error(`[${requestId}] Missing credentialId and userId for webhook ${webhookId}`)
-          await markWebhookFailed(webhookId)
-          failureCount++
-          return
-        }
-
-        if (credentialSetId) {
-          const [cs] = await db
-            .select({ organizationId: credentialSet.organizationId })
-            .from(credentialSet)
-            .where(eq(credentialSet.id, credentialSetId))
-            .limit(1)
-
-          if (cs?.organizationId) {
-            const hasAccess = await isOrganizationOnTeamOrEnterprisePlan(cs.organizationId)
-            if (!hasAccess) {
-              logger.error(
-                `[${requestId}] Polling Group plan restriction: Your current plan does not support Polling Groups. Upgrade to Team or Enterprise to use this feature.`,
-                {
-                  webhookId,
-                  credentialSetId,
-                  organizationId: cs.organizationId,
-                }
-              )
-              await markWebhookFailed(webhookId)
-              failureCount++
-              return
-            }
-          }
-        }
-
-        let accessToken: string | null = null
-        if (credentialId) {
-          const resolved = await resolveOAuthAccountId(credentialId)
-          if (!resolved) {
-            logger.error(
-              `[${requestId}] Failed to resolve OAuth account for credential ${credentialId}, webhook ${webhookId}`
-            )
-            await markWebhookFailed(webhookId)
-            failureCount++
-            return
-          }
-          const rows = await db
-            .select()
-            .from(account)
-            .where(eq(account.id, resolved.accountId))
-            .limit(1)
-          if (!rows.length) {
-            logger.error(
-              `[${requestId}] Credential ${credentialId} not found for webhook ${webhookId}`
-            )
-            await markWebhookFailed(webhookId)
-            failureCount++
-            return
-          }
-          const ownerUserId = rows[0].userId
-          accessToken = await refreshAccessTokenIfNeeded(resolved.accountId, ownerUserId, requestId)
-        } else if (userId) {
-          accessToken = await getOAuthToken(userId, 'outlook')
-        }
-
-        if (!accessToken) {
-          logger.error(
-            `[${requestId}] Failed to get Outlook access token for webhook ${webhookId} (cred or fallback)`
-          )
-          await markWebhookFailed(webhookId)
-          failureCount++
-          return
-        }
+    try {
+      logger.info(`[${requestId}] Processing Outlook webhook: ${webhookId}`)
 
-        const config = webhookData.providerConfig as unknown as OutlookWebhookConfig
+      const accessToken = await resolveOAuthCredential(webhookData, 'outlook', requestId, logger)
+      const config = webhookData.providerConfig as unknown as OutlookWebhookConfig
+      const now = new Date()
 
-        const now = new Date()
+      const { emails } = await fetchNewOutlookEmails(accessToken, config, requestId, logger)
 
-        const fetchResult = await fetchNewOutlookEmails(accessToken, config, requestId)
-        const { emails } = fetchResult
+      if (!emails || !emails.length) {
+        await updateWebhookProviderConfig(
+          webhookId,
+          { lastCheckedTimestamp: now.toISOString() },
+          logger
+        )
+        await markWebhookSuccess(webhookId, logger)
+        logger.info(`[${requestId}] No new emails found for webhook ${webhookId}`)
+        return 'success'
+      }
 
-        if (!emails || !emails.length) {
-          await updateWebhookLastChecked(webhookId, now.toISOString())
-          await markWebhookSuccess(webhookId)
-          logger.info(`[${requestId}] No new emails found for webhook ${webhookId}`)
-          successCount++
-          return
-        }
+      logger.info(`[${requestId}] Found ${emails.length} emails for webhook ${webhookId}`)
 
-        logger.info(`[${requestId}] Found ${emails.length} emails for webhook ${webhookId}`)
+      const { processedCount, failedCount } = await processOutlookEmails(
+        emails,
+        webhookData,
+        workflowData,
+        config,
+        accessToken,
+        requestId,
+        logger
+      )
 
-        logger.info(`[${requestId}] Processing ${emails.length} emails for webhook ${webhookId}`)
+      await updateWebhookProviderConfig(
+        webhookId,
+        { lastCheckedTimestamp: now.toISOString() },
+        logger
+      )
 
-        const { processedCount, failedCount } = await processOutlookEmails(
-          emails,
-          webhookData,
-          config,
-          accessToken,
-          requestId
+      if (failedCount > 0 && processedCount === 0) {
+        await markWebhookFailed(webhookId, logger)
+        logger.warn(
+          `[${requestId}] All ${failedCount} emails failed to process for webhook ${webhookId}`
         )
-
-        await updateWebhookLastChecked(webhookId, now.toISOString())
-
-        if (failedCount > 0 && processedCount === 0) {
-          await markWebhookFailed(webhookId)
-          failureCount++
-          logger.warn(
-            `[${requestId}] All ${failedCount} emails failed to process for webhook ${webhookId}`
-          )
-        } else {
-          await markWebhookSuccess(webhookId)
-          successCount++
-          logger.info(
-            `[${requestId}] Successfully processed ${processedCount} emails for webhook ${webhookId}${failedCount > 0 ? ` (${failedCount} failed)` : ''}`
-          )
-        }
-      } catch (error) {
-        logger.error(`[${requestId}] Error processing Outlook webhook ${webhookId}:`, error)
-        await markWebhookFailed(webhookId)
-        failureCount++
+        return 'failure'
       }
-    }
-
-    for (const webhookData of activeWebhooks) {
-      const promise: Promise = enqueue(webhookData)
-        .catch((err) => {
-          logger.error('Unexpected error in webhook processing:', err)
-          failureCount++
-        })
-        .finally(() => {
-          const idx = running.indexOf(promise)
-          if (idx !== -1) running.splice(idx, 1)
-        })
-
-      running.push(promise)
-
-      if (running.length >= CONCURRENCY) {
-        await Promise.race(running)
-      }
-    }
 
-    await Promise.allSettled(running)
-
-    logger.info(`Outlook polling completed: ${successCount} successful, ${failureCount} failed`)
-
-    return {
-      total: activeWebhooks.length,
-      successful: successCount,
-      failed: failureCount,
-      details: [],
+      await markWebhookSuccess(webhookId, logger)
+      logger.info(
+        `[${requestId}] Successfully processed ${processedCount} emails for webhook ${webhookId}${failedCount > 0 ? ` (${failedCount} failed)` : ''}`
+      )
+      return 'success'
+    } catch (error) {
+      logger.error(`[${requestId}] Error processing Outlook webhook ${webhookId}:`, error)
+      await markWebhookFailed(webhookId, logger)
+      return 'failure'
     }
-  } catch (error) {
-    logger.error('Error during Outlook webhook polling:', error)
-    throw error
-  }
+  },
 }
 
 async function fetchNewOutlookEmails(
   accessToken: string,
   config: OutlookWebhookConfig,
-  requestId: string
+  requestId: string,
+  logger: ReturnType
 ) {
   try {
     const apiUrl = 'https://graph.microsoft.com/v1.0/me/messages'
@@ -383,9 +180,7 @@ async function fetchNewOutlookEmails(
       '$select',
       'id,conversationId,subject,bodyPreview,body,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,hasAttachments,isRead,parentFolderId'
     )
-
     params.append('$orderby', 'receivedDateTime desc')
-
     params.append('$top', (config.maxEmailsPerPoll || 25).toString())
 
     if (config.lastCheckedTimestamp) {
@@ -395,7 +190,6 @@ async function fetchNewOutlookEmails(
     }
 
     const fullUrl = `${apiUrl}?${params.toString()}`
-
     logger.info(`[${requestId}] Fetching emails from: ${fullUrl}`)
 
     const response = await fetch(fullUrl, {
@@ -427,7 +221,8 @@ async function fetchNewOutlookEmails(
         resolvedFolderIds = await resolveWellKnownFolderIds(
           accessToken,
           config.folderIds,
-          requestId
+          requestId,
+          logger
         )
       }
     }
@@ -463,7 +258,8 @@ function isWellKnownFolderName(folderId: string): boolean {
 async function resolveWellKnownFolderId(
   accessToken: string,
   folderName: string,
-  requestId: string
+  requestId: string,
+  logger: ReturnType
 ): Promise {
   try {
     const response = await fetch(`https://graph.microsoft.com/v1.0/me/mailFolders/${folderName}`, {
@@ -491,18 +287,16 @@ async function resolveWellKnownFolderId(
 async function resolveWellKnownFolderIds(
   accessToken: string,
   folderIds: string[],
-  requestId: string
+  requestId: string,
+  logger: ReturnType
 ): Promise> {
   const resolvedIds = new Map()
-
   const wellKnownFolders = folderIds.filter(isWellKnownFolderName)
-  if (wellKnownFolders.length === 0) {
-    return resolvedIds
-  }
+  if (wellKnownFolders.length === 0) return resolvedIds
 
   const resolutions = await Promise.all(
     wellKnownFolders.map(async (folderName) => {
-      const actualId = await resolveWellKnownFolderId(accessToken, folderName, requestId)
+      const actualId = await resolveWellKnownFolderId(accessToken, folderName, requestId, logger)
       return { folderName, actualId }
     })
   )
@@ -516,7 +310,6 @@ async function resolveWellKnownFolderIds(
   logger.info(
     `[${requestId}] Resolved ${resolvedIds.size}/${wellKnownFolders.length} well-known folders`
   )
-
   return resolvedIds
 }
 
@@ -525,16 +318,12 @@ function filterEmailsByFolder(
   config: OutlookWebhookConfig,
   resolvedFolderIds?: Map
 ): OutlookEmail[] {
-  if (!config.folderIds || !config.folderIds.length) {
-    return emails
-  }
+  if (!config.folderIds || !config.folderIds.length) return emails
 
   const actualFolderIds = config.folderIds.map((configFolder) => {
     if (resolvedFolderIds && isWellKnownFolderName(configFolder)) {
       const resolvedId = resolvedFolderIds.get(configFolder.toLowerCase())
-      if (resolvedId) {
-        return resolvedId
-      }
+      if (resolvedId) return resolvedId
     }
     return configFolder
   })
@@ -544,17 +333,18 @@ function filterEmailsByFolder(
     const hasMatchingFolder = actualFolderIds.some(
       (folderId) => emailFolderId.toLowerCase() === folderId.toLowerCase()
     )
-
     return config.folderFilterBehavior === 'INCLUDE' ? hasMatchingFolder : !hasMatchingFolder
   })
 }
 
 async function processOutlookEmails(
   emails: OutlookEmail[],
-  webhookData: any,
+  webhookData: PollWebhookContext['webhookData'],
+  workflowData: PollWebhookContext['workflowData'],
   config: OutlookWebhookConfig,
   accessToken: string,
-  requestId: string
+  requestId: string,
+  logger: ReturnType
 ) {
   let processedCount = 0
   let failedCount = 0
@@ -568,7 +358,12 @@ async function processOutlookEmails(
           let attachments: OutlookAttachment[] = []
           if (config.includeAttachments && email.hasAttachments) {
             try {
-              attachments = await downloadOutlookAttachments(accessToken, email.id, requestId)
+              attachments = await downloadOutlookAttachments(
+                accessToken,
+                email.id,
+                requestId,
+                logger
+              )
             } catch (error) {
               logger.error(
                 `[${requestId}] Error downloading attachments for email ${email.id}:`,
@@ -588,12 +383,8 @@ async function processOutlookEmails(
             bodyText: (() => {
               const content = email.body?.content || ''
               const type = (email.body?.contentType || '').toLowerCase()
-              if (!content) {
-                return email.bodyPreview || ''
-              }
-              if (type === 'text' || type === 'text/plain') {
-                return content
-              }
+              if (!content) return email.bodyPreview || ''
+              if (type === 'text' || type === 'text/plain') return content
               return convertHtmlToPlainText(content)
             })(),
             bodyHtml: email.body?.content || '',
@@ -618,36 +409,27 @@ async function processOutlookEmails(
             `[${requestId}] Processing email: ${email.subject} from ${email.from?.emailAddress?.address}`
           )
 
-          const webhookUrl = `${getInternalApiBaseUrl()}/api/webhooks/trigger/${webhookData.path}`
-
-          const response = await fetch(webhookUrl, {
-            method: 'POST',
-            headers: {
-              'Content-Type': 'application/json',
-              'User-Agent': 'Sim/1.0',
-            },
-            body: JSON.stringify(payload),
-          })
+          const result = await processPolledWebhookEvent(
+            webhookData,
+            workflowData,
+            payload,
+            requestId
+          )
 
-          if (!response.ok) {
-            const errorText = await response.text()
+          if (!result.success) {
             logger.error(
-              `[${requestId}] Failed to trigger webhook for email ${email.id}:`,
-              response.status,
-              errorText
+              `[${requestId}] Failed to process webhook for email ${email.id}:`,
+              result.statusCode,
+              result.error
             )
-            throw new Error(`Webhook request failed: ${response.status} - ${errorText}`)
+            throw new Error(`Webhook processing failed (${result.statusCode}): ${result.error}`)
           }
 
           if (config.markAsRead) {
-            await markOutlookEmailAsRead(accessToken, email.id)
+            await markOutlookEmailAsRead(accessToken, email.id, logger)
           }
 
-          return {
-            emailId: email.id,
-            webhookStatus: response.status,
-            processed: true,
-          }
+          return { emailId: email.id, processed: true }
         }
       )
 
@@ -667,7 +449,8 @@ async function processOutlookEmails(
 async function downloadOutlookAttachments(
   accessToken: string,
   messageId: string,
-  requestId: string
+  requestId: string,
+  logger: ReturnType
 ): Promise {
   const attachments: OutlookAttachment[] = []
 
@@ -722,7 +505,11 @@ async function downloadOutlookAttachments(
   return attachments
 }
 
-async function markOutlookEmailAsRead(accessToken: string, messageId: string) {
+async function markOutlookEmailAsRead(
+  accessToken: string,
+  messageId: string,
+  logger: ReturnType
+) {
   try {
     const response = await fetch(`https://graph.microsoft.com/v1.0/me/messages/${messageId}`, {
       method: 'PATCH',
@@ -730,9 +517,7 @@ async function markOutlookEmailAsRead(accessToken: string, messageId: string) {
         Authorization: `Bearer ${accessToken}`,
         'Content-Type': 'application/json',
       },
-      body: JSON.stringify({
-        isRead: true,
-      }),
+      body: JSON.stringify({ isRead: true }),
     })
 
     if (!response.ok) {
@@ -746,34 +531,3 @@ async function markOutlookEmailAsRead(accessToken: string, messageId: string) {
     logger.error(`Error marking email ${messageId} as read:`, error)
   }
 }
-
-async function updateWebhookLastChecked(webhookId: string, timestamp: string) {
-  try {
-    const currentWebhook = await db
-      .select({ providerConfig: webhook.providerConfig })
-      .from(webhook)
-      .where(eq(webhook.id, webhookId))
-      .limit(1)
-
-    if (!currentWebhook.length) {
-      logger.error(`Webhook ${webhookId} not found`)
-      return
-    }
-
-    const currentConfig = (currentWebhook[0].providerConfig as any) || {}
-    const updatedConfig = {
-      ...currentConfig,
-      lastCheckedTimestamp: timestamp,
-    }
-
-    await db
-      .update(webhook)
-      .set({
-        providerConfig: updatedConfig,
-        updatedAt: new Date(),
-      })
-      .where(eq(webhook.id, webhookId))
-  } catch (error) {
-    logger.error(`Error updating webhook ${webhookId} last checked timestamp:`, error)
-  }
-}
diff --git a/apps/sim/lib/webhooks/polling/registry.ts b/apps/sim/lib/webhooks/polling/registry.ts
new file mode 100644
index 00000000000..fe2db69ed4f
--- /dev/null
+++ b/apps/sim/lib/webhooks/polling/registry.ts
@@ -0,0 +1,19 @@
+import { gmailPollingHandler } from '@/lib/webhooks/polling/gmail'
+import { imapPollingHandler } from '@/lib/webhooks/polling/imap'
+import { outlookPollingHandler } from '@/lib/webhooks/polling/outlook'
+import { rssPollingHandler } from '@/lib/webhooks/polling/rss'
+import type { PollingProviderHandler } from '@/lib/webhooks/polling/types'
+
+const POLLING_HANDLERS: Record = {
+  gmail: gmailPollingHandler,
+  imap: imapPollingHandler,
+  outlook: outlookPollingHandler,
+  rss: rssPollingHandler,
+}
+
+export const VALID_POLLING_PROVIDERS = new Set(Object.keys(POLLING_HANDLERS))
+
+/** Look up the polling handler for a provider. */
+export function getPollingHandler(provider: string): PollingProviderHandler | undefined {
+  return POLLING_HANDLERS[provider]
+}
diff --git a/apps/sim/lib/webhooks/polling/rss.ts b/apps/sim/lib/webhooks/polling/rss.ts
new file mode 100644
index 00000000000..31044fc8924
--- /dev/null
+++ b/apps/sim/lib/webhooks/polling/rss.ts
@@ -0,0 +1,307 @@
+import Parser from 'rss-parser'
+import { pollingIdempotency } from '@/lib/core/idempotency/service'
+import {
+  secureFetchWithPinnedIP,
+  validateUrlWithDNS,
+} from '@/lib/core/security/input-validation.server'
+import type { PollingProviderHandler, PollWebhookContext } from '@/lib/webhooks/polling/types'
+import {
+  markWebhookFailed,
+  markWebhookSuccess,
+  updateWebhookProviderConfig,
+} from '@/lib/webhooks/polling/utils'
+import { processPolledWebhookEvent } from '@/lib/webhooks/processor'
+
+const MAX_GUIDS_TO_TRACK = 100
+
+interface RssWebhookConfig {
+  feedUrl: string
+  lastCheckedTimestamp?: string
+  lastSeenGuids?: string[]
+  etag?: string
+  lastModified?: string
+}
+
+interface RssItem {
+  title?: string
+  link?: string
+  pubDate?: string
+  guid?: string
+  description?: string
+  content?: string
+  contentSnippet?: string
+  author?: string
+  creator?: string
+  categories?: string[]
+  enclosure?: {
+    url: string
+    type?: string
+    length?: string | number
+  }
+  isoDate?: string
+  [key: string]: unknown
+}
+
+interface RssFeed {
+  title?: string
+  link?: string
+  description?: string
+  items: RssItem[]
+}
+
+export interface RssWebhookPayload {
+  title?: string
+  link?: string
+  pubDate?: string
+  item: RssItem
+  feed: {
+    title?: string
+    link?: string
+    description?: string
+  }
+  timestamp: string
+}
+
+const parser = new Parser({
+  timeout: 30000,
+  headers: {
+    'User-Agent': 'Sim/1.0 RSS Poller',
+  },
+})
+
+export const rssPollingHandler: PollingProviderHandler = {
+  provider: 'rss',
+  label: 'RSS',
+
+  async pollWebhook(ctx: PollWebhookContext): Promise<'success' | 'failure'> {
+    const { webhookData, workflowData, requestId, logger } = ctx
+    const webhookId = webhookData.id
+
+    try {
+      const config = webhookData.providerConfig as unknown as RssWebhookConfig
+
+      if (!config?.feedUrl) {
+        logger.error(`[${requestId}] Missing feedUrl for webhook ${webhookId}`)
+        await markWebhookFailed(webhookId, logger)
+        return 'failure'
+      }
+
+      const now = new Date()
+      const { feed, items: newItems } = await fetchNewRssItems(config, requestId, logger)
+
+      if (!newItems.length) {
+        await updateRssState(webhookId, now.toISOString(), [], config, logger)
+        await markWebhookSuccess(webhookId, logger)
+        logger.info(`[${requestId}] No new items found for webhook ${webhookId}`)
+        return 'success'
+      }
+
+      logger.info(`[${requestId}] Found ${newItems.length} new items for webhook ${webhookId}`)
+
+      const { processedCount, failedCount } = await processRssItems(
+        newItems,
+        feed,
+        webhookData,
+        workflowData,
+        requestId,
+        logger
+      )
+
+      const newGuids = newItems
+        .map((item) => item.guid || item.link || '')
+        .filter((guid) => guid.length > 0)
+
+      await updateRssState(webhookId, now.toISOString(), newGuids, config, logger)
+
+      if (failedCount > 0 && processedCount === 0) {
+        await markWebhookFailed(webhookId, logger)
+        logger.warn(
+          `[${requestId}] All ${failedCount} items failed to process for webhook ${webhookId}`
+        )
+        return 'failure'
+      }
+
+      await markWebhookSuccess(webhookId, logger)
+      logger.info(
+        `[${requestId}] Successfully processed ${processedCount} items for webhook ${webhookId}${failedCount > 0 ? ` (${failedCount} failed)` : ''}`
+      )
+      return 'success'
+    } catch (error) {
+      logger.error(`[${requestId}] Error processing RSS webhook ${webhookId}:`, error)
+      await markWebhookFailed(webhookId, logger)
+      return 'failure'
+    }
+  },
+}
+
+async function updateRssState(
+  webhookId: string,
+  timestamp: string,
+  newGuids: string[],
+  config: RssWebhookConfig,
+  logger: ReturnType
+) {
+  const existingGuids = config.lastSeenGuids || []
+  const allGuids = [...newGuids, ...existingGuids].slice(0, MAX_GUIDS_TO_TRACK)
+
+  await updateWebhookProviderConfig(
+    webhookId,
+    {
+      lastCheckedTimestamp: timestamp,
+      lastSeenGuids: allGuids,
+    },
+    logger
+  )
+}
+
+async function fetchNewRssItems(
+  config: RssWebhookConfig,
+  requestId: string,
+  logger: ReturnType
+): Promise<{ feed: RssFeed; items: RssItem[] }> {
+  try {
+    const urlValidation = await validateUrlWithDNS(config.feedUrl, 'feedUrl')
+    if (!urlValidation.isValid) {
+      logger.error(`[${requestId}] Invalid RSS feed URL: ${urlValidation.error}`)
+      throw new Error(`Invalid RSS feed URL: ${urlValidation.error}`)
+    }
+
+    const response = await secureFetchWithPinnedIP(config.feedUrl, urlValidation.resolvedIP!, {
+      headers: {
+        'User-Agent': 'Sim/1.0 RSS Poller',
+        Accept: 'application/rss+xml, application/xml, text/xml, */*',
+      },
+      timeout: 30000,
+    })
+
+    if (!response.ok) {
+      await response.text().catch(() => {})
+      throw new Error(`Failed to fetch RSS feed: ${response.status} ${response.statusText}`)
+    }
+
+    const xmlContent = await response.text()
+    const feed = await parser.parseString(xmlContent)
+
+    if (!feed.items || !feed.items.length) {
+      return { feed: feed as RssFeed, items: [] }
+    }
+
+    const lastCheckedTime = config.lastCheckedTimestamp
+      ? new Date(config.lastCheckedTimestamp)
+      : null
+    const lastSeenGuids = new Set(config.lastSeenGuids || [])
+
+    const newItems = feed.items.filter((item) => {
+      const itemGuid = item.guid || item.link || ''
+
+      if (itemGuid && lastSeenGuids.has(itemGuid)) {
+        return false
+      }
+
+      if (lastCheckedTime && item.isoDate) {
+        const itemDate = new Date(item.isoDate)
+        if (itemDate <= lastCheckedTime) {
+          return false
+        }
+      }
+
+      return true
+    })
+
+    newItems.sort((a, b) => {
+      const dateA = a.isoDate ? new Date(a.isoDate).getTime() : 0
+      const dateB = b.isoDate ? new Date(b.isoDate).getTime() : 0
+      return dateB - dateA
+    })
+
+    const limitedItems = newItems.slice(0, 25)
+
+    logger.info(
+      `[${requestId}] Found ${newItems.length} new items (processing ${limitedItems.length})`
+    )
+
+    return { feed: feed as RssFeed, items: limitedItems as RssItem[] }
+  } catch (error) {
+    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
+    logger.error(`[${requestId}] Error fetching RSS feed:`, errorMessage)
+    throw error
+  }
+}
+
+async function processRssItems(
+  items: RssItem[],
+  feed: RssFeed,
+  webhookData: PollWebhookContext['webhookData'],
+  workflowData: PollWebhookContext['workflowData'],
+  requestId: string,
+  logger: ReturnType
+): Promise<{ processedCount: number; failedCount: number }> {
+  let processedCount = 0
+  let failedCount = 0
+
+  for (const item of items) {
+    try {
+      const itemGuid = item.guid || item.link || `${item.title}-${item.pubDate}`
+
+      await pollingIdempotency.executeWithIdempotency(
+        'rss',
+        `${webhookData.id}:${itemGuid}`,
+        async () => {
+          const payload: RssWebhookPayload = {
+            title: item.title,
+            link: item.link,
+            pubDate: item.pubDate,
+            item: {
+              title: item.title,
+              link: item.link,
+              pubDate: item.pubDate,
+              guid: item.guid,
+              description: item.description,
+              content: item.content,
+              contentSnippet: item.contentSnippet,
+              author: item.author || item.creator,
+              categories: item.categories,
+              enclosure: item.enclosure,
+              isoDate: item.isoDate,
+            },
+            feed: {
+              title: feed.title,
+              link: feed.link,
+              description: feed.description,
+            },
+            timestamp: new Date().toISOString(),
+          }
+
+          const result = await processPolledWebhookEvent(
+            webhookData,
+            workflowData,
+            payload,
+            requestId
+          )
+
+          if (!result.success) {
+            logger.error(
+              `[${requestId}] Failed to process webhook for item ${itemGuid}:`,
+              result.statusCode,
+              result.error
+            )
+            throw new Error(`Webhook processing failed (${result.statusCode}): ${result.error}`)
+          }
+
+          return { itemGuid, processed: true }
+        }
+      )
+
+      logger.info(
+        `[${requestId}] Successfully processed item ${item.title || itemGuid} for webhook ${webhookData.id}`
+      )
+      processedCount++
+    } catch (error) {
+      const errorMessage = error instanceof Error ? error.message : 'Unknown error'
+      logger.error(`[${requestId}] Error processing item:`, errorMessage)
+      failedCount++
+    }
+  }
+
+  return { processedCount, failedCount }
+}
diff --git a/apps/sim/lib/webhooks/polling/types.ts b/apps/sim/lib/webhooks/polling/types.ts
new file mode 100644
index 00000000000..a69b0427f25
--- /dev/null
+++ b/apps/sim/lib/webhooks/polling/types.ts
@@ -0,0 +1,58 @@
+import type { Logger } from '@sim/logger'
+
+/** Summary returned after polling all webhooks for a provider. */
+export interface PollSummary {
+  total: number
+  successful: number
+  failed: number
+}
+
+/** Context passed to a provider handler when processing one webhook. */
+export interface PollWebhookContext {
+  webhookData: WebhookRecord
+  workflowData: WorkflowRecord
+  requestId: string
+  logger: Logger
+}
+
+/** DB row shape for the webhook table. */
+export interface WebhookRecord {
+  id: string
+  path: string
+  provider: string | null
+  blockId: string | null
+  providerConfig: unknown
+  credentialSetId: string | null
+  workflowId: string
+  [key: string]: unknown
+}
+
+/** DB row shape for the workflow table. */
+export interface WorkflowRecord {
+  id: string
+  userId: string
+  workspaceId: string
+  [key: string]: unknown
+}
+
+/**
+ * Strategy interface for provider-specific polling behavior.
+ * Mirrors `WebhookProviderHandler` from `providers/types.ts`.
+ *
+ * Each provider implements `pollWebhook()` — the full inner loop for one webhook:
+ * validate config, resolve credentials, fetch new items, process each via
+ * `processPolledWebhookEvent()` (wrapped in `pollingIdempotency`), update state.
+ */
+export interface PollingProviderHandler {
+  /** Provider name used in DB queries (e.g. 'gmail', 'rss'). */
+  readonly provider: string
+
+  /** Display label for log messages (e.g. 'Gmail', 'RSS'). */
+  readonly label: string
+
+  /**
+   * Process a single webhook entry.
+   * Return 'success' (even if 0 new items) or 'failure'.
+   */
+  pollWebhook(ctx: PollWebhookContext): Promise<'success' | 'failure'>
+}
diff --git a/apps/sim/lib/webhooks/polling/utils.ts b/apps/sim/lib/webhooks/polling/utils.ts
new file mode 100644
index 00000000000..cca46585258
--- /dev/null
+++ b/apps/sim/lib/webhooks/polling/utils.ts
@@ -0,0 +1,242 @@
+import { db } from '@sim/db'
+import {
+  account,
+  credentialSet,
+  webhook,
+  workflow,
+  workflowDeploymentVersion,
+} from '@sim/db/schema'
+import type { Logger } from '@sim/logger'
+import { and, eq, isNull, or, sql } from 'drizzle-orm'
+import { isOrganizationOnTeamOrEnterprisePlan } from '@/lib/billing'
+import type { WebhookRecord, WorkflowRecord } from '@/lib/webhooks/polling/types'
+import {
+  getOAuthToken,
+  refreshAccessTokenIfNeeded,
+  resolveOAuthAccountId,
+} from '@/app/api/auth/oauth/utils'
+import { MAX_CONSECUTIVE_FAILURES } from '@/triggers/constants'
+
+/** Concurrency limit for parallel webhook processing. Standardized across all providers. */
+export const CONCURRENCY = 10
+
+/** Increment the webhook's failure count. Auto-disables after MAX_CONSECUTIVE_FAILURES. */
+export async function markWebhookFailed(webhookId: string, logger: Logger): Promise {
+  try {
+    const result = await db
+      .update(webhook)
+      .set({
+        failedCount: sql`COALESCE(${webhook.failedCount}, 0) + 1`,
+        lastFailedAt: new Date(),
+        updatedAt: new Date(),
+      })
+      .where(eq(webhook.id, webhookId))
+      .returning({ failedCount: webhook.failedCount })
+
+    const newFailedCount = result[0]?.failedCount || 0
+    if (newFailedCount >= MAX_CONSECUTIVE_FAILURES) {
+      await db
+        .update(webhook)
+        .set({
+          isActive: false,
+          updatedAt: new Date(),
+        })
+        .where(eq(webhook.id, webhookId))
+
+      logger.warn(
+        `Webhook ${webhookId} auto-disabled after ${MAX_CONSECUTIVE_FAILURES} consecutive failures`
+      )
+    }
+  } catch (err) {
+    logger.error(`Failed to mark webhook ${webhookId} as failed:`, err)
+  }
+}
+
+/** Reset the webhook's failure count on successful poll. */
+export async function markWebhookSuccess(webhookId: string, logger: Logger): Promise {
+  try {
+    await db
+      .update(webhook)
+      .set({
+        failedCount: 0,
+        updatedAt: new Date(),
+      })
+      .where(eq(webhook.id, webhookId))
+  } catch (err) {
+    logger.error(`Failed to mark webhook ${webhookId} as successful:`, err)
+  }
+}
+
+/** Fetch all active webhooks for a provider, joined with their workflow. */
+export async function fetchActiveWebhooks(
+  provider: string
+): Promise<{ webhook: WebhookRecord; workflow: WorkflowRecord }[]> {
+  const rows = await db
+    .select({ webhook, workflow })
+    .from(webhook)
+    .innerJoin(workflow, eq(webhook.workflowId, workflow.id))
+    .leftJoin(
+      workflowDeploymentVersion,
+      and(
+        eq(workflowDeploymentVersion.workflowId, workflow.id),
+        eq(workflowDeploymentVersion.isActive, true)
+      )
+    )
+    .where(
+      and(
+        eq(webhook.provider, provider),
+        eq(webhook.isActive, true),
+        isNull(webhook.archivedAt),
+        eq(workflow.isDeployed, true),
+        isNull(workflow.archivedAt),
+        or(
+          eq(webhook.deploymentVersionId, workflowDeploymentVersion.id),
+          and(isNull(workflowDeploymentVersion.id), isNull(webhook.deploymentVersionId))
+        )
+      )
+    )
+
+  return rows as unknown as { webhook: WebhookRecord; workflow: WorkflowRecord }[]
+}
+
+/**
+ * Run an async function over entries with bounded concurrency.
+ * Returns aggregate success/failure counts.
+ */
+export async function runWithConcurrency(
+  entries: { webhook: WebhookRecord; workflow: WorkflowRecord }[],
+  processFn: (entry: {
+    webhook: WebhookRecord
+    workflow: WorkflowRecord
+  }) => Promise<'success' | 'failure'>,
+  logger: Logger
+): Promise<{ successCount: number; failureCount: number }> {
+  const running: Promise[] = []
+  let successCount = 0
+  let failureCount = 0
+
+  for (const entry of entries) {
+    const promise: Promise = processFn(entry)
+      .then((result) => {
+        if (result === 'success') {
+          successCount++
+        } else {
+          failureCount++
+        }
+      })
+      .catch((err) => {
+        logger.error('Unexpected error in webhook processing:', err)
+        failureCount++
+      })
+      .finally(() => {
+        const idx = running.indexOf(promise)
+        if (idx !== -1) running.splice(idx, 1)
+      })
+
+    running.push(promise)
+
+    if (running.length >= CONCURRENCY) {
+      await Promise.race(running)
+    }
+  }
+
+  await Promise.allSettled(running)
+
+  return { successCount, failureCount }
+}
+
+/**
+ * Read-merge-write pattern for updating provider-specific config fields.
+ * Each provider passes its specific state updates (historyId, lastSeenGuids, etc.).
+ */
+export async function updateWebhookProviderConfig(
+  webhookId: string,
+  configUpdates: Record,
+  logger: Logger
+): Promise {
+  try {
+    const result = await db.select().from(webhook).where(eq(webhook.id, webhookId))
+    const existingConfig = (result[0]?.providerConfig as Record) || {}
+
+    await db
+      .update(webhook)
+      .set({
+        providerConfig: {
+          ...existingConfig,
+          ...configUpdates,
+        } as Record,
+        updatedAt: new Date(),
+      })
+      .where(eq(webhook.id, webhookId))
+  } catch (err) {
+    logger.error(`Failed to update webhook ${webhookId} config:`, err)
+  }
+}
+
+/**
+ * Resolve OAuth credentials for a webhook. Shared by Gmail and Outlook.
+ * Returns the access token or throws on failure.
+ */
+export async function resolveOAuthCredential(
+  webhookData: WebhookRecord,
+  oauthProvider: string,
+  requestId: string,
+  logger: Logger
+): Promise {
+  const metadata = webhookData.providerConfig as Record | null
+  const credentialId = metadata?.credentialId as string | undefined
+  const userId = metadata?.userId as string | undefined
+  const credentialSetId = (webhookData.credentialSetId as string | undefined) ?? undefined
+
+  if (!credentialId && !userId) {
+    throw new Error(`Missing credential info for webhook ${webhookData.id}`)
+  }
+
+  if (credentialSetId) {
+    const [cs] = await db
+      .select({ organizationId: credentialSet.organizationId })
+      .from(credentialSet)
+      .where(eq(credentialSet.id, credentialSetId))
+      .limit(1)
+
+    if (cs?.organizationId) {
+      const hasAccess = await isOrganizationOnTeamOrEnterprisePlan(cs.organizationId)
+      if (!hasAccess) {
+        logger.error(
+          `[${requestId}] Polling Group plan restriction: Your current plan does not support Polling Groups. Upgrade to Team or Enterprise to use this feature.`,
+          {
+            webhookId: webhookData.id,
+            credentialSetId,
+            organizationId: cs.organizationId,
+          }
+        )
+        throw new Error('Polling Group plan restriction')
+      }
+    }
+  }
+
+  let accessToken: string | null = null
+
+  if (credentialId) {
+    const resolved = await resolveOAuthAccountId(credentialId)
+    if (!resolved) {
+      throw new Error(
+        `Failed to resolve OAuth account for credential ${credentialId}, webhook ${webhookData.id}`
+      )
+    }
+    const rows = await db.select().from(account).where(eq(account.id, resolved.accountId)).limit(1)
+    if (!rows.length) {
+      throw new Error(`Credential ${credentialId} not found for webhook ${webhookData.id}`)
+    }
+    const ownerUserId = rows[0].userId
+    accessToken = await refreshAccessTokenIfNeeded(resolved.accountId, ownerUserId, requestId)
+  } else if (userId) {
+    accessToken = await getOAuthToken(userId, oauthProvider)
+  }
+
+  if (!accessToken) {
+    throw new Error(`Failed to get ${oauthProvider} access token for webhook ${webhookData.id}`)
+  }
+
+  return accessToken
+}
diff --git a/apps/sim/lib/webhooks/processor.ts b/apps/sim/lib/webhooks/processor.ts
index eb1503c0029..d75f539ee38 100644
--- a/apps/sim/lib/webhooks/processor.ts
+++ b/apps/sim/lib/webhooks/processor.ts
@@ -4,12 +4,13 @@ import { createLogger } from '@sim/logger'
 import { and, eq, isNull, or } from 'drizzle-orm'
 import { type NextRequest, NextResponse } from 'next/server'
 import { isOrganizationOnTeamOrEnterprisePlan } from '@/lib/billing/core/subscription'
+import { tryAdmit } from '@/lib/core/admission/gate'
 import { getInlineJobQueue, getJobQueue, shouldExecuteInline } from '@/lib/core/async-jobs'
 import type { AsyncExecutionCorrelation } from '@/lib/core/async-jobs/types'
 import { createBullMQJobData, isBullMQEnabled } from '@/lib/core/bullmq'
 import { isProd } from '@/lib/core/config/feature-flags'
 import { generateId } from '@/lib/core/utils/uuid'
-import { enqueueWorkspaceDispatch } from '@/lib/core/workspace-dispatch'
+import { DispatchQueueFullError, enqueueWorkspaceDispatch } from '@/lib/core/workspace-dispatch'
 import { getEffectiveDecryptedEnv } from '@/lib/environment/utils'
 import { preprocessExecution } from '@/lib/execution/preprocessing'
 import {
@@ -18,6 +19,7 @@ import {
   requiresPendingWebhookVerification,
 } from '@/lib/webhooks/pending-verification'
 import { getProviderHandler } from '@/lib/webhooks/providers'
+import { blockExistsInDeployment } from '@/lib/workflows/persistence/utils'
 import { executeWebhookJob } from '@/background/webhook-execution'
 import { resolveEnvVarReferences } from '@/executor/utils/reference-validation'
 import { isPollingWebhookProvider } from '@/triggers/constants'
@@ -672,3 +674,215 @@ export async function queueWebhookExecution(
     return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
   }
 }
+
+export interface PolledWebhookEventResult {
+  success: boolean
+  error?: string
+  statusCode?: number
+}
+
+interface PolledWebhookRecord {
+  id: string
+  path: string
+  provider: string | null
+  blockId: string | null
+  providerConfig: unknown
+  credentialSetId: string | null
+  workflowId: string
+}
+
+interface PolledWorkflowRecord {
+  id: string
+  userId: string
+  workspaceId: string
+}
+
+/**
+ * Processes a polled webhook event directly, bypassing the HTTP trigger route.
+ * Used by polling services (Gmail, Outlook, IMAP, RSS) to avoid the self-POST
+ * anti-pattern where they would otherwise POST back to /api/webhooks/trigger/{path}.
+ *
+ * Performs only the steps actually needed for polling providers:
+ * admission control, preprocessing, block existence check, and queue execution.
+ */
+export async function processPolledWebhookEvent(
+  foundWebhook: PolledWebhookRecord,
+  foundWorkflow: PolledWorkflowRecord,
+  body: Record | object,
+  requestId: string
+): Promise {
+  if (!foundWebhook.provider) {
+    return { success: false, error: 'Webhook has no provider', statusCode: 400 }
+  }
+  const provider = foundWebhook.provider
+
+  const ticket = tryAdmit()
+  if (!ticket) {
+    logger.warn(`[${requestId}] Admission gate rejected polled webhook event`)
+    return { success: false, error: 'Server at capacity', statusCode: 429 }
+  }
+
+  try {
+    const preprocessResult = await checkWebhookPreprocessing(foundWorkflow, foundWebhook, requestId)
+    if (preprocessResult.error) {
+      return { success: false, error: 'Preprocessing failed', statusCode: 500 }
+    }
+
+    if (foundWebhook.blockId) {
+      const blockExists = await blockExistsInDeployment(foundWorkflow.id, foundWebhook.blockId)
+      if (!blockExists) {
+        logger.info(
+          `[${requestId}] Trigger block ${foundWebhook.blockId} not found in deployment for workflow ${foundWorkflow.id}`
+        )
+        return { success: false, error: 'Trigger block not found in deployment', statusCode: 404 }
+      }
+    }
+
+    const providerConfig = (foundWebhook.providerConfig as Record) || {}
+    const credentialId = providerConfig.credentialId as string | undefined
+    const credentialSetId = foundWebhook.credentialSetId as string | undefined
+
+    if (credentialSetId) {
+      const billingCheck = await verifyCredentialSetBilling(credentialSetId)
+      if (!billingCheck.valid) {
+        logger.warn(`[${requestId}] Credential set billing check failed: ${billingCheck.error}`)
+        return { success: false, error: billingCheck.error, statusCode: 403 }
+      }
+    }
+
+    const actorUserId = preprocessResult.actorUserId
+    if (!actorUserId) {
+      logger.error(`[${requestId}] No actorUserId provided for webhook ${foundWebhook.id}`)
+      return { success: false, error: 'Unable to resolve billing account', statusCode: 500 }
+    }
+
+    const executionId = preprocessResult.executionId ?? generateId()
+    const correlation =
+      preprocessResult.correlation ??
+      ({
+        executionId,
+        requestId,
+        source: 'webhook' as const,
+        workflowId: foundWorkflow.id,
+        webhookId: foundWebhook.id,
+        path: foundWebhook.path,
+        provider,
+        triggerType: 'webhook',
+      } satisfies AsyncExecutionCorrelation)
+
+    const payload = {
+      webhookId: foundWebhook.id,
+      workflowId: foundWorkflow.id,
+      userId: actorUserId,
+      executionId,
+      requestId,
+      correlation,
+      provider,
+      body,
+      headers: { 'content-type': 'application/json' } as Record,
+      path: foundWebhook.path,
+      blockId: foundWebhook.blockId ?? undefined,
+      workspaceId: foundWorkflow.workspaceId,
+      ...(credentialId ? { credentialId } : {}),
+    }
+
+    if (isPollingWebhookProvider(payload.provider) && !shouldExecuteInline()) {
+      const jobId = isBullMQEnabled()
+        ? await enqueueWorkspaceDispatch({
+            id: executionId,
+            workspaceId: foundWorkflow.workspaceId,
+            lane: 'runtime',
+            queueName: 'webhook-execution',
+            bullmqJobName: 'webhook-execution',
+            bullmqPayload: createBullMQJobData(payload, {
+              workflowId: foundWorkflow.id,
+              userId: actorUserId,
+              correlation,
+            }),
+            metadata: {
+              workflowId: foundWorkflow.id,
+              userId: actorUserId,
+              correlation,
+            },
+          })
+        : await (await getJobQueue()).enqueue('webhook-execution', payload, {
+            metadata: {
+              workflowId: foundWorkflow.id,
+              workspaceId: foundWorkflow.workspaceId,
+              userId: actorUserId,
+              correlation,
+            },
+          })
+      logger.info(
+        `[${requestId}] Queued polling webhook execution task ${jobId} for ${provider} webhook via job queue`
+      )
+    } else {
+      const jobQueue = await getInlineJobQueue()
+      const jobId = isBullMQEnabled()
+        ? await enqueueWorkspaceDispatch({
+            id: executionId,
+            workspaceId: foundWorkflow.workspaceId,
+            lane: 'runtime',
+            queueName: 'webhook-execution',
+            bullmqJobName: 'webhook-execution',
+            bullmqPayload: createBullMQJobData(payload, {
+              workflowId: foundWorkflow.id,
+              userId: actorUserId,
+              correlation,
+            }),
+            metadata: {
+              workflowId: foundWorkflow.id,
+              userId: actorUserId,
+              correlation,
+            },
+          })
+        : await jobQueue.enqueue('webhook-execution', payload, {
+            metadata: {
+              workflowId: foundWorkflow.id,
+              workspaceId: foundWorkflow.workspaceId,
+              userId: actorUserId,
+              correlation,
+            },
+          })
+      logger.info(`[${requestId}] Queued ${provider} webhook execution ${jobId} via inline backend`)
+
+      if (!isBullMQEnabled()) {
+        void (async () => {
+          try {
+            await jobQueue.startJob(jobId)
+            const output = await executeWebhookJob(payload)
+            await jobQueue.completeJob(jobId, output)
+          } catch (error) {
+            const errorMessage = error instanceof Error ? error.message : String(error)
+            logger.error(`[${requestId}] Webhook execution failed`, {
+              jobId,
+              error: errorMessage,
+            })
+            try {
+              await jobQueue.markJobFailed(jobId, errorMessage)
+            } catch (markFailedError) {
+              logger.error(`[${requestId}] Failed to mark job as failed`, {
+                jobId,
+                error:
+                  markFailedError instanceof Error
+                    ? markFailedError.message
+                    : String(markFailedError),
+              })
+            }
+          }
+        })()
+      }
+    }
+
+    return { success: true }
+  } catch (error: unknown) {
+    if (error instanceof DispatchQueueFullError) {
+      logger.warn(`[${requestId}] Dispatch queue full for polled webhook: ${error.message}`)
+      return { success: false, error: 'Service temporarily at capacity', statusCode: 503 }
+    }
+    logger.error(`[${requestId}] Failed to process polled webhook event:`, error)
+    return { success: false, error: 'Internal server error', statusCode: 500 }
+  } finally {
+    ticket.release()
+  }
+}
diff --git a/apps/sim/lib/webhooks/rss-polling-service.ts b/apps/sim/lib/webhooks/rss-polling-service.ts
deleted file mode 100644
index e6727a2f7ca..00000000000
--- a/apps/sim/lib/webhooks/rss-polling-service.ts
+++ /dev/null
@@ -1,442 +0,0 @@
-import { db } from '@sim/db'
-import { webhook, workflow, workflowDeploymentVersion } from '@sim/db/schema'
-import { createLogger } from '@sim/logger'
-import { and, eq, isNull, or, sql } from 'drizzle-orm'
-import Parser from 'rss-parser'
-import { pollingIdempotency } from '@/lib/core/idempotency/service'
-import {
-  secureFetchWithPinnedIP,
-  validateUrlWithDNS,
-} from '@/lib/core/security/input-validation.server'
-import { getInternalApiBaseUrl } from '@/lib/core/utils/urls'
-import { generateShortId } from '@/lib/core/utils/uuid'
-import { MAX_CONSECUTIVE_FAILURES } from '@/triggers/constants'
-
-const logger = createLogger('RssPollingService')
-const MAX_GUIDS_TO_TRACK = 100 // Track recent guids to prevent duplicates
-
-interface RssWebhookConfig {
-  feedUrl: string
-  lastCheckedTimestamp?: string
-  lastSeenGuids?: string[]
-  etag?: string
-  lastModified?: string
-}
-
-interface RssItem {
-  title?: string
-  link?: string
-  pubDate?: string
-  guid?: string
-  description?: string
-  content?: string
-  contentSnippet?: string
-  author?: string
-  creator?: string
-  categories?: string[]
-  enclosure?: {
-    url: string
-    type?: string
-    length?: string | number
-  }
-  isoDate?: string
-  [key: string]: any
-}
-
-interface RssFeed {
-  title?: string
-  link?: string
-  description?: string
-  items: RssItem[]
-}
-
-export interface RssWebhookPayload {
-  title?: string
-  link?: string
-  pubDate?: string
-  item: RssItem
-  feed: {
-    title?: string
-    link?: string
-    description?: string
-  }
-  timestamp: string
-}
-
-const parser = new Parser({
-  timeout: 30000,
-  headers: {
-    'User-Agent': 'Sim/1.0 RSS Poller',
-  },
-})
-
-async function markWebhookFailed(webhookId: string) {
-  try {
-    const result = await db
-      .update(webhook)
-      .set({
-        failedCount: sql`COALESCE(${webhook.failedCount}, 0) + 1`,
-        lastFailedAt: new Date(),
-        updatedAt: new Date(),
-      })
-      .where(eq(webhook.id, webhookId))
-      .returning({ failedCount: webhook.failedCount })
-
-    const newFailedCount = result[0]?.failedCount || 0
-    const shouldDisable = newFailedCount >= MAX_CONSECUTIVE_FAILURES
-
-    if (shouldDisable) {
-      await db
-        .update(webhook)
-        .set({
-          isActive: false,
-          updatedAt: new Date(),
-        })
-        .where(eq(webhook.id, webhookId))
-
-      logger.warn(
-        `Webhook ${webhookId} auto-disabled after ${MAX_CONSECUTIVE_FAILURES} consecutive failures`
-      )
-    }
-  } catch (err) {
-    logger.error(`Failed to mark webhook ${webhookId} as failed:`, err)
-  }
-}
-
-async function markWebhookSuccess(webhookId: string) {
-  try {
-    await db
-      .update(webhook)
-      .set({
-        failedCount: 0,
-        updatedAt: new Date(),
-      })
-      .where(eq(webhook.id, webhookId))
-  } catch (err) {
-    logger.error(`Failed to mark webhook ${webhookId} as successful:`, err)
-  }
-}
-
-export async function pollRssWebhooks() {
-  logger.info('Starting RSS webhook polling')
-
-  try {
-    const activeWebhooksResult = await db
-      .select({ webhook })
-      .from(webhook)
-      .innerJoin(workflow, eq(webhook.workflowId, workflow.id))
-      .leftJoin(
-        workflowDeploymentVersion,
-        and(
-          eq(workflowDeploymentVersion.workflowId, workflow.id),
-          eq(workflowDeploymentVersion.isActive, true)
-        )
-      )
-      .where(
-        and(
-          eq(webhook.provider, 'rss'),
-          eq(webhook.isActive, true),
-          eq(workflow.isDeployed, true),
-          or(
-            eq(webhook.deploymentVersionId, workflowDeploymentVersion.id),
-            and(isNull(workflowDeploymentVersion.id), isNull(webhook.deploymentVersionId))
-          )
-        )
-      )
-
-    const activeWebhooks = activeWebhooksResult.map((r) => r.webhook)
-
-    if (!activeWebhooks.length) {
-      logger.info('No active RSS webhooks found')
-      return { total: 0, successful: 0, failed: 0, details: [] }
-    }
-
-    logger.info(`Found ${activeWebhooks.length} active RSS webhooks`)
-
-    const CONCURRENCY = 10
-    const running: Promise[] = []
-    let successCount = 0
-    let failureCount = 0
-
-    const enqueue = async (webhookData: (typeof activeWebhooks)[number]) => {
-      const webhookId = webhookData.id
-      const requestId = generateShortId()
-
-      try {
-        const config = webhookData.providerConfig as unknown as RssWebhookConfig
-
-        if (!config?.feedUrl) {
-          logger.error(`[${requestId}] Missing feedUrl for webhook ${webhookId}`)
-          await markWebhookFailed(webhookId)
-          failureCount++
-          return
-        }
-
-        const now = new Date()
-
-        const { feed, items: newItems } = await fetchNewRssItems(config, requestId)
-
-        if (!newItems.length) {
-          await updateWebhookConfig(webhookId, now.toISOString(), [])
-          await markWebhookSuccess(webhookId)
-          logger.info(`[${requestId}] No new items found for webhook ${webhookId}`)
-          successCount++
-          return
-        }
-
-        logger.info(`[${requestId}] Found ${newItems.length} new items for webhook ${webhookId}`)
-
-        const { processedCount, failedCount: itemFailedCount } = await processRssItems(
-          newItems,
-          feed,
-          webhookData,
-          requestId
-        )
-
-        const newGuids = newItems
-          .map((item) => item.guid || item.link || '')
-          .filter((guid) => guid.length > 0)
-
-        await updateWebhookConfig(webhookId, now.toISOString(), newGuids)
-
-        if (itemFailedCount > 0 && processedCount === 0) {
-          await markWebhookFailed(webhookId)
-          failureCount++
-          logger.warn(
-            `[${requestId}] All ${itemFailedCount} items failed to process for webhook ${webhookId}`
-          )
-        } else {
-          await markWebhookSuccess(webhookId)
-          successCount++
-          logger.info(
-            `[${requestId}] Successfully processed ${processedCount} items for webhook ${webhookId}${itemFailedCount > 0 ? ` (${itemFailedCount} failed)` : ''}`
-          )
-        }
-      } catch (error) {
-        logger.error(`[${requestId}] Error processing RSS webhook ${webhookId}:`, error)
-        await markWebhookFailed(webhookId)
-        failureCount++
-      }
-    }
-
-    for (const webhookData of activeWebhooks) {
-      const promise = enqueue(webhookData)
-        .then(() => {})
-        .catch((err) => {
-          logger.error('Unexpected error in webhook processing:', err)
-          failureCount++
-        })
-
-      running.push(promise)
-
-      if (running.length >= CONCURRENCY) {
-        const completedIdx = await Promise.race(running.map((p, i) => p.then(() => i)))
-        running.splice(completedIdx, 1)
-      }
-    }
-
-    await Promise.allSettled(running)
-
-    const summary = {
-      total: activeWebhooks.length,
-      successful: successCount,
-      failed: failureCount,
-      details: [],
-    }
-
-    logger.info('RSS polling completed', {
-      total: summary.total,
-      successful: summary.successful,
-      failed: summary.failed,
-    })
-
-    return summary
-  } catch (error) {
-    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
-    logger.error('Error in RSS polling service:', errorMessage)
-    throw error
-  }
-}
-
-async function fetchNewRssItems(
-  config: RssWebhookConfig,
-  requestId: string
-): Promise<{ feed: RssFeed; items: RssItem[] }> {
-  try {
-    const urlValidation = await validateUrlWithDNS(config.feedUrl, 'feedUrl')
-    if (!urlValidation.isValid) {
-      logger.error(`[${requestId}] Invalid RSS feed URL: ${urlValidation.error}`)
-      throw new Error(`Invalid RSS feed URL: ${urlValidation.error}`)
-    }
-
-    const response = await secureFetchWithPinnedIP(config.feedUrl, urlValidation.resolvedIP!, {
-      headers: {
-        'User-Agent': 'Sim/1.0 RSS Poller',
-        Accept: 'application/rss+xml, application/xml, text/xml, */*',
-      },
-      timeout: 30000,
-    })
-
-    if (!response.ok) {
-      await response.text().catch(() => {})
-      throw new Error(`Failed to fetch RSS feed: ${response.status} ${response.statusText}`)
-    }
-
-    const xmlContent = await response.text()
-
-    const feed = await parser.parseString(xmlContent)
-
-    if (!feed.items || !feed.items.length) {
-      return { feed: feed as RssFeed, items: [] }
-    }
-
-    const lastCheckedTime = config.lastCheckedTimestamp
-      ? new Date(config.lastCheckedTimestamp)
-      : null
-    const lastSeenGuids = new Set(config.lastSeenGuids || [])
-
-    const newItems = feed.items.filter((item) => {
-      const itemGuid = item.guid || item.link || ''
-
-      if (itemGuid && lastSeenGuids.has(itemGuid)) {
-        return false
-      }
-
-      if (lastCheckedTime && item.isoDate) {
-        const itemDate = new Date(item.isoDate)
-        if (itemDate <= lastCheckedTime) {
-          return false
-        }
-      }
-
-      return true
-    })
-
-    newItems.sort((a, b) => {
-      const dateA = a.isoDate ? new Date(a.isoDate).getTime() : 0
-      const dateB = b.isoDate ? new Date(b.isoDate).getTime() : 0
-      return dateB - dateA
-    })
-
-    const limitedItems = newItems.slice(0, 25)
-
-    logger.info(
-      `[${requestId}] Found ${newItems.length} new items (processing ${limitedItems.length})`
-    )
-
-    return { feed: feed as RssFeed, items: limitedItems as RssItem[] }
-  } catch (error) {
-    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
-    logger.error(`[${requestId}] Error fetching RSS feed:`, errorMessage)
-    throw error
-  }
-}
-
-async function processRssItems(
-  items: RssItem[],
-  feed: RssFeed,
-  webhookData: any,
-  requestId: string
-): Promise<{ processedCount: number; failedCount: number }> {
-  let processedCount = 0
-  let failedCount = 0
-
-  for (const item of items) {
-    try {
-      const itemGuid = item.guid || item.link || `${item.title}-${item.pubDate}`
-
-      await pollingIdempotency.executeWithIdempotency(
-        'rss',
-        `${webhookData.id}:${itemGuid}`,
-        async () => {
-          const payload: RssWebhookPayload = {
-            title: item.title,
-            link: item.link,
-            pubDate: item.pubDate,
-            item: {
-              title: item.title,
-              link: item.link,
-              pubDate: item.pubDate,
-              guid: item.guid,
-              description: item.description,
-              content: item.content,
-              contentSnippet: item.contentSnippet,
-              author: item.author || item.creator,
-              categories: item.categories,
-              enclosure: item.enclosure,
-              isoDate: item.isoDate,
-            },
-            feed: {
-              title: feed.title,
-              link: feed.link,
-              description: feed.description,
-            },
-            timestamp: new Date().toISOString(),
-          }
-
-          const webhookUrl = `${getInternalApiBaseUrl()}/api/webhooks/trigger/${webhookData.path}`
-
-          const response = await fetch(webhookUrl, {
-            method: 'POST',
-            headers: {
-              'Content-Type': 'application/json',
-              'User-Agent': 'Sim/1.0',
-            },
-            body: JSON.stringify(payload),
-          })
-
-          if (!response.ok) {
-            const errorText = await response.text()
-            logger.error(
-              `[${requestId}] Failed to trigger webhook for item ${itemGuid}:`,
-              response.status,
-              errorText
-            )
-            throw new Error(`Webhook request failed: ${response.status} - ${errorText}`)
-          }
-
-          return {
-            itemGuid,
-            webhookStatus: response.status,
-            processed: true,
-          }
-        }
-      )
-
-      logger.info(
-        `[${requestId}] Successfully processed item ${item.title || itemGuid} for webhook ${webhookData.id}`
-      )
-      processedCount++
-    } catch (error) {
-      const errorMessage = error instanceof Error ? error.message : 'Unknown error'
-      logger.error(`[${requestId}] Error processing item:`, errorMessage)
-      failedCount++
-    }
-  }
-
-  return { processedCount, failedCount }
-}
-
-async function updateWebhookConfig(webhookId: string, timestamp: string, newGuids: string[]) {
-  try {
-    const result = await db.select().from(webhook).where(eq(webhook.id, webhookId))
-    const existingConfig = (result[0]?.providerConfig as Record) || {}
-
-    const existingGuids = existingConfig.lastSeenGuids || []
-    const allGuids = [...newGuids, ...existingGuids].slice(0, MAX_GUIDS_TO_TRACK)
-
-    await db
-      .update(webhook)
-      .set({
-        providerConfig: {
-          ...existingConfig,
-          lastCheckedTimestamp: timestamp,
-          lastSeenGuids: allGuids,
-        } as any,
-        updatedAt: new Date(),
-      })
-      .where(eq(webhook.id, webhookId))
-  } catch (err) {
-    logger.error(`Failed to update webhook ${webhookId} config:`, err)
-  }
-}

From a591d7c22758cc555b9d2d235e62f835e36a27f7 Mon Sep 17 00:00:00 2001
From: Vikhyath Mondreti 
Date: Tue, 7 Apr 2026 21:05:45 -0700
Subject: [PATCH 11/15] fix(manual): mock payloads nested recursion (#4037)

---
 .../lib/workflows/triggers/trigger-utils.ts   | 29 +++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/apps/sim/lib/workflows/triggers/trigger-utils.ts b/apps/sim/lib/workflows/triggers/trigger-utils.ts
index f1ee5ce7450..699cbc51756 100644
--- a/apps/sim/lib/workflows/triggers/trigger-utils.ts
+++ b/apps/sim/lib/workflows/triggers/trigger-utils.ts
@@ -67,7 +67,9 @@ function generateMockValue(type: string, _description?: string, fieldName?: stri
 }
 
 /**
- * Recursively processes nested output structures
+ * Recursively processes nested output structures, expanding JSON-Schema-style
+ * objects/arrays that define `properties` or `items` instead of returning
+ * a generic placeholder.
  */
 function processOutputField(key: string, field: unknown, depth = 0, maxDepth = 10): unknown {
   if (depth > maxDepth) {
@@ -80,7 +82,30 @@ function processOutputField(key: string, field: unknown, depth = 0, maxDepth = 1
     'type' in field &&
     typeof (field as Record).type === 'string'
   ) {
-    const typedField = field as { type: string; description?: string }
+    const typedField = field as {
+      type: string
+      description?: string
+      properties?: Record
+      items?: unknown
+    }
+
+    if (
+      (typedField.type === 'object' || typedField.type === 'json') &&
+      typedField.properties &&
+      typeof typedField.properties === 'object'
+    ) {
+      const nestedObject: Record = {}
+      for (const [nestedKey, nestedField] of Object.entries(typedField.properties)) {
+        nestedObject[nestedKey] = processOutputField(nestedKey, nestedField, depth + 1, maxDepth)
+      }
+      return nestedObject
+    }
+
+    if (typedField.type === 'array' && typedField.items && typeof typedField.items === 'object') {
+      const itemValue = processOutputField(`${key}_item`, typedField.items, depth + 1, maxDepth)
+      return [itemValue]
+    }
+
     return generateMockValue(typedField.type, typedField.description, key)
   }
 

From 7b81a760eac58eaddd88565b1f871472945fe4da Mon Sep 17 00:00:00 2001
From: Waleed 
Date: Tue, 7 Apr 2026 22:35:34 -0700
Subject: [PATCH 12/15] fix(kb): show 'pending' instead of past date for
 overdue next sync (#4039)

---
 .../components/connectors-section/connectors-section.tsx    | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connectors-section.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connectors-section.tsx
index 578b6df254e..3d08cdb7c62 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connectors-section.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connectors-section.tsx
@@ -2,7 +2,7 @@
 
 import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
 import { createLogger } from '@sim/logger'
-import { format, formatDistanceToNow } from 'date-fns'
+import { format, formatDistanceToNow, isPast } from 'date-fns'
 import {
   AlertCircle,
   CheckCircle2,
@@ -380,7 +380,9 @@ function ConnectorCard({
                   ·
                   
                     Next sync:{' '}
-                    {formatDistanceToNow(new Date(connector.nextSyncAt), { addSuffix: true })}
+                    {isPast(new Date(connector.nextSyncAt))
+                      ? 'pending'
+                      : formatDistanceToNow(new Date(connector.nextSyncAt), { addSuffix: true })}
                   
                 
               )}

From 9282d1bf5485460a739b36250a31c5f47c2aae5b Mon Sep 17 00:00:00 2001
From: Waleed 
Date: Tue, 7 Apr 2026 23:40:06 -0700
Subject: [PATCH 13/15] feat(secrets): allow admins to view and edit workspace
 secret values (#4040)

* feat(secrets): allow admins to view and edit workspace secret values

* fix(secrets): cross-browser masking and grid layout for non-admin users
---
 .../credentials/credentials-manager.tsx       | 80 +++++++++++--------
 1 file changed, 48 insertions(+), 32 deletions(-)

diff --git a/apps/sim/app/workspace/[workspaceId]/settings/components/credentials/credentials-manager.tsx b/apps/sim/app/workspace/[workspaceId]/settings/components/credentials/credentials-manager.tsx
index e87f0ee5cf4..cf2f07519d1 100644
--- a/apps/sim/app/workspace/[workspaceId]/settings/components/credentials/credentials-manager.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/settings/components/credentials/credentials-manager.tsx
@@ -127,10 +127,11 @@ interface WorkspaceVariableRowProps {
   renamingKey: string | null
   pendingKeyValue: string
   hasCredential: boolean
-  isAdmin: boolean
+  canEdit: boolean
   onRenameStart: (key: string) => void
   onPendingKeyChange: (value: string) => void
   onRenameEnd: (key: string, value: string) => void
+  onValueChange: (key: string, value: string) => void
   onDelete: (key: string) => void
   onViewDetails: (envKey: string) => void
 }
@@ -141,18 +142,16 @@ function WorkspaceVariableRow({
   renamingKey,
   pendingKeyValue,
   hasCredential,
-  isAdmin,
+  canEdit,
   onRenameStart,
   onPendingKeyChange,
   onRenameEnd,
+  onValueChange,
   onDelete,
   onViewDetails,
 }: WorkspaceVariableRowProps) {
   const [valueFocused, setValueFocused] = useState(false)
 
-  const maskedValueStyle =
-    isAdmin && !valueFocused ? ({ WebkitTextSecurity: 'disc' } as React.CSSProperties) : undefined
-
   return (
     
e.target.removeAttribute('readOnly')} + onFocus={(e) => { + if (canEdit) e.target.removeAttribute('readOnly') + }} className='h-9' />
onValueChange(envKey, e.target.value)} readOnly - onFocus={() => { - if (isAdmin) setValueFocused(true) + onFocus={(e) => { + if (canEdit) { + setValueFocused(true) + e.target.removeAttribute('readOnly') + } }} onBlur={() => { - if (isAdmin) setValueFocused(false) + if (canEdit) setValueFocused(false) }} + name={`workspace_env_value_${envKey}_${Math.random()}`} autoComplete='off' autoCorrect='off' autoCapitalize='off' spellCheck='false' - style={maskedValueStyle} className='h-9' /> - - - - - Delete secret - + {canEdit ? ( + + + + + Delete secret + + ) : ( +
+ )}
) } @@ -316,7 +326,7 @@ export function CredentialsManager() { const { data: workspacePermissions } = useWorkspacePermissionsQuery(workspaceId || null) const queryClient = useQueryClient() - const isAdmin = useMemo(() => { + const isWorkspaceAdmin = useMemo(() => { const userId = session?.user?.id if (!userId || !workspacePermissions?.users) return false const currentUser = workspacePermissions.users.find((user) => user.userId === userId) @@ -791,6 +801,10 @@ export function CredentialsManager() { [pendingKeyValue, renamingKey] ) + const handleWorkspaceValueChange = useCallback((key: string, value: string) => { + setWorkspaceVars((prev) => ({ ...prev, [key]: value })) + }, []) + const handleDeleteWorkspaceVar = useCallback((key: string) => { setWorkspaceVars((prev) => { const next = { ...prev } @@ -1536,25 +1550,27 @@ export function CredentialsManager() { renamingKey={renamingKey} pendingKeyValue={pendingKeyValue} hasCredential={envKeyToCredential.has(key)} - isAdmin={isAdmin} + canEdit={isWorkspaceAdmin} onRenameStart={setRenamingKey} onPendingKeyChange={setPendingKeyValue} onRenameEnd={handleWorkspaceKeyRename} + onValueChange={handleWorkspaceValueChange} onDelete={handleDeleteWorkspaceVar} onViewDetails={(envKey) => handleViewDetails(envKey, 'env_workspace')} /> ))} - {(searchTerm.trim() - ? filteredNewWorkspaceRows - : newWorkspaceRows.map((row, index) => ({ row, originalIndex: index })) - ).map(({ row, originalIndex }) => ( - - ))} + {isWorkspaceAdmin && + (searchTerm.trim() + ? filteredNewWorkspaceRows + : newWorkspaceRows.map((row, index) => ({ row, originalIndex: index })) + ).map(({ row, originalIndex }) => ( + + ))}
)} From d0d35dd4067d45c5ba9e873b4603e67f8709048b Mon Sep 17 00:00:00 2001 From: Waleed Date: Wed, 8 Apr 2026 00:26:33 -0700 Subject: [PATCH 14/15] fix: address PR review comments (#4042) * fix: address PR review comments on staging release - Add try/catch around clipboard.writeText() in CopyCodeButton - Add missing folder and past_chat cases in resolveResourceFromContext - Return 400 for ZodError instead of 500 in all 8 Athena API routes Co-Authored-By: Claude Opus 4.6 * fix(api): return 400 for Zod validation errors across 27 API routes Routes using z.parse() were returning 500 for ZodError (client input validation failures). Added instanceof z.ZodError check to return 400 before the generic 500 handler, matching the established pattern used by 115+ other routes. Affected services: CloudWatch (7), CloudFormation (7), DynamoDB (6), Slack (3), Outlook (2), OneDrive (1), Google Drive (1). Co-Authored-By: Claude Opus 4.6 * fix(api): add success:false to ZodError responses for consistency 7 routes used { success: false, error: ... } in their generic error handler but our ZodError handler only returned { error: ... }. Aligned the ZodError response shape to match. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- .../app/api/tools/athena/create-named-query/route.ts | 6 ++++++ .../app/api/tools/athena/get-named-query/route.ts | 6 ++++++ .../api/tools/athena/get-query-execution/route.ts | 6 ++++++ .../app/api/tools/athena/get-query-results/route.ts | 6 ++++++ .../app/api/tools/athena/list-named-queries/route.ts | 6 ++++++ .../api/tools/athena/list-query-executions/route.ts | 6 ++++++ apps/sim/app/api/tools/athena/start-query/route.ts | 6 ++++++ apps/sim/app/api/tools/athena/stop-query/route.ts | 6 ++++++ .../describe-stack-drift-detection-status/route.ts | 6 ++++++ .../cloudformation/describe-stack-events/route.ts | 6 ++++++ .../tools/cloudformation/describe-stacks/route.ts | 6 ++++++ .../tools/cloudformation/detect-stack-drift/route.ts | 6 ++++++ .../api/tools/cloudformation/get-template/route.ts | 6 ++++++ .../cloudformation/list-stack-resources/route.ts | 6 ++++++ .../tools/cloudformation/validate-template/route.ts | 6 ++++++ .../api/tools/cloudwatch/describe-alarms/route.ts | 6 ++++++ .../tools/cloudwatch/describe-log-groups/route.ts | 6 ++++++ .../tools/cloudwatch/describe-log-streams/route.ts | 6 ++++++ .../app/api/tools/cloudwatch/get-log-events/route.ts | 6 ++++++ .../tools/cloudwatch/get-metric-statistics/route.ts | 6 ++++++ .../app/api/tools/cloudwatch/list-metrics/route.ts | 6 ++++++ .../sim/app/api/tools/cloudwatch/query-logs/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/delete/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/get/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/put/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/query/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/scan/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/update/route.ts | 6 ++++++ .../sim/app/api/tools/google_drive/download/route.ts | 6 ++++++ apps/sim/app/api/tools/onedrive/download/route.ts | 6 ++++++ apps/sim/app/api/tools/outlook/draft/route.ts | 6 ++++++ apps/sim/app/api/tools/outlook/send/route.ts | 6 ++++++ apps/sim/app/api/tools/slack/download/route.ts | 6 ++++++ apps/sim/app/api/tools/slack/send-ephemeral/route.ts | 6 ++++++ apps/sim/app/api/tools/slack/send-message/route.ts | 6 ++++++ apps/sim/components/ui/copy-code-button.tsx | 12 ++++++++---- 36 files changed, 218 insertions(+), 4 deletions(-) diff --git a/apps/sim/app/api/tools/athena/create-named-query/route.ts b/apps/sim/app/api/tools/athena/create-named-query/route.ts index f9f997d618e..f49bc16247d 100644 --- a/apps/sim/app/api/tools/athena/create-named-query/route.ts +++ b/apps/sim/app/api/tools/athena/create-named-query/route.ts @@ -55,6 +55,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to create Athena named query' logger.error('CreateNamedQuery failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/athena/get-named-query/route.ts b/apps/sim/app/api/tools/athena/get-named-query/route.ts index 83e9845b75c..394bbda2b87 100644 --- a/apps/sim/app/api/tools/athena/get-named-query/route.ts +++ b/apps/sim/app/api/tools/athena/get-named-query/route.ts @@ -53,6 +53,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get Athena named query' logger.error('GetNamedQuery failed', { error: errorMessage }) return NextResponse.json({ error: errorMessage }, { status: 500 }) diff --git a/apps/sim/app/api/tools/athena/get-query-execution/route.ts b/apps/sim/app/api/tools/athena/get-query-execution/route.ts index b043db11414..129f4794dc4 100644 --- a/apps/sim/app/api/tools/athena/get-query-execution/route.ts +++ b/apps/sim/app/api/tools/athena/get-query-execution/route.ts @@ -63,6 +63,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get Athena query execution' logger.error('GetQueryExecution failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/athena/get-query-results/route.ts b/apps/sim/app/api/tools/athena/get-query-results/route.ts index d89488371db..260cc73dc0c 100644 --- a/apps/sim/app/api/tools/athena/get-query-results/route.ts +++ b/apps/sim/app/api/tools/athena/get-query-results/route.ts @@ -74,6 +74,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get Athena query results' logger.error('GetQueryResults failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/athena/list-named-queries/route.ts b/apps/sim/app/api/tools/athena/list-named-queries/route.ts index c9f74ca2161..326e03711bb 100644 --- a/apps/sim/app/api/tools/athena/list-named-queries/route.ts +++ b/apps/sim/app/api/tools/athena/list-named-queries/route.ts @@ -51,6 +51,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to list Athena named queries' logger.error('ListNamedQueries failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/athena/list-query-executions/route.ts b/apps/sim/app/api/tools/athena/list-query-executions/route.ts index 096afee99cb..958d09b1735 100644 --- a/apps/sim/app/api/tools/athena/list-query-executions/route.ts +++ b/apps/sim/app/api/tools/athena/list-query-executions/route.ts @@ -51,6 +51,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to list Athena query executions' logger.error('ListQueryExecutions failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/athena/start-query/route.ts b/apps/sim/app/api/tools/athena/start-query/route.ts index 6af793cbe01..0555246aa8e 100644 --- a/apps/sim/app/api/tools/athena/start-query/route.ts +++ b/apps/sim/app/api/tools/athena/start-query/route.ts @@ -67,6 +67,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to start Athena query' logger.error('StartQuery failed', { error: errorMessage }) return NextResponse.json({ error: errorMessage }, { status: 500 }) diff --git a/apps/sim/app/api/tools/athena/stop-query/route.ts b/apps/sim/app/api/tools/athena/stop-query/route.ts index 2f3422b36e2..0a7558d314a 100644 --- a/apps/sim/app/api/tools/athena/stop-query/route.ts +++ b/apps/sim/app/api/tools/athena/stop-query/route.ts @@ -43,6 +43,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to stop Athena query' logger.error('StopQuery failed', { error: errorMessage }) return NextResponse.json({ error: errorMessage }, { status: 500 }) diff --git a/apps/sim/app/api/tools/cloudformation/describe-stack-drift-detection-status/route.ts b/apps/sim/app/api/tools/cloudformation/describe-stack-drift-detection-status/route.ts index b47611b0cfb..d267bb01fa3 100644 --- a/apps/sim/app/api/tools/cloudformation/describe-stack-drift-detection-status/route.ts +++ b/apps/sim/app/api/tools/cloudformation/describe-stack-drift-detection-status/route.ts @@ -53,6 +53,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe stack drift detection status' logger.error('DescribeStackDriftDetectionStatus failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/describe-stack-events/route.ts b/apps/sim/app/api/tools/cloudformation/describe-stack-events/route.ts index b838512a437..a3108eebffc 100644 --- a/apps/sim/app/api/tools/cloudformation/describe-stack-events/route.ts +++ b/apps/sim/app/api/tools/cloudformation/describe-stack-events/route.ts @@ -70,6 +70,12 @@ export async function POST(request: NextRequest) { output: { events }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe CloudFormation stack events' logger.error('DescribeStackEvents failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/describe-stacks/route.ts b/apps/sim/app/api/tools/cloudformation/describe-stacks/route.ts index 30cf207d7e6..d8fc946b519 100644 --- a/apps/sim/app/api/tools/cloudformation/describe-stacks/route.ts +++ b/apps/sim/app/api/tools/cloudformation/describe-stacks/route.ts @@ -78,6 +78,12 @@ export async function POST(request: NextRequest) { output: { stacks }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe CloudFormation stacks' logger.error('DescribeStacks failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/detect-stack-drift/route.ts b/apps/sim/app/api/tools/cloudformation/detect-stack-drift/route.ts index 30d05166816..a21c3e70410 100644 --- a/apps/sim/app/api/tools/cloudformation/detect-stack-drift/route.ts +++ b/apps/sim/app/api/tools/cloudformation/detect-stack-drift/route.ts @@ -48,6 +48,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to detect CloudFormation stack drift' logger.error('DetectStackDrift failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/get-template/route.ts b/apps/sim/app/api/tools/cloudformation/get-template/route.ts index 9abdad4e170..a5e6edeeaa3 100644 --- a/apps/sim/app/api/tools/cloudformation/get-template/route.ts +++ b/apps/sim/app/api/tools/cloudformation/get-template/route.ts @@ -45,6 +45,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get CloudFormation template' logger.error('GetTemplate failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/list-stack-resources/route.ts b/apps/sim/app/api/tools/cloudformation/list-stack-resources/route.ts index ca22c8e8567..dfc65171362 100644 --- a/apps/sim/app/api/tools/cloudformation/list-stack-resources/route.ts +++ b/apps/sim/app/api/tools/cloudformation/list-stack-resources/route.ts @@ -67,6 +67,12 @@ export async function POST(request: NextRequest) { output: { resources }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to list CloudFormation stack resources' logger.error('ListStackResources failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/validate-template/route.ts b/apps/sim/app/api/tools/cloudformation/validate-template/route.ts index e2a8b4428ed..1264d813fdf 100644 --- a/apps/sim/app/api/tools/cloudformation/validate-template/route.ts +++ b/apps/sim/app/api/tools/cloudformation/validate-template/route.ts @@ -53,6 +53,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to validate CloudFormation template' logger.error('ValidateTemplate failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/describe-alarms/route.ts b/apps/sim/app/api/tools/cloudwatch/describe-alarms/route.ts index 0ab6c4aad8d..3fc65ab5bfd 100644 --- a/apps/sim/app/api/tools/cloudwatch/describe-alarms/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/describe-alarms/route.ts @@ -88,6 +88,12 @@ export async function POST(request: NextRequest) { output: { alarms: [...metricAlarms, ...compositeAlarms] }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe CloudWatch alarms' logger.error('DescribeAlarms failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/describe-log-groups/route.ts b/apps/sim/app/api/tools/cloudwatch/describe-log-groups/route.ts index a10f46c4efa..fcb29be5289 100644 --- a/apps/sim/app/api/tools/cloudwatch/describe-log-groups/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/describe-log-groups/route.ts @@ -54,6 +54,12 @@ export async function POST(request: NextRequest) { output: { logGroups }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe CloudWatch log groups' logger.error('DescribeLogGroups failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/describe-log-streams/route.ts b/apps/sim/app/api/tools/cloudwatch/describe-log-streams/route.ts index d74ad6de266..223e51617b9 100644 --- a/apps/sim/app/api/tools/cloudwatch/describe-log-streams/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/describe-log-streams/route.ts @@ -44,6 +44,12 @@ export async function POST(request: NextRequest) { output: { logStreams: result.logStreams }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe CloudWatch log streams' logger.error('DescribeLogStreams failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/get-log-events/route.ts b/apps/sim/app/api/tools/cloudwatch/get-log-events/route.ts index c42d49e97ab..e1a8abcf666 100644 --- a/apps/sim/app/api/tools/cloudwatch/get-log-events/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/get-log-events/route.ts @@ -52,6 +52,12 @@ export async function POST(request: NextRequest) { output: { events: result.events }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get CloudWatch log events' logger.error('GetLogEvents failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/get-metric-statistics/route.ts b/apps/sim/app/api/tools/cloudwatch/get-metric-statistics/route.ts index 321092b3283..677bafca3ca 100644 --- a/apps/sim/app/api/tools/cloudwatch/get-metric-statistics/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/get-metric-statistics/route.ts @@ -89,6 +89,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get CloudWatch metric statistics' logger.error('GetMetricStatistics failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/list-metrics/route.ts b/apps/sim/app/api/tools/cloudwatch/list-metrics/route.ts index 09485cb8590..36d2c31e2fa 100644 --- a/apps/sim/app/api/tools/cloudwatch/list-metrics/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/list-metrics/route.ts @@ -62,6 +62,12 @@ export async function POST(request: NextRequest) { output: { metrics }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to list CloudWatch metrics' logger.error('ListMetrics failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/query-logs/route.ts b/apps/sim/app/api/tools/cloudwatch/query-logs/route.ts index a471edc20e8..75b4dab2395 100644 --- a/apps/sim/app/api/tools/cloudwatch/query-logs/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/query-logs/route.ts @@ -63,6 +63,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'CloudWatch Log Insights query failed' logger.error('QueryLogs failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/dynamodb/delete/route.ts b/apps/sim/app/api/tools/dynamodb/delete/route.ts index 0002787f373..5b6ab1d5b20 100644 --- a/apps/sim/app/api/tools/dynamodb/delete/route.ts +++ b/apps/sim/app/api/tools/dynamodb/delete/route.ts @@ -41,6 +41,12 @@ export async function POST(request: NextRequest) { message: 'Item deleted successfully', }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB delete failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/dynamodb/get/route.ts b/apps/sim/app/api/tools/dynamodb/get/route.ts index 851f1cb0740..1eca9d3f72e 100644 --- a/apps/sim/app/api/tools/dynamodb/get/route.ts +++ b/apps/sim/app/api/tools/dynamodb/get/route.ts @@ -48,6 +48,12 @@ export async function POST(request: NextRequest) { item: result.item, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB get failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/dynamodb/put/route.ts b/apps/sim/app/api/tools/dynamodb/put/route.ts index cb001c5873a..2572cdcd5e7 100644 --- a/apps/sim/app/api/tools/dynamodb/put/route.ts +++ b/apps/sim/app/api/tools/dynamodb/put/route.ts @@ -36,6 +36,12 @@ export async function POST(request: NextRequest) { item: validatedData.item, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB put failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/dynamodb/query/route.ts b/apps/sim/app/api/tools/dynamodb/query/route.ts index 06945c10070..3b1fadeee12 100644 --- a/apps/sim/app/api/tools/dynamodb/query/route.ts +++ b/apps/sim/app/api/tools/dynamodb/query/route.ts @@ -51,6 +51,12 @@ export async function POST(request: NextRequest) { count: result.count, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB query failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/dynamodb/scan/route.ts b/apps/sim/app/api/tools/dynamodb/scan/route.ts index c083faad584..64c47895b0a 100644 --- a/apps/sim/app/api/tools/dynamodb/scan/route.ts +++ b/apps/sim/app/api/tools/dynamodb/scan/route.ts @@ -45,6 +45,12 @@ export async function POST(request: NextRequest) { count: result.count, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB scan failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/dynamodb/update/route.ts b/apps/sim/app/api/tools/dynamodb/update/route.ts index 07abcc25648..3a5892fe61a 100644 --- a/apps/sim/app/api/tools/dynamodb/update/route.ts +++ b/apps/sim/app/api/tools/dynamodb/update/route.ts @@ -50,6 +50,12 @@ export async function POST(request: NextRequest) { item: result.attributes, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB update failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/google_drive/download/route.ts b/apps/sim/app/api/tools/google_drive/download/route.ts index 2a9730dcada..e4131423f91 100644 --- a/apps/sim/app/api/tools/google_drive/download/route.ts +++ b/apps/sim/app/api/tools/google_drive/download/route.ts @@ -240,6 +240,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error downloading Google Drive file:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/onedrive/download/route.ts b/apps/sim/app/api/tools/onedrive/download/route.ts index a50338af557..2cc268ffd5e 100644 --- a/apps/sim/app/api/tools/onedrive/download/route.ts +++ b/apps/sim/app/api/tools/onedrive/download/route.ts @@ -165,6 +165,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error downloading OneDrive file:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/outlook/draft/route.ts b/apps/sim/app/api/tools/outlook/draft/route.ts index eeee0f14e17..801b3b90869 100644 --- a/apps/sim/app/api/tools/outlook/draft/route.ts +++ b/apps/sim/app/api/tools/outlook/draft/route.ts @@ -176,6 +176,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error creating Outlook draft:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/outlook/send/route.ts b/apps/sim/app/api/tools/outlook/send/route.ts index f90f62518a8..f2d39ef11e6 100644 --- a/apps/sim/app/api/tools/outlook/send/route.ts +++ b/apps/sim/app/api/tools/outlook/send/route.ts @@ -189,6 +189,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error sending Outlook email:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/slack/download/route.ts b/apps/sim/app/api/tools/slack/download/route.ts index 45c34bcd11d..83a44386d4d 100644 --- a/apps/sim/app/api/tools/slack/download/route.ts +++ b/apps/sim/app/api/tools/slack/download/route.ts @@ -158,6 +158,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error downloading Slack file:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/slack/send-ephemeral/route.ts b/apps/sim/app/api/tools/slack/send-ephemeral/route.ts index 6d443e5039a..1387290c6ae 100644 --- a/apps/sim/app/api/tools/slack/send-ephemeral/route.ts +++ b/apps/sim/app/api/tools/slack/send-ephemeral/route.ts @@ -84,6 +84,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error sending ephemeral message:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/slack/send-message/route.ts b/apps/sim/app/api/tools/slack/send-message/route.ts index a6b8a3db71c..5520a280f6e 100644 --- a/apps/sim/app/api/tools/slack/send-message/route.ts +++ b/apps/sim/app/api/tools/slack/send-message/route.ts @@ -77,6 +77,12 @@ export async function POST(request: NextRequest) { return NextResponse.json({ success: true, output: result.output }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error sending Slack message:`, error) return NextResponse.json( { diff --git a/apps/sim/components/ui/copy-code-button.tsx b/apps/sim/components/ui/copy-code-button.tsx index 5113c796016..87f17764cf0 100644 --- a/apps/sim/components/ui/copy-code-button.tsx +++ b/apps/sim/components/ui/copy-code-button.tsx @@ -14,10 +14,14 @@ export function CopyCodeButton({ code, className }: CopyCodeButtonProps) { const timerRef = useRef | null>(null) const handleCopy = useCallback(async () => { - await navigator.clipboard.writeText(code) - setCopied(true) - if (timerRef.current) clearTimeout(timerRef.current) - timerRef.current = setTimeout(() => setCopied(false), 2000) + try { + await navigator.clipboard.writeText(code) + setCopied(true) + if (timerRef.current) clearTimeout(timerRef.current) + timerRef.current = setTimeout(() => setCopied(false), 2000) + } catch { + // Clipboard write can fail when document lacks focus or permission is denied + } }, [code]) useEffect( From 3c7bfa797a5d242b85a5dd2c9bb66df455077f19 Mon Sep 17 00:00:00 2001 From: Waleed Date: Wed, 8 Apr 2026 00:59:54 -0700 Subject: [PATCH 15/15] improvement(kb): deferred content fetching and metadata-based hashes for connectors (#4044) * improvement(kb): deferred content fetching and metadata-based hashes for connectors * fix(kb): remove message count from outlook contentHash to prevent list/get divergence * fix(kb): increase outlook getDocument message limit from 50 to 250 * fix(kb): skip outlook messages without conversationId to prevent broken stubs * fix(kb): scope outlook getDocument to same folder as listDocuments to prevent hash divergence * fix(kb): add missing connector sync cron job to Helm values The connector sync endpoint existed but had no cron job configured to trigger it, meaning scheduled syncs would never fire. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- apps/sim/connectors/asana/asana.ts | 8 +- apps/sim/connectors/fireflies/fireflies.ts | 63 +++++-------- .../google-calendar/google-calendar.ts | 12 ++- .../sim/connectors/google-docs/google-docs.ts | 74 +++++++--------- .../connectors/google-sheets/google-sheets.ts | 43 ++++----- apps/sim/connectors/hubspot/hubspot.ts | 15 ++-- apps/sim/connectors/intercom/intercom.ts | 23 ++--- apps/sim/connectors/jira/jira.ts | 44 ++++++---- apps/sim/connectors/linear/linear.ts | 62 ++++++------- apps/sim/connectors/outlook/outlook.ts | 88 ++++++++++++++----- apps/sim/connectors/reddit/reddit.ts | 46 +++++----- apps/sim/connectors/salesforce/salesforce.ts | 49 ++++++++--- apps/sim/connectors/servicenow/servicenow.ts | 26 +++--- apps/sim/connectors/webflow/webflow.ts | 13 +-- apps/sim/connectors/wordpress/wordpress.ts | 10 +-- apps/sim/connectors/zendesk/zendesk.ts | 70 ++++++++------- helm/sim/values.yaml | 9 ++ 17 files changed, 350 insertions(+), 305 deletions(-) diff --git a/apps/sim/connectors/asana/asana.ts b/apps/sim/connectors/asana/asana.ts index e6febeb8210..25009ec5c4a 100644 --- a/apps/sim/connectors/asana/asana.ts +++ b/apps/sim/connectors/asana/asana.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { AsanaIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, joinTagArray, parseTagDate } from '@/connectors/utils' +import { joinTagArray, parseTagDate } from '@/connectors/utils' const logger = createLogger('AsanaConnector') @@ -240,7 +240,6 @@ export const asanaConnector: ConnectorConfig = { for (const task of result.data) { const content = buildTaskContent(task) - const contentHash = await computeContentHash(content) const tagNames = task.tags?.map((t) => t.name).filter(Boolean) || [] documents.push({ @@ -249,7 +248,7 @@ export const asanaConnector: ConnectorConfig = { content, mimeType: 'text/plain', sourceUrl: task.permalink_url || undefined, - contentHash, + contentHash: `asana:${task.gid}:${task.modified_at ?? ''}`, metadata: { project: currentProjectGid, assignee: task.assignee?.name, @@ -315,7 +314,6 @@ export const asanaConnector: ConnectorConfig = { if (!task) return null const content = buildTaskContent(task) - const contentHash = await computeContentHash(content) const tagNames = task.tags?.map((t) => t.name).filter(Boolean) || [] return { @@ -324,7 +322,7 @@ export const asanaConnector: ConnectorConfig = { content, mimeType: 'text/plain', sourceUrl: task.permalink_url || undefined, - contentHash, + contentHash: `asana:${task.gid}:${task.modified_at ?? ''}`, metadata: { assignee: task.assignee?.name, completed: task.completed, diff --git a/apps/sim/connectors/fireflies/fireflies.ts b/apps/sim/connectors/fireflies/fireflies.ts index cfb9d0f24a2..c09cccb426d 100644 --- a/apps/sim/connectors/fireflies/fireflies.ts +++ b/apps/sim/connectors/fireflies/fireflies.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { FirefliesIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, parseTagDate } from '@/connectors/utils' +import { parseTagDate } from '@/connectors/utils' const logger = createLogger('FirefliesConnector') @@ -196,17 +196,6 @@ export const firefliesConnector: ConnectorConfig = { id name } - sentences { - index - speaker_name - text - } - summary { - keywords - action_items - overview - short_summary - } } }`, variables @@ -214,32 +203,27 @@ export const firefliesConnector: ConnectorConfig = { const transcripts = (data.transcripts || []) as FirefliesTranscript[] - const documents: ExternalDocument[] = await Promise.all( - transcripts.map(async (transcript) => { - const content = formatTranscriptContent(transcript) - const contentHash = await computeContentHash(content) - - const meetingDate = transcript.date ? new Date(transcript.date).toISOString() : undefined - const speakerNames = transcript.speakers?.map((s) => s.name).filter(Boolean) ?? [] - - return { - externalId: transcript.id, - title: transcript.title || 'Untitled Meeting', - content, - mimeType: 'text/plain' as const, - sourceUrl: transcript.transcript_url || undefined, - contentHash, - metadata: { - hostEmail: transcript.host_email, - duration: transcript.duration, - meetingDate, - participants: transcript.participants, - speakers: speakerNames, - keywords: transcript.summary?.keywords, - }, - } - }) - ) + const documents: ExternalDocument[] = transcripts.map((transcript) => { + const meetingDate = transcript.date ? new Date(transcript.date).toISOString() : undefined + const speakerNames = transcript.speakers?.map((s) => s.name).filter(Boolean) ?? [] + + return { + externalId: transcript.id, + title: transcript.title || 'Untitled Meeting', + content: '', + contentDeferred: true, + mimeType: 'text/plain' as const, + sourceUrl: transcript.transcript_url || undefined, + contentHash: `fireflies:${transcript.id}:${transcript.date ?? ''}:${transcript.duration ?? ''}`, + metadata: { + hostEmail: transcript.host_email, + duration: transcript.duration, + meetingDate, + participants: transcript.participants, + speakers: speakerNames, + }, + } + }) const totalFetched = ((syncContext?.totalDocsFetched as number) ?? 0) + documents.length if (syncContext) syncContext.totalDocsFetched = totalFetched @@ -296,7 +280,7 @@ export const firefliesConnector: ConnectorConfig = { if (!transcript) return null const content = formatTranscriptContent(transcript) - const contentHash = await computeContentHash(content) + const contentHash = `fireflies:${transcript.id}:${transcript.date ?? ''}:${transcript.duration ?? ''}` const meetingDate = transcript.date ? new Date(transcript.date).toISOString() : undefined const speakerNames = transcript.speakers?.map((s) => s.name).filter(Boolean) ?? [] @@ -305,6 +289,7 @@ export const firefliesConnector: ConnectorConfig = { externalId: transcript.id, title: transcript.title || 'Untitled Meeting', content, + contentDeferred: false, mimeType: 'text/plain', sourceUrl: transcript.transcript_url || undefined, contentHash, diff --git a/apps/sim/connectors/google-calendar/google-calendar.ts b/apps/sim/connectors/google-calendar/google-calendar.ts index 1fbda8d1a3b..d107cb0569a 100644 --- a/apps/sim/connectors/google-calendar/google-calendar.ts +++ b/apps/sim/connectors/google-calendar/google-calendar.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { GoogleCalendarIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, parseTagDate } from '@/connectors/utils' +import { parseTagDate } from '@/connectors/utils' const logger = createLogger('GoogleCalendarConnector') @@ -195,14 +195,12 @@ function getTimeRange(sourceConfig: Record): { timeMin: string; /** * Converts a CalendarEvent to an ExternalDocument. */ -async function eventToDocument(event: CalendarEvent): Promise { +function eventToDocument(event: CalendarEvent): ExternalDocument | null { if (event.status === 'cancelled') return null const content = eventToContent(event) if (!content.trim()) return null - const contentHash = await computeContentHash(content) - const startTime = event.start?.dateTime || event.start?.date || '' const attendeeCount = event.attendees?.filter((a) => !a.resource).length || 0 @@ -212,7 +210,7 @@ async function eventToDocument(event: CalendarEvent): Promise { - try { - const content = await fetchDocContent(accessToken, file.id) - if (!content.trim()) { - logger.info(`Skipping empty document: ${file.name} (${file.id})`) - return null - } - - const contentHash = await computeContentHash(content) - - return { - externalId: file.id, - title: file.name || 'Untitled', - content, - mimeType: 'text/plain', - sourceUrl: file.webViewLink || `https://docs.google.com/document/d/${file.id}/edit`, - contentHash, - metadata: { - modifiedTime: file.modifiedTime, - createdTime: file.createdTime, - owners: file.owners?.map((o) => o.displayName || o.emailAddress).filter(Boolean), - }, - } - } catch (error) { - logger.warn(`Failed to extract content from document: ${file.name} (${file.id})`, { - error: error instanceof Error ? error.message : String(error), - }) - return null +function fileToStub(file: DriveFile): ExternalDocument { + return { + externalId: file.id, + title: file.name || 'Untitled', + content: '', + contentDeferred: true, + mimeType: 'text/plain', + sourceUrl: file.webViewLink || `https://docs.google.com/document/d/${file.id}/edit`, + contentHash: `gdocs:${file.id}:${file.modifiedTime ?? ''}`, + metadata: { + modifiedTime: file.modifiedTime, + createdTime: file.createdTime, + owners: file.owners?.map((o) => o.displayName || o.emailAddress).filter(Boolean), + }, } } @@ -246,18 +229,11 @@ export const googleDocsConnector: ConnectorConfig = { const maxDocs = sourceConfig.maxDocs ? Number(sourceConfig.maxDocs) : 0 const previouslyFetched = (syncContext?.totalDocsFetched as number) ?? 0 - const CONCURRENCY = 5 - const documents: ExternalDocument[] = [] - for (let i = 0; i < files.length; i += CONCURRENCY) { - if (maxDocs > 0 && previouslyFetched + documents.length >= maxDocs) break - const batch = files.slice(i, i + CONCURRENCY) - const results = await Promise.all(batch.map((file) => fileToDocument(accessToken, file))) - documents.push(...(results.filter(Boolean) as ExternalDocument[])) - } + let documents = files.map(fileToStub) if (maxDocs > 0) { const remaining = maxDocs - previouslyFetched if (documents.length > remaining) { - documents.splice(remaining) + documents = documents.slice(0, remaining) } } @@ -300,7 +276,17 @@ export const googleDocsConnector: ConnectorConfig = { if (file.trashed) return null if (file.mimeType !== 'application/vnd.google-apps.document') return null - return fileToDocument(accessToken, file) + try { + const content = await fetchDocContent(accessToken, file.id) + if (!content.trim()) return null + + return { ...fileToStub(file), content, contentDeferred: false } + } catch (error) { + logger.warn(`Failed to extract content from document: ${file.name} (${file.id})`, { + error: error instanceof Error ? error.message : String(error), + }) + return null + } }, validateConfig: async ( diff --git a/apps/sim/connectors/google-sheets/google-sheets.ts b/apps/sim/connectors/google-sheets/google-sheets.ts index 9b70ea9a941..2fb1c1f2865 100644 --- a/apps/sim/connectors/google-sheets/google-sheets.ts +++ b/apps/sim/connectors/google-sheets/google-sheets.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { GoogleSheetsIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, parseTagDate } from '@/connectors/utils' +import { parseTagDate } from '@/connectors/utils' const logger = createLogger('GoogleSheetsConnector') @@ -168,7 +168,6 @@ async function sheetToDocument( return null } - const contentHash = await computeContentHash(content) const rowCount = dataRows.length return { @@ -177,7 +176,7 @@ async function sheetToDocument( content, mimeType: 'text/plain', sourceUrl: `https://docs.google.com/spreadsheets/d/${spreadsheetId}/edit#gid=${sheet.sheetId}`, - contentHash, + contentHash: `gsheets:${spreadsheetId}:${sheet.sheetId}:${modifiedTime ?? ''}`, metadata: { spreadsheetId, spreadsheetTitle, @@ -259,22 +258,24 @@ export const googleSheetsConnector: ConnectorConfig = { sheetCount: sheets.length, }) - const documents: ExternalDocument[] = [] - for (let i = 0; i < sheets.length; i += CONCURRENCY) { - const batch = sheets.slice(i, i + CONCURRENCY) - const results = await Promise.all( - batch.map((sheet) => - sheetToDocument( - accessToken, - spreadsheetId, - metadata.properties.title, - sheet, - modifiedTime - ) - ) - ) - documents.push(...(results.filter(Boolean) as ExternalDocument[])) - } + const documents: ExternalDocument[] = sheets.map((sheet) => ({ + externalId: `${spreadsheetId}__sheet__${sheet.sheetId}`, + title: `${metadata.properties.title} - ${sheet.title}`, + content: '', + contentDeferred: true, + mimeType: 'text/plain', + sourceUrl: `https://docs.google.com/spreadsheets/d/${spreadsheetId}/edit#gid=${sheet.sheetId}`, + contentHash: `gsheets:${spreadsheetId}:${sheet.sheetId}:${modifiedTime ?? ''}`, + metadata: { + spreadsheetId, + spreadsheetTitle: metadata.properties.title, + sheetTitle: sheet.title, + sheetId: sheet.sheetId, + rowCount: sheet.gridProperties?.rowCount, + columnCount: sheet.gridProperties?.columnCount, + ...(modifiedTime ? { modifiedTime } : {}), + }, + })) return { documents, @@ -324,13 +325,15 @@ export const googleSheetsConnector: ConnectorConfig = { return null } - return sheetToDocument( + const doc = await sheetToDocument( accessToken, spreadsheetId, metadata.properties.title, sheetEntry.properties, modifiedTime ) + if (!doc) return null + return { ...doc, contentDeferred: false } }, validateConfig: async ( diff --git a/apps/sim/connectors/hubspot/hubspot.ts b/apps/sim/connectors/hubspot/hubspot.ts index 0a8a669284d..2395784e80d 100644 --- a/apps/sim/connectors/hubspot/hubspot.ts +++ b/apps/sim/connectors/hubspot/hubspot.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { HubspotIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, parseTagDate } from '@/connectors/utils' +import { parseTagDate } from '@/connectors/utils' const logger = createLogger('HubSpotConnector') @@ -140,16 +140,15 @@ function buildRecordContent(objectType: string, properties: Record, objectType: string, portalId: string -): Promise { +): ExternalDocument { const id = record.id as string const properties = (record.properties || {}) as Record const content = buildRecordContent(objectType, properties) - const contentHash = await computeContentHash(content) const title = buildRecordTitle(objectType, properties) const lastModified = @@ -161,7 +160,7 @@ async function recordToDocument( content, mimeType: 'text/plain', sourceUrl: `https://app.hubspot.com/contacts/${portalId}/record/${objectType}/${id}`, - contentHash, + contentHash: `hubspot:${id}:${lastModified ?? ''}`, metadata: { objectType, owner: properties.hubspot_owner_id || undefined, @@ -260,8 +259,8 @@ export const hubspotConnector: ConnectorConfig = { const paging = data.paging as { next?: { after?: string } } | undefined const nextCursor = paging?.next?.after - const documents: ExternalDocument[] = await Promise.all( - results.map((record) => recordToDocument(record, objectType, portalId)) + const documents: ExternalDocument[] = results.map((record) => + recordToDocument(record, objectType, portalId) ) const previouslyFetched = (syncContext?.totalDocsFetched as number) ?? 0 @@ -322,7 +321,7 @@ export const hubspotConnector: ConnectorConfig = { } const record = await response.json() - return recordToDocument(record, objectType, portalId) + return recordToDocument(record as Record, objectType, portalId) }, validateConfig: async ( diff --git a/apps/sim/connectors/intercom/intercom.ts b/apps/sim/connectors/intercom/intercom.ts index 906607e2487..e7e011d83a3 100644 --- a/apps/sim/connectors/intercom/intercom.ts +++ b/apps/sim/connectors/intercom/intercom.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { IntercomIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, htmlToPlainText, parseTagDate } from '@/connectors/utils' +import { htmlToPlainText, parseTagDate } from '@/connectors/utils' const logger = createLogger('IntercomConnector') @@ -309,7 +309,6 @@ export const intercomConnector: ConnectorConfig = { const content = formatArticle(article) if (!content.trim()) continue - const contentHash = await computeContentHash(content) const updatedAt = new Date(article.updated_at * 1000).toISOString() documents.push({ @@ -318,7 +317,7 @@ export const intercomConnector: ConnectorConfig = { content, mimeType: 'text/plain', sourceUrl: `https://app.intercom.com/a/apps/_/articles/articles/${article.id}/show`, - contentHash, + contentHash: `intercom:article-${article.id}:${article.updated_at}`, metadata: { type: 'article', state: article.state, @@ -337,28 +336,23 @@ export const intercomConnector: ConnectorConfig = { const conversations = await fetchConversations(accessToken, maxItems, conversationState) for (const conversation of conversations) { - const detail = await fetchConversationDetail(accessToken, conversation.id) - const content = formatConversation(detail) - if (!content.trim()) continue - - const contentHash = await computeContentHash(content) const updatedAt = new Date(conversation.updated_at * 1000).toISOString() const tags = conversation.tags?.tags?.map((t) => t.name) || [] documents.push({ externalId: `conversation-${conversation.id}`, title: conversation.title || `Conversation #${conversation.id}`, - content, + content: '', + contentDeferred: true, mimeType: 'text/plain', sourceUrl: `https://app.intercom.com/a/apps/_/inbox/inbox/all/conversations/${conversation.id}`, - contentHash, + contentHash: `intercom:conversation-${conversation.id}:${conversation.updated_at}`, metadata: { type: 'conversation', state: conversation.state, tags: tags.join(', '), updatedAt, createdAt: new Date(conversation.created_at * 1000).toISOString(), - messageCount: (detail.conversation_parts?.total_count ?? 0) + 1, }, }) } @@ -383,7 +377,6 @@ export const intercomConnector: ConnectorConfig = { const content = formatArticle(article) if (!content.trim()) return null - const contentHash = await computeContentHash(content) const updatedAt = new Date(article.updated_at * 1000).toISOString() return { @@ -392,7 +385,7 @@ export const intercomConnector: ConnectorConfig = { content, mimeType: 'text/plain', sourceUrl: `https://app.intercom.com/a/apps/_/articles/articles/${article.id}/show`, - contentHash, + contentHash: `intercom:article-${article.id}:${article.updated_at}`, metadata: { type: 'article', state: article.state, @@ -410,7 +403,6 @@ export const intercomConnector: ConnectorConfig = { const content = formatConversation(detail) if (!content.trim()) return null - const contentHash = await computeContentHash(content) const updatedAt = new Date(detail.updated_at * 1000).toISOString() const tags = detail.tags?.tags?.map((t) => t.name) || [] @@ -418,9 +410,10 @@ export const intercomConnector: ConnectorConfig = { externalId, title: detail.title || `Conversation #${detail.id}`, content, + contentDeferred: false, mimeType: 'text/plain', sourceUrl: `https://app.intercom.com/a/apps/_/inbox/inbox/all/conversations/${detail.id}`, - contentHash, + contentHash: `intercom:conversation-${detail.id}:${detail.updated_at}`, metadata: { type: 'conversation', state: detail.state, diff --git a/apps/sim/connectors/jira/jira.ts b/apps/sim/connectors/jira/jira.ts index aaa1218a58f..ea883f77a03 100644 --- a/apps/sim/connectors/jira/jira.ts +++ b/apps/sim/connectors/jira/jira.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { JiraIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, joinTagArray, parseTagDate } from '@/connectors/utils' +import { joinTagArray, parseTagDate } from '@/connectors/utils' import { extractAdfText, getJiraCloudId } from '@/tools/jira/utils' const logger = createLogger('JiraConnector') @@ -33,16 +33,12 @@ function buildIssueContent(fields: Record): string { } /** - * Converts a Jira issue API response to an ExternalDocument. + * Extracts common metadata fields from a Jira issue into an ExternalDocument + * stub with deferred content. The contentHash is metadata-based so it is + * identical whether produced during listing or full fetch. */ -async function issueToDocument( - issue: Record, - domain: string -): Promise { +function issueToStub(issue: Record, domain: string): ExternalDocument { const fields = (issue.fields || {}) as Record - const content = buildIssueContent(fields) - const contentHash = await computeContentHash(content) - const key = issue.key as string const issueType = fields.issuetype as Record | undefined const status = fields.status as Record | undefined @@ -51,14 +47,16 @@ async function issueToDocument( const reporter = fields.reporter as Record | undefined const project = fields.project as Record | undefined const labels = Array.isArray(fields.labels) ? (fields.labels as string[]) : [] + const updated = (fields.updated as string) ?? '' return { externalId: String(issue.id), title: `${key}: ${(fields.summary as string) || 'Untitled'}`, - content, + content: '', + contentDeferred: true, mimeType: 'text/plain', sourceUrl: `https://${domain}/browse/${key}`, - contentHash, + contentHash: `jira:${issue.id}:${updated}`, metadata: { key, issueType: issueType?.name, @@ -74,6 +72,22 @@ async function issueToDocument( } } +/** + * Converts a fully-fetched Jira issue (with description and comments) into an + * ExternalDocument with resolved content. + */ +function issueToFullDocument(issue: Record, domain: string): ExternalDocument { + const stub = issueToStub(issue, domain) + const fields = (issue.fields || {}) as Record + const content = buildIssueContent(fields) + + return { + ...stub, + content, + contentDeferred: false, + } +} + export const jiraConnector: ConnectorConfig = { id: 'jira', name: 'Jira', @@ -162,7 +176,7 @@ export const jiraConnector: ConnectorConfig = { params.append('maxResults', String(Math.min(PAGE_SIZE, remaining))) params.append( 'fields', - 'summary,description,comment,issuetype,status,priority,assignee,reporter,project,labels,created,updated' + 'summary,issuetype,status,priority,assignee,reporter,project,labels,created,updated' ) const url = `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/search?${params.toString()}` @@ -190,9 +204,7 @@ export const jiraConnector: ConnectorConfig = { const issues = (data.issues || []) as Record[] const total = (data.total as number) ?? 0 - const documents: ExternalDocument[] = await Promise.all( - issues.map((issue) => issueToDocument(issue, domain)) - ) + const documents: ExternalDocument[] = issues.map((issue) => issueToStub(issue, domain)) const nextStart = startAt + issues.length const hasMore = nextStart < total && (maxIssues <= 0 || nextStart < maxIssues) @@ -239,7 +251,7 @@ export const jiraConnector: ConnectorConfig = { } const issue = await response.json() - return issueToDocument(issue, domain) + return issueToFullDocument(issue, domain) }, validateConfig: async ( diff --git a/apps/sim/connectors/linear/linear.ts b/apps/sim/connectors/linear/linear.ts index fbcb2dde60e..efe391c7c00 100644 --- a/apps/sim/connectors/linear/linear.ts +++ b/apps/sim/connectors/linear/linear.ts @@ -3,7 +3,7 @@ import { LinearIcon } from '@/components/icons' import type { RetryOptions } from '@/lib/knowledge/documents/utils' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, joinTagArray, parseTagDate } from '@/connectors/utils' +import { joinTagArray, parseTagDate } from '@/connectors/utils' const logger = createLogger('LinearConnector') @@ -278,36 +278,34 @@ export const linearConnector: ConnectorConfig = { const nodes = (issuesConn.nodes || []) as Record[] const pageInfo = issuesConn.pageInfo as Record - const documents: ExternalDocument[] = await Promise.all( - nodes.map(async (issue) => { - const content = buildIssueContent(issue) - const contentHash = await computeContentHash(content) + const documents: ExternalDocument[] = nodes.map((issue) => { + const content = buildIssueContent(issue) + const contentHash = `linear:${issue.id}:${issue.updatedAt}` - const labelNodes = ((issue.labels as Record)?.nodes || []) as Record< - string, - unknown - >[] + const labelNodes = ((issue.labels as Record)?.nodes || []) as Record< + string, + unknown + >[] - return { - externalId: issue.id as string, - title: `${(issue.identifier as string) || ''}: ${(issue.title as string) || 'Untitled'}`, - content, - mimeType: 'text/plain' as const, - sourceUrl: (issue.url as string) || undefined, - contentHash, - metadata: { - identifier: issue.identifier, - state: (issue.state as Record)?.name, - priority: issue.priorityLabel, - assignee: (issue.assignee as Record)?.name, - labels: labelNodes.map((l) => l.name as string), - team: (issue.team as Record)?.name, - project: (issue.project as Record)?.name, - lastModified: issue.updatedAt, - }, - } - }) - ) + return { + externalId: issue.id as string, + title: `${(issue.identifier as string) || ''}: ${(issue.title as string) || 'Untitled'}`, + content, + mimeType: 'text/plain' as const, + sourceUrl: (issue.url as string) || undefined, + contentHash, + metadata: { + identifier: issue.identifier, + state: (issue.state as Record)?.name, + priority: issue.priorityLabel, + assignee: (issue.assignee as Record)?.name, + labels: labelNodes.map((l) => l.name as string), + team: (issue.team as Record)?.name, + project: (issue.project as Record)?.name, + lastModified: issue.updatedAt, + }, + } + }) const hasNextPage = Boolean(pageInfo.hasNextPage) const endCursor = (pageInfo.endCursor as string) || undefined @@ -335,7 +333,7 @@ export const linearConnector: ConnectorConfig = { if (!issue) return null const content = buildIssueContent(issue) - const contentHash = await computeContentHash(content) + const contentHash = `linear:${issue.id}:${issue.updatedAt}` const labelNodes = ((issue.labels as Record)?.nodes || []) as Record< string, @@ -346,7 +344,7 @@ export const linearConnector: ConnectorConfig = { externalId: issue.id as string, title: `${(issue.identifier as string) || ''}: ${(issue.title as string) || 'Untitled'}`, content, - mimeType: 'text/plain', + mimeType: 'text/plain' as const, sourceUrl: (issue.url as string) || undefined, contentHash, metadata: { @@ -379,7 +377,6 @@ export const linearConnector: ConnectorConfig = { } try { - // Verify the token works by fetching teams const data = await linearGraphQL(accessToken, TEAMS_QUERY, undefined, VALIDATE_RETRY_OPTIONS) const teamsConn = data.teams as Record const teams = (teamsConn.nodes || []) as Record[] @@ -391,7 +388,6 @@ export const linearConnector: ConnectorConfig = { } } - // If teamId specified, verify it exists const teamId = sourceConfig.teamId as string | undefined if (teamId) { const found = teams.some((t) => t.id === teamId) diff --git a/apps/sim/connectors/outlook/outlook.ts b/apps/sim/connectors/outlook/outlook.ts index 1c800701caa..d36635d6d9b 100644 --- a/apps/sim/connectors/outlook/outlook.ts +++ b/apps/sim/connectors/outlook/outlook.ts @@ -2,14 +2,37 @@ import { createLogger } from '@sim/logger' import { OutlookIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, htmlToPlainText, parseTagDate } from '@/connectors/utils' +import { htmlToPlainText, parseTagDate } from '@/connectors/utils' const logger = createLogger('OutlookConnector') const GRAPH_API_BASE = 'https://graph.microsoft.com/v1.0/me' const DEFAULT_MAX_CONVERSATIONS = 500 const MESSAGES_PER_PAGE = 50 -const MESSAGE_FIELDS = [ +/** + * Fields requested when listing messages (no body — deferred to getDocument). + */ +const LIST_MESSAGE_FIELDS = [ + 'id', + 'conversationId', + 'subject', + 'from', + 'toRecipients', + 'receivedDateTime', + 'sentDateTime', + 'categories', + 'importance', + 'inferenceClassification', + 'hasAttachments', + 'webLink', + 'isDraft', + 'parentFolderId', +].join(',') + +/** + * Fields requested when fetching full message content in getDocument. + */ +const FULL_MESSAGE_FIELDS = [ 'id', 'conversationId', 'subject', @@ -84,7 +107,7 @@ function buildInitialUrl(sourceConfig: Record): string { const params = new URLSearchParams({ $top: String(MESSAGES_PER_PAGE), - $select: MESSAGE_FIELDS, + $select: LIST_MESSAGE_FIELDS, }) // Build $filter clauses @@ -353,7 +376,6 @@ export const outlookConnector: ConnectorConfig = { const headers: Record = { Authorization: `Bearer ${accessToken}`, Accept: 'application/json', - Prefer: 'outlook.body-content-type="text"', } const response = await fetchWithRetry(url, { method: 'GET', headers }) @@ -385,7 +407,8 @@ export const outlookConnector: ConnectorConfig = { continue } - const convId = msg.conversationId || msg.id + if (!msg.conversationId) continue + const convId = msg.conversationId if (!conversations[convId]) { conversations[convId] = [] } @@ -407,8 +430,8 @@ export const outlookConnector: ConnectorConfig = { } } - // Phase 2: Group conversations into documents - logger.info('Grouping Outlook messages into conversations', { + // Phase 2: Build lightweight stubs — content is deferred to getDocument + logger.info('Building Outlook conversation stubs', { totalMessages: syncContext?._totalMessagesFetched, totalConversations: Object.keys(conversations).length, }) @@ -433,23 +456,26 @@ export const outlookConnector: ConnectorConfig = { const documents: ExternalDocument[] = [] for (const [convId, msgs] of limited) { - const result = formatConversation(convId, msgs) - if (!result) continue + if (msgs.length === 0) continue - const contentHash = await computeContentHash(result.content) + const lastDate = msgs.reduce((max, m) => { + const d = m.receivedDateTime || '' + return d > max ? d : max + }, '') - // Use the first message's webLink as the source URL + const subject = msgs[0].subject || 'No Subject' const firstWithLink = msgs.find((m) => m.webLink) - const sourceUrl = firstWithLink?.webLink || `https://outlook.office.com/mail/inbox` + const sourceUrl = firstWithLink?.webLink || 'https://outlook.office.com/mail/inbox' documents.push({ externalId: convId, - title: result.subject, - content: result.content, + title: subject, + content: '', + contentDeferred: true, mimeType: 'text/plain', sourceUrl, - contentHash, - metadata: result.metadata, + contentHash: `outlook:${convId}:${lastDate}`, + metadata: {}, }) } @@ -462,14 +488,25 @@ export const outlookConnector: ConnectorConfig = { externalId: string ): Promise => { try { - // Fetch messages for this conversation + // Scope to the same folder as listDocuments so contentHash stays consistent + const folder = (sourceConfig.folder as string) || 'inbox' + const basePath = + folder === 'all' + ? `${GRAPH_API_BASE}/messages` + : `${GRAPH_API_BASE}/mailFolders/${WELL_KNOWN_FOLDERS[folder] || folder}/messages` + + const filterParts = [ + `conversationId eq '${externalId.replace(/'/g, "''")}'`, + 'isDraft eq false', + ] + const params = new URLSearchParams({ - $filter: `conversationId eq '${externalId.replace(/'/g, "''")}'`, - $select: MESSAGE_FIELDS, - $top: '50', + $filter: filterParts.join(' and '), + $select: FULL_MESSAGE_FIELDS, + $top: '250', }) - const url = `${GRAPH_API_BASE}/messages?${params.toString()}` + const url = `${basePath}?${params.toString()}` const response = await fetchWithRetry(url, { method: 'GET', @@ -493,16 +530,21 @@ export const outlookConnector: ConnectorConfig = { const result = formatConversation(externalId, messages) if (!result) return null - const contentHash = await computeContentHash(result.content) + const lastDate = messages.reduce((max, m) => { + const d = m.receivedDateTime || '' + return d > max ? d : max + }, '') + const firstWithLink = messages.find((m) => m.webLink) return { externalId, title: result.subject, content: result.content, + contentDeferred: false, mimeType: 'text/plain', sourceUrl: firstWithLink?.webLink || 'https://outlook.office.com/mail/inbox', - contentHash, + contentHash: `outlook:${externalId}:${lastDate}`, metadata: result.metadata, } } catch (error) { diff --git a/apps/sim/connectors/reddit/reddit.ts b/apps/sim/connectors/reddit/reddit.ts index b74a8d4b0b3..ce636ad1be7 100644 --- a/apps/sim/connectors/reddit/reddit.ts +++ b/apps/sim/connectors/reddit/reddit.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { RedditIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, parseTagDate } from '@/connectors/utils' +import { parseTagDate } from '@/connectors/utils' const logger = createLogger('RedditConnector') @@ -338,29 +338,23 @@ export const redditConnector: ConnectorConfig = { afterToken ) - const documents: ExternalDocument[] = [] - - for (const post of posts) { - const content = await formatPostContent(accessToken, post, COMMENTS_PER_POST) - const contentHash = await computeContentHash(content) - - documents.push({ - externalId: post.id, - title: post.title, - content, - mimeType: 'text/plain', - sourceUrl: `https://www.reddit.com${post.permalink}`, - contentHash, - metadata: { - author: post.author, - score: post.score, - commentCount: post.num_comments, - flair: post.link_flair_text ?? undefined, - postDate: new Date(post.created_utc * 1000).toISOString(), - subreddit: post.subreddit, - }, - }) - } + const documents: ExternalDocument[] = posts.map((post) => ({ + externalId: post.id, + title: post.title, + content: '', + contentDeferred: true, + mimeType: 'text/plain', + sourceUrl: `https://www.reddit.com${post.permalink}`, + contentHash: `reddit:${post.id}:${post.created_utc}`, + metadata: { + author: post.author, + score: post.score, + commentCount: post.num_comments, + flair: post.link_flair_text ?? undefined, + postDate: new Date(post.created_utc * 1000).toISOString(), + subreddit: post.subreddit, + }, + })) const totalCollected = collectedSoFar + documents.length const hasMore = after !== null && totalCollected < maxPosts @@ -397,15 +391,15 @@ export const redditConnector: ConnectorConfig = { const comments = data.length >= 2 ? extractComments(data[1] as RedditListing, COMMENTS_PER_POST) : [] const content = await formatPostContent(accessToken, post, COMMENTS_PER_POST, comments) - const contentHash = await computeContentHash(content) return { externalId: post.id, title: post.title, content, + contentDeferred: false, mimeType: 'text/plain', sourceUrl: `https://www.reddit.com${post.permalink}`, - contentHash, + contentHash: `reddit:${post.id}:${post.created_utc}`, metadata: { author: post.author, score: post.score, diff --git a/apps/sim/connectors/salesforce/salesforce.ts b/apps/sim/connectors/salesforce/salesforce.ts index c829187c699..c090ad91559 100644 --- a/apps/sim/connectors/salesforce/salesforce.ts +++ b/apps/sim/connectors/salesforce/salesforce.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { SalesforceIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, htmlToPlainText, parseTagDate } from '@/connectors/utils' +import { htmlToPlainText, parseTagDate } from '@/connectors/utils' const logger = createLogger('SalesforceConnector') @@ -12,7 +12,14 @@ const PAGE_SIZE = 200 /** SOQL field lists per object type. */ const OBJECT_FIELDS: Record = { - KnowledgeArticleVersion: ['Id', 'Title', 'Summary', 'LastModifiedDate', 'ArticleNumber'], + KnowledgeArticleVersion: [ + 'Id', + 'Title', + 'Summary', + 'LastModifiedDate', + 'ArticleNumber', + 'PublishStatus', + ], Case: ['Id', 'Subject', 'Description', 'Status', 'LastModifiedDate', 'CaseNumber'], Account: ['Id', 'Name', 'Description', 'Industry', 'LastModifiedDate'], Opportunity: [ @@ -146,36 +153,52 @@ function getRecordStatus(objectType: string, record: Record): s } /** - * Converts a Salesforce record to an ExternalDocument. + * Creates a lightweight stub for a Salesforce record with metadata-based hash. + * Content is deferred and fetched later via getDocument only for new/changed docs. */ -async function recordToDocument( +function recordToStub( record: Record, objectType: string, instanceUrl: string -): Promise { +): ExternalDocument { const id = record.Id as string - const content = buildRecordContent(objectType, record) - const contentHash = await computeContentHash(content) const title = buildRecordTitle(objectType, record) - + const lastModified = (record.LastModifiedDate as string) || '' const baseUrl = instanceUrl.replace(`/services/data/${API_VERSION}/`, '') return { externalId: id, title, - content, + content: '', + contentDeferred: true, mimeType: 'text/plain', sourceUrl: `${baseUrl}/${id}`, - contentHash, + contentHash: `salesforce:${id}:${lastModified}`, metadata: { objectType, - lastModified: (record.LastModifiedDate as string) || undefined, + lastModified: lastModified || undefined, recordNumber: getRecordNumber(objectType, record), status: getRecordStatus(objectType, record), }, } } +/** + * Builds a full ExternalDocument with content from a Salesforce record. + */ +function recordToDocument( + record: Record, + objectType: string, + instanceUrl: string +): ExternalDocument { + const stub = recordToStub(record, objectType, instanceUrl) + return { + ...stub, + content: buildRecordContent(objectType, record), + contentDeferred: false, + } +} + export const salesforceConnector: ConnectorConfig = { id: 'salesforce', name: 'Salesforce', @@ -257,8 +280,8 @@ export const salesforceConnector: ConnectorConfig = { const records = (data.records || []) as Record[] const nextRecordsUrl = data.nextRecordsUrl as string | undefined - const documents: ExternalDocument[] = await Promise.all( - records.map((record) => recordToDocument(record, objectType, instanceUrl)) + const documents: ExternalDocument[] = records.map((record) => + recordToStub(record, objectType, instanceUrl) ) const previouslyFetched = (syncContext?.totalDocsFetched as number) ?? 0 diff --git a/apps/sim/connectors/servicenow/servicenow.ts b/apps/sim/connectors/servicenow/servicenow.ts index 3aefb66fbdc..ebd33e79056 100644 --- a/apps/sim/connectors/servicenow/servicenow.ts +++ b/apps/sim/connectors/servicenow/servicenow.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { ServiceNowIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, htmlToPlainText, parseTagDate } from '@/connectors/utils' +import { htmlToPlainText, parseTagDate } from '@/connectors/utils' const logger = createLogger('ServiceNowConnector') @@ -184,15 +184,13 @@ function priorityLabel(priority: string | undefined): string { /** * Converts a KB article record to an ExternalDocument. */ -async function kbArticleToDocument( - article: KBArticle, - instanceUrl: string -): Promise { +function kbArticleToDocument(article: KBArticle, instanceUrl: string): ExternalDocument { const title = rawValue(article.short_description) || rawValue(article.number) || article.sys_id const articleText = rawValue(article.text) || rawValue(article.wiki) || '' const content = htmlToPlainText(articleText) - const contentHash = await computeContentHash(content) const sysId = rawValue(article.sys_id as unknown as string) || article.sys_id + const updatedOn = rawValue(article.sys_updated_on) || '' + const contentHash = `servicenow:${sysId}:${updatedOn}` const sourceUrl = `${instanceUrl}/kb_view.do?sys_kb_id=${sysId}` return { @@ -218,10 +216,7 @@ async function kbArticleToDocument( /** * Converts an incident record to an ExternalDocument. */ -async function incidentToDocument( - incident: Incident, - instanceUrl: string -): Promise { +function incidentToDocument(incident: Incident, instanceUrl: string): ExternalDocument { const number = rawValue(incident.number) const shortDesc = rawValue(incident.short_description) const title = number ? `${number}: ${shortDesc || 'Untitled'}` : shortDesc || incident.sys_id @@ -258,8 +253,9 @@ async function incidentToDocument( } const content = parts.join('\n') - const contentHash = await computeContentHash(content) const sysId = rawValue(incident.sys_id as unknown as string) || incident.sys_id + const updatedOn = rawValue(incident.sys_updated_on) || '' + const contentHash = `servicenow:${sysId}:${updatedOn}` const sourceUrl = `${instanceUrl}/incident.do?sys_id=${sysId}` return { @@ -478,8 +474,8 @@ export const servicenowConnector: ConnectorConfig = { const documents: ExternalDocument[] = [] for (const record of result) { const doc = isKB - ? await kbArticleToDocument(record as unknown as KBArticle, instanceUrl) - : await incidentToDocument(record as unknown as Incident, instanceUrl) + ? kbArticleToDocument(record as unknown as KBArticle, instanceUrl) + : incidentToDocument(record as unknown as Incident, instanceUrl) if (doc.content.trim()) { documents.push(doc) @@ -532,8 +528,8 @@ export const servicenowConnector: ConnectorConfig = { const record = result[0] const doc = isKB - ? await kbArticleToDocument(record as unknown as KBArticle, instanceUrl) - : await incidentToDocument(record as unknown as Incident, instanceUrl) + ? kbArticleToDocument(record as unknown as KBArticle, instanceUrl) + : incidentToDocument(record as unknown as Incident, instanceUrl) return doc.content.trim() ? doc : null } catch (error) { diff --git a/apps/sim/connectors/webflow/webflow.ts b/apps/sim/connectors/webflow/webflow.ts index c398ed815f1..b0ee6932fac 100644 --- a/apps/sim/connectors/webflow/webflow.ts +++ b/apps/sim/connectors/webflow/webflow.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { WebflowIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, htmlToPlainText, parseTagDate } from '@/connectors/utils' +import { htmlToPlainText, parseTagDate } from '@/connectors/utils' const logger = createLogger('WebflowConnector') @@ -194,8 +194,8 @@ export const webflowConnector: ConnectorConfig = { } const items = data.items || [] - let documents: ExternalDocument[] = await Promise.all( - items.map((item) => itemToDocument(item, currentCollectionId, collectionName)) + let documents: ExternalDocument[] = items.map((item) => + itemToDocument(item, currentCollectionId, collectionName) ) if (maxItems > 0) { @@ -373,13 +373,14 @@ export const webflowConnector: ConnectorConfig = { /** * Converts a Webflow CMS item to an ExternalDocument. */ -async function itemToDocument( +function itemToDocument( item: WebflowItem, collectionId: string, collectionName: string -): Promise { +): ExternalDocument { const plainText = itemToPlainText(item, collectionName) - const contentHash = await computeContentHash(plainText) + const lastModified = item.lastUpdated || item.lastPublished || item.createdOn || '' + const contentHash = `webflow:${item.id}:${lastModified}` const title = extractItemTitle(item) const slug = (item.fieldData?.slug as string) || '' diff --git a/apps/sim/connectors/wordpress/wordpress.ts b/apps/sim/connectors/wordpress/wordpress.ts index 9f835e52e06..eb079f104a9 100644 --- a/apps/sim/connectors/wordpress/wordpress.ts +++ b/apps/sim/connectors/wordpress/wordpress.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { WordpressIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, htmlToPlainText, joinTagArray, parseTagDate } from '@/connectors/utils' +import { htmlToPlainText, joinTagArray, parseTagDate } from '@/connectors/utils' const logger = createLogger('WordPressConnector') @@ -59,10 +59,10 @@ function extractTagNames(tags: Record): string[] { /** * Converts a WordPress post to an ExternalDocument. */ -async function postToDocument(post: WordPressPost): Promise { +function postToDocument(post: WordPressPost): ExternalDocument { const plainText = htmlToPlainText(post.content) const fullContent = `# ${post.title}\n\n${plainText}` - const contentHash = await computeContentHash(fullContent) + const contentHash = `wordpress:${post.ID}:${post.modified || ''}` const categories = extractCategoryNames(post.categories) const tags = extractTagNames(post.tags) @@ -182,7 +182,7 @@ export const wordpressConnector: ConnectorConfig = { const data = (await response.json()) as WordPressPostsResponse const posts = data.posts || [] - const documents = await Promise.all(posts.map(postToDocument)) + const documents = posts.map(postToDocument) const totalFetched = totalDocsFetched + documents.length if (syncContext) syncContext.totalDocsFetched = totalFetched @@ -226,7 +226,7 @@ export const wordpressConnector: ConnectorConfig = { } const post = (await response.json()) as WordPressPost - return await postToDocument(post) + return postToDocument(post) } catch (error) { logger.warn('Failed to get WordPress document', { externalId, diff --git a/apps/sim/connectors/zendesk/zendesk.ts b/apps/sim/connectors/zendesk/zendesk.ts index d42d016366a..6bdf57e6108 100644 --- a/apps/sim/connectors/zendesk/zendesk.ts +++ b/apps/sim/connectors/zendesk/zendesk.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { ZendeskIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, htmlToPlainText, joinTagArray, parseTagDate } from '@/connectors/utils' +import { htmlToPlainText, joinTagArray, parseTagDate } from '@/connectors/utils' const logger = createLogger('ZendeskConnector') @@ -207,14 +207,11 @@ function formatTicketContent(ticket: ZendeskTicket, comments: ZendeskComment[]): } /** - * Converts an article to an ExternalDocument. + * Converts an article to an ExternalDocument with inline content. + * Articles return body inline from the list API so no deferral is needed. */ -async function articleToDocument( - article: ZendeskArticle, - subdomain: string -): Promise { +function articleToDocument(article: ZendeskArticle, subdomain: string): ExternalDocument { const content = htmlToPlainText(article.body || '') - const contentHash = await computeContentHash(content) return { externalId: `article-${article.id}`, @@ -222,7 +219,7 @@ async function articleToDocument( content, mimeType: 'text/plain', sourceUrl: article.html_url || `https://${subdomain}.zendesk.com/hc/articles/${article.id}`, - contentHash, + contentHash: `zendesk:article:${article.id}:${article.updated_at}`, metadata: { type: 'article', articleId: article.id, @@ -238,23 +235,50 @@ async function articleToDocument( } /** - * Converts a ticket (with comments) to an ExternalDocument. + * Creates a deferred stub for a ticket. Content is not fetched here because + * each ticket requires a separate comments API call. Full content is fetched + * lazily via getDocument only for new/changed documents. + */ +function ticketToStub(ticket: ZendeskTicket, subdomain: string): ExternalDocument { + return { + externalId: `ticket-${ticket.id}`, + title: `Ticket #${ticket.id}: ${ticket.subject}`, + content: '', + contentDeferred: true, + mimeType: 'text/plain', + sourceUrl: `https://${subdomain}.zendesk.com/agent/tickets/${ticket.id}`, + contentHash: `zendesk:ticket:${ticket.id}:${ticket.updated_at}`, + metadata: { + type: 'ticket', + ticketId: ticket.id, + status: ticket.status, + priority: ticket.priority, + tags: ticket.tags, + createdAt: ticket.created_at, + updatedAt: ticket.updated_at, + }, + } +} + +/** + * Converts a ticket (with comments) to a full ExternalDocument. + * Used by getDocument to resolve deferred ticket stubs. */ -async function ticketToDocument( +function ticketToDocument( ticket: ZendeskTicket, comments: ZendeskComment[], subdomain: string -): Promise { +): ExternalDocument { const content = formatTicketContent(ticket, comments) - const contentHash = await computeContentHash(content) return { externalId: `ticket-${ticket.id}`, title: `Ticket #${ticket.id}: ${ticket.subject}`, content, + contentDeferred: false, mimeType: 'text/plain', sourceUrl: `https://${subdomain}.zendesk.com/agent/tickets/${ticket.id}`, - contentHash, + contentHash: `zendesk:ticket:${ticket.id}:${ticket.updated_at}`, metadata: { type: 'ticket', ticketId: ticket.id, @@ -375,8 +399,7 @@ export const zendeskConnector: ConnectorConfig = { for (const article of articles) { if (!article.body?.trim()) continue - const doc = await articleToDocument(article, subdomain) - documents.push(doc) + documents.push(articleToDocument(article, subdomain)) } } @@ -391,21 +414,8 @@ export const zendeskConnector: ConnectorConfig = { ) logger.info(`Fetched ${tickets.length} tickets from Zendesk`) - const BATCH_SIZE = 5 - for (let i = 0; i < tickets.length; i += BATCH_SIZE) { - const batch = tickets.slice(i, i + BATCH_SIZE) - const batchResults = await Promise.all( - batch.map(async (ticket) => { - const comments = await fetchTicketComments( - subdomain, - accessToken, - sourceConfig, - ticket.id - ) - return ticketToDocument(ticket, comments, subdomain) - }) - ) - documents.push(...batchResults) + for (const ticket of tickets) { + documents.push(ticketToStub(ticket, subdomain)) } } diff --git a/helm/sim/values.yaml b/helm/sim/values.yaml index b7b32cb4c4e..2e596c69bcf 100644 --- a/helm/sim/values.yaml +++ b/helm/sim/values.yaml @@ -985,6 +985,15 @@ cronjobs: successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 1 + connectorSync: + enabled: true + name: connector-sync + schedule: "*/5 * * * *" + path: "/api/knowledge/connectors/sync" + concurrencyPolicy: Forbid + successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 1 + # Global CronJob settings image: repository: curlimages/curl