Skip to content

Commit a37dc4d

Browse files
committed
fix(webhooks): keep the Ashby error extractor local to the provider
Importing the shared extractor from @/tools/ashby/utils failed check:tool-registry-boundary. Two separate reasons, both real: An import edge from lib/webhooks/providers into @/tools/** grows the workspace page graphs that reach the providers, because @/tools/types statically reaches @/lib/oauth, the rate limiter and the executor. And carving the helper into its own file did not help either: the knowledge page graph already sits exactly at the +42 ceiling the audit allows, so one more module anywhere it can reach is one too many. So the logic is duplicated across the subsystem boundary rather than shared across it, with a comment on both sides saying why. Both copies derive from the same three documented Ashby error shapes and are covered independently.
1 parent db5dee4 commit a37dc4d

1 file changed

Lines changed: 45 additions & 1 deletion

File tree

apps/sim/lib/webhooks/providers/ashby.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,51 @@ import type {
1616
WebhookProviderHandler,
1717
} from '@/lib/webhooks/providers/types'
1818
import { buildFallbackDeliveryFingerprint } from '@/lib/webhooks/providers/utils'
19-
import { ashbyErrorMessage } from '@/tools/ashby/utils'
19+
20+
/**
21+
* Kept local rather than imported from `@/tools/ashby/utils`, which has the same
22+
* logic. The webhook providers are reachable from workspace page graphs, and the
23+
* knowledge page graph currently sits exactly at the ceiling
24+
* `check:tool-registry-boundary` allows - so neither an import edge into
25+
* `@/tools/**` nor an extra module in this directory fits. Both copies derive
26+
* from the same three documented Ashby error shapes and are covered
27+
* independently by `tools/ashby/utils.test.ts` and `ashby.test.ts` here.
28+
*/
29+
/**
30+
* Extract a human-readable error message from an Ashby error response. Ashby
31+
* documents two shapes and uses three in practice:
32+
*
33+
* - `errorInfo: { code, message, requestId }`
34+
* - `errors: ['webhook_not_found']` - plain strings
35+
* - `errors: [{ message, parameter }]` - objects, which is the form a 403 for a
36+
* missing module permission arrives in, and which stringifies to
37+
* `[object Object]` unless the message is read explicitly
38+
*
39+
* A single response can carry more than one of these at once.
40+
*/
41+
function ashbyErrorMessage(data: unknown, fallback: string): string {
42+
if (!data || typeof data !== 'object') return fallback
43+
const d = data as Record<string, unknown>
44+
const info = d.errorInfo as Record<string, unknown> | undefined
45+
if (info && typeof info.message === 'string' && info.message) return info.message
46+
if (Array.isArray(d.errors) && d.errors.length > 0) {
47+
const messages = d.errors
48+
.map((e) => {
49+
if (typeof e === 'string') return e
50+
if (e && typeof e === 'object') {
51+
const entry = e as Record<string, unknown>
52+
const message = typeof entry.message === 'string' ? entry.message : ''
53+
const parameter = typeof entry.parameter === 'string' ? entry.parameter : ''
54+
if (message && parameter) return `${message} (${parameter})`
55+
if (message) return message
56+
}
57+
return ''
58+
})
59+
.filter(Boolean)
60+
if (messages.length > 0) return messages.join('; ')
61+
}
62+
return fallback
63+
}
2064

2165
const logger = createLogger('WebhookProvider:Ashby')
2266

0 commit comments

Comments
 (0)