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
72 changes: 58 additions & 14 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,37 +1,81 @@
# Required - App
# ─── App ─────────────────────────────────────────────────────────────────────
# REQUIRED in production; defaults to 'development'
NODE_ENV=development

# REQUIRED in production; defaults to 3001
PORT=3001

# Required - Database
# ─── Database ─────────────────────────────────────────────────────────────────
# REQUIRED — must be a valid PostgreSQL URL
DATABASE_URL=postgresql://postgres:password@localhost:5432/orbitstream

# Required - Redis
# ─── Redis ────────────────────────────────────────────────────────────────────
# REQUIRED — must be a valid Redis URL
REDIS_URL=redis://localhost:6379

# Required - Auth
# ─── Auth / JWT ───────────────────────────────────────────────────────────────
# REQUIRED — minimum 32 characters; generate with: openssl rand -base64 48
JWT_SECRET=change-me-to-a-random-32-char-string-minimum

# OPTIONAL — token lifetime; defaults to '7d'
JWT_EXPIRES_IN=7d

# Required - Stellar
# OPTIONAL — previous JWT secret, accepted during key rotation window
JWT_SECRET_PREVIOUS=

# ─── Stellar ──────────────────────────────────────────────────────────────────
# REQUIRED — 'testnet' or 'mainnet'
STELLAR_NETWORK=testnet

# REQUIRED — Horizon API base URL
STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org

# OPTIONAL — explicit network passphrase; derived from STELLAR_NETWORK if absent
STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015

# Required - Platform
# Your Stellar public key for receiving payments.
# ─── Stellar auth secrets (at least one required for auth to work) ─────────────
# Fallback secret key used when network-specific keys are absent
STELLAR_PLATFORM_SECRET_KEY=

# Network-specific overrides (take precedence over STELLAR_PLATFORM_SECRET_KEY)
TESTNET_AUTH_SECRET_KEY=
MAINNET_AUTH_SECRET_KEY=

# ─── Platform ─────────────────────────────────────────────────────────────────
# REQUIRED — Stellar public key (starts with G) that receives payments
PLATFORM_RECEIVING_ACCOUNT=G...

# REQUIRED in production; defaults to 'http://localhost:3000'
FRONTEND_URL=http://localhost:3000

# Optional
# REQUIRED in production; defaults to 'http://localhost:3001'
PLATFORM_DOMAIN=http://localhost:3001

# ─── Checkout ─────────────────────────────────────────────────────────────────
# OPTIONAL — session TTL in minutes; defaults to 30
CHECKOUT_SESSION_TTL_MINUTES=30

# OPTIONAL — SEP-10 auth challenge TTL in seconds; defaults to 300
CHALLENGE_TTL_SECONDS=300

# ─── CORS ─────────────────────────────────────────────────────────────────────
# OPTIONAL — comma-separated list of allowed merchant origins
CORS_ALLOWED_ORIGINS=http://localhost:3000
JWT_SECRET_PREVIOUS=
PLATFORM_DOMAIN=http://localhost:3001
STELLAR_RPC_URL=https://soroban-testnet.stellar.org
STREAM_CONTRACT_ID=
TREASURY_CONTRACT_ID=

# ─── Redis cursor ─────────────────────────────────────────────────────────────
# OPTIONAL — Horizon payment cursor TTL in Redis; defaults to 24h
REDIS_CURSOR_TTL_HOURS=24

# ─── Webhook worker ───────────────────────────────────────────────────────────
# OPTIONAL — poll interval in ms; defaults to 250
WEBHOOK_POLL_MS=250

# OPTIONAL — max concurrent deliveries; defaults to 100
WEBHOOK_MAX_CONCURRENCY=100

# OPTIONAL — set to 'true' to disable the webhook worker process
WEBHOOK_WORKER_DISABLED=false
WS_CORS_ORIGIN=http://localhost:3000

# ─── Security ─────────────────────────────────────────────────────────────────
# OPTIONAL — override the default Content-Security-Policy header value
CONTENT_SECURITY_POLICY=
4 changes: 4 additions & 0 deletions jest-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ process.env.DATABASE_URL = 'postgresql://test:test@localhost:5432/test';
process.env.REDIS_URL = 'redis://localhost:6379';
process.env.JWT_SECRET = 'test-secret-with-at-least-32-characters';
process.env.PLATFORM_DOMAIN = 'http://localhost:3001';
process.env.STELLAR_NETWORK = 'testnet';
process.env.STELLAR_HORIZON_URL = 'https://horizon-testnet.stellar.org';
process.env.PLATFORM_RECEIVING_ACCOUNT =
'GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5';
17 changes: 16 additions & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,27 @@ import type { Config } from 'jest';
const config: Config = {
moduleFileExtensions: ['js', 'json', 'ts'],
rootDir: 'src',
// Default: run all specs (unit + integration together)
testRegex: '.*\\.spec\\.ts$',
transform: {
'^.+\\.ts$': 'ts-jest',
},
collectCoverageFrom: ['**/*.ts', '!main.ts', '!index.ts', '!**/*.module.ts'],
collectCoverageFrom: [
'**/*.ts',
'!main.ts',
'!index.ts',
'!**/*.module.ts',
'!**/*.dto.ts',
'!**/*.constants.ts',
'!db/schema.ts',
],
coverageDirectory: '../coverage',
coverageThreshold: {
global: { lines: 0, functions: 0, branches: 0 },
'./auth/**/*.ts': { lines: 80, functions: 80, branches: 80 },
'./checkout/**/*.ts': { lines: 80, functions: 80, branches: 80 },
'./payments/**/*.ts': { lines: 80, functions: 80, branches: 80 },
},
testEnvironment: 'node',
setupFiles: ['../jest-setup.ts'],
};
Expand Down
56 changes: 54 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,23 @@
"start": "node dist/main.js",
"dev": "ts-node src/main.ts",
"test": "jest",
"test:unit": "jest --testPathPattern='(?<!integration)\\.spec\\.ts$' --passWithNoTests",
"test:integration": "jest --testPathPattern='integration\\.spec\\.ts$' --passWithNoTests",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage --testPathPattern='(?<!integration)\\.spec\\.ts$'",
"test:cov": "jest --coverage",
"lint": "eslint \"{src,test}/**/*.ts\"",
"lint:fix": "eslint \"{src,test}/**/*.ts\" --fix",
"format": "prettier --write \"src/**/*.ts\"",
"format:check": "prettier --check \"src/**/*.ts\"",
"drizzle:generate": "drizzle-kit generate",
"drizzle:push": "drizzle-kit push",
"drizzle:studio": "drizzle-kit studio"
"drizzle:studio": "drizzle-kit studio",
"config:check": "ts-node scripts/config-check.ts"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^4.0.4",
"@nestjs/core": "^10.0.0",
"@nestjs/jwt": "^10.1.0",
"@nestjs/passport": "^10.0.0",
Expand All @@ -43,7 +48,8 @@
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.0",
"typeorm": "^0.3.17",
"uuid": "^9.0.0"
"uuid": "^9.0.0",
"zod": "^4.4.3"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
Expand Down
18 changes: 18 additions & 0 deletions scripts/config-check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'dotenv/config';
import { validate } from '../src/config/config.schema';

try {
const config = validate(process.env as Record<string, unknown>);
console.log('✓ Config is valid');
const nodeEnv = config.NODE_ENV;
const dbUrl = config.DATABASE_URL.replace(/:\/\/[^@]+@/, '://<credentials>@');
console.log(` NODE_ENV=${nodeEnv}`);
console.log(` DATABASE_URL=${dbUrl}`);
console.log(` REDIS_URL=${config.REDIS_URL}`);
console.log(` STELLAR_NETWORK=${config.STELLAR_NETWORK}`);
process.exit(0);
} catch (err) {
console.error('✗ Config validation failed:');
console.error((err as Error).message);
process.exit(1);
}
Loading
Loading