@nodaro/shared 3.0.0 → 3.1.0

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/index.cjs CHANGED
@@ -3372,7 +3372,13 @@ var ASPECT_RATIO_DIMENSIONS = {
3372
3372
  "16:9": { width: 1920, height: 1080 },
3373
3373
  "9:16": { width: 1080, height: 1920 },
3374
3374
  "1:1": { width: 1080, height: 1080 },
3375
- "4:5": { width: 1080, height: 1350 }
3375
+ "4:5": { width: 1080, height: 1350 },
3376
+ // Ultra-wide. 1680x720 rather than a 1920-wide pair because the Scene3D v2
3377
+ // admission bounds require even integers on both axes and 1920/(21/9) is
3378
+ // odd; 1680x720 is the pair the scene contract names as supported. Additive:
3379
+ // every consumer here is a keyed lookup with a fallback, and a node only
3380
+ // reaches this entry if its own aspect enum offers 21:9 (today, Pro 3D).
3381
+ "21:9": { width: 1680, height: 720 }
3376
3382
  };
3377
3383
  var MOTION_TRANSFER_PROVIDERS = [
3378
3384
  "kling",
@@ -4138,7 +4144,11 @@ var COMPOSER_PLAN_MAP = {
4138
4144
  // validated `Scene3DPlan` revision on their `composition` handle, so
4139
4145
  // render-video routes either one to the `3d-scene` renderer unchanged.
4140
4146
  "generate-3d-scene": { planType: "3d-scene", planField: "scenePlan" },
4141
- "edit-3d-scene": { planType: "3d-scene", planField: "scenePlan" }
4147
+ "edit-3d-scene": { planType: "3d-scene", planField: "scenePlan" },
4148
+ // 3D Render Pro authors the SAME `scenePlan` revision (v2) alongside its
4149
+ // MP4, so the render-only re-run reads it through this map exactly as it
4150
+ // reads a Basic revision — no second plan lane, no second render path.
4151
+ "pro-3d-render": { planType: "3d-scene", planField: "scenePlan" }
4142
4152
  };
4143
4153
  var COMPOSER_PLAN_FIELDS = [
4144
4154
  ...new Set(Object.values(COMPOSER_PLAN_MAP).map((m) => m.planField))
@@ -5016,6 +5026,157 @@ function resolveTopazUpscale(input) {
5016
5026
  };
5017
5027
  }
5018
5028
 
5029
+ // src/producer-types.ts
5030
+ var VIDEO_PRODUCER_TYPES = /* @__PURE__ */ new Set([
5031
+ "image-to-video",
5032
+ "video-to-video",
5033
+ "switchx",
5034
+ // Beeble SwitchX relight/composite
5035
+ "text-to-video",
5036
+ // Unified video node — emits videoUrl identically to i2v/t2v (its payload-builder
5037
+ // case dispatches dynamically to "image-to-video" or "text-to-video" jobName based
5038
+ // on whether a start frame is wired). Without this, getPrimaryOutput would fall
5039
+ // through to the imageUrl/videoUrl/audioUrl/text default and downstream consumers
5040
+ // could silently misroute the output.
5041
+ "generate-video",
5042
+ // Generate Video Pro — Seedance-2-family multi-segment stitch variant of
5043
+ // generate-video (same "emits videoUrl" contract; a trimmed provider +
5044
+ // handle set). Must mirror generate-video here or its output can't connect
5045
+ // downstream (the recurring "cannot connect the outputs" bug class).
5046
+ "generate-video-pro",
5047
+ // Edit Video Pro — Seedance-2-family span-replace sibling of generate-
5048
+ // video-pro (same "emits videoUrl" contract; source video + prompt in,
5049
+ // ONE video out). Must mirror generate-video-pro here or its output can't
5050
+ // connect downstream (the recurring "cannot connect the outputs" bug class).
5051
+ "edit-video-pro",
5052
+ "upload-video",
5053
+ "youtube-video",
5054
+ "combine-videos",
5055
+ "lip-sync",
5056
+ "speech-to-video",
5057
+ "motion-transfer",
5058
+ "video-upscale",
5059
+ "extend-video",
5060
+ // face-swap output is video (writes generatedVideoUrl, per-result `url`).
5061
+ // Frontend execution-graph already includes it in VIDEO_SOURCE_TYPES; this
5062
+ // entry brings the shared set in line so canvas typed-handle validation
5063
+ // doesn't reject face-swap → video-consumer edges that the orchestrator
5064
+ // would happily route at runtime.
5065
+ "face-swap",
5066
+ "video-retake",
5067
+ // video-sfx: adds an SFX track to a video → emits a video URL. Belongs here so
5068
+ // canvas handle validation accepts video-sfx → video-consumer edges and the
5069
+ // backend routes its output as video (it was previously relying on a fallback).
5070
+ "video-sfx",
5071
+ "suno-music-video",
5072
+ "merge-video-audio",
5073
+ "add-captions",
5074
+ "resize-video",
5075
+ "social-media-format",
5076
+ "trim-video",
5077
+ "render-video",
5078
+ "speed-ramp",
5079
+ "loop-video",
5080
+ "fade-video",
5081
+ "transcode-video",
5082
+ "manual-edit",
5083
+ // Remove Audio: strips the audio track, emits a silent video.
5084
+ "remove-audio",
5085
+ // AI Avatar (HeyGen): avatar + voice/audio → video.
5086
+ "ai-avatar",
5087
+ // Cinematic Avatar (HeyGen cinematic_avatar): prompt + 1–3 avatar looks → video.
5088
+ "cinematic-avatar",
5089
+ // Assemble Narrated Video: fits N (clip, voice) blocks into one MP4 → video.
5090
+ "assemble-narrated-video",
5091
+ // Still to Video: one still image + one audio track → MP4 (local FFmpeg,
5092
+ // no provider). Emits generatedVideoUrl like every other ffmpeg video node.
5093
+ "still-to-video",
5094
+ // Slideshow: 2-100 stills + one optional audio track → MP4 (local FFmpeg,
5095
+ // no provider). Same contract; images arrive via the image-collage lane.
5096
+ "slideshow",
5097
+ // GIF to Video: animated GIF → H.264 MP4 (local FFmpeg, no provider).
5098
+ // Emits generatedVideoUrl so it connects to any downstream video consumer
5099
+ // (e.g. a Seedance video-reference input) by an ordinary edge.
5100
+ "gif-to-video",
5101
+ // 3D Render Pro: authors a scene AND exports it in one operation, settling
5102
+ // with the standard `videoUrl` field. It is a video producer as much as it
5103
+ // is a composition producer — omitting it here is the "cannot connect the
5104
+ // outputs" bug, and its `composition` handle is typed separately.
5105
+ "pro-3d-render"
5106
+ ]);
5107
+ var DYNAMIC_PRODUCER_TYPES = /* @__PURE__ */ new Set([
5108
+ "list",
5109
+ "sub-workflow",
5110
+ "adjust-volume",
5111
+ // Dual-mode: audio in → audio out; video in → video out (+ revoiced audio).
5112
+ // Listed here so canvas validators accept its output on BOTH audio and video
5113
+ // input handles (it also stays in AUDIO_PRODUCER_TYPES as its default).
5114
+ "voice-changer",
5115
+ // voice-changer-pro (renamed from voice-recast in #3581) is a behavioral
5116
+ // twin of voice-changer — identical dual-mode output. Must mirror it in
5117
+ // EVERY producer set or its outputs can't connect (was the "cannot connect
5118
+ // the outputs of voice-changer-pro" bug). Guarded by producer-types.test.ts.
5119
+ "voice-changer-pro",
5120
+ // Dubbing joined the dual-mode family with the full-surface upgrade:
5121
+ // audio in → dubbed audio; video in (or a video sourceUrl) → dubbed VIDEO
5122
+ // (+ audio sidecar). Same wiring contract as voice-changer; stays in
5123
+ // AUDIO_PRODUCER_TYPES as its default. Explicitly asserted in
5124
+ // producer-types.test.ts (the suite does not fail on omission).
5125
+ "dubbing",
5126
+ "reduce",
5127
+ // Dual-output time chunker (UI label "Split into Chunks"; type id stays
5128
+ // "split-media"): video in → video chunks, audio in → audio chunks — two
5129
+ // independent lanes on two output handles. Like voice-changer, the canvas
5130
+ // validator only sees the source NODE type, not which handle a wire leaves,
5131
+ // so it lives here to be accepted on BOTH audio and video input handles. The
5132
+ // backend routes the correct lane by sourceHandle in getPrimaryOutput
5133
+ // (output-extractor.ts); the frontend does so in extractNodeOutput.
5134
+ "split-media"
5135
+ ]);
5136
+ var AUDIO_PRODUCER_TYPES = /* @__PURE__ */ new Set([
5137
+ "text-to-speech",
5138
+ "text-to-audio",
5139
+ "generate-music",
5140
+ "upload-audio",
5141
+ "suno-generate",
5142
+ "suno-cover",
5143
+ "suno-extend",
5144
+ "suno-separate",
5145
+ "audio-separation",
5146
+ "suno-mashup",
5147
+ "suno-replace-section",
5148
+ "suno-add-instrumental",
5149
+ "suno-add-vocals",
5150
+ "suno-convert-wav",
5151
+ "suno-upload-extend",
5152
+ "trim-audio",
5153
+ "mix-audio",
5154
+ "combine-audio",
5155
+ "adjust-volume",
5156
+ "audio-fx",
5157
+ "reference-audio",
5158
+ "audio-isolation",
5159
+ "text-to-dialogue",
5160
+ "voice-changer",
5161
+ // Twin of voice-changer (see DYNAMIC_PRODUCER_TYPES note). Audio is its
5162
+ // default output mode; video mode is handled via DYNAMIC membership.
5163
+ "voice-changer-pro",
5164
+ "dubbing",
5165
+ "voice-remix",
5166
+ "voice-design",
5167
+ // Extract Audio: demuxes a video's audio track to a standalone MP3.
5168
+ "extract-audio"
5169
+ ]);
5170
+ var FAN_OUT_EACH_TYPES = /* @__PURE__ */ new Set([
5171
+ "list",
5172
+ "split-text",
5173
+ "filter-list",
5174
+ "deduplicate",
5175
+ "merge-lists",
5176
+ "sort-list",
5177
+ "selector"
5178
+ ]);
5179
+
5019
5180
  // src/presentation-utils.ts
5020
5181
  var INPUT_NODE_TYPES = /* @__PURE__ */ new Set([
5021
5182
  "text-prompt",
@@ -5193,7 +5354,7 @@ function getOutputNodes(nodes, edges, curatedOnly = true) {
5193
5354
  if (n.data.presentationOutput === true) return true;
5194
5355
  if (n.data.presentationVisible === true) {
5195
5356
  if (NON_OUTPUT_TYPES.has(n.type)) return false;
5196
- return !nodesWithOutgoing.has(n.id) || MEDIA_PRODUCING_TYPES.has(n.type);
5357
+ return !nodesWithOutgoing.has(n.id) || isMediaProducingType(n.type);
5197
5358
  }
5198
5359
  return false;
5199
5360
  }
@@ -5206,8 +5367,15 @@ function getOutputType(nodeType) {
5206
5367
  if (VIDEO_OUTPUT_TYPES.has(nodeType)) return "video";
5207
5368
  if (AUDIO_OUTPUT_TYPES.has(nodeType)) return "audio";
5208
5369
  if (TEXT_OUTPUT_TYPES.has(nodeType)) return "text";
5370
+ if (VIDEO_PRODUCER_TYPES.has(nodeType)) return "video";
5371
+ if (AUDIO_PRODUCER_TYPES.has(nodeType)) return "audio";
5209
5372
  return "data";
5210
5373
  }
5374
+ function isMediaProducingType(nodeType) {
5375
+ if (MEDIA_PRODUCING_TYPES.has(nodeType)) return true;
5376
+ const output = getOutputType(nodeType);
5377
+ return output === "image" || output === "video" || output === "audio";
5378
+ }
5211
5379
  function getNodeResult(nodeData) {
5212
5380
  const previewItems = nodeData.previewItems;
5213
5381
  if (previewItems && previewItems.length > 0) {
@@ -8776,6 +8944,7 @@ var NODE_MAPPABLE_FIELDS = {
8776
8944
  "3d-title": ["titlePrompt"],
8777
8945
  "generate-3d-scene": ["scenePrompt"],
8778
8946
  "edit-3d-scene": ["editPrompt"],
8947
+ "pro-3d-render": ["scenePrompt"],
8779
8948
  "motion-graphics": ["motionPrompt"],
8780
8949
  "generate-script": ["styleGuide"],
8781
8950
  "speech-to-video": ["prompt", "negativePrompt"],
@@ -12913,152 +13082,6 @@ function resolveAudioCrossfadeCurve(id) {
12913
13082
  return CURVES_BY_ID.get(id)?.ffmpeg ?? "tri";
12914
13083
  }
12915
13084
 
12916
- // src/producer-types.ts
12917
- var VIDEO_PRODUCER_TYPES = /* @__PURE__ */ new Set([
12918
- "image-to-video",
12919
- "video-to-video",
12920
- "switchx",
12921
- // Beeble SwitchX relight/composite
12922
- "text-to-video",
12923
- // Unified video node — emits videoUrl identically to i2v/t2v (its payload-builder
12924
- // case dispatches dynamically to "image-to-video" or "text-to-video" jobName based
12925
- // on whether a start frame is wired). Without this, getPrimaryOutput would fall
12926
- // through to the imageUrl/videoUrl/audioUrl/text default and downstream consumers
12927
- // could silently misroute the output.
12928
- "generate-video",
12929
- // Generate Video Pro — Seedance-2-family multi-segment stitch variant of
12930
- // generate-video (same "emits videoUrl" contract; a trimmed provider +
12931
- // handle set). Must mirror generate-video here or its output can't connect
12932
- // downstream (the recurring "cannot connect the outputs" bug class).
12933
- "generate-video-pro",
12934
- // Edit Video Pro — Seedance-2-family span-replace sibling of generate-
12935
- // video-pro (same "emits videoUrl" contract; source video + prompt in,
12936
- // ONE video out). Must mirror generate-video-pro here or its output can't
12937
- // connect downstream (the recurring "cannot connect the outputs" bug class).
12938
- "edit-video-pro",
12939
- "upload-video",
12940
- "youtube-video",
12941
- "combine-videos",
12942
- "lip-sync",
12943
- "speech-to-video",
12944
- "motion-transfer",
12945
- "video-upscale",
12946
- "extend-video",
12947
- // face-swap output is video (writes generatedVideoUrl, per-result `url`).
12948
- // Frontend execution-graph already includes it in VIDEO_SOURCE_TYPES; this
12949
- // entry brings the shared set in line so canvas typed-handle validation
12950
- // doesn't reject face-swap → video-consumer edges that the orchestrator
12951
- // would happily route at runtime.
12952
- "face-swap",
12953
- "video-retake",
12954
- // video-sfx: adds an SFX track to a video → emits a video URL. Belongs here so
12955
- // canvas handle validation accepts video-sfx → video-consumer edges and the
12956
- // backend routes its output as video (it was previously relying on a fallback).
12957
- "video-sfx",
12958
- "suno-music-video",
12959
- "merge-video-audio",
12960
- "add-captions",
12961
- "resize-video",
12962
- "social-media-format",
12963
- "trim-video",
12964
- "render-video",
12965
- "speed-ramp",
12966
- "loop-video",
12967
- "fade-video",
12968
- "transcode-video",
12969
- "manual-edit",
12970
- // Remove Audio: strips the audio track, emits a silent video.
12971
- "remove-audio",
12972
- // AI Avatar (HeyGen): avatar + voice/audio → video.
12973
- "ai-avatar",
12974
- // Cinematic Avatar (HeyGen cinematic_avatar): prompt + 1–3 avatar looks → video.
12975
- "cinematic-avatar",
12976
- // Assemble Narrated Video: fits N (clip, voice) blocks into one MP4 → video.
12977
- "assemble-narrated-video",
12978
- // Still to Video: one still image + one audio track → MP4 (local FFmpeg,
12979
- // no provider). Emits generatedVideoUrl like every other ffmpeg video node.
12980
- "still-to-video",
12981
- // Slideshow: 2-100 stills + one optional audio track → MP4 (local FFmpeg,
12982
- // no provider). Same contract; images arrive via the image-collage lane.
12983
- "slideshow",
12984
- // GIF to Video: animated GIF → H.264 MP4 (local FFmpeg, no provider).
12985
- // Emits generatedVideoUrl so it connects to any downstream video consumer
12986
- // (e.g. a Seedance video-reference input) by an ordinary edge.
12987
- "gif-to-video"
12988
- ]);
12989
- var DYNAMIC_PRODUCER_TYPES = /* @__PURE__ */ new Set([
12990
- "list",
12991
- "sub-workflow",
12992
- "adjust-volume",
12993
- // Dual-mode: audio in → audio out; video in → video out (+ revoiced audio).
12994
- // Listed here so canvas validators accept its output on BOTH audio and video
12995
- // input handles (it also stays in AUDIO_PRODUCER_TYPES as its default).
12996
- "voice-changer",
12997
- // voice-changer-pro (renamed from voice-recast in #3581) is a behavioral
12998
- // twin of voice-changer — identical dual-mode output. Must mirror it in
12999
- // EVERY producer set or its outputs can't connect (was the "cannot connect
13000
- // the outputs of voice-changer-pro" bug). Guarded by producer-types.test.ts.
13001
- "voice-changer-pro",
13002
- // Dubbing joined the dual-mode family with the full-surface upgrade:
13003
- // audio in → dubbed audio; video in (or a video sourceUrl) → dubbed VIDEO
13004
- // (+ audio sidecar). Same wiring contract as voice-changer; stays in
13005
- // AUDIO_PRODUCER_TYPES as its default. Explicitly asserted in
13006
- // producer-types.test.ts (the suite does not fail on omission).
13007
- "dubbing",
13008
- "reduce",
13009
- // Dual-output time chunker (UI label "Split into Chunks"; type id stays
13010
- // "split-media"): video in → video chunks, audio in → audio chunks — two
13011
- // independent lanes on two output handles. Like voice-changer, the canvas
13012
- // validator only sees the source NODE type, not which handle a wire leaves,
13013
- // so it lives here to be accepted on BOTH audio and video input handles. The
13014
- // backend routes the correct lane by sourceHandle in getPrimaryOutput
13015
- // (output-extractor.ts); the frontend does so in extractNodeOutput.
13016
- "split-media"
13017
- ]);
13018
- var AUDIO_PRODUCER_TYPES = /* @__PURE__ */ new Set([
13019
- "text-to-speech",
13020
- "text-to-audio",
13021
- "generate-music",
13022
- "upload-audio",
13023
- "suno-generate",
13024
- "suno-cover",
13025
- "suno-extend",
13026
- "suno-separate",
13027
- "audio-separation",
13028
- "suno-mashup",
13029
- "suno-replace-section",
13030
- "suno-add-instrumental",
13031
- "suno-add-vocals",
13032
- "suno-convert-wav",
13033
- "suno-upload-extend",
13034
- "trim-audio",
13035
- "mix-audio",
13036
- "combine-audio",
13037
- "adjust-volume",
13038
- "audio-fx",
13039
- "reference-audio",
13040
- "audio-isolation",
13041
- "text-to-dialogue",
13042
- "voice-changer",
13043
- // Twin of voice-changer (see DYNAMIC_PRODUCER_TYPES note). Audio is its
13044
- // default output mode; video mode is handled via DYNAMIC membership.
13045
- "voice-changer-pro",
13046
- "dubbing",
13047
- "voice-remix",
13048
- "voice-design",
13049
- // Extract Audio: demuxes a video's audio track to a standalone MP3.
13050
- "extract-audio"
13051
- ]);
13052
- var FAN_OUT_EACH_TYPES = /* @__PURE__ */ new Set([
13053
- "list",
13054
- "split-text",
13055
- "filter-list",
13056
- "deduplicate",
13057
- "merge-lists",
13058
- "sort-list",
13059
- "selector"
13060
- ]);
13061
-
13062
13085
  // src/suno-track-sources.ts
13063
13086
  var SUNO_TRACK_SOURCE_TYPES = /* @__PURE__ */ new Set([
13064
13087
  "suno-generate",
@@ -16250,8 +16273,8 @@ function scene3DCameraTrackIssues(track) {
16250
16273
  }
16251
16274
  const quaternionTolerance = SCENE3D_CAMERA_TRACK_LIMITS.quaternionTolerance;
16252
16275
  track.samples.forEach((sample, index) => {
16253
- const [x, y, z22, w] = sample.quaternion;
16254
- const norm = Math.sqrt(x * x + y * y + z22 * z22 + w * w);
16276
+ const [x, y, z23, w] = sample.quaternion;
16277
+ const norm = Math.sqrt(x * x + y * y + z23 * z23 + w * w);
16255
16278
  if (Math.abs(norm - 1) > quaternionTolerance) {
16256
16279
  issues.push({
16257
16280
  path: ["samples", index, "quaternion"],
@@ -16342,6 +16365,121 @@ function parseScene3DCameraTrackJson(text) {
16342
16365
  }
16343
16366
  return { ok: true, value: parsed.data };
16344
16367
  }
16368
+ var PRO3D_RENDER_NODE_TYPE = "pro-3d-render";
16369
+ var PRO3D_RENDER_LABEL = "3D Render Pro";
16370
+ var PRO3D_RENDER_CREDIT_ID = "pro-3d-render";
16371
+ var PRO3D_RENDER_ENGINES = ["blender-cloud", "blender-local"];
16372
+ var PRO3D_RENDER_DEFAULT_ENGINE = "blender-cloud";
16373
+ var PRO3D_RENDER_QUALITY_PROFILES = ["standard"];
16374
+ var PRO3D_RENDER_DEFAULT_QUALITY = "standard";
16375
+ var PRO3D_RENDER_STYLES = ["clay"];
16376
+ var PRO3D_RENDER_DEFAULT_STYLE = "clay";
16377
+ var PRO3D_RENDER_MIN_REPAIR_PASSES = 0;
16378
+ var PRO3D_RENDER_MAX_REPAIR_PASSES = 2;
16379
+ var PRO3D_RENDER_DEFAULT_REPAIR_PASSES = 2;
16380
+ var PRO3D_RENDER_ASPECT_RATIOS = ["16:9", "9:16", "1:1", "4:5", "21:9"];
16381
+ var PRO3D_RENDER_PROMPT_MAX = 8e3;
16382
+ var PRO3D_RENDER_LIMITS = {
16383
+ promptMax: PRO3D_RENDER_PROMPT_MAX,
16384
+ editPromptMax: PRO3D_RENDER_PROMPT_MAX,
16385
+ minDurationSeconds: SCENE3D_LIMITS.minDurationSeconds,
16386
+ maxDurationSeconds: SCENE3D_LIMITS.maxDurationSeconds,
16387
+ minFps: SCENE3D_LIMITS.minFps,
16388
+ maxFps: SCENE3D_LIMITS.maxFps,
16389
+ maxReferences: SCENE3D_LIMITS.maxReferences,
16390
+ /** Opaque ids the caller echoes back (quote, export, connection). */
16391
+ maxIdLength: 200,
16392
+ /** `Idempotency-Key` bounds — the platform's floor, with a ceiling so an
16393
+ * unbounded header can never reach a lookup or a database column. */
16394
+ minIdempotencyKeyLength: 8,
16395
+ maxIdempotencyKeyLength: 255
16396
+ };
16397
+ var PRO3D_RENDER_SOURCE_KINDS = ["prompt", "scene", "local-export"];
16398
+ function isPro3DRenderRenderOnly(source) {
16399
+ return source.kind === "scene" && source.editPrompt === void 0;
16400
+ }
16401
+ function pro3DRenderProducedSchemaVersion(source) {
16402
+ return source.kind === "scene" ? null : 2;
16403
+ }
16404
+ var pro3DRenderQuoteSchema = zod.z.object({
16405
+ quoteId: zod.z.string().min(1),
16406
+ expiresAt: zod.z.string().min(1),
16407
+ maxCredits: zod.z.number(),
16408
+ breakdown: zod.z.array(
16409
+ zod.z.object({ code: zod.z.string(), label: zod.z.string(), credits: zod.z.number() }).passthrough()
16410
+ ),
16411
+ pricingVersion: zod.z.string(),
16412
+ capabilitiesVersion: zod.z.string(),
16413
+ normalizedInputHash: zod.z.string().min(1)
16414
+ }).passthrough();
16415
+ function isPro3DRenderQuote(value) {
16416
+ return pro3DRenderQuoteSchema.safeParse(value).success;
16417
+ }
16418
+ var pro3DRenderJobOutputSchema = zod.z.object({
16419
+ videoUrl: zod.z.string().min(1),
16420
+ scenePlan: scene3DAnyPlanSchema,
16421
+ sceneRevisionId: zod.z.string().min(1),
16422
+ posterAssetId: zod.z.string().min(1),
16423
+ sourceArtifactId: zod.z.string().min(1).optional(),
16424
+ validation: zod.z.object({
16425
+ status: zod.z.literal("passed"),
16426
+ reportAssetId: zod.z.string().min(1),
16427
+ warnings: zod.z.array(
16428
+ zod.z.object({
16429
+ code: zod.z.string(),
16430
+ message: zod.z.string(),
16431
+ shotId: zod.z.string().optional()
16432
+ }).passthrough()
16433
+ )
16434
+ }).passthrough(),
16435
+ renderer: zod.z.string().min(1),
16436
+ metadata: zod.z.object({
16437
+ width: zod.z.number().int().positive(),
16438
+ height: zod.z.number().int().positive(),
16439
+ fps: zod.z.number().positive(),
16440
+ frames: zod.z.number().int().positive(),
16441
+ duration: zod.z.number().positive()
16442
+ }).passthrough(),
16443
+ changeSummary: zod.z.string().optional()
16444
+ }).passthrough();
16445
+ function isPro3DRenderJobOutput(value) {
16446
+ return pro3DRenderJobOutputSchema.safeParse(value).success;
16447
+ }
16448
+ var pro3DRenderCoreOutputSchema = zod.z.object({
16449
+ videoUrl: zod.z.string().min(1),
16450
+ scenePlan: scene3DAnyPlanSchema
16451
+ }).passthrough();
16452
+ function buildPro3DRenderSource(input) {
16453
+ if (input.sourceMode === "scene") {
16454
+ const revisionId = input.revisionId?.trim();
16455
+ const sourceJobId = input.sourceJobId?.trim();
16456
+ if (!revisionId) {
16457
+ return { ok: false, message: "no scene to render \u2014 wire a 3D scene in, or run this node once." };
16458
+ }
16459
+ const editPrompt = input.editPrompt?.trim();
16460
+ return {
16461
+ ok: true,
16462
+ source: { kind: "scene", revisionId, ...sourceJobId ? { sourceJobId } : {}, ...editPrompt ? { editPrompt } : {} }
16463
+ };
16464
+ }
16465
+ const prompt = input.prompt?.trim();
16466
+ if (!prompt) {
16467
+ return { ok: false, message: "no brief \u2014 describe the scene, or wire a prompt in." };
16468
+ }
16469
+ const references = input.references ?? [];
16470
+ return {
16471
+ ok: true,
16472
+ source: { kind: "prompt", prompt, ...references.length > 0 ? { references } : {} }
16473
+ };
16474
+ }
16475
+ function pro3DRenderTimingOverrides(input) {
16476
+ if (input.source.kind === "scene" && !input.overrideSourceTiming) return {};
16477
+ const out = {};
16478
+ if (typeof input.durationSeconds === "number") out.durationSeconds = input.durationSeconds;
16479
+ if (typeof input.fps === "number") out.fps = input.fps;
16480
+ if (typeof input.aspectRatio === "string") out.aspectRatio = input.aspectRatio;
16481
+ return out;
16482
+ }
16345
16483
 
16346
16484
  // src/studio-transient.ts
16347
16485
  var STUDIO_TRANSIENT_KEYS = [
@@ -16524,6 +16662,83 @@ async function applyScene3DV2EditOperations(input, operations, options) {
16524
16662
  return { ok: true, plan: { ...plan, provenance: { ...plan.provenance, contentHash } }, changeSummary: `Applied ${ops.data.length} scene edit${ops.data.length === 1 ? "" : "s"}` };
16525
16663
  }
16526
16664
 
16665
+ // src/scene3d-authoring-engine.ts
16666
+ var SCENE3D_BASIC_ENGINE = "basic";
16667
+ var SCENE3D_AUTHORING_ENGINES = [SCENE3D_BASIC_ENGINE, ...SCENE3D_V2_ENGINES];
16668
+ var SCENE3D_DEFAULT_ADVANCED_ENGINE = "blender-cloud";
16669
+ function isScene3DAuthoringEngine(value) {
16670
+ return typeof value === "string" && SCENE3D_AUTHORING_ENGINES.includes(value);
16671
+ }
16672
+ function advancedFields(engine) {
16673
+ return { engine, acceptedSceneSchemaVersions: [...SCENE3D_SUPPORTED_SCHEMA_VERSIONS] };
16674
+ }
16675
+ function serves(available, engine) {
16676
+ return available === void 0 || available.includes(engine);
16677
+ }
16678
+ function planAuthoringEngine(plan) {
16679
+ const provenance = plan?.provenance;
16680
+ const engine = provenance?.engine;
16681
+ return typeof engine === "string" && isKnownScene3DEngine(engine) ? engine : void 0;
16682
+ }
16683
+ function resolveScene3DAuthoringEngine(input) {
16684
+ const requested = typeof input.requested === "string" && input.requested.trim() !== "" ? input.requested.trim() : void 0;
16685
+ if (requested !== void 0 && !isScene3DAuthoringEngine(requested)) {
16686
+ return {
16687
+ ok: false,
16688
+ code: "unknown_engine",
16689
+ message: `"${requested}" is not a 3D authoring engine \u2014 choose Basic, or an advanced engine this install offers.`
16690
+ };
16691
+ }
16692
+ const version = input.plan === void 0 ? void 0 : scene3DPlanSchemaVersion(input.plan);
16693
+ if (version !== void 0 && version !== null && !SCENE3D_SUPPORTED_SCHEMA_VERSIONS.includes(version)) {
16694
+ return {
16695
+ ok: false,
16696
+ code: "unsupported_schema_version",
16697
+ message: `This scene uses schema version ${version}, which this version of Nodaro cannot edit.`
16698
+ };
16699
+ }
16700
+ const isV2 = version === SCENE3D_SCHEMA_VERSION_V2;
16701
+ if (isV2) {
16702
+ if (requested === SCENE3D_BASIC_ENGINE) {
16703
+ return {
16704
+ ok: false,
16705
+ code: "schema_requires_advanced",
16706
+ message: "This scene was authored by an advanced engine (schema v2) and cannot be edited on the Basic engine \u2014 switch this node's engine to the advanced one."
16707
+ };
16708
+ }
16709
+ if (requested !== void 0) {
16710
+ return serves(input.availableEngines, requested) ? { ok: true, lane: "advanced", engine: requested, fields: advancedFields(requested) } : unavailable(requested);
16711
+ }
16712
+ const preferred = [];
16713
+ const authored = planAuthoringEngine(input.plan);
16714
+ if (authored) preferred.push(authored);
16715
+ if (!preferred.includes(SCENE3D_DEFAULT_ADVANCED_ENGINE)) preferred.push(SCENE3D_DEFAULT_ADVANCED_ENGINE);
16716
+ const engine2 = preferred.find((candidate) => serves(input.availableEngines, candidate));
16717
+ if (!engine2) {
16718
+ return {
16719
+ ok: false,
16720
+ code: "advanced_unavailable",
16721
+ message: "This scene needs an advanced 3D engine to edit, and this install does not have one available."
16722
+ };
16723
+ }
16724
+ return { ok: true, lane: "advanced", engine: engine2, fields: advancedFields(engine2) };
16725
+ }
16726
+ if (requested === void 0 || requested === SCENE3D_BASIC_ENGINE) {
16727
+ return { ok: true, lane: "basic", engine: void 0, fields: {} };
16728
+ }
16729
+ const engine = requested;
16730
+ if (!serves(input.availableEngines, engine)) return unavailable(engine);
16731
+ return { ok: true, lane: "advanced", engine, fields: advancedFields(engine) };
16732
+ }
16733
+ function unavailable(engine) {
16734
+ return {
16735
+ ok: false,
16736
+ code: "engine_unavailable",
16737
+ message: `The "${engine}" 3D authoring engine is not available on this install.`
16738
+ };
16739
+ }
16740
+ var SCENE3D_BASIC_SCHEMA_VERSION = SCENE3D_SCHEMA_VERSION;
16741
+
16527
16742
  exports.ACCESS_LEVELS = ACCESS_LEVELS;
16528
16743
  exports.ACTIVE_SCENE_HELPERS = ACTIVE_SCENE_HELPERS;
16529
16744
  exports.ADVANCED_MODE_UNAVAILABLE_REASON = ADVANCED_MODE_UNAVAILABLE_REASON;
@@ -16819,6 +17034,22 @@ exports.PRESET_LABELS = PRESET_LABELS;
16819
17034
  exports.PRESET_SETTING_KEYS = PRESET_SETTING_KEYS;
16820
17035
  exports.PRICING_DEFAULT_DURATION_SEC = PRICING_DEFAULT_DURATION_SEC;
16821
17036
  exports.PRICING_DEFAULT_RESOLUTION = PRICING_DEFAULT_RESOLUTION;
17037
+ exports.PRO3D_RENDER_ASPECT_RATIOS = PRO3D_RENDER_ASPECT_RATIOS;
17038
+ exports.PRO3D_RENDER_CREDIT_ID = PRO3D_RENDER_CREDIT_ID;
17039
+ exports.PRO3D_RENDER_DEFAULT_ENGINE = PRO3D_RENDER_DEFAULT_ENGINE;
17040
+ exports.PRO3D_RENDER_DEFAULT_QUALITY = PRO3D_RENDER_DEFAULT_QUALITY;
17041
+ exports.PRO3D_RENDER_DEFAULT_REPAIR_PASSES = PRO3D_RENDER_DEFAULT_REPAIR_PASSES;
17042
+ exports.PRO3D_RENDER_DEFAULT_STYLE = PRO3D_RENDER_DEFAULT_STYLE;
17043
+ exports.PRO3D_RENDER_ENGINES = PRO3D_RENDER_ENGINES;
17044
+ exports.PRO3D_RENDER_LABEL = PRO3D_RENDER_LABEL;
17045
+ exports.PRO3D_RENDER_LIMITS = PRO3D_RENDER_LIMITS;
17046
+ exports.PRO3D_RENDER_MAX_REPAIR_PASSES = PRO3D_RENDER_MAX_REPAIR_PASSES;
17047
+ exports.PRO3D_RENDER_MIN_REPAIR_PASSES = PRO3D_RENDER_MIN_REPAIR_PASSES;
17048
+ exports.PRO3D_RENDER_NODE_TYPE = PRO3D_RENDER_NODE_TYPE;
17049
+ exports.PRO3D_RENDER_PROMPT_MAX = PRO3D_RENDER_PROMPT_MAX;
17050
+ exports.PRO3D_RENDER_QUALITY_PROFILES = PRO3D_RENDER_QUALITY_PROFILES;
17051
+ exports.PRO3D_RENDER_SOURCE_KINDS = PRO3D_RENDER_SOURCE_KINDS;
17052
+ exports.PRO3D_RENDER_STYLES = PRO3D_RENDER_STYLES;
16822
17053
  exports.PROMPT_HARD_CEILING = PROMPT_HARD_CEILING;
16823
17054
  exports.PROMPT_PREFIX_KEY = PROMPT_PREFIX_KEY;
16824
17055
  exports.PROMPT_SUFFIX_KEY = PROMPT_SUFFIX_KEY;
@@ -16854,10 +17085,14 @@ exports.RESERVED_TEMPLATE_VARS = RESERVED_TEMPLATE_VARS;
16854
17085
  exports.SCENE3D_ASSET_KINDS = SCENE3D_ASSET_KINDS;
16855
17086
  exports.SCENE3D_ASSET_ROLES = SCENE3D_ASSET_ROLES;
16856
17087
  exports.SCENE3D_ASSET_ROLE_KINDS = SCENE3D_ASSET_ROLE_KINDS;
17088
+ exports.SCENE3D_AUTHORING_ENGINES = SCENE3D_AUTHORING_ENGINES;
17089
+ exports.SCENE3D_BASIC_ENGINE = SCENE3D_BASIC_ENGINE;
17090
+ exports.SCENE3D_BASIC_SCHEMA_VERSION = SCENE3D_BASIC_SCHEMA_VERSION;
16857
17091
  exports.SCENE3D_CAMERA_TRACK_FORMAT = SCENE3D_CAMERA_TRACK_FORMAT;
16858
17092
  exports.SCENE3D_CAMERA_TRACK_LIMITS = SCENE3D_CAMERA_TRACK_LIMITS;
16859
17093
  exports.SCENE3D_CAMERA_TRACK_VERSION = SCENE3D_CAMERA_TRACK_VERSION;
16860
17094
  exports.SCENE3D_CLAY_LIGHTING_PRESETS = SCENE3D_CLAY_LIGHTING_PRESETS;
17095
+ exports.SCENE3D_DEFAULT_ADVANCED_ENGINE = SCENE3D_DEFAULT_ADVANCED_ENGINE;
16861
17096
  exports.SCENE3D_DEFAULT_DURATION_SECONDS = SCENE3D_DEFAULT_DURATION_SECONDS;
16862
17097
  exports.SCENE3D_DEFAULT_ENTITY_CAPABILITIES = SCENE3D_DEFAULT_ENTITY_CAPABILITIES;
16863
17098
  exports.SCENE3D_DEFAULT_FPS = SCENE3D_DEFAULT_FPS;
@@ -17070,6 +17305,7 @@ exports.buildModelTree = buildModelTree;
17070
17305
  exports.buildMotionCreditModelIdentifier = buildMotionCreditModelIdentifier;
17071
17306
  exports.buildNodePresetExport = buildNodePresetExport;
17072
17307
  exports.buildPanelPrompt = buildPanelPrompt;
17308
+ exports.buildPro3DRenderSource = buildPro3DRenderSource;
17073
17309
  exports.buildProgressSegments = buildProgressSegments;
17074
17310
  exports.buildRangeLabel = buildRangeLabel;
17075
17311
  exports.buildScraperCreditId = buildScraperCreditId;
@@ -17229,6 +17465,10 @@ exports.isObjectAspectRatio = isObjectAspectRatio;
17229
17465
  exports.isOversizedScene = isOversizedScene;
17230
17466
  exports.isPaygRetentionActive = isPaygRetentionActive;
17231
17467
  exports.isPerSecondLipSyncProvider = isPerSecondLipSyncProvider;
17468
+ exports.isPro3DRenderJobOutput = isPro3DRenderJobOutput;
17469
+ exports.isPro3DRenderQuote = isPro3DRenderQuote;
17470
+ exports.isPro3DRenderRenderOnly = isPro3DRenderRenderOnly;
17471
+ exports.isScene3DAuthoringEngine = isScene3DAuthoringEngine;
17232
17472
  exports.isScene3DCameraTrack = isScene3DCameraTrack;
17233
17473
  exports.isScene3DHttpUrl = isScene3DHttpUrl;
17234
17474
  exports.isScene3DPlan = isScene3DPlan;
@@ -17304,6 +17544,11 @@ exports.presetApplyClearKeys = presetApplyClearKeys;
17304
17544
  exports.presetDataMatches = presetDataMatches;
17305
17545
  exports.presetEntries = presetEntries;
17306
17546
  exports.pricedVideoSelection = pricedVideoSelection;
17547
+ exports.pro3DRenderCoreOutputSchema = pro3DRenderCoreOutputSchema;
17548
+ exports.pro3DRenderJobOutputSchema = pro3DRenderJobOutputSchema;
17549
+ exports.pro3DRenderProducedSchemaVersion = pro3DRenderProducedSchemaVersion;
17550
+ exports.pro3DRenderQuoteSchema = pro3DRenderQuoteSchema;
17551
+ exports.pro3DRenderTimingOverrides = pro3DRenderTimingOverrides;
17307
17552
  exports.qualityOptionsByKind = qualityOptionsByKind;
17308
17553
  exports.readPromptAffixes = readPromptAffixes;
17309
17554
  exports.refHandleCategory = refHandleCategory;
@@ -17340,6 +17585,7 @@ exports.resolveNormalizedImageGen = resolveNormalizedImageGen;
17340
17585
  exports.resolveObjectAspectRatio = resolveObjectAspectRatio;
17341
17586
  exports.resolvePipelineModel = resolvePipelineModel;
17342
17587
  exports.resolveRelativeWindowToken = resolveRelativeWindowToken;
17588
+ exports.resolveScene3DAuthoringEngine = resolveScene3DAuthoringEngine;
17343
17589
  exports.resolveScraperCreditId = resolveScraperCreditId;
17344
17590
  exports.resolveSelectorRefs = resolveSelectorRefs;
17345
17591
  exports.resolveSeparator = resolveSeparator;