← Public packages
@kentcdodds/raycast
Raycast launcher: stored execute commands via webhooks (canonical; do not use raycast-shortcuts).
src/webhook.ts
98 lines · 2.9 KB · TypeScriptimport listCommands from './list-commands.ts'
import run, { type RunInput } from './run.ts'
const ROUTER_ACTIONS = new Set(['list-commands', 'run'] as const)
type RouterAction = 'list-commands' | 'run'
function isPlainObject(value: unknown): value is Record<string, unknown> {
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
}
/**
* Ignore GitHub deliveries that may still hit this URL from an old
* webhookUrlApply → kentcdodds/kody-raycast-hooks registration.
*/
function isGithubWebhookNoise(input: Record<string, unknown>): boolean {
const action = typeof input.action === 'string' ? input.action.trim() : ''
if (action === 'list-commands' || action === 'run') return false
if (typeof input.commandId === 'string' && input.commandId.trim()) return false
if (typeof input.code === 'string' && input.code.trim()) return false
if (typeof input.zen === 'string') return true
if ('hook_id' in input || isPlainObject(input.hook)) return true
if (isPlainObject(input.installation)) return true
if (
'repositories_added' in input ||
'repositories_removed' in input ||
'repository_selection' in input
) {
return true
}
if (isPlainObject(input.organization) && isPlainObject(input.sender)) return true
if (
isPlainObject(input.security_advisory) ||
isPlainObject(input.marketplace_purchase) ||
isPlainObject(input.sponsorship)
) {
return true
}
if (isPlainObject(input.repository)) return true
const sender = input.sender
if (
isPlainObject(sender) &&
typeof sender.login === 'string' &&
typeof input.action === 'string'
) {
return true
}
return false
}
export type WebhookInput = {
/** Router action. Required for Raycast / HTTP callers. */
action?: RouterAction | string
includeCode?: boolean
commandId?: string
code?: string
params?: Record<string, unknown>
idempotencyKey?: string
}
/**
* Single inbound webhook router for the Raycast launcher.
* POST params: `{ action: "list-commands" | "run", ... }`.
* Agents should prefer `kody:@kentcdodds/raycast/...` imports over this webhook.
*
* @example
* import webhook from 'kody:@kentcdodds/raycast/webhook'
* await webhook({ action: 'list-commands' })
* await webhook({ action: 'run', commandId: 'ping-discord-general' })
*/
export default async function webhook(input: WebhookInput = {}) {
const record = input as Record<string, unknown>
if (isGithubWebhookNoise(record)) {
return {
ok: true,
ignored: true,
reason: 'github-webhook-event',
}
}
const action = typeof input.action === 'string' ? input.action.trim() : ''
if (!ROUTER_ACTIONS.has(action as RouterAction)) {
throw new Error('Provide action: "list-commands" | "run"')
}
if (action === 'list-commands') {
return await listCommands({ includeCode: Boolean(input.includeCode) })
}
const runInput: RunInput = {
commandId: input.commandId,
code: input.code,
params: input.params,
idempotencyKey: input.idempotencyKey,
}
return await run(runInput)
}