@buildcores/render-client 1.0.6 → 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 +32 -14
- package/dist/hooks/useBuildRender.d.ts +9 -1
- package/dist/index.d.ts +24 -19
- package/dist/index.esm.js +87 -14
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +87 -14
- 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")
|
|
@@ -38,24 +54,26 @@ export interface RenderAPIService {
|
|
|
38
54
|
/**
|
|
39
55
|
* Submit a render build request
|
|
40
56
|
* @param parts - The parts configuration for the build
|
|
41
|
-
* @param config -
|
|
57
|
+
* @param config - API configuration (environment, auth token) - required
|
|
42
58
|
* @returns Promise with the rendered MP4 video
|
|
43
59
|
*/
|
|
44
|
-
renderBuildExperimental(parts: RenderBuildRequest, config
|
|
60
|
+
renderBuildExperimental(parts: RenderBuildRequest, config: ApiConfig): Promise<RenderBuildResponse>;
|
|
45
61
|
/**
|
|
46
62
|
* Get available parts for building
|
|
47
|
-
* @param config -
|
|
63
|
+
* @param config - API configuration (environment, auth token) - required
|
|
48
64
|
* @returns Promise with available parts by category
|
|
49
65
|
*/
|
|
50
|
-
getAvailableParts(config
|
|
51
|
-
}
|
|
52
|
-
export interface ApiConfig {
|
|
53
|
-
environment?: "staging" | "prod";
|
|
54
|
-
authToken?: string;
|
|
66
|
+
getAvailableParts(config: ApiConfig): Promise<AvailablePartsResponse>;
|
|
55
67
|
}
|
|
56
|
-
export declare const buildApiUrl: (endpoint: string, config
|
|
57
|
-
export declare const buildHeaders: (config
|
|
58
|
-
export declare const renderBuildExperimental: (request: RenderBuildRequest, config
|
|
59
|
-
export declare const
|
|
60
|
-
export declare const
|
|
68
|
+
export declare const buildApiUrl: (endpoint: string, config: ApiConfig) => string;
|
|
69
|
+
export declare const buildHeaders: (config: ApiConfig) => Record<string, string>;
|
|
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>;
|
|
77
|
+
export declare const renderSpriteExperimental: (request: RenderBuildRequest, config: ApiConfig) => Promise<RenderSpriteResponse>;
|
|
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 {
|
|
@@ -530,26 +539,22 @@ interface RenderAPIService {
|
|
|
530
539
|
/**
|
|
531
540
|
* Submit a render build request
|
|
532
541
|
* @param parts - The parts configuration for the build
|
|
533
|
-
* @param config -
|
|
542
|
+
* @param config - API configuration (environment, auth token) - required
|
|
534
543
|
* @returns Promise with the rendered MP4 video
|
|
535
544
|
*/
|
|
536
|
-
renderBuildExperimental(parts: RenderBuildRequest, config
|
|
545
|
+
renderBuildExperimental(parts: RenderBuildRequest, config: ApiConfig): Promise<RenderBuildResponse>;
|
|
537
546
|
/**
|
|
538
547
|
* Get available parts for building
|
|
539
|
-
* @param config -
|
|
548
|
+
* @param config - API configuration (environment, auth token) - required
|
|
540
549
|
* @returns Promise with available parts by category
|
|
541
550
|
*/
|
|
542
|
-
getAvailableParts(config
|
|
543
|
-
}
|
|
544
|
-
interface ApiConfig {
|
|
545
|
-
environment?: "staging" | "prod";
|
|
546
|
-
authToken?: string;
|
|
551
|
+
getAvailableParts(config: ApiConfig): Promise<AvailablePartsResponse>;
|
|
547
552
|
}
|
|
548
|
-
declare const buildApiUrl: (endpoint: string, config
|
|
549
|
-
declare const buildHeaders: (config
|
|
550
|
-
declare const renderBuildExperimental: (request: RenderBuildRequest, config
|
|
551
|
-
declare const renderSpriteExperimental: (request: RenderBuildRequest, config
|
|
552
|
-
declare const getAvailableParts: (config
|
|
553
|
+
declare const buildApiUrl: (endpoint: string, config: ApiConfig) => string;
|
|
554
|
+
declare const buildHeaders: (config: ApiConfig) => Record<string, string>;
|
|
555
|
+
declare const renderBuildExperimental: (request: RenderBuildRequest, config: ApiConfig) => Promise<RenderBuildResponse>;
|
|
556
|
+
declare const renderSpriteExperimental: (request: RenderBuildRequest, config: ApiConfig) => Promise<RenderSpriteResponse>;
|
|
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,12 +324,13 @@ 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
|
|
330
331
|
const buildApiUrl = (endpoint, config) => {
|
|
331
332
|
const baseUrl = `${API_BASE_URL}${endpoint}`;
|
|
332
|
-
if (config
|
|
333
|
+
if (config.environment) {
|
|
333
334
|
const separator = endpoint.includes("?") ? "&" : "?";
|
|
334
335
|
return `${baseUrl}${separator}environment=${config.environment}`;
|
|
335
336
|
}
|
|
@@ -341,11 +342,12 @@ const buildHeaders = (config) => {
|
|
|
341
342
|
"Content-Type": "application/json",
|
|
342
343
|
accept: "application/json",
|
|
343
344
|
};
|
|
344
|
-
if (config
|
|
345
|
+
if (config.authToken) {
|
|
345
346
|
headers["Authorization"] = `Bearer ${config.authToken}`;
|
|
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
|
};
|