@adminide-stack/yantra-mobile 12.0.121 → 12.0.123-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/lib/features/apps/appArt.js +1 -1
  2. package/lib/features/apps/appArt.js.map +1 -1
  3. package/lib/features/apps/mobileAppCatalog.js +15 -11
  4. package/lib/features/apps/mobileAppCatalog.js.map +1 -1
  5. package/lib/features/canvas/CanvasAgentChatPane.js +82 -20
  6. package/lib/features/canvas/CanvasAgentChatPane.js.map +1 -1
  7. package/lib/features/canvas/CanvasBoardsGrid.js +291 -100
  8. package/lib/features/canvas/CanvasBoardsGrid.js.map +1 -1
  9. package/lib/features/canvas/CanvasEditToolsPanel.js +105 -12
  10. package/lib/features/canvas/CanvasEditToolsPanel.js.map +1 -1
  11. package/lib/features/canvas/CanvasExperience.js +266 -68
  12. package/lib/features/canvas/CanvasExperience.js.map +1 -1
  13. package/lib/features/canvas/CanvasGeneratePanel.js +204 -66
  14. package/lib/features/canvas/CanvasGeneratePanel.js.map +1 -1
  15. package/lib/features/canvas/CanvasLibrarySheet.js +31 -13
  16. package/lib/features/canvas/CanvasLibrarySheet.js.map +1 -1
  17. package/lib/features/canvas/CanvasModelPicker.js +176 -0
  18. package/lib/features/canvas/CanvasModelPicker.js.map +1 -0
  19. package/lib/features/canvas/CanvasTasksPanel.js +325 -29
  20. package/lib/features/canvas/CanvasTasksPanel.js.map +1 -1
  21. package/lib/features/canvas/CanvasTemplatesPanel.js +5 -4
  22. package/lib/features/canvas/CanvasTemplatesPanel.js.map +1 -1
  23. package/lib/features/canvas/CanvasToolDock.js +137 -61
  24. package/lib/features/canvas/CanvasToolDock.js.map +1 -1
  25. package/lib/features/canvas/FrameExtractorExperience.js +33 -2
  26. package/lib/features/canvas/FrameExtractorExperience.js.map +1 -1
  27. package/lib/features/canvas/GeneratorReferenceSlots.js +197 -0
  28. package/lib/features/canvas/GeneratorReferenceSlots.js.map +1 -0
  29. package/lib/features/canvas/NativeCanvasViewer.js +89 -11
  30. package/lib/features/canvas/NativeCanvasViewer.js.map +1 -1
  31. package/lib/features/canvas/PromoContextFields.js +55 -2
  32. package/lib/features/canvas/PromoContextFields.js.map +1 -1
  33. package/lib/features/canvas/SetStudioExperience.js +323 -13
  34. package/lib/features/canvas/SetStudioExperience.js.map +1 -1
  35. package/lib/features/canvas/VideoEditExperience.js +1 -53
  36. package/lib/features/canvas/VideoEditExperience.js.map +1 -1
  37. package/lib/features/canvas/VideoEditorExperience.js +697 -506
  38. package/lib/features/canvas/VideoEditorExperience.js.map +1 -1
  39. package/lib/features/canvas/VideoGeneratorExperience.js +22 -5
  40. package/lib/features/canvas/VideoGeneratorExperience.js.map +1 -1
  41. package/lib/features/canvas/canvasAgentChat.js +125 -11
  42. package/lib/features/canvas/canvasAgentChat.js.map +1 -1
  43. package/lib/features/canvas/canvasCore.js +117 -12
  44. package/lib/features/canvas/canvasCore.js.map +1 -1
  45. package/lib/features/canvas/canvasEditOps.js +148 -111
  46. package/lib/features/canvas/canvasEditOps.js.map +1 -1
  47. package/lib/features/canvas/canvasTaskSync.js +235 -0
  48. package/lib/features/canvas/canvasTaskSync.js.map +1 -0
  49. package/lib/features/canvas/canvasTasks.js +98 -11
  50. package/lib/features/canvas/canvasTasks.js.map +1 -1
  51. package/lib/features/canvas/createTiles.js +247 -0
  52. package/lib/features/canvas/createTiles.js.map +1 -0
  53. package/lib/features/canvas/deepLinks.js +83 -0
  54. package/lib/features/canvas/deepLinks.js.map +1 -0
  55. package/lib/features/canvas/frameExtract.js +13 -1
  56. package/lib/features/canvas/frameExtract.js.map +1 -1
  57. package/lib/features/canvas/generationModels.js +36 -8
  58. package/lib/features/canvas/generationModels.js.map +1 -1
  59. package/lib/features/canvas/generatorCommands.js +106 -0
  60. package/lib/features/canvas/generatorCommands.js.map +1 -0
  61. package/lib/features/canvas/generatorReferences.js +82 -0
  62. package/lib/features/canvas/generatorReferences.js.map +1 -0
  63. package/lib/features/canvas/homeWork.js +74 -0
  64. package/lib/features/canvas/homeWork.js.map +1 -0
  65. package/lib/features/canvas/linksRpc.js +130 -0
  66. package/lib/features/canvas/linksRpc.js.map +1 -0
  67. package/lib/features/canvas/mediaRecheck.js +176 -0
  68. package/lib/features/canvas/mediaRecheck.js.map +1 -0
  69. package/lib/features/canvas/mediaUrls.js +258 -0
  70. package/lib/features/canvas/mediaUrls.js.map +1 -0
  71. package/lib/features/canvas/nativeViewerRegistry.js.map +1 -1
  72. package/lib/features/canvas/promoProjectImport.js +80 -13
  73. package/lib/features/canvas/promoProjectImport.js.map +1 -1
  74. package/lib/features/canvas/promoVideo.js +106 -15
  75. package/lib/features/canvas/promoVideo.js.map +1 -1
  76. package/lib/features/canvas/reframe.js +228 -0
  77. package/lib/features/canvas/reframe.js.map +1 -0
  78. package/lib/features/canvas/serverTasks.js +697 -0
  79. package/lib/features/canvas/serverTasks.js.map +1 -0
  80. package/lib/features/canvas/set/SetViewportWebView.js +207 -28
  81. package/lib/features/canvas/set/SetViewportWebView.js.map +1 -1
  82. package/lib/features/canvas/set/agent/prompt.js +66 -0
  83. package/lib/features/canvas/set/agent/prompt.js.map +1 -0
  84. package/lib/features/canvas/set/agent/setOps.js +203 -0
  85. package/lib/features/canvas/set/agent/setOps.js.map +1 -0
  86. package/lib/features/canvas/set/agent/setTurn.js +128 -0
  87. package/lib/features/canvas/set/agent/setTurn.js.map +1 -0
  88. package/lib/features/canvas/set/agent/snapshot.js +43 -0
  89. package/lib/features/canvas/set/agent/snapshot.js.map +1 -0
  90. package/lib/features/canvas/set/agent/tools.js +580 -0
  91. package/lib/features/canvas/set/agent/tools.js.map +1 -0
  92. package/lib/features/canvas/set/setProject.js +43 -4
  93. package/lib/features/canvas/set/setProject.js.map +1 -1
  94. package/lib/features/canvas/set/supplyLibrary.js +397 -0
  95. package/lib/features/canvas/set/supplyLibrary.js.map +1 -0
  96. package/lib/features/canvas/storageLibrary.js +113 -52
  97. package/lib/features/canvas/storageLibrary.js.map +1 -1
  98. package/lib/features/canvas/studioCatalog.js +15 -2
  99. package/lib/features/canvas/studioCatalog.js.map +1 -1
  100. package/lib/features/canvas/studioLooks.js +1 -8
  101. package/lib/features/canvas/studioLooks.js.map +1 -1
  102. package/lib/features/canvas/useBoardMediaRefresh.js +66 -0
  103. package/lib/features/canvas/useBoardMediaRefresh.js.map +1 -0
  104. package/lib/features/canvas/useMediaSource.js +84 -0
  105. package/lib/features/canvas/useMediaSource.js.map +1 -0
  106. package/lib/features/canvas/video3d.js +11 -10
  107. package/lib/features/canvas/video3d.js.map +1 -1
  108. package/lib/features/canvas/videoEditor/BlurBoxOverlay.js +46 -0
  109. package/lib/features/canvas/videoEditor/BlurBoxOverlay.js.map +1 -0
  110. package/lib/features/canvas/videoEditor/ExportTaskCard.js +134 -0
  111. package/lib/features/canvas/videoEditor/ExportTaskCard.js.map +1 -0
  112. package/lib/features/canvas/videoEditor/agent/AgentCutPane.js +45 -7
  113. package/lib/features/canvas/videoEditor/agent/AgentCutPane.js.map +1 -1
  114. package/lib/features/canvas/videoEditor/agent/agentLoop.js +4 -2
  115. package/lib/features/canvas/videoEditor/agent/agentLoop.js.map +1 -1
  116. package/lib/features/canvas/videoEditor/agent/attachments.js +304 -0
  117. package/lib/features/canvas/videoEditor/agent/attachments.js.map +1 -0
  118. package/lib/features/canvas/videoEditor/agent/brainClient.js +3 -2
  119. package/lib/features/canvas/videoEditor/agent/brainClient.js.map +1 -1
  120. package/lib/features/canvas/videoEditor/agent/cutTools.js +207 -7
  121. package/lib/features/canvas/videoEditor/agent/cutTools.js.map +1 -1
  122. package/lib/features/canvas/videoEditor/blurBox.js +34 -0
  123. package/lib/features/canvas/videoEditor/blurBox.js.map +1 -0
  124. package/lib/features/canvas/videoEditor/compileTimeline.js +668 -0
  125. package/lib/features/canvas/videoEditor/compileTimeline.js.map +1 -0
  126. package/lib/features/canvas/videoEditor/editorModel.js +56 -22
  127. package/lib/features/canvas/videoEditor/editorModel.js.map +1 -1
  128. package/lib/features/canvas/videoEditor/exportPipeline.js +77 -0
  129. package/lib/features/canvas/videoEditor/exportPipeline.js.map +1 -0
  130. package/lib/features/canvas/videoEditor/exportRenderer.js +19 -12
  131. package/lib/features/canvas/videoEditor/exportRenderer.js.map +1 -1
  132. package/lib/features/canvas/videoEditor/exportTask.js +216 -0
  133. package/lib/features/canvas/videoEditor/exportTask.js.map +1 -0
  134. package/lib/features/canvas/videoEditor/formWidgets.js +142 -0
  135. package/lib/features/canvas/videoEditor/formWidgets.js.map +1 -0
  136. package/lib/features/canvas/videoEditor/produce/ProduceVideoSheet.js +195 -0
  137. package/lib/features/canvas/videoEditor/produce/ProduceVideoSheet.js.map +1 -0
  138. package/lib/features/canvas/videoEditor/produce/produceScenes.js +158 -0
  139. package/lib/features/canvas/videoEditor/produce/produceScenes.js.map +1 -0
  140. package/lib/features/canvas/videoEditor/remoteMediaClient.js +17 -5
  141. package/lib/features/canvas/videoEditor/remoteMediaClient.js.map +1 -1
  142. package/lib/features/canvas/videoEditor/renderTimeline.js +207 -0
  143. package/lib/features/canvas/videoEditor/renderTimeline.js.map +1 -0
  144. package/lib/features/canvas/videoEditor/renewLinks.js +64 -0
  145. package/lib/features/canvas/videoEditor/renewLinks.js.map +1 -0
  146. package/lib/features/canvas/videoEditor/sceneLayers.js +101 -0
  147. package/lib/features/canvas/videoEditor/sceneLayers.js.map +1 -0
  148. package/lib/features/canvas/videoEditor/tools/ToolsDrawer.js +283 -0
  149. package/lib/features/canvas/videoEditor/tools/ToolsDrawer.js.map +1 -0
  150. package/lib/features/canvas/videoEditor/tools/catalog.js +576 -0
  151. package/lib/features/canvas/videoEditor/tools/catalog.js.map +1 -0
  152. package/lib/features/canvas/videoEditor/videoProjectsStore.js +27 -3
  153. package/lib/features/canvas/videoEditor/videoProjectsStore.js.map +1 -1
  154. package/lib/features/webbuilder/WebBuilderExperience.js +29 -1
  155. package/lib/features/webbuilder/WebBuilderExperience.js.map +1 -1
  156. package/lib/features/webbuilder/buildFragments.js +8 -4
  157. package/lib/features/webbuilder/buildFragments.js.map +1 -1
  158. package/lib/features/webbuilder/codezenHandoff.js +108 -0
  159. package/lib/features/webbuilder/codezenHandoff.js.map +1 -0
  160. package/lib/features/webbuilder/workflow.js.map +1 -1
  161. package/lib/hooks/useChatApi.js +1 -2
  162. package/lib/hooks/useChatApi.js.map +1 -1
  163. package/lib/screens/CanvasBoard/index.js +12 -1
  164. package/lib/screens/CanvasBoard/index.js.map +1 -1
  165. package/lib/screens/Home/HomeScreen.js.map +1 -1
  166. package/lib/screens/Home/components/HomeSuggestions.js +3 -3
  167. package/lib/screens/Home/components/HomeSuggestions.js.map +1 -1
  168. package/lib/screens/WebBuilder/index.js +4 -2
  169. package/lib/screens/WebBuilder/index.js.map +1 -1
  170. package/lib/screens/WebBuilderNative/index.js +29 -2
  171. package/lib/screens/WebBuilderNative/index.js.map +1 -1
  172. package/lib/screens/WebBuilderNative/useWebBuilderHost.js +30 -6
  173. package/lib/screens/WebBuilderNative/useWebBuilderHost.js.map +1 -1
  174. package/package.json +4 -4
  175. /package/lib/assets/apps/{paper2poster.webp → poster.webp} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"exportRenderer.js","sources":["../../../../src/features/canvas/videoEditor/exportRenderer.ts"],"sourcesContent":["/**\n * REMOTE-SIDE export renderer - the connector chain that turns an editor\n * timeline into one rendered mp4, ported from the hosts' videoConnectorClient\n * so binaries without the onExportVideo seam still export OTA.\n *\n * Transport-agnostic on purpose: it drives a RunMediaAction (host seam or\n * remoteMediaClient fallback, the caller decides) and an optional uploader\n * for phone-local clip sources. Keep the op sequence in lockstep with the\n * hosts' renderExportSpec - clips (SLIDESHOW / TRIM / SPEED / MUTE / VOLUME /\n * COLOR_ADJUST) -> CONCAT -> voiceover ADD_AUDIO -> OVERLAY_TEXT titles.\n */\nimport type { VideoExportSpec } from './editorModel';\nimport { resultUrl, type RunMediaAction } from './mediaActions';\nimport { colorFromSolidSrc, solidColorPngDataUrl } from './solidColorPng';\n\nconst VIDEO = 'yantra-video-editing';\n\n/** Server-side grade per editor filter id - COLOR_ADJUST params. */\nconst FILTER_GRADE: Record<string, Record<string, number> | null> = {\n none: null,\n cinematic: { contrast: 1.12, saturation: 0.92, brightness: -0.04 },\n film: { saturation: 0.85, gamma: 1.05, brightness: 0.03 },\n kodak: { saturation: 1.15, gamma: 0.95, hue: 8 },\n mono: { saturation: 0, contrast: 1.08 },\n vivid: { contrast: 1.15, saturation: 1.35 },\n warm: { hue: -12, saturation: 1.08, brightness: 0.03 },\n cool: { hue: 12, saturation: 0.95 },\n dreamy: { blur: 4, brightness: 0.06, saturation: 1.1 },\n};\n\nexport interface RenderProgress {\n /** Human stage label, e.g. \"Trimming clip 2/3\". */\n stage: string;\n}\n\n/** Phone-local or inline URIs the agent cannot fetch. */\nfunction needsUpload(url: string): boolean {\n return /^(file|ph|assets-library|content|data):/i.test(url);\n}\n\n/** Blank scenes are 1×1 GIF data URLs — slideshow needs an even PNG instead. */\nfunction imageSrcForExport(clip: VideoExportSpec['clips'][number]): string {\n const fill = clip.fillColor || colorFromSolidSrc(clip.src);\n if (fill) return solidColorPngDataUrl(fill);\n return clip.src;\n}\n\n/**\n * Compose the editor timeline through connector ops. Returns the final\n * rendered video URL (presigned storage URL from the render service).\n */\nexport async function renderExportSpec(\n spec: VideoExportSpec,\n runAction: RunMediaAction,\n uploadMedia?: (localUri: string) => Promise<string>,\n onProgress?: (p: RenderProgress) => void,\n): Promise<string> {\n const run = async (action: string, params: Record<string, unknown>, label: string) =>\n resultUrl(await runAction(VIDEO, action, params), label);\n\n const clipUrls: string[] = [];\n for (let i = 0; i < spec.clips.length; i += 1) {\n const clip = spec.clips[i];\n const label = `clip ${i + 1}/${spec.clips.length}`;\n let url = clip.type === 'image' ? imageSrcForExport(clip) : clip.src;\n\n if (needsUpload(url)) {\n if (!uploadMedia) throw new Error(`${label} is on this phone and no uploader is available`);\n onProgress?.({ stage: `Uploading ${label}` });\n url = await uploadMedia(url);\n }\n\n if (clip.type === 'image') {\n onProgress?.({ stage: `Rendering still ${label}` });\n const sec = (clip.durationSec ?? 3) / clip.speed;\n if (clip.kenBurns) {\n url = await run(\n 'YANTRA_VIDEO_EDIT_KEN_BURNS',\n {\n input_url: url,\n duration_ms: Math.round(sec * 1000),\n fps: spec.fps,\n zoom_start: clip.kenBurns.zoomStart,\n zoom_end: clip.kenBurns.zoomEnd,\n direction: clip.kenBurns.direction,\n },\n 'KEN_BURNS',\n );\n } else {\n url = await run(\n 'YANTRA_VIDEO_EDIT_SLIDESHOW',\n { input_url: url, duration_per_image: sec, fps: spec.fps },\n 'SLIDESHOW',\n );\n }\n } else {\n let end = clip.trimEndSec;\n if (clip.trimStartSec > 0 && end === null) {\n onProgress?.({ stage: `Measuring ${label}` });\n const probe = await runAction(VIDEO, 'YANTRA_VIDEO_EDIT_PROBE', { input_url: url });\n const duration = Number(\n (probe.duration_secs as number | undefined) ??\n (probe.duration as number | undefined) ??\n ((probe.format as Record<string, unknown> | undefined)?.duration as number | undefined),\n );\n if (Number.isFinite(duration) && duration > 0) end = duration;\n }\n if (end !== null && (clip.trimStartSec > 0 || end > 0)) {\n onProgress?.({ stage: `Trimming ${label}` });\n url = await run(\n 'YANTRA_VIDEO_EDIT_TRIM',\n { input_url: url, start_secs: clip.trimStartSec, end_secs: end },\n 'TRIM',\n );\n }\n if (clip.speed !== 1) {\n onProgress?.({ stage: `Speed ${clip.speed}x ${label}` });\n url = await run('YANTRA_VIDEO_EDIT_SPEED', { input_url: url, factor: clip.speed }, 'SPEED');\n }\n if (clip.muted) {\n onProgress?.({ stage: `Muting ${label}` });\n url = await run('YANTRA_VIDEO_EDIT_MUTE', { input_url: url }, 'MUTE');\n } else if (clip.volume < 0.99) {\n onProgress?.({ stage: `Volume ${label}` });\n url = await run('YANTRA_VIDEO_EDIT_VOLUME', { input_url: url, level: clip.volume }, 'VOLUME');\n }\n }\n\n const grade = FILTER_GRADE[clip.filter] ?? null;\n if (grade) {\n onProgress?.({ stage: `Grading ${label}` });\n url = await run('YANTRA_VIDEO_EDIT_COLOR_ADJUST', { input_url: url, ...grade }, 'COLOR_ADJUST');\n }\n clipUrls.push(url);\n }\n\n if (clipUrls.length === 0) throw new Error('Nothing to render');\n let finalUrl = clipUrls[0];\n if (clipUrls.length > 1) {\n onProgress?.({ stage: `Joining ${clipUrls.length} clips` });\n finalUrl = await run(\n 'YANTRA_VIDEO_EDIT_CONCAT',\n { input_url: clipUrls[0], input_urls: clipUrls.slice(1), reencode: true },\n 'CONCAT',\n );\n }\n\n if (spec.soundtrack) {\n // Music bed first: replace-mode swaps the clips' own audio for the\n // track, and the voiceover then mixes ON TOP so narration always\n // survives whichever soundtrack mode is chosen.\n onProgress?.({ stage: 'Adding soundtrack' });\n finalUrl = await run(\n 'YANTRA_VIDEO_EDIT_ADD_AUDIO',\n {\n input_url: finalUrl,\n audio_input_url: spec.soundtrack.audioUrl,\n replace_existing: spec.soundtrack.mode === 'replace',\n },\n 'ADD_AUDIO',\n );\n }\n\n if (spec.voiceover) {\n // The generated narration muxes under the finished cut - after concat,\n // before titles, so text timings stay relative to the final video.\n onProgress?.({ stage: 'Adding voiceover' });\n finalUrl = await run(\n 'YANTRA_VIDEO_EDIT_ADD_AUDIO',\n {\n input_url: finalUrl,\n audio_input_url: spec.voiceover.audioUrl,\n // A replace-mode voiceover must not erase the soundtrack that\n // was muxed one step earlier - narration mixes over it.\n replace_existing: spec.voiceover.mode === 'replace' && !spec.soundtrack,\n },\n 'ADD_AUDIO',\n );\n }\n\n for (let i = 0; i < spec.texts.length; i += 1) {\n const t = spec.texts[i];\n onProgress?.({ stage: `Title ${i + 1}/${spec.texts.length}` });\n finalUrl = await run(\n 'YANTRA_VIDEO_EDIT_OVERLAY_TEXT',\n {\n input_url: finalUrl,\n text: t.text,\n // Normalized editor position -> ffmpeg expressions over the\n // actual frame size, anchored at the text centre.\n x: `(w-text_w)*${t.x.toFixed(3)}`,\n y: `(h-text_h)*${t.y.toFixed(3)}`,\n font_size: 36,\n font_color: 'white',\n start_secs: t.startSec,\n end_secs: t.startSec + t.durationSec,\n },\n 'OVERLAY_TEXT',\n );\n }\n\n return finalUrl;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"exportRenderer.js","sources":["../../../../src/features/canvas/videoEditor/exportRenderer.ts"],"sourcesContent":["/**\n * REMOTE-SIDE export renderer - the connector chain that turns an editor\n * timeline into one rendered mp4, ported from the hosts' videoConnectorClient\n * so binaries without the onExportVideo seam still export OTA.\n *\n * Transport-agnostic on purpose: it drives a RunMediaAction (host seam or\n * remoteMediaClient fallback, the caller decides) and an optional uploader\n * for phone-local clip sources. Keep the op sequence in lockstep with the\n * hosts' renderExportSpec - clips (SLIDESHOW / TRIM / SPEED / MUTE / VOLUME /\n * COLOR_ADJUST) -> CONCAT -> voiceover ADD_AUDIO -> OVERLAY_TEXT titles.\n */\nimport type { VideoExportSpec } from './editorModel';\nimport { resultUrl, type RunMediaAction } from './mediaActions';\nimport { colorFromSolidSrc, solidColorPngDataUrl } from './solidColorPng';\n\nconst VIDEO = 'yantra-video-editing';\n\n/** Server-side grade per editor filter id - COLOR_ADJUST params. */\nconst FILTER_GRADE: Record<string, Record<string, number> | null> = {\n none: null,\n cinematic: { contrast: 1.12, saturation: 0.92, brightness: -0.04 },\n film: { saturation: 0.85, gamma: 1.05, brightness: 0.03 },\n kodak: { saturation: 1.15, gamma: 0.95, hue: 8 },\n mono: { saturation: 0, contrast: 1.08 },\n vivid: { contrast: 1.15, saturation: 1.35 },\n warm: { hue: -12, saturation: 1.08, brightness: 0.03 },\n cool: { hue: 12, saturation: 0.95 },\n dreamy: { blur: 4, brightness: 0.06, saturation: 1.1 },\n};\n\nexport interface RenderProgress {\n /** Human stage label, e.g. \"Trimming clip 2/3\". */\n stage: string;\n}\n\n/** Phone-local or inline URIs the agent cannot fetch. */\nfunction needsUpload(url: string): boolean {\n return /^(file|ph|assets-library|content|data):/i.test(url);\n}\n\n/** Blank scenes are 1×1 GIF data URLs — slideshow needs an even PNG instead. */\nfunction imageSrcForExport(clip: VideoExportSpec['clips'][number]): string {\n const fill = clip.fillColor || colorFromSolidSrc(clip.src);\n if (fill) return solidColorPngDataUrl(fill);\n return clip.src;\n}\n\n/**\n * Compose the editor timeline through connector ops. Returns the final\n * rendered video URL (presigned storage URL from the render service).\n */\nexport async function renderExportSpec(\n spec: VideoExportSpec,\n runAction: RunMediaAction,\n uploadMedia?: (localUri: string) => Promise<string>,\n onProgress?: (p: RenderProgress) => void,\n): Promise<string> {\n // Every step but the one producing the finished video is an intermediate:\n // `ephemeral` stores it under tmp/, out of the user's media library (web\n // runExport). Which stage is last is known up front from the spec.\n const tail: 'clip' | 'concat' | 'soundtrack' | 'voiceover' | 'text' = spec.texts.length\n ? 'text'\n : spec.voiceover\n ? 'voiceover'\n : spec.soundtrack\n ? 'soundtrack'\n : spec.clips.length > 1\n ? 'concat'\n : 'clip';\n const run = async (action: string, params: Record<string, unknown>, label: string, final = false) =>\n resultUrl(await runAction(VIDEO, action, final ? params : { ...params, ephemeral: true }), label);\n // A lone clip's own ops ARE the finished video; which of them runs last\n // depends on the clip, so none of them is marked.\n const clipFinal = tail === 'clip';\n\n const clipUrls: string[] = [];\n for (let i = 0; i < spec.clips.length; i += 1) {\n const clip = spec.clips[i];\n const label = `clip ${i + 1}/${spec.clips.length}`;\n let url = clip.type === 'image' ? imageSrcForExport(clip) : clip.src;\n\n if (needsUpload(url)) {\n if (!uploadMedia) throw new Error(`${label} is on this phone and no uploader is available`);\n onProgress?.({ stage: `Uploading ${label}` });\n url = await uploadMedia(url);\n }\n\n if (clip.type === 'image') {\n onProgress?.({ stage: `Rendering still ${label}` });\n const sec = (clip.durationSec ?? 3) / clip.speed;\n if (clip.kenBurns) {\n url = await run(\n 'YANTRA_VIDEO_EDIT_KEN_BURNS',\n {\n input_url: url,\n duration_ms: Math.round(sec * 1000),\n fps: spec.fps,\n zoom_start: clip.kenBurns.zoomStart,\n zoom_end: clip.kenBurns.zoomEnd,\n direction: clip.kenBurns.direction,\n },\n 'KEN_BURNS',\n clipFinal,\n );\n } else {\n url = await run(\n 'YANTRA_VIDEO_EDIT_SLIDESHOW',\n { input_url: url, duration_per_image: sec, fps: spec.fps },\n 'SLIDESHOW',\n clipFinal,\n );\n }\n } else {\n let end = clip.trimEndSec;\n if (clip.trimStartSec > 0 && end === null) {\n onProgress?.({ stage: `Measuring ${label}` });\n const probe = await runAction(VIDEO, 'YANTRA_VIDEO_EDIT_PROBE', { input_url: url });\n const duration = Number(\n (probe.duration_secs as number | undefined) ??\n (probe.duration as number | undefined) ??\n ((probe.format as Record<string, unknown> | undefined)?.duration as number | undefined),\n );\n if (Number.isFinite(duration) && duration > 0) end = duration;\n }\n if (end !== null && (clip.trimStartSec > 0 || end > 0)) {\n onProgress?.({ stage: `Trimming ${label}` });\n url = await run(\n 'YANTRA_VIDEO_EDIT_TRIM',\n { input_url: url, start_secs: clip.trimStartSec, end_secs: end },\n 'TRIM',\n clipFinal,\n );\n }\n if (clip.speed !== 1) {\n onProgress?.({ stage: `Speed ${clip.speed}x ${label}` });\n url = await run('YANTRA_VIDEO_EDIT_SPEED', { input_url: url, factor: clip.speed }, 'SPEED', clipFinal);\n }\n if (clip.muted) {\n onProgress?.({ stage: `Muting ${label}` });\n url = await run('YANTRA_VIDEO_EDIT_MUTE', { input_url: url }, 'MUTE', clipFinal);\n } else if (clip.volume < 0.99) {\n onProgress?.({ stage: `Volume ${label}` });\n url = await run(\n 'YANTRA_VIDEO_EDIT_VOLUME',\n { input_url: url, level: clip.volume },\n 'VOLUME',\n clipFinal,\n );\n }\n }\n\n const grade = FILTER_GRADE[clip.filter] ?? null;\n if (grade) {\n onProgress?.({ stage: `Grading ${label}` });\n url = await run('YANTRA_VIDEO_EDIT_COLOR_ADJUST', { input_url: url, ...grade }, 'COLOR_ADJUST', clipFinal);\n }\n clipUrls.push(url);\n }\n\n if (clipUrls.length === 0) throw new Error('Nothing to render');\n let finalUrl = clipUrls[0];\n if (clipUrls.length > 1) {\n onProgress?.({ stage: `Joining ${clipUrls.length} clips` });\n finalUrl = await run(\n 'YANTRA_VIDEO_EDIT_CONCAT',\n { input_url: clipUrls[0], input_urls: clipUrls.slice(1), reencode: true },\n 'CONCAT',\n tail === 'concat',\n );\n }\n\n if (spec.soundtrack) {\n // Music bed first: replace-mode swaps the clips' own audio for the\n // track, and the voiceover then mixes ON TOP so narration always\n // survives whichever soundtrack mode is chosen.\n onProgress?.({ stage: 'Adding soundtrack' });\n finalUrl = await run(\n 'YANTRA_VIDEO_EDIT_ADD_AUDIO',\n {\n input_url: finalUrl,\n audio_input_url: spec.soundtrack.audioUrl,\n replace_existing: spec.soundtrack.mode === 'replace',\n },\n 'ADD_AUDIO',\n tail === 'soundtrack',\n );\n }\n\n if (spec.voiceover) {\n // The generated narration muxes under the finished cut - after concat,\n // before titles, so text timings stay relative to the final video.\n onProgress?.({ stage: 'Adding voiceover' });\n finalUrl = await run(\n 'YANTRA_VIDEO_EDIT_ADD_AUDIO',\n {\n input_url: finalUrl,\n audio_input_url: spec.voiceover.audioUrl,\n // A replace-mode voiceover must not erase the soundtrack that\n // was muxed one step earlier - narration mixes over it.\n replace_existing: spec.voiceover.mode === 'replace' && !spec.soundtrack,\n },\n 'ADD_AUDIO',\n tail === 'voiceover',\n );\n }\n\n for (let i = 0; i < spec.texts.length; i += 1) {\n const t = spec.texts[i];\n onProgress?.({ stage: `Title ${i + 1}/${spec.texts.length}` });\n finalUrl = await run(\n 'YANTRA_VIDEO_EDIT_OVERLAY_TEXT',\n {\n input_url: finalUrl,\n text: t.text,\n // Normalized editor position -> ffmpeg expressions over the\n // actual frame size, anchored at the text centre.\n x: `(w-text_w)*${t.x.toFixed(3)}`,\n y: `(h-text_h)*${t.y.toFixed(3)}`,\n font_size: 36,\n font_color: 'white',\n start_secs: t.startSec,\n end_secs: t.startSec + t.durationSec,\n },\n 'OVERLAY_TEXT',\n i === spec.texts.length - 1,\n );\n }\n\n return finalUrl;\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,216 @@
1
+ import {hydrateCanvasTasks,addCanvasTask,patchCanvasTask,getCanvasTask,listCanvasTasks,isTerminal}from'../canvasTasks.js';import {ensureFetchableMediaUrl}from'../mediaUrls.js';import {prepareRenderTimeline}from'./exportPipeline.js';import {renderExportSpec}from'./exportRenderer.js';import {submitRenderTimeline,renderDeadline,RENDER_POLL_EVERY_MS,pollRenderTimeline,MAX_POLL_ERRORS}from'./renderTimeline.js';var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ const defaultDeps = {
21
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
22
+ now: () => Date.now(),
23
+ renderLocally: renderExportSpec
24
+ };
25
+ let deps = defaultDeps;
26
+ const pollers = /* @__PURE__ */ new Map();
27
+ const working = /* @__PURE__ */ new Set();
28
+ let seq = 0;
29
+ const newId = () => `export-${Date.now().toString(36)}-${(seq++).toString(36)}`;
30
+ const stepLine = (poll2) => poll2.step ? `Step ${poll2.step.index} of ${poll2.step.total} \xB7 ${poll2.step.label}` : poll2.label || "Rendering\u2026";
31
+ const errorText = (err, fallback) => (err instanceof Error ? err.message : typeof err === "string" ? err : "") || fallback;
32
+ const settle = (id, patch) => patchCanvasTask(id, __spreadProps(__spreadValues({}, patch), {
33
+ endedAt: deps.now()
34
+ }));
35
+ function exportResult(url, task) {
36
+ var _a, _b, _c;
37
+ return {
38
+ url,
39
+ title: (task == null ? void 0 : task.brief) || "Video export",
40
+ projectId: (_c = (_b = (_a = task == null ? void 0 : task.render) == null ? void 0 : _a.runId) != null ? _b : task == null ? void 0 : task.id) != null ? _c : "",
41
+ preset: "export",
42
+ pipeline: (task == null ? void 0 : task.local) ? "client-chain" : "render-timeline"
43
+ };
44
+ }
45
+ async function startExportTask(run, input) {
46
+ await hydrateCanvasTasks();
47
+ const id = newId();
48
+ addCanvasTask({
49
+ id,
50
+ kind: "export",
51
+ title: "Video export",
52
+ brief: input.brief,
53
+ boardId: input.boardId,
54
+ state: "submitting",
55
+ createdAt: deps.now(),
56
+ request: {
57
+ prompt: input.brief,
58
+ preset: "export",
59
+ durationSeconds: 0,
60
+ aspectRatio: ""
61
+ },
62
+ lastLine: "Starting the render\u2026"
63
+ });
64
+ working.add(id);
65
+ void runExport(run, id, input).finally(() => working.delete(id));
66
+ return id;
67
+ }
68
+ async function runExport(run, id, input) {
69
+ const line = (lastLine) => {
70
+ var _a;
71
+ if (((_a = getCanvasTask(id)) == null ? void 0 : _a.state) === "submitting") patchCanvasTask(id, {
72
+ lastLine
73
+ });
74
+ };
75
+ let handle;
76
+ try {
77
+ const compiled = await prepareRenderTimeline(input.spec, run, {
78
+ upload: input.upload,
79
+ refresh: (url) => ensureFetchableMediaUrl(run, url),
80
+ onProgress: line
81
+ });
82
+ if (compiled.warnings.length) patchCanvasTask(id, {
83
+ warnings: compiled.warnings
84
+ });
85
+ if (compiled.steps.length === 0 && compiled.finalRef.kind === "url") {
86
+ settle(id, {
87
+ state: "succeeded",
88
+ result: exportResult(compiled.finalRef.url, getCanvasTask(id)),
89
+ lastLine: "Ready"
90
+ });
91
+ return;
92
+ }
93
+ line("Starting the render\u2026");
94
+ try {
95
+ handle = await submitRenderTimeline(run, compiled);
96
+ } catch (err) {
97
+ if (!getCanvasTask(id)) return;
98
+ await renderLocally(run, id, input, err);
99
+ return;
100
+ }
101
+ } catch (err) {
102
+ settle(id, {
103
+ state: "failed",
104
+ error: errorText(err, "Could not start the render"),
105
+ lastLine: "Failed"
106
+ });
107
+ return;
108
+ }
109
+ if (!getCanvasTask(id)) return;
110
+ patchCanvasTask(id, __spreadValues({
111
+ state: "running",
112
+ render: handle,
113
+ startedAt: deps.now(),
114
+ lastLine: "Rendering\u2026"
115
+ }, handle.notice ? {
116
+ notice: handle.notice
117
+ } : {}));
118
+ follow(run, id);
119
+ }
120
+ async function renderLocally(run, id, input, why) {
121
+ patchCanvasTask(id, {
122
+ state: "running",
123
+ local: true,
124
+ startedAt: deps.now(),
125
+ lastLine: "Rendering on this device\u2026"
126
+ });
127
+ try {
128
+ const url = await deps.renderLocally(input.spec, run, input.upload, (p) => patchCanvasTask(id, {
129
+ lastLine: p.stage
130
+ }));
131
+ settle(id, {
132
+ state: "succeeded",
133
+ result: exportResult(url, getCanvasTask(id)),
134
+ lastLine: "Ready"
135
+ });
136
+ } catch (err) {
137
+ const submitError = errorText(why, "");
138
+ settle(id, {
139
+ state: "failed",
140
+ error: errorText(err, "The render failed") + (submitError ? ` (render service: ${submitError})` : ""),
141
+ lastLine: "Failed"
142
+ });
143
+ }
144
+ }
145
+ function follow(run, id) {
146
+ if (pollers.has(id)) return;
147
+ const job = poll(run, id).finally(() => pollers.delete(id));
148
+ pollers.set(id, job);
149
+ }
150
+ async function poll(run, id) {
151
+ var _a;
152
+ const start = getCanvasTask(id);
153
+ if (!(start == null ? void 0 : start.render) || start.state !== "running") return;
154
+ const handle = start.render;
155
+ const deadlineAt = renderDeadline((_a = start.startedAt) != null ? _a : start.createdAt, handle);
156
+ let errors = 0;
157
+ while (deps.now() < deadlineAt) {
158
+ await deps.sleep(RENDER_POLL_EVERY_MS);
159
+ const current = getCanvasTask(id);
160
+ if ((current == null ? void 0 : current.state) !== "running") return;
161
+ let answer;
162
+ try {
163
+ answer = await pollRenderTimeline(run, handle);
164
+ errors = 0;
165
+ } catch (err) {
166
+ if (++errors < MAX_POLL_ERRORS) continue;
167
+ settle(id, {
168
+ state: "failed",
169
+ error: errorText(err, "Lost track of the render"),
170
+ lastLine: "Failed"
171
+ });
172
+ return;
173
+ }
174
+ if (answer.state === "running") {
175
+ patchCanvasTask(id, __spreadProps(__spreadValues({}, answer.step ? {
176
+ step: answer.step
177
+ } : {}), {
178
+ lastLine: stepLine(answer)
179
+ }));
180
+ continue;
181
+ }
182
+ if (answer.state === "failed") {
183
+ settle(id, {
184
+ state: "failed",
185
+ error: answer.error || "The render failed",
186
+ lastLine: "Failed"
187
+ });
188
+ return;
189
+ }
190
+ settle(id, {
191
+ state: "succeeded",
192
+ result: exportResult(answer.url || handle.outputUrl, current),
193
+ lastLine: "Ready"
194
+ });
195
+ return;
196
+ }
197
+ settle(id, {
198
+ state: "failed",
199
+ error: "The render is taking longer than expected - check back shortly.",
200
+ lastLine: "Timed out"
201
+ });
202
+ }
203
+ function resumeExportTasks(run) {
204
+ for (const task of listCanvasTasks()) {
205
+ if (task.kind !== "export" || isTerminal(task.state) || pollers.has(task.id) || working.has(task.id)) continue;
206
+ if (task.state === "running" && task.render && !task.local) {
207
+ follow(run, task.id);
208
+ } else {
209
+ settle(task.id, {
210
+ state: "failed",
211
+ error: "The app closed before the render finished starting - export again.",
212
+ lastLine: "Interrupted"
213
+ });
214
+ }
215
+ }
216
+ }export{resumeExportTasks,startExportTask};//# sourceMappingURL=exportTask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exportTask.js","sources":["../../../../src/features/canvas/videoEditor/exportTask.ts"],"sourcesContent":["/**\n * Durable video-editor export - native twin of web tasks/exportTask.ts.\n *\n * The editor's spec is prepared + compiled (exportPipeline), handed to the\n * connector's detached render (RENDER_TIMELINE_SUBMIT), and polled from\n * module scope as a canvasTasks entry of kind 'export' - so the editor can\n * close, the board can change and a relaunch picks the render back up from\n * the stored handle (canvasTasks.resumePromoTasks -> resumeExportTasks).\n *\n * When SUBMIT is rejected or unavailable (an older connector), the in-app\n * client chain (exportRenderer.renderExportSpec) renders it instead - not\n * durable, but it still exports.\n */\nimport {\n addCanvasTask,\n getCanvasTask,\n hydrateCanvasTasks,\n isTerminal,\n listCanvasTasks,\n patchCanvasTask,\n type CanvasTask,\n} from '../canvasTasks';\nimport type { PromoRunResult } from '../promoVideo';\nimport { ensureFetchableMediaUrl } from '../mediaUrls';\nimport type { VideoExportSpec } from './editorModel';\nimport { prepareRenderTimeline } from './exportPipeline';\nimport { renderExportSpec } from './exportRenderer';\nimport type { RunMediaAction } from './mediaActions';\nimport {\n MAX_POLL_ERRORS,\n RENDER_POLL_EVERY_MS,\n pollRenderTimeline,\n renderDeadline,\n submitRenderTimeline,\n type RenderHandle,\n type RenderPoll,\n} from './renderTimeline';\n\nexport interface ExportTaskDeps {\n sleep: (ms: number) => Promise<void>;\n now: () => number;\n /** The client-chain fallback, replaceable in tests. */\n renderLocally: typeof renderExportSpec;\n}\n\nconst defaultDeps: ExportTaskDeps = {\n sleep: (ms) => new Promise((r) => setTimeout(r, ms)),\n now: () => Date.now(),\n renderLocally: renderExportSpec,\n};\nlet deps = defaultDeps;\n\n/** Test seam: fake clock/sleep/fallback; null restores the defaults. */\nexport function configureExportTaskDeps(next: Partial<ExportTaskDeps> | null): void {\n deps = next ? { ...defaultDeps, ...next } : defaultDeps;\n pollers.clear();\n working.clear();\n}\n\nexport interface StartExportTaskInput {\n spec: VideoExportSpec;\n boardId: string;\n /** The project's title - what the card shows. */\n brief: string;\n /** Host uploader for phone-local clips. */\n upload?: (localUri: string) => Promise<string>;\n}\n\n/** Renders this process is following (never doubled up by a resume). */\nconst pollers = new Map<string, Promise<void>>();\n/** Exports this process is still preparing/submitting or rendering locally. */\nconst working = new Set<string>();\n\nlet seq = 0;\nconst newId = () => `export-${Date.now().toString(36)}-${(seq++).toString(36)}`;\n\nconst stepLine = (poll: RenderPoll): string =>\n poll.step ? `Step ${poll.step.index} of ${poll.step.total} · ${poll.step.label}` : poll.label || 'Rendering…';\n\nconst errorText = (err: unknown, fallback: string): string =>\n (err instanceof Error ? err.message : typeof err === 'string' ? err : '') || fallback;\n\nconst settle = (id: string, patch: Partial<CanvasTask>) => patchCanvasTask(id, { ...patch, endedAt: deps.now() });\n\nfunction exportResult(url: string, task: CanvasTask | undefined): PromoRunResult {\n return {\n url,\n title: task?.brief || 'Video export',\n projectId: task?.render?.runId ?? task?.id ?? '',\n preset: 'export',\n pipeline: task?.local ? 'client-chain' : 'render-timeline',\n };\n}\n\n/**\n * Register an export task and start it. Resolves with the task id as soon as\n * it is registered; preparation, the SUBMIT and the poll carry on by\n * themselves (watch it with subscribeCanvasTasks / getCanvasTask).\n */\nexport async function startExportTask(run: RunMediaAction, input: StartExportTaskInput): Promise<string> {\n await hydrateCanvasTasks();\n const id = newId();\n addCanvasTask({\n id,\n kind: 'export',\n title: 'Video export',\n brief: input.brief,\n boardId: input.boardId,\n state: 'submitting',\n createdAt: deps.now(),\n request: { prompt: input.brief, preset: 'export', durationSeconds: 0, aspectRatio: '' },\n lastLine: 'Starting the render…',\n });\n working.add(id);\n void runExport(run, id, input).finally(() => working.delete(id));\n return id;\n}\n\nasync function runExport(run: RunMediaAction, id: string, input: StartExportTaskInput): Promise<void> {\n const line = (lastLine: string) => {\n if (getCanvasTask(id)?.state === 'submitting') patchCanvasTask(id, { lastLine });\n };\n let handle: RenderHandle;\n try {\n const compiled = await prepareRenderTimeline(input.spec, run, {\n upload: input.upload,\n refresh: (url) => ensureFetchableMediaUrl(run, url),\n onProgress: line,\n });\n if (compiled.warnings.length) patchCanvasTask(id, { warnings: compiled.warnings });\n // One untouched clip compiles to no steps: that clip is the export.\n if (compiled.steps.length === 0 && compiled.finalRef.kind === 'url') {\n settle(id, {\n state: 'succeeded',\n result: exportResult(compiled.finalRef.url, getCanvasTask(id)),\n lastLine: 'Ready',\n });\n return;\n }\n line('Starting the render…');\n try {\n handle = await submitRenderTimeline(run, compiled);\n } catch (err) {\n if (!getCanvasTask(id)) return;\n await renderLocally(run, id, input, err);\n return;\n }\n } catch (err) {\n settle(id, { state: 'failed', error: errorText(err, 'Could not start the render'), lastLine: 'Failed' });\n return;\n }\n if (!getCanvasTask(id)) return; // dismissed during the submit\n patchCanvasTask(id, {\n state: 'running',\n render: handle,\n startedAt: deps.now(),\n lastLine: 'Rendering…',\n ...(handle.notice ? { notice: handle.notice } : {}),\n });\n follow(run, id);\n}\n\n/** SUBMIT unavailable: the pre-durable client chain, in-process. */\nasync function renderLocally(run: RunMediaAction, id: string, input: StartExportTaskInput, why: unknown) {\n patchCanvasTask(id, {\n state: 'running',\n local: true,\n startedAt: deps.now(),\n lastLine: 'Rendering on this device…',\n });\n try {\n const url = await deps.renderLocally(input.spec, run, input.upload, (p) =>\n patchCanvasTask(id, { lastLine: p.stage }),\n );\n settle(id, { state: 'succeeded', result: exportResult(url, getCanvasTask(id)), lastLine: 'Ready' });\n } catch (err) {\n const submitError = errorText(why, '');\n settle(id, {\n state: 'failed',\n error: errorText(err, 'The render failed') + (submitError ? ` (render service: ${submitError})` : ''),\n lastLine: 'Failed',\n });\n }\n}\n\nfunction follow(run: RunMediaAction, id: string) {\n if (pollers.has(id)) return;\n const job = poll(run, id).finally(() => pollers.delete(id));\n pollers.set(id, job);\n}\n\n/** Keep polling one running render until it settles. The deadline is the RUN's: a relaunch never extends it. */\nasync function poll(run: RunMediaAction, id: string): Promise<void> {\n const start = getCanvasTask(id);\n if (!start?.render || start.state !== 'running') return;\n const handle = start.render;\n const deadlineAt = renderDeadline(start.startedAt ?? start.createdAt, handle);\n let errors = 0;\n while (deps.now() < deadlineAt) {\n await deps.sleep(RENDER_POLL_EVERY_MS);\n const current = getCanvasTask(id);\n if (current?.state !== 'running') return; // settled elsewhere or dismissed\n let answer: RenderPoll;\n try {\n answer = await pollRenderTimeline(run, handle);\n errors = 0;\n } catch (err) {\n if (++errors < MAX_POLL_ERRORS) continue;\n settle(id, { state: 'failed', error: errorText(err, 'Lost track of the render'), lastLine: 'Failed' });\n return;\n }\n if (answer.state === 'running') {\n patchCanvasTask(id, { ...(answer.step ? { step: answer.step } : {}), lastLine: stepLine(answer) });\n continue;\n }\n if (answer.state === 'failed') {\n settle(id, { state: 'failed', error: answer.error || 'The render failed', lastLine: 'Failed' });\n return;\n }\n settle(id, {\n state: 'succeeded',\n result: exportResult(answer.url || handle.outputUrl, current),\n lastLine: 'Ready',\n });\n return;\n }\n settle(id, {\n state: 'failed',\n error: 'The render is taking longer than expected - check back shortly.',\n lastLine: 'Timed out',\n });\n}\n\n/**\n * Pick up every export this app started and has not settled (call on app\n * open; canvasTasks.resumePromoTasks does). One caught mid-submit, or\n * rendering through the in-app chain, by an app close lost its work - it\n * fails with a reason instead of spinning forever.\n */\nexport function resumeExportTasks(run: RunMediaAction): void {\n for (const task of listCanvasTasks()) {\n if (task.kind !== 'export' || isTerminal(task.state) || pollers.has(task.id) || working.has(task.id)) continue;\n if (task.state === 'running' && task.render && !task.local) {\n follow(run, task.id);\n } else {\n settle(task.id, {\n state: 'failed',\n error: 'The app closed before the render finished starting - export again.',\n lastLine: 'Interrupted',\n });\n }\n }\n}\n\n/** Whether this process is following / working on an export right now. */\nexport const isExportActive = (id: string): boolean => pollers.has(id) || working.has(id);\n"],"names":["poll"],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ import {jsxs,jsx}from'react/jsx-runtime';import {StyleSheet,View,Text,Pressable,TextInput,ScrollView}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';function Field({
2
+ label,
3
+ value,
4
+ onChange,
5
+ multiline,
6
+ keyboardType
7
+ }) {
8
+ return /* @__PURE__ */ jsxs(View, { style: formStyles.field, children: [
9
+ /* @__PURE__ */ jsx(Text, { style: formStyles.fieldLabel, children: label }),
10
+ /* @__PURE__ */ jsx(TextInput, { value, onChangeText: onChange, style: [formStyles.fieldInput, multiline && formStyles.fieldMulti], placeholderTextColor: "#5A5A66", autoCapitalize: "none", autoCorrect: false, multiline, keyboardType })
11
+ ] });
12
+ }
13
+ function Stepper({
14
+ label,
15
+ value,
16
+ onLess,
17
+ onMore
18
+ }) {
19
+ return /* @__PURE__ */ jsxs(View, { style: formStyles.stepper, children: [
20
+ /* @__PURE__ */ jsx(Text, { style: formStyles.stepperLabel, children: label }),
21
+ /* @__PURE__ */ jsx(Pressable, { onPress: onLess, hitSlop: 8, accessibilityRole: "button", accessibilityLabel: `${label} less`, children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "minus", size: 15, color: "#F7F7FA" }) }),
22
+ /* @__PURE__ */ jsx(Text, { style: formStyles.stepperValue, children: value }),
23
+ /* @__PURE__ */ jsx(Pressable, { onPress: onMore, hitSlop: 8, accessibilityRole: "button", accessibilityLabel: `${label} more`, children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "plus", size: 15, color: "#F7F7FA" }) })
24
+ ] });
25
+ }
26
+ function ChoiceRow({
27
+ label,
28
+ options,
29
+ value,
30
+ onChange
31
+ }) {
32
+ return /* @__PURE__ */ jsxs(View, { children: [
33
+ /* @__PURE__ */ jsx(Text, { style: formStyles.fieldLabel, children: label }),
34
+ /* @__PURE__ */ jsx(View, { style: formStyles.row, children: options.map((o) => {
35
+ const on = o.value === value;
36
+ return /* @__PURE__ */ jsx(Pressable, { onPress: () => onChange(o.value), style: [formStyles.choice, on && formStyles.choiceOn], accessibilityRole: "button", accessibilityState: {
37
+ selected: on
38
+ }, children: /* @__PURE__ */ jsx(Text, { style: [formStyles.choiceLabel, on && formStyles.choiceLabelOn], numberOfLines: 1, children: o.label }) }, o.value);
39
+ }) })
40
+ ] });
41
+ }
42
+ function PickRow({
43
+ label,
44
+ items,
45
+ selected,
46
+ onSelect,
47
+ empty
48
+ }) {
49
+ if (items.length === 0) return /* @__PURE__ */ jsx(Text, { style: formStyles.hint, children: empty });
50
+ return /* @__PURE__ */ jsxs(View, { children: [
51
+ /* @__PURE__ */ jsx(Text, { style: formStyles.fieldLabel, children: label }),
52
+ /* @__PURE__ */ jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: formStyles.row, children: items.map((item) => {
53
+ const on = item.src === selected;
54
+ return /* @__PURE__ */ jsx(Pressable, { onPress: () => onSelect(item.src), style: [formStyles.choice, on && formStyles.choiceOn], children: /* @__PURE__ */ jsx(Text, { style: [formStyles.choiceLabel, on && formStyles.choiceLabelOn], numberOfLines: 1, children: item.generatedAssetName || item.type }) }, item.id);
55
+ }) })
56
+ ] });
57
+ }
58
+ function PickMulti({
59
+ items,
60
+ selected,
61
+ onChange,
62
+ empty
63
+ }) {
64
+ if (items.length === 0) return /* @__PURE__ */ jsx(Text, { style: formStyles.hint, children: empty });
65
+ return /* @__PURE__ */ jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: formStyles.row, children: items.map((item) => {
66
+ const on = selected.includes(item.src);
67
+ return /* @__PURE__ */ jsx(Pressable, { onPress: () => onChange(on ? selected.filter((u) => u !== item.src) : [...selected, item.src]), style: [formStyles.choice, on && formStyles.choiceOn], children: /* @__PURE__ */ jsx(Text, { style: [formStyles.choiceLabel, on && formStyles.choiceLabelOn], numberOfLines: 1, children: item.generatedAssetName || item.type }) }, item.id);
68
+ }) });
69
+ }
70
+ const formStyles = StyleSheet.create({
71
+ field: {
72
+ minWidth: 88,
73
+ flexGrow: 1
74
+ },
75
+ fieldLabel: {
76
+ color: "#9A9AA5",
77
+ fontSize: 11,
78
+ marginBottom: 4
79
+ },
80
+ fieldInput: {
81
+ color: "#F7F7FA",
82
+ fontSize: 13,
83
+ paddingHorizontal: 10,
84
+ paddingVertical: 8,
85
+ borderRadius: 9,
86
+ backgroundColor: "#1F1F24"
87
+ },
88
+ fieldMulti: {
89
+ minHeight: 56,
90
+ textAlignVertical: "top"
91
+ },
92
+ stepper: {
93
+ flexDirection: "row",
94
+ alignItems: "center",
95
+ gap: 9,
96
+ paddingHorizontal: 12,
97
+ paddingVertical: 8,
98
+ borderRadius: 9,
99
+ backgroundColor: "#1F1F24"
100
+ },
101
+ stepperLabel: {
102
+ color: "#9A9AA5",
103
+ fontSize: 11.5
104
+ },
105
+ stepperValue: {
106
+ color: "#F7F7FA",
107
+ fontSize: 12.5,
108
+ fontVariant: ["tabular-nums"],
109
+ minWidth: 44,
110
+ textAlign: "center"
111
+ },
112
+ hint: {
113
+ color: "#9A9AA5",
114
+ fontSize: 13,
115
+ lineHeight: 18
116
+ },
117
+ row: {
118
+ flexDirection: "row",
119
+ alignItems: "center",
120
+ gap: 8,
121
+ flexWrap: "wrap",
122
+ paddingVertical: 4
123
+ },
124
+ choice: {
125
+ paddingHorizontal: 12,
126
+ paddingVertical: 8,
127
+ borderRadius: 9,
128
+ backgroundColor: "#1F1F24",
129
+ maxWidth: 160
130
+ },
131
+ choiceOn: {
132
+ backgroundColor: "#8B7CFF"
133
+ },
134
+ choiceLabel: {
135
+ color: "#F7F7FA",
136
+ fontSize: 12.5,
137
+ fontWeight: "500"
138
+ },
139
+ choiceLabelOn: {
140
+ color: "#0A0A0C"
141
+ }
142
+ });export{ChoiceRow,Field,PickMulti,PickRow,Stepper,formStyles};//# sourceMappingURL=formWidgets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formWidgets.js","sources":["../../../../src/features/canvas/videoEditor/formWidgets.tsx"],"sourcesContent":["/**\n * Small form widgets shared by the Edit Video sheet (VideoEditExperience) and\n * the editor's Tools drawer: a text field, a +/- stepper and media pickers.\n */\nimport React from 'react';\nimport { Pressable, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport type { CanvasItem } from '../canvasCore';\n\nexport function Field({\n label,\n value,\n onChange,\n multiline,\n keyboardType,\n}: {\n label: string;\n value: string;\n onChange: (v: string) => void;\n multiline?: boolean;\n keyboardType?: 'default' | 'decimal-pad' | 'numbers-and-punctuation';\n}) {\n return (\n <View style={formStyles.field}>\n <Text style={formStyles.fieldLabel}>{label}</Text>\n <TextInput\n value={value}\n onChangeText={onChange}\n style={[formStyles.fieldInput, multiline && formStyles.fieldMulti]}\n placeholderTextColor=\"#5A5A66\"\n autoCapitalize=\"none\"\n autoCorrect={false}\n multiline={multiline}\n keyboardType={keyboardType}\n />\n </View>\n );\n}\n\nexport function Stepper({\n label,\n value,\n onLess,\n onMore,\n}: {\n label: string;\n value: string;\n onLess: () => void;\n onMore: () => void;\n}) {\n return (\n <View style={formStyles.stepper}>\n <Text style={formStyles.stepperLabel}>{label}</Text>\n <Pressable onPress={onLess} hitSlop={8} accessibilityRole=\"button\" accessibilityLabel={`${label} less`}>\n <MaterialCommunityIcons name=\"minus\" size={15} color=\"#F7F7FA\" />\n </Pressable>\n <Text style={formStyles.stepperValue}>{value}</Text>\n <Pressable onPress={onMore} hitSlop={8} accessibilityRole=\"button\" accessibilityLabel={`${label} more`}>\n <MaterialCommunityIcons name=\"plus\" size={15} color=\"#F7F7FA\" />\n </Pressable>\n </View>\n );\n}\n\n/** Pick one of a fixed set of labelled values (chips). */\nexport function ChoiceRow({\n label,\n options,\n value,\n onChange,\n}: {\n label: string;\n options: ReadonlyArray<{ value: string; label: string }>;\n value: string;\n onChange: (v: string) => void;\n}) {\n return (\n <View>\n <Text style={formStyles.fieldLabel}>{label}</Text>\n <View style={formStyles.row}>\n {options.map((o) => {\n const on = o.value === value;\n return (\n <Pressable\n key={o.value}\n onPress={() => onChange(o.value)}\n style={[formStyles.choice, on && formStyles.choiceOn]}\n accessibilityRole=\"button\"\n accessibilityState={{ selected: on }}\n >\n <Text style={[formStyles.choiceLabel, on && formStyles.choiceLabelOn]} numberOfLines={1}>\n {o.label}\n </Text>\n </Pressable>\n );\n })}\n </View>\n </View>\n );\n}\n\nexport function PickRow({\n label,\n items,\n selected,\n onSelect,\n empty,\n}: {\n label: string;\n items: readonly CanvasItem[];\n selected: string;\n onSelect: (url: string) => void;\n empty: string;\n}) {\n if (items.length === 0) return <Text style={formStyles.hint}>{empty}</Text>;\n return (\n <View>\n <Text style={formStyles.fieldLabel}>{label}</Text>\n <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={formStyles.row}>\n {items.map((item) => {\n const on = item.src === selected;\n return (\n <Pressable\n key={item.id}\n onPress={() => onSelect(item.src)}\n style={[formStyles.choice, on && formStyles.choiceOn]}\n >\n <Text style={[formStyles.choiceLabel, on && formStyles.choiceLabelOn]} numberOfLines={1}>\n {item.generatedAssetName || item.type}\n </Text>\n </Pressable>\n );\n })}\n </ScrollView>\n </View>\n );\n}\n\nexport function PickMulti({\n items,\n selected,\n onChange,\n empty,\n}: {\n items: readonly CanvasItem[];\n selected: string[];\n onChange: (urls: string[]) => void;\n empty: string;\n}) {\n if (items.length === 0) return <Text style={formStyles.hint}>{empty}</Text>;\n return (\n <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={formStyles.row}>\n {items.map((item) => {\n const on = selected.includes(item.src);\n return (\n <Pressable\n key={item.id}\n onPress={() => onChange(on ? selected.filter((u) => u !== item.src) : [...selected, item.src])}\n style={[formStyles.choice, on && formStyles.choiceOn]}\n >\n <Text style={[formStyles.choiceLabel, on && formStyles.choiceLabelOn]} numberOfLines={1}>\n {item.generatedAssetName || item.type}\n </Text>\n </Pressable>\n );\n })}\n </ScrollView>\n );\n}\n\nexport const formStyles = StyleSheet.create({\n field: { minWidth: 88, flexGrow: 1 },\n fieldLabel: { color: '#9A9AA5', fontSize: 11, marginBottom: 4 },\n fieldInput: {\n color: '#F7F7FA',\n fontSize: 13,\n paddingHorizontal: 10,\n paddingVertical: 8,\n borderRadius: 9,\n backgroundColor: '#1F1F24',\n },\n fieldMulti: { minHeight: 56, textAlignVertical: 'top' },\n stepper: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 9,\n paddingHorizontal: 12,\n paddingVertical: 8,\n borderRadius: 9,\n backgroundColor: '#1F1F24',\n },\n stepperLabel: { color: '#9A9AA5', fontSize: 11.5 },\n stepperValue: {\n color: '#F7F7FA',\n fontSize: 12.5,\n fontVariant: ['tabular-nums'],\n minWidth: 44,\n textAlign: 'center',\n },\n hint: { color: '#9A9AA5', fontSize: 13, lineHeight: 18 },\n row: { flexDirection: 'row', alignItems: 'center', gap: 8, flexWrap: 'wrap', paddingVertical: 4 },\n choice: {\n paddingHorizontal: 12,\n paddingVertical: 8,\n borderRadius: 9,\n backgroundColor: '#1F1F24',\n maxWidth: 160,\n },\n choiceOn: { backgroundColor: '#8B7CFF' },\n choiceLabel: { color: '#F7F7FA', fontSize: 12.5, fontWeight: '500' },\n choiceLabelOn: { color: '#0A0A0C' },\n});\n"],"names":[],"mappings":"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"}