Something went wrong. Try again.
Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol.
Something went wrong. Try again.
3.3 kB · 83 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384import { describe, expect, test } from 'bun:test'import { isWebhookOwnerAtCapacity, MAX_WEBHOOK_LIST_LIMIT, normalizeWebhookListLimit, validateWebhookCreateInput, type WebhookCreateInput,} from './webhook-policy'
const did = 'did:plc:aaaaaaaaaaaaaaaaaaaaaaaa'const valid = { scopeAturi: `at://${did}`, url: 'https://receiver.example/hook', events: ['create', 'update'] as const,}
describe('main webhook API policy', () => { test('accepts a canonical DID-only scope and HTTPS endpoint', () => { const result = validateWebhookCreateInput(valid, { allowLoopbackDev: false }) expect(result.ok).toBe(true) if (result.ok) expect(result.record.scope.aturi).toBe(valid.scopeAturi) })
test('rejects HTTP, handle scopes, duplicate/oversized events, and conflicting secret forms before PDS writes', () => { const invalidInputs: WebhookCreateInput[] = [ { ...valid, url: 'http://receiver.example/hook' }, { ...valid, scopeAturi: 'at://alice.example' }, { ...valid, events: ['create', 'create'] }, { ...valid, events: ['create', 'update', 'delete', 'create'] }, { ...valid, secret: 'inline', secretId: 'managed' }, { ...valid, secret: 'x'.repeat(257) }, { ...valid, secretId: 'x'.repeat(65) }, { ...valid, secretId: 'secret-☃' }, { ...valid, secretId: 'secret/name' }, { ...valid, secretId: 'secret%2Fname' }, { ...valid, url: `https://receiver.example/${'x'.repeat(2_049)}` }, { ...valid, scopeAturi: `at://${did}/${'x'.repeat(2_049)}` }, ] for (const input of invalidInputs) { expect(validateWebhookCreateInput(input, { allowLoopbackDev: false }).ok).toBe(false) } })
test('uses the same exact secret-ID boundary as secret management', () => { expect(validateWebhookCreateInput({ ...valid, secretId: 'a'.repeat(64) }, { allowLoopbackDev: false }).ok).toBe( true, ) })
test('permits HTTP only for explicitly enabled loopback development', () => { expect( validateWebhookCreateInput({ ...valid, url: 'http://127.0.0.1:43123/hook' }, { allowLoopbackDev: false }).ok, ).toBe(false) expect( validateWebhookCreateInput({ ...valid, url: 'http://127.0.0.1:43123/hook' }, { allowLoopbackDev: true }).ok, ).toBe(true) expect( validateWebhookCreateInput({ ...valid, url: 'http://not-loopback.example/hook' }, { allowLoopbackDev: true }).ok, ).toBe(false) })
test('passes backlinksOnly through and rejects it alongside backlinks: false', () => { const result = validateWebhookCreateInput({ ...valid, backlinksOnly: true }, { allowLoopbackDev: false }) expect(result.ok).toBe(true) if (result.ok) expect(result.record.scope.backlinksOnly).toBe(true) expect( validateWebhookCreateInput({ ...valid, backlinks: false, backlinksOnly: true }, { allowLoopbackDev: false }).ok, ).toBe(false) })
test('enforces the owner quota at exactly 50 records', () => { expect(isWebhookOwnerAtCapacity(49)).toBe(false) expect(isWebhookOwnerAtCapacity(50)).toBe(true) expect(isWebhookOwnerAtCapacity(51)).toBe(true) })
test('bounds public webhook list pages', () => { expect(normalizeWebhookListLimit(undefined)).toBe(MAX_WEBHOOK_LIST_LIMIT) expect(normalizeWebhookListLimit(0)).toBe(MAX_WEBHOOK_LIST_LIMIT) expect(normalizeWebhookListLimit(1)).toBe(1) expect(normalizeWebhookListLimit(10_000)).toBe(MAX_WEBHOOK_LIST_LIMIT) })})