@nodaro/shared 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +32 -0
- package/dist/index.cjs +12506 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +12269 -0
- package/dist/index.d.ts +12269 -0
- package/dist/index.js +11831 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
- package/src/__tests__/__snapshots__/prompt-builder-segments.test.ts.snap +65 -0
- package/src/__tests__/ai-avatar-pricing.test.ts +321 -0
- package/src/__tests__/apply-video-negative-prompt.test.ts +76 -0
- package/src/__tests__/attach-columns.test.ts +28 -0
- package/src/__tests__/audio-crossfade-curves.test.ts +33 -0
- package/src/__tests__/build-model-menu.test.ts +58 -0
- package/src/__tests__/character-aspect-defaults.test.ts +142 -0
- package/src/__tests__/character-mention-slug.test.ts +199 -0
- package/src/__tests__/character-reference-photo-kinds.test.ts +32 -0
- package/src/__tests__/character-usage-mode.test.ts +147 -0
- package/src/__tests__/character-variant-assets.test.ts +142 -0
- package/src/__tests__/character-voice.test.ts +130 -0
- package/src/__tests__/cinematic-avatar-pricing.test.ts +119 -0
- package/src/__tests__/combine-transitions.test.ts +137 -0
- package/src/__tests__/component-types.test.ts +87 -0
- package/src/__tests__/condition-variables.test.ts +98 -0
- package/src/__tests__/credit-identifiers.test.ts +811 -0
- package/src/__tests__/default-video-provider.test.ts +63 -0
- package/src/__tests__/entity-image-handle.test.ts +43 -0
- package/src/__tests__/entity-variants.test.ts +33 -0
- package/src/__tests__/fal-lip-sync-sets.test.ts +31 -0
- package/src/__tests__/featured-entities.test.ts +33 -0
- package/src/__tests__/film-pricing.test.ts +64 -0
- package/src/__tests__/filter-condition.test.ts +285 -0
- package/src/__tests__/freecut-protocol.test.ts +35 -0
- package/src/__tests__/generate-text-items.test.ts +19 -0
- package/src/__tests__/generated-results.test.ts +50 -0
- package/src/__tests__/graph-utils.test.ts +618 -0
- package/src/__tests__/group-aggregation.test.ts +83 -0
- package/src/__tests__/i18n-locale-completeness.test.ts +156 -0
- package/src/__tests__/image-critic-node.test.ts +86 -0
- package/src/__tests__/image-mask-mode.test.ts +16 -0
- package/src/__tests__/image-ref-limit.test.ts +78 -0
- package/src/__tests__/inpaint-region.test.ts +24 -0
- package/src/__tests__/input-field-map-parity.test.ts +30 -0
- package/src/__tests__/json-evaluator.test.ts +289 -0
- package/src/__tests__/json-path.test.ts +64 -0
- package/src/__tests__/lip-sync-pricing.test.ts +142 -0
- package/src/__tests__/list-merge.test.ts +96 -0
- package/src/__tests__/list-sort.test.ts +134 -0
- package/src/__tests__/llm-models.test.ts +445 -0
- package/src/__tests__/location-mention-slug.test.ts +246 -0
- package/src/__tests__/locations-coverage-critic-schema.test.ts +92 -0
- package/src/__tests__/loop-delimiter.test.ts +39 -0
- package/src/__tests__/lottie-slots.test.ts +245 -0
- package/src/__tests__/model-catalog-flux2-resolutions.test.ts +21 -0
- package/src/__tests__/model-constants-location.test.ts +20 -0
- package/src/__tests__/model-constants.test.ts +122 -0
- package/src/__tests__/model-tree.test.ts +86 -0
- package/src/__tests__/no-internal-imports.test.ts +25 -0
- package/src/__tests__/node-default-mappings.test.ts +175 -0
- package/src/__tests__/node-mappable-fields.test.ts +7 -0
- package/src/__tests__/node-preset-export.test.ts +46 -0
- package/src/__tests__/node-preset-extract.test.ts +166 -0
- package/src/__tests__/node-refs-canonical.test.ts +54 -0
- package/src/__tests__/node-refs-combine.test.ts +54 -0
- package/src/__tests__/node-refs.test.ts +187 -0
- package/src/__tests__/node-runtime-keys.test.ts +99 -0
- package/src/__tests__/object-aspect-defaults.test.ts +59 -0
- package/src/__tests__/parameter-node-value.test.ts +137 -0
- package/src/__tests__/pinterest-url.test.ts +35 -0
- package/src/__tests__/pipeline-chat.test.ts +110 -0
- package/src/__tests__/pipeline-validation.test.ts +98 -0
- package/src/__tests__/presentation-utils.test.ts +1137 -0
- package/src/__tests__/producer-types.test.ts +47 -0
- package/src/__tests__/prompt-length-limits.test.ts +156 -0
- package/src/__tests__/provider-directive-defaults.test.ts +46 -0
- package/src/__tests__/reduce-strategy-registry.test.ts +43 -0
- package/src/__tests__/reference-board-templates.test.ts +33 -0
- package/src/__tests__/reference-roles.test.ts +36 -0
- package/src/__tests__/resolve-field-mappings.test.ts +110 -0
- package/src/__tests__/resolve-pipeline-model.test.ts +76 -0
- package/src/__tests__/scene-node-types.test.ts +80 -0
- package/src/__tests__/scraper-actors.test.ts +67 -0
- package/src/__tests__/seedance-2-catalog.test.ts +18 -0
- package/src/__tests__/seedance-2-credit-id.test.ts +23 -0
- package/src/__tests__/seedance-aspects.test.ts +52 -0
- package/src/__tests__/selector.test.ts +1151 -0
- package/src/__tests__/settled-with-limit.test.ts +214 -0
- package/src/__tests__/social-media-specs.test.ts +129 -0
- package/src/__tests__/sub-workflow-validation.test.ts +88 -0
- package/src/__tests__/switchx-pricing.test.ts +28 -0
- package/src/__tests__/to-connected-references.test.ts +153 -0
- package/src/__tests__/utilities.test.ts +541 -0
- package/src/__tests__/video-analysis-pricing.test.ts +58 -0
- package/src/__tests__/video-analysis.test.ts +63 -0
- package/src/__tests__/video-audio-capability.test.ts +204 -0
- package/src/__tests__/video-gen-providers.test.ts +28 -0
- package/src/__tests__/video-mode-aliases.test.ts +150 -0
- package/src/__tests__/video-ref-limits.test.ts +72 -0
- package/src/__tests__/video-utils.test.ts +303 -0
- package/src/__tests__/voice-changer-models.test.ts +33 -0
- package/src/__tests__/workflow-export-strip.test.ts +46 -0
- package/src/ai-avatar-pricing.ts +213 -0
- package/src/ancestor-refs.ts +48 -0
- package/src/animals.ts +231 -0
- package/src/audio-crossfade-curves.ts +73 -0
- package/src/audio-fx-presets.ts +64 -0
- package/src/avatar-payload-validators.ts +214 -0
- package/src/caption-styles.ts +31 -0
- package/src/character-aspect-defaults.ts +102 -0
- package/src/character-facets.ts +37 -0
- package/src/character-mention-slug.ts +166 -0
- package/src/character-usage-mode.ts +109 -0
- package/src/character-variant-assets.ts +121 -0
- package/src/character-voice.ts +151 -0
- package/src/cinematic-avatar-pricing.ts +111 -0
- package/src/clone-utils.ts +46 -0
- package/src/combine-transitions.ts +482 -0
- package/src/community.ts +112 -0
- package/src/component-types.ts +127 -0
- package/src/condition-variables.ts +65 -0
- package/src/credit-estimators/index.ts +15 -0
- package/src/credit-estimators/video-utils.ts +165 -0
- package/src/credit-identifiers.ts +304 -0
- package/src/entity-approval-types.ts +31 -0
- package/src/entity-aspect-defaults.ts +82 -0
- package/src/entity-asset-types.ts +296 -0
- package/src/entity-image-handle.ts +36 -0
- package/src/extra-refs.ts +139 -0
- package/src/featured-entities.ts +136 -0
- package/src/film-pricing.ts +117 -0
- package/src/filter-condition.ts +250 -0
- package/src/flux2-pricing.ts +18 -0
- package/src/freecut-protocol.ts +52 -0
- package/src/furniture.ts +167 -0
- package/src/generate-text-items.ts +15 -0
- package/src/generated-results.ts +63 -0
- package/src/group-aggregation.ts +75 -0
- package/src/hint-graph-types.ts +18 -0
- package/src/i18n/action-fx.ar.ts +89 -0
- package/src/i18n/action-fx.de.ts +89 -0
- package/src/i18n/action-fx.es.ts +89 -0
- package/src/i18n/action-fx.fr.ts +89 -0
- package/src/i18n/action-fx.he.ts +89 -0
- package/src/i18n/action-fx.hi.ts +89 -0
- package/src/i18n/action-fx.ja.ts +89 -0
- package/src/i18n/action-fx.ko.ts +89 -0
- package/src/i18n/action-fx.pt-BR.ts +89 -0
- package/src/i18n/action-fx.ru.ts +89 -0
- package/src/i18n/action-fx.zh-CN.ts +89 -0
- package/src/i18n/aesthetic.ar.ts +170 -0
- package/src/i18n/aesthetic.de.ts +48 -0
- package/src/i18n/aesthetic.es.ts +169 -0
- package/src/i18n/aesthetic.fr.ts +52 -0
- package/src/i18n/aesthetic.he.ts +169 -0
- package/src/i18n/aesthetic.hi.ts +55 -0
- package/src/i18n/aesthetic.ja.ts +165 -0
- package/src/i18n/aesthetic.ko.ts +169 -0
- package/src/i18n/aesthetic.pt-BR.ts +148 -0
- package/src/i18n/aesthetic.ru.ts +155 -0
- package/src/i18n/aesthetic.zh-CN.ts +172 -0
- package/src/i18n/animals.ar.ts +145 -0
- package/src/i18n/animals.de.ts +144 -0
- package/src/i18n/animals.es.ts +158 -0
- package/src/i18n/animals.fr.ts +144 -0
- package/src/i18n/animals.he.ts +155 -0
- package/src/i18n/animals.hi.ts +157 -0
- package/src/i18n/animals.ja.ts +159 -0
- package/src/i18n/animals.ko.ts +159 -0
- package/src/i18n/animals.pt-BR.ts +157 -0
- package/src/i18n/animals.ru.ts +155 -0
- package/src/i18n/animals.zh-CN.ts +155 -0
- package/src/i18n/atmosphere.ar.ts +49 -0
- package/src/i18n/atmosphere.de.ts +47 -0
- package/src/i18n/atmosphere.es.ts +50 -0
- package/src/i18n/atmosphere.fr.ts +47 -0
- package/src/i18n/atmosphere.he.ts +47 -0
- package/src/i18n/atmosphere.hi.ts +49 -0
- package/src/i18n/atmosphere.ja.ts +49 -0
- package/src/i18n/atmosphere.ko.ts +49 -0
- package/src/i18n/atmosphere.pt-BR.ts +49 -0
- package/src/i18n/atmosphere.ru.ts +47 -0
- package/src/i18n/atmosphere.zh-CN.ts +152 -0
- package/src/i18n/backdrop.ar.ts +53 -0
- package/src/i18n/backdrop.de.ts +46 -0
- package/src/i18n/backdrop.es.ts +54 -0
- package/src/i18n/backdrop.fr.ts +52 -0
- package/src/i18n/backdrop.he.ts +51 -0
- package/src/i18n/backdrop.hi.ts +59 -0
- package/src/i18n/backdrop.ja.ts +61 -0
- package/src/i18n/backdrop.ko.ts +59 -0
- package/src/i18n/backdrop.pt-BR.ts +59 -0
- package/src/i18n/backdrop.ru.ts +57 -0
- package/src/i18n/backdrop.zh-CN.ts +57 -0
- package/src/i18n/camera-format.ar.ts +40 -0
- package/src/i18n/camera-format.de.ts +37 -0
- package/src/i18n/camera-format.es.ts +41 -0
- package/src/i18n/camera-format.fr.ts +37 -0
- package/src/i18n/camera-format.he.ts +37 -0
- package/src/i18n/camera-format.hi.ts +42 -0
- package/src/i18n/camera-format.ja.ts +37 -0
- package/src/i18n/camera-format.ko.ts +37 -0
- package/src/i18n/camera-format.pt-BR.ts +46 -0
- package/src/i18n/camera-format.ru.ts +42 -0
- package/src/i18n/camera-format.zh-CN.ts +42 -0
- package/src/i18n/camera-motions.ar.ts +86 -0
- package/src/i18n/camera-motions.de.ts +74 -0
- package/src/i18n/camera-motions.es.ts +86 -0
- package/src/i18n/camera-motions.fr.ts +86 -0
- package/src/i18n/camera-motions.he.ts +86 -0
- package/src/i18n/camera-motions.hi.ts +99 -0
- package/src/i18n/camera-motions.ja.ts +99 -0
- package/src/i18n/camera-motions.ko.ts +99 -0
- package/src/i18n/camera-motions.pt-BR.ts +99 -0
- package/src/i18n/camera-motions.ru.ts +99 -0
- package/src/i18n/camera-motions.zh-CN.ts +99 -0
- package/src/i18n/character-fx.ar.ts +72 -0
- package/src/i18n/character-fx.de.ts +72 -0
- package/src/i18n/character-fx.es.ts +72 -0
- package/src/i18n/character-fx.fr.ts +72 -0
- package/src/i18n/character-fx.he.ts +72 -0
- package/src/i18n/character-fx.hi.ts +72 -0
- package/src/i18n/character-fx.ja.ts +72 -0
- package/src/i18n/character-fx.ko.ts +72 -0
- package/src/i18n/character-fx.pt-BR.ts +72 -0
- package/src/i18n/character-fx.ru.ts +72 -0
- package/src/i18n/character-fx.zh-CN.ts +72 -0
- package/src/i18n/color-look.ar.ts +50 -0
- package/src/i18n/color-look.de.ts +47 -0
- package/src/i18n/color-look.es.ts +50 -0
- package/src/i18n/color-look.fr.ts +50 -0
- package/src/i18n/color-look.he.ts +49 -0
- package/src/i18n/color-look.hi.ts +52 -0
- package/src/i18n/color-look.ja.ts +54 -0
- package/src/i18n/color-look.ko.ts +54 -0
- package/src/i18n/color-look.pt-BR.ts +54 -0
- package/src/i18n/color-look.ru.ts +52 -0
- package/src/i18n/color-look.zh-CN.ts +53 -0
- package/src/i18n/composition-effects.ar.ts +26 -0
- package/src/i18n/composition-effects.de.ts +25 -0
- package/src/i18n/composition-effects.es.ts +27 -0
- package/src/i18n/composition-effects.fr.ts +25 -0
- package/src/i18n/composition-effects.he.ts +25 -0
- package/src/i18n/composition-effects.hi.ts +27 -0
- package/src/i18n/composition-effects.ja.ts +27 -0
- package/src/i18n/composition-effects.ko.ts +27 -0
- package/src/i18n/composition-effects.pt-BR.ts +25 -0
- package/src/i18n/composition-effects.ru.ts +82 -0
- package/src/i18n/composition-effects.zh-CN.ts +25 -0
- package/src/i18n/era.ar.ts +37 -0
- package/src/i18n/era.de.ts +34 -0
- package/src/i18n/era.es.ts +37 -0
- package/src/i18n/era.fr.ts +37 -0
- package/src/i18n/era.he.ts +36 -0
- package/src/i18n/era.hi.ts +39 -0
- package/src/i18n/era.ja.ts +41 -0
- package/src/i18n/era.ko.ts +39 -0
- package/src/i18n/era.pt-BR.ts +41 -0
- package/src/i18n/era.ru.ts +121 -0
- package/src/i18n/era.zh-CN.ts +39 -0
- package/src/i18n/exposure-settings.ar.ts +28 -0
- package/src/i18n/exposure-settings.de.ts +26 -0
- package/src/i18n/exposure-settings.es.ts +28 -0
- package/src/i18n/exposure-settings.fr.ts +29 -0
- package/src/i18n/exposure-settings.he.ts +28 -0
- package/src/i18n/exposure-settings.hi.ts +31 -0
- package/src/i18n/exposure-settings.ja.ts +31 -0
- package/src/i18n/exposure-settings.ko.ts +31 -0
- package/src/i18n/exposure-settings.pt-BR.ts +31 -0
- package/src/i18n/exposure-settings.ru.ts +31 -0
- package/src/i18n/exposure-settings.zh-CN.ts +31 -0
- package/src/i18n/framing.ar.ts +78 -0
- package/src/i18n/framing.de.ts +73 -0
- package/src/i18n/framing.es.ts +78 -0
- package/src/i18n/framing.fr.ts +78 -0
- package/src/i18n/framing.he.ts +77 -0
- package/src/i18n/framing.hi.ts +82 -0
- package/src/i18n/framing.ja.ts +84 -0
- package/src/i18n/framing.ko.ts +82 -0
- package/src/i18n/framing.pt-BR.ts +84 -0
- package/src/i18n/framing.ru.ts +82 -0
- package/src/i18n/framing.zh-CN.ts +82 -0
- package/src/i18n/furniture.ar.ts +92 -0
- package/src/i18n/furniture.de.ts +93 -0
- package/src/i18n/furniture.es.ts +101 -0
- package/src/i18n/furniture.fr.ts +93 -0
- package/src/i18n/furniture.he.ts +101 -0
- package/src/i18n/furniture.hi.ts +101 -0
- package/src/i18n/furniture.ja.ts +101 -0
- package/src/i18n/furniture.ko.ts +101 -0
- package/src/i18n/furniture.pt-BR.ts +101 -0
- package/src/i18n/furniture.ru.ts +101 -0
- package/src/i18n/furniture.zh-CN.ts +101 -0
- package/src/i18n/held-prop.ar.ts +74 -0
- package/src/i18n/held-prop.de.ts +65 -0
- package/src/i18n/held-prop.es.ts +83 -0
- package/src/i18n/held-prop.fr.ts +74 -0
- package/src/i18n/held-prop.he.ts +73 -0
- package/src/i18n/held-prop.hi.ts +82 -0
- package/src/i18n/held-prop.ja.ts +84 -0
- package/src/i18n/held-prop.ko.ts +84 -0
- package/src/i18n/held-prop.pt-BR.ts +84 -0
- package/src/i18n/held-prop.ru.ts +82 -0
- package/src/i18n/held-prop.zh-CN.ts +82 -0
- package/src/i18n/index.ts +208 -0
- package/src/i18n/instrumentation.ar.ts +195 -0
- package/src/i18n/instrumentation.de.ts +195 -0
- package/src/i18n/instrumentation.es.ts +195 -0
- package/src/i18n/instrumentation.fr.ts +195 -0
- package/src/i18n/instrumentation.he.ts +195 -0
- package/src/i18n/instrumentation.hi.ts +195 -0
- package/src/i18n/instrumentation.ja.ts +195 -0
- package/src/i18n/instrumentation.ko.ts +195 -0
- package/src/i18n/instrumentation.pt-BR.ts +195 -0
- package/src/i18n/instrumentation.ru.ts +195 -0
- package/src/i18n/instrumentation.zh-CN.ts +195 -0
- package/src/i18n/lens.ar.ts +24 -0
- package/src/i18n/lens.de.ts +24 -0
- package/src/i18n/lens.es.ts +24 -0
- package/src/i18n/lens.fr.ts +24 -0
- package/src/i18n/lens.he.ts +24 -0
- package/src/i18n/lens.hi.ts +24 -0
- package/src/i18n/lens.ja.ts +24 -0
- package/src/i18n/lens.ko.ts +24 -0
- package/src/i18n/lens.pt-BR.ts +24 -0
- package/src/i18n/lens.ru.ts +25 -0
- package/src/i18n/lens.zh-CN.ts +24 -0
- package/src/i18n/lighting.ar.ts +86 -0
- package/src/i18n/lighting.de.ts +84 -0
- package/src/i18n/lighting.es.ts +89 -0
- package/src/i18n/lighting.fr.ts +84 -0
- package/src/i18n/lighting.he.ts +88 -0
- package/src/i18n/lighting.hi.ts +90 -0
- package/src/i18n/lighting.ja.ts +90 -0
- package/src/i18n/lighting.ko.ts +90 -0
- package/src/i18n/lighting.pt-BR.ts +90 -0
- package/src/i18n/lighting.ru.ts +88 -0
- package/src/i18n/lighting.zh-CN.ts +92 -0
- package/src/i18n/loop-subject.ar.ts +39 -0
- package/src/i18n/loop-subject.de.ts +39 -0
- package/src/i18n/loop-subject.es.ts +39 -0
- package/src/i18n/loop-subject.fr.ts +39 -0
- package/src/i18n/loop-subject.he.ts +39 -0
- package/src/i18n/loop-subject.hi.ts +39 -0
- package/src/i18n/loop-subject.ja.ts +39 -0
- package/src/i18n/loop-subject.ko.ts +39 -0
- package/src/i18n/loop-subject.pt-BR.ts +39 -0
- package/src/i18n/loop-subject.ru.ts +39 -0
- package/src/i18n/loop-subject.zh-CN.ts +39 -0
- package/src/i18n/materials.ar.ts +80 -0
- package/src/i18n/materials.de.ts +80 -0
- package/src/i18n/materials.es.ts +87 -0
- package/src/i18n/materials.fr.ts +80 -0
- package/src/i18n/materials.he.ts +86 -0
- package/src/i18n/materials.hi.ts +86 -0
- package/src/i18n/materials.ja.ts +88 -0
- package/src/i18n/materials.ko.ts +88 -0
- package/src/i18n/materials.pt-BR.ts +88 -0
- package/src/i18n/materials.ru.ts +86 -0
- package/src/i18n/materials.zh-CN.ts +86 -0
- package/src/i18n/mood.ar.ts +61 -0
- package/src/i18n/mood.de.ts +61 -0
- package/src/i18n/mood.es.ts +66 -0
- package/src/i18n/mood.fr.ts +61 -0
- package/src/i18n/mood.he.ts +64 -0
- package/src/i18n/mood.hi.ts +66 -0
- package/src/i18n/mood.ja.ts +66 -0
- package/src/i18n/mood.ko.ts +66 -0
- package/src/i18n/mood.pt-BR.ts +64 -0
- package/src/i18n/mood.ru.ts +64 -0
- package/src/i18n/mood.zh-CN.ts +64 -0
- package/src/i18n/music-genre.ar.ts +302 -0
- package/src/i18n/music-genre.de.ts +302 -0
- package/src/i18n/music-genre.es.ts +302 -0
- package/src/i18n/music-genre.fr.ts +302 -0
- package/src/i18n/music-genre.he.ts +302 -0
- package/src/i18n/music-genre.hi.ts +302 -0
- package/src/i18n/music-genre.ja.ts +302 -0
- package/src/i18n/music-genre.ko.ts +302 -0
- package/src/i18n/music-genre.pt-BR.ts +302 -0
- package/src/i18n/music-genre.ru.ts +302 -0
- package/src/i18n/music-genre.zh-CN.ts +302 -0
- package/src/i18n/music-mood.ar.ts +75 -0
- package/src/i18n/music-mood.de.ts +75 -0
- package/src/i18n/music-mood.es.ts +75 -0
- package/src/i18n/music-mood.fr.ts +75 -0
- package/src/i18n/music-mood.he.ts +75 -0
- package/src/i18n/music-mood.hi.ts +75 -0
- package/src/i18n/music-mood.ja.ts +75 -0
- package/src/i18n/music-mood.ko.ts +75 -0
- package/src/i18n/music-mood.pt-BR.ts +75 -0
- package/src/i18n/music-mood.ru.ts +75 -0
- package/src/i18n/music-mood.zh-CN.ts +75 -0
- package/src/i18n/person.ar.ts +638 -0
- package/src/i18n/person.de.ts +629 -0
- package/src/i18n/person.es.ts +645 -0
- package/src/i18n/person.fr.ts +621 -0
- package/src/i18n/person.he.ts +656 -0
- package/src/i18n/person.hi.ts +654 -0
- package/src/i18n/person.ja.ts +662 -0
- package/src/i18n/person.ko.ts +662 -0
- package/src/i18n/person.pt-BR.ts +656 -0
- package/src/i18n/person.ru.ts +656 -0
- package/src/i18n/person.zh-CN.ts +656 -0
- package/src/i18n/photo-genre.ar.ts +58 -0
- package/src/i18n/photo-genre.de.ts +52 -0
- package/src/i18n/photo-genre.es.ts +64 -0
- package/src/i18n/photo-genre.fr.ts +58 -0
- package/src/i18n/photo-genre.he.ts +62 -0
- package/src/i18n/photo-genre.hi.ts +63 -0
- package/src/i18n/photo-genre.ja.ts +65 -0
- package/src/i18n/photo-genre.ko.ts +63 -0
- package/src/i18n/photo-genre.pt-BR.ts +65 -0
- package/src/i18n/photo-genre.ru.ts +63 -0
- package/src/i18n/photo-genre.zh-CN.ts +63 -0
- package/src/i18n/photographer.ar.ts +75 -0
- package/src/i18n/photographer.de.ts +74 -0
- package/src/i18n/photographer.es.ts +77 -0
- package/src/i18n/photographer.fr.ts +77 -0
- package/src/i18n/photographer.he.ts +78 -0
- package/src/i18n/photographer.hi.ts +80 -0
- package/src/i18n/photographer.ja.ts +84 -0
- package/src/i18n/photographer.ko.ts +84 -0
- package/src/i18n/photographer.pt-BR.ts +83 -0
- package/src/i18n/photographer.ru.ts +78 -0
- package/src/i18n/photographer.zh-CN.ts +78 -0
- package/src/i18n/pose.ar.ts +95 -0
- package/src/i18n/pose.de.ts +96 -0
- package/src/i18n/pose.es.ts +104 -0
- package/src/i18n/pose.fr.ts +96 -0
- package/src/i18n/pose.he.ts +104 -0
- package/src/i18n/pose.hi.ts +104 -0
- package/src/i18n/pose.ja.ts +104 -0
- package/src/i18n/pose.ko.ts +104 -0
- package/src/i18n/pose.pt-BR.ts +104 -0
- package/src/i18n/pose.ru.ts +104 -0
- package/src/i18n/pose.zh-CN.ts +104 -0
- package/src/i18n/post-process-effects.ar.ts +25 -0
- package/src/i18n/post-process-effects.de.ts +24 -0
- package/src/i18n/post-process-effects.es.ts +26 -0
- package/src/i18n/post-process-effects.fr.ts +24 -0
- package/src/i18n/post-process-effects.he.ts +24 -0
- package/src/i18n/post-process-effects.hi.ts +26 -0
- package/src/i18n/post-process-effects.ja.ts +26 -0
- package/src/i18n/post-process-effects.ko.ts +26 -0
- package/src/i18n/post-process-effects.pt-BR.ts +24 -0
- package/src/i18n/post-process-effects.ru.ts +24 -0
- package/src/i18n/post-process-effects.zh-CN.ts +24 -0
- package/src/i18n/render-quality.ar.ts +34 -0
- package/src/i18n/render-quality.de.ts +30 -0
- package/src/i18n/render-quality.es.ts +35 -0
- package/src/i18n/render-quality.fr.ts +34 -0
- package/src/i18n/render-quality.he.ts +33 -0
- package/src/i18n/render-quality.hi.ts +39 -0
- package/src/i18n/render-quality.ja.ts +39 -0
- package/src/i18n/render-quality.ko.ts +39 -0
- package/src/i18n/render-quality.pt-BR.ts +37 -0
- package/src/i18n/render-quality.ru.ts +37 -0
- package/src/i18n/render-quality.zh-CN.ts +37 -0
- package/src/i18n/seasons.ar.ts +10 -0
- package/src/i18n/seasons.de.ts +10 -0
- package/src/i18n/seasons.es.ts +10 -0
- package/src/i18n/seasons.fr.ts +10 -0
- package/src/i18n/seasons.he.ts +10 -0
- package/src/i18n/seasons.hi.ts +10 -0
- package/src/i18n/seasons.ja.ts +10 -0
- package/src/i18n/seasons.ko.ts +10 -0
- package/src/i18n/seasons.pt-BR.ts +10 -0
- package/src/i18n/seasons.ru.ts +10 -0
- package/src/i18n/seasons.zh-CN.ts +10 -0
- package/src/i18n/setting.ar.ts +73 -0
- package/src/i18n/setting.de.ts +73 -0
- package/src/i18n/setting.es.ts +77 -0
- package/src/i18n/setting.fr.ts +73 -0
- package/src/i18n/setting.he.ts +76 -0
- package/src/i18n/setting.hi.ts +76 -0
- package/src/i18n/setting.ja.ts +78 -0
- package/src/i18n/setting.ko.ts +76 -0
- package/src/i18n/setting.pt-BR.ts +78 -0
- package/src/i18n/setting.ru.ts +76 -0
- package/src/i18n/setting.zh-CN.ts +76 -0
- package/src/i18n/style.ar.ts +55 -0
- package/src/i18n/style.de.ts +54 -0
- package/src/i18n/style.es.ts +54 -0
- package/src/i18n/style.fr.ts +54 -0
- package/src/i18n/style.he.ts +54 -0
- package/src/i18n/style.hi.ts +54 -0
- package/src/i18n/style.ja.ts +54 -0
- package/src/i18n/style.ko.ts +54 -0
- package/src/i18n/style.pt-BR.ts +56 -0
- package/src/i18n/style.ru.ts +54 -0
- package/src/i18n/style.zh-CN.ts +54 -0
- package/src/i18n/styling.ar.ts +295 -0
- package/src/i18n/styling.de.ts +285 -0
- package/src/i18n/styling.es.ts +317 -0
- package/src/i18n/styling.fr.ts +285 -0
- package/src/i18n/styling.he.ts +307 -0
- package/src/i18n/styling.hi.ts +323 -0
- package/src/i18n/styling.ja.ts +317 -0
- package/src/i18n/styling.ko.ts +311 -0
- package/src/i18n/styling.pt-BR.ts +301 -0
- package/src/i18n/styling.ru.ts +301 -0
- package/src/i18n/styling.zh-CN.ts +307 -0
- package/src/i18n/temporal.ar.ts +31 -0
- package/src/i18n/temporal.de.ts +24 -0
- package/src/i18n/temporal.es.ts +27 -0
- package/src/i18n/temporal.fr.ts +28 -0
- package/src/i18n/temporal.he.ts +31 -0
- package/src/i18n/temporal.hi.ts +31 -0
- package/src/i18n/temporal.ja.ts +31 -0
- package/src/i18n/temporal.ko.ts +31 -0
- package/src/i18n/temporal.pt-BR.ts +31 -0
- package/src/i18n/temporal.ru.ts +31 -0
- package/src/i18n/temporal.zh-CN.ts +31 -0
- package/src/i18n/transitions.ar.ts +97 -0
- package/src/i18n/transitions.de.ts +97 -0
- package/src/i18n/transitions.es.ts +97 -0
- package/src/i18n/transitions.fr.ts +97 -0
- package/src/i18n/transitions.he.ts +97 -0
- package/src/i18n/transitions.hi.ts +97 -0
- package/src/i18n/transitions.ja.ts +97 -0
- package/src/i18n/transitions.ko.ts +97 -0
- package/src/i18n/transitions.pt-BR.ts +97 -0
- package/src/i18n/transitions.ru.ts +97 -0
- package/src/i18n/transitions.zh-CN.ts +97 -0
- package/src/i18n/types.ts +158 -0
- package/src/i18n/vehicles.ar.ts +137 -0
- package/src/i18n/vehicles.de.ts +125 -0
- package/src/i18n/vehicles.es.ts +138 -0
- package/src/i18n/vehicles.fr.ts +125 -0
- package/src/i18n/vehicles.he.ts +136 -0
- package/src/i18n/vehicles.hi.ts +138 -0
- package/src/i18n/vehicles.ja.ts +138 -0
- package/src/i18n/vehicles.ko.ts +138 -0
- package/src/i18n/vehicles.pt-BR.ts +136 -0
- package/src/i18n/vehicles.ru.ts +136 -0
- package/src/i18n/vehicles.zh-CN.ts +136 -0
- package/src/i18n/voice-character.ar.ts +126 -0
- package/src/i18n/voice-character.de.ts +126 -0
- package/src/i18n/voice-character.es.ts +126 -0
- package/src/i18n/voice-character.fr.ts +126 -0
- package/src/i18n/voice-character.he.ts +126 -0
- package/src/i18n/voice-character.hi.ts +126 -0
- package/src/i18n/voice-character.ja.ts +126 -0
- package/src/i18n/voice-character.ko.ts +126 -0
- package/src/i18n/voice-character.pt-BR.ts +126 -0
- package/src/i18n/voice-character.ru.ts +126 -0
- package/src/i18n/voice-character.zh-CN.ts +126 -0
- package/src/i18n/voice-delivery.ar.ts +77 -0
- package/src/i18n/voice-delivery.de.ts +77 -0
- package/src/i18n/voice-delivery.es.ts +77 -0
- package/src/i18n/voice-delivery.fr.ts +77 -0
- package/src/i18n/voice-delivery.he.ts +77 -0
- package/src/i18n/voice-delivery.hi.ts +77 -0
- package/src/i18n/voice-delivery.ja.ts +77 -0
- package/src/i18n/voice-delivery.ko.ts +77 -0
- package/src/i18n/voice-delivery.pt-BR.ts +77 -0
- package/src/i18n/voice-delivery.ru.ts +77 -0
- package/src/i18n/voice-delivery.zh-CN.ts +77 -0
- package/src/i18n/weapons.ar.ts +115 -0
- package/src/i18n/weapons.de.ts +114 -0
- package/src/i18n/weapons.es.ts +116 -0
- package/src/i18n/weapons.fr.ts +103 -0
- package/src/i18n/weapons.he.ts +114 -0
- package/src/i18n/weapons.hi.ts +116 -0
- package/src/i18n/weapons.ja.ts +116 -0
- package/src/i18n/weapons.ko.ts +116 -0
- package/src/i18n/weapons.pt-BR.ts +114 -0
- package/src/i18n/weapons.ru.ts +114 -0
- package/src/i18n/weapons.zh-CN.ts +114 -0
- package/src/image-critic-node.ts +61 -0
- package/src/image-critic-types.ts +40 -0
- package/src/index.ts +866 -0
- package/src/inject-upstream.ts +15 -0
- package/src/inpaint-region.ts +51 -0
- package/src/json-evaluator.ts +732 -0
- package/src/json-path.ts +52 -0
- package/src/lip-sync-pricing.ts +90 -0
- package/src/list-merge.ts +40 -0
- package/src/list-sort.ts +122 -0
- package/src/list-source-resolver.ts +50 -0
- package/src/llm-models.ts +245 -0
- package/src/location-mention-slug.ts +291 -0
- package/src/location-preset-catalog-map.ts +128 -0
- package/src/loop-delimiter.ts +73 -0
- package/src/lora-routing.ts +95 -0
- package/src/lottie-overlay-catalog.ts +175 -0
- package/src/lottie-slots.ts +309 -0
- package/src/model-catalog.ts +2386 -0
- package/src/model-constants.ts +1910 -0
- package/src/model-tree.ts +120 -0
- package/src/monetization.ts +15 -0
- package/src/multi-pick.ts +42 -0
- package/src/node-default-mappings.ts +262 -0
- package/src/node-mappable-fields.ts +70 -0
- package/src/node-preset-export.ts +56 -0
- package/src/node-preset-extract.ts +147 -0
- package/src/node-refs.ts +253 -0
- package/src/node-runtime-keys.ts +117 -0
- package/src/object-aspect-defaults.ts +72 -0
- package/src/object-picker-types.ts +22 -0
- package/src/parameter-node-value.ts +284 -0
- package/src/pinterest-url.ts +28 -0
- package/src/pipeline-chat.ts +72 -0
- package/src/pipeline-defaults.ts +318 -0
- package/src/pipeline-events.ts +162 -0
- package/src/pipeline-state-types.ts +196 -0
- package/src/pipeline-types.ts +647 -0
- package/src/pipeline-validation.ts +87 -0
- package/src/presentation-types.ts +23 -0
- package/src/presentation-utils.ts +397 -0
- package/src/producer-types.ts +188 -0
- package/src/progress-curve.ts +99 -0
- package/src/provider-directive-defaults.ts +69 -0
- package/src/reduce-strategy-registry.ts +121 -0
- package/src/reference-board-templates.ts +81 -0
- package/src/reference-roles.ts +153 -0
- package/src/reference-sheet/__tests__/board-to-column.test.ts +20 -0
- package/src/reference-sheet/__tests__/catalog.test.ts +50 -0
- package/src/reference-sheet/__tests__/cost.test.ts +38 -0
- package/src/reference-sheet/__tests__/no-drift.test.ts +28 -0
- package/src/reference-sheet/__tests__/panel-plan.test.ts +61 -0
- package/src/reference-sheet/__tests__/panel-prompts.test.ts +17 -0
- package/src/reference-sheet/__tests__/plan-generation.test.ts +72 -0
- package/src/reference-sheet/__tests__/presets.test.ts +54 -0
- package/src/reference-sheet/__tests__/types.test.ts +24 -0
- package/src/reference-sheet/catalog.ts +144 -0
- package/src/reference-sheet/cost.ts +37 -0
- package/src/reference-sheet/credit-id.ts +7 -0
- package/src/reference-sheet/index.ts +8 -0
- package/src/reference-sheet/panel-plan.ts +65 -0
- package/src/reference-sheet/panel-prompts.ts +14 -0
- package/src/reference-sheet/plan-generation.ts +79 -0
- package/src/reference-sheet/presets.ts +77 -0
- package/src/reference-sheet/types.ts +92 -0
- package/src/repeat-types.ts +97 -0
- package/src/resolve-field-mappings.ts +119 -0
- package/src/route-filter.ts +80 -0
- package/src/scene-helper-types.ts +249 -0
- package/src/scene-node-types.ts +281 -0
- package/src/scraper-actors.ts +57 -0
- package/src/scraper-output-schemas.ts +25 -0
- package/src/seasons.ts +45 -0
- package/src/selector.ts +864 -0
- package/src/settled-with-limit.ts +42 -0
- package/src/shot-element.ts +43 -0
- package/src/social-media-specs.ts +121 -0
- package/src/social-post.ts +24 -0
- package/src/sub-workflow-validation.ts +78 -0
- package/src/supported-fonts.ts +40 -0
- package/src/surround.ts +113 -0
- package/src/switchx-pricing.ts +33 -0
- package/src/text-separators.ts +59 -0
- package/src/to-connected-references.ts +77 -0
- package/src/types.ts +272 -0
- package/src/variant-job-id.ts +17 -0
- package/src/vehicles.ts +213 -0
- package/src/video-analysis-pricing.ts +74 -0
- package/src/video-analysis.ts +127 -0
- package/src/video-duration.ts +25 -0
- package/src/voice-changer-models.ts +36 -0
- package/src/voice-matcher-types.ts +37 -0
- package/src/voices.ts +92 -0
- package/src/weapons.ts +190 -0
- package/src/workflow-export.ts +153 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { ShowrunnerPlan } from "./pipeline-types"
|
|
2
|
+
|
|
3
|
+
export interface ObjectsValidationIssue {
|
|
4
|
+
severity: "blocking" | "warning"
|
|
5
|
+
type:
|
|
6
|
+
| "duplicate_key"
|
|
7
|
+
| "empty_significance"
|
|
8
|
+
| "orphan_object"
|
|
9
|
+
| "unresolved_scene_object_ref"
|
|
10
|
+
object_key?: string
|
|
11
|
+
scene_index?: number
|
|
12
|
+
message: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ObjectsValidationResult {
|
|
16
|
+
ok: boolean
|
|
17
|
+
verdict: "pass" | "fail"
|
|
18
|
+
issues: ObjectsValidationIssue[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function validateObjects(
|
|
22
|
+
objects: ShowrunnerPlan["objects"],
|
|
23
|
+
plan: ShowrunnerPlan,
|
|
24
|
+
): ObjectsValidationResult {
|
|
25
|
+
const issues: ObjectsValidationIssue[] = []
|
|
26
|
+
|
|
27
|
+
// 1. Duplicate keys
|
|
28
|
+
const seenKeys = new Map<string, number>()
|
|
29
|
+
for (const obj of objects) {
|
|
30
|
+
seenKeys.set(obj.key, (seenKeys.get(obj.key) ?? 0) + 1)
|
|
31
|
+
}
|
|
32
|
+
for (const [key, count] of seenKeys) {
|
|
33
|
+
if (count > 1) {
|
|
34
|
+
issues.push({
|
|
35
|
+
severity: "blocking",
|
|
36
|
+
type: "duplicate_key",
|
|
37
|
+
object_key: key,
|
|
38
|
+
message: `Object key "${key}" appears ${count} times — keys must be unique`,
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 2. Empty narrative_significance
|
|
44
|
+
for (const obj of objects) {
|
|
45
|
+
if (!obj.narrative_significance || obj.narrative_significance.trim() === "") {
|
|
46
|
+
issues.push({
|
|
47
|
+
severity: "blocking",
|
|
48
|
+
type: "empty_significance",
|
|
49
|
+
object_key: obj.key,
|
|
50
|
+
message: `Object "${obj.key}" has empty narrative_significance`,
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 3. Unresolved scene → object refs
|
|
56
|
+
const objectKeySet = new Set(objects.map((o) => o.key))
|
|
57
|
+
const referencedKeys = new Set<string>()
|
|
58
|
+
for (const sc of plan.scenes) {
|
|
59
|
+
for (const k of sc.object_keys) {
|
|
60
|
+
referencedKeys.add(k)
|
|
61
|
+
if (!objectKeySet.has(k)) {
|
|
62
|
+
issues.push({
|
|
63
|
+
severity: "blocking",
|
|
64
|
+
type: "unresolved_scene_object_ref",
|
|
65
|
+
object_key: k,
|
|
66
|
+
scene_index: sc.scene_index,
|
|
67
|
+
message: `Scene ${sc.scene_index} references unknown object_key "${k}"`,
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 4. Orphan objects (listed but never referenced) — warning only
|
|
74
|
+
for (const obj of objects) {
|
|
75
|
+
if (!referencedKeys.has(obj.key)) {
|
|
76
|
+
issues.push({
|
|
77
|
+
severity: "warning",
|
|
78
|
+
type: "orphan_object",
|
|
79
|
+
object_key: obj.key,
|
|
80
|
+
message: `Object "${obj.key}" listed but no scene references it`,
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const ok = !issues.some((i) => i.severity === "blocking")
|
|
86
|
+
return { ok, verdict: ok ? "pass" : "fail", issues }
|
|
87
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ExposableField {
|
|
2
|
+
readonly key: string
|
|
3
|
+
readonly label: string
|
|
4
|
+
readonly type: "select" | "slider" | "toggle" | "text" | "aspect-ratio" | "color"
|
|
5
|
+
readonly options?: ReadonlyArray<{ value: string; label: string }>
|
|
6
|
+
readonly min?: number
|
|
7
|
+
readonly max?: number
|
|
8
|
+
readonly step?: number
|
|
9
|
+
readonly defaultValue?: unknown
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ExposableOutput {
|
|
13
|
+
readonly key: string
|
|
14
|
+
readonly label: string
|
|
15
|
+
readonly outputType: "image" | "video" | "audio" | "text" | "data"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type PresentationItem =
|
|
19
|
+
| { type: "node"; nodeId: string }
|
|
20
|
+
| { type: "field"; id: string; nodeId: string; field: string; allowedValues?: Array<string | number | boolean> }
|
|
21
|
+
| { type: "output"; id: string; nodeId: string; outputKey: string }
|
|
22
|
+
| { type: "richtext"; id: string; content: string }
|
|
23
|
+
| { type: "group"; id: string; title: string; items: PresentationItem[]; showTitle?: boolean; showBackground?: boolean }
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presentation / API utilities — pure logic, no React deps.
|
|
3
|
+
* Shared between frontend (presentation mode) and backend (API schema generation).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { GenericNode, GenericEdge } from "./types.js"
|
|
7
|
+
import type { PresentationItem } from "./presentation-types.js"
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Node type sets
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
export const INPUT_NODE_TYPES = new Set([
|
|
14
|
+
"text-prompt",
|
|
15
|
+
"upload-image",
|
|
16
|
+
"upload-video",
|
|
17
|
+
"upload-audio",
|
|
18
|
+
"tone",
|
|
19
|
+
"style-guide",
|
|
20
|
+
"provider",
|
|
21
|
+
"scene-count",
|
|
22
|
+
"duration",
|
|
23
|
+
"aspect-ratio",
|
|
24
|
+
"motion",
|
|
25
|
+
"camera-motion",
|
|
26
|
+
"framing",
|
|
27
|
+
"lens",
|
|
28
|
+
"camera-format",
|
|
29
|
+
"lighting",
|
|
30
|
+
"color-look",
|
|
31
|
+
"atmosphere",
|
|
32
|
+
"action-fx",
|
|
33
|
+
"temporal",
|
|
34
|
+
"reference-audio",
|
|
35
|
+
])
|
|
36
|
+
|
|
37
|
+
const TRIGGER_NODE_TYPES = new Set([
|
|
38
|
+
"webhook-trigger",
|
|
39
|
+
"schedule-trigger",
|
|
40
|
+
])
|
|
41
|
+
|
|
42
|
+
const ALWAYS_EXCLUDED_TYPES = new Set([
|
|
43
|
+
"sticky-note",
|
|
44
|
+
"webhook-trigger",
|
|
45
|
+
"schedule-trigger",
|
|
46
|
+
"sub-workflow-input",
|
|
47
|
+
"sub-workflow-output",
|
|
48
|
+
])
|
|
49
|
+
|
|
50
|
+
const NON_OUTPUT_TYPES = new Set([
|
|
51
|
+
"text-prompt",
|
|
52
|
+
"list",
|
|
53
|
+
"upload-image",
|
|
54
|
+
"upload-video",
|
|
55
|
+
"upload-audio",
|
|
56
|
+
"reference-audio",
|
|
57
|
+
"rss-feed",
|
|
58
|
+
"youtube-video",
|
|
59
|
+
"tone",
|
|
60
|
+
"style-guide",
|
|
61
|
+
"provider",
|
|
62
|
+
"scene-count",
|
|
63
|
+
"duration",
|
|
64
|
+
"aspect-ratio",
|
|
65
|
+
"motion",
|
|
66
|
+
"camera-motion",
|
|
67
|
+
"framing",
|
|
68
|
+
"lens",
|
|
69
|
+
"camera-format",
|
|
70
|
+
"lighting",
|
|
71
|
+
"color-look",
|
|
72
|
+
"atmosphere",
|
|
73
|
+
"action-fx",
|
|
74
|
+
"temporal",
|
|
75
|
+
"sticky-note",
|
|
76
|
+
"sub-workflow-input",
|
|
77
|
+
"sub-workflow-output",
|
|
78
|
+
"webhook-trigger",
|
|
79
|
+
"schedule-trigger",
|
|
80
|
+
"combine-text",
|
|
81
|
+
"split-text",
|
|
82
|
+
"save-to-storage",
|
|
83
|
+
"webhook-output",
|
|
84
|
+
"component",
|
|
85
|
+
])
|
|
86
|
+
|
|
87
|
+
const MEDIA_PRODUCING_TYPES = new Set([
|
|
88
|
+
"generate-image",
|
|
89
|
+
"edit-image",
|
|
90
|
+
"image-to-image",
|
|
91
|
+
"image-to-video",
|
|
92
|
+
"text-to-video",
|
|
93
|
+
"video-to-video",
|
|
94
|
+
"text-to-speech",
|
|
95
|
+
"generate-music",
|
|
96
|
+
"text-to-audio",
|
|
97
|
+
"generate-script",
|
|
98
|
+
"ai-writer",
|
|
99
|
+
"llm-chat",
|
|
100
|
+
"render-video",
|
|
101
|
+
"video-composer",
|
|
102
|
+
"after-effects",
|
|
103
|
+
"lottie-overlay",
|
|
104
|
+
"3d-title",
|
|
105
|
+
"motion-graphics",
|
|
106
|
+
"composite",
|
|
107
|
+
"text-to-dialogue",
|
|
108
|
+
"voice-changer",
|
|
109
|
+
"dubbing",
|
|
110
|
+
"voice-remix",
|
|
111
|
+
"voice-design",
|
|
112
|
+
"extend-video",
|
|
113
|
+
"lip-sync",
|
|
114
|
+
"motion-transfer",
|
|
115
|
+
"video-upscale",
|
|
116
|
+
])
|
|
117
|
+
|
|
118
|
+
// Output type categorizations
|
|
119
|
+
const IMAGE_OUTPUT_TYPES = new Set([
|
|
120
|
+
"generate-image", "edit-image", "image-to-image",
|
|
121
|
+
"upload-image",
|
|
122
|
+
])
|
|
123
|
+
|
|
124
|
+
const VIDEO_OUTPUT_TYPES = new Set([
|
|
125
|
+
"image-to-video", "text-to-video", "video-to-video", "extend-video",
|
|
126
|
+
"render-video", "video-composer", "after-effects", "lottie-overlay",
|
|
127
|
+
"3d-title", "motion-graphics", "composite",
|
|
128
|
+
"combine-videos", "merge-video-audio", "resize-video", "trim-video",
|
|
129
|
+
"speed-ramp", "loop-video", "fade-video", "transcode-video",
|
|
130
|
+
"upload-video",
|
|
131
|
+
"lip-sync", "motion-transfer", "video-upscale", "add-captions",
|
|
132
|
+
"social-media-format",
|
|
133
|
+
])
|
|
134
|
+
|
|
135
|
+
const AUDIO_OUTPUT_TYPES = new Set([
|
|
136
|
+
"text-to-speech", "generate-music", "text-to-audio",
|
|
137
|
+
"text-to-dialogue", "voice-changer", "dubbing", "voice-remix",
|
|
138
|
+
"voice-design", "mix-audio", "adjust-volume", "audio-fx", "trim-audio",
|
|
139
|
+
"audio-isolation",
|
|
140
|
+
"audio-separation",
|
|
141
|
+
"upload-audio",
|
|
142
|
+
])
|
|
143
|
+
|
|
144
|
+
const TEXT_OUTPUT_TYPES = new Set([
|
|
145
|
+
"generate-script", "ai-writer", "llm-chat", "transcribe", "image-to-text", "qa-check",
|
|
146
|
+
"text-prompt",
|
|
147
|
+
])
|
|
148
|
+
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// Output type enum
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
export type OutputType = "image" | "video" | "audio" | "text" | "data"
|
|
154
|
+
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Core functions
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
/** Get nodes that act as user inputs (text prompts, uploads, parameters). */
|
|
160
|
+
export function getInputNodes<T extends GenericNode>(nodes: T[], curatedOnly = true): T[] {
|
|
161
|
+
return nodes.filter((n) => {
|
|
162
|
+
if (!n.type || ALWAYS_EXCLUDED_TYPES.has(n.type)) return false
|
|
163
|
+
if (n.hidden) return false
|
|
164
|
+
if (curatedOnly) {
|
|
165
|
+
// New explicit flag
|
|
166
|
+
if (n.data.presentationInput === true) return true
|
|
167
|
+
// Backwards compat: old flag on input-type nodes
|
|
168
|
+
if (n.data.presentationVisible === true && INPUT_NODE_TYPES.has(n.type)) return true
|
|
169
|
+
return false
|
|
170
|
+
}
|
|
171
|
+
return true
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Get leaf/media-producing nodes that represent workflow outputs. */
|
|
176
|
+
export function getOutputNodes<T extends GenericNode>(
|
|
177
|
+
nodes: T[],
|
|
178
|
+
edges: GenericEdge[],
|
|
179
|
+
curatedOnly = true,
|
|
180
|
+
): T[] {
|
|
181
|
+
const nodesWithOutgoing = new Set(edges.map((e) => e.source))
|
|
182
|
+
|
|
183
|
+
return nodes.filter((n) => {
|
|
184
|
+
if (!n.type || ALWAYS_EXCLUDED_TYPES.has(n.type)) return false
|
|
185
|
+
if (n.hidden) return false
|
|
186
|
+
if (curatedOnly) {
|
|
187
|
+
// New explicit flag
|
|
188
|
+
if (n.data.presentationOutput === true) return true
|
|
189
|
+
// Backwards compat: old flag on output-eligible nodes
|
|
190
|
+
if (n.data.presentationVisible === true) {
|
|
191
|
+
if (NON_OUTPUT_TYPES.has(n.type)) return false
|
|
192
|
+
return !nodesWithOutgoing.has(n.id) || MEDIA_PRODUCING_TYPES.has(n.type)
|
|
193
|
+
}
|
|
194
|
+
return false
|
|
195
|
+
}
|
|
196
|
+
return true
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Map node type to its output media type. */
|
|
201
|
+
export function getOutputType(nodeType: string | undefined): OutputType {
|
|
202
|
+
if (!nodeType) return "data"
|
|
203
|
+
if (IMAGE_OUTPUT_TYPES.has(nodeType)) return "image"
|
|
204
|
+
if (VIDEO_OUTPUT_TYPES.has(nodeType)) return "video"
|
|
205
|
+
if (AUDIO_OUTPUT_TYPES.has(nodeType)) return "audio"
|
|
206
|
+
if (TEXT_OUTPUT_TYPES.has(nodeType)) return "text"
|
|
207
|
+
return "data"
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Extract the result URL or text from a node's data. */
|
|
211
|
+
export function getNodeResult(
|
|
212
|
+
nodeData: Record<string, unknown>,
|
|
213
|
+
): { url?: string; text?: string } {
|
|
214
|
+
// Preview node: extract first visible item from previewItems
|
|
215
|
+
const previewItems = nodeData.previewItems as
|
|
216
|
+
| Array<{ type: string; value: string; visible?: boolean }>
|
|
217
|
+
| undefined
|
|
218
|
+
if (previewItems && previewItems.length > 0) {
|
|
219
|
+
const first = previewItems.find((item) => item.visible !== false) ?? previewItems[0]
|
|
220
|
+
if (first) {
|
|
221
|
+
if (first.type === "image" || first.type === "video" || first.type === "audio") {
|
|
222
|
+
return { url: first.value }
|
|
223
|
+
}
|
|
224
|
+
return { text: first.value }
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const results = nodeData.generatedResults as
|
|
229
|
+
| Array<Record<string, unknown>>
|
|
230
|
+
| undefined
|
|
231
|
+
|
|
232
|
+
if (results && results.length > 0) {
|
|
233
|
+
const idx = (nodeData.activeResultIndex as number) ?? 0
|
|
234
|
+
const active = results[idx] ?? results[0]
|
|
235
|
+
const url = (active?.url ?? active?.imageUrl ?? active?.videoUrl ?? active?.audioUrl) as
|
|
236
|
+
| string
|
|
237
|
+
| undefined
|
|
238
|
+
const text = (active?.text ?? active?.script) as string | undefined
|
|
239
|
+
return { url, text }
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Fallback to individual generated fields
|
|
243
|
+
const url = (nodeData.generatedImageUrl ??
|
|
244
|
+
nodeData.generatedVideoUrl ??
|
|
245
|
+
nodeData.generatedAudioUrl) as string | undefined
|
|
246
|
+
const text = (nodeData.generatedScript ?? nodeData.generatedText) as
|
|
247
|
+
| string
|
|
248
|
+
| undefined
|
|
249
|
+
|
|
250
|
+
return { url, text }
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** Human-readable label for a node. */
|
|
254
|
+
export function getNodeLabel(node: GenericNode): string {
|
|
255
|
+
return (
|
|
256
|
+
(node.data.label as string) ||
|
|
257
|
+
node.type?.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) ||
|
|
258
|
+
"Node"
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// ---------------------------------------------------------------------------
|
|
263
|
+
// Input field schema (for API schema generation)
|
|
264
|
+
// ---------------------------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
export interface InputFieldSchema {
|
|
267
|
+
key: string
|
|
268
|
+
type: "text" | "image-url" | "video-url" | "audio-url" | "select" | "number"
|
|
269
|
+
options?: string[]
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Override field per input-node type. The `key` for a parameter-picker MUST be
|
|
273
|
+
// the field that `getParameterValue()` (parameter-node-value.ts) actually reads
|
|
274
|
+
// — for multi-dimension pickers, its FIRST per-dimension field (the
|
|
275
|
+
// "representative key"). A mismatch silently drops the curated app/MCP/SDK input
|
|
276
|
+
// (the override lands on a field nothing reads). This map is the single source
|
|
277
|
+
// of truth for app-input override fields (consumed by extract-app-inputs.ts,
|
|
278
|
+
// api-tokens.ts, and the app-runner). Its parity with getParameterValue is
|
|
279
|
+
// guarded by input-field-map-parity.test.ts so the two can't drift.
|
|
280
|
+
export const INPUT_FIELD_MAP: Record<string, InputFieldSchema> = {
|
|
281
|
+
// --- Source / upload nodes (not parameter pickers) ---
|
|
282
|
+
"text-prompt": { key: "text", type: "text" },
|
|
283
|
+
"upload-image": { key: "url", type: "image-url" },
|
|
284
|
+
"upload-video": { key: "url", type: "video-url" },
|
|
285
|
+
"upload-audio": { key: "url", type: "audio-url" },
|
|
286
|
+
"reference-audio": { key: "extractedAudioUrl", type: "audio-url" },
|
|
287
|
+
// --- Classic parameters ---
|
|
288
|
+
"provider": { key: "provider", type: "select" },
|
|
289
|
+
"style-guide": { key: "text", type: "text" }, // reads data.text (was wrongly "styleGuide")
|
|
290
|
+
"scene-count": { key: "count", type: "number" },
|
|
291
|
+
"duration": { key: "seconds", type: "number" }, // reads data.seconds (was wrongly "duration")
|
|
292
|
+
"aspect-ratio": { key: "ratio", type: "select" }, // reads data.ratio (was wrongly "aspectRatio")
|
|
293
|
+
// --- Single-field parameter pickers ---
|
|
294
|
+
"tone": { key: "tone", type: "select" },
|
|
295
|
+
"motion": { key: "motion", type: "select" },
|
|
296
|
+
"camera-motion": { key: "cameraMotion", type: "select" },
|
|
297
|
+
"lens": { key: "lens", type: "select" },
|
|
298
|
+
"camera-format": { key: "cameraFormat", type: "select" },
|
|
299
|
+
"color-look": { key: "colorLook", type: "select" },
|
|
300
|
+
"atmosphere": { key: "atmosphere", type: "select" },
|
|
301
|
+
"style": { key: "style", type: "select" },
|
|
302
|
+
"setting": { key: "setting", type: "select" },
|
|
303
|
+
"mood": { key: "mood", type: "select" },
|
|
304
|
+
"photographer": { key: "photographer", type: "select" },
|
|
305
|
+
"aesthetic": { key: "aesthetic", type: "select" },
|
|
306
|
+
"era": { key: "era", type: "select" },
|
|
307
|
+
"material": { key: "material", type: "select" },
|
|
308
|
+
"animal": { key: "animal", type: "select" },
|
|
309
|
+
"vehicle": { key: "vehicle", type: "select" },
|
|
310
|
+
"weapon": { key: "weapon", type: "select" },
|
|
311
|
+
"furniture": { key: "furniture", type: "select" },
|
|
312
|
+
"photo-genre": { key: "photoGenre", type: "select" },
|
|
313
|
+
"backdrop": { key: "backdrop", type: "select" },
|
|
314
|
+
"held-prop": { key: "heldProp", type: "select" },
|
|
315
|
+
"render-quality": { key: "renderQuality", type: "select" },
|
|
316
|
+
"composition-effects": { key: "compositionEffect", type: "select" },
|
|
317
|
+
"post-process-effects": { key: "postProcess", type: "select" },
|
|
318
|
+
"action-fx": { key: "actionFx", type: "select" },
|
|
319
|
+
"character-fx": { key: "characterFx", type: "select" },
|
|
320
|
+
"transition": { key: "transition", type: "select" },
|
|
321
|
+
"loop-subject": { key: "loopSubject", type: "select" },
|
|
322
|
+
// --- Multi-dimension pickers: representative (first) field. Overriding only
|
|
323
|
+
// sets that dimension; full hint composition runs in the executors. ---
|
|
324
|
+
"framing": { key: "shotSize", type: "select" },
|
|
325
|
+
"lighting": { key: "timeOfDay", type: "select" },
|
|
326
|
+
"temporal": { key: "temporalSpeed", type: "select" },
|
|
327
|
+
"person": { key: "type", type: "select" },
|
|
328
|
+
"pose": { key: "pose", type: "select" },
|
|
329
|
+
"styling": { key: "makeup", type: "select" },
|
|
330
|
+
"exposure-settings": { key: "aperture", type: "select" },
|
|
331
|
+
"music-genre": { key: "subgenre", type: "select" },
|
|
332
|
+
"music-mood": { key: "emotion", type: "select" },
|
|
333
|
+
"instrumentation": { key: "production", type: "select" },
|
|
334
|
+
"voice-character": { key: "timbre", type: "select" },
|
|
335
|
+
"voice-delivery": { key: "archetype", type: "select" },
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Get the overridable field schema for an input node type. */
|
|
339
|
+
export function getInputFieldSchema(nodeType: string): InputFieldSchema | undefined {
|
|
340
|
+
return INPUT_FIELD_MAP[nodeType]
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ---------------------------------------------------------------------------
|
|
344
|
+
// Migration & validation helpers (PresentationItem)
|
|
345
|
+
// ---------------------------------------------------------------------------
|
|
346
|
+
|
|
347
|
+
/** Migrate a legacy string[] order to PresentationItem[]. */
|
|
348
|
+
export function migrateToItems(order: string[] | undefined): PresentationItem[] | undefined {
|
|
349
|
+
if (!order) return undefined
|
|
350
|
+
return order.map((nodeId) => ({ type: "node" as const, nodeId }))
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/** Strip nested groups — groups may only contain non-group items. */
|
|
354
|
+
export function validateNoNestedGroups(items: PresentationItem[]): PresentationItem[] {
|
|
355
|
+
return items.map((item) => {
|
|
356
|
+
if (item.type === "group") {
|
|
357
|
+
return { ...item, items: item.items.filter((child) => child.type !== "group") }
|
|
358
|
+
}
|
|
359
|
+
return item
|
|
360
|
+
})
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/** Recursively flatten all items, unwrapping groups. */
|
|
364
|
+
export function flattenItems(items: PresentationItem[]): PresentationItem[] {
|
|
365
|
+
const result: PresentationItem[] = []
|
|
366
|
+
for (const item of items) {
|
|
367
|
+
if (item.type === "group") {
|
|
368
|
+
result.push(...flattenItems(item.items))
|
|
369
|
+
} else {
|
|
370
|
+
result.push(item)
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return result
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/** Get the sortable/unique ID for a PresentationItem. */
|
|
377
|
+
export function getItemSortId(item: PresentationItem): string {
|
|
378
|
+
return item.type === "node" ? item.nodeId : item.id
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** Remove items whose nodeId no longer exists in the workflow. */
|
|
382
|
+
export function cleanOrphanedItems(
|
|
383
|
+
items: PresentationItem[],
|
|
384
|
+
nodeIds: Set<string>
|
|
385
|
+
): PresentationItem[] {
|
|
386
|
+
return items
|
|
387
|
+
.filter((item) => {
|
|
388
|
+
if (item.type === "node" || item.type === "field" || item.type === "output") return nodeIds.has(item.nodeId)
|
|
389
|
+
return true
|
|
390
|
+
})
|
|
391
|
+
.map((item) => {
|
|
392
|
+
if (item.type === "group") {
|
|
393
|
+
return { ...item, items: cleanOrphanedItems(item.items, nodeIds) }
|
|
394
|
+
}
|
|
395
|
+
return item
|
|
396
|
+
})
|
|
397
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Producer-type sets — single source of truth for the node types whose
|
|
3
|
+
* primary output is a video URL, audio URL, etc.
|
|
4
|
+
*
|
|
5
|
+
* Consumed by:
|
|
6
|
+
* - backend/src/services/workflow-engine/execution-graph.ts (orchestrator
|
|
7
|
+
* dispatch + asset-type tagging in payload-builder, output-extractor,
|
|
8
|
+
* inline-executor — re-exported there as VIDEO_SOURCE_TYPES /
|
|
9
|
+
* AUDIO_SOURCE_TYPES for backwards compatibility).
|
|
10
|
+
* - frontend/src/lib/generate-video-handles.ts (handle connection
|
|
11
|
+
* validation on the Generate Video node).
|
|
12
|
+
*
|
|
13
|
+
* Lifting these here ensures the frontend handle validator can never reject
|
|
14
|
+
* a connection from a node type that the backend would happily route at
|
|
15
|
+
* execution time (the prior drift bug, see issue 1 of the Task 4.1 review).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Source node types whose primary output is a video URL.
|
|
20
|
+
* Mirrors the backend execution-graph VIDEO_SOURCE_TYPES verbatim.
|
|
21
|
+
*/
|
|
22
|
+
export const VIDEO_PRODUCER_TYPES: ReadonlySet<string> = new Set([
|
|
23
|
+
"image-to-video",
|
|
24
|
+
"video-to-video",
|
|
25
|
+
"switchx", // Beeble SwitchX relight/composite
|
|
26
|
+
"text-to-video",
|
|
27
|
+
// Unified video node — emits videoUrl identically to i2v/t2v (its payload-builder
|
|
28
|
+
// case dispatches dynamically to "image-to-video" or "text-to-video" jobName based
|
|
29
|
+
// on whether a start frame is wired). Without this, getPrimaryOutput would fall
|
|
30
|
+
// through to the imageUrl/videoUrl/audioUrl/text default and downstream consumers
|
|
31
|
+
// could silently misroute the output.
|
|
32
|
+
"generate-video",
|
|
33
|
+
"upload-video",
|
|
34
|
+
"youtube-video",
|
|
35
|
+
"combine-videos",
|
|
36
|
+
"lip-sync",
|
|
37
|
+
"speech-to-video",
|
|
38
|
+
"motion-transfer",
|
|
39
|
+
"video-upscale",
|
|
40
|
+
"extend-video",
|
|
41
|
+
// face-swap output is video (writes generatedVideoUrl, per-result `url`).
|
|
42
|
+
// Frontend execution-graph already includes it in VIDEO_SOURCE_TYPES; this
|
|
43
|
+
// entry brings the shared set in line so canvas typed-handle validation
|
|
44
|
+
// doesn't reject face-swap → video-consumer edges that the orchestrator
|
|
45
|
+
// would happily route at runtime.
|
|
46
|
+
"face-swap",
|
|
47
|
+
"video-retake",
|
|
48
|
+
// video-sfx: adds an SFX track to a video → emits a video URL. Belongs here so
|
|
49
|
+
// canvas handle validation accepts video-sfx → video-consumer edges and the
|
|
50
|
+
// backend routes its output as video (it was previously relying on a fallback).
|
|
51
|
+
"video-sfx",
|
|
52
|
+
"suno-music-video",
|
|
53
|
+
"merge-video-audio",
|
|
54
|
+
"add-captions",
|
|
55
|
+
"resize-video",
|
|
56
|
+
"social-media-format",
|
|
57
|
+
"trim-video",
|
|
58
|
+
"render-video",
|
|
59
|
+
"speed-ramp",
|
|
60
|
+
"loop-video",
|
|
61
|
+
"fade-video",
|
|
62
|
+
"transcode-video",
|
|
63
|
+
"manual-edit",
|
|
64
|
+
// Remove Audio: strips the audio track, emits a silent video.
|
|
65
|
+
"remove-audio",
|
|
66
|
+
// AI Avatar (HeyGen): avatar + voice/audio → video.
|
|
67
|
+
"ai-avatar",
|
|
68
|
+
// Cinematic Avatar (HeyGen cinematic_avatar): prompt + 1–3 avatar looks → video.
|
|
69
|
+
"cinematic-avatar",
|
|
70
|
+
// Assemble Narrated Video: fits N (clip, voice) blocks into one MP4 → video.
|
|
71
|
+
"assemble-narrated-video",
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Source node types whose output media-type cannot be classified
|
|
76
|
+
* statically — iterators, dynamic dispatchers, sub-workflow wrappers.
|
|
77
|
+
* The orchestrator decides their actual output type at execution time
|
|
78
|
+
* based on what's wired upstream (loop iterates upstream column type;
|
|
79
|
+
* sub-workflow emits its leaf node's type; adjust-volume passes through
|
|
80
|
+
* video or audio based on its `lastInputType` runtime field;
|
|
81
|
+
* voice-changer emits audio in audio mode, video+audio in video mode).
|
|
82
|
+
*
|
|
83
|
+
* Typed-handle validators (frontend/src/lib/{generate-image,generate-
|
|
84
|
+
* video,ffmpeg}-handles.ts) must include these as acceptors on EVERY
|
|
85
|
+
* media-typed input handle — otherwise the canvas validator hard-
|
|
86
|
+
* rejects edges that the orchestrator would happily route at runtime.
|
|
87
|
+
*
|
|
88
|
+
* Lifted here from `frontend/src/lib/ffmpeg-handles.ts` (where the
|
|
89
|
+
* escape hatch was first added) so the same set drives ALL handle
|
|
90
|
+
* validators uniformly. Adding a new dynamic-output node type means
|
|
91
|
+
* one edit here instead of N across sibling validator files.
|
|
92
|
+
*
|
|
93
|
+
* Intentionally OMITTED:
|
|
94
|
+
* - `webhook-trigger` / `schedule-trigger` — their outputs are
|
|
95
|
+
* user-defined JSON shapes, not media URLs. Accepting them as
|
|
96
|
+
* media producers creates false-positive drops at the canvas
|
|
97
|
+
* that fail at execution. Users wanting trigger → media flows
|
|
98
|
+
* should wire through an upload node.
|
|
99
|
+
*/
|
|
100
|
+
export const DYNAMIC_PRODUCER_TYPES: ReadonlySet<string> = new Set([
|
|
101
|
+
"list",
|
|
102
|
+
"sub-workflow",
|
|
103
|
+
"adjust-volume",
|
|
104
|
+
// Dual-mode: audio in → audio out; video in → video out (+ revoiced audio).
|
|
105
|
+
// Listed here so canvas validators accept its output on BOTH audio and video
|
|
106
|
+
// input handles (it also stays in AUDIO_PRODUCER_TYPES as its default).
|
|
107
|
+
"voice-changer",
|
|
108
|
+
// voice-changer-pro (renamed from voice-recast in #3581) is a behavioral
|
|
109
|
+
// twin of voice-changer — identical dual-mode output. Must mirror it in
|
|
110
|
+
// EVERY producer set or its outputs can't connect (was the "cannot connect
|
|
111
|
+
// the outputs of voice-changer-pro" bug). Guarded by producer-types.test.ts.
|
|
112
|
+
"voice-changer-pro",
|
|
113
|
+
"reduce",
|
|
114
|
+
// Dual-output time chunker (UI label "Split into Chunks"; type id stays
|
|
115
|
+
// "split-media"): video in → video chunks, audio in → audio chunks — two
|
|
116
|
+
// independent lanes on two output handles. Like voice-changer, the canvas
|
|
117
|
+
// validator only sees the source NODE type, not which handle a wire leaves,
|
|
118
|
+
// so it lives here to be accepted on BOTH audio and video input handles. The
|
|
119
|
+
// backend routes the correct lane by sourceHandle in getPrimaryOutput
|
|
120
|
+
// (output-extractor.ts); the frontend does so in extractNodeOutput.
|
|
121
|
+
"split-media",
|
|
122
|
+
])
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Source node types whose primary output is an audio URL.
|
|
126
|
+
* Mirrors the backend execution-graph AUDIO_SOURCE_TYPES verbatim.
|
|
127
|
+
*/
|
|
128
|
+
export const AUDIO_PRODUCER_TYPES: ReadonlySet<string> = new Set([
|
|
129
|
+
"text-to-speech",
|
|
130
|
+
"text-to-audio",
|
|
131
|
+
"generate-music",
|
|
132
|
+
"upload-audio",
|
|
133
|
+
"suno-generate",
|
|
134
|
+
"suno-cover",
|
|
135
|
+
"suno-extend",
|
|
136
|
+
"suno-separate",
|
|
137
|
+
"audio-separation",
|
|
138
|
+
"suno-mashup",
|
|
139
|
+
"suno-replace-section",
|
|
140
|
+
"suno-add-instrumental",
|
|
141
|
+
"suno-add-vocals",
|
|
142
|
+
"suno-convert-wav",
|
|
143
|
+
"suno-upload-extend",
|
|
144
|
+
"trim-audio",
|
|
145
|
+
"mix-audio",
|
|
146
|
+
"combine-audio",
|
|
147
|
+
"adjust-volume",
|
|
148
|
+
"audio-fx",
|
|
149
|
+
"reference-audio",
|
|
150
|
+
"audio-isolation",
|
|
151
|
+
"text-to-dialogue",
|
|
152
|
+
"voice-changer",
|
|
153
|
+
// Twin of voice-changer (see DYNAMIC_PRODUCER_TYPES note). Audio is its
|
|
154
|
+
// default output mode; video mode is handled via DYNAMIC membership.
|
|
155
|
+
"voice-changer-pro",
|
|
156
|
+
"dubbing",
|
|
157
|
+
"voice-remix",
|
|
158
|
+
"voice-design",
|
|
159
|
+
// Extract Audio: demuxes a video's audio track to a standalone MP3.
|
|
160
|
+
"extract-audio",
|
|
161
|
+
])
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Source node types whose primary output is a LIST that, by default, fans out
|
|
165
|
+
* one downstream execution per element when an edge leaves them WITHOUT an
|
|
166
|
+
* explicit `outputMode` (all other edges default to "last"). `selector` is
|
|
167
|
+
* included because its picked/rest channels are lists too.
|
|
168
|
+
*
|
|
169
|
+
* Single source of truth for the fan-out "each" default, consumed by:
|
|
170
|
+
* - backend/src/services/workflow-engine/input-resolver.ts (DEFAULT_EACH_TYPES)
|
|
171
|
+
* - frontend/src/components/editor/workflow-editor/types.ts (FAN_OUT_EACH_TYPES)
|
|
172
|
+
* - frontend/src/components/editor/workflow-editor/node-input-resolver.ts
|
|
173
|
+
*
|
|
174
|
+
* These three previously kept independent copies; the backend copy drifted
|
|
175
|
+
* (missing the four list-transform types), so server-side workflow runs
|
|
176
|
+
* silently dropped all-but-the-first item for filter-list / deduplicate /
|
|
177
|
+
* merge-lists / sort-list sources while the canvas fanned out N ways. Lifting
|
|
178
|
+
* the set here makes that drift impossible.
|
|
179
|
+
*/
|
|
180
|
+
export const FAN_OUT_EACH_TYPES: ReadonlySet<string> = new Set([
|
|
181
|
+
"list",
|
|
182
|
+
"split-text",
|
|
183
|
+
"filter-list",
|
|
184
|
+
"deduplicate",
|
|
185
|
+
"merge-lists",
|
|
186
|
+
"sort-list",
|
|
187
|
+
"selector",
|
|
188
|
+
])
|