feat: implement StreamCreated handler#43
Conversation
- Add StreamCreated event handler for parsing Soroban events - Map event payload to Stream record with event identity tracking - Add deterministic event identity for idempotency checks - Add mocked payload tests covering: - Payload parsing and validation - Event identity derivation - Record mapping - Handler idempotency - Multiple stream ID handling
|
@d3vobed Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
📝 WalkthroughWalkthroughAdds StreamCreated event types, payload validation, identity generation, record mapping, handler composition, package exports, and Vitest coverage for parsing and handler behavior. ChangesStreamCreated handler
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@indexer/streams/src/handlers/streamCreated.ts`:
- Around line 22-31: The StreamCreated handler currently trusts a type cast
after JSON.parse, so invalid shapes can still produce a malformed StreamRecord.
Update the logic in streamCreated.ts, around the parsed payload handling in the
StreamCreatedPayload flow, to perform a real runtime validation of the parsed
object before building the return value. Use the existing streamCreated event
handler path to reject or guard against missing or wrong-typed streamId, sender,
recipient, amount, startTime, and endTime fields, and only return the record
once validation passes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: cc30f585-3708-4e5f-b38f-f39951ab7f30
📒 Files selected for processing (4)
indexer/streams/src/handlers/streamCreated.test.tsindexer/streams/src/handlers/streamCreated.tsindexer/streams/src/handlers/types.tsindexer/streams/src/index.ts
Add runtime validation for all required fields (streamId, sender, recipient, amount, startTime, endTime) per PR review feedback. Previously relied solely on TypeScript type assertion which does not enforce shape at runtime. Now validates field presence, type, and non-empty constraint with clear error messages.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@indexer/streams/src/handlers/streamCreated.test.ts`:
- Around line 64-99: The negative coverage for parseStreamCreatedPayload is
missing a valid JSON payload with the wrong top-level shape, so add tests in
streamCreated.test for a case like null and ideally another non-object JSON
value. Harden parseStreamCreatedPayload in streamCreated to validate that
JSON.parse returns a non-null object before reading fields, and throw the same
intended validation error instead of letting a raw TypeError escape. Keep the
existing field validation path for streamId, amount, and recipient after the
shape check.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 78a38b2b-57d1-4a94-b612-8ab650892627
📒 Files selected for processing (2)
indexer/streams/src/handlers/streamCreated.test.tsindexer/streams/src/handlers/streamCreated.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- indexer/streams/src/handlers/streamCreated.ts
| test("throws on invalid JSON data", () => { | ||
| const event = createMockEvent({ data: "not-json" }); | ||
|
|
||
| expect(() => parseStreamCreatedPayload(event)).toThrow( | ||
| "Failed to parse event data: invalid JSON", | ||
| ); | ||
| }); | ||
|
|
||
| test("throws on missing streamId field", () => { | ||
| const { streamId: _, ...partial } = mockPayload; | ||
| const event = createMockEvent({ data: JSON.stringify(partial) }); | ||
|
|
||
| expect(() => parseStreamCreatedPayload(event)).toThrow( | ||
| 'Invalid payload: "streamId" must be a non-empty string', | ||
| ); | ||
| }); | ||
|
|
||
| test("throws on non-string amount field", () => { | ||
| const event = createMockEvent({ | ||
| data: JSON.stringify({ ...mockPayload, amount: 12345 }), | ||
| }); | ||
|
|
||
| expect(() => parseStreamCreatedPayload(event)).toThrow( | ||
| 'Invalid payload: "amount" must be a non-empty string', | ||
| ); | ||
| }); | ||
|
|
||
| test("throws on empty string recipient", () => { | ||
| const event = createMockEvent({ | ||
| data: JSON.stringify({ ...mockPayload, recipient: "" }), | ||
| }); | ||
|
|
||
| expect(() => parseStreamCreatedPayload(event)).toThrow( | ||
| 'Invalid payload: "recipient" must be a non-empty string', | ||
| ); | ||
| }); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
Add a non-object JSON payload case.
These negative tests still miss valid JSON with the wrong top-level shape, e.g. data: "null". In indexer/streams/src/handlers/streamCreated.ts:22-39, JSON.parse would succeed and the subsequent parsed[field] access would throw a raw TypeError instead of the intended validation error. Please add a case for null (and ideally another non-object shape) and harden the parser accordingly.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@indexer/streams/src/handlers/streamCreated.test.ts` around lines 64 - 99, The
negative coverage for parseStreamCreatedPayload is missing a valid JSON payload
with the wrong top-level shape, so add tests in streamCreated.test for a case
like null and ideally another non-object JSON value. Harden
parseStreamCreatedPayload in streamCreated to validate that JSON.parse returns a
non-null object before reading fields, and throw the same intended validation
error instead of letting a raw TypeError escape. Keep the existing field
validation path for streamId, amount, and recipient after the shape check.
|
Hi Chief @d3vobed Thank you for your awesome contribution, however after analyzing your implementation, there is a minor fixes and merge conflict to be fixed. Kindly fix them to merge your PR asap. Also do not forget to use fundable.finance to offramp. |
Summary
Implements the
StreamCreatedevent handler for the payment streams domain as specified in #34.Changes
parseStreamCreatedPayloadvalidates the event topic matchesStreamCreatedand extracts the structured payload (streamId,sender,recipient,amount,startTime,endTime)mapStreamCreatedToRecordcombines the parsed payload with event identity metadata into aStreamRecordgetEventIdentityproduces a deterministic string fromcontractId:ledger:txHash:eventIndexfor idempotency checkshandleStreamCreatedcomposes the above into a single call, returning both the stream record and identityTesting
Verification
bun run indexer:type-check✅bun run indexer:test✅ (10 tests)bun run indexer:lint✅Closes #34
Summary by CodeRabbit