Skip to content

feat: streaming client methods + types [AMB-3016] - #46

Draft
bufo24 wants to merge 1 commit into
mainfrom
jesseva/amb-3016-sdk-streaming-client-methods-types
Draft

feat: streaming client methods + types [AMB-3016]#46
bufo24 wants to merge 1 commit into
mainfrom
jesseva/amb-3016-sdk-streaming-client-methods-types

Conversation

@bufo24

@bufo24 bufo24 commented Aug 21, 2026

Copy link
Copy Markdown
Member

Summary

Adds transactions.watch(id) and wallets.watchEvents(id) to @ambosstech/payments: mint a short-lived stream token via GraphQL, then open a plain fetch-based text/event-stream reader (no EventSource — works in Node and browsers), yielding the same PaymentEvent shape webhooks already use.

  • Transactions.watch(id, options?)AsyncIterable<PaymentEvent> for GET /payments/stream/transactions/:id.
  • Wallets.watchEvents(id, options?)AsyncIterable<PaymentEvent> for GET /payments/stream/wallets/:id.
  • Shared watchPaymentEventStream (src/resources/streaming.ts) does mint → fetch → SSE-parse → yield for both; src/resources/sseParser.ts is a standalone, unit-tested text/event-stream line parser (manual getReader()/TextDecoder loop, portable to browsers).
  • Auth: the stream token travels as Authorization: Bearer <token> (not ?token=) since a fetch-based client can set headers, unlike browser EventSource — lower exposure than a query string per the design doc's own reasoning.
  • Errors before/during the stream surface as this SDK's existing ApiError (401/404 pre-stream HTTP rejection) / NetworkError (transport failure, malformed payload, or an aborted options.signal) — no new error type.
  • A stream_closed control event (sent before the server closes a stream for a reason other than transaction-terminal state) ends iteration without being yielded as a PaymentEvent.

Two unmerged cross-repo dependencies

  1. amboss-rails-api#565 (unmerged) — adds payment.mutation.stream_token.mint(input: MintStreamTokenInput!): StreamToken! to the live schema. This SDK's GraphQL codegen generates typed operations from a static checked-in schema snapshot refreshed only against live production, so it genuinely cannot generate types for a mutation that isn't deployed yet. The mint call is therefore hand-authored as a plain query string in src/resources/streamToken.ts, with hand-written types in src/resources/streamToken.types.ts — verified field-for-field against schema.gql in PR #565 (StreamTokenMutations.mint(input): StreamToken!, StreamToken { token, expires_at }, flat, not wrapped). Names match the eventual generated types exactly.
    • Follow-up once #565 merges and deploys: run pnpm --filter @ambosstech/core run refresh-schema && pnpm --filter @ambosstech/payments run codegen, then delete streamToken.ts + streamToken.types.ts in favor of the generated MintStreamToken operation. Both files carry a TODO(AMB-3016) marking this.
  2. amboss-rails-api#564 (unmerged, design doc) — specifies the SSE endpoint contract this PR implements against: GET /payments/stream/{transactions,wallets}/:id?token=..., the text/event-stream shape (mirrors PaymentEvent verbatim, no parallel type), 15s heartbeats, 60s token TTL / 30-minute max stream lifetime, and how each stream ends (transaction stream closes after a terminal status; wallet/environment stream has no terminal state and stays open until lifetime expiry or disconnect).

Scope

Client methods + types only, per AMB-3016. Not included (separate tickets):

  • README.md / docs/INTEGRATION.md / AGENTS.md resource-table updates (AMB-3018).
  • Runnable example script + CI example test (AMB-3017).

Test plan

  • pnpm build — passes (core then payments)
  • pnpm typecheck — passes
  • pnpm test — passes, including new unit tests:
    • src/resources/sseParser.test.ts — SSE line-parsing (id/event/data fields, multi-line data, heartbeat comments, chunk reassembly, multiple events, no-trailing-blank-line)
    • src/resources/streaming.test.tsTransactions.watch/Wallets.watchEvents end-to-end (mint → fetch → yield), stream_closed handling, pre-stream 401 → ApiError, aborted signalNetworkError
  • pnpm format:check — passes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant