Skip to content

Commit e155ebc

Browse files
authored
feature: add indexer recordings (#13)
* feat: configure testnet recording and bun debugging This enables debugging the recording process and captures real testnet API responses for mock server playback. Adds VS Code Bun debugger configuration for server * fix: remove problematic response headers during replay - Strip transfer-encoding and content-encoding headers in beforeReplay hook to prevent conflicts with content-length and decompression errors - Replace server tests with replay-focused tests - Update unrecorded endpoint test to use non-existent account address - Re-record HAR files with consistent API token format * refactor: separate recording and replay into distinct CLI tools - Split bin/server.ts (replay-only) and bin/record.ts (recording-only) - Update startServer() to remove mode parameter, always replays - Created tests for replay and recording - Update tests to use new API signatures - Add debug configurations for both tools * refactor: record test to just test the record function Removed the bin record file since recording happens on every server start * feat:added scripts to find data * feat: add algod API endpoint recordings and binary msgpack support - Add comprehensive algod request functions in src/requests/algodRequests.ts - Add beforePersist hook to ensure msgpack responses are base64 encoded - Refactor record.ts to use modular request functions - Update HAR recordings with complete endpoint coverage - Add indexer and kmd request modules * chore: removed finding data scripts * chore: updated snapshot for failing test * feat: added indexer endpoint recordings * chore: updated snapshot
1 parent 34e2581 commit e155ebc

File tree

6 files changed

+2823
-14
lines changed

6 files changed

+2823
-14
lines changed

resources/mock-server/.vscode/launch.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"request": "launch",
1010
"name": "Debug Replay Server",
1111
"program": "${workspaceFolder}/bin/server.ts",
12-
"args": ["algod"], // Change to: algod, indexer, or kmd
12+
"args": ["indexer"], // Change to: algod, indexer, or kmd
1313
// "args": ["algod", "${workspaceFolder}/tmp-recordings"], // Change to: algod, indexer, or kmd
1414
"cwd": "${workspaceFolder}",
1515
"stopOnEntry": false,
@@ -19,6 +19,19 @@
1919
"LOG_LEVEL": "debug"
2020
}
2121
},
22+
{
23+
"type": "bun",
24+
"request": "launch",
25+
"name": "Debug Find Pending Transactions",
26+
"program": "${workspaceFolder}/scripts/find-pending-transactions.ts",
27+
"args": ["60", "1000"], // [pollDuration in seconds, pollInterval in ms]
28+
"cwd": "${workspaceFolder}",
29+
"stopOnEntry": false,
30+
"watchMode": false,
31+
"env": {
32+
"NODE_ENV": "development"
33+
}
34+
},
2235
{
2336
"type": "bun",
2437
"request": "launch",

resources/mock-server/__test__/__snapshots__/replay.test.ts.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ HealthCheck {
4242
"dbAvailable": true,
4343
"errors": undefined,
4444
"isMigrating": false,
45-
"message": "57490591",
46-
"round": 57490591n,
45+
"message": "57772761",
46+
"round": 57772761n,
4747
"version": "3.9.0",
4848
}
4949
`;

resources/mock-server/mock-server.code-workspace

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
// This ensures consistency between CLI builds and editor type checking
1616
"typescript.enablePromptUseWorkspaceTsdk": true
1717
}
18-
}
18+
}

resources/mock-server/recordings/indexer_2682762536/recording.har

Lines changed: 2680 additions & 10 deletions
Large diffs are not rendered by default.

resources/mock-server/src/index.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,29 @@ export function getPolly(
9191
);
9292
});
9393

94+
// Decode base64-encoded msgpack responses from HAR files
95+
polly.server.any().on("beforeResponse", (_req, res) => {
96+
console.log("beforeResponse triggered");
97+
console.log("Content-Type:", res.headers["content-type"]);
98+
console.log("Body type:", typeof res.body);
99+
console.log(
100+
"Body (first 50 chars):",
101+
typeof res.body === "string" ? res.body.substring(0, 50) : "NOT A STRING"
102+
);
103+
104+
// Base64 decode attempt
105+
if (
106+
res.body &&
107+
typeof res.body === "string" &&
108+
res.headers["content-type"]?.includes("msgpack")
109+
) {
110+
console.log("Attempting base64 decode...");
111+
const buffer = Buffer.from(res.body, "base64");
112+
res.body = new Uint8Array(buffer) as any;
113+
console.log("Decoded body type:", res.body?.constructor.name);
114+
}
115+
});
116+
94117
return polly;
95118
}
96119

resources/mock-server/src/requests/indexerRequests.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,108 @@ export async function algosdkIndexerRequests() {
66
"https://testnet-idx.4160.nodely.dev",
77
443
88
);
9+
10+
// ========================================
11+
// TEST DATA SOURCES:
12+
// - Using same test data from algod requests (Lora object mothers)
13+
// ========================================
14+
15+
const address = "25M5BT2DMMED3V6CWDEYKSNEFGPXX4QBIINCOICLXXRU3UGTSGRMF3MTOE";
16+
// TODO: Find app with a localstate
17+
const appId = 718348254; // testnet
18+
const appIdWithBoxes = 742949200; // xgov testnet
19+
const assetId = 705457144;
20+
const txId = "VIXTUMAPT7NR4RB2WVOGMETW4QY43KIDA3HWDWWXS3UEDKGTEECQ";
21+
const round = 24099447;
22+
23+
// ============================================
24+
// NO PARAMETERS NEEDED
25+
// ============================================
26+
27+
// GET /health
928
await indexer.makeHealthCheck().do();
29+
30+
// ============================================
31+
// ACCOUNT ENDPOINTS
32+
// ============================================
33+
34+
// GET /v2/accounts
35+
await indexer.searchAccounts().limit(1).do();
36+
37+
// GET /v2/accounts/{account-id}
38+
await indexer.lookupAccountByID(address).do();
39+
40+
// GET /v2/accounts/{account-id}/transactions
41+
await indexer.lookupAccountTransactions(address).do();
42+
43+
// GET /v2/accounts/{account-id}/assets
44+
await indexer.lookupAccountAssets(address).do();
45+
46+
// GET /v2/accounts/{account-id}/created-assets
47+
await indexer.lookupAccountCreatedAssets(address).do();
48+
49+
// GET /v2/accounts/{account-id}/created-applications
50+
await indexer.lookupAccountCreatedApplications(address).do();
51+
52+
// GET /v2/accounts/{account-id}/apps-local-state
53+
await indexer.lookupAccountAppLocalStates(address).do();
54+
55+
// ============================================
56+
// TRANSACTION ENDPOINTS
57+
// ============================================
58+
59+
// GET /v2/transactions
60+
await indexer.searchForTransactions().limit(1).do();
61+
62+
// GET /v2/transactions/{txid}
63+
await indexer.lookupTransactionByID(txId).do();
64+
65+
// ============================================
66+
// ASSET ENDPOINTS
67+
// ============================================
68+
69+
// GET /v2/assets
70+
await indexer.searchForAssets().limit(1).do();
71+
72+
// GET /v2/assets/{asset-id}
73+
await indexer.lookupAssetByID(assetId).do();
74+
75+
// GET /v2/assets/{asset-id}/balances
76+
await indexer.lookupAssetBalances(assetId).do();
77+
78+
// GET /v2/assets/{asset-id}/transactions
79+
await indexer.lookupAssetTransactions(assetId).do();
80+
81+
// ============================================
82+
// APPLICATION ENDPOINTS
83+
// ============================================
84+
85+
// GET /v2/applications
86+
await indexer.searchForApplications().limit(1).do();
87+
88+
// GET /v2/applications/{application-id}
89+
await indexer.lookupApplications(appId).do();
90+
91+
// GET /v2/applications/{application-id}/logs
92+
await indexer.lookupApplicationLogs(appId).do();
93+
94+
// GET /v2/applications/{application-id}/box
95+
const boxName = Buffer.from(
96+
"cBbHBNV+zUy/Mz5IRhIrBLxr1on5wmidhXEavV+SasC8",
97+
"base64"
98+
);
99+
await indexer.lookupApplicationBoxByIDandName(appIdWithBoxes, boxName).do();
100+
101+
// GET /v2/applications/{application-id}/boxes
102+
await indexer.searchForApplicationBoxes(appIdWithBoxes).do();
103+
104+
// ============================================
105+
// BLOCK ENDPOINTS
106+
// ============================================
107+
108+
// GET /v2/blocks/{round-number}
109+
await indexer.lookupBlock(round).do();
110+
111+
// GET /v2/block-headers
112+
await indexer.searchForBlockHeaders().limit(1).do();
10113
}

0 commit comments

Comments
 (0)