Skip to content

Commit 77dffee

Browse files
authored
Merge branch 'main' into fix/json-body-limit-and-jwt-exp-validation
2 parents 9935dc8 + f50d60b commit 77dffee

50 files changed

Lines changed: 654 additions & 579 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/dependabot.yml

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ version: 2
22

33
updates:
44
# ── npm: root workspace ────────────────────────────────────────────────────
5+
# flowfi is a single npm workspace (frontend + backend hoisted into one root
6+
# package-lock.json). Dependabot must update from the workspace root so the
7+
# root lockfile CI runs `npm ci` against stays in sync. Per-directory entries
8+
# for /frontend and /backend only touched their package.json without updating
9+
# the root lockfile, so every PR they opened failed `npm ci` with
10+
# "lock file's X does not satisfy Y". One root entry covers all workspaces.
511
- package-ecosystem: "npm"
612
directory: "/"
713
schedule:
@@ -14,32 +20,6 @@ updates:
1420
- "minor"
1521
- "patch"
1622

17-
# ── npm: frontend ──────────────────────────────────────────────────────────
18-
- package-ecosystem: "npm"
19-
directory: "/frontend"
20-
schedule:
21-
interval: "weekly"
22-
day: "monday"
23-
open-pull-requests-limit: 10
24-
groups:
25-
minor-and-patch:
26-
update-types:
27-
- "minor"
28-
- "patch"
29-
30-
# ── npm: backend ───────────────────────────────────────────────────────────
31-
- package-ecosystem: "npm"
32-
directory: "/backend"
33-
schedule:
34-
interval: "weekly"
35-
day: "monday"
36-
open-pull-requests-limit: 10
37-
groups:
38-
minor-and-patch:
39-
update-types:
40-
- "minor"
41-
- "patch"
42-
4323
# ── Cargo: contracts ───────────────────────────────────────────────────────
4424
- package-ecosystem: "cargo"
4525
directory: "/contracts"

.github/workflows/ci.yml

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,6 @@ jobs:
4242
run: npm run test:coverage
4343
working-directory: frontend
4444

45-
- name: Upload frontend coverage to Codecov
46-
uses: codecov/codecov-action@v5
47-
with:
48-
files: frontend/coverage/lcov.info
49-
flags: frontend
50-
name: frontend-coverage
51-
fail_ci_if_error: false
52-
verbose: true
53-
env:
54-
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
55-
5645
- name: Build
5746
run: npm run build
5847
working-directory: frontend

backend/.env.example

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
# Database
22
DATABASE_URL="postgresql://user:password@localhost:5433/flowfi?schema=public"
33

4+
# PostgreSQL pool settings
5+
# Maximum database connections per backend process (default: 10)
6+
PG_POOL_MAX=10
7+
# How long an idle connection stays open before being closed (milliseconds, default: 30000)
8+
PG_IDLE_TIMEOUT_MS=30000
9+
# How long to wait when establishing a new database connection (milliseconds, default: 5000)
10+
PG_CONNECTION_TIMEOUT_MS=5000
11+
# Maximum time a PostgreSQL statement may run before cancellation (milliseconds, default: 30000)
12+
PG_STATEMENT_TIMEOUT_MS=30000
13+
414
# Server
515
PORT=3001
616
NODE_ENV=development

backend/Dockerfile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ COPY package*.json ./
2121
RUN npm install --omit=dev
2222

2323
COPY --from=builder /app/dist ./dist
24-
COPY --from=builder /app/src/generated ./src/generated
24+
COPY --from=builder /app/src/generated ./dist/generated
25+
COPY --from=builder /app/prisma ./prisma
26+
# Prisma 7 reads the schema location and datasource url from prisma.config.ts,
27+
# and the schema's `datasource db {}` block has no inline url. The CI health
28+
# check runs `prisma db push` inside this image, so the config must be present
29+
# too (dotenv is a runtime dependency, so the config loads).
30+
COPY prisma.config.ts ./
2531

2632
EXPOSE 3001
2733

backend/docs/DEPRECATION_POLICY.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,10 @@ X-API-Migration-Path: /v1/streams
148148
- `/streams``/v1/streams`
149149
- `/events``/v1/events`
150150

151-
**Status:** Deprecated (as of 2024-02-21)
151+
**Status:** Removed (deprecated 2024-02-21, sunset 2024-12-31, handlers deleted 2026-06-30)
152152

153-
**Sunset Date:** 2024-12-31
153+
These routes no longer exist in the codebase. Clients still calling the unversioned
154+
paths will receive a 404. Update all callers to use the `/v1/` prefix.
154155

155156
**Migration:**
156157
```javascript

backend/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
"express-rate-limit": "^8.5.2",
3333
"ioredis": "^5.11.1",
3434
"pg": "^8.21.0",
35-
"stellar-sdk": "^13.3.0",
3635
"swagger-jsdoc": "^6.3.0",
3736
"swagger-ui-express": "^5.0.1",
3837
"winston": "^3.11.0",
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- CreateIndex
2+
CREATE INDEX IF NOT EXISTS "Stream_tokenAddress_idx" ON "Stream"("tokenAddress");

backend/prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ model Stream {
5151
5252
@@index([sender])
5353
@@index([recipient])
54+
@@index([tokenAddress])
5455
@@index([streamId])
5556
@@index([isActive])
5657
@@index([isPaused])

backend/prisma/seed.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import pg from 'pg';
21
import { PrismaPg } from '@prisma/adapter-pg';
32
import { PrismaClient } from '../src/generated/prisma/index.js';
3+
import { createPgPool } from '../src/lib/pg-pool.js';
44

5-
const connectionString = process.env.DATABASE_URL;
6-
const pool = new pg.Pool({ connectionString });
5+
const pool = createPgPool();
76
const adapter = new PrismaPg(pool);
87
const prisma = new PrismaClient({ adapter });
98

backend/src/app.ts

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,18 @@ app.use(requestIdMiddleware);
3232
app.disable('x-powered-by');
3333

3434
// Helmet-equivalent core headers without external dependency.
35+
// Strict CSP applied globally; the /api-docs route overrides it below for Swagger UI.
3536
app.use((req: Request, res: Response, next: NextFunction) => {
3637
res.setHeader('X-Content-Type-Options', 'nosniff');
3738
res.setHeader('X-Frame-Options', 'DENY');
3839
res.setHeader('Referrer-Policy', 'no-referrer');
3940
res.setHeader('X-DNS-Prefetch-Control', 'off');
4041
res.setHeader('X-Download-Options', 'noopen');
4142
res.setHeader('X-Permitted-Cross-Domain-Policies', 'none');
42-
if (isProduction) {
43+
res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; frame-ancestors 'none'; object-src 'none'");
44+
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
45+
res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
46+
if (process.env.NODE_ENV === 'production') {
4347
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
4448
}
4549
next();
@@ -78,7 +82,11 @@ app.use(express.json({ limit: '1mb' }));
7882
app.use(sandboxMiddleware);
7983

8084
// Swagger UI setup
81-
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, {
85+
// Override CSP for /api-docs only: Swagger UI requires inline scripts/styles.
86+
app.use('/api-docs', (req: Request, res: Response, next: NextFunction) => {
87+
res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'; object-src 'none'");
88+
next();
89+
}, swaggerUi.serve, swaggerUi.setup(swaggerSpec, {
8290
customCss: '.swagger-ui .topbar { display: none }',
8391
customSiteTitle: 'FlowFi API Documentation',
8492
}));
@@ -105,35 +113,6 @@ app.use((req: Request, res: Response, next: NextFunction) => {
105113
return next(); // Not versioned, continue to deprecated handlers
106114
});
107115

108-
// Legacy routes (deprecated - redirect to v1)
109-
// These will be removed in a future version
110-
// Only match unversioned requests
111-
app.use('/streams', (req: Request, res: Response, next) => {
112-
res.status(410).json({
113-
error: 'Deprecated endpoint',
114-
message: 'This endpoint has been deprecated. Please use /v1/streams instead.',
115-
deprecated: true,
116-
migration: {
117-
old: '/streams',
118-
new: '/v1/streams',
119-
},
120-
sunsetDate: '2024-12-31',
121-
});
122-
});
123-
124-
app.use('/events', (req: Request, res: Response, next) => {
125-
res.status(410).json({
126-
error: 'Deprecated endpoint',
127-
message: 'This endpoint has been deprecated. Please use /v1/events instead.',
128-
deprecated: true,
129-
migration: {
130-
old: '/events',
131-
new: '/v1/events',
132-
},
133-
sunsetDate: '2024-12-31',
134-
});
135-
});
136-
137116
// Health check routes
138117
app.use('/health', healthRoutes);
139118

0 commit comments

Comments
 (0)