test(contracts): cover webhook, event-replay, analytics, and notification endpoints - #556
Merged
Xhristin3 merged 3 commits intoAug 27, 2026
Conversation
…tion endpoints Add contract coverage (issue XStreamRollz#534) for the API surfaces that shipped after the contract suite was built: GET /webhooks/:id/deliveries, GET /streams/:id/events (replay, XStreamRollz#396), GET /streams/:id/analytics, and GET /notifications. POST /webhooks was already pinned by create-webhook; the delivery-log contract now exercises the seeded subscription → deliveries chain via the existing placeholder mechanism, so no per-contract setup duplication is introduced. The schemas are tightened to the exact field types the SDK declares for WebhookSubscription/WebhookDelivery — the id/streamId string-vs-number choice and the closed event union — and the SDK consumer test asserts mutual assignability between each schema's zod output type and the SDK interface at compile time, so a server-side type change fails CI in either direction. The SDK also gains listDeliveries(), listStreamEvents(), getStreamAnalytics(), and listNotifications() so the new endpoints are exercised end to end instead of hand-mocked. Provider suite (api) now seeds a recorded stream event and an unread notification so the replay/analytics/notification contracts validate non-empty shapes, and wires the real NotificationsController + in-memory repository into the module. Also carries the same pre-existing bad-merge repairs the contract suite needs to compile and run (auth refresh/isAdmin, gateway authenticate shape, streams pending-event id, duplicate module imports) and removes the stale axios-based SDK client test that the nock-based integration suite supersedes. Closes XStreamRollz#534
api/package.json gained @types/cookie-parser@^1.4.10 (auth refresh work) without a lockfile regeneration, so every `npm ci` in CI fails with EUSAGE. Regenerate the root lockfile to add the missing resolution, sync the stale api/sdk workspace version entries, and prune an unreferenced nested conventional-commits-parser entry.
Contributor
Author
CI status updateNew commit pushed: The CI quality matrix was blocked at the very first step ( Current check status:
|
Xhristin3
approved these changes
Aug 27, 2026
Xhristin3
approved these changes
Aug 27, 2026
Closed
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #534
Adds contract coverage for the API surfaces that shipped after the contract suite was built:
GET /webhooks/:id/deliveries,GET /streams/:id/events(replay, #396),GET /streams/:id/analytics, andGET /notifications(POST /webhookswas already pinned by the existingcreate-webhookcontract). The delivery-log contract exercises the seeded subscription → deliveries chain through the existing placeholder mechanism, so no per-contract setup logic is duplicated in the provider suite. The contract schemas now assert the exact field types the SDK declares forWebhookSubscription/WebhookDelivery— the id/streamId string-vs-number choice and the closed event union — and the SDK consumer test pins that equality at compile time in both directions.Why
The contract suite only pinned streams CRUD and auth.
GET /webhooks/:id/deliveries,GET /streams/:id/events,GET /streams/:id/analytics, andGET /notificationswere unprotected: a response-shape change (e.g. the id/streamId stringification that already bitStream/User) would ship with green provider and consumer tests because neither side asserted the shape. The SDK'sWebhookDeliverytype was hand-maintained against the deliveries endpoint with zero machine-checked coverage.What was built
tests/contracts/src/schemas.tsstreamEventTypeSchema(closed union),streamEventRecordSchema(typed<StreamEventRecord>— string ids pinned),paginatedStreamEventsSchema,streamAnalyticsSchema,notificationSchema,notificationsPageSchema,paginatedWebhookDeliveriesSchema;webhookSubscriptionSchema/webhookDeliverySchemaevents tightened fromz.string()to the closed event uniontests/contracts/src/webhooks.contract.tslist-webhook-deliveries(seeded webhook → its delivery log), ordered beforedelete-webhooktests/contracts/src/streams.contract.tslist-stream-eventsandget-stream-analyticsagainst the seeded streamtests/contracts/src/notifications.contract.tslist-notificationstests/contracts/src/index.tsnotificationsContractsapi/src/contract-provider.spec.tsNotificationsController+ in-memoryNotificationsRepository; seeds one recorded stream event and one unread notification so the new contracts validate non-empty shapesxstreamroll-sdk/src/types.tsStreamAnalytics,Notification,NotificationsPagetypesxstreamroll-sdk/src/client.tslistDeliveries(),listStreamEvents(),getStreamAnalytics(),listNotifications()methodsxstreamroll-sdk/src/index.tsxstreamroll-sdk/__tests__/contract.consumer.test.tsAssertEqualin both directions, via the schema's zod_outputtype so the SDK needs no direct zod dependency)xstreamroll-sdk/README.mdIntegration changes outside
contracts//sdk/refresh()token-string contract +isAdminclaim, gatewayauthenticate()destructuring, streams pending-eventid, duplicate module/import fixes inmain.ts/streams.module.ts/audit.module.ts, and stale specs updated to the contracts their sources implement.xstreamroll-sdk/__tests__/client.test.ts— deleted; it tested the removed axios-based client (did not compile) and is superseded by the nock-basedclient.integration.test.ts.Acceptance criteria coverage
POST /webhooks,GET /webhooks/:id/deliveries,GET /streams/:id/events,GET /streams/:id/analytics, andGET /notifications(contract-provider.spec.ts19/19;contract.consumer.test.ts13/13)WebhookSubscription/WebhookDelivery— including the id/streamId string-vs-number choice and the closed event union (contract.consumer.test.tstype-levelAssertEqualassertions; verified during development: a deliberate schema narrowing ofdelivery.idtonumberfails the consumer suite with TS2344 and the provider suite's schema validation)beforeAll; contracts referencePLACEHOLDERids and execute in array order)cd api && npm testandcd xstreamroll-sdk && npm testnpm run build --workspace=tests/contractssucceeds; CI contract jobs (api provider, sdk consumer) are greenid: z.number()vs SDKstring | number→ TS2344; not committed)Test plan
cd api && npx jest— 444/444 passing (39/39 suites) against a fresh Postgres 16 test DBcd api && npx tsc --noEmit— 0 errors;npx eslint "src/**/*.ts"— 0 errorscd api && npm run build— succeedscd xstreamroll-sdk && npx jest— 72/72 passing (6/6 suites);npm run typecheck— 0 errors;npm run lint— 0 errorscd app && npx jest— 222/222 passing (19/20 suites); the one failing suite (fetch-json.test.ts) fails identically onmain— a Node 24/jsdom incompatibility in a file this PR does not touchnpm run build --workspace=tests/contractsand--workspace=packages/types— succeed; contracts lint/typecheck — cleanEnv vars / Notes
No new environment variables or migrations. The
list-notificationscontract pins numeric notification ids and ISO-string timestamps as they appear on the wire. The type-pinning assertions live in the SDK consumer test and run under ts-jest (CI runs with a fresh cache, so the compile-time check always fires there);npx tsc --noEmitin the SDK only coverssrc/, which is why the assertions live in__tests__.