Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ jobs:
files: backend/coverage/lcov.info
flags: backend
name: backend-coverage
fail_ci_if_error: true
fail_ci_if_error: false
verbose: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
Expand Down Expand Up @@ -150,7 +150,7 @@ jobs:
files: contracts/coverage/cobertura.xml
flags: contracts
name: contracts-coverage
fail_ci_if_error: true
fail_ci_if_error: false
verbose: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
Expand Down
40 changes: 32 additions & 8 deletions backend/src/controllers/stream.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,34 +56,58 @@ function sumStringI128(values: string[]): string {
* Create a new stream (stub for on-chain indexing)
*/
export const createStream = async (req: Request, res: Response) => {
// This would typically involve validating the stream already exists on-chain
// or preparing metadata for the frontend to submit the transaction.
// For now, let's allow "registering" a stream if it doesn't exist.
try {
const { streamId, sender, recipient, tokenAddress, ratePerSecond, depositedAmount, startTime } = req.body;

const parsedStreamId = Number.parseInt(streamId, 10);
const parsedStartTime = Number.parseInt(startTime, 10);
const parsedRatePerSecond = BigInt(ratePerSecond);
const parsedDepositedAmount = BigInt(depositedAmount);

if (!Number.isFinite(parsedStreamId)) {
return res.status(400).json({ error: 'Invalid streamId: must be a valid integer' });
}

if (!Number.isFinite(parsedStartTime) || parsedStartTime < 0) {
return res.status(400).json({ error: 'Invalid startTime: must be a non-negative integer' });
}

if (parsedRatePerSecond <= 0n) {
return res.status(400).json({ error: 'Invalid ratePerSecond: must be greater than zero' });
}

if (parsedDepositedAmount <= 0n) {
return res.status(400).json({ error: 'Invalid depositedAmount: must be greater than zero' });
}

const endTime = parsedStartTime + Number(parsedDepositedAmount / parsedRatePerSecond);

const stream = await prisma.stream.upsert({
where: { streamId: parseInt(streamId) },
where: { streamId: parsedStreamId },
update: {
isActive: true,
lastUpdateTime: Math.floor(Date.now() / 1000)
},
create: {
streamId: parseInt(streamId),
streamId: parsedStreamId,
sender,
recipient,
tokenAddress,
ratePerSecond,
depositedAmount,
withdrawnAmount: "0",
startTime: parseInt(startTime),
endTime: parseInt(startTime) + Number(BigInt(depositedAmount) / BigInt(ratePerSecond)),
lastUpdateTime: parseInt(startTime)
startTime: parsedStartTime,
endTime,
lastUpdateTime: parsedStartTime
}
});

return res.status(201).json(stream);
} catch (error) {
if (error instanceof RangeError) {
logger.error('Range error in createStream:', error);
return res.status(400).json({ error: 'Invalid numeric values in request body' });
}
logger.error('Error creating/upserting stream:', error);
return res.status(500).json({ error: 'Internal server error' });
}
Expand Down
52 changes: 38 additions & 14 deletions backend/src/controllers/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,46 @@ export const getUserEvents = async (req: Request, res: Response, next: NextFunct
return res.status(400).json({ error: 'Invalid publicKey parameter' });
}

const events = await prisma.streamEvent.findMany({
where: {
stream: {
OR: [
{ sender: publicKey },
{ recipient: publicKey }
]
}
},
orderBy: { timestamp: 'desc' },
include: {
stream: true
const rawLimit = req.query['limit'];
const rawOffset = req.query['offset'];

const limit = Math.min(
rawLimit && typeof rawLimit === 'string' ? (Number.parseInt(rawLimit, 10) || 50) : 50,
200
);
const offset = rawOffset && typeof rawOffset === 'string' ? (Number.parseInt(rawOffset, 10) || 0) : 0;

const whereClause = {
stream: {
OR: [
{ sender: publicKey },
{ recipient: publicKey }
]
}
};

const [events, total] = await Promise.all([
prisma.streamEvent.findMany({
where: whereClause,
orderBy: { timestamp: 'desc' },
take: limit,
skip: offset,
include: {
stream: true
}
}),
prisma.streamEvent.count({ where: whereClause })
]);

const hasMore = offset + events.length < total;

return res.status(200).json({
data: events,
total,
hasMore,
limit,
offset
});

return res.status(200).json(events);
} catch (error) {
next(error);
}
Expand Down
94 changes: 0 additions & 94 deletions backend/src/routes/events.routes.ts

This file was deleted.

34 changes: 29 additions & 5 deletions backend/src/routes/v1/user.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,47 @@ router.get('/:publicKey', getUser);
* tags:
* - Users
* summary: Fetch user activity history
* description: Returns a chronological history of all stream events associated with the user.
* description: Returns a paginated chronological history of all stream events associated with the user.
* parameters:
* - in: path
* name: publicKey
* required: true
* schema:
* type: string
* description: Stellar public key
* - in: query
* name: limit
* schema:
* type: integer
* default: 50
* maximum: 200
* description: Maximum number of events to return
* - in: query
* name: offset
* schema:
* type: integer
* default: 0
* description: Number of events to skip for pagination
* responses:
* 200:
* description: List of user events
* description: Paginated list of user events
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: '#/components/schemas/StreamEvent'
* type: object
* properties:
* data:
* type: array
* items:
* $ref: '#/components/schemas/StreamEvent'
* total:
* type: integer
* hasMore:
* type: boolean
* limit:
* type: integer
* offset:
* type: integer
* 404:
* description: User not found
*/
Expand Down
Loading