fix(knowledge): fix document processing stuck in processing state (#3857)

* fix(knowledge): fix document processing stuck in processing state

* fix(knowledge): use Promise.allSettled for document dispatch and fix Copilot OAuth context

- Change Promise.all to Promise.allSettled in processDocumentsWithQueue so
  one failed dispatch doesn't abort the entire batch
- Add writeOAuthReturnContext before showing LazyOAuthRequiredModal from
  Copilot tools so useOAuthReturnForWorkflow can handle the return
- Add consumeOAuthReturnContext on modal close to clean up stale context

* fix(knowledge): fix type error in useCredentialRefreshTriggers call

Pass empty string instead of undefined for connectorProviderId fallback
to match the hook's string parameter type.

* upgrade turbo

* fix(knowledge): fix type error in connectors-section useCredentialRefreshTriggers call

Same string narrowing fix as add-connector-modal — pass empty string
fallback for providerId.
This commit is contained in:
Waleed
2026-03-30 20:35:08 -07:00
committed by GitHub
parent 0abeac77e1
commit 7d4dd26760
13 changed files with 240 additions and 151 deletions

View File

@@ -900,7 +900,11 @@ export function KnowledgeBase({
onClick={() => setShowConnectorsModal(true)}
className='flex shrink-0 cursor-pointer items-center gap-1.5 rounded-md px-2 py-1 text-[var(--text-secondary)] text-caption shadow-[inset_0_0_0_1px_var(--border)] transition-colors hover-hover:bg-[var(--surface-3)]'
>
{ConnectorIcon && <ConnectorIcon className='h-[14px] w-[14px]' />}
{connector.status === 'syncing' ? (
<Loader2 className='h-[14px] w-[14px] animate-spin' />
) : (
ConnectorIcon && <ConnectorIcon className='h-[14px] w-[14px]' />
)}
{def?.name || connector.connectorType}
</button>
)

View File

@@ -19,21 +19,17 @@ import {
ModalHeader,
Tooltip,
} from '@/components/emcn'
import { useSession } from '@/lib/auth/auth-client'
import { consumeOAuthReturnContext, writeOAuthReturnContext } from '@/lib/credentials/client-state'
import {
getCanonicalScopesForProvider,
getProviderIdFromServiceId,
type OAuthProvider,
} from '@/lib/oauth'
import { consumeOAuthReturnContext } from '@/lib/credentials/client-state'
import { getProviderIdFromServiceId, type OAuthProvider } from '@/lib/oauth'
import { ConnectorSelectorField } from '@/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/components/connector-selector-field'
import { OAuthRequiredModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal'
import { ConnectCredentialModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/connect-credential-modal'
import { getDependsOnFields } from '@/blocks/utils'
import { CONNECTOR_REGISTRY } from '@/connectors/registry'
import type { ConnectorConfig, ConnectorConfigField } from '@/connectors/types'
import { useCreateConnector } from '@/hooks/queries/kb/connectors'
import { useOAuthCredentials } from '@/hooks/queries/oauth/oauth-credentials'
import type { SelectorKey } from '@/hooks/selectors/types'
import { useCredentialRefreshTriggers } from '@/hooks/use-credential-refresh-triggers'
const SYNC_INTERVALS = [
{ label: 'Every hour', value: 60 },
@@ -69,7 +65,6 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
const [searchTerm, setSearchTerm] = useState('')
const { workspaceId } = useParams<{ workspaceId: string }>()
const { data: session } = useSession()
const { mutate: createConnector, isPending: isCreating } = useCreateConnector()
const connectorConfig = selectedType ? CONNECTOR_REGISTRY[selectedType] : null
@@ -82,10 +77,16 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
[connectorConfig]
)
const { data: credentials = [], isLoading: credentialsLoading } = useOAuthCredentials(
connectorProviderId ?? undefined,
{ enabled: Boolean(connectorConfig) && !isApiKeyMode, workspaceId }
)
const {
data: credentials = [],
isLoading: credentialsLoading,
refetch: refetchCredentials,
} = useOAuthCredentials(connectorProviderId ?? undefined, {
enabled: Boolean(connectorConfig) && !isApiKeyMode,
workspaceId,
})
useCredentialRefreshTriggers(refetchCredentials, connectorProviderId ?? '', workspaceId)
const effectiveCredentialId =
selectedCredentialId ?? (credentials.length === 1 ? credentials[0].id : null)
@@ -263,51 +264,9 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
)
}
const handleConnectNewAccount = useCallback(async () => {
if (!connectorConfig || !connectorProviderId || !workspaceId) return
const userName = session?.user?.name
const integrationName = connectorConfig.name
const displayName = userName ? `${userName}'s ${integrationName}` : integrationName
try {
const res = await fetch('/api/credentials/draft', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
workspaceId,
providerId: connectorProviderId,
displayName,
}),
})
if (!res.ok) {
setError('Failed to prepare credential. Please try again.')
return
}
} catch {
setError('Failed to prepare credential. Please try again.')
return
}
writeOAuthReturnContext({
origin: 'kb-connectors',
knowledgeBaseId,
displayName,
providerId: connectorProviderId,
preCount: credentials.length,
workspaceId,
requestedAt: Date.now(),
})
const handleConnectNewAccount = useCallback(() => {
setShowOAuthModal(true)
}, [
connectorConfig,
connectorProviderId,
workspaceId,
session?.user?.name,
knowledgeBaseId,
credentials.length,
])
}, [])
const filteredEntries = useMemo(() => {
const term = searchTerm.toLowerCase().trim()
@@ -396,40 +355,40 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
) : (
<div className='flex flex-col gap-2'>
<Label>Account</Label>
{credentialsLoading ? (
<div className='flex items-center gap-2 text-[var(--text-muted)] text-small'>
<Loader2 className='h-4 w-4 animate-spin' />
Loading credentials...
</div>
) : (
<Combobox
size='sm'
options={[
...credentials.map(
(cred): ComboboxOption => ({
label: cred.name || cred.provider,
value: cred.id,
icon: connectorConfig.icon,
})
),
{
label: 'Connect new account',
value: '__connect_new__',
icon: Plus,
onSelect: () => {
void handleConnectNewAccount()
},
<Combobox
size='sm'
options={[
...credentials.map(
(cred): ComboboxOption => ({
label: cred.name || cred.provider,
value: cred.id,
icon: connectorConfig.icon,
})
),
{
label:
credentials.length > 0
? `Connect another ${connectorConfig.name} account`
: `Connect ${connectorConfig.name} account`,
value: '__connect_new__',
icon: Plus,
onSelect: () => {
void handleConnectNewAccount()
},
]}
value={effectiveCredentialId ?? undefined}
onChange={(value) => setSelectedCredentialId(value)}
placeholder={
credentials.length === 0
? `No ${connectorConfig.name} accounts`
: 'Select account'
}
/>
)}
},
]}
value={effectiveCredentialId ?? undefined}
onChange={(value) => setSelectedCredentialId(value)}
onOpenChange={(isOpen) => {
if (isOpen) void refetchCredentials()
}}
placeholder={
credentials.length === 0
? `No ${connectorConfig.name} accounts`
: 'Select account'
}
isLoading={credentialsLoading}
/>
</div>
)}
@@ -590,20 +549,23 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
)}
</ModalContent>
</Modal>
{connectorConfig && connectorConfig.auth.mode === 'oauth' && connectorProviderId && (
<OAuthRequiredModal
isOpen={showOAuthModal}
onClose={() => {
consumeOAuthReturnContext()
setShowOAuthModal(false)
}}
provider={connectorProviderId}
toolName={connectorConfig.name}
requiredScopes={getCanonicalScopesForProvider(connectorProviderId)}
newScopes={[]}
serviceId={connectorConfig.auth.provider}
/>
)}
{showOAuthModal &&
connectorConfig &&
connectorConfig.auth.mode === 'oauth' &&
connectorProviderId && (
<ConnectCredentialModal
isOpen={showOAuthModal}
onClose={() => {
consumeOAuthReturnContext()
setShowOAuthModal(false)
}}
provider={connectorProviderId}
serviceId={connectorConfig.auth.provider}
workspaceId={workspaceId}
knowledgeBaseId={knowledgeBaseId}
credentialCount={credentials.length}
/>
)}
</>
)
}

View File

@@ -36,6 +36,7 @@ import {
} from '@/lib/oauth'
import { getMissingRequiredScopes } from '@/lib/oauth/utils'
import { EditConnectorModal } from '@/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/edit-connector-modal'
import { ConnectCredentialModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/connect-credential-modal'
import { OAuthRequiredModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal'
import { CONNECTOR_REGISTRY } from '@/connectors/registry'
import type { ConnectorData, SyncLogData } from '@/hooks/queries/kb/connectors'
@@ -46,6 +47,7 @@ import {
useUpdateConnector,
} from '@/hooks/queries/kb/connectors'
import { useOAuthCredentials } from '@/hooks/queries/oauth/oauth-credentials'
import { useCredentialRefreshTriggers } from '@/hooks/use-credential-refresh-triggers'
const logger = createLogger('ConnectorsSection')
@@ -328,11 +330,16 @@ function ConnectorCard({
const requiredScopes =
connectorDef?.auth.mode === 'oauth' ? (connectorDef.auth.requiredScopes ?? []) : []
const { data: credentials } = useOAuthCredentials(providerId, { workspaceId })
const { data: credentials, refetch: refetchCredentials } = useOAuthCredentials(providerId, {
workspaceId,
})
useCredentialRefreshTriggers(refetchCredentials, providerId ?? '', workspaceId)
const missingScopes = useMemo(() => {
if (!credentials || !connector.credentialId) return []
const credential = credentials.find((c) => c.id === connector.credentialId)
if (!credential) return []
return getMissingRequiredScopes(credential, requiredScopes)
}, [credentials, connector.credentialId, requiredScopes])
@@ -484,15 +491,17 @@ function ConnectorCard({
<Button
variant='active'
onClick={() => {
writeOAuthReturnContext({
origin: 'kb-connectors',
knowledgeBaseId,
displayName: connectorDef?.name ?? connector.connectorType,
providerId: providerId!,
preCount: credentials?.length ?? 0,
workspaceId,
requestedAt: Date.now(),
})
if (connector.credentialId) {
writeOAuthReturnContext({
origin: 'kb-connectors',
knowledgeBaseId,
displayName: connectorDef?.name ?? connector.connectorType,
providerId: providerId!,
preCount: credentials?.length ?? 0,
workspaceId,
requestedAt: Date.now(),
})
}
setShowOAuthModal(true)
}}
className='w-full px-2 py-1 font-medium text-caption'
@@ -510,7 +519,22 @@ function ConnectorCard({
</div>
)}
{showOAuthModal && serviceId && providerId && (
{showOAuthModal && serviceId && providerId && !connector.credentialId && (
<ConnectCredentialModal
isOpen={showOAuthModal}
onClose={() => {
consumeOAuthReturnContext()
setShowOAuthModal(false)
}}
provider={providerId as OAuthProvider}
serviceId={serviceId}
workspaceId={workspaceId}
knowledgeBaseId={knowledgeBaseId}
credentialCount={credentials?.length ?? 0}
/>
)}
{showOAuthModal && serviceId && providerId && connector.credentialId && (
<OAuthRequiredModal
isOpen={showOAuthModal}
onClose={() => {

View File

@@ -14,6 +14,7 @@ import {
ModalHeader,
} from '@/components/emcn'
import { client } from '@/lib/auth/auth-client'
import type { OAuthReturnContext } from '@/lib/credentials/client-state'
import { writeOAuthReturnContext } from '@/lib/credentials/client-state'
import {
getCanonicalScopesForProvider,
@@ -27,17 +28,22 @@ import { useCreateCredentialDraft } from '@/hooks/queries/credentials'
const logger = createLogger('ConnectCredentialModal')
export interface ConnectCredentialModalProps {
interface ConnectCredentialModalBaseProps {
isOpen: boolean
onClose: () => void
provider: OAuthProvider
serviceId: string
workspaceId: string
workflowId: string
/** Number of existing credentials for this provider — used to detect a successful new connection. */
credentialCount: number
}
export type ConnectCredentialModalProps = ConnectCredentialModalBaseProps &
(
| { workflowId: string; knowledgeBaseId?: never }
| { workflowId?: never; knowledgeBaseId: string }
)
export function ConnectCredentialModal({
isOpen,
onClose,
@@ -45,6 +51,7 @@ export function ConnectCredentialModal({
serviceId,
workspaceId,
workflowId,
knowledgeBaseId,
credentialCount,
}: ConnectCredentialModalProps) {
const [displayName, setDisplayName] = useState('')
@@ -97,15 +104,19 @@ export function ConnectCredentialModal({
try {
await createDraft.mutateAsync({ workspaceId, providerId, displayName: trimmedName })
writeOAuthReturnContext({
origin: 'workflow',
workflowId,
const baseContext = {
displayName: trimmedName,
providerId,
preCount: credentialCount,
workspaceId,
requestedAt: Date.now(),
})
}
const returnContext: OAuthReturnContext = knowledgeBaseId
? { ...baseContext, origin: 'kb-connectors' as const, knowledgeBaseId }
: { ...baseContext, origin: 'workflow' as const, workflowId: workflowId! }
writeOAuthReturnContext(returnContext)
if (providerId === 'trello') {
window.location.href = '/api/auth/trello/authorize'

View File

@@ -7,6 +7,7 @@ import { Button, Combobox } from '@/components/emcn/components'
import { getSubscriptionAccessState } from '@/lib/billing/client'
import { getEnv, isTruthy } from '@/lib/core/config/env'
import { getPollingProviderFromOAuth } from '@/lib/credential-sets/providers'
import { consumeOAuthReturnContext, writeOAuthReturnContext } from '@/lib/credentials/client-state'
import {
getCanonicalScopesForProvider,
getProviderIdFromServiceId,
@@ -357,7 +358,18 @@ export function CredentialSelector({
</div>
<Button
variant='active'
onClick={() => setShowOAuthModal(true)}
onClick={() => {
writeOAuthReturnContext({
origin: 'workflow',
workflowId: activeWorkflowId || '',
displayName: selectedCredential?.name ?? getProviderName(provider),
providerId: effectiveProviderId,
preCount: credentials.length,
workspaceId,
requestedAt: Date.now(),
})
setShowOAuthModal(true)
}}
className='w-full px-2 py-1 font-medium text-caption'
>
Update access
@@ -380,7 +392,10 @@ export function CredentialSelector({
{showOAuthModal && (
<OAuthRequiredModal
isOpen={showOAuthModal}
onClose={() => setShowOAuthModal(false)}
onClose={() => {
consumeOAuthReturnContext()
setShowOAuthModal(false)
}}
provider={provider}
toolName={getProviderName(provider)}
requiredScopes={getCanonicalScopesForProvider(effectiveProviderId)}

View File

@@ -4,6 +4,7 @@ import { createElement, useCallback, useMemo, useRef, useState } from 'react'
import { ExternalLink } from 'lucide-react'
import { useParams } from 'next/navigation'
import { Button, Combobox } from '@/components/emcn/components'
import { consumeOAuthReturnContext, writeOAuthReturnContext } from '@/lib/credentials/client-state'
import {
getCanonicalScopesForProvider,
getProviderIdFromServiceId,
@@ -222,7 +223,18 @@ export function ToolCredentialSelector({
</div>
<Button
variant='active'
onClick={() => setShowOAuthModal(true)}
onClick={() => {
writeOAuthReturnContext({
origin: 'workflow',
workflowId: effectiveWorkflowId || '',
displayName: selectedCredential?.name ?? getProviderName(provider),
providerId: effectiveProviderId,
preCount: credentials.length,
workspaceId,
requestedAt: Date.now(),
})
setShowOAuthModal(true)
}}
className='w-full px-2 py-1 font-medium text-caption'
>
Update access
@@ -245,7 +257,10 @@ export function ToolCredentialSelector({
{showOAuthModal && (
<OAuthRequiredModal
isOpen={showOAuthModal}
onClose={() => setShowOAuthModal(false)}
onClose={() => {
consumeOAuthReturnContext()
setShowOAuthModal(false)
}}
provider={provider}
toolName={getProviderName(provider)}
requiredScopes={getCanonicalScopesForProvider(effectiveProviderId)}

View File

@@ -19,6 +19,7 @@ import { createLogger } from '@sim/logger'
import { useShallow } from 'zustand/react/shallow'
import { useSession } from '@/lib/auth/auth-client'
import type { OAuthConnectEventDetail } from '@/lib/copilot/tools/client/base-tool'
import { consumeOAuthReturnContext, writeOAuthReturnContext } from '@/lib/credentials/client-state'
import type { OAuthProvider } from '@/lib/oauth'
import { BLOCK_DIMENSIONS, CONTAINER_DIMENSIONS } from '@/lib/workflows/blocks/block-dimensions'
import { TriggerUtils } from '@/lib/workflows/triggers/triggers'
@@ -478,6 +479,17 @@ const WorkflowContent = React.memo(
const handleOpenOAuthConnect = (event: Event) => {
const detail = (event as CustomEvent<OAuthConnectEventDetail>).detail
if (!detail) return
writeOAuthReturnContext({
origin: 'workflow',
workflowId: workflowIdParam,
displayName: detail.providerName,
providerId: detail.providerId,
preCount: 0,
workspaceId,
requestedAt: Date.now(),
})
setOauthModal({
provider: detail.providerId as OAuthProvider,
serviceId: detail.serviceId,
@@ -490,7 +502,7 @@ const WorkflowContent = React.memo(
window.addEventListener('open-oauth-connect', handleOpenOAuthConnect as EventListener)
return () =>
window.removeEventListener('open-oauth-connect', handleOpenOAuthConnect as EventListener)
}, [])
}, [workflowIdParam, workspaceId])
const { diffAnalysis, isShowingDiff, isDiffReady, reapplyDiffMarkers, hasActiveDiff } =
useWorkflowDiffStore(
@@ -4103,7 +4115,10 @@ const WorkflowContent = React.memo(
<Suspense fallback={null}>
<LazyOAuthRequiredModal
isOpen={true}
onClose={() => setOauthModal(null)}
onClose={() => {
consumeOAuthReturnContext()
setOauthModal(null)
}}
provider={oauthModal.provider}
toolName={oauthModal.providerName}
serviceId={oauthModal.serviceId}

View File

@@ -1,6 +1,7 @@
import { db } from '@sim/db'
import {
document,
embedding,
knowledgeBase,
knowledgeConnector,
knowledgeConnectorSyncLog,
@@ -658,6 +659,23 @@ export async function executeSync(
if (stuckDocs.length > 0) {
logger.info(`Retrying ${stuckDocs.length} stuck documents`, { connectorId })
try {
const stuckDocIds = stuckDocs.map((doc) => doc.id)
await db.delete(embedding).where(inArray(embedding.documentId, stuckDocIds))
await db
.update(document)
.set({
processingStatus: 'pending',
processingStartedAt: null,
processingCompletedAt: null,
processingError: null,
chunkCount: 0,
tokenCount: 0,
characterCount: 0,
})
.where(inArray(document.id, stuckDocIds))
await processDocumentsWithQueue(
stuckDocs.map((doc) => ({
documentId: doc.id,

View File

@@ -156,17 +156,12 @@ export async function dispatchDocumentProcessingJob(payload: DocumentJobData): P
return
}
void processDocumentAsync(
await processDocumentAsync(
payload.knowledgeBaseId,
payload.documentId,
payload.docData,
payload.processingOptions
).catch((error) => {
logger.error(`[${payload.requestId}] Direct document processing failed`, {
documentId: payload.documentId,
error: error instanceof Error ? error.message : String(error),
})
})
)
}
export interface DocumentTagData {
@@ -385,9 +380,27 @@ export async function processDocumentsWithQueue(
}
)
await Promise.all(jobPayloads.map((payload) => dispatchDocumentProcessingJob(payload)))
const results = await Promise.allSettled(
jobPayloads.map((payload) => dispatchDocumentProcessingJob(payload))
)
const failures = results.filter((r): r is PromiseRejectedResult => r.status === 'rejected')
if (failures.length > 0) {
logger.error(`[${requestId}] ${failures.length}/${results.length} document dispatches failed`, {
errors: failures.map((f) =>
f.reason instanceof Error ? f.reason.message : String(f.reason)
),
})
}
logger.info(
`[${requestId}] Document dispatch complete: ${results.length - failures.length}/${results.length} succeeded`
)
if (failures.length === results.length) {
throw new Error(`All ${failures.length} document processing dispatches failed`)
}
logger.info(`[${requestId}] All documents dispatched for processing`)
return
}
@@ -434,6 +447,7 @@ export async function processDocumentAsync(
.set({
processingStatus: 'processing',
processingStartedAt: new Date(),
processingCompletedAt: null,
processingError: null,
})
.where(
@@ -624,8 +638,9 @@ export async function processDocumentAsync(
logger.info(`[${documentId}] Successfully processed document in ${processingTime}ms`)
} catch (error) {
const processingTime = Date.now() - startTime
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
logger.error(`[${documentId}] Failed to process document after ${processingTime}ms:`, {
error: error instanceof Error ? error.message : 'Unknown error',
error: errorMessage,
stack: error instanceof Error ? error.stack : undefined,
filename: docData.filename,
fileUrl: docData.fileUrl,
@@ -636,10 +651,12 @@ export async function processDocumentAsync(
.update(document)
.set({
processingStatus: 'failed',
processingError: error instanceof Error ? error.message : 'Unknown error',
processingError: errorMessage,
processingCompletedAt: new Date(),
})
.where(eq(document.id, documentId))
throw error
}
}
@@ -1527,7 +1544,7 @@ export async function markDocumentAsFailedTimeout(
.update(document)
.set({
processingStatus: 'failed',
processingError: 'Processing timed out - background process may have been terminated',
processingError: 'Processing timed out. Please retry or re-sync the connector.',
processingCompletedAt: now,
})
.where(eq(document.id, documentId))

View File

@@ -101,6 +101,8 @@ async function getEmbeddingConfig(
}
}
const EMBEDDING_REQUEST_TIMEOUT_MS = 60_000
async function callEmbeddingAPI(inputs: string[], config: EmbeddingConfig): Promise<number[][]> {
return retryWithExponentialBackoff(
async () => {
@@ -119,11 +121,15 @@ async function callEmbeddingAPI(inputs: string[], config: EmbeddingConfig): Prom
...(useDimensions && { dimensions: EMBEDDING_DIMENSIONS }),
}
const controller = new AbortController()
const timeout = setTimeout(() => controller.abort(), EMBEDDING_REQUEST_TIMEOUT_MS)
const response = await fetch(config.apiUrl, {
method: 'POST',
headers: config.headers,
body: JSON.stringify(requestBody),
})
signal: controller.signal,
}).finally(() => clearTimeout(timeout))
if (!response.ok) {
const errorText = await response.text()

View File

@@ -1504,7 +1504,9 @@ export async function refreshOAuthToken(
refreshToken: newRefreshToken || refreshToken, // Return new refresh token if available
}
} catch (error) {
logger.error('Error refreshing token:', { error })
logger.error('Error refreshing token:', {
error: error instanceof Error ? error.message : String(error),
})
return null
}
}

View File

@@ -10,7 +10,7 @@
"glob": "13.0.0",
"husky": "9.1.7",
"lint-staged": "16.0.0",
"turbo": "2.8.20",
"turbo": "2.9.1",
},
},
"apps/docs": {
@@ -1483,17 +1483,17 @@
"@trigger.dev/sdk": ["@trigger.dev/sdk@4.4.3", "", { "dependencies": { "@opentelemetry/api": "1.9.0", "@opentelemetry/semantic-conventions": "1.36.0", "@trigger.dev/core": "4.4.3", "chalk": "^5.2.0", "cronstrue": "^2.21.0", "debug": "^4.3.4", "evt": "^2.4.13", "slug": "^6.0.0", "ulid": "^2.3.0", "uncrypto": "^0.1.3", "uuid": "^9.0.0", "ws": "^8.11.0" }, "peerDependencies": { "ai": "^4.2.0 || ^5.0.0 || ^6.0.0", "zod": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["ai"] }, "sha512-ghJkak+PTBJJ9HiHMcnahJmzjsgCzYiIHu5Qj5R7I9q5LS6i7mkx169rB/tOE9HLadd4HSu3yYA5DrH4wXhZuw=="],
"@turbo/darwin-64": ["@turbo/darwin-64@2.8.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-FQ9EX1xMU5nbwjxXxM3yU88AQQ6Sqc6S44exPRroMcx9XZHqqppl5ymJF0Ig/z3nvQNwDmz1Gsnvxubo+nXWjQ=="],
"@turbo/darwin-64": ["@turbo/darwin-64@2.9.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-d1zTcIf6VWT7cdfjhi0X36C2PRsUi2HdEwYzVgkLHmuuYtL+1Y1Zu3JdlouoB/NjG2vX3q4NnKLMNhDOEweoIg=="],
"@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.8.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Gpyh9ATFGThD6/s9L95YWY54cizg/VRWl2B67h0yofG8BpHf67DFAh9nuJVKG7bY0+SBJDAo5cMur+wOl9YOYw=="],
"@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.9.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-AwJ4mA++Kpem33Lcov093hS1LrgqbKxqq5FCReoqsA8ayEG6eAJAo8ItDd9qQTdBiXxZH8GHCspLAMIe1t3Xyw=="],
"@turbo/linux-64": ["@turbo/linux-64@2.8.20", "", { "os": "linux", "cpu": "x64" }, "sha512-p2QxWUYyYUgUFG0b0kR+pPi8t7c9uaVlRtjTTI1AbCvVqkpjUfCcReBn6DgG/Hu8xrWdKLuyQFaLYFzQskZbcA=="],
"@turbo/linux-64": ["@turbo/linux-64@2.9.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HT9SjKkjEw9uvlgly/qwCGEm4wOXOwQPSPS+wkg+/O1Qan3F1uU/0PFYzxl3m4lfuV3CP9wr2Dq5dPrUX+B9Ag=="],
"@turbo/linux-arm64": ["@turbo/linux-arm64@2.8.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-Gn5yjlZGLRZWarLWqdQzv0wMqyBNIdq1QLi48F1oY5Lo9kiohuf7BPQWtWxeNVS2NgJ1+nb/DzK1JduYC4AWOA=="],
"@turbo/linux-arm64": ["@turbo/linux-arm64@2.9.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-+4s5GZs3kjxc1KMhLBhoQy4UBkXjOhgidA9ipNllkA4JLivSqUCuOgU1Xbyp6vzYrsqHJ9vvwo/2mXgEtD6ZHg=="],
"@turbo/windows-64": ["@turbo/windows-64@2.8.20", "", { "os": "win32", "cpu": "x64" }, "sha512-vyaDpYk/8T6Qz5V/X+ihKvKFEZFUoC0oxYpC1sZanK6gaESJlmV3cMRT3Qhcg4D2VxvtC2Jjs9IRkrZGL+exLw=="],
"@turbo/windows-64": ["@turbo/windows-64@2.9.1", "", { "os": "win32", "cpu": "x64" }, "sha512-ZO7GCyQd5HV564XWHc9KysjanFfM3DmnWquyEByu+hQMq42g9OMU/fYOCfHS6Xj2aXkIg2FHJeRV+iAck2YrbQ=="],
"@turbo/windows-arm64": ["@turbo/windows-arm64@2.8.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-voicVULvUV5yaGXo0Iue13BcHGYW3u0VgqSbfQwBaHbpj1zLjYV4KIe+7fYIo6DO8FVUJzxFps3ODCQG/Wy2Qw=="],
"@turbo/windows-arm64": ["@turbo/windows-arm64@2.9.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-BjX2fdz38mBb/H94JXrD5cJ+mEq8NmsCbYdC42JzQebJ0X8EdNgyFoEhOydPGViOmaRmhhdZnPZKKn6wahSpcA=="],
"@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="],
@@ -3629,7 +3629,7 @@
"tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="],
"turbo": ["turbo@2.8.20", "", { "optionalDependencies": { "@turbo/darwin-64": "2.8.20", "@turbo/darwin-arm64": "2.8.20", "@turbo/linux-64": "2.8.20", "@turbo/linux-arm64": "2.8.20", "@turbo/windows-64": "2.8.20", "@turbo/windows-arm64": "2.8.20" }, "bin": { "turbo": "bin/turbo" } }, "sha512-Rb4qk5YT8RUwwdXtkLpkVhNEe/lor6+WV7S5tTlLpxSz6MjV5Qi8jGNn4gS6NAvrYGA/rNrE6YUQM85sCZUDbQ=="],
"turbo": ["turbo@2.9.1", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.1", "@turbo/darwin-arm64": "2.9.1", "@turbo/linux-64": "2.9.1", "@turbo/linux-arm64": "2.9.1", "@turbo/windows-64": "2.9.1", "@turbo/windows-arm64": "2.9.1" }, "bin": { "turbo": "bin/turbo" } }, "sha512-TO9du8MwLTAKoXcGezekh9cPJabJUb0+8KxtpMR6kXdRASrmJ8qXf2GkVbCREgzbMQakzfNcux9cZtxheDY4RQ=="],
"tweetnacl": ["tweetnacl@0.14.5", "", {}, "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="],

View File

@@ -39,7 +39,7 @@
"glob": "13.0.0",
"husky": "9.1.7",
"lint-staged": "16.0.0",
"turbo": "2.8.20"
"turbo": "2.9.1"
},
"lint-staged": {
"*.{js,jsx,ts,tsx,json,css,scss}": [