@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,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Like Promise.allSettled but limits how many tasks run concurrently.
|
|
3
|
+
* Uses a worker-pool pattern so a new task starts as soon as a slot frees up.
|
|
4
|
+
* When `cancelledRef` is provided and becomes truthy, remaining un-started
|
|
5
|
+
* tasks are skipped (already-running tasks continue to completion/rejection).
|
|
6
|
+
*/
|
|
7
|
+
export async function settledWithLimit<T>(
|
|
8
|
+
tasks: (() => Promise<T>)[],
|
|
9
|
+
limit: number,
|
|
10
|
+
cancelledRef?: { cancelled: boolean },
|
|
11
|
+
): Promise<PromiseSettledResult<T>[]> {
|
|
12
|
+
const results: PromiseSettledResult<T>[] = new Array(tasks.length)
|
|
13
|
+
let nextIndex = 0
|
|
14
|
+
|
|
15
|
+
const cancelledError = new Error("Execution cancelled")
|
|
16
|
+
|
|
17
|
+
async function worker(): Promise<void> {
|
|
18
|
+
while (nextIndex < tasks.length) {
|
|
19
|
+
if (cancelledRef?.cancelled) break
|
|
20
|
+
const idx = nextIndex++
|
|
21
|
+
try {
|
|
22
|
+
const value = await tasks[idx]()
|
|
23
|
+
results[idx] = { status: "fulfilled", value }
|
|
24
|
+
} catch (reason) {
|
|
25
|
+
results[idx] = { status: "rejected", reason }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const workers = Array.from(
|
|
31
|
+
{ length: Math.min(limit, tasks.length) },
|
|
32
|
+
() => worker(),
|
|
33
|
+
)
|
|
34
|
+
await Promise.all(workers)
|
|
35
|
+
|
|
36
|
+
// Fill any un-started slots (from cancellation) with a shared rejection
|
|
37
|
+
for (let i = 0; i < results.length; i++) {
|
|
38
|
+
if (!results[i]) results[i] = { status: "rejected", reason: cancelledError }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return results
|
|
42
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { SupportedFontName } from "./supported-fonts.js"
|
|
2
|
+
|
|
3
|
+
export interface ShotTextElement {
|
|
4
|
+
readonly id: string
|
|
5
|
+
readonly type: "text"
|
|
6
|
+
readonly text: string
|
|
7
|
+
readonly fontFamily?: SupportedFontName
|
|
8
|
+
readonly fontSize: number
|
|
9
|
+
readonly fontWeight?: 300 | 400 | 700 | 900
|
|
10
|
+
readonly color?: string
|
|
11
|
+
readonly x: number
|
|
12
|
+
readonly y: number
|
|
13
|
+
readonly letterSpacing?: number
|
|
14
|
+
readonly opacity?: number
|
|
15
|
+
readonly dir?: "rtl" | "ltr"
|
|
16
|
+
}
|
|
17
|
+
export interface ShotShapeElement {
|
|
18
|
+
readonly id: string
|
|
19
|
+
readonly type: "shape"
|
|
20
|
+
readonly shape: "rectangle" | "circle" | "line"
|
|
21
|
+
readonly fill?: string
|
|
22
|
+
readonly stroke?: string
|
|
23
|
+
readonly strokeWidth?: number
|
|
24
|
+
readonly x: number
|
|
25
|
+
readonly y: number
|
|
26
|
+
readonly width: number
|
|
27
|
+
readonly height: number
|
|
28
|
+
readonly cornerRadius?: number
|
|
29
|
+
readonly opacity?: number
|
|
30
|
+
}
|
|
31
|
+
export interface ShotImageElement {
|
|
32
|
+
readonly id: string
|
|
33
|
+
readonly type: "image"
|
|
34
|
+
readonly src: string
|
|
35
|
+
readonly x: number
|
|
36
|
+
readonly y: number
|
|
37
|
+
readonly width: number
|
|
38
|
+
readonly height: number
|
|
39
|
+
readonly fit?: "contain" | "cover"
|
|
40
|
+
readonly radius?: number
|
|
41
|
+
readonly opacity?: number
|
|
42
|
+
}
|
|
43
|
+
export type ShotElement = ShotTextElement | ShotShapeElement | ShotImageElement
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export type SocialMediaPlatform = "instagram" | "tiktok" | "x" | "youtube" | "facebook" | "linkedin" | "telegram"
|
|
2
|
+
|
|
3
|
+
export type SocialMediaContentType =
|
|
4
|
+
| "feed-square" | "feed-portrait" | "feed-landscape" | "story-reel" // Instagram
|
|
5
|
+
| "video" // TikTok
|
|
6
|
+
| "image-landscape" | "image-square" | "x-video" // X
|
|
7
|
+
| "short" // YouTube
|
|
8
|
+
| "fb-feed-portrait" | "reel" // Facebook
|
|
9
|
+
| "li-image-landscape" | "li-image-square" | "li-video" // LinkedIn
|
|
10
|
+
|
|
11
|
+
export interface SocialMediaSpec {
|
|
12
|
+
readonly platform: SocialMediaPlatform
|
|
13
|
+
readonly contentType: SocialMediaContentType
|
|
14
|
+
readonly label: string
|
|
15
|
+
readonly width: number
|
|
16
|
+
readonly height: number
|
|
17
|
+
readonly maxDurationSeconds: number | null // null = image only (no duration limit)
|
|
18
|
+
readonly textLimit: number
|
|
19
|
+
readonly isVideo: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const PLATFORM_SPECS: Record<string, SocialMediaSpec> = {
|
|
23
|
+
"instagram:feed-square": {
|
|
24
|
+
platform: "instagram", contentType: "feed-square", label: "Feed Square",
|
|
25
|
+
width: 1080, height: 1080, maxDurationSeconds: 60, textLimit: 2200, isVideo: true,
|
|
26
|
+
},
|
|
27
|
+
"instagram:feed-portrait": {
|
|
28
|
+
platform: "instagram", contentType: "feed-portrait", label: "Feed Portrait",
|
|
29
|
+
width: 1080, height: 1350, maxDurationSeconds: 60, textLimit: 2200, isVideo: true,
|
|
30
|
+
},
|
|
31
|
+
"instagram:feed-landscape": {
|
|
32
|
+
platform: "instagram", contentType: "feed-landscape", label: "Feed Landscape",
|
|
33
|
+
width: 1080, height: 566, maxDurationSeconds: 60, textLimit: 2200, isVideo: true,
|
|
34
|
+
},
|
|
35
|
+
"instagram:story-reel": {
|
|
36
|
+
platform: "instagram", contentType: "story-reel", label: "Story / Reel",
|
|
37
|
+
width: 1080, height: 1920, maxDurationSeconds: 180, textLimit: 2200, isVideo: true,
|
|
38
|
+
},
|
|
39
|
+
"tiktok:video": {
|
|
40
|
+
platform: "tiktok", contentType: "video", label: "Video",
|
|
41
|
+
width: 1080, height: 1920, maxDurationSeconds: 600, textLimit: 4000, isVideo: true,
|
|
42
|
+
},
|
|
43
|
+
"x:image-landscape": {
|
|
44
|
+
platform: "x", contentType: "image-landscape", label: "Image Landscape",
|
|
45
|
+
width: 1200, height: 675, maxDurationSeconds: null, textLimit: 280, isVideo: false,
|
|
46
|
+
},
|
|
47
|
+
"x:image-square": {
|
|
48
|
+
platform: "x", contentType: "image-square", label: "Image Square",
|
|
49
|
+
width: 1080, height: 1080, maxDurationSeconds: null, textLimit: 280, isVideo: false,
|
|
50
|
+
},
|
|
51
|
+
"x:x-video": {
|
|
52
|
+
platform: "x", contentType: "x-video", label: "Video",
|
|
53
|
+
width: 1920, height: 1080, maxDurationSeconds: 140, textLimit: 280, isVideo: true,
|
|
54
|
+
},
|
|
55
|
+
"youtube:short": {
|
|
56
|
+
platform: "youtube", contentType: "short", label: "Short",
|
|
57
|
+
width: 1080, height: 1920, maxDurationSeconds: 180, textLimit: 5000, isVideo: true,
|
|
58
|
+
},
|
|
59
|
+
"facebook:fb-feed-portrait": {
|
|
60
|
+
platform: "facebook", contentType: "fb-feed-portrait", label: "Feed Portrait",
|
|
61
|
+
width: 1080, height: 1350, maxDurationSeconds: null, textLimit: 63206, isVideo: false,
|
|
62
|
+
},
|
|
63
|
+
"facebook:reel": {
|
|
64
|
+
platform: "facebook", contentType: "reel", label: "Reel",
|
|
65
|
+
width: 1080, height: 1920, maxDurationSeconds: 90, textLimit: 63206, isVideo: true,
|
|
66
|
+
},
|
|
67
|
+
"linkedin:li-image-landscape": {
|
|
68
|
+
platform: "linkedin", contentType: "li-image-landscape", label: "Image Landscape",
|
|
69
|
+
width: 1200, height: 627, maxDurationSeconds: null, textLimit: 3000, isVideo: false,
|
|
70
|
+
},
|
|
71
|
+
"linkedin:li-image-square": {
|
|
72
|
+
platform: "linkedin", contentType: "li-image-square", label: "Image Square",
|
|
73
|
+
width: 1080, height: 1080, maxDurationSeconds: null, textLimit: 3000, isVideo: false,
|
|
74
|
+
},
|
|
75
|
+
"linkedin:li-video": {
|
|
76
|
+
platform: "linkedin", contentType: "li-video", label: "Video",
|
|
77
|
+
width: 1920, height: 1080, maxDurationSeconds: 600, textLimit: 3000, isVideo: true,
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const CONTENT_TYPES_BY_PLATFORM: Record<SocialMediaPlatform, ReadonlyArray<{ key: string; label: string }>> = {
|
|
82
|
+
instagram: [
|
|
83
|
+
{ key: "instagram:feed-square", label: "Feed Square (1080×1080)" },
|
|
84
|
+
{ key: "instagram:feed-portrait", label: "Feed Portrait (1080×1350)" },
|
|
85
|
+
{ key: "instagram:feed-landscape", label: "Feed Landscape (1080×566)" },
|
|
86
|
+
{ key: "instagram:story-reel", label: "Story / Reel (1080×1920)" },
|
|
87
|
+
],
|
|
88
|
+
tiktok: [
|
|
89
|
+
{ key: "tiktok:video", label: "Video (1080×1920)" },
|
|
90
|
+
],
|
|
91
|
+
x: [
|
|
92
|
+
{ key: "x:image-landscape", label: "Image Landscape (1200×675)" },
|
|
93
|
+
{ key: "x:image-square", label: "Image Square (1080×1080)" },
|
|
94
|
+
{ key: "x:x-video", label: "Video (1920×1080)" },
|
|
95
|
+
],
|
|
96
|
+
youtube: [
|
|
97
|
+
{ key: "youtube:short", label: "Short (1080×1920)" },
|
|
98
|
+
],
|
|
99
|
+
facebook: [
|
|
100
|
+
{ key: "facebook:fb-feed-portrait", label: "Feed Portrait (1080×1350)" },
|
|
101
|
+
{ key: "facebook:reel", label: "Reel (1080×1920)" },
|
|
102
|
+
],
|
|
103
|
+
linkedin: [
|
|
104
|
+
{ key: "linkedin:li-image-landscape", label: "Image Landscape (1200×627)" },
|
|
105
|
+
{ key: "linkedin:li-image-square", label: "Image Square (1080×1080)" },
|
|
106
|
+
{ key: "linkedin:li-video", label: "Video (1920×1080)" },
|
|
107
|
+
],
|
|
108
|
+
telegram: [
|
|
109
|
+
{ key: "telegram:message", label: "Message (text)" },
|
|
110
|
+
],
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const PLATFORM_LABELS: Record<SocialMediaPlatform, string> = {
|
|
114
|
+
instagram: "Instagram",
|
|
115
|
+
tiktok: "TikTok",
|
|
116
|
+
x: "X (Twitter)",
|
|
117
|
+
youtube: "YouTube",
|
|
118
|
+
facebook: "Facebook",
|
|
119
|
+
linkedin: "LinkedIn",
|
|
120
|
+
telegram: "Telegram",
|
|
121
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared constants for social post nodes.
|
|
3
|
+
*
|
|
4
|
+
* Used by both the frontend DAG executor and backend orchestrator so input
|
|
5
|
+
* routing + API validation agree on which node types are social posts and
|
|
6
|
+
* on Instagram's carousel item limits.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** Node types that publish to a social platform via POST /v1/social/publish. */
|
|
10
|
+
export const SOCIAL_POST_NODE_TYPES = new Set([
|
|
11
|
+
"instagram-post",
|
|
12
|
+
"tiktok-post",
|
|
13
|
+
"youtube-upload",
|
|
14
|
+
"linkedin-post",
|
|
15
|
+
"x-post",
|
|
16
|
+
"facebook-post",
|
|
17
|
+
"telegram-post",
|
|
18
|
+
])
|
|
19
|
+
|
|
20
|
+
/** Instagram carousel limits per Meta Graph API.
|
|
21
|
+
* Meta's documented limit is 10 items; sending >10 fails at container
|
|
22
|
+
* creation with "(#100) too little or too many attachments". */
|
|
23
|
+
export const INSTAGRAM_CAROUSEL_MIN_ITEMS = 2
|
|
24
|
+
export const INSTAGRAM_CAROUSEL_MAX_ITEMS = 10
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export interface SubWorkflowPort {
|
|
2
|
+
readonly id: string
|
|
3
|
+
readonly name: string
|
|
4
|
+
readonly mediaType: "text" | "image" | "video" | "audio" | "any"
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
interface BoundaryNode {
|
|
8
|
+
readonly id: string
|
|
9
|
+
readonly type: string
|
|
10
|
+
readonly data: { readonly routeId?: string; readonly ports?: readonly SubWorkflowPort[] }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type ValidationError =
|
|
14
|
+
| { code: "missing_output_for_route"; routeId: string; inputNodeId: string }
|
|
15
|
+
| { code: "missing_input_for_route"; routeId: string; outputNodeId: string }
|
|
16
|
+
| { code: "route_has_no_output_ports"; routeId: string; outputNodeId: string }
|
|
17
|
+
| { code: "duplicate_route_id"; routeId: string; nodeIds: readonly string[] }
|
|
18
|
+
|
|
19
|
+
export type ValidationResult =
|
|
20
|
+
| { ok: true }
|
|
21
|
+
| { ok: false; errors: readonly ValidationError[] }
|
|
22
|
+
|
|
23
|
+
export function validateSubWorkflowRoutes(
|
|
24
|
+
nodes: readonly BoundaryNode[],
|
|
25
|
+
): ValidationResult {
|
|
26
|
+
const inputs = nodes.filter((n) => n.type === "sub-workflow-input")
|
|
27
|
+
const outputs = nodes.filter((n) => n.type === "sub-workflow-output")
|
|
28
|
+
|
|
29
|
+
if (inputs.length === 0 && outputs.length === 0) return { ok: true }
|
|
30
|
+
|
|
31
|
+
const errors: ValidationError[] = []
|
|
32
|
+
|
|
33
|
+
// 1. Duplicate routeIds within input or output lists
|
|
34
|
+
const groupByRoute = (list: readonly BoundaryNode[]) => {
|
|
35
|
+
const map = new Map<string, BoundaryNode[]>()
|
|
36
|
+
for (const n of list) {
|
|
37
|
+
const r = n.data.routeId
|
|
38
|
+
if (!r) continue
|
|
39
|
+
const bucket = map.get(r) ?? []
|
|
40
|
+
bucket.push(n)
|
|
41
|
+
map.set(r, bucket)
|
|
42
|
+
}
|
|
43
|
+
return map
|
|
44
|
+
}
|
|
45
|
+
for (const [routeId, group] of groupByRoute(inputs)) {
|
|
46
|
+
if (group.length > 1) errors.push({ code: "duplicate_route_id", routeId, nodeIds: group.map((g) => g.id) })
|
|
47
|
+
}
|
|
48
|
+
for (const [routeId, group] of groupByRoute(outputs)) {
|
|
49
|
+
if (group.length > 1) errors.push({ code: "duplicate_route_id", routeId, nodeIds: group.map((g) => g.id) })
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 2. Every input routeId must have a matching output
|
|
53
|
+
const outputByRoute = new Map(outputs.map((o) => [o.data.routeId, o] as const))
|
|
54
|
+
for (const inputNode of inputs) {
|
|
55
|
+
const routeId = inputNode.data.routeId
|
|
56
|
+
if (!routeId) continue
|
|
57
|
+
const matchingOutput = outputByRoute.get(routeId)
|
|
58
|
+
if (!matchingOutput) {
|
|
59
|
+
errors.push({ code: "missing_output_for_route", routeId, inputNodeId: inputNode.id })
|
|
60
|
+
continue
|
|
61
|
+
}
|
|
62
|
+
if (!matchingOutput.data.ports || matchingOutput.data.ports.length === 0) {
|
|
63
|
+
errors.push({ code: "route_has_no_output_ports", routeId, outputNodeId: matchingOutput.id })
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 3. Every output routeId must have a matching input
|
|
68
|
+
const inputByRoute = new Map(inputs.map((i) => [i.data.routeId, i] as const))
|
|
69
|
+
for (const outputNode of outputs) {
|
|
70
|
+
const routeId = outputNode.data.routeId
|
|
71
|
+
if (!routeId) continue
|
|
72
|
+
if (!inputByRoute.has(routeId)) {
|
|
73
|
+
errors.push({ code: "missing_input_for_route", routeId, outputNodeId: outputNode.id })
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return errors.length === 0 ? { ok: true } : { ok: false, errors }
|
|
78
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical list of font display names supported by the Remotion renderer.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth shared by:
|
|
5
|
+
* - the backend Zod schemas (`z.enum(SUPPORTED_FONT_NAMES)`), which CANNOT
|
|
6
|
+
* import `@nodaro/remotion` (its font-registry pulls the render runtime +
|
|
7
|
+
* `@remotion/google-fonts` side-effects into a validation path), and
|
|
8
|
+
* - `packages/remotion/src/lib/font-registry.ts`, which loads each face and
|
|
9
|
+
* is kept in lock-step with this tuple by a compile-time `satisfies` guard.
|
|
10
|
+
*
|
|
11
|
+
* Order/spelling MUST match the keys of the `fonts` object in font-registry.ts.
|
|
12
|
+
*/
|
|
13
|
+
export const SUPPORTED_FONT_NAMES = [
|
|
14
|
+
"Inter",
|
|
15
|
+
"Roboto",
|
|
16
|
+
"Open Sans",
|
|
17
|
+
"Montserrat",
|
|
18
|
+
"Poppins",
|
|
19
|
+
"Raleway",
|
|
20
|
+
"Nunito",
|
|
21
|
+
"Lato",
|
|
22
|
+
"Playfair Display",
|
|
23
|
+
"Merriweather",
|
|
24
|
+
"Lora",
|
|
25
|
+
"EB Garamond",
|
|
26
|
+
"Bebas Neue",
|
|
27
|
+
"Oswald",
|
|
28
|
+
"Anton",
|
|
29
|
+
"Dancing Script",
|
|
30
|
+
"Pacifico",
|
|
31
|
+
"Caveat",
|
|
32
|
+
"Roboto Mono",
|
|
33
|
+
"Fira Code",
|
|
34
|
+
"Rubik",
|
|
35
|
+
"Heebo",
|
|
36
|
+
"Cairo",
|
|
37
|
+
"Tajawal",
|
|
38
|
+
] as const
|
|
39
|
+
|
|
40
|
+
export type SupportedFontName = (typeof SUPPORTED_FONT_NAMES)[number]
|
package/src/surround.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surround continuation — shared single source of truth.
|
|
3
|
+
*
|
|
4
|
+
* The Location 360° "look-around" builds each ring view (45°, 90°, …) as an
|
|
5
|
+
* image-to-image continuation of the previous view. The platform forces
|
|
6
|
+
* geometric continuity by handing the model a half-done frame: one edge holds
|
|
7
|
+
* the previous view's carried pixels, the rest is flat gray, and the model is
|
|
8
|
+
* asked to paint the gray region.
|
|
9
|
+
*
|
|
10
|
+
* This module owns the bits that are pure and reused across the route Zod
|
|
11
|
+
* schema, the SDK input type, and the worker: the direction enum, the carried
|
|
12
|
+
* fraction defaults, and the fill prompt. The geometry math + sharp compositing
|
|
13
|
+
* + color harmonization live backend-side (they need `sharp`).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The carry/paint axis for a continuation.
|
|
18
|
+
*
|
|
19
|
+
* PAN (horizontal — half-carry continuation):
|
|
20
|
+
* - `right` — turning right: the new frame's LEFT edge continues the previous
|
|
21
|
+
* view's RIGHT edge, so the carried band sits on the LEFT, painted on the RIGHT.
|
|
22
|
+
* - `left` — turning left: the new frame's RIGHT edge continues the previous
|
|
23
|
+
* view's LEFT edge, so the carried band sits on the RIGHT, painted on the LEFT.
|
|
24
|
+
* (Mirror of `right`. Lets studio chain BOTH ways from a keyframe, capping
|
|
25
|
+
* chain depth so quality doesn't compound down a long one-way chain.)
|
|
26
|
+
*
|
|
27
|
+
* TILT (vertical — thin-strip, subject-driven re-render):
|
|
28
|
+
* - `up` — tilting straight up: render the open SKY overhead. A thin strip of
|
|
29
|
+
* the establishing shot's TOP edge is carried into the new frame's BOTTOM for
|
|
30
|
+
* a soft horizon transition; the rest is painted as sky (NOT a mirrored
|
|
31
|
+
* landscape).
|
|
32
|
+
* - `down` — tilting straight down: render the GROUND below. A thin strip of the
|
|
33
|
+
* BOTTOM edge is carried into the new frame's TOP.
|
|
34
|
+
*/
|
|
35
|
+
export const SURROUND_DIRECTIONS = ["right", "left", "up", "down"] as const
|
|
36
|
+
export type SurroundDirection = (typeof SURROUND_DIRECTIONS)[number]
|
|
37
|
+
|
|
38
|
+
/** Half the frame is carried for a horizontal pan (matches studio's composite). */
|
|
39
|
+
export const DEFAULT_CARRIED_FRACTION = 0.5
|
|
40
|
+
/**
|
|
41
|
+
* Tilts carry only a thin horizon strip. Carrying half of a horizontal frame is
|
|
42
|
+
* exactly what makes the model echo/mirror the landscape vertically instead of
|
|
43
|
+
* rendering what's actually overhead/underfoot — so tilts keep the carry small
|
|
44
|
+
* and let the tilt prompt drive the subject.
|
|
45
|
+
*/
|
|
46
|
+
export const TILT_CARRIED_FRACTION = 0.12
|
|
47
|
+
|
|
48
|
+
/** True for the vertical tilt directions (up/down), false for the pans. */
|
|
49
|
+
export function isTiltDirection(direction: SurroundDirection): boolean {
|
|
50
|
+
return direction === "up" || direction === "down"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The carried fraction the platform uses when the caller doesn't pin one. */
|
|
54
|
+
export function defaultCarriedFraction(direction: SurroundDirection): number {
|
|
55
|
+
return isTiltDirection(direction) ? TILT_CARRIED_FRACTION : DEFAULT_CARRIED_FRACTION
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Which edge of the NEW frame holds the carried pixels vs the painted region. */
|
|
59
|
+
const EDGE: Record<SurroundDirection, { carried: string; painted: string }> = {
|
|
60
|
+
right: { carried: "left", painted: "right" },
|
|
61
|
+
left: { carried: "right", painted: "left" },
|
|
62
|
+
up: { carried: "bottom", painted: "top" },
|
|
63
|
+
down: { carried: "top", painted: "bottom" },
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** What a tilt must actually render (NOT a continuation of the landscape). */
|
|
67
|
+
const TILT_SUBJECT: Record<"up" | "down", { word: string; subject: string; where: string }> = {
|
|
68
|
+
up: {
|
|
69
|
+
word: "up",
|
|
70
|
+
subject: "the open sky directly overhead — sky, clouds, or (for an interior) the canopy or ceiling",
|
|
71
|
+
where: "overhead",
|
|
72
|
+
},
|
|
73
|
+
down: {
|
|
74
|
+
word: "down",
|
|
75
|
+
subject: "the ground directly below — terrain, floor, or water surface",
|
|
76
|
+
where: "below",
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Build the fill prompt the model receives alongside the half-carry composite.
|
|
82
|
+
*
|
|
83
|
+
* `userPrompt` (an optional scene hint from the caller) is woven in front. PAN
|
|
84
|
+
* directions get the seamless-continuation prompt (with the anti-golden-hour
|
|
85
|
+
* negative that fights the documented warm-regrade drift). TILT directions get a
|
|
86
|
+
* subject-forcing prompt — render the sky / ground overhead / below, explicitly
|
|
87
|
+
* NOT a mirrored landscape — which is what stops the vertical echo.
|
|
88
|
+
*/
|
|
89
|
+
export function buildSurroundFillPrompt(direction: SurroundDirection, userPrompt?: string): string {
|
|
90
|
+
const scene = userPrompt && userPrompt.trim() ? `${userPrompt.trim()}. ` : ""
|
|
91
|
+
const { carried, painted } = EDGE[direction]
|
|
92
|
+
|
|
93
|
+
if (direction === "up" || direction === "down") {
|
|
94
|
+
const t = TILT_SUBJECT[direction]
|
|
95
|
+
return (
|
|
96
|
+
`${scene}` +
|
|
97
|
+
`This is a camera tilted straight ${t.word} from the same scene. The ${carried} strip holds real, finished pixels from the edge of the horizon view; the ${painted} region is flat gray and MUST be painted as ${t.subject}. ` +
|
|
98
|
+
`Render what is genuinely ${t.where} — do NOT repeat, mirror, or continue the landscape, and do NOT draw a horizon line or distant scenery in the painted region. ` +
|
|
99
|
+
`CRITICAL: keep the ${carried} strip unchanged and match the scene's EXACT lighting, time of day, white balance, and color grade — the same light as the ${carried} strip; no golden hour, no sunset, no warm relight, no cinematic regrade. ` +
|
|
100
|
+
`Blend smoothly into the ${carried} strip with no visible seam. No people, no text, no labels, no watermarks.`
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// pan (right / left)
|
|
105
|
+
return (
|
|
106
|
+
`${scene}` +
|
|
107
|
+
`This is a partial frame: the ${carried} portion contains real, finished pixels and the ${painted} portion is flat gray that MUST be painted in. ` +
|
|
108
|
+
`Paint ONLY the ${painted} gray region as a natural, seamless continuation of the ${carried} portion — same scene, same perspective, continuing the horizon, geometry, and content across the boundary with no break. ` +
|
|
109
|
+
`Keep the ${carried} portion completely unchanged. ` +
|
|
110
|
+
`CRITICAL: do NOT change the lighting, exposure, white balance, or time of day. Match the ${carried} portion's EXACT light, color temperature, and contrast across the whole frame — if it is flat overcast daylight, keep flat overcast daylight. No golden hour, no sunset, no warm relight, no cinematic regrade. ` +
|
|
111
|
+
`The seam between the ${carried} and ${painted} portions must be invisible. No people, no text, no labels, no watermarks.`
|
|
112
|
+
)
|
|
113
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Beeble SwitchX — Relight & Switch video node. Non-monetary tier bucketing
|
|
2
|
+
// and credit-identifier helpers. Beeble bills per 30-frame block with no
|
|
3
|
+
// per-job meter returned, so we reserve a block tier (the smallest tier that
|
|
4
|
+
// covers the clip's frame count) and commit it verbatim — tiers are 30-frame
|
|
5
|
+
// multiples, so a clip snaps to the exact number of blocks Beeble bills
|
|
6
|
+
// (ceil(frames/30)); there is no tier over-charge.
|
|
7
|
+
//
|
|
8
|
+
// The $-per-block provider rate and the credits-per-block formula derived
|
|
9
|
+
// from it live in `backend/src/lib/pricing/switchx-cost.ts` (core, not ee/).
|
|
10
|
+
// They were moved out of this package (published Apache-2.0 on npm — an
|
|
11
|
+
// irrevocable grant) per the 2026-07-06 public-flip IP audit, S5.
|
|
12
|
+
export const SWITCHX_FRAME_TIERS = [30, 60, 90, 120, 150, 180, 210, 240] as const
|
|
13
|
+
|
|
14
|
+
/** Beeble's metering granularity: frames per billed block. */
|
|
15
|
+
export const SWITCHX_BLOCK_FRAMES = 30
|
|
16
|
+
|
|
17
|
+
export function pickSwitchXFrameTier(frames?: number): number {
|
|
18
|
+
if (frames === undefined || !Number.isFinite(frames) || frames <= 0) return 240
|
|
19
|
+
for (const t of SWITCHX_FRAME_TIERS) if (frames <= t) return t
|
|
20
|
+
return 240
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function readMaxResolution(body: Record<string, unknown>): 720 | 1080 {
|
|
24
|
+
const r = Number(body.maxResolution ?? body.max_resolution)
|
|
25
|
+
return r === 720 ? 720 : 1080 // default 1080
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Frames are stashed on the raw body by the route's ffprobe preHandler.
|
|
29
|
+
export function resolveSwitchXCreditId(body: Record<string, unknown>): string {
|
|
30
|
+
const frames = Number(body.__probedFrameCount)
|
|
31
|
+
const tier = pickSwitchXFrameTier(Number.isFinite(frames) ? frames : undefined)
|
|
32
|
+
return `beeble-switchx:${tier}f:${readMaxResolution(body)}p`
|
|
33
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared separator presets for the Combine Text and Split Text nodes.
|
|
3
|
+
* Single source of truth for both the frontend DAG executor and backend orchestrator.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const SEPARATOR_PRESETS = [
|
|
7
|
+
"newline",
|
|
8
|
+
"double-newline",
|
|
9
|
+
"comma",
|
|
10
|
+
"space",
|
|
11
|
+
"stars",
|
|
12
|
+
"custom",
|
|
13
|
+
] as const
|
|
14
|
+
|
|
15
|
+
export type SeparatorPreset = (typeof SEPARATOR_PRESETS)[number]
|
|
16
|
+
|
|
17
|
+
const SPLIT_MAP: Record<string, string> = {
|
|
18
|
+
newline: "\n",
|
|
19
|
+
"double-newline": "\n\n",
|
|
20
|
+
comma: ",",
|
|
21
|
+
space: " ",
|
|
22
|
+
stars: "***",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const COMBINE_MAP: Record<string, string> = {
|
|
26
|
+
...SPLIT_MAP,
|
|
27
|
+
comma: ", ",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Human-readable label for the node badge. */
|
|
31
|
+
export const SEPARATOR_DISPLAY: Record<string, string> = {
|
|
32
|
+
newline: "\\n",
|
|
33
|
+
"double-newline": "\\n\\n",
|
|
34
|
+
comma: ",",
|
|
35
|
+
space: "space",
|
|
36
|
+
stars: "***",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ResolveSeparatorOptions {
|
|
40
|
+
/** Use combine-text spacing — e.g. ", " for comma instead of "," */
|
|
41
|
+
combineSpacing?: boolean
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Resolve a separator value to its actual string.
|
|
46
|
+
* - Enum preset → mapped value (e.g. "newline" → "\n")
|
|
47
|
+
* - "custom" → customSeparator field
|
|
48
|
+
* - Anything else → literal string (back-compat with legacy values like "===NEXT===")
|
|
49
|
+
*/
|
|
50
|
+
export function resolveSeparator(
|
|
51
|
+
raw: string | undefined,
|
|
52
|
+
customSeparator: string | undefined,
|
|
53
|
+
opts?: ResolveSeparatorOptions,
|
|
54
|
+
): string {
|
|
55
|
+
const r = raw || "newline"
|
|
56
|
+
if (r === "custom") return customSeparator ?? ""
|
|
57
|
+
const map = opts?.combineSpacing ? COMBINE_MAP : SPLIT_MAP
|
|
58
|
+
return map[r] ?? r
|
|
59
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { ConnectedReference } from "./types.js"
|
|
2
|
+
import { characterMentionSlug } from "./character-mention-slug.js"
|
|
3
|
+
import { locationMentionSlug } from "./location-mention-slug.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A bound entity (a wired Character or Location) ready to convert into a
|
|
7
|
+
* `ConnectedReference`. The minimal identity an app captures when a user binds
|
|
8
|
+
* an entity — the SLUG (and thus the resolver match) is DERIVED from `name`
|
|
9
|
+
* here, so callers can't drift from Nodaro's mention resolver. Apps own their
|
|
10
|
+
* own binding UX (chips, pickers); this is just the contract mapping.
|
|
11
|
+
*/
|
|
12
|
+
export interface EntityReferenceInput {
|
|
13
|
+
/** The entity row id. */
|
|
14
|
+
readonly id: string
|
|
15
|
+
readonly kind: "character" | "location" | "creature"
|
|
16
|
+
/** Display name — the slug is derived from this. */
|
|
17
|
+
readonly name: string
|
|
18
|
+
/** Resolved thumbnail/source URL; null/undefined → "" (placeholder-safe). */
|
|
19
|
+
readonly url?: string | null
|
|
20
|
+
/** Variant slug (e.g. "smile", "rain"); undefined = canonical/default. */
|
|
21
|
+
readonly variant?: string
|
|
22
|
+
/** Optional free-text descriptor (creature bindings: species/appearance) —
|
|
23
|
+
* folded into the auto-generated directive subject by the prompt builder. */
|
|
24
|
+
readonly description?: string | null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Map ONE bound entity to its `ConnectedReference`. character → `wired-character`
|
|
29
|
+
* (slug via `characterMentionSlug`), location → `wired-location` (slug via
|
|
30
|
+
* `locationMentionSlug`), creature → `wired-creature` (no mention-slug machinery
|
|
31
|
+
* — like `wired-object`, a bound creature AUTO-ATTACHES and gets a canonical-style
|
|
32
|
+
* creature/animal-subject directive with zero typing; `{image:N:creature}` tokens
|
|
33
|
+
* also resolve against it). Canonical-description fields are null here (a binding
|
|
34
|
+
* captures only name+variant; the picker/full-row path supplies descriptions).
|
|
35
|
+
*/
|
|
36
|
+
export function toConnectedReference(entity: EntityReferenceInput): ConnectedReference {
|
|
37
|
+
if (entity.kind === "character") {
|
|
38
|
+
return {
|
|
39
|
+
id: entity.id,
|
|
40
|
+
defaultName: entity.name,
|
|
41
|
+
source: "wired-character",
|
|
42
|
+
url: entity.url ?? "",
|
|
43
|
+
characterSlug: characterMentionSlug(entity.name),
|
|
44
|
+
variantSlug: entity.variant,
|
|
45
|
+
characterCanonicalDescription: null,
|
|
46
|
+
variantDescription: null,
|
|
47
|
+
variantDisplayName: entity.variant ?? "canonical",
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (entity.kind === "creature") {
|
|
51
|
+
return {
|
|
52
|
+
id: entity.id,
|
|
53
|
+
defaultName: entity.name,
|
|
54
|
+
source: "wired-creature",
|
|
55
|
+
url: entity.url ?? "",
|
|
56
|
+
...(entity.description ? { description: entity.description } : {}),
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
id: entity.id,
|
|
61
|
+
defaultName: entity.name,
|
|
62
|
+
source: "wired-location",
|
|
63
|
+
url: entity.url ?? "",
|
|
64
|
+
locationSlug: locationMentionSlug(entity.name),
|
|
65
|
+
locationCanonicalDescription: null,
|
|
66
|
+
locationVariantBucket: undefined,
|
|
67
|
+
locationVariantSlug: entity.variant,
|
|
68
|
+
locationVariantDisplayName: entity.variant ?? "canonical",
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Batch form — `entities.map(toConnectedReference)`. */
|
|
73
|
+
export function toConnectedReferences(
|
|
74
|
+
entities: readonly EntityReferenceInput[],
|
|
75
|
+
): ConnectedReference[] {
|
|
76
|
+
return entities.map(toConnectedReference)
|
|
77
|
+
}
|