@nodaro/shared 1.4.2

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.
Files changed (665) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +32 -0
  3. package/dist/index.cjs +12506 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +12269 -0
  6. package/dist/index.d.ts +12269 -0
  7. package/dist/index.js +11831 -0
  8. package/dist/index.js.map +1 -0
  9. package/package.json +54 -0
  10. package/src/__tests__/__snapshots__/prompt-builder-segments.test.ts.snap +65 -0
  11. package/src/__tests__/ai-avatar-pricing.test.ts +321 -0
  12. package/src/__tests__/apply-video-negative-prompt.test.ts +76 -0
  13. package/src/__tests__/attach-columns.test.ts +28 -0
  14. package/src/__tests__/audio-crossfade-curves.test.ts +33 -0
  15. package/src/__tests__/build-model-menu.test.ts +58 -0
  16. package/src/__tests__/character-aspect-defaults.test.ts +142 -0
  17. package/src/__tests__/character-mention-slug.test.ts +199 -0
  18. package/src/__tests__/character-reference-photo-kinds.test.ts +32 -0
  19. package/src/__tests__/character-usage-mode.test.ts +147 -0
  20. package/src/__tests__/character-variant-assets.test.ts +142 -0
  21. package/src/__tests__/character-voice.test.ts +130 -0
  22. package/src/__tests__/cinematic-avatar-pricing.test.ts +119 -0
  23. package/src/__tests__/combine-transitions.test.ts +137 -0
  24. package/src/__tests__/component-types.test.ts +87 -0
  25. package/src/__tests__/condition-variables.test.ts +98 -0
  26. package/src/__tests__/credit-identifiers.test.ts +811 -0
  27. package/src/__tests__/default-video-provider.test.ts +63 -0
  28. package/src/__tests__/entity-image-handle.test.ts +43 -0
  29. package/src/__tests__/entity-variants.test.ts +33 -0
  30. package/src/__tests__/fal-lip-sync-sets.test.ts +31 -0
  31. package/src/__tests__/featured-entities.test.ts +33 -0
  32. package/src/__tests__/film-pricing.test.ts +64 -0
  33. package/src/__tests__/filter-condition.test.ts +285 -0
  34. package/src/__tests__/freecut-protocol.test.ts +35 -0
  35. package/src/__tests__/generate-text-items.test.ts +19 -0
  36. package/src/__tests__/generated-results.test.ts +50 -0
  37. package/src/__tests__/graph-utils.test.ts +618 -0
  38. package/src/__tests__/group-aggregation.test.ts +83 -0
  39. package/src/__tests__/i18n-locale-completeness.test.ts +156 -0
  40. package/src/__tests__/image-critic-node.test.ts +86 -0
  41. package/src/__tests__/image-mask-mode.test.ts +16 -0
  42. package/src/__tests__/image-ref-limit.test.ts +78 -0
  43. package/src/__tests__/inpaint-region.test.ts +24 -0
  44. package/src/__tests__/input-field-map-parity.test.ts +30 -0
  45. package/src/__tests__/json-evaluator.test.ts +289 -0
  46. package/src/__tests__/json-path.test.ts +64 -0
  47. package/src/__tests__/lip-sync-pricing.test.ts +142 -0
  48. package/src/__tests__/list-merge.test.ts +96 -0
  49. package/src/__tests__/list-sort.test.ts +134 -0
  50. package/src/__tests__/llm-models.test.ts +445 -0
  51. package/src/__tests__/location-mention-slug.test.ts +246 -0
  52. package/src/__tests__/locations-coverage-critic-schema.test.ts +92 -0
  53. package/src/__tests__/loop-delimiter.test.ts +39 -0
  54. package/src/__tests__/lottie-slots.test.ts +245 -0
  55. package/src/__tests__/model-catalog-flux2-resolutions.test.ts +21 -0
  56. package/src/__tests__/model-constants-location.test.ts +20 -0
  57. package/src/__tests__/model-constants.test.ts +122 -0
  58. package/src/__tests__/model-tree.test.ts +86 -0
  59. package/src/__tests__/no-internal-imports.test.ts +25 -0
  60. package/src/__tests__/node-default-mappings.test.ts +175 -0
  61. package/src/__tests__/node-mappable-fields.test.ts +7 -0
  62. package/src/__tests__/node-preset-export.test.ts +46 -0
  63. package/src/__tests__/node-preset-extract.test.ts +166 -0
  64. package/src/__tests__/node-refs-canonical.test.ts +54 -0
  65. package/src/__tests__/node-refs-combine.test.ts +54 -0
  66. package/src/__tests__/node-refs.test.ts +187 -0
  67. package/src/__tests__/node-runtime-keys.test.ts +99 -0
  68. package/src/__tests__/object-aspect-defaults.test.ts +59 -0
  69. package/src/__tests__/parameter-node-value.test.ts +137 -0
  70. package/src/__tests__/pinterest-url.test.ts +35 -0
  71. package/src/__tests__/pipeline-chat.test.ts +110 -0
  72. package/src/__tests__/pipeline-validation.test.ts +98 -0
  73. package/src/__tests__/presentation-utils.test.ts +1137 -0
  74. package/src/__tests__/producer-types.test.ts +47 -0
  75. package/src/__tests__/prompt-length-limits.test.ts +156 -0
  76. package/src/__tests__/provider-directive-defaults.test.ts +46 -0
  77. package/src/__tests__/reduce-strategy-registry.test.ts +43 -0
  78. package/src/__tests__/reference-board-templates.test.ts +33 -0
  79. package/src/__tests__/reference-roles.test.ts +36 -0
  80. package/src/__tests__/resolve-field-mappings.test.ts +110 -0
  81. package/src/__tests__/resolve-pipeline-model.test.ts +76 -0
  82. package/src/__tests__/scene-node-types.test.ts +80 -0
  83. package/src/__tests__/scraper-actors.test.ts +67 -0
  84. package/src/__tests__/seedance-2-catalog.test.ts +18 -0
  85. package/src/__tests__/seedance-2-credit-id.test.ts +23 -0
  86. package/src/__tests__/seedance-aspects.test.ts +52 -0
  87. package/src/__tests__/selector.test.ts +1151 -0
  88. package/src/__tests__/settled-with-limit.test.ts +214 -0
  89. package/src/__tests__/social-media-specs.test.ts +129 -0
  90. package/src/__tests__/sub-workflow-validation.test.ts +88 -0
  91. package/src/__tests__/switchx-pricing.test.ts +28 -0
  92. package/src/__tests__/to-connected-references.test.ts +153 -0
  93. package/src/__tests__/utilities.test.ts +541 -0
  94. package/src/__tests__/video-analysis-pricing.test.ts +58 -0
  95. package/src/__tests__/video-analysis.test.ts +63 -0
  96. package/src/__tests__/video-audio-capability.test.ts +204 -0
  97. package/src/__tests__/video-gen-providers.test.ts +28 -0
  98. package/src/__tests__/video-mode-aliases.test.ts +150 -0
  99. package/src/__tests__/video-ref-limits.test.ts +72 -0
  100. package/src/__tests__/video-utils.test.ts +303 -0
  101. package/src/__tests__/voice-changer-models.test.ts +33 -0
  102. package/src/__tests__/workflow-export-strip.test.ts +46 -0
  103. package/src/ai-avatar-pricing.ts +213 -0
  104. package/src/ancestor-refs.ts +48 -0
  105. package/src/animals.ts +231 -0
  106. package/src/audio-crossfade-curves.ts +73 -0
  107. package/src/audio-fx-presets.ts +64 -0
  108. package/src/avatar-payload-validators.ts +214 -0
  109. package/src/caption-styles.ts +31 -0
  110. package/src/character-aspect-defaults.ts +102 -0
  111. package/src/character-facets.ts +37 -0
  112. package/src/character-mention-slug.ts +166 -0
  113. package/src/character-usage-mode.ts +109 -0
  114. package/src/character-variant-assets.ts +121 -0
  115. package/src/character-voice.ts +151 -0
  116. package/src/cinematic-avatar-pricing.ts +111 -0
  117. package/src/clone-utils.ts +46 -0
  118. package/src/combine-transitions.ts +482 -0
  119. package/src/community.ts +112 -0
  120. package/src/component-types.ts +127 -0
  121. package/src/condition-variables.ts +65 -0
  122. package/src/credit-estimators/index.ts +15 -0
  123. package/src/credit-estimators/video-utils.ts +165 -0
  124. package/src/credit-identifiers.ts +304 -0
  125. package/src/entity-approval-types.ts +31 -0
  126. package/src/entity-aspect-defaults.ts +82 -0
  127. package/src/entity-asset-types.ts +296 -0
  128. package/src/entity-image-handle.ts +36 -0
  129. package/src/extra-refs.ts +139 -0
  130. package/src/featured-entities.ts +136 -0
  131. package/src/film-pricing.ts +117 -0
  132. package/src/filter-condition.ts +250 -0
  133. package/src/flux2-pricing.ts +18 -0
  134. package/src/freecut-protocol.ts +52 -0
  135. package/src/furniture.ts +167 -0
  136. package/src/generate-text-items.ts +15 -0
  137. package/src/generated-results.ts +63 -0
  138. package/src/group-aggregation.ts +75 -0
  139. package/src/hint-graph-types.ts +18 -0
  140. package/src/i18n/action-fx.ar.ts +89 -0
  141. package/src/i18n/action-fx.de.ts +89 -0
  142. package/src/i18n/action-fx.es.ts +89 -0
  143. package/src/i18n/action-fx.fr.ts +89 -0
  144. package/src/i18n/action-fx.he.ts +89 -0
  145. package/src/i18n/action-fx.hi.ts +89 -0
  146. package/src/i18n/action-fx.ja.ts +89 -0
  147. package/src/i18n/action-fx.ko.ts +89 -0
  148. package/src/i18n/action-fx.pt-BR.ts +89 -0
  149. package/src/i18n/action-fx.ru.ts +89 -0
  150. package/src/i18n/action-fx.zh-CN.ts +89 -0
  151. package/src/i18n/aesthetic.ar.ts +170 -0
  152. package/src/i18n/aesthetic.de.ts +48 -0
  153. package/src/i18n/aesthetic.es.ts +169 -0
  154. package/src/i18n/aesthetic.fr.ts +52 -0
  155. package/src/i18n/aesthetic.he.ts +169 -0
  156. package/src/i18n/aesthetic.hi.ts +55 -0
  157. package/src/i18n/aesthetic.ja.ts +165 -0
  158. package/src/i18n/aesthetic.ko.ts +169 -0
  159. package/src/i18n/aesthetic.pt-BR.ts +148 -0
  160. package/src/i18n/aesthetic.ru.ts +155 -0
  161. package/src/i18n/aesthetic.zh-CN.ts +172 -0
  162. package/src/i18n/animals.ar.ts +145 -0
  163. package/src/i18n/animals.de.ts +144 -0
  164. package/src/i18n/animals.es.ts +158 -0
  165. package/src/i18n/animals.fr.ts +144 -0
  166. package/src/i18n/animals.he.ts +155 -0
  167. package/src/i18n/animals.hi.ts +157 -0
  168. package/src/i18n/animals.ja.ts +159 -0
  169. package/src/i18n/animals.ko.ts +159 -0
  170. package/src/i18n/animals.pt-BR.ts +157 -0
  171. package/src/i18n/animals.ru.ts +155 -0
  172. package/src/i18n/animals.zh-CN.ts +155 -0
  173. package/src/i18n/atmosphere.ar.ts +49 -0
  174. package/src/i18n/atmosphere.de.ts +47 -0
  175. package/src/i18n/atmosphere.es.ts +50 -0
  176. package/src/i18n/atmosphere.fr.ts +47 -0
  177. package/src/i18n/atmosphere.he.ts +47 -0
  178. package/src/i18n/atmosphere.hi.ts +49 -0
  179. package/src/i18n/atmosphere.ja.ts +49 -0
  180. package/src/i18n/atmosphere.ko.ts +49 -0
  181. package/src/i18n/atmosphere.pt-BR.ts +49 -0
  182. package/src/i18n/atmosphere.ru.ts +47 -0
  183. package/src/i18n/atmosphere.zh-CN.ts +152 -0
  184. package/src/i18n/backdrop.ar.ts +53 -0
  185. package/src/i18n/backdrop.de.ts +46 -0
  186. package/src/i18n/backdrop.es.ts +54 -0
  187. package/src/i18n/backdrop.fr.ts +52 -0
  188. package/src/i18n/backdrop.he.ts +51 -0
  189. package/src/i18n/backdrop.hi.ts +59 -0
  190. package/src/i18n/backdrop.ja.ts +61 -0
  191. package/src/i18n/backdrop.ko.ts +59 -0
  192. package/src/i18n/backdrop.pt-BR.ts +59 -0
  193. package/src/i18n/backdrop.ru.ts +57 -0
  194. package/src/i18n/backdrop.zh-CN.ts +57 -0
  195. package/src/i18n/camera-format.ar.ts +40 -0
  196. package/src/i18n/camera-format.de.ts +37 -0
  197. package/src/i18n/camera-format.es.ts +41 -0
  198. package/src/i18n/camera-format.fr.ts +37 -0
  199. package/src/i18n/camera-format.he.ts +37 -0
  200. package/src/i18n/camera-format.hi.ts +42 -0
  201. package/src/i18n/camera-format.ja.ts +37 -0
  202. package/src/i18n/camera-format.ko.ts +37 -0
  203. package/src/i18n/camera-format.pt-BR.ts +46 -0
  204. package/src/i18n/camera-format.ru.ts +42 -0
  205. package/src/i18n/camera-format.zh-CN.ts +42 -0
  206. package/src/i18n/camera-motions.ar.ts +86 -0
  207. package/src/i18n/camera-motions.de.ts +74 -0
  208. package/src/i18n/camera-motions.es.ts +86 -0
  209. package/src/i18n/camera-motions.fr.ts +86 -0
  210. package/src/i18n/camera-motions.he.ts +86 -0
  211. package/src/i18n/camera-motions.hi.ts +99 -0
  212. package/src/i18n/camera-motions.ja.ts +99 -0
  213. package/src/i18n/camera-motions.ko.ts +99 -0
  214. package/src/i18n/camera-motions.pt-BR.ts +99 -0
  215. package/src/i18n/camera-motions.ru.ts +99 -0
  216. package/src/i18n/camera-motions.zh-CN.ts +99 -0
  217. package/src/i18n/character-fx.ar.ts +72 -0
  218. package/src/i18n/character-fx.de.ts +72 -0
  219. package/src/i18n/character-fx.es.ts +72 -0
  220. package/src/i18n/character-fx.fr.ts +72 -0
  221. package/src/i18n/character-fx.he.ts +72 -0
  222. package/src/i18n/character-fx.hi.ts +72 -0
  223. package/src/i18n/character-fx.ja.ts +72 -0
  224. package/src/i18n/character-fx.ko.ts +72 -0
  225. package/src/i18n/character-fx.pt-BR.ts +72 -0
  226. package/src/i18n/character-fx.ru.ts +72 -0
  227. package/src/i18n/character-fx.zh-CN.ts +72 -0
  228. package/src/i18n/color-look.ar.ts +50 -0
  229. package/src/i18n/color-look.de.ts +47 -0
  230. package/src/i18n/color-look.es.ts +50 -0
  231. package/src/i18n/color-look.fr.ts +50 -0
  232. package/src/i18n/color-look.he.ts +49 -0
  233. package/src/i18n/color-look.hi.ts +52 -0
  234. package/src/i18n/color-look.ja.ts +54 -0
  235. package/src/i18n/color-look.ko.ts +54 -0
  236. package/src/i18n/color-look.pt-BR.ts +54 -0
  237. package/src/i18n/color-look.ru.ts +52 -0
  238. package/src/i18n/color-look.zh-CN.ts +53 -0
  239. package/src/i18n/composition-effects.ar.ts +26 -0
  240. package/src/i18n/composition-effects.de.ts +25 -0
  241. package/src/i18n/composition-effects.es.ts +27 -0
  242. package/src/i18n/composition-effects.fr.ts +25 -0
  243. package/src/i18n/composition-effects.he.ts +25 -0
  244. package/src/i18n/composition-effects.hi.ts +27 -0
  245. package/src/i18n/composition-effects.ja.ts +27 -0
  246. package/src/i18n/composition-effects.ko.ts +27 -0
  247. package/src/i18n/composition-effects.pt-BR.ts +25 -0
  248. package/src/i18n/composition-effects.ru.ts +82 -0
  249. package/src/i18n/composition-effects.zh-CN.ts +25 -0
  250. package/src/i18n/era.ar.ts +37 -0
  251. package/src/i18n/era.de.ts +34 -0
  252. package/src/i18n/era.es.ts +37 -0
  253. package/src/i18n/era.fr.ts +37 -0
  254. package/src/i18n/era.he.ts +36 -0
  255. package/src/i18n/era.hi.ts +39 -0
  256. package/src/i18n/era.ja.ts +41 -0
  257. package/src/i18n/era.ko.ts +39 -0
  258. package/src/i18n/era.pt-BR.ts +41 -0
  259. package/src/i18n/era.ru.ts +121 -0
  260. package/src/i18n/era.zh-CN.ts +39 -0
  261. package/src/i18n/exposure-settings.ar.ts +28 -0
  262. package/src/i18n/exposure-settings.de.ts +26 -0
  263. package/src/i18n/exposure-settings.es.ts +28 -0
  264. package/src/i18n/exposure-settings.fr.ts +29 -0
  265. package/src/i18n/exposure-settings.he.ts +28 -0
  266. package/src/i18n/exposure-settings.hi.ts +31 -0
  267. package/src/i18n/exposure-settings.ja.ts +31 -0
  268. package/src/i18n/exposure-settings.ko.ts +31 -0
  269. package/src/i18n/exposure-settings.pt-BR.ts +31 -0
  270. package/src/i18n/exposure-settings.ru.ts +31 -0
  271. package/src/i18n/exposure-settings.zh-CN.ts +31 -0
  272. package/src/i18n/framing.ar.ts +78 -0
  273. package/src/i18n/framing.de.ts +73 -0
  274. package/src/i18n/framing.es.ts +78 -0
  275. package/src/i18n/framing.fr.ts +78 -0
  276. package/src/i18n/framing.he.ts +77 -0
  277. package/src/i18n/framing.hi.ts +82 -0
  278. package/src/i18n/framing.ja.ts +84 -0
  279. package/src/i18n/framing.ko.ts +82 -0
  280. package/src/i18n/framing.pt-BR.ts +84 -0
  281. package/src/i18n/framing.ru.ts +82 -0
  282. package/src/i18n/framing.zh-CN.ts +82 -0
  283. package/src/i18n/furniture.ar.ts +92 -0
  284. package/src/i18n/furniture.de.ts +93 -0
  285. package/src/i18n/furniture.es.ts +101 -0
  286. package/src/i18n/furniture.fr.ts +93 -0
  287. package/src/i18n/furniture.he.ts +101 -0
  288. package/src/i18n/furniture.hi.ts +101 -0
  289. package/src/i18n/furniture.ja.ts +101 -0
  290. package/src/i18n/furniture.ko.ts +101 -0
  291. package/src/i18n/furniture.pt-BR.ts +101 -0
  292. package/src/i18n/furniture.ru.ts +101 -0
  293. package/src/i18n/furniture.zh-CN.ts +101 -0
  294. package/src/i18n/held-prop.ar.ts +74 -0
  295. package/src/i18n/held-prop.de.ts +65 -0
  296. package/src/i18n/held-prop.es.ts +83 -0
  297. package/src/i18n/held-prop.fr.ts +74 -0
  298. package/src/i18n/held-prop.he.ts +73 -0
  299. package/src/i18n/held-prop.hi.ts +82 -0
  300. package/src/i18n/held-prop.ja.ts +84 -0
  301. package/src/i18n/held-prop.ko.ts +84 -0
  302. package/src/i18n/held-prop.pt-BR.ts +84 -0
  303. package/src/i18n/held-prop.ru.ts +82 -0
  304. package/src/i18n/held-prop.zh-CN.ts +82 -0
  305. package/src/i18n/index.ts +208 -0
  306. package/src/i18n/instrumentation.ar.ts +195 -0
  307. package/src/i18n/instrumentation.de.ts +195 -0
  308. package/src/i18n/instrumentation.es.ts +195 -0
  309. package/src/i18n/instrumentation.fr.ts +195 -0
  310. package/src/i18n/instrumentation.he.ts +195 -0
  311. package/src/i18n/instrumentation.hi.ts +195 -0
  312. package/src/i18n/instrumentation.ja.ts +195 -0
  313. package/src/i18n/instrumentation.ko.ts +195 -0
  314. package/src/i18n/instrumentation.pt-BR.ts +195 -0
  315. package/src/i18n/instrumentation.ru.ts +195 -0
  316. package/src/i18n/instrumentation.zh-CN.ts +195 -0
  317. package/src/i18n/lens.ar.ts +24 -0
  318. package/src/i18n/lens.de.ts +24 -0
  319. package/src/i18n/lens.es.ts +24 -0
  320. package/src/i18n/lens.fr.ts +24 -0
  321. package/src/i18n/lens.he.ts +24 -0
  322. package/src/i18n/lens.hi.ts +24 -0
  323. package/src/i18n/lens.ja.ts +24 -0
  324. package/src/i18n/lens.ko.ts +24 -0
  325. package/src/i18n/lens.pt-BR.ts +24 -0
  326. package/src/i18n/lens.ru.ts +25 -0
  327. package/src/i18n/lens.zh-CN.ts +24 -0
  328. package/src/i18n/lighting.ar.ts +86 -0
  329. package/src/i18n/lighting.de.ts +84 -0
  330. package/src/i18n/lighting.es.ts +89 -0
  331. package/src/i18n/lighting.fr.ts +84 -0
  332. package/src/i18n/lighting.he.ts +88 -0
  333. package/src/i18n/lighting.hi.ts +90 -0
  334. package/src/i18n/lighting.ja.ts +90 -0
  335. package/src/i18n/lighting.ko.ts +90 -0
  336. package/src/i18n/lighting.pt-BR.ts +90 -0
  337. package/src/i18n/lighting.ru.ts +88 -0
  338. package/src/i18n/lighting.zh-CN.ts +92 -0
  339. package/src/i18n/loop-subject.ar.ts +39 -0
  340. package/src/i18n/loop-subject.de.ts +39 -0
  341. package/src/i18n/loop-subject.es.ts +39 -0
  342. package/src/i18n/loop-subject.fr.ts +39 -0
  343. package/src/i18n/loop-subject.he.ts +39 -0
  344. package/src/i18n/loop-subject.hi.ts +39 -0
  345. package/src/i18n/loop-subject.ja.ts +39 -0
  346. package/src/i18n/loop-subject.ko.ts +39 -0
  347. package/src/i18n/loop-subject.pt-BR.ts +39 -0
  348. package/src/i18n/loop-subject.ru.ts +39 -0
  349. package/src/i18n/loop-subject.zh-CN.ts +39 -0
  350. package/src/i18n/materials.ar.ts +80 -0
  351. package/src/i18n/materials.de.ts +80 -0
  352. package/src/i18n/materials.es.ts +87 -0
  353. package/src/i18n/materials.fr.ts +80 -0
  354. package/src/i18n/materials.he.ts +86 -0
  355. package/src/i18n/materials.hi.ts +86 -0
  356. package/src/i18n/materials.ja.ts +88 -0
  357. package/src/i18n/materials.ko.ts +88 -0
  358. package/src/i18n/materials.pt-BR.ts +88 -0
  359. package/src/i18n/materials.ru.ts +86 -0
  360. package/src/i18n/materials.zh-CN.ts +86 -0
  361. package/src/i18n/mood.ar.ts +61 -0
  362. package/src/i18n/mood.de.ts +61 -0
  363. package/src/i18n/mood.es.ts +66 -0
  364. package/src/i18n/mood.fr.ts +61 -0
  365. package/src/i18n/mood.he.ts +64 -0
  366. package/src/i18n/mood.hi.ts +66 -0
  367. package/src/i18n/mood.ja.ts +66 -0
  368. package/src/i18n/mood.ko.ts +66 -0
  369. package/src/i18n/mood.pt-BR.ts +64 -0
  370. package/src/i18n/mood.ru.ts +64 -0
  371. package/src/i18n/mood.zh-CN.ts +64 -0
  372. package/src/i18n/music-genre.ar.ts +302 -0
  373. package/src/i18n/music-genre.de.ts +302 -0
  374. package/src/i18n/music-genre.es.ts +302 -0
  375. package/src/i18n/music-genre.fr.ts +302 -0
  376. package/src/i18n/music-genre.he.ts +302 -0
  377. package/src/i18n/music-genre.hi.ts +302 -0
  378. package/src/i18n/music-genre.ja.ts +302 -0
  379. package/src/i18n/music-genre.ko.ts +302 -0
  380. package/src/i18n/music-genre.pt-BR.ts +302 -0
  381. package/src/i18n/music-genre.ru.ts +302 -0
  382. package/src/i18n/music-genre.zh-CN.ts +302 -0
  383. package/src/i18n/music-mood.ar.ts +75 -0
  384. package/src/i18n/music-mood.de.ts +75 -0
  385. package/src/i18n/music-mood.es.ts +75 -0
  386. package/src/i18n/music-mood.fr.ts +75 -0
  387. package/src/i18n/music-mood.he.ts +75 -0
  388. package/src/i18n/music-mood.hi.ts +75 -0
  389. package/src/i18n/music-mood.ja.ts +75 -0
  390. package/src/i18n/music-mood.ko.ts +75 -0
  391. package/src/i18n/music-mood.pt-BR.ts +75 -0
  392. package/src/i18n/music-mood.ru.ts +75 -0
  393. package/src/i18n/music-mood.zh-CN.ts +75 -0
  394. package/src/i18n/person.ar.ts +638 -0
  395. package/src/i18n/person.de.ts +629 -0
  396. package/src/i18n/person.es.ts +645 -0
  397. package/src/i18n/person.fr.ts +621 -0
  398. package/src/i18n/person.he.ts +656 -0
  399. package/src/i18n/person.hi.ts +654 -0
  400. package/src/i18n/person.ja.ts +662 -0
  401. package/src/i18n/person.ko.ts +662 -0
  402. package/src/i18n/person.pt-BR.ts +656 -0
  403. package/src/i18n/person.ru.ts +656 -0
  404. package/src/i18n/person.zh-CN.ts +656 -0
  405. package/src/i18n/photo-genre.ar.ts +58 -0
  406. package/src/i18n/photo-genre.de.ts +52 -0
  407. package/src/i18n/photo-genre.es.ts +64 -0
  408. package/src/i18n/photo-genre.fr.ts +58 -0
  409. package/src/i18n/photo-genre.he.ts +62 -0
  410. package/src/i18n/photo-genre.hi.ts +63 -0
  411. package/src/i18n/photo-genre.ja.ts +65 -0
  412. package/src/i18n/photo-genre.ko.ts +63 -0
  413. package/src/i18n/photo-genre.pt-BR.ts +65 -0
  414. package/src/i18n/photo-genre.ru.ts +63 -0
  415. package/src/i18n/photo-genre.zh-CN.ts +63 -0
  416. package/src/i18n/photographer.ar.ts +75 -0
  417. package/src/i18n/photographer.de.ts +74 -0
  418. package/src/i18n/photographer.es.ts +77 -0
  419. package/src/i18n/photographer.fr.ts +77 -0
  420. package/src/i18n/photographer.he.ts +78 -0
  421. package/src/i18n/photographer.hi.ts +80 -0
  422. package/src/i18n/photographer.ja.ts +84 -0
  423. package/src/i18n/photographer.ko.ts +84 -0
  424. package/src/i18n/photographer.pt-BR.ts +83 -0
  425. package/src/i18n/photographer.ru.ts +78 -0
  426. package/src/i18n/photographer.zh-CN.ts +78 -0
  427. package/src/i18n/pose.ar.ts +95 -0
  428. package/src/i18n/pose.de.ts +96 -0
  429. package/src/i18n/pose.es.ts +104 -0
  430. package/src/i18n/pose.fr.ts +96 -0
  431. package/src/i18n/pose.he.ts +104 -0
  432. package/src/i18n/pose.hi.ts +104 -0
  433. package/src/i18n/pose.ja.ts +104 -0
  434. package/src/i18n/pose.ko.ts +104 -0
  435. package/src/i18n/pose.pt-BR.ts +104 -0
  436. package/src/i18n/pose.ru.ts +104 -0
  437. package/src/i18n/pose.zh-CN.ts +104 -0
  438. package/src/i18n/post-process-effects.ar.ts +25 -0
  439. package/src/i18n/post-process-effects.de.ts +24 -0
  440. package/src/i18n/post-process-effects.es.ts +26 -0
  441. package/src/i18n/post-process-effects.fr.ts +24 -0
  442. package/src/i18n/post-process-effects.he.ts +24 -0
  443. package/src/i18n/post-process-effects.hi.ts +26 -0
  444. package/src/i18n/post-process-effects.ja.ts +26 -0
  445. package/src/i18n/post-process-effects.ko.ts +26 -0
  446. package/src/i18n/post-process-effects.pt-BR.ts +24 -0
  447. package/src/i18n/post-process-effects.ru.ts +24 -0
  448. package/src/i18n/post-process-effects.zh-CN.ts +24 -0
  449. package/src/i18n/render-quality.ar.ts +34 -0
  450. package/src/i18n/render-quality.de.ts +30 -0
  451. package/src/i18n/render-quality.es.ts +35 -0
  452. package/src/i18n/render-quality.fr.ts +34 -0
  453. package/src/i18n/render-quality.he.ts +33 -0
  454. package/src/i18n/render-quality.hi.ts +39 -0
  455. package/src/i18n/render-quality.ja.ts +39 -0
  456. package/src/i18n/render-quality.ko.ts +39 -0
  457. package/src/i18n/render-quality.pt-BR.ts +37 -0
  458. package/src/i18n/render-quality.ru.ts +37 -0
  459. package/src/i18n/render-quality.zh-CN.ts +37 -0
  460. package/src/i18n/seasons.ar.ts +10 -0
  461. package/src/i18n/seasons.de.ts +10 -0
  462. package/src/i18n/seasons.es.ts +10 -0
  463. package/src/i18n/seasons.fr.ts +10 -0
  464. package/src/i18n/seasons.he.ts +10 -0
  465. package/src/i18n/seasons.hi.ts +10 -0
  466. package/src/i18n/seasons.ja.ts +10 -0
  467. package/src/i18n/seasons.ko.ts +10 -0
  468. package/src/i18n/seasons.pt-BR.ts +10 -0
  469. package/src/i18n/seasons.ru.ts +10 -0
  470. package/src/i18n/seasons.zh-CN.ts +10 -0
  471. package/src/i18n/setting.ar.ts +73 -0
  472. package/src/i18n/setting.de.ts +73 -0
  473. package/src/i18n/setting.es.ts +77 -0
  474. package/src/i18n/setting.fr.ts +73 -0
  475. package/src/i18n/setting.he.ts +76 -0
  476. package/src/i18n/setting.hi.ts +76 -0
  477. package/src/i18n/setting.ja.ts +78 -0
  478. package/src/i18n/setting.ko.ts +76 -0
  479. package/src/i18n/setting.pt-BR.ts +78 -0
  480. package/src/i18n/setting.ru.ts +76 -0
  481. package/src/i18n/setting.zh-CN.ts +76 -0
  482. package/src/i18n/style.ar.ts +55 -0
  483. package/src/i18n/style.de.ts +54 -0
  484. package/src/i18n/style.es.ts +54 -0
  485. package/src/i18n/style.fr.ts +54 -0
  486. package/src/i18n/style.he.ts +54 -0
  487. package/src/i18n/style.hi.ts +54 -0
  488. package/src/i18n/style.ja.ts +54 -0
  489. package/src/i18n/style.ko.ts +54 -0
  490. package/src/i18n/style.pt-BR.ts +56 -0
  491. package/src/i18n/style.ru.ts +54 -0
  492. package/src/i18n/style.zh-CN.ts +54 -0
  493. package/src/i18n/styling.ar.ts +295 -0
  494. package/src/i18n/styling.de.ts +285 -0
  495. package/src/i18n/styling.es.ts +317 -0
  496. package/src/i18n/styling.fr.ts +285 -0
  497. package/src/i18n/styling.he.ts +307 -0
  498. package/src/i18n/styling.hi.ts +323 -0
  499. package/src/i18n/styling.ja.ts +317 -0
  500. package/src/i18n/styling.ko.ts +311 -0
  501. package/src/i18n/styling.pt-BR.ts +301 -0
  502. package/src/i18n/styling.ru.ts +301 -0
  503. package/src/i18n/styling.zh-CN.ts +307 -0
  504. package/src/i18n/temporal.ar.ts +31 -0
  505. package/src/i18n/temporal.de.ts +24 -0
  506. package/src/i18n/temporal.es.ts +27 -0
  507. package/src/i18n/temporal.fr.ts +28 -0
  508. package/src/i18n/temporal.he.ts +31 -0
  509. package/src/i18n/temporal.hi.ts +31 -0
  510. package/src/i18n/temporal.ja.ts +31 -0
  511. package/src/i18n/temporal.ko.ts +31 -0
  512. package/src/i18n/temporal.pt-BR.ts +31 -0
  513. package/src/i18n/temporal.ru.ts +31 -0
  514. package/src/i18n/temporal.zh-CN.ts +31 -0
  515. package/src/i18n/transitions.ar.ts +97 -0
  516. package/src/i18n/transitions.de.ts +97 -0
  517. package/src/i18n/transitions.es.ts +97 -0
  518. package/src/i18n/transitions.fr.ts +97 -0
  519. package/src/i18n/transitions.he.ts +97 -0
  520. package/src/i18n/transitions.hi.ts +97 -0
  521. package/src/i18n/transitions.ja.ts +97 -0
  522. package/src/i18n/transitions.ko.ts +97 -0
  523. package/src/i18n/transitions.pt-BR.ts +97 -0
  524. package/src/i18n/transitions.ru.ts +97 -0
  525. package/src/i18n/transitions.zh-CN.ts +97 -0
  526. package/src/i18n/types.ts +158 -0
  527. package/src/i18n/vehicles.ar.ts +137 -0
  528. package/src/i18n/vehicles.de.ts +125 -0
  529. package/src/i18n/vehicles.es.ts +138 -0
  530. package/src/i18n/vehicles.fr.ts +125 -0
  531. package/src/i18n/vehicles.he.ts +136 -0
  532. package/src/i18n/vehicles.hi.ts +138 -0
  533. package/src/i18n/vehicles.ja.ts +138 -0
  534. package/src/i18n/vehicles.ko.ts +138 -0
  535. package/src/i18n/vehicles.pt-BR.ts +136 -0
  536. package/src/i18n/vehicles.ru.ts +136 -0
  537. package/src/i18n/vehicles.zh-CN.ts +136 -0
  538. package/src/i18n/voice-character.ar.ts +126 -0
  539. package/src/i18n/voice-character.de.ts +126 -0
  540. package/src/i18n/voice-character.es.ts +126 -0
  541. package/src/i18n/voice-character.fr.ts +126 -0
  542. package/src/i18n/voice-character.he.ts +126 -0
  543. package/src/i18n/voice-character.hi.ts +126 -0
  544. package/src/i18n/voice-character.ja.ts +126 -0
  545. package/src/i18n/voice-character.ko.ts +126 -0
  546. package/src/i18n/voice-character.pt-BR.ts +126 -0
  547. package/src/i18n/voice-character.ru.ts +126 -0
  548. package/src/i18n/voice-character.zh-CN.ts +126 -0
  549. package/src/i18n/voice-delivery.ar.ts +77 -0
  550. package/src/i18n/voice-delivery.de.ts +77 -0
  551. package/src/i18n/voice-delivery.es.ts +77 -0
  552. package/src/i18n/voice-delivery.fr.ts +77 -0
  553. package/src/i18n/voice-delivery.he.ts +77 -0
  554. package/src/i18n/voice-delivery.hi.ts +77 -0
  555. package/src/i18n/voice-delivery.ja.ts +77 -0
  556. package/src/i18n/voice-delivery.ko.ts +77 -0
  557. package/src/i18n/voice-delivery.pt-BR.ts +77 -0
  558. package/src/i18n/voice-delivery.ru.ts +77 -0
  559. package/src/i18n/voice-delivery.zh-CN.ts +77 -0
  560. package/src/i18n/weapons.ar.ts +115 -0
  561. package/src/i18n/weapons.de.ts +114 -0
  562. package/src/i18n/weapons.es.ts +116 -0
  563. package/src/i18n/weapons.fr.ts +103 -0
  564. package/src/i18n/weapons.he.ts +114 -0
  565. package/src/i18n/weapons.hi.ts +116 -0
  566. package/src/i18n/weapons.ja.ts +116 -0
  567. package/src/i18n/weapons.ko.ts +116 -0
  568. package/src/i18n/weapons.pt-BR.ts +114 -0
  569. package/src/i18n/weapons.ru.ts +114 -0
  570. package/src/i18n/weapons.zh-CN.ts +114 -0
  571. package/src/image-critic-node.ts +61 -0
  572. package/src/image-critic-types.ts +40 -0
  573. package/src/index.ts +866 -0
  574. package/src/inject-upstream.ts +15 -0
  575. package/src/inpaint-region.ts +51 -0
  576. package/src/json-evaluator.ts +732 -0
  577. package/src/json-path.ts +52 -0
  578. package/src/lip-sync-pricing.ts +90 -0
  579. package/src/list-merge.ts +40 -0
  580. package/src/list-sort.ts +122 -0
  581. package/src/list-source-resolver.ts +50 -0
  582. package/src/llm-models.ts +245 -0
  583. package/src/location-mention-slug.ts +291 -0
  584. package/src/location-preset-catalog-map.ts +128 -0
  585. package/src/loop-delimiter.ts +73 -0
  586. package/src/lora-routing.ts +95 -0
  587. package/src/lottie-overlay-catalog.ts +175 -0
  588. package/src/lottie-slots.ts +309 -0
  589. package/src/model-catalog.ts +2386 -0
  590. package/src/model-constants.ts +1910 -0
  591. package/src/model-tree.ts +120 -0
  592. package/src/monetization.ts +15 -0
  593. package/src/multi-pick.ts +42 -0
  594. package/src/node-default-mappings.ts +262 -0
  595. package/src/node-mappable-fields.ts +70 -0
  596. package/src/node-preset-export.ts +56 -0
  597. package/src/node-preset-extract.ts +147 -0
  598. package/src/node-refs.ts +253 -0
  599. package/src/node-runtime-keys.ts +117 -0
  600. package/src/object-aspect-defaults.ts +72 -0
  601. package/src/object-picker-types.ts +22 -0
  602. package/src/parameter-node-value.ts +284 -0
  603. package/src/pinterest-url.ts +28 -0
  604. package/src/pipeline-chat.ts +72 -0
  605. package/src/pipeline-defaults.ts +318 -0
  606. package/src/pipeline-events.ts +162 -0
  607. package/src/pipeline-state-types.ts +196 -0
  608. package/src/pipeline-types.ts +647 -0
  609. package/src/pipeline-validation.ts +87 -0
  610. package/src/presentation-types.ts +23 -0
  611. package/src/presentation-utils.ts +397 -0
  612. package/src/producer-types.ts +188 -0
  613. package/src/progress-curve.ts +99 -0
  614. package/src/provider-directive-defaults.ts +69 -0
  615. package/src/reduce-strategy-registry.ts +121 -0
  616. package/src/reference-board-templates.ts +81 -0
  617. package/src/reference-roles.ts +153 -0
  618. package/src/reference-sheet/__tests__/board-to-column.test.ts +20 -0
  619. package/src/reference-sheet/__tests__/catalog.test.ts +50 -0
  620. package/src/reference-sheet/__tests__/cost.test.ts +38 -0
  621. package/src/reference-sheet/__tests__/no-drift.test.ts +28 -0
  622. package/src/reference-sheet/__tests__/panel-plan.test.ts +61 -0
  623. package/src/reference-sheet/__tests__/panel-prompts.test.ts +17 -0
  624. package/src/reference-sheet/__tests__/plan-generation.test.ts +72 -0
  625. package/src/reference-sheet/__tests__/presets.test.ts +54 -0
  626. package/src/reference-sheet/__tests__/types.test.ts +24 -0
  627. package/src/reference-sheet/catalog.ts +144 -0
  628. package/src/reference-sheet/cost.ts +37 -0
  629. package/src/reference-sheet/credit-id.ts +7 -0
  630. package/src/reference-sheet/index.ts +8 -0
  631. package/src/reference-sheet/panel-plan.ts +65 -0
  632. package/src/reference-sheet/panel-prompts.ts +14 -0
  633. package/src/reference-sheet/plan-generation.ts +79 -0
  634. package/src/reference-sheet/presets.ts +77 -0
  635. package/src/reference-sheet/types.ts +92 -0
  636. package/src/repeat-types.ts +97 -0
  637. package/src/resolve-field-mappings.ts +119 -0
  638. package/src/route-filter.ts +80 -0
  639. package/src/scene-helper-types.ts +249 -0
  640. package/src/scene-node-types.ts +281 -0
  641. package/src/scraper-actors.ts +57 -0
  642. package/src/scraper-output-schemas.ts +25 -0
  643. package/src/seasons.ts +45 -0
  644. package/src/selector.ts +864 -0
  645. package/src/settled-with-limit.ts +42 -0
  646. package/src/shot-element.ts +43 -0
  647. package/src/social-media-specs.ts +121 -0
  648. package/src/social-post.ts +24 -0
  649. package/src/sub-workflow-validation.ts +78 -0
  650. package/src/supported-fonts.ts +40 -0
  651. package/src/surround.ts +113 -0
  652. package/src/switchx-pricing.ts +33 -0
  653. package/src/text-separators.ts +59 -0
  654. package/src/to-connected-references.ts +77 -0
  655. package/src/types.ts +272 -0
  656. package/src/variant-job-id.ts +17 -0
  657. package/src/vehicles.ts +213 -0
  658. package/src/video-analysis-pricing.ts +74 -0
  659. package/src/video-analysis.ts +127 -0
  660. package/src/video-duration.ts +25 -0
  661. package/src/voice-changer-models.ts +36 -0
  662. package/src/voice-matcher-types.ts +37 -0
  663. package/src/voices.ts +92 -0
  664. package/src/weapons.ts +190 -0
  665. package/src/workflow-export.ts +153 -0
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Location `@-mention` parser. Mirrors `character-mention-slug.ts` shape but
3
+ * with two key differences:
4
+ *
5
+ * 1. **Bucketed variants:** the 3rd segment can be `bucket/variant` (slash-
6
+ * separated, e.g. `weather/rain` or `lighting/cinematic`) in addition
7
+ * to a bare usage-mode keyword. Locations carry their variants split
8
+ * across 5 buckets (timeOfDay / weather / seasons / angles / lighting)
9
+ * plus motion clips; the bucket prefix disambiguates which array to
10
+ * pull from when two buckets happen to share a variant name.
11
+ *
12
+ * 2. **Smaller usage-mode set:** locations support 4 modes ("identical",
13
+ * "style", "layout", "none") — a strict subset of the 8 character modes.
14
+ * The character modes "face" / "face-pose" / "pose" / "emotion" / "name"
15
+ * don't apply to scenes.
16
+ *
17
+ * The mention resolver (Phase 2 #2 follow-up) uses the parsed token to look
18
+ * up the variant URL by walking the upstream Location node's `node.data`:
19
+ * timeOfDay / weather / seasons / angles / lighting / atmosphereMotions
20
+ * arrays, each `{name, url}`. Slug match is case-insensitive via the same
21
+ * slugify helper used by character variants.
22
+ *
23
+ * Format reference (the parser accepts these shapes; everything else returns
24
+ * null and the token falls through to literal-text in the final prompt):
25
+ *
26
+ * @oldlibrary:1 — canonical, default mode
27
+ * @oldlibrary:1:weather/rain — rain variant from weather bucket
28
+ * @oldlibrary:1:layout — canonical, mode "layout"
29
+ * @oldlibrary:1:weather/rain:style — variant + mode override
30
+ * @oldlibrary:1:weather/rain:bogus — null (4th segment must be a known
31
+ * location usage mode)
32
+ */
33
+
34
+ /** Modes that apply to scenes/locations. Subset of character `USAGE_MODES`. */
35
+ export const LOCATION_USAGE_MODES = [
36
+ "identical",
37
+ "style",
38
+ "layout",
39
+ "none",
40
+ ] as const
41
+
42
+ export type LocationUsageMode = (typeof LOCATION_USAGE_MODES)[number]
43
+
44
+ /** Default mode when neither the slug nor the location node specifies one. */
45
+ export const DEFAULT_LOCATION_USAGE_MODE: LocationUsageMode = "identical"
46
+
47
+ /** Type guard — narrows an arbitrary string to `LocationUsageMode`. */
48
+ export function isLocationUsageMode(s: string): s is LocationUsageMode {
49
+ return (LOCATION_USAGE_MODES as readonly string[]).includes(s)
50
+ }
51
+
52
+ /**
53
+ * Human-readable label for the location usage-mode dropdown / badge UI.
54
+ * Mirrors `usageModeLabel` for character modes but with location-specific
55
+ * phrasing — locations don't have face/pose semantics, so the labels speak
56
+ * about the scene as a whole (framing, layout, mood) instead of subject
57
+ * features. Used by the location pill's mode menu (slice 4) and the
58
+ * hierarchical drill in the `@`-autocomplete.
59
+ *
60
+ * Phrasing decisions:
61
+ * - "Match exactly" — strongest possible directive; the scene should
62
+ * reproduce the reference verbatim. Equivalent in role to character
63
+ * "Identical".
64
+ * - "Style / mood only" — atmospheric transfer (lighting, color grade,
65
+ * mood) without locking the framing. Maps to character "Style only".
66
+ * - "Layout / framing only" — keep the spatial composition (where things
67
+ * are, where the camera sits) without copying the textures or palette.
68
+ * No character-side equivalent.
69
+ * - "No textual bias" — visual reference only, no top-level header
70
+ * mention. Maps to character "None".
71
+ */
72
+ export function locationUsageModeLabel(mode: LocationUsageMode): string {
73
+ switch (mode) {
74
+ case "identical": return "Match exactly"
75
+ case "style": return "Style / mood only"
76
+ case "layout": return "Layout / framing only"
77
+ case "none": return "No textual bias"
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Slugify a location name for use in @-mention tokens. Same algorithm as
83
+ * `characterMentionSlug` — lowercase, strip non-alphanumeric, collapse runs.
84
+ * Kept as a separate export to make the call site's intent explicit and to
85
+ * allow future divergence (e.g., locations may need to preserve digits at
86
+ * the start, characters may not).
87
+ */
88
+ export function locationMentionSlug(name: string): string {
89
+ return name
90
+ .toLowerCase()
91
+ .replace(/[^a-z0-9]+/g, "-")
92
+ .replace(/-+/g, "-")
93
+ .replace(/^-|-$/g, "")
94
+ }
95
+
96
+ export interface LocationMentionTokenInfo {
97
+ readonly token: string
98
+ readonly locationSlug: string
99
+ readonly imageIndex: number
100
+ /** "weather", "lighting", etc. — null when the mention targets the canonical
101
+ * main image. */
102
+ readonly bucket: string | null
103
+ /** Variant name within the bucket (e.g. "rain"). null for canonical. */
104
+ readonly variant: string | null
105
+ /** Per-mention mode override; null falls back to the location node's default
106
+ * (or the global "identical" default). */
107
+ readonly usageMode: LocationUsageMode | null
108
+ /** Bare-slug ROLE (Unified Reference Roles, Phase D + F2) — any slash-less,
109
+ * non-mode 3rd segment (`background`, `empty-background`, `as-is`, … or a
110
+ * CUSTOM slug), stored verbatim in slug form. Absent (undefined) for canonical /
111
+ * bucket-variant / mode tokens. The hybrid resolver + role pill map it back to
112
+ * the phrase key via `normalizeRoleSlug` (custom slugs pass through). Optional so
113
+ * canonical/variant/mode tokens stay shape-identical to the pre-Phase-D parser
114
+ * output. */
115
+ readonly role?: string
116
+ /**
117
+ * Additive per-mention identity-lock sentinel (Unified Reference Roles,
118
+ * Task 4 + F4). Tri-state: `true` (`~lock`, force ON) | `false` (`~nolock`,
119
+ * force OFF — suppresses a ref-level `identityLock.enabled = true`) |
120
+ * ABSENT/undefined (neither — inherit the ref default; byte-identical to the
121
+ * pre-Task-4 shape). Only ACTED UPON by the HYBRID resolver; the LEGACY
122
+ * resolver ignores it, so both sentinels are inert on the legacy path.
123
+ */
124
+ readonly lock?: boolean
125
+ /** Byte offset into the source prompt — used to splice the token out at
126
+ * resolve time. */
127
+ readonly offset: number
128
+ }
129
+
130
+ /**
131
+ * Parse a single `@<location>:<index>(:<bucket>/<variant>|<mode>)?(:<mode>)?`
132
+ * token. Returns null when the token doesn't match any supported shape
133
+ * (caller falls back to literal text).
134
+ *
135
+ * Disambiguation at the 3rd segment: presence of `/` indicates a
136
+ * bucket/variant pair; absence indicates a bare mode keyword. The 4th
137
+ * segment is always a mode override (and must be a valid `LocationUsageMode`).
138
+ */
139
+ export function parseLocationMentionToken(
140
+ text: string,
141
+ ): {
142
+ locationSlug: string
143
+ imageIndex: number
144
+ bucket: string | null
145
+ variant: string | null
146
+ usageMode: LocationUsageMode | null
147
+ /** Bare-slug role (slug form). Present for ANY bare, non-mode 3rd segment
148
+ * (preset OR custom, F2); OMITTED (undefined) for every other shape so
149
+ * canonical/variant/mode results stay byte-identical to the pre-Phase-D parser. */
150
+ role?: string
151
+ /** Additive per-mention identity-lock sentinel (Task 4 + F4). Tri-state:
152
+ * `true` (`~lock`) | `false` (`~nolock`) | OMITTED (neither — byte-identical). */
153
+ lock?: boolean
154
+ } | null {
155
+ if (!text.startsWith("@")) return null
156
+ let rest = text.slice(1)
157
+ if (rest.length === 0 || !/^[a-z]/.test(rest)) return null
158
+
159
+ // Additive `~lock` / `~nolock` sentinels (Task 4 + F4). Strip a trailing
160
+ // `~nolock` (force lock OFF) or `~lock` (force lock ON) BEFORE splitting so
161
+ // the segment grammar stays byte-identical (a `~` never appears inside a
162
+ // bucket/variant/mode/role segment). Check `~nolock` FIRST. A token with
163
+ // NEITHER sentinel is untouched and gains NO `lock` key (byte-identical).
164
+ let lockField: { lock?: boolean } = {}
165
+ if (rest.endsWith("~nolock")) {
166
+ rest = rest.slice(0, -"~nolock".length)
167
+ lockField = { lock: false }
168
+ } else if (rest.endsWith("~lock")) {
169
+ rest = rest.slice(0, -"~lock".length)
170
+ lockField = { lock: true }
171
+ }
172
+
173
+ const parts = rest.split(":")
174
+ if (parts.length < 2 || parts.length > 4) return null
175
+
176
+ const [locationSlug, indexStr, third, fourth] = parts
177
+ if (!/^[a-z][a-z0-9-]*$/.test(locationSlug)) return null
178
+ if (!/^\d+$/.test(indexStr)) return null
179
+ const imageIndex = parseInt(indexStr, 10)
180
+ if (!Number.isInteger(imageIndex) || imageIndex < 1) return null
181
+
182
+ // 2-part: @oldlibrary:1 — canonical, default mode.
183
+ if (parts.length === 2) {
184
+ return {
185
+ locationSlug,
186
+ imageIndex,
187
+ bucket: null,
188
+ variant: null,
189
+ usageMode: null,
190
+ ...lockField,
191
+ }
192
+ }
193
+
194
+ // 3-part: @oldlibrary:1:X — X is either bucket/variant or a mode keyword.
195
+ if (parts.length === 3) {
196
+ if (third.includes("/")) {
197
+ const slashAt = third.indexOf("/")
198
+ const bucket = third.slice(0, slashAt)
199
+ const variant = third.slice(slashAt + 1)
200
+ if (!/^[a-z][a-z0-9-]*$/.test(bucket)) return null
201
+ if (!/^[a-z][a-z0-9-]*$/.test(variant)) return null
202
+ return { locationSlug, imageIndex, bucket, variant, usageMode: null, ...lockField }
203
+ }
204
+ if (!/^[a-z][a-z0-9-]*$/.test(third)) return null
205
+ if (isLocationUsageMode(third)) {
206
+ return {
207
+ locationSlug,
208
+ imageIndex,
209
+ bucket: null,
210
+ variant: null,
211
+ usageMode: third,
212
+ ...lockField,
213
+ }
214
+ }
215
+ // Additive (Unified Reference Roles, Phase D + F2 follow-up): a bare, non-
216
+ // mode 3rd segment parses as a ROLE, stored verbatim in slug form
217
+ // (`background`, `empty-background`, `as-is`, …, or a user's CUSTOM slug).
218
+ // The F2 follow-up REMOVED the preset membership gate so custom location
219
+ // roles behave like custom character roles — any valid slug (guaranteed
220
+ // `[a-z][a-z0-9-]*` by the regex above, and not a `LocationUsageMode`, which
221
+ // is caught first) is accepted. Legacy stays byte-identical NOT via this
222
+ // parser but via the resolver's `if (t.role) continue` guard, which skips
223
+ // ANY role token (preset or custom) → literal text with no bullet / phrase.
224
+ // The slug round-trips through the pill's `renderText`; the hybrid resolver /
225
+ // pill map it to a phrase via `normalizeRoleSlug` (custom slugs pass through
226
+ // unchanged). (`layout`/`style` never reach this branch — usage modes above.)
227
+ return {
228
+ locationSlug,
229
+ imageIndex,
230
+ bucket: null,
231
+ variant: null,
232
+ usageMode: null,
233
+ role: third,
234
+ ...lockField,
235
+ }
236
+ }
237
+
238
+ // 4-part: @oldlibrary:1:bucket/variant:mode.
239
+ if (parts.length === 4) {
240
+ if (!third.includes("/")) return null
241
+ const slashAt = third.indexOf("/")
242
+ const bucket = third.slice(0, slashAt)
243
+ const variant = third.slice(slashAt + 1)
244
+ if (!/^[a-z][a-z0-9-]*$/.test(bucket)) return null
245
+ if (!/^[a-z][a-z0-9-]*$/.test(variant)) return null
246
+ if (!isLocationUsageMode(fourth)) return null
247
+ return { locationSlug, imageIndex, bucket, variant, usageMode: fourth, ...lockField }
248
+ }
249
+
250
+ return null
251
+ }
252
+
253
+ /**
254
+ * Find all location @-mentions in a prompt that match a known location slug.
255
+ *
256
+ * The regex captures every `@<slug>:<index>(:<segment>)?(:<segment>)?` shape
257
+ * where each segment is either `[a-z][a-z0-9-]*` (the character format —
258
+ * shared with characters) or `[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*` (the
259
+ * bucket/variant format — location-only). `knownLocationSlugs` filters to
260
+ * only the user's wired locations so `@kira:1:smile` doesn't accidentally
261
+ * trip the location parser.
262
+ */
263
+ export function findLocationMentionTokens(
264
+ prompt: string,
265
+ knownLocationSlugs: readonly string[],
266
+ ): LocationMentionTokenInfo[] {
267
+ const tokens: LocationMentionTokenInfo[] = []
268
+ // Each optional segment is either a plain slug (`[a-z][a-z0-9-]*`) OR a
269
+ // bucket/variant pair (`[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*`). The two are
270
+ // disjoint at the regex level — bucket/variant requires the literal `/`.
271
+ const segment = "(?:[a-z][a-z0-9-]*\\/[a-z][a-z0-9-]*|[a-z][a-z0-9-]*)"
272
+ // The optional trailing `(?:~(?:no)?lock)?` absorbs the additive Task-4/F4
273
+ // identity-lock sentinel (`~lock` force-on OR `~nolock` force-off) INTO the
274
+ // captured token (spliced out at resolve time); optional, so a lock-less token
275
+ // matches byte-identically to before. `(?![a-z0-9-])` keeps `~locked` /
276
+ // `~nolockx` literal.
277
+ const regex = new RegExp(
278
+ `(?:^|[^a-zA-Z0-9])(@[a-z][a-z0-9-]*:\\d+(?::${segment})?(?::${segment})?(?:~(?:no)?lock(?![a-z0-9-]))?)`,
279
+ "g",
280
+ )
281
+ const knownSet = new Set(knownLocationSlugs)
282
+ for (const match of prompt.matchAll(regex)) {
283
+ const token = match[1]
284
+ const offset = (match.index ?? 0) + (match[0].length - token.length)
285
+ const parsed = parseLocationMentionToken(token)
286
+ if (parsed && knownSet.has(parsed.locationSlug)) {
287
+ tokens.push({ token, ...parsed, offset })
288
+ }
289
+ }
290
+ return tokens
291
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Adapter from the Location Studio's backend preset strings to canonical
3
+ * picker-catalog entries.
4
+ *
5
+ * The Location Studio's tab presets ship 46 backend-stable variant strings
6
+ * (e.g. "wide", "golden hour", "drone fly-over"). These strings are what the
7
+ * frontend sends to `POST /v1/generate-location-asset` and what backend Zod
8
+ * validates against the `VARIANTS` map in
9
+ * `backend/src/routes/generate-location-asset.ts`. They MUST stay stable.
10
+ *
11
+ * For display, however, we want translated labels that match the rest of
12
+ * the app. Instead of maintaining a parallel `location-variants` i18n
13
+ * catalog (the duplication this file replaces), the Studio looks up each
14
+ * preset against an existing canonical catalog — framing, lighting,
15
+ * atmosphere, camera-motions, seasons — and uses the existing localized
16
+ * label.
17
+ *
18
+ * Adding a new preset to a Location Studio tab: pick the closest entry in
19
+ * the relevant canonical catalog and add a mapping here. If the closest
20
+ * match is wrong, ADD a new entry to the canonical catalog (so the
21
+ * camera-motion picker / framing picker / etc. all benefit), then map.
22
+ */
23
+ import type { I18nCatalogId } from "./i18n/types.js"
24
+
25
+ export interface LocationCatalogRef {
26
+ readonly catalogId: I18nCatalogId
27
+ readonly entryId: string
28
+ }
29
+
30
+ /**
31
+ * Backend variant string → canonical catalog reference.
32
+ *
33
+ * Keys MUST match the strings in `VARIANTS` in
34
+ * `backend/src/routes/generate-location-asset.ts` AND the preset arrays in
35
+ * the Location Studio tab wrappers
36
+ * (`frontend/src/components/editor/location-studio/{time-of-day,weather,seasons,angles,lighting}-tab.tsx`)
37
+ * AND `motion-tab.tsx`'s MOTION_PRESETS.
38
+ */
39
+ export const LOCATION_PRESET_TO_CATALOG: Readonly<Record<string, LocationCatalogRef>> = {
40
+ // ── timeOfDay (9) → lighting time-of-day category ────────────────────
41
+ "dawn": { catalogId: "lighting", entryId: "dawn" },
42
+ "morning": { catalogId: "lighting", entryId: "morning" },
43
+ "noon": { catalogId: "lighting", entryId: "noon" },
44
+ "afternoon": { catalogId: "lighting", entryId: "afternoon" },
45
+ "golden hour": { catalogId: "lighting", entryId: "golden-hour" },
46
+ "dusk": { catalogId: "lighting", entryId: "dusk" },
47
+ "blue hour": { catalogId: "lighting", entryId: "blue-hour" },
48
+ "night": { catalogId: "lighting", entryId: "night" },
49
+ "midnight": { catalogId: "lighting", entryId: "midnight" },
50
+
51
+ // ── weather (9) → atmosphere ─────────────────────────────────────────
52
+ "clear": { catalogId: "atmosphere", entryId: "clear" },
53
+ "cloudy": { catalogId: "atmosphere", entryId: "cloudy" },
54
+ "light rain": { catalogId: "atmosphere", entryId: "light-rain" },
55
+ "heavy rain": { catalogId: "atmosphere", entryId: "heavy-rain" },
56
+ "storm": { catalogId: "atmosphere", entryId: "storm" },
57
+ "snow": { catalogId: "atmosphere", entryId: "snow" },
58
+ "blizzard": { catalogId: "atmosphere", entryId: "blizzard" },
59
+ "fog": { catalogId: "atmosphere", entryId: "fog" },
60
+ "mist": { catalogId: "atmosphere", entryId: "mist" },
61
+
62
+ // ── seasons (4) → seasons (this catalog only exists to serve this tab) ─
63
+ "spring": { catalogId: "seasons", entryId: "spring" },
64
+ "summer": { catalogId: "seasons", entryId: "summer" },
65
+ "autumn": { catalogId: "seasons", entryId: "autumn" },
66
+ "winter": { catalogId: "seasons", entryId: "winter" },
67
+
68
+ // ── angles (8) → framing ────────────────────────────────────────────
69
+ "wide": { catalogId: "framing", entryId: "wide-shot" },
70
+ "medium": { catalogId: "framing", entryId: "medium-shot" },
71
+ "closeup": { catalogId: "framing", entryId: "close-up" },
72
+ // `framing` has `birds-eye` and `overhead` but no plain `aerial`. The
73
+ // semantic intent ("view from above") is `birds-eye`, so we route there.
74
+ "aerial": { catalogId: "framing", entryId: "birds-eye" },
75
+ "low-angle": { catalogId: "framing", entryId: "low-angle" },
76
+ "eye-level": { catalogId: "framing", entryId: "eye-level" },
77
+ "bird's-eye": { catalogId: "framing", entryId: "birds-eye" },
78
+ "dutch tilt": { catalogId: "framing", entryId: "dutch-angle" },
79
+
80
+ // ── lighting (8) → lighting non-time-of-day categories ───────────────
81
+ // (`"blue hour"` is shared with timeOfDay above — same canonical entry.)
82
+ "soft natural": { catalogId: "lighting", entryId: "natural" },
83
+ "harsh sunlight": { catalogId: "lighting", entryId: "harsh-midday" },
84
+ "golden": { catalogId: "lighting", entryId: "golden-hour" },
85
+ "neon": { catalogId: "lighting", entryId: "neon-night" },
86
+ "candlelit": { catalogId: "lighting", entryId: "candlelight" },
87
+ "cinematic": { catalogId: "lighting", entryId: "three-point" },
88
+ "dramatic chiaroscuro": { catalogId: "lighting", entryId: "chiaroscuro" },
89
+
90
+ // ── motion (8) → camera-motions ──────────────────────────────────────
91
+ // The "slow" / "gentle" qualifiers are dropped at lookup time — the
92
+ // chip displays the canonical motion name ("Dolly-In", "Pan Left") with
93
+ // the user's locale applied.
94
+ "slow dolly-in": { catalogId: "camera-motions", entryId: "dolly-in" },
95
+ "slow pan-left": { catalogId: "camera-motions", entryId: "pan-left" },
96
+ "slow pan-right": { catalogId: "camera-motions", entryId: "pan-right" },
97
+ "push up": { catalogId: "camera-motions", entryId: "pedestal-up" },
98
+ "drone fly-over": { catalogId: "camera-motions", entryId: "fly-over" },
99
+ "gentle drift": { catalogId: "camera-motions", entryId: "gentle-drift" },
100
+ "parallax": { catalogId: "camera-motions", entryId: "parallax" },
101
+ "static atmospheric": { catalogId: "camera-motions", entryId: "static" },
102
+ }
103
+
104
+ /**
105
+ * Resolve a backend preset string to its canonical catalog reference, or
106
+ * undefined if the preset is unknown (caller falls back to the raw
107
+ * preset string as the display label).
108
+ */
109
+ export function resolveLocationPresetCatalog(preset: string): LocationCatalogRef | undefined {
110
+ return LOCATION_PRESET_TO_CATALOG[preset]
111
+ }
112
+
113
+ /**
114
+ * Each Location Studio tab pulls all its localized labels from a single
115
+ * canonical catalog (the tab's bucket → catalog mapping below). This lets
116
+ * the tab call `useLocalizedCatalog(LOCATION_BUCKET_TO_CATALOG_ID[bucket])`
117
+ * once and resolve every preset chip through the same catalog.
118
+ *
119
+ * Atmosphere motion (motion-tab.tsx) uses `camera-motions` directly — it's
120
+ * a single-bucket tab so the mapping isn't needed there.
121
+ */
122
+ export const LOCATION_BUCKET_TO_CATALOG_ID = {
123
+ timeOfDay: "lighting",
124
+ weather: "atmosphere",
125
+ seasons: "seasons",
126
+ angles: "framing",
127
+ lighting: "lighting",
128
+ } as const satisfies Record<string, I18nCatalogId>
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Sentinel value persisted by the "None" delimiter option in the UI. Distinct
3
+ * from `undefined` (which means "default to newline") so we can tell the
4
+ * difference between "user actively chose not to split" and "field never set".
5
+ */
6
+ export const NO_SPLIT_DELIMITER = "__none__" as const
7
+
8
+ /**
9
+ * Split text using a loop node's column delimiter.
10
+ *
11
+ * Uses the first text-type column's `splitDelimiter` to determine
12
+ * how to split upstream text. Falls back to newline when no delimiter
13
+ * is configured. The "first text column wins" heuristic is intentional:
14
+ * connected mode pipes a single text stream into the loop, so we use
15
+ * the primary text column's delimiter as the split strategy.
16
+ *
17
+ * `splitDelimiter === NO_SPLIT_DELIMITER` ("__none__") returns the input as
18
+ * a single-item array — the user explicitly opted out of splitting.
19
+ */
20
+ export function splitByLoopDelimiter(
21
+ text: string,
22
+ columns: ReadonlyArray<{ type?: string; splitDelimiter?: string }> | undefined,
23
+ ): string[] {
24
+ const firstTextCol = (columns ?? []).find((c) => (c.type ?? "text") === "text")
25
+ const raw = firstTextCol?.splitDelimiter
26
+ if (raw === NO_SPLIT_DELIMITER) {
27
+ const trimmed = text.trim()
28
+ return trimmed.length > 0 ? [trimmed] : []
29
+ }
30
+ const delimiter = raw ?? "\n"
31
+ return text.split(delimiter).map((s) => s.trim()).filter((s) => s.length > 0)
32
+ }
33
+
34
+ /**
35
+ * Split pasted (or manually-triggered) text into rows, inserting below
36
+ * the source row. Returns the new rows array and truncation metadata.
37
+ *
38
+ * Pure function — callers handle persisting the result and showing toasts.
39
+ */
40
+ export function spliceDelimitedRows(
41
+ rows: readonly (readonly string[])[],
42
+ rowIndex: number,
43
+ colIndex: number,
44
+ pastedText: string,
45
+ delimiter: string,
46
+ columnCount: number,
47
+ maxItems: number,
48
+ ): { newRows: string[][]; truncated: boolean; totalProduced: number } {
49
+ const parts = pastedText.split(delimiter).map((s) => s.trim()).filter((s) => s.length > 0)
50
+ if (parts.length <= 1) {
51
+ // Nothing to split — return rows unchanged with first part (or original) in cell
52
+ const newRows = rows.map((r) => [...r])
53
+ if (parts.length === 1) newRows[rowIndex][colIndex] = parts[0]
54
+ return { newRows, truncated: false, totalProduced: newRows.length }
55
+ }
56
+
57
+ const newRows = rows.map((r) => [...r])
58
+ newRows[rowIndex][colIndex] = parts[0]
59
+ const insertRows = parts.slice(1).map((part) => {
60
+ const r = Array.from<string>({ length: columnCount }).fill("")
61
+ r[colIndex] = part
62
+ return r
63
+ })
64
+ newRows.splice(rowIndex + 1, 0, ...insertRows)
65
+
66
+ const truncated = newRows.length > maxItems
67
+ const totalProduced = newRows.length
68
+ return {
69
+ newRows: truncated ? newRows.slice(0, maxItems) : newRows,
70
+ truncated,
71
+ totalProduced,
72
+ }
73
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Character LoRA routing decision + identifier constants.
3
+ *
4
+ * Shared between backend (orchestrator's payload-builder) and frontend
5
+ * (single-node Run's execute-node). MUST agree byte-for-byte — the backend
6
+ * stamps the credit identifier and worker payload off this decision, the
7
+ * frontend stamps the `_internalLora` body hint off it. Mismatches would
8
+ * silently degrade trained-character generations to ref injection.
9
+ */
10
+
11
+ /**
12
+ * Synthetic Replicate model id selected by the orchestrator (and the
13
+ * single-node Run pre-Zod swap) when a single trained `@character` mention
14
+ * is detected. Routes through `black-forest-labs/flux-dev-lora` with the
15
+ * character's trained version under `extraParams.lora_version`. Never
16
+ * appears in user-facing dropdowns.
17
+ */
18
+ export const FLUX_LORA_CHARACTER_MODEL_ID = "flux-lora-character" as const
19
+
20
+ /**
21
+ * `jobs.job_type` discriminator + credit identifier for character LoRA
22
+ * training jobs. Used for `STATIC_CREDIT_COSTS`/`model_pricing` lookup,
23
+ * `creditGuard` reservation, refund flow, and webhook job lookup.
24
+ */
25
+ export const CHARACTER_LORA_TRAINING_JOB_TYPE = "character-lora-training" as const
26
+
27
+ /**
28
+ * The three LoRA fields read off `CharacterNodeData` and stamped onto every
29
+ * `ConnectedReference` produced from a wired character. Shared between the
30
+ * backend's `expandWiredCharacterRefs` and the frontend's
31
+ * `expandCharacterNodeIntoRefs` so both sides emit the same three fields
32
+ * without copy-paste drift.
33
+ */
34
+ export interface CharacterLoraFields {
35
+ readonly loraReplicateVersion: string | null
36
+ readonly loraTriggerWord: string | null
37
+ readonly loraTrainingStatus: string | null
38
+ }
39
+
40
+ /**
41
+ * Extract the three LoRA fields from a character node's `data`, normalized
42
+ * to `null` for missing/undefined values so downstream type-checks (e.g.
43
+ * `selectLoraRoutingForMentions`'s `=== "succeeded"`) are deterministic.
44
+ */
45
+ export function extractCharacterLoraFields(charData: {
46
+ loraReplicateVersion?: string | null
47
+ loraTriggerWord?: string | null
48
+ loraTrainingStatus?: string | null
49
+ }): CharacterLoraFields {
50
+ return {
51
+ loraReplicateVersion: charData.loraReplicateVersion ?? null,
52
+ loraTriggerWord: charData.loraTriggerWord ?? null,
53
+ loraTrainingStatus: charData.loraTrainingStatus ?? null,
54
+ }
55
+ }
56
+
57
+ export interface LoraRouting {
58
+ readonly characterSlug: string
59
+ readonly triggerWord: string
60
+ readonly loraVersion: string
61
+ }
62
+
63
+ export interface LoraEligibleRef {
64
+ readonly characterSlug?: string
65
+ readonly loraReplicateVersion?: string | null
66
+ readonly loraTriggerWord?: string | null
67
+ readonly loraTrainingStatus?: string | null
68
+ }
69
+
70
+ /**
71
+ * Returns a LoraRouting iff EXACTLY ONE distinct character is mentioned AND
72
+ * that character has a successful LoRA. Returns null otherwise → caller
73
+ * falls back to ref injection. Multi-character LoRA composition is Phase 2.
74
+ */
75
+ export function selectLoraRoutingForMentions(
76
+ refs: readonly LoraEligibleRef[],
77
+ ): LoraRouting | null {
78
+ const distinct = new Set(refs.map((r) => r.characterSlug).filter(Boolean))
79
+ if (distinct.size !== 1) return null
80
+ const slug = [...distinct][0]!
81
+ const match = refs.find((r) => r.characterSlug === slug)
82
+ if (
83
+ !match ||
84
+ !match.loraReplicateVersion ||
85
+ !match.loraTriggerWord ||
86
+ match.loraTrainingStatus !== "succeeded"
87
+ ) {
88
+ return null
89
+ }
90
+ return {
91
+ characterSlug: slug,
92
+ triggerWord: match.loraTriggerWord,
93
+ loraVersion: match.loraReplicateVersion,
94
+ }
95
+ }