feat(api): add POST /streams/events ingest endpoint and SDK publishEvent - #549
Merged
Xhristin3 merged 2 commits intoAug 24, 2026
Merged
Conversation
Adds an API-key-guarded ingest endpoint that queues stream events for the processing worker via the existing pending-events repository, and wires a matching publishEvent method into the SDK. Contract tests cover the request shape in both the provider and consumer suites. Closes XStreamRollz#514
Contributor
Author
|
@Xhristin3 resolved. |
9 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 #514
Adds an API-key-guarded
POST /streams/eventsingest endpoint that queues stream events for the processing worker, plus a matchingpublishEventmethod on the SDK client. The single most important design decision: the endpoint reuses the existing pending-events repository path (insertPendingEvent) that the worker already drains, so ingest and the existing event lifecycle share one queue rather than introducing a parallel mechanism.Why
The platform could only produce stream events through the API's internal flows; external producers (mobile/web SDKs, server-side integrations) had no authenticated entry point to submit events. The obvious shortcut — a JWT-guarded endpoint — would have coupled event ingestion to end-user auth, which is wrong: ingest is a machine-to-machine surface. The endpoint is guarded by an API key (
X-Stream-Api-Keyheader,STREAM_API_KEYenv) instead, keeping it distinct from user auth while still authenticated.What was built
api/src/streams/dto/ingest-stream-event.dto.tsIngestStreamEventDto: streamId (numeric string), eventType, payload, occurredAt, optional clientEventId. Validation via class-validator. Has matching tests instreams.service.spec.ts/stream-api-key.guard.spec.ts.api/src/streams/stream-api-key.guard.tsStreamApiKeyGuard— checksX-Stream-Api-KeyagainstSTREAM_API_KEY; throwsUnauthorizedExceptionwhen missing/mismatched/unset. Has matchingstream-api-key.guard.spec.ts.api/src/streams/repository/streams.repository.tsinsertPendingEvent+getPendingEventsto the in-memory repository (previously only on the DB repo).api/src/streams/repository/streams-db.repository.tsinsertPendingEvent— persists intostream_datawith a unique constraint onclient_event_id.api/src/streams/streams.service.tsingestEvent()— validates payload shape, dedupes onclientEventId, delegates to repository.api/src/streams/streams.controller.tsPOST /streams/eventshandler with Swagger docs, guarded byStreamApiKeyGuard.api/src/streams/streams.module.tsStreamApiKeyGuardas a provider.tests/contracts/src/schemas.ts+contract.ts+streams.contract.tsingestStreamEventcontract entry + request/response schemas.api/src/contract-provider.spec.tsxstreamroll-sdk/src/types.ts+client.tsStreamConfig.apiKey+publishEvent()— sends the API key header, posts to/streams/events.xstreamroll-sdk/__tests__/contract.consumer.test.ts+client.integration.test.tsxstreamroll-sdk/README.mdapiKeyconfig +publishEvent.api/src/database.integration.spec.tsinsertPendingEventwrites a row and dedupes onclient_event_id.Integration changes outside the module
api/src/contract-provider.spec.ts— added the API-key header injection +STREAM_API_KEYenv so the contract provider can exercise the guarded endpoint.api/src/streams/repository/streams.repository.ts(in-memory) — gained the two pending-event methods so the interface matches the DB repo; both are needed for the service-level tests.Acceptance criteria coverage
POST /streams/eventsendpoint guarded by an API key (stream-api-key.guard.spec.ts— rejects missing/mismatched key,streams.controller.spec.ts— handler delegates)streams-db.repository.tsinsertPendingEvent, proven bydatabase.integration.spec.ts)201with the created event (streams.controller.spec.ts)client_event_id(database.integration.spec.ts— unique constraint test)publishEventthat sends the API key (contract.consumer.test.ts,client.integration.test.ts)tests/contracts/src/streams.contract.ts, provider + consumer suites pass)Test plan
api: npm test— 322/325 passing (3 pre-existing failures:list-streamsid serialization,streams.controllerstaledescriptionexpectation,jwt-secret-validatorenv-dependent — all reproduced on base)xstreamroll-sdk: npm test— 66/67 passing (1 pre-existinggetStreamStatusfixture failure, reproduced on base)--max-warnings=0gate)Env vars / Notes
STREAM_API_KEYis required byconfig/env.tsin non-development environments; deployments must set it before the ingest endpoint can be used.