@nodaro/shared 3.0.0 → 3.2.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",
@@ -15356,6 +15379,7 @@ var scene3DEntityV2Schema = zod.z.object({
15356
15379
  position: vec3Schema.optional(),
15357
15380
  rotation: rotationVec3Schema.optional(),
15358
15381
  scale: scaleVec3Schema.optional(),
15382
+ visible: zod.z.boolean().optional(),
15359
15383
  identityColor: scene3DColorSchema.optional(),
15360
15384
  anchors: zod.z.array(scene3DAnchorSchema).max(SCENE3D_V2_LIMITS.maxAnchorsPerEntity).optional(),
15361
15385
  capabilities: zod.z.array(scene3DEntityCapabilitySchema).max(SCENE3D_ENTITY_CAPABILITIES.length).optional(),
@@ -16250,8 +16274,8 @@ function scene3DCameraTrackIssues(track) {
16250
16274
  }
16251
16275
  const quaternionTolerance = SCENE3D_CAMERA_TRACK_LIMITS.quaternionTolerance;
16252
16276
  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);
16277
+ const [x, y, z23, w] = sample.quaternion;
16278
+ const norm = Math.sqrt(x * x + y * y + z23 * z23 + w * w);
16255
16279
  if (Math.abs(norm - 1) > quaternionTolerance) {
16256
16280
  issues.push({
16257
16281
  path: ["samples", index, "quaternion"],
@@ -16342,6 +16366,121 @@ function parseScene3DCameraTrackJson(text) {
16342
16366
  }
16343
16367
  return { ok: true, value: parsed.data };
16344
16368
  }
16369
+ var PRO3D_RENDER_NODE_TYPE = "pro-3d-render";
16370
+ var PRO3D_RENDER_LABEL = "3D Render Pro";
16371
+ var PRO3D_RENDER_CREDIT_ID = "pro-3d-render";
16372
+ var PRO3D_RENDER_ENGINES = ["blender-cloud", "blender-local"];
16373
+ var PRO3D_RENDER_DEFAULT_ENGINE = "blender-cloud";
16374
+ var PRO3D_RENDER_QUALITY_PROFILES = ["standard"];
16375
+ var PRO3D_RENDER_DEFAULT_QUALITY = "standard";
16376
+ var PRO3D_RENDER_STYLES = ["clay"];
16377
+ var PRO3D_RENDER_DEFAULT_STYLE = "clay";
16378
+ var PRO3D_RENDER_MIN_REPAIR_PASSES = 0;
16379
+ var PRO3D_RENDER_MAX_REPAIR_PASSES = 2;
16380
+ var PRO3D_RENDER_DEFAULT_REPAIR_PASSES = 2;
16381
+ var PRO3D_RENDER_ASPECT_RATIOS = ["16:9", "9:16", "1:1", "4:5", "21:9"];
16382
+ var PRO3D_RENDER_PROMPT_MAX = 8e3;
16383
+ var PRO3D_RENDER_LIMITS = {
16384
+ promptMax: PRO3D_RENDER_PROMPT_MAX,
16385
+ editPromptMax: PRO3D_RENDER_PROMPT_MAX,
16386
+ minDurationSeconds: SCENE3D_LIMITS.minDurationSeconds,
16387
+ maxDurationSeconds: SCENE3D_LIMITS.maxDurationSeconds,
16388
+ minFps: SCENE3D_LIMITS.minFps,
16389
+ maxFps: SCENE3D_LIMITS.maxFps,
16390
+ maxReferences: SCENE3D_LIMITS.maxReferences,
16391
+ /** Opaque ids the caller echoes back (quote, export, connection). */
16392
+ maxIdLength: 200,
16393
+ /** `Idempotency-Key` bounds — the platform's floor, with a ceiling so an
16394
+ * unbounded header can never reach a lookup or a database column. */
16395
+ minIdempotencyKeyLength: 8,
16396
+ maxIdempotencyKeyLength: 255
16397
+ };
16398
+ var PRO3D_RENDER_SOURCE_KINDS = ["prompt", "scene", "local-export"];
16399
+ function isPro3DRenderRenderOnly(source) {
16400
+ return source.kind === "scene" && source.editPrompt === void 0;
16401
+ }
16402
+ function pro3DRenderProducedSchemaVersion(source) {
16403
+ return source.kind === "scene" ? null : 2;
16404
+ }
16405
+ var pro3DRenderQuoteSchema = zod.z.object({
16406
+ quoteId: zod.z.string().min(1),
16407
+ expiresAt: zod.z.string().min(1),
16408
+ maxCredits: zod.z.number(),
16409
+ breakdown: zod.z.array(
16410
+ zod.z.object({ code: zod.z.string(), label: zod.z.string(), credits: zod.z.number() }).passthrough()
16411
+ ),
16412
+ pricingVersion: zod.z.string(),
16413
+ capabilitiesVersion: zod.z.string(),
16414
+ normalizedInputHash: zod.z.string().min(1)
16415
+ }).passthrough();
16416
+ function isPro3DRenderQuote(value) {
16417
+ return pro3DRenderQuoteSchema.safeParse(value).success;
16418
+ }
16419
+ var pro3DRenderJobOutputSchema = zod.z.object({
16420
+ videoUrl: zod.z.string().min(1),
16421
+ scenePlan: scene3DAnyPlanSchema,
16422
+ sceneRevisionId: zod.z.string().min(1),
16423
+ posterAssetId: zod.z.string().min(1),
16424
+ sourceArtifactId: zod.z.string().min(1).optional(),
16425
+ validation: zod.z.object({
16426
+ status: zod.z.literal("passed"),
16427
+ reportAssetId: zod.z.string().min(1),
16428
+ warnings: zod.z.array(
16429
+ zod.z.object({
16430
+ code: zod.z.string(),
16431
+ message: zod.z.string(),
16432
+ shotId: zod.z.string().optional()
16433
+ }).passthrough()
16434
+ )
16435
+ }).passthrough(),
16436
+ renderer: zod.z.string().min(1),
16437
+ metadata: zod.z.object({
16438
+ width: zod.z.number().int().positive(),
16439
+ height: zod.z.number().int().positive(),
16440
+ fps: zod.z.number().positive(),
16441
+ frames: zod.z.number().int().positive(),
16442
+ duration: zod.z.number().positive()
16443
+ }).passthrough(),
16444
+ changeSummary: zod.z.string().optional()
16445
+ }).passthrough();
16446
+ function isPro3DRenderJobOutput(value) {
16447
+ return pro3DRenderJobOutputSchema.safeParse(value).success;
16448
+ }
16449
+ var pro3DRenderCoreOutputSchema = zod.z.object({
16450
+ videoUrl: zod.z.string().min(1),
16451
+ scenePlan: scene3DAnyPlanSchema
16452
+ }).passthrough();
16453
+ function buildPro3DRenderSource(input) {
16454
+ if (input.sourceMode === "scene") {
16455
+ const revisionId = input.revisionId?.trim();
16456
+ const sourceJobId = input.sourceJobId?.trim();
16457
+ if (!revisionId) {
16458
+ return { ok: false, message: "no scene to render \u2014 wire a 3D scene in, or run this node once." };
16459
+ }
16460
+ const editPrompt = input.editPrompt?.trim();
16461
+ return {
16462
+ ok: true,
16463
+ source: { kind: "scene", revisionId, ...sourceJobId ? { sourceJobId } : {}, ...editPrompt ? { editPrompt } : {} }
16464
+ };
16465
+ }
16466
+ const prompt = input.prompt?.trim();
16467
+ if (!prompt) {
16468
+ return { ok: false, message: "no brief \u2014 describe the scene, or wire a prompt in." };
16469
+ }
16470
+ const references = input.references ?? [];
16471
+ return {
16472
+ ok: true,
16473
+ source: { kind: "prompt", prompt, ...references.length > 0 ? { references } : {} }
16474
+ };
16475
+ }
16476
+ function pro3DRenderTimingOverrides(input) {
16477
+ if (input.source.kind === "scene" && !input.overrideSourceTiming) return {};
16478
+ const out = {};
16479
+ if (typeof input.durationSeconds === "number") out.durationSeconds = input.durationSeconds;
16480
+ if (typeof input.fps === "number") out.fps = input.fps;
16481
+ if (typeof input.aspectRatio === "string") out.aspectRatio = input.aspectRatio;
16482
+ return out;
16483
+ }
16345
16484
 
16346
16485
  // src/studio-transient.ts
16347
16486
  var STUDIO_TRANSIENT_KEYS = [
@@ -16524,6 +16663,83 @@ async function applyScene3DV2EditOperations(input, operations, options) {
16524
16663
  return { ok: true, plan: { ...plan, provenance: { ...plan.provenance, contentHash } }, changeSummary: `Applied ${ops.data.length} scene edit${ops.data.length === 1 ? "" : "s"}` };
16525
16664
  }
16526
16665
 
16666
+ // src/scene3d-authoring-engine.ts
16667
+ var SCENE3D_BASIC_ENGINE = "basic";
16668
+ var SCENE3D_AUTHORING_ENGINES = [SCENE3D_BASIC_ENGINE, ...SCENE3D_V2_ENGINES];
16669
+ var SCENE3D_DEFAULT_ADVANCED_ENGINE = "blender-cloud";
16670
+ function isScene3DAuthoringEngine(value) {
16671
+ return typeof value === "string" && SCENE3D_AUTHORING_ENGINES.includes(value);
16672
+ }
16673
+ function advancedFields(engine) {
16674
+ return { engine, acceptedSceneSchemaVersions: [...SCENE3D_SUPPORTED_SCHEMA_VERSIONS] };
16675
+ }
16676
+ function serves(available, engine) {
16677
+ return available === void 0 || available.includes(engine);
16678
+ }
16679
+ function planAuthoringEngine(plan) {
16680
+ const provenance = plan?.provenance;
16681
+ const engine = provenance?.engine;
16682
+ return typeof engine === "string" && isKnownScene3DEngine(engine) ? engine : void 0;
16683
+ }
16684
+ function resolveScene3DAuthoringEngine(input) {
16685
+ const requested = typeof input.requested === "string" && input.requested.trim() !== "" ? input.requested.trim() : void 0;
16686
+ if (requested !== void 0 && !isScene3DAuthoringEngine(requested)) {
16687
+ return {
16688
+ ok: false,
16689
+ code: "unknown_engine",
16690
+ message: `"${requested}" is not a 3D authoring engine \u2014 choose Basic, or an advanced engine this install offers.`
16691
+ };
16692
+ }
16693
+ const version = input.plan === void 0 ? void 0 : scene3DPlanSchemaVersion(input.plan);
16694
+ if (version !== void 0 && version !== null && !SCENE3D_SUPPORTED_SCHEMA_VERSIONS.includes(version)) {
16695
+ return {
16696
+ ok: false,
16697
+ code: "unsupported_schema_version",
16698
+ message: `This scene uses schema version ${version}, which this version of Nodaro cannot edit.`
16699
+ };
16700
+ }
16701
+ const isV2 = version === SCENE3D_SCHEMA_VERSION_V2;
16702
+ if (isV2) {
16703
+ if (requested === SCENE3D_BASIC_ENGINE) {
16704
+ return {
16705
+ ok: false,
16706
+ code: "schema_requires_advanced",
16707
+ 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."
16708
+ };
16709
+ }
16710
+ if (requested !== void 0) {
16711
+ return serves(input.availableEngines, requested) ? { ok: true, lane: "advanced", engine: requested, fields: advancedFields(requested) } : unavailable(requested);
16712
+ }
16713
+ const preferred = [];
16714
+ const authored = planAuthoringEngine(input.plan);
16715
+ if (authored) preferred.push(authored);
16716
+ if (!preferred.includes(SCENE3D_DEFAULT_ADVANCED_ENGINE)) preferred.push(SCENE3D_DEFAULT_ADVANCED_ENGINE);
16717
+ const engine2 = preferred.find((candidate) => serves(input.availableEngines, candidate));
16718
+ if (!engine2) {
16719
+ return {
16720
+ ok: false,
16721
+ code: "advanced_unavailable",
16722
+ message: "This scene needs an advanced 3D engine to edit, and this install does not have one available."
16723
+ };
16724
+ }
16725
+ return { ok: true, lane: "advanced", engine: engine2, fields: advancedFields(engine2) };
16726
+ }
16727
+ if (requested === void 0 || requested === SCENE3D_BASIC_ENGINE) {
16728
+ return { ok: true, lane: "basic", engine: void 0, fields: {} };
16729
+ }
16730
+ const engine = requested;
16731
+ if (!serves(input.availableEngines, engine)) return unavailable(engine);
16732
+ return { ok: true, lane: "advanced", engine, fields: advancedFields(engine) };
16733
+ }
16734
+ function unavailable(engine) {
16735
+ return {
16736
+ ok: false,
16737
+ code: "engine_unavailable",
16738
+ message: `The "${engine}" 3D authoring engine is not available on this install.`
16739
+ };
16740
+ }
16741
+ var SCENE3D_BASIC_SCHEMA_VERSION = SCENE3D_SCHEMA_VERSION;
16742
+
16527
16743
  exports.ACCESS_LEVELS = ACCESS_LEVELS;
16528
16744
  exports.ACTIVE_SCENE_HELPERS = ACTIVE_SCENE_HELPERS;
16529
16745
  exports.ADVANCED_MODE_UNAVAILABLE_REASON = ADVANCED_MODE_UNAVAILABLE_REASON;
@@ -16819,6 +17035,22 @@ exports.PRESET_LABELS = PRESET_LABELS;
16819
17035
  exports.PRESET_SETTING_KEYS = PRESET_SETTING_KEYS;
16820
17036
  exports.PRICING_DEFAULT_DURATION_SEC = PRICING_DEFAULT_DURATION_SEC;
16821
17037
  exports.PRICING_DEFAULT_RESOLUTION = PRICING_DEFAULT_RESOLUTION;
17038
+ exports.PRO3D_RENDER_ASPECT_RATIOS = PRO3D_RENDER_ASPECT_RATIOS;
17039
+ exports.PRO3D_RENDER_CREDIT_ID = PRO3D_RENDER_CREDIT_ID;
17040
+ exports.PRO3D_RENDER_DEFAULT_ENGINE = PRO3D_RENDER_DEFAULT_ENGINE;
17041
+ exports.PRO3D_RENDER_DEFAULT_QUALITY = PRO3D_RENDER_DEFAULT_QUALITY;
17042
+ exports.PRO3D_RENDER_DEFAULT_REPAIR_PASSES = PRO3D_RENDER_DEFAULT_REPAIR_PASSES;
17043
+ exports.PRO3D_RENDER_DEFAULT_STYLE = PRO3D_RENDER_DEFAULT_STYLE;
17044
+ exports.PRO3D_RENDER_ENGINES = PRO3D_RENDER_ENGINES;
17045
+ exports.PRO3D_RENDER_LABEL = PRO3D_RENDER_LABEL;
17046
+ exports.PRO3D_RENDER_LIMITS = PRO3D_RENDER_LIMITS;
17047
+ exports.PRO3D_RENDER_MAX_REPAIR_PASSES = PRO3D_RENDER_MAX_REPAIR_PASSES;
17048
+ exports.PRO3D_RENDER_MIN_REPAIR_PASSES = PRO3D_RENDER_MIN_REPAIR_PASSES;
17049
+ exports.PRO3D_RENDER_NODE_TYPE = PRO3D_RENDER_NODE_TYPE;
17050
+ exports.PRO3D_RENDER_PROMPT_MAX = PRO3D_RENDER_PROMPT_MAX;
17051
+ exports.PRO3D_RENDER_QUALITY_PROFILES = PRO3D_RENDER_QUALITY_PROFILES;
17052
+ exports.PRO3D_RENDER_SOURCE_KINDS = PRO3D_RENDER_SOURCE_KINDS;
17053
+ exports.PRO3D_RENDER_STYLES = PRO3D_RENDER_STYLES;
16822
17054
  exports.PROMPT_HARD_CEILING = PROMPT_HARD_CEILING;
16823
17055
  exports.PROMPT_PREFIX_KEY = PROMPT_PREFIX_KEY;
16824
17056
  exports.PROMPT_SUFFIX_KEY = PROMPT_SUFFIX_KEY;
@@ -16854,10 +17086,14 @@ exports.RESERVED_TEMPLATE_VARS = RESERVED_TEMPLATE_VARS;
16854
17086
  exports.SCENE3D_ASSET_KINDS = SCENE3D_ASSET_KINDS;
16855
17087
  exports.SCENE3D_ASSET_ROLES = SCENE3D_ASSET_ROLES;
16856
17088
  exports.SCENE3D_ASSET_ROLE_KINDS = SCENE3D_ASSET_ROLE_KINDS;
17089
+ exports.SCENE3D_AUTHORING_ENGINES = SCENE3D_AUTHORING_ENGINES;
17090
+ exports.SCENE3D_BASIC_ENGINE = SCENE3D_BASIC_ENGINE;
17091
+ exports.SCENE3D_BASIC_SCHEMA_VERSION = SCENE3D_BASIC_SCHEMA_VERSION;
16857
17092
  exports.SCENE3D_CAMERA_TRACK_FORMAT = SCENE3D_CAMERA_TRACK_FORMAT;
16858
17093
  exports.SCENE3D_CAMERA_TRACK_LIMITS = SCENE3D_CAMERA_TRACK_LIMITS;
16859
17094
  exports.SCENE3D_CAMERA_TRACK_VERSION = SCENE3D_CAMERA_TRACK_VERSION;
16860
17095
  exports.SCENE3D_CLAY_LIGHTING_PRESETS = SCENE3D_CLAY_LIGHTING_PRESETS;
17096
+ exports.SCENE3D_DEFAULT_ADVANCED_ENGINE = SCENE3D_DEFAULT_ADVANCED_ENGINE;
16861
17097
  exports.SCENE3D_DEFAULT_DURATION_SECONDS = SCENE3D_DEFAULT_DURATION_SECONDS;
16862
17098
  exports.SCENE3D_DEFAULT_ENTITY_CAPABILITIES = SCENE3D_DEFAULT_ENTITY_CAPABILITIES;
16863
17099
  exports.SCENE3D_DEFAULT_FPS = SCENE3D_DEFAULT_FPS;
@@ -17070,6 +17306,7 @@ exports.buildModelTree = buildModelTree;
17070
17306
  exports.buildMotionCreditModelIdentifier = buildMotionCreditModelIdentifier;
17071
17307
  exports.buildNodePresetExport = buildNodePresetExport;
17072
17308
  exports.buildPanelPrompt = buildPanelPrompt;
17309
+ exports.buildPro3DRenderSource = buildPro3DRenderSource;
17073
17310
  exports.buildProgressSegments = buildProgressSegments;
17074
17311
  exports.buildRangeLabel = buildRangeLabel;
17075
17312
  exports.buildScraperCreditId = buildScraperCreditId;
@@ -17229,6 +17466,10 @@ exports.isObjectAspectRatio = isObjectAspectRatio;
17229
17466
  exports.isOversizedScene = isOversizedScene;
17230
17467
  exports.isPaygRetentionActive = isPaygRetentionActive;
17231
17468
  exports.isPerSecondLipSyncProvider = isPerSecondLipSyncProvider;
17469
+ exports.isPro3DRenderJobOutput = isPro3DRenderJobOutput;
17470
+ exports.isPro3DRenderQuote = isPro3DRenderQuote;
17471
+ exports.isPro3DRenderRenderOnly = isPro3DRenderRenderOnly;
17472
+ exports.isScene3DAuthoringEngine = isScene3DAuthoringEngine;
17232
17473
  exports.isScene3DCameraTrack = isScene3DCameraTrack;
17233
17474
  exports.isScene3DHttpUrl = isScene3DHttpUrl;
17234
17475
  exports.isScene3DPlan = isScene3DPlan;
@@ -17304,6 +17545,11 @@ exports.presetApplyClearKeys = presetApplyClearKeys;
17304
17545
  exports.presetDataMatches = presetDataMatches;
17305
17546
  exports.presetEntries = presetEntries;
17306
17547
  exports.pricedVideoSelection = pricedVideoSelection;
17548
+ exports.pro3DRenderCoreOutputSchema = pro3DRenderCoreOutputSchema;
17549
+ exports.pro3DRenderJobOutputSchema = pro3DRenderJobOutputSchema;
17550
+ exports.pro3DRenderProducedSchemaVersion = pro3DRenderProducedSchemaVersion;
17551
+ exports.pro3DRenderQuoteSchema = pro3DRenderQuoteSchema;
17552
+ exports.pro3DRenderTimingOverrides = pro3DRenderTimingOverrides;
17307
17553
  exports.qualityOptionsByKind = qualityOptionsByKind;
17308
17554
  exports.readPromptAffixes = readPromptAffixes;
17309
17555
  exports.refHandleCategory = refHandleCategory;
@@ -17340,6 +17586,7 @@ exports.resolveNormalizedImageGen = resolveNormalizedImageGen;
17340
17586
  exports.resolveObjectAspectRatio = resolveObjectAspectRatio;
17341
17587
  exports.resolvePipelineModel = resolvePipelineModel;
17342
17588
  exports.resolveRelativeWindowToken = resolveRelativeWindowToken;
17589
+ exports.resolveScene3DAuthoringEngine = resolveScene3DAuthoringEngine;
17343
17590
  exports.resolveScraperCreditId = resolveScraperCreditId;
17344
17591
  exports.resolveSelectorRefs = resolveSelectorRefs;
17345
17592
  exports.resolveSeparator = resolveSeparator;