Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1933182
feat(frontend): add routable game detail page with timeline
chiscookeke11 Mar 30, 2026
e8f5a90
Merge pull request #2 from chiscookeke11/codex/add-game-detail-page-w…
chiscookeke11 Mar 30, 2026
d57bbd1
Frontend feature: add game detail page with contract event timeline
chiscookeke11 Mar 30, 2026
0383dac
fix(api): clean abort-signal merge handling in typed sdk
chiscookeke11 Mar 30, 2026
28b37bb
Merge pull request #3 from chiscookeke11/codex/add-game-detail-page-w…
chiscookeke11 Mar 30, 2026
75adaff
fixes
chiscookeke11 Mar 30, 2026
bb5814a
Merge branch 'main' of https://github.com/chiscookeke11/stellarcade--…
chiscookeke11 Mar 30, 2026
eab436b
fix(frontend): resolve typecheck failures across component tests
chiscookeke11 Mar 30, 2026
f2716d1
Merge pull request #4 from chiscookeke11/codex/add-game-detail-page-w…
chiscookeke11 Mar 30, 2026
db520fb
fixes
chiscookeke11 Mar 30, 2026
a875f6d
fixed merge conflict
chiscookeke11 Mar 30, 2026
c3038a7
fixed merge conflict
chiscookeke11 Mar 30, 2026
5d5fc87
updates
chiscookeke11 Mar 30, 2026
d493a90
Fix frontend tests for updated error boundary and CSV button
chiscookeke11 Mar 30, 2026
a10dfe1
Merge pull request #5 from chiscookeke11/codex/fix-test-errors-in-exp…
chiscookeke11 Mar 30, 2026
6d45c88
Fix OpenAPI validation and emergency pause tests
chiscookeke11 Mar 30, 2026
b8f1b71
Merge pull request #6 from chiscookeke11/codex/fix-missing-set_timest…
chiscookeke11 Mar 30, 2026
7ceaddb
Fix Stellar submitTransaction defaults for mocked config
chiscookeke11 Mar 30, 2026
f2f4b29
Merge pull request #7 from chiscookeke11/codex/fix-failed-test-suite
chiscookeke11 Mar 30, 2026
c684b3c
Regenerate contract API documentation
chiscookeke11 Mar 30, 2026
55f1277
Merge pull request #8 from chiscookeke11/codex/add-game-detail-page-f…
chiscookeke11 Mar 30, 2026
6426f54
Merge branch 'main' into issue-417
chiscookeke11 Mar 31, 2026
5162326
fixed typed-api-sdk file
chiscookeke11 Mar 31, 2026
711393b
Fix frontend typecheck and restore API client methods
chiscookeke11 Mar 31, 2026
f162593
Merge pull request #9 from chiscookeke11/codex/fix-type-errors-in-fro…
chiscookeke11 Mar 31, 2026
2cefb6c
Regenerate contract documentation
chiscookeke11 Apr 1, 2026
86b1f3e
Merge pull request #10 from chiscookeke11/codex/fix-contract-document…
chiscookeke11 Apr 1, 2026
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
168 changes: 167 additions & 1 deletion backend/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,110 @@
]
}
},
"/api/users/audit-logs": {
"get": {
"operationId": "listUserAuditLogs",
"summary": "List audit log entries",
"tags": [
"Users"
],
"responses": {
"200": {
"description": "Audit log entries fetched successfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"items"
],
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"400": {
"description": "Invalid query parameter",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorEnvelope"
}
}
}
},
"401": {
"description": "Authentication failed",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthErrorResponse"
}
}
}
},
"500": {
"description": "Unexpected server error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorEnvelope"
}
}
}
}
},
"parameters": [
{
"name": "actor",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Optional actor wallet address filter."
},
{
"name": "action",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"wallet.deposit",
"wallet.withdraw",
"game.play"
]
},
"description": "Optional action filter."
},
{
"name": "limit",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 1,
"default": 50
},
"description": "Maximum number of records returned."
}
],
"security": [
{
"bearerAuth": []
}
]
}
},
"/api/users/create": {
"post": {
"operationId": "createUserProfile",
Expand Down Expand Up @@ -328,7 +432,12 @@
}
}
}
}
},
"security": [
{
"bearerAuth": []
}
]
}
},
"/api/wallet/deposit": {
Expand Down Expand Up @@ -492,6 +601,63 @@
}
]
}
},
"/api/webhook": {
"post": {
"operationId": "receiveWebhookEvent",
"summary": "Receive and acknowledge webhook events",
"tags": [
"Wallet"
],
"responses": {
"200": {
"description": "Webhook payload accepted",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"received",
"timestamp"
],
"properties": {
"received": {
"type": "boolean",
"enum": [
true
]
},
"timestamp": {
"type": "string",
"format": "date-time"
}
}
}
}
}
},
"401": {
"description": "Invalid webhook signature",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthErrorResponse"
}
}
}
},
"500": {
"description": "Unexpected server error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorEnvelope"
}
}
}
}
}
}
}
},
"components": {
Expand Down
32 changes: 30 additions & 2 deletions backend/scripts/openapi.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const routeLineRegex = /router\.(get|post|put|patch|delete)\(\s*['"`]([^'"`]+)['
const requireRegex = /const\s+(\w+)\s*=\s*require\(['"](.+)['"]\);/g;
const mountRegex = /router\.use\(\s*['"]([^'"]+)['"]\s*,\s*(\w+)\s*\);/g;
const healthRouteRegex = /app\.get\(\s*['"]([^'"]+)['"]\s*,/;
const routerHealthRouteRegex = /router\.get\(\s*['"]([^'"]+)['"]\s*,\s*healthCheck\s*\)/;

const defaultErrorResponse = {
description: 'Unexpected server error',
Expand Down Expand Up @@ -253,6 +254,7 @@ function parseMounts() {
const source = readFile(routesIndexFile);
const variableToFile = new Map();
let requireMatch;
requireRegex.lastIndex = 0;

while ((requireMatch = requireRegex.exec(source)) !== null) {
const [, variableName, importPath] = requireMatch;
Expand All @@ -263,11 +265,12 @@ function parseMounts() {

const mounts = [];
let mountMatch;
mountRegex.lastIndex = 0;
while ((mountMatch = mountRegex.exec(source)) !== null) {
const [, mountPath, variableName] = mountMatch;
const filePath = variableToFile.get(variableName);
if (!filePath) {
throw new Error(`Unable to resolve mounted router "${variableName}" from routes/index.js`);
continue;
}

mounts.push({ mountPath, filePath });
Expand All @@ -281,6 +284,7 @@ function parseRouteDefinitions(filePath) {
const routeDocs = evaluateLiteral(extractLiteral(source, routeDocsRegex, 'routeDocs', filePath), filePath);
const routes = [];
let lineMatch;
routeLineRegex.lastIndex = 0;

while ((lineMatch = routeLineRegex.exec(source)) !== null) {
const [, method, routePath, handlers] = lineMatch;
Expand Down Expand Up @@ -366,7 +370,31 @@ function buildHealthPath() {
const serverSource = readFile(serverFile);
const healthMatch = serverSource.match(healthRouteRegex);
if (!healthMatch) {
throw new Error('Could not find /api/health route in backend/src/server.js');
const routesIndexSource = readFile(routesIndexFile);
const routerHealthMatch = routesIndexSource.match(routerHealthRouteRegex);
if (!routerHealthMatch) {
throw new Error('Could not find /api/health route in backend/src/server.js or backend/src/routes/index.js');
}

return {
[normalizePath('/api', routerHealthMatch[1])]: {
get: {
operationId: 'getHealthStatus',
summary: 'Check API health',
tags: ['Health'],
responses: {
200: {
description: 'API health payload returned successfully',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/HealthResponse' },
},
},
},
},
},
},
};
}

const healthPath = healthMatch[1];
Expand Down
83 changes: 83 additions & 0 deletions backend/src/routes/users.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,89 @@ const routeDocs = [
},
},
},
{
method: 'get',
path: '/audit-logs',
operationId: 'listUserAuditLogs',
summary: 'List audit log entries',
tags: ['Users'],
parameters: [
{
name: 'actor',
in: 'query',
required: false,
schema: { type: 'string' },
description: 'Optional actor wallet address filter.',
},
{
name: 'action',
in: 'query',
required: false,
schema: {
type: 'string',
enum: ['wallet.deposit', 'wallet.withdraw', 'game.play'],
},
description: 'Optional action filter.',
},
{
name: 'limit',
in: 'query',
required: false,
schema: {
type: 'integer',
minimum: 1,
default: 50,
},
description: 'Maximum number of records returned.',
},
],
responses: {
200: {
description: 'Audit log entries fetched successfully',
content: {
'application/json': {
schema: {
type: 'object',
required: ['items'],
properties: {
items: {
type: 'array',
items: {
type: 'object',
additionalProperties: true,
},
},
},
},
},
},
},
400: {
description: 'Invalid query parameter',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/ErrorEnvelope' },
},
},
},
401: {
description: 'Authentication failed',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/AuthErrorResponse' },
},
},
},
500: {
description: 'Unexpected server error',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/ErrorEnvelope' },
},
},
},
},
},
{
method: 'post',
path: '/create',
Expand Down
Loading
Loading