@buildcores/render-client 1.0.7 → 1.0.8
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.
- package/dist/api.d.ts +23 -5
- package/dist/hooks/useBuildRender.d.ts +9 -1
- package/dist/index.d.ts +15 -10
- package/dist/index.esm.js +85 -12
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +85 -12
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/SpriteRender.d.ts +0 -2
package/dist/api.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { RenderBuildRequest, AvailablePartsResponse } from "./types";
|
|
1
|
+
import { RenderBuildRequest, AvailablePartsResponse, ApiConfig } from "./types";
|
|
2
2
|
declare const API_BASE_URL = "https://www.renderapi.buildcores.com";
|
|
3
3
|
export declare const API_ENDPOINTS: {
|
|
4
4
|
readonly RENDER_BUILD_EXPERIMENTAL: "/render-build-experimental";
|
|
5
|
+
readonly RENDER_BUILD: "/render-build";
|
|
5
6
|
readonly AVAILABLE_PARTS: "/available-parts";
|
|
6
7
|
};
|
|
7
8
|
export interface RenderBuildResponse {
|
|
@@ -18,6 +19,21 @@ export interface RenderBuildResponse {
|
|
|
18
19
|
format?: string;
|
|
19
20
|
};
|
|
20
21
|
}
|
|
22
|
+
export interface RenderJobCreateResponse {
|
|
23
|
+
job_id: string;
|
|
24
|
+
status: "queued" | "processing" | "completed" | "error";
|
|
25
|
+
}
|
|
26
|
+
export interface RenderJobStatusResponse {
|
|
27
|
+
job_id: string;
|
|
28
|
+
status: "queued" | "processing" | "completed" | "error";
|
|
29
|
+
url?: string | null;
|
|
30
|
+
error?: string | null;
|
|
31
|
+
end_time?: string | null;
|
|
32
|
+
}
|
|
33
|
+
export interface RenderBuildAsyncResponse {
|
|
34
|
+
/** Final URL to the rendered MP4 (or sprite) asset */
|
|
35
|
+
videoUrl: string;
|
|
36
|
+
}
|
|
21
37
|
export interface RenderSpriteResponse {
|
|
22
38
|
/**
|
|
23
39
|
* The rendered sprite sheet as a Blob (when format is "sprite")
|
|
@@ -49,13 +65,15 @@ export interface RenderAPIService {
|
|
|
49
65
|
*/
|
|
50
66
|
getAvailableParts(config: ApiConfig): Promise<AvailablePartsResponse>;
|
|
51
67
|
}
|
|
52
|
-
export interface ApiConfig {
|
|
53
|
-
environment?: "staging" | "prod";
|
|
54
|
-
authToken?: string;
|
|
55
|
-
}
|
|
56
68
|
export declare const buildApiUrl: (endpoint: string, config: ApiConfig) => string;
|
|
57
69
|
export declare const buildHeaders: (config: ApiConfig) => Record<string, string>;
|
|
58
70
|
export declare const renderBuildExperimental: (request: RenderBuildRequest, config: ApiConfig) => Promise<RenderBuildResponse>;
|
|
71
|
+
export declare const createRenderBuildJob: (request: RenderBuildRequest, config: ApiConfig) => Promise<RenderJobCreateResponse>;
|
|
72
|
+
export declare const getRenderBuildStatus: (jobId: string, config: ApiConfig) => Promise<RenderJobStatusResponse>;
|
|
73
|
+
export declare const renderBuild: (request: RenderBuildRequest, config: ApiConfig, options?: {
|
|
74
|
+
pollIntervalMs?: number;
|
|
75
|
+
timeoutMs?: number;
|
|
76
|
+
}) => Promise<RenderBuildAsyncResponse>;
|
|
59
77
|
export declare const renderSpriteExperimental: (request: RenderBuildRequest, config: ApiConfig) => Promise<RenderSpriteResponse>;
|
|
60
78
|
export declare const getAvailableParts: (config: ApiConfig) => Promise<AvailablePartsResponse>;
|
|
61
79
|
export { API_BASE_URL };
|
|
@@ -9,4 +9,12 @@ export interface UseBuildRenderReturn {
|
|
|
9
9
|
isRenderingBuild: boolean;
|
|
10
10
|
renderError: string | null;
|
|
11
11
|
}
|
|
12
|
-
export
|
|
12
|
+
export interface UseBuildRenderOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Choose which backend flow to use
|
|
15
|
+
* - 'async' (default): uses /render-build and polls /render-build/{jobId}
|
|
16
|
+
* - 'experimental': uses /render-build-experimental and returns Blob
|
|
17
|
+
*/
|
|
18
|
+
mode?: "async" | "experimental";
|
|
19
|
+
}
|
|
20
|
+
export declare const useBuildRender: (parts: RenderBuildRequest, apiConfig: ApiConfig, onLoadStart?: () => void, options?: UseBuildRenderOptions) => UseBuildRenderReturn;
|
package/dist/index.d.ts
CHANGED
|
@@ -79,7 +79,7 @@ interface BuildRenderVideoProps {
|
|
|
79
79
|
* />
|
|
80
80
|
* ```
|
|
81
81
|
*/
|
|
82
|
-
apiConfig: ApiConfig
|
|
82
|
+
apiConfig: ApiConfig;
|
|
83
83
|
/**
|
|
84
84
|
* Optional mouse sensitivity for dragging (default: 0.005).
|
|
85
85
|
*
|
|
@@ -188,7 +188,7 @@ interface BuildRenderProps {
|
|
|
188
188
|
* />
|
|
189
189
|
* ```
|
|
190
190
|
*/
|
|
191
|
-
apiConfig: ApiConfig
|
|
191
|
+
apiConfig: ApiConfig;
|
|
192
192
|
/**
|
|
193
193
|
* Optional mouse sensitivity for dragging (default: 0.05).
|
|
194
194
|
*
|
|
@@ -211,7 +211,7 @@ interface BuildRenderProps {
|
|
|
211
211
|
/**
|
|
212
212
|
* API configuration for environment and authentication
|
|
213
213
|
*/
|
|
214
|
-
interface ApiConfig
|
|
214
|
+
interface ApiConfig {
|
|
215
215
|
/**
|
|
216
216
|
* Environment to use for API requests
|
|
217
217
|
* - 'staging': Development/testing environment
|
|
@@ -455,7 +455,15 @@ interface UseBuildRenderReturn {
|
|
|
455
455
|
isRenderingBuild: boolean;
|
|
456
456
|
renderError: string | null;
|
|
457
457
|
}
|
|
458
|
-
|
|
458
|
+
interface UseBuildRenderOptions {
|
|
459
|
+
/**
|
|
460
|
+
* Choose which backend flow to use
|
|
461
|
+
* - 'async' (default): uses /render-build and polls /render-build/{jobId}
|
|
462
|
+
* - 'experimental': uses /render-build-experimental and returns Blob
|
|
463
|
+
*/
|
|
464
|
+
mode?: "async" | "experimental";
|
|
465
|
+
}
|
|
466
|
+
declare const useBuildRender: (parts: RenderBuildRequest, apiConfig: ApiConfig, onLoadStart?: () => void, options?: UseBuildRenderOptions) => UseBuildRenderReturn;
|
|
459
467
|
|
|
460
468
|
interface UseSpriteRenderReturn {
|
|
461
469
|
spriteSrc: string | null;
|
|
@@ -467,7 +475,7 @@ interface UseSpriteRenderReturn {
|
|
|
467
475
|
totalFrames: number;
|
|
468
476
|
} | null;
|
|
469
477
|
}
|
|
470
|
-
declare const useSpriteRender: (parts: RenderBuildRequest, apiConfig: ApiConfig
|
|
478
|
+
declare const useSpriteRender: (parts: RenderBuildRequest, apiConfig: ApiConfig, onLoadStart?: () => void) => UseSpriteRenderReturn;
|
|
471
479
|
|
|
472
480
|
interface DragIconProps {
|
|
473
481
|
width?: number;
|
|
@@ -494,6 +502,7 @@ declare const InstructionTooltip: React__default.FC<InstructionTooltipProps>;
|
|
|
494
502
|
declare const API_BASE_URL = "https://www.renderapi.buildcores.com";
|
|
495
503
|
declare const API_ENDPOINTS: {
|
|
496
504
|
readonly RENDER_BUILD_EXPERIMENTAL: "/render-build-experimental";
|
|
505
|
+
readonly RENDER_BUILD: "/render-build";
|
|
497
506
|
readonly AVAILABLE_PARTS: "/available-parts";
|
|
498
507
|
};
|
|
499
508
|
interface RenderBuildResponse {
|
|
@@ -541,10 +550,6 @@ interface RenderAPIService {
|
|
|
541
550
|
*/
|
|
542
551
|
getAvailableParts(config: ApiConfig): Promise<AvailablePartsResponse>;
|
|
543
552
|
}
|
|
544
|
-
interface ApiConfig {
|
|
545
|
-
environment?: "staging" | "prod";
|
|
546
|
-
authToken?: string;
|
|
547
|
-
}
|
|
548
553
|
declare const buildApiUrl: (endpoint: string, config: ApiConfig) => string;
|
|
549
554
|
declare const buildHeaders: (config: ApiConfig) => Record<string, string>;
|
|
550
555
|
declare const renderBuildExperimental: (request: RenderBuildRequest, config: ApiConfig) => Promise<RenderBuildResponse>;
|
|
@@ -552,4 +557,4 @@ declare const renderSpriteExperimental: (request: RenderBuildRequest, config: Ap
|
|
|
552
557
|
declare const getAvailableParts: (config: ApiConfig) => Promise<AvailablePartsResponse>;
|
|
553
558
|
|
|
554
559
|
export { API_BASE_URL, API_ENDPOINTS, BuildRender, BuildRenderVideo, DragIcon, InstructionTooltip, LoadingErrorOverlay, PartCategory, arePartsEqual, buildApiUrl, buildHeaders, calculateCircularFrame, calculateCircularTime, getAvailableParts, renderBuildExperimental, renderSpriteExperimental, useBouncePatternProgress, useBuildRender, useSpriteRender, useSpriteScrubbing, useVideoScrubbing };
|
|
555
|
-
export type { ApiConfig
|
|
560
|
+
export type { ApiConfig, AvailablePartsResponse, BuildRenderProps, BuildRenderVideoProps, PartDetails, RenderAPIService, RenderBuildRequest, RenderBuildResponse, RenderSpriteResponse, UseBuildRenderOptions, UseBuildRenderReturn, UseSpriteRenderReturn };
|
package/dist/index.esm.js
CHANGED
|
@@ -324,6 +324,7 @@ const API_BASE_URL = "https://www.renderapi.buildcores.com";
|
|
|
324
324
|
// API Endpoints
|
|
325
325
|
const API_ENDPOINTS = {
|
|
326
326
|
RENDER_BUILD_EXPERIMENTAL: "/render-build-experimental",
|
|
327
|
+
RENDER_BUILD: "/render-build",
|
|
327
328
|
AVAILABLE_PARTS: "/available-parts",
|
|
328
329
|
};
|
|
329
330
|
// API URL helpers
|
|
@@ -346,6 +347,7 @@ const buildHeaders = (config) => {
|
|
|
346
347
|
}
|
|
347
348
|
return headers;
|
|
348
349
|
};
|
|
350
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
349
351
|
// API Implementation
|
|
350
352
|
const renderBuildExperimental = async (request, config) => {
|
|
351
353
|
const requestWithFormat = {
|
|
@@ -369,6 +371,65 @@ const renderBuildExperimental = async (request, config) => {
|
|
|
369
371
|
},
|
|
370
372
|
};
|
|
371
373
|
};
|
|
374
|
+
// New async endpoints implementation
|
|
375
|
+
const createRenderBuildJob = async (request, config) => {
|
|
376
|
+
const body = {
|
|
377
|
+
parts: request.parts,
|
|
378
|
+
// If provided, forward format; default handled server-side but we keep explicit default
|
|
379
|
+
...(request.format ? { format: request.format } : {}),
|
|
380
|
+
};
|
|
381
|
+
const response = await fetch(buildApiUrl(API_ENDPOINTS.RENDER_BUILD, config), {
|
|
382
|
+
method: "POST",
|
|
383
|
+
headers: buildHeaders(config),
|
|
384
|
+
body: JSON.stringify(body),
|
|
385
|
+
});
|
|
386
|
+
if (!response.ok) {
|
|
387
|
+
throw new Error(`Create render job failed: ${response.status} ${response.statusText}`);
|
|
388
|
+
}
|
|
389
|
+
const data = (await response.json());
|
|
390
|
+
if (!data?.job_id) {
|
|
391
|
+
throw new Error("Create render job failed: missing job_id in response");
|
|
392
|
+
}
|
|
393
|
+
return data;
|
|
394
|
+
};
|
|
395
|
+
const getRenderBuildStatus = async (jobId, config) => {
|
|
396
|
+
const url = buildApiUrl(`${API_ENDPOINTS.RENDER_BUILD}/${encodeURIComponent(jobId)}`, config);
|
|
397
|
+
const response = await fetch(url, {
|
|
398
|
+
method: "GET",
|
|
399
|
+
headers: buildHeaders(config),
|
|
400
|
+
});
|
|
401
|
+
if (response.status === 404) {
|
|
402
|
+
throw new Error("Render job not found");
|
|
403
|
+
}
|
|
404
|
+
if (!response.ok) {
|
|
405
|
+
throw new Error(`Get render job status failed: ${response.status} ${response.statusText}`);
|
|
406
|
+
}
|
|
407
|
+
return (await response.json());
|
|
408
|
+
};
|
|
409
|
+
const renderBuild = async (request, config, options) => {
|
|
410
|
+
const pollIntervalMs = 1500;
|
|
411
|
+
const timeoutMs = 120000; // 2 minutes default
|
|
412
|
+
const { job_id } = await createRenderBuildJob(request, config);
|
|
413
|
+
const start = Date.now();
|
|
414
|
+
// Poll until completed or error or timeout
|
|
415
|
+
for (;;) {
|
|
416
|
+
const status = await getRenderBuildStatus(job_id, config);
|
|
417
|
+
if (status.status === "completed") {
|
|
418
|
+
const finalUrl = status.url ?? undefined;
|
|
419
|
+
if (!finalUrl) {
|
|
420
|
+
throw new Error("Render job completed but no URL returned");
|
|
421
|
+
}
|
|
422
|
+
return { videoUrl: finalUrl };
|
|
423
|
+
}
|
|
424
|
+
if (status.status === "error") {
|
|
425
|
+
throw new Error(status.error || "Render job failed");
|
|
426
|
+
}
|
|
427
|
+
if (Date.now() - start > timeoutMs) {
|
|
428
|
+
throw new Error("Timed out waiting for render job to complete");
|
|
429
|
+
}
|
|
430
|
+
await sleep(pollIntervalMs);
|
|
431
|
+
}
|
|
432
|
+
};
|
|
372
433
|
const renderSpriteExperimental = async (request, config) => {
|
|
373
434
|
const requestWithFormat = {
|
|
374
435
|
...request,
|
|
@@ -473,7 +534,7 @@ const arePartsEqual = (parts1, parts2) => {
|
|
|
473
534
|
}
|
|
474
535
|
return true;
|
|
475
536
|
};
|
|
476
|
-
const useBuildRender = (parts, apiConfig, onLoadStart) => {
|
|
537
|
+
const useBuildRender = (parts, apiConfig, onLoadStart, options) => {
|
|
477
538
|
const [videoSrc, setVideoSrc] = useState(null);
|
|
478
539
|
const [isRenderingBuild, setIsRenderingBuild] = useState(false);
|
|
479
540
|
const [renderError, setRenderError] = useState(null);
|
|
@@ -483,15 +544,27 @@ const useBuildRender = (parts, apiConfig, onLoadStart) => {
|
|
|
483
544
|
setIsRenderingBuild(true);
|
|
484
545
|
setRenderError(null);
|
|
485
546
|
onLoadStart?.();
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
547
|
+
const mode = options?.mode ?? "async";
|
|
548
|
+
if (mode === "experimental") {
|
|
549
|
+
const response = await renderBuildExperimental(currentParts, apiConfig);
|
|
550
|
+
const objectUrl = URL.createObjectURL(response.video);
|
|
551
|
+
setVideoSrc((prevSrc) => {
|
|
552
|
+
if (prevSrc && prevSrc.startsWith("blob:")) {
|
|
553
|
+
URL.revokeObjectURL(prevSrc);
|
|
554
|
+
}
|
|
555
|
+
return objectUrl;
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
const { videoUrl } = await renderBuild(currentParts, apiConfig);
|
|
560
|
+
// Clean up previous object URL (if any) before setting new one
|
|
561
|
+
setVideoSrc((prevSrc) => {
|
|
562
|
+
if (prevSrc && prevSrc.startsWith("blob:")) {
|
|
563
|
+
URL.revokeObjectURL(prevSrc);
|
|
564
|
+
}
|
|
565
|
+
return videoUrl;
|
|
566
|
+
});
|
|
567
|
+
}
|
|
495
568
|
}
|
|
496
569
|
catch (error) {
|
|
497
570
|
setRenderError(error instanceof Error ? error.message : "Failed to render build");
|
|
@@ -499,7 +572,7 @@ const useBuildRender = (parts, apiConfig, onLoadStart) => {
|
|
|
499
572
|
finally {
|
|
500
573
|
setIsRenderingBuild(false);
|
|
501
574
|
}
|
|
502
|
-
}, [apiConfig, onLoadStart]);
|
|
575
|
+
}, [apiConfig, onLoadStart, options?.mode]);
|
|
503
576
|
// Effect to call API when parts content changes (using custom equality check)
|
|
504
577
|
useEffect(() => {
|
|
505
578
|
const shouldFetch = previousPartsRef.current === null ||
|
|
@@ -512,7 +585,7 @@ const useBuildRender = (parts, apiConfig, onLoadStart) => {
|
|
|
512
585
|
// Cleanup effect for component unmount
|
|
513
586
|
useEffect(() => {
|
|
514
587
|
return () => {
|
|
515
|
-
if (videoSrc) {
|
|
588
|
+
if (videoSrc && videoSrc.startsWith("blob:")) {
|
|
516
589
|
URL.revokeObjectURL(videoSrc);
|
|
517
590
|
}
|
|
518
591
|
};
|