@agent-foundry/replay-server 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/.cursor/dev.mdc +941 -0
  2. package/.cursor/project.mdc +17 -2
  3. package/.env +30 -0
  4. package/Dockerfile +6 -0
  5. package/README.md +153 -12
  6. package/dist/cli/render.js +14 -4
  7. package/dist/cli/render.js.map +1 -1
  8. package/dist/renderer/PuppeteerRenderer.d.ts +12 -2
  9. package/dist/renderer/PuppeteerRenderer.d.ts.map +1 -1
  10. package/dist/renderer/PuppeteerRenderer.js +23 -16
  11. package/dist/renderer/PuppeteerRenderer.js.map +1 -1
  12. package/dist/server/index.d.ts +4 -0
  13. package/dist/server/index.d.ts.map +1 -1
  14. package/dist/server/index.js +200 -46
  15. package/dist/server/index.js.map +1 -1
  16. package/dist/services/BundleManager.d.ts +99 -0
  17. package/dist/services/BundleManager.d.ts.map +1 -0
  18. package/dist/services/BundleManager.js +410 -0
  19. package/dist/services/BundleManager.js.map +1 -0
  20. package/dist/services/OSSClient.d.ts +51 -0
  21. package/dist/services/OSSClient.d.ts.map +1 -0
  22. package/dist/services/OSSClient.js +207 -0
  23. package/dist/services/OSSClient.js.map +1 -0
  24. package/dist/services/index.d.ts +7 -0
  25. package/dist/services/index.d.ts.map +1 -0
  26. package/dist/services/index.js +7 -0
  27. package/dist/services/index.js.map +1 -0
  28. package/dist/services/types.d.ts +73 -0
  29. package/dist/services/types.d.ts.map +1 -0
  30. package/dist/services/types.js +5 -0
  31. package/dist/services/types.js.map +1 -0
  32. package/docker-compose.local.yml +8 -0
  33. package/env.example +30 -0
  34. package/package.json +7 -3
  35. package/restart.sh +5 -0
  36. package/samples/jump_arena_0_ja-mks5um2x-nksbmz.json +1907 -0
  37. package/scripts/render-pipeline.sh +657 -0
  38. package/scripts/test-bundle-preload.sh +20 -0
  39. package/scripts/test-service-sts.sh +176 -0
  40. package/src/cli/render.ts +18 -7
  41. package/src/renderer/PuppeteerRenderer.ts +41 -21
  42. package/src/server/index.ts +249 -68
  43. package/src/services/BundleManager.ts +503 -0
  44. package/src/services/OSSClient.ts +286 -0
  45. package/src/services/index.ts +7 -0
  46. package/src/services/types.ts +78 -0
@@ -0,0 +1,207 @@
1
+ /**
2
+ * OSS Client
3
+ *
4
+ * Handles authenticated downloads from Alibaba Cloud OSS using STS credentials
5
+ * obtained from the BFF API.
6
+ */
7
+ import OSS from 'ali-oss';
8
+ import * as fs from 'fs';
9
+ import * as path from 'path';
10
+ /**
11
+ * Error thrown by OSS client operations
12
+ */
13
+ export class OSSClientError extends Error {
14
+ code;
15
+ statusCode;
16
+ constructor(message, code, statusCode) {
17
+ super(message);
18
+ this.code = code;
19
+ this.statusCode = statusCode;
20
+ this.name = 'OSSClientError';
21
+ }
22
+ }
23
+ /**
24
+ * OSS Client for downloading bundles with STS authentication
25
+ */
26
+ export class OSSClient {
27
+ bffBaseUrl;
28
+ serviceToken;
29
+ timeout;
30
+ cachedCredentials = null;
31
+ credentialsExpiresAt = null;
32
+ constructor(config) {
33
+ this.bffBaseUrl = config.bffBaseUrl.replace(/\/$/, '');
34
+ this.serviceToken = config.serviceToken;
35
+ this.timeout = config.timeout ?? 30000;
36
+ }
37
+ /**
38
+ * Get STS credentials from BFF API
39
+ * Caches credentials until they expire (with 5 minute buffer)
40
+ *
41
+ * Uses the /studio/service/sts endpoint which requires BFF_SERVICE_TOKEN
42
+ * (set to SUPABASE_JWT_SECRET) for service-to-service authentication.
43
+ */
44
+ async getSTSCredentials() {
45
+ // Check if cached credentials are still valid (with 5 minute buffer)
46
+ if (this.cachedCredentials && this.credentialsExpiresAt) {
47
+ const bufferMs = 5 * 60 * 1000; // 5 minutes
48
+ if (new Date().getTime() + bufferMs < this.credentialsExpiresAt.getTime()) {
49
+ return this.cachedCredentials;
50
+ }
51
+ }
52
+ if (!this.serviceToken) {
53
+ throw new OSSClientError('BFF_SERVICE_TOKEN is required for STS credentials. Set it to the value of SUPABASE_JWT_SECRET from BFF.', 'SERVICE_TOKEN_MISSING');
54
+ }
55
+ console.log('[OSSClient] Requesting STS credentials from BFF...');
56
+ const controller = new AbortController();
57
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
58
+ try {
59
+ const headers = {
60
+ 'Content-Type': 'application/json',
61
+ 'Authorization': `Bearer ${this.serviceToken}`,
62
+ };
63
+ // Use the service-to-service endpoint
64
+ const response = await fetch(`${this.bffBaseUrl}/studio/service/sts`, {
65
+ method: 'POST',
66
+ headers,
67
+ signal: controller.signal,
68
+ });
69
+ clearTimeout(timeoutId);
70
+ if (!response.ok) {
71
+ let detail = response.statusText;
72
+ try {
73
+ const error = await response.json();
74
+ detail = error.detail || error.message || response.statusText;
75
+ }
76
+ catch {
77
+ // Ignore JSON parse error
78
+ }
79
+ throw new OSSClientError(`Failed to get STS credentials: ${detail}`, 'STS_REQUEST_FAILED', response.status);
80
+ }
81
+ const data = await response.json();
82
+ // Extract credentials from response
83
+ // BFF /studio/service/sts returns: { credentials: { accessKeyId, ... }, bucket, region }
84
+ const creds = data.credentials || data;
85
+ const credentials = {
86
+ accessKeyId: creds.accessKeyId || creds.access_key_id,
87
+ accessKeySecret: creds.accessKeySecret || creds.access_key_secret,
88
+ securityToken: creds.securityToken || creds.security_token,
89
+ expiration: creds.expiration,
90
+ bucket: data.bucket,
91
+ region: data.region,
92
+ };
93
+ // Validate credentials
94
+ if (!credentials.accessKeyId || !credentials.accessKeySecret || !credentials.securityToken) {
95
+ throw new OSSClientError('Invalid STS credentials response from BFF', 'INVALID_STS_RESPONSE');
96
+ }
97
+ // Validate bucket and region
98
+ if (!credentials.bucket || !credentials.region) {
99
+ throw new OSSClientError('Invalid STS credentials response from BFF: missing bucket or region', 'INVALID_STS_RESPONSE');
100
+ }
101
+ // Cache credentials
102
+ this.cachedCredentials = credentials;
103
+ this.credentialsExpiresAt = new Date(credentials.expiration);
104
+ console.log('[OSSClient] STS credentials obtained, expires:', credentials.expiration);
105
+ return credentials;
106
+ }
107
+ catch (error) {
108
+ clearTimeout(timeoutId);
109
+ if (error instanceof OSSClientError) {
110
+ throw error;
111
+ }
112
+ if (error instanceof Error && error.name === 'AbortError') {
113
+ throw new OSSClientError('STS credentials request timeout', 'STS_TIMEOUT', 408);
114
+ }
115
+ throw new OSSClientError(`Failed to get STS credentials: ${error instanceof Error ? error.message : String(error)}`, 'STS_REQUEST_ERROR');
116
+ }
117
+ }
118
+ /**
119
+ * Download file from OSS URL with STS authentication
120
+ *
121
+ * @param url - OSS URL to download from
122
+ * @param destPath - Local destination path
123
+ * @param onProgress - Optional progress callback (0-100)
124
+ */
125
+ async downloadFile(url, destPath, onProgress) {
126
+ console.log(`[OSSClient] Downloading ${url} to ${destPath}`);
127
+ // Get STS credentials
128
+ const credentials = await this.getSTSCredentials();
129
+ if (!credentials.bucket || !credentials.region) {
130
+ throw new OSSClientError('Missing bucket or region in STS credentials', 'INVALID_CREDENTIALS');
131
+ }
132
+ // Parse URL to extract object key
133
+ // URL format: https://bucket.oss-region.aliyuncs.com/path/to/object
134
+ // or: https://oss-region.aliyuncs.com/bucket/path/to/object
135
+ const parsedUrl = new URL(url);
136
+ let objectKey = parsedUrl.pathname.slice(1); // Remove leading /
137
+ // Handle case where bucket is in the path (not subdomain)
138
+ if (parsedUrl.hostname.includes('aliyuncs.com') && !parsedUrl.hostname.startsWith(credentials.bucket)) {
139
+ // Format: https://oss-region.aliyuncs.com/bucket/path/to/object
140
+ const pathParts = objectKey.split('/');
141
+ if (pathParts[0] === credentials.bucket) {
142
+ objectKey = pathParts.slice(1).join('/');
143
+ }
144
+ }
145
+ console.log(`[OSSClient] Extracted object key: ${objectKey}`);
146
+ try {
147
+ // Create OSS client with STS credentials
148
+ const client = new OSS({
149
+ accessKeyId: credentials.accessKeyId,
150
+ accessKeySecret: credentials.accessKeySecret,
151
+ stsToken: credentials.securityToken,
152
+ bucket: credentials.bucket,
153
+ region: credentials.region,
154
+ timeout: 10 * 60 * 1000, // 10 minutes
155
+ });
156
+ // Ensure destination directory exists
157
+ const destDir = path.dirname(destPath);
158
+ fs.mkdirSync(destDir, { recursive: true });
159
+ // Download file
160
+ // Note: ali-oss client.get() for Node.js doesn't support progress callbacks
161
+ // Progress tracking would require streaming the response manually
162
+ const result = await client.get(objectKey, destPath, {
163
+ timeout: 10 * 60 * 1000,
164
+ });
165
+ if (onProgress) {
166
+ onProgress(100);
167
+ }
168
+ console.log(`[OSSClient] Download complete: ${destPath}`);
169
+ }
170
+ catch (error) {
171
+ // Clean up partial download
172
+ if (fs.existsSync(destPath)) {
173
+ try {
174
+ fs.unlinkSync(destPath);
175
+ }
176
+ catch {
177
+ // Ignore cleanup error
178
+ }
179
+ }
180
+ // Handle OSS SDK errors
181
+ if (error.code === 'ConnectionTimeoutError' || error.code === 'RequestTimeout') {
182
+ throw new OSSClientError('Download timeout', 'DOWNLOAD_TIMEOUT', 408);
183
+ }
184
+ if (error.status === 403 || error.code === 'AccessDenied') {
185
+ throw new OSSClientError('Access denied - check STS credentials and permissions', 'DOWNLOAD_FORBIDDEN', 403);
186
+ }
187
+ if (error.status === 404 || error.code === 'NoSuchKey') {
188
+ throw new OSSClientError(`Object not found: ${objectKey}`, 'OBJECT_NOT_FOUND', 404);
189
+ }
190
+ throw new OSSClientError(`Download failed: ${error.message || String(error)}`, 'DOWNLOAD_ERROR', error.status);
191
+ }
192
+ }
193
+ /**
194
+ * Clear cached credentials
195
+ */
196
+ clearCredentialsCache() {
197
+ this.cachedCredentials = null;
198
+ this.credentialsExpiresAt = null;
199
+ }
200
+ }
201
+ /**
202
+ * Create an OSS client instance
203
+ */
204
+ export function createOSSClient(config) {
205
+ return new OSSClient(config);
206
+ }
207
+ //# sourceMappingURL=OSSClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OSSClient.js","sourceRoot":"","sources":["../../src/services/OSSClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Services exports
3
+ */
4
+ export * from './types.js';
5
+ export * from './OSSClient.js';
6
+ export * from './BundleManager.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Services exports
3
+ */
4
+ export * from './types.js';
5
+ export * from './OSSClient.js';
6
+ export * from './BundleManager.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Shared types for replay-server services
3
+ */
4
+ /**
5
+ * STS credentials from BFF API for OSS access
6
+ */
7
+ export interface STSCredentials {
8
+ accessKeyId: string;
9
+ accessKeySecret: string;
10
+ securityToken: string;
11
+ expiration: string;
12
+ bucket?: string;
13
+ region?: string;
14
+ }
15
+ /**
16
+ * OSS client configuration
17
+ */
18
+ export interface OSSClientConfig {
19
+ /** BFF API base URL for STS credentials */
20
+ bffBaseUrl: string;
21
+ /** Optional service-to-service auth token */
22
+ serviceToken?: string;
23
+ /** Request timeout in milliseconds (default: 30000) */
24
+ timeout?: number;
25
+ }
26
+ /**
27
+ * Bundle information
28
+ */
29
+ export interface BundleInfo {
30
+ bundleId: string;
31
+ bundleUrl?: string;
32
+ status: 'pending' | 'downloading' | 'ready' | 'error';
33
+ size?: number;
34
+ cachedAt?: Date;
35
+ lastAccessedAt?: Date;
36
+ error?: string;
37
+ /** Download progress percentage (0-100) */
38
+ progress?: number;
39
+ }
40
+ /**
41
+ * Bundle manager configuration
42
+ */
43
+ export interface BundleManagerConfig {
44
+ /** Directory to store bundles (default: /tmp/bundles) */
45
+ bundlesDir: string;
46
+ /** Maximum cache size in bytes (default: 10GB) */
47
+ maxCacheSize: number;
48
+ }
49
+ /**
50
+ * Cache statistics
51
+ */
52
+ export interface CacheStats {
53
+ /** Used cache size in bytes */
54
+ used: number;
55
+ /** Maximum cache size in bytes */
56
+ max: number;
57
+ /** Usage percentage (0-100) */
58
+ usedPercent: number;
59
+ /** Number of cached bundles */
60
+ bundleCount: number;
61
+ }
62
+ /**
63
+ * Download statistics
64
+ */
65
+ export interface DownloadStats {
66
+ /** Number of active downloads */
67
+ active: number;
68
+ /** Total completed downloads */
69
+ completed: number;
70
+ /** Total failed downloads */
71
+ failed: number;
72
+ }
73
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/services/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,OAAO,GAAG,OAAO,CAAC;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACvB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;CAClB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Shared types for replay-server services
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/services/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -13,6 +13,8 @@ version: '3.8'
13
13
 
14
14
  services:
15
15
  replay-server:
16
+ extra_hosts:
17
+ - "host.docker.internal:host-gateway"
16
18
  build:
17
19
  context: ../..
18
20
  dockerfile: packages/replay-server/Dockerfile
@@ -22,6 +24,12 @@ services:
22
24
  - PORT=3001
23
25
  - BUNDLES_DIR=/app/packages/replay-server/bundles
24
26
  - OUTPUT_DIR=/app/packages/replay-server/output
27
+ # BFF API URL for STS credentials (required for dynamic bundle downloads)
28
+ - BFF_BASE_URL=http://host.docker.internal:11001
29
+ # Service-to-service auth token for BFF
30
+ - BFF_SERVICE_TOKEN=ijwt8jbx3Kkf2XDE8bR3AViGJchA5VppbOwpBFTF
31
+ # Maximum cache size in bytes (default: 10GB)
32
+ - MAX_CACHE_SIZE=10737418240
25
33
  volumes:
26
34
  # Mount output directory for easy access to rendered videos
27
35
  - ./output:/app/packages/replay-server/output
package/env.example ADDED
@@ -0,0 +1,30 @@
1
+ # Replay Server Environment Variables
2
+
3
+ # Server port
4
+ PORT=3001
5
+
6
+ # Default game URL (fallback when no bundleId specified)
7
+ GAME_URL=http://localhost:5173
8
+
9
+ # Directory containing game bundles
10
+ BUNDLES_DIR=./bundles
11
+
12
+ # Directory for rendered video output
13
+ OUTPUT_DIR=./output
14
+
15
+ # Puppeteer executable path (for containerized environments)
16
+ PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
17
+
18
+ # =============================================================================
19
+ # Bundle Download Configuration
20
+ # =============================================================================
21
+
22
+ # BFF API URL for STS credentials (required for dynamic bundle downloads)
23
+ BFF_BASE_URL=http://localhost:11001
24
+
25
+ # Service-to-service auth token for BFF (REQUIRED for bundle downloads)
26
+ # Set this to the value of SUPABASE_JWT_SECRET from BFF's .env file
27
+ # BFF_SERVICE_TOKEN=your-supabase-jwt-secret-from-bff
28
+
29
+ # Maximum bundle cache size in bytes (default: 10GB = 10737418240)
30
+ MAX_CACHE_SIZE=10737418240
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-foundry/replay-server",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Video rendering service for AgentFoundry mini-game replays",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,7 +17,9 @@
17
17
  "puppeteer": "^22.0.0",
18
18
  "fluent-ffmpeg": "^2.1.2",
19
19
  "cors": "^2.8.5",
20
- "uuid": "^9.0.0"
20
+ "uuid": "^9.0.0",
21
+ "tar-stream": "^3.1.6",
22
+ "ali-oss": "^6.23.0"
21
23
  },
22
24
  "devDependencies": {
23
25
  "@types/express": "^4.17.21",
@@ -25,6 +27,8 @@
25
27
  "@types/cors": "^2.8.17",
26
28
  "@types/uuid": "^9.0.7",
27
29
  "@types/node": "^20.11.0",
30
+ "@types/tar-stream": "^3.1.3",
31
+ "@types/ali-oss": "^6.23.0",
28
32
  "typescript": "^5.3.3",
29
33
  "tsx": "^4.7.0",
30
34
  "rimraf": "^5.0.5"
@@ -32,4 +36,4 @@
32
36
  "publishConfig": {
33
37
  "access": "public"
34
38
  }
35
- }
39
+ }
package/restart.sh ADDED
@@ -0,0 +1,5 @@
1
+ docker compose -f docker-compose.local.yml down
2
+
3
+ docker compose -f docker-compose.local.yml build
4
+
5
+ docker compose -f docker-compose.local.yml up -d