@mevdragon/vidfarm-devcli 0.19.1 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.agents/skills/music/SKILL.md +416 -0
  2. package/.agents/skills/music/references/api_reference.md +519 -0
  3. package/.agents/skills/music/references/installation.md +65 -0
  4. package/.agents/skills/text-to-speech/SKILL.md +226 -0
  5. package/.agents/skills/text-to-speech/references/installation.md +90 -0
  6. package/.agents/skills/text-to-speech/references/streaming.md +307 -0
  7. package/.agents/skills/text-to-speech/references/voice-settings.md +115 -0
  8. package/.agents/skills/vidfarm-media/SKILL.md +25 -11
  9. package/.agents/skills/vidfarm-media/references/tts.md +41 -3
  10. package/SKILL.director.md +31 -13
  11. package/SKILL.platform.md +2 -2
  12. package/demo/dist/app.css +1 -1
  13. package/demo/dist/app.js +75 -75
  14. package/dist/src/app.js +129 -41
  15. package/dist/src/cli.js +162 -5
  16. package/dist/src/config.js +12 -0
  17. package/dist/src/devcli/clips.js +7 -2
  18. package/dist/src/domain.js +3 -0
  19. package/dist/src/editor-chat.js +5 -1
  20. package/dist/src/frontend/file-directory.js +41 -18
  21. package/dist/src/primitive-context.js +14 -0
  22. package/dist/src/primitive-registry.js +140 -18
  23. package/dist/src/reskin/chat-page.js +1 -1
  24. package/dist/src/reskin/inpaint-clipper-page.js +446 -205
  25. package/dist/src/reskin/library-page.js +7 -1
  26. package/dist/src/reskin/portfolio-page.js +9 -9
  27. package/dist/src/reskin/settings-page.js +4 -4
  28. package/dist/src/reskin/theme.js +8 -4
  29. package/dist/src/services/billing.js +5 -0
  30. package/dist/src/services/clip-curation/ffmpeg.js +48 -0
  31. package/dist/src/services/clip-curation/hunt.js +2 -0
  32. package/dist/src/services/clip-curation/index.js +1 -1
  33. package/dist/src/services/clip-curation/scan.js +29 -16
  34. package/dist/src/services/elevenlabs.js +222 -0
  35. package/dist/src/services/providers.js +216 -2
  36. package/dist/src/services/swipe-customize.js +5 -2
  37. package/package.json +1 -1
  38. package/public/assets/file-directory-app.js +3 -2
@@ -7,6 +7,7 @@ import { ServerlessProviderKeyService } from "./serverless-provider-keys.js";
7
7
  import sharp from "sharp";
8
8
  import { ProviderAuthError, ProviderKeyUnavailableError, ProviderLeaseTimeoutError, ProviderQuotaExceededError, ProviderRateLimitError, ProviderTransientError, ProviderWaitExceededError, SpeechVoiceMismatchError, conciseProviderDetails, parseRetryAfterSeconds, rateLimitOrQuotaError } from "./provider-errors.js";
9
9
  import { SUPPORTED_STT_MODELS, SUPPORTED_TTS_MODELS, defaultSpeechModelFor, generateSpeechWithKey, inferSpeechContentType, speechVoiceFamilyFor, speechVoiceMismatch, transcribeSpeechWithKey } from "./speech.js";
10
+ import { DEFAULT_ELEVENLABS_STT_MODEL, DEFAULT_ELEVENLABS_TTS_MODEL, elevenLabsListVoices, elevenLabsMusicCompose, elevenLabsSpeechToText, elevenLabsTextToSpeech, validateElevenLabsKey } from "./elevenlabs.js";
10
11
  export { ProviderAuthError, ProviderKeyUnavailableError, ProviderLeaseTimeoutError, ProviderQuotaExceededError, ProviderRateLimitError, ProviderTransientError, ProviderWaitExceededError } from "./provider-errors.js";
11
12
  const SUPPORTED_TEXT_MODELS = {
12
13
  openai: new Set(["gpt-5.4"]),
@@ -70,6 +71,8 @@ const OPENAI_IMAGE_SIZES = new Set([
70
71
  "auto"
71
72
  ]);
72
73
  const GEMINI_IMAGE_ASPECT_RATIOS = new Set(["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "9:21"]);
74
+ // elevenlabs is intentionally absent — it validates against its own /v1/user
75
+ // endpoint (see validateProviderKey), not a chat-completion probe.
73
76
  const PROVIDER_KEY_VALIDATION_MODELS = {
74
77
  openai: "gpt-4.1-mini",
75
78
  gemini: "gemini-3.1-flash-lite-preview",
@@ -334,6 +337,20 @@ export class ProviderService {
334
337
  return [...new Set(providers)];
335
338
  }
336
339
  async validateProviderKey(input) {
340
+ // ElevenLabs is audio-only: validate against its own account endpoint, not a
341
+ // chat-completion probe.
342
+ if (input.provider === "elevenlabs") {
343
+ if (config.mockProviders) {
344
+ return { provider: input.provider, model: "elevenlabs", mock: true };
345
+ }
346
+ try {
347
+ await validateElevenLabsKey(input.secret);
348
+ return { provider: input.provider, model: "elevenlabs", mock: false };
349
+ }
350
+ catch (error) {
351
+ throw new Error(toProviderValidationMessage(input.provider, error));
352
+ }
353
+ }
337
354
  const model = PROVIDER_KEY_VALIDATION_MODELS[input.provider];
338
355
  if (!model) {
339
356
  throw new Error(`Provider ${input.provider} does not support validation.`);
@@ -541,7 +558,123 @@ export class ProviderService {
541
558
  await this.releaseLease(lease);
542
559
  }
543
560
  }
561
+ // --- Audio (music / TTS / STT): platform-key + wallet vs BYOK routing ---
562
+ async resolveCustomerElevenLabsKey(customerId) {
563
+ const now = new Date().toISOString();
564
+ const secret = (await this.serverlessProviderKeys.listProviderKeysWithSecrets(customerId))
565
+ .filter((entry) => String(entry.provider) === "elevenlabs")
566
+ .filter((entry) => String(entry.status) === "active")
567
+ .filter((entry) => !entry.cooldown_until || String(entry.cooldown_until) <= now)
568
+ .map((entry) => readStoredProviderSecret(String(entry.secret ?? "")))
569
+ .find((value) => value.trim().length > 0);
570
+ return secret ?? null;
571
+ }
572
+ async customerHasByokAudioKey(customerId) {
573
+ const providers = await this.listAvailableProvidersAsync(customerId);
574
+ return providers.some((provider) => provider === "openai" || provider === "gemini" || provider === "openrouter");
575
+ }
576
+ /**
577
+ * Decide how an audio call is authorized. Default (`use_wallet_credits` unset
578
+ * or true): the platform ElevenLabs key, billed to the wallet. Explicit
579
+ * `false`: the customer's own ElevenLabs key, else a BYOK openai/gemini/
580
+ * openrouter key (TTS/STT only), else fall back to the platform key + wallet.
581
+ */
582
+ async resolveAudioAuthPlan(input) {
583
+ // `undefined` = legacy BYOK-only. Internal callers (captions, voice-matched
584
+ // regenerate-speech) never pass the flag, so they keep their exact behavior
585
+ // and never silently draw on the platform key or the wallet. Only surfaces
586
+ // that explicitly opt in (the music/tts/stt primitives) reach ElevenLabs.
587
+ if (input.useWalletCredits === undefined) {
588
+ return { mode: "byok" };
589
+ }
590
+ const platformKey = config.ELEVENLABS_API_KEY?.trim() || null;
591
+ if (input.useWalletCredits) {
592
+ if (platformKey) {
593
+ return { mode: "elevenlabs", apiKey: platformKey, walletBilled: true, scope: "platform" };
594
+ }
595
+ // Operator hasn't wired a platform key — honor the intent with the user's
596
+ // own ElevenLabs key (no charge) or a BYOK audio key before failing.
597
+ const userKey = await this.resolveCustomerElevenLabsKey(input.customerId);
598
+ if (userKey) {
599
+ return { mode: "elevenlabs", apiKey: userKey, walletBilled: false, scope: "user" };
600
+ }
601
+ if (input.byokFallback && (await this.customerHasByokAudioKey(input.customerId))) {
602
+ return { mode: "byok" };
603
+ }
604
+ throw new ProviderKeyUnavailableError("use_wallet_credits is on but no platform ElevenLabs key is configured, and you have no usable audio key. Ask the operator to set ELEVENLABS_API_KEY or save your own key.");
605
+ }
606
+ // use_wallet_credits === false: prefer the user's OWN key, then a BYOK audio
607
+ // key (TTS/STT), and only then fall back to the platform key + wallet.
608
+ const userKey = await this.resolveCustomerElevenLabsKey(input.customerId);
609
+ if (userKey) {
610
+ return { mode: "elevenlabs", apiKey: userKey, walletBilled: false, scope: "user" };
611
+ }
612
+ if (input.byokFallback && (await this.customerHasByokAudioKey(input.customerId))) {
613
+ return { mode: "byok" };
614
+ }
615
+ if (platformKey) {
616
+ return { mode: "elevenlabs", apiKey: platformKey, walletBilled: true, scope: "platform" };
617
+ }
618
+ throw new ProviderKeyUnavailableError(input.capability === "music"
619
+ ? "Music needs ElevenLabs: save an ElevenLabs key in Settings, or ask the operator to configure the platform ELEVENLABS_API_KEY (use_wallet_credits)."
620
+ : `No audio provider available for ${input.capability}. Enable use_wallet_credits (platform ElevenLabs key), save your own ElevenLabs key, or add an OpenAI/Gemini/OpenRouter key.`);
621
+ }
622
+ /** Voices available to whichever ElevenLabs account will serve this customer. */
623
+ async listElevenLabsVoices(input) {
624
+ const plan = await this.resolveAudioAuthPlan({
625
+ customerId: input.customerId,
626
+ useWalletCredits: input.useWalletCredits,
627
+ byokFallback: false,
628
+ capability: "tts"
629
+ });
630
+ if (plan.mode !== "elevenlabs") {
631
+ throw new ProviderKeyUnavailableError("No ElevenLabs account is available to list voices.");
632
+ }
633
+ return { scope: plan.scope, voices: await elevenLabsListVoices(plan.apiKey) };
634
+ }
544
635
  async generateSpeech(input) {
636
+ const plan = await this.resolveAudioAuthPlan({
637
+ customerId: input.customerId,
638
+ useWalletCredits: input.useWalletCredits,
639
+ byokFallback: true,
640
+ capability: "tts"
641
+ });
642
+ if (plan.mode === "elevenlabs") {
643
+ const model = /^eleven/i.test(input.model || "") ? input.model : DEFAULT_ELEVENLABS_TTS_MODEL;
644
+ const generated = await elevenLabsTextToSpeech({
645
+ apiKey: plan.apiKey,
646
+ text: input.text,
647
+ voice: input.voice,
648
+ model,
649
+ responseFormat: input.responseFormat
650
+ });
651
+ const billing = plan.walletBilled
652
+ ? {
653
+ costUsd: Number(((generated.characterCount / 1000) * config.ELEVENLABS_TTS_USD_PER_1K_CHARS).toFixed(4)),
654
+ costCenterSlug: "elevenlabs_tts",
655
+ metadata: {
656
+ operation: "tts",
657
+ provider: "elevenlabs",
658
+ model,
659
+ character_count: generated.characterCount,
660
+ wallet_billed: true,
661
+ scope: plan.scope
662
+ }
663
+ }
664
+ : null;
665
+ return {
666
+ bytes: generated.bytes,
667
+ contentType: generated.contentType,
668
+ usage: generated.usage,
669
+ effectiveProvider: "elevenlabs",
670
+ effectiveModel: model,
671
+ billing
672
+ };
673
+ }
674
+ const byok = await this.generateSpeechByok(input);
675
+ return { ...byok.result, effectiveProvider: byok.provider, effectiveModel: byok.model, billing: null };
676
+ }
677
+ async generateSpeechByok(input) {
545
678
  // Provider fallback must stay voice-aware: a Gemini preset routed to an
546
679
  // OpenAI key (or the reverse) would 400 opaquely at the provider.
547
680
  const attempts = (await providerAttempts({
@@ -562,11 +695,12 @@ export class ProviderService {
562
695
  let lastError = null;
563
696
  for (const attempt of attempts) {
564
697
  try {
565
- return await this.generateSpeechWithProvider({
698
+ const result = await this.generateSpeechWithProvider({
566
699
  ...input,
567
700
  provider: attempt.provider,
568
701
  model: attempt.model
569
702
  });
703
+ return { result, provider: attempt.provider, model: attempt.model };
570
704
  }
571
705
  catch (error) {
572
706
  lastError = error;
@@ -581,6 +715,42 @@ export class ProviderService {
581
715
  throw lastError instanceof Error ? lastError : new ProviderLeaseTimeoutError("No eligible AI speech provider key became available in time.");
582
716
  }
583
717
  }
718
+ /** ElevenLabs music generation. Platform key + wallet by default; the
719
+ * customer's own ElevenLabs key when use_wallet_credits is false. */
720
+ async generateMusic(input) {
721
+ const plan = await this.resolveAudioAuthPlan({
722
+ customerId: input.customerId,
723
+ useWalletCredits: input.useWalletCredits,
724
+ byokFallback: false,
725
+ capability: "music"
726
+ });
727
+ if (plan.mode !== "elevenlabs") {
728
+ throw new ProviderKeyUnavailableError("Music generation requires an ElevenLabs key.");
729
+ }
730
+ const generated = await elevenLabsMusicCompose({
731
+ apiKey: plan.apiKey,
732
+ prompt: input.prompt,
733
+ musicLengthMs: input.musicLengthMs,
734
+ compositionPlan: input.compositionPlan,
735
+ model: input.model,
736
+ outputFormat: input.outputFormat
737
+ });
738
+ const minutes = Math.max(0, generated.musicLengthMs) / 60000;
739
+ const billing = plan.walletBilled
740
+ ? {
741
+ costUsd: Number((minutes * config.ELEVENLABS_MUSIC_USD_PER_MIN).toFixed(4)),
742
+ costCenterSlug: "elevenlabs_music",
743
+ metadata: {
744
+ operation: "music",
745
+ provider: "elevenlabs",
746
+ music_length_ms: generated.musicLengthMs,
747
+ wallet_billed: true,
748
+ scope: plan.scope
749
+ }
750
+ }
751
+ : null;
752
+ return { ...generated, scope: plan.scope, billing };
753
+ }
584
754
  async generateSpeechWithProvider(input) {
585
755
  assertSupportedSpeechModel("tts", input.provider, input.model);
586
756
  const lease = await this.leaseCustomerKey({
@@ -1475,6 +1645,45 @@ export class ProviderService {
1475
1645
  }
1476
1646
  }
1477
1647
  async transcribeSpeech(input) {
1648
+ const plan = await this.resolveAudioAuthPlan({
1649
+ customerId: input.customerId,
1650
+ useWalletCredits: input.useWalletCredits,
1651
+ byokFallback: true,
1652
+ capability: "stt"
1653
+ });
1654
+ if (plan.mode === "elevenlabs") {
1655
+ const model = /^scribe/i.test(input.model || "") ? input.model : DEFAULT_ELEVENLABS_STT_MODEL;
1656
+ const transcription = await elevenLabsSpeechToText({
1657
+ apiKey: plan.apiKey,
1658
+ audio: input.audio,
1659
+ contentType: input.contentType,
1660
+ model,
1661
+ diarize: input.diarize,
1662
+ languageCode: input.language
1663
+ });
1664
+ const minutes = Math.max(0, transcription.audioDurationSec ?? 0) / 60;
1665
+ const billing = plan.walletBilled
1666
+ ? {
1667
+ costUsd: Number((minutes * config.ELEVENLABS_STT_USD_PER_MIN).toFixed(4)),
1668
+ costCenterSlug: "elevenlabs_stt",
1669
+ metadata: {
1670
+ operation: "stt",
1671
+ provider: "elevenlabs",
1672
+ model,
1673
+ audio_duration_sec: transcription.audioDurationSec,
1674
+ wallet_billed: true,
1675
+ scope: plan.scope
1676
+ }
1677
+ }
1678
+ : null;
1679
+ const { audioDurationSec, ...rest } = transcription;
1680
+ void audioDurationSec;
1681
+ return { ...rest, effectiveProvider: "elevenlabs", effectiveModel: model, billing };
1682
+ }
1683
+ const byok = await this.transcribeSpeechByok(input);
1684
+ return { ...byok.result, effectiveProvider: byok.provider, effectiveModel: byok.model, billing: null };
1685
+ }
1686
+ async transcribeSpeechByok(input) {
1478
1687
  const attempts = await providerAttempts({
1479
1688
  providerKeyService: this.serverlessProviderKeys,
1480
1689
  customerId: input.customerId,
@@ -1489,11 +1698,12 @@ export class ProviderService {
1489
1698
  let lastError = null;
1490
1699
  for (const attempt of attempts) {
1491
1700
  try {
1492
- return await this.transcribeSpeechWithProvider({
1701
+ const result = await this.transcribeSpeechWithProvider({
1493
1702
  ...input,
1494
1703
  provider: attempt.provider,
1495
1704
  model: attempt.model
1496
1705
  });
1706
+ return { result, provider: attempt.provider, model: attempt.model };
1497
1707
  }
1498
1708
  catch (error) {
1499
1709
  lastError = error;
@@ -2041,6 +2251,10 @@ function formatProviderLabel(provider) {
2041
2251
  return "OpenRouter";
2042
2252
  case "perplexity":
2043
2253
  return "Perplexity";
2254
+ case "elevenlabs":
2255
+ return "ElevenLabs";
2256
+ default:
2257
+ return provider;
2044
2258
  }
2045
2259
  }
2046
2260
  function readStringField(value, field) {
@@ -66,6 +66,7 @@ export async function reconcileSwipeRows(customerId, rows) {
66
66
  }
67
67
  return out;
68
68
  }
69
+ // Text generation only — the audio-only elevenlabs provider never appears here.
69
70
  const TEXT_MODEL_DEFAULTS = {
70
71
  openai: "gpt-5.4-mini",
71
72
  gemini: "gemini-2.5-flash",
@@ -246,7 +247,9 @@ function parseJsonLoose(text) {
246
247
  }
247
248
  async function generateRecaption(input) {
248
249
  const available = await providers.listAvailableProvidersAsync(input.customerId);
249
- const provider = TEXT_PROVIDER_PRIORITY.find((p) => available.includes(p)) ?? available[0];
250
+ // Text generation only never fall back to a non-text provider (e.g. the
251
+ // audio-only elevenlabs key), which has no text model.
252
+ const provider = TEXT_PROVIDER_PRIORITY.find((p) => available.includes(p));
250
253
  if (!provider)
251
254
  throw new NoProviderKeyError();
252
255
  const generated = await providers.generateText({
@@ -254,7 +257,7 @@ async function generateRecaption(input) {
254
257
  jobId: input.jobId,
255
258
  workerId: "swipe-customize",
256
259
  provider,
257
- model: TEXT_MODEL_DEFAULTS[provider],
260
+ model: TEXT_MODEL_DEFAULTS[provider] ?? "gpt-5.4-mini",
258
261
  prompt: input.prompt,
259
262
  temperature: 0.7,
260
263
  responseFormat: "json"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mevdragon/vidfarm-devcli",
3
- "version": "0.19.1",
3
+ "version": "0.20.1",
4
4
  "description": "Local bridge for the Vidfarm Trackpad Editor. `vidfarm serve <template_id>` boots the FULL editor on localhost (disk-backed records/storage, free in-process render); edit composition.html on disk (Claude Code, Codex, etc.) and the browser live-morphs it.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,2 +1,3 @@
1
- var Me=["files","temp","raws","projects","approved"],pe=[{key:"files",label:"My Files",description:"Durable personal files \u2014 brand assets, characters, saved context. Vector-searchable via notes."},{key:"temp",label:"Temp",description:"Scratch space, auto-organized by date (YYYY-MM-DD) and auto-deleted after 30 days."},{key:"raws",label:"Raws",description:"The reusable clip / source-footage library, organized into folders by source."},{key:"projects",label:"Projects",description:"Your video-editing projects \u2014 one folder per fork, holding that composition's working files (composition.html/json, cast, media) and saved versions. Read-only: browse to reference or study another fork."},{key:"approved",label:"Approved",description:"Finished, ready-to-post cuts, organized into folders (defaults to a folder per tracer/campaign)."}];function qe(r){return r==="files"||r==="temp"||r==="raws"||r==="projects"||r==="approved"}function ue(r){return String(r??"").split("/").map(n=>n.trim()).filter(Boolean).join("/")}function J(r){let n=String(r??"").split("/").map(h=>h.trim()).filter(Boolean);if(n.length===0)return{root:null,folderPath:"",segments:[]};let[s,...a]=n;return qe(s)?{root:s,folderPath:a.join("/"),segments:a}:{root:null,folderPath:"",segments:n}}function Z(r,n,s){let a=[r,ue(n)];return s&&a.push(String(s).trim()),"/"+a.filter(Boolean).join("/")}var We="/api/v1/user/me";function i(r,n,s){let a=document.createElement(r);return n&&(a.className=n),s!=null&&(a.textContent=s),a}function Je(r){if(!r||r<=0)return"";let n=["B","KB","MB","GB"],s=r,a=0;for(;s>=1024&&a<n.length-1;)s/=1024,a++;return(s>=10||a===0?Math.round(s):s.toFixed(1))+" "+n[a]}function Ve(r){if(typeof r!="number"||!(r>0))return"";r=Math.round(r);let n=Math.floor(r/60),s=r%60;return n+":"+(s<10?"0"+s:s)}function Se(r){let n=i("span","rk-aichat-fic "+(r.kind==="folder"?"rk-aichat-fic-folder":"rk-aichat-fic-file"));if(r.kind==="folder")return n.textContent="/",n;if(r.thumbUrl){let a=i("img");return a.src=r.thumbUrl,a.alt="",a.loading="lazy",n.appendChild(a),n}let s=r.contentType||"";if(r.viewUrl&&s.indexOf("image/")===0){let a=i("img");return a.src=r.viewUrl,a.alt="",a.loading="lazy",n.appendChild(a),n}if(r.viewUrl&&s.indexOf("video/")===0){let a=i("video");return a.src=r.viewUrl,a.muted=!0,a.playsInline=!0,n.appendChild(a),n}return n.textContent=(r.name.split(".").pop()||r.name.slice(0,1)||"?").slice(0,3).toUpperCase(),n}var fe;function he(r){let n=document.getElementById("rk-dir-toast");n||(n=i("div"),n.id="rk-dir-toast",n.className="rk-dir-toast",document.body.appendChild(n)),n.textContent=r,n.classList.add("is-on"),fe&&window.clearTimeout(fe),fe=window.setTimeout(()=>n&&n.classList.remove("is-on"),1800)}function $e(r){return navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(r):new Promise((n,s)=>{try{let a=i("textarea");a.value=r,a.style.position="fixed",a.style.opacity="0",document.body.appendChild(a),a.select(),document.execCommand("copy"),document.body.removeChild(a),n()}catch(a){s(a)}})}var q=null;function Re(r,n){q&&q();let s=i("div","rk-dir-menu");n.forEach(f=>{let L=i("button","rk-dir-menuitem"+(f.danger?" is-danger":""),f.label);L.type="button",L.addEventListener("click",N=>{N.stopPropagation(),x(),f.run()}),s.appendChild(L)}),document.body.appendChild(s);let a=r instanceof HTMLElement?r.getBoundingClientRect():r,h=s.offsetWidth,v=s.offsetHeight,S=a.bottom+4,w=a.right-h;w<8&&(w=a.left),S+v>window.innerHeight-8&&(S=Math.max(8,a.top-v-4)),s.style.top=S+"px",s.style.left=Math.max(8,w)+"px";function x(){s.remove(),document.removeEventListener("click",m,!0),document.removeEventListener("keydown",D,!0),window.removeEventListener("scroll",x,!0),q===x&&(q=null)}function m(f){s.contains(f.target)||x()}function D(f){f.key==="Escape"&&x()}setTimeout(()=>{document.addEventListener("click",m,!0),document.addEventListener("keydown",D,!0),window.addEventListener("scroll",x,!0)},0),q=x}function me(r,n={}){let s=n.apiBase||We,a=n.roots&&n.roots.length?n.roots:Me.slice(),h=a.length===1?a[0]:null,v=n.mode||"attach",S=n.showSearch!==!1,w=n.showMultiSelect!==!1,x=n.showUpload!=null?n.showUpload:v==="attach",m=n.primaryClick||"copyPath",D=n.cloudAvailable!=null?n.cloudAvailable:typeof window<"u"&&window.__vidfarmCloudSpace===!0,f=window.__rkDirectoryHost||{},L=e=>(n.onAttach||f.onAttach||(()=>he("Attached "+e.length+" item(s)")))(e),N=(e,t)=>{let o=n.onPreview||f.onPreview;o?o(e,t):e[t]&&e[t].viewUrl&&window.open(e[t].viewUrl,"_blank","noopener")},T=e=>(n.onToast||f.onToast||he)(e),R=e=>$e(e).then(()=>T("Copied "+e)).catch(()=>T("Couldn't copy path")),p=He(n.initialPath,h),u="idle",g=[],P=[],V=null,W=!1,k=new Map,$=!1,I=[],X="idle",H=!1,le="local";function ge(){return le==="cloud"?"/cloud":""}function He(e,t){let o=J(e||"");return o.root?Z(o.root,o.folderPath):t?"/"+t:"/"}r.classList.add("rk-dir"),r.innerHTML="";let be=i("div","rk-dir-search"),z=i("input","rk-dir-search-input");z.type="search",z.placeholder="Search files \u2014 meaning, name, or path\u2026",be.appendChild(z);let O=i("div","rk-aichat-crumbs rk-dir-crumbs"),_=i("div","rk-dir-selbar");_.hidden=!0;let b=i("div","rk-aichat-files-body rk-dir-body"),y=i("label","rk-aichat-drop rk-dir-drop");y.hidden=!0;let ee=i("span","rk-aichat-drop-text","Drop files here"),B=i("input");B.type="file",B.multiple=!0,B.hidden=!0,y.appendChild(ee),y.appendChild(B);let de=i("div","rk-dir-space"),te=i("button","rk-dir-space-btn is-on","Local"),ne=i("button","rk-dir-space-btn","Cloud");te.type="button",ne.type="button",de.appendChild(te),de.appendChild(ne);function ke(e){le!==e&&(le=e,te.classList.toggle("is-on",e==="local"),ne.classList.toggle("is-on",e==="cloud"),$=!1,I=[],z.value="",k.clear(),p=h?"/"+h:"/",u="idle",F(!0))}te.addEventListener("click",()=>ke("local")),ne.addEventListener("click",()=>ke("cloud")),D&&r.appendChild(de),S&&r.appendChild(be),r.appendChild(O),w&&r.appendChild(_),r.appendChild(b),x&&r.appendChild(y);function ye(e,t){let o=new URL(s+ge()+"/directory",window.location.href);return o.searchParams.set("path",e),t&&o.searchParams.set("offset",String(t)),o.toString()}function F(e){if(!H){if(!e&&u==="ready"){C();return}u="loading",C(),fetch(ye(p),{credentials:"same-origin",headers:{accept:"application/json"}}).then(t=>{if(t.status===401||t.status===403)return u="auth",null;if(!t.ok)throw new Error("http "+t.status);return t.json()}).then(t=>{if(!H){if(!t){C();return}g=Oe(t.folders||[]),P=t.files||[],V=typeof t.next_offset=="number"?t.next_offset:null,u="ready",C()}}).catch(()=>{H||(u="error",C())})}}function Oe(e){return p!=="/"?e:e.filter(t=>a.indexOf(t.root)!==-1)}function _e(){V==null||W||(W=!0,C(),fetch(ye(p,V),{credentials:"same-origin",headers:{accept:"application/json"}}).then(e=>e.ok?e.json():null).then(e=>{if(W=!1,H||!e){C();return}P=P.concat(e.files||[]),V=typeof e.next_offset=="number"?e.next_offset:null,C()}).catch(()=>{W=!1,C()}))}let ce;function Be(){let e=z.value.trim();if(ce&&window.clearTimeout(ce),!e){$=!1,I=[],C();return}ce=window.setTimeout(()=>Ue(e),260)}function Ue(e){$=!0,X="loading",C();let t=h?"/"+h:p!=="/"?p:"";fetch(s+ge()+"/directory/search",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:e,path:t,mode:"auto",limit:40})}).then(o=>o.ok?o.json():null).then(o=>{H||(I=o&&o.results||[],X="ready",C())}).catch(()=>{H||(X="error",C())})}function U(e){let t=J(e);p=t.root?Z(t.root,t.folderPath):"/",u="idle",$=!1,z.value="",(n.onNavigate||(()=>{}))(p),F(!0)}function j(){return J(p).root}function re(){return J(p).folderPath}function Y(e){return!!e&&e!=="projects"}function oe(e){let t=j();if(!t){T("Open a root (/files, /temp, /raws) first");return}if(!Y(t)){T("/projects is read-only");return}let o=(window.prompt("New folder name")||"").trim();if(!o)return;let d=ue(e??re()),c=Z(t,d?d+"/"+o:o);fetch(s+"/directory/folders",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:c})}).then(l=>l.ok?l.json():l.json().then(E=>Promise.reject(new Error(E.error||"http "+l.status)))).then(l=>{U(l.path||(t===j()?p:"/"+t)),T("Created "+(l.path||o))}).catch(l=>T(l.message||"Couldn't create folder"))}function ie(e){let t=e.kind==="folder",o=(window.prompt(t?"Rename folder":"Rename file",e.name)||"").trim();!o||o===e.name||fetch(s+"/directory/rename",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:e.path,new_name:o,...t?{}:{file_id:e.id}})}).then(d=>d.ok?d.json():d.json().then(c=>Promise.reject(new Error(c.error||"http "+d.status)))).then(()=>{k.has(e.path)&&(k.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(k.values()))),F(!0),T("Renamed to "+o)}).catch(d=>T(d.message||"Couldn't rename"))}function je(e,t){t?k.set(e.path,e):k.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(k.values())),Ce();let o=b.querySelector('[data-path="'+Xe(e.path)+'"]');o&&o.classList.toggle("is-selected",t)}function ve(){k.clear(),(n.onSelectionChange||(()=>{}))([]),C()}function se(e,t,o){let d=i("button","rk-aichat-crumb"+(t?" is-current":""),e);return d.type="button",d.addEventListener("click",o),d}function Ne(){O.innerHTML="";let e=j(),t=re();if(h||O.appendChild(se("Files",p==="/",()=>U("/"))),!e)return;let o=(pe.find(c=>c.key===e)||{label:e}).label;h||O.appendChild(we()),O.appendChild(se(o,!t,()=>U("/"+e)));let d="";if(t.split("/").filter(Boolean).forEach((c,l,E)=>{O.appendChild(we()),d=d?d+"/"+c:c;let M="/"+e+"/"+d;O.appendChild(se(c,l===E.length-1,()=>U(M)))}),Y(e)){let c=i("button","rk-dir-newfolder","+ Folder");c.type="button",c.title="New folder here (or right-click)",c.addEventListener("click",()=>oe()),O.appendChild(c)}}function we(){return i("span","rk-aichat-crumb-sep","/")}function Ce(){if(!w)return;let e=k.size;if(_.hidden=e===0,e===0)return;if(_.innerHTML="",_.appendChild(i("span","rk-dir-selcount",e+" selected")),v==="attach"){let d=i("button","rk-dir-selbtn","Attach");d.type="button",d.addEventListener("click",()=>{L(Array.from(k.values())),ve()}),_.appendChild(d)}let t=i("button","rk-dir-selbtn","Copy paths");t.type="button",t.addEventListener("click",()=>R(Array.from(k.values()).map(d=>d.path).join(`
2
- `)));let o=i("button","rk-dir-selbtn is-ghost","Clear");o.type="button",o.addEventListener("click",ve),_.appendChild(t),_.appendChild(o)}function xe(e){let t=i("input","rk-dir-check");return t.type="checkbox",t.checked=k.has(e.path),t.setAttribute("aria-label","Select "+e.name),t.addEventListener("click",o=>o.stopPropagation()),t.addEventListener("change",()=>je(e,t.checked)),t}function Ee(e){let t=i("div","rk-aichat-frow rk-dir-row"+(k.has(e.path)?" is-selected":""));t.setAttribute("data-path",e.path),w&&t.appendChild(xe(e));let o=i("button","rk-aichat-fmainbtn");o.type="button",o.title="Copy path "+e.path,o.appendChild(Se(e));let d=i("span","rk-aichat-fmain");d.appendChild(i("span","rk-aichat-fname",e.name));let c=e.meta&&typeof e.meta.description=="string"?e.meta.description:"";d.appendChild(i("span","rk-aichat-fmeta",c||"folder")),o.appendChild(d),o.addEventListener("click",()=>R(e.path)),t.appendChild(o);let l=i("button","rk-aichat-fadd rk-dir-open","Open \u203A");l.type="button",l.title="Open folder",l.addEventListener("click",M=>{M.stopPropagation(),U(e.path)}),t.appendChild(l);let E=[{label:"Open folder",run:()=>U(e.path)}];return Y(e.root)&&(E.push({label:"New subfolder",run:()=>oe(e.folderPath)}),E.push({label:"Rename",run:()=>ie(e)})),E.push({label:"Copy path",run:()=>R(e.path)}),t.appendChild(Le(e,E)),t}function De(e,t,o,d){let c=i("div","rk-aichat-frow rk-dir-row"+(k.has(e.path)?" is-selected":""));c.setAttribute("data-path",e.path),w&&c.appendChild(xe(e));let l=i("button","rk-aichat-fmainbtn");l.type="button";let E=m==="copyPath"?"Copy path ":m==="attach"?"Attach ":"Preview ";l.title=E+e.name,l.appendChild(Se(e));let M=i("span","rk-aichat-fmain");M.appendChild(i("span","rk-aichat-fname",e.name));let G=d?e.path:Ve(e.durationSec)||Je(e.sizeBytes)||e.contentType||"file";if(M.appendChild(i("span","rk-aichat-fmeta",G)),l.appendChild(M),l.addEventListener("click",()=>{m==="attach"?L([e]):m==="preview"?N(t,o):R(e.path)}),c.appendChild(l),v==="attach"&&m==="preview"){let Q=i("button","rk-aichat-fadd rk-dir-attach","+");Q.type="button",Q.title="Attach "+e.name,Q.setAttribute("aria-label","Attach "+e.name),Q.addEventListener("click",Ke=>{Ke.stopPropagation(),L([e])}),c.appendChild(Q)}let A=[];return v==="attach"&&A.push({label:"Attach",run:()=>L([e])}),e.viewUrl&&A.push({label:"View",run:()=>window.open(e.viewUrl,"_blank","noopener")}),e.viewUrl&&A.push({label:"Preview",run:()=>N(t,o)}),(e.root==="files"||e.root==="temp")&&e.id&&A.push({label:"Rename",run:()=>ie(e)}),A.push({label:"Copy path",run:()=>R(e.path)}),c.appendChild(Le(e,A)),c}function Le(e,t){let o=i("button","rk-dir-kebab","\u22EF");return o.type="button",o.setAttribute("aria-label","More actions"),o.addEventListener("click",d=>{d.stopPropagation(),Re(o,t)}),o}function K(e,t,o){let d=i("div","rk-aichat-fstate");if(d.appendChild(i("div",void 0,e)),t){let c=i("a");c.href=t.href,c.textContent=t.label,d.appendChild(c)}if(o){let c=i("button",void 0,"Try again");c.type="button",c.addEventListener("click",()=>F(!0)),d.appendChild(c)}return d}function C(){if(!H){if(Ne(),Ce(),Fe(),b.innerHTML="",$){ze();return}if(u==="loading"&&!P.length&&!g.length){b.appendChild(K("Loading your files\u2026"));return}if(u==="auth"){b.appendChild(K("Sign in to browse your files.",{href:"/login",label:"Sign in"}));return}if(u==="error"){b.appendChild(K("Couldn't reach your files.",void 0,!0));return}if(!g.length&&!P.length){b.appendChild(K(p==="/"?"No files yet.":"This folder is empty."));return}if(g.forEach(e=>b.appendChild(Ee(e))),P.forEach((e,t)=>b.appendChild(De(e,P,t))),V!=null){let e=i("button","rk-aichat-loadmore",W?"Loading\u2026":"Load more");e.type="button",e.disabled=W,e.addEventListener("click",_e),b.appendChild(e)}}}function ze(){if(X==="loading"&&!I.length){b.appendChild(K("Searching\u2026"));return}if(X==="error"){b.appendChild(K("Search failed."));return}if(!I.length){b.appendChild(K("No matches."));return}let e=I.filter(t=>t.kind!=="folder");I.forEach((t,o)=>{t.kind==="folder"?b.appendChild(Ee(t)):b.appendChild(De(t,e,e.indexOf(t),!0))})}let ae=!1;function Te(){let e=j();return e==="files"?s+"/attachments/upload":e==="temp"?s+"/temporary-files/upload":null}function Fe(){if(!x)return;let e=Te();if(y.hidden=!e||u==="auth",!y.hidden&&!ae){let t=re(),o=j()?(pe.find(d=>d.key===j())||{label:""}).label:"";ee.textContent="Drop files into "+o+(t?" / "+t:"")}}function Pe(e){let t=Te();if(!t||ae||!e||!e.length)return;ae=!0;let o=re(),d=Array.from(e),c=0,l=0;ee.textContent="Uploading "+d.length+" file(s)\u2026";let E=M=>{if(M>=d.length){ae=!1,l&&T(l+" of "+d.length+" failed"),F(!0);return}let G=new FormData;G.append("file",d[M]),G.append("folder_path",o),fetch(t,{method:"POST",credentials:"same-origin",body:G}).then(A=>{if(!A.ok)throw new Error("http "+A.status);c++}).catch(()=>{l++}).then(()=>E(M+1))};E(0)}function Ye(e){return g.concat(P,I).find(t=>t.path===e)}return b.addEventListener("contextmenu",e=>{let t=!!j(),o=e.target.closest(".rk-dir-row"),d={top:e.clientY,bottom:e.clientY,left:e.clientX,right:e.clientX},c=[],l=o?Ye(o.getAttribute("data-path")||""):void 0;l&&l.kind==="folder"?(c.push({label:"Open folder",run:()=>U(l.path)}),Y(l.root)&&c.push({label:"New subfolder",run:()=>oe(l.folderPath)}),Y(l.root)&&c.push({label:"Rename",run:()=>ie(l)}),c.push({label:"Copy path",run:()=>R(l.path)})):l&&(v==="attach"&&c.push({label:"Attach",run:()=>L([l])}),l.viewUrl&&c.push({label:"View",run:()=>window.open(l.viewUrl,"_blank","noopener")}),l.viewUrl&&c.push({label:"Preview",run:()=>N(P,P.indexOf(l))}),l.root!=="raws"&&Y(l.root)&&l.id&&c.push({label:"Rename",run:()=>ie(l)}),c.push({label:"Copy path",run:()=>R(l.path)})),t&&Y(j())&&c.push({label:"New folder here",run:()=>oe()}),c.length&&(e.preventDefault(),Re(d,c))}),z.addEventListener("input",Be),y.addEventListener("click",e=>{(e.target===y||e.target===ee)&&B.click()}),B.addEventListener("change",()=>{Pe(B.files),B.value=""}),y.addEventListener("dragover",e=>{e.preventDefault(),y.classList.add("is-drag")}),y.addEventListener("dragleave",e=>{e.target===y&&y.classList.remove("is-drag")}),y.addEventListener("drop",e=>{e.preventDefault(),y.classList.remove("is-drag"),e.dataTransfer&&e.dataTransfer.files&&Pe(e.dataTransfer.files)}),(n.onNavigate||(()=>{}))(p),F(!0),{refresh:()=>F(!0),navigate:U,getSelection:()=>Array.from(k.values()),getCurrentPath:()=>p,destroy:()=>{H=!0,q&&q(),r.innerHTML=""}}}function Xe(r){return window.CSS&&window.CSS.escape?window.CSS.escape(r):r.replace(/["\\]/g,"\\$&")}var Ae="rk-dirpick-style";function Ge(){if(document.getElementById(Ae))return;let r=document.createElement("style");r.id=Ae,r.textContent=[".rk-dirpick{position:fixed;inset:0;z-index:1200;display:grid;place-items:center;padding:20px;","background:rgba(28,25,23,.44);backdrop-filter:blur(2px);animation:rk-dirpick-fade .16s ease}","@keyframes rk-dirpick-fade{from{opacity:0}to{opacity:1}}",".rk-dirpick-panel{width:min(560px,100%);max-height:min(82vh,700px);display:flex;flex-direction:column;","background:var(--rk-surface,#fff);border:1px solid var(--rk-border,#e6e0d6);border-radius:var(--rk-r-3xl,20px);","box-shadow:var(--rk-shadow-lg,0 24px 60px rgba(28,25,23,.28));overflow:hidden}",".rk-dirpick-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 18px;","border-bottom:1px solid var(--rk-border,#e6e0d6)}",".rk-dirpick-title{font-family:var(--rk-font-display,inherit);font-weight:800;font-size:15px;color:var(--rk-ink,#1c1917)}",".rk-dirpick-close{border:0;background:transparent;font-size:22px;line-height:1;color:var(--rk-text-muted,#78716c);cursor:pointer;padding:0 4px}",".rk-dirpick-close:hover{color:var(--rk-ink,#1c1917)}",".rk-dirpick-hint{padding:10px 18px 0;font-size:12.5px;line-height:1.4;color:var(--rk-text-muted,#78716c)}",".rk-dirpick-mount{padding:12px 14px;overflow:auto;flex:1;min-height:0}",".rk-dirpick-foot{display:flex;align-items:center;gap:10px;padding:12px 18px;border-top:1px solid var(--rk-border,#e6e0d6)}",".rk-dirpick-dest{flex:1;min-width:0;font-size:12.5px;color:var(--rk-text-muted,#78716c);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",".rk-dirpick-dest b{color:var(--rk-ink,#1c1917);font-weight:700}",".rk-dirpick-btn{flex:none;min-height:36px;padding:0 16px;border-radius:999px;border:0;cursor:pointer;","font:inherit;font-size:13px;font-weight:800;background:var(--rk-gold-500,var(--rk-gold-600,#fcb900));color:var(--rk-ink,#1c1917)}",".rk-dirpick-btn:hover:not(:disabled){background:var(--rk-gold-600,#e0a500)}",".rk-dirpick-btn:disabled{opacity:.5;cursor:default}",".rk-dirpick-btn.is-ghost{background:transparent;border:1px solid var(--rk-border,#e6e0d6);color:var(--rk-ink,#1c1917)}"].join(""),document.head.appendChild(r)}function Qe(r={}){Ge();let n=r.select==="folder"?"folder":"file",s=!1,a=null,h=i("div","rk-dirpick"),v=i("div","rk-dirpick-panel"),S=i("div","rk-dirpick-head");S.appendChild(i("span","rk-dirpick-title",r.title||(n==="folder"?"Choose a folder":"Choose a file")));let w=i("button","rk-dirpick-close");w.type="button",w.setAttribute("aria-label","Close"),w.innerHTML="&times;",S.appendChild(w),v.appendChild(S),r.hint&&v.appendChild(i("div","rk-dirpick-hint",r.hint));let x=i("div","rk-dirpick-mount");v.appendChild(x);let m=null,D=null;function f(p){s||(s=!0,R(),p?(r.onPick||(()=>{}))(p):(r.onCancel||(()=>{}))())}function L(p){let u=J(p);if(!u.root)return null;let g=u.folderPath||"",P=g?g.split("/").filter(Boolean).pop()||g:u.root;return{path:Z(u.root,g),root:u.root,folderPath:g,name:P,kind:"folder"}}function N(p){if(!m||!D)return;let u=L(p);if(u){m.innerHTML="",m.appendChild(document.createTextNode("Save to "));let g=i("b",void 0,u.path);m.appendChild(g),D.disabled=!1}else m.textContent="Open a folder (Files, Temp, \u2026) to choose a destination.",D.disabled=!0}if(n==="folder"){let p=i("div","rk-dirpick-foot");m=i("div","rk-dirpick-dest");let u=i("button","rk-dirpick-btn is-ghost","Cancel");u.type="button",u.addEventListener("click",()=>f(null)),D=i("button","rk-dirpick-btn",r.confirmLabel||"Use this folder"),D.type="button",D.addEventListener("click",()=>{let g=a?L(a.getCurrentPath()):null;g&&f(g)}),p.appendChild(m),p.appendChild(u),p.appendChild(D),v.appendChild(p)}h.appendChild(v),document.body.appendChild(h);function T(p){p.key==="Escape"&&f(null)}function R(){document.removeEventListener("keydown",T,!0);try{a&&a.destroy()}catch{}h.remove()}return w.addEventListener("click",()=>f(null)),h.addEventListener("click",p=>{p.target===h&&f(null)}),document.addEventListener("keydown",T,!0),a=me(x,{roots:r.roots,initialPath:r.initialPath,apiBase:r.apiBase,mode:"standalone",showSearch:!0,showMultiSelect:!1,showUpload:!1,primaryClick:n==="file"?"attach":"copyPath",onNavigate:p=>N(p),onAttach:p=>{if(n!=="file")return;let u=p&&p[0];if(u){if(r.accept&&!r.accept(u)){he(r.rejectMessage||"That file can't be used here.");return}f(u)}}}),{close:()=>f(null)}}function Ze(r){let n=r.dataset,s=(n.roots||"").split(",").map(a=>a.trim()).filter(Boolean);return{roots:s.length?s:void 0,initialPath:n.initialPath||void 0,mode:n.mode==="standalone"?"standalone":"attach",showSearch:n.showSearch!=="false",showMultiSelect:n.showMultiselect!=="false",showUpload:n.showUpload!=null?n.showUpload==="true":void 0,primaryClick:n.primaryClick||"copyPath",cloudAvailable:n.cloudAvailable!=null?n.cloudAvailable==="true":void 0}}function Ie(){Array.prototype.slice.call(document.querySelectorAll("[data-rk-directory]")).forEach(n=>{n.getAttribute("data-rk-dir-mounted")!=="1"&&(n.setAttribute("data-rk-dir-mounted","1"),window.__rkDirectoryInstance=me(n,Ze(n)))})}window.__vidfarmDirectory={mount:me,pick:Qe};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Ie):Ie();window.dispatchEvent(new CustomEvent("vidfarm:directory-ready"));export{me as createDirectoryExplorer,Qe as openDirectoryPicker};
1
+ var Ie=["files","temp","raws","projects","approved"],fe=[{key:"files",label:"My Files",description:"Durable personal files \u2014 brand assets, characters, saved context. Vector-searchable via notes."},{key:"temp",label:"Temp",description:"Scratch space, auto-organized by date (YYYY-MM-DD) and auto-deleted after 30 days."},{key:"raws",label:"Raws",description:"The reusable clip / source-footage library, organized into folders by source."},{key:"projects",label:"Projects",description:"Your video-editing projects \u2014 one folder per fork, holding that composition's working files (composition.html/json, cast, media) and saved versions. Read-only: browse to reference or study another fork."},{key:"approved",label:"Approved",description:"Finished, ready-to-post cuts, organized into folders (defaults to a folder per tracer/campaign)."}];function Je(r){return r==="files"||r==="temp"||r==="raws"||r==="projects"||r==="approved"}function he(r){return String(r??"").split("/").map(n=>n.trim()).filter(Boolean).join("/")}function $(r){let n=String(r??"").split("/").map(h=>h.trim()).filter(Boolean);if(n.length===0)return{root:null,folderPath:"",segments:[]};let[c,...a]=n;return Je(c)?{root:c,folderPath:a.join("/"),segments:a}:{root:null,folderPath:"",segments:n}}function X(r,n,c){let a=[r,he(n)];return c&&a.push(String(c).trim()),"/"+a.filter(Boolean).join("/")}var Ve="/api/v1/user/me";function i(r,n,c){let a=document.createElement(r);return n&&(a.className=n),c!=null&&(a.textContent=c),a}function $e(r){if(!r||r<=0)return"";let n=["B","KB","MB","GB"],c=r,a=0;for(;c>=1024&&a<n.length-1;)c/=1024,a++;return(c>=10||a===0?Math.round(c):c.toFixed(1))+" "+n[a]}function Xe(r){if(typeof r!="number"||!(r>0))return"";r=Math.round(r);let n=Math.floor(r/60),c=r%60;return n+":"+(c<10?"0"+c:c)}function He(r){let n=i("span","rk-aichat-fic "+(r.kind==="folder"?"rk-aichat-fic-folder":"rk-aichat-fic-file"));if(r.kind==="folder")return n.textContent="/",n;if(r.thumbUrl){let a=i("img");return a.src=r.thumbUrl,a.alt="",a.loading="lazy",n.appendChild(a),n}let c=r.contentType||"";if(r.viewUrl&&c.indexOf("image/")===0){let a=i("img");return a.src=r.viewUrl,a.alt="",a.loading="lazy",n.appendChild(a),n}if(r.viewUrl&&c.indexOf("video/")===0){let a=i("video");return a.src=r.viewUrl,a.muted=!0,a.playsInline=!0,n.appendChild(a),n}return n.textContent=(r.name.split(".").pop()||r.name.slice(0,1)||"?").slice(0,3).toUpperCase(),n}var me;function be(r){let n=document.getElementById("rk-dir-toast");n||(n=i("div"),n.id="rk-dir-toast",n.className="rk-dir-toast",document.body.appendChild(n)),n.textContent=r,n.classList.add("is-on"),me&&window.clearTimeout(me),me=window.setTimeout(()=>n&&n.classList.remove("is-on"),1800)}function Ge(r){return navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(r):new Promise((n,c)=>{try{let a=i("textarea");a.value=r,a.style.position="fixed",a.style.opacity="0",document.body.appendChild(a),a.select(),document.execCommand("copy"),document.body.removeChild(a),n()}catch(a){c(a)}})}var J=null;function ge(r,n){J&&J();let c=i("div","rk-dir-menu");n.forEach(f=>{let P=i("button","rk-dir-menuitem"+(f.danger?" is-danger":""),f.label);P.type="button",P.addEventListener("click",N=>{N.stopPropagation(),E(),f.run()}),c.appendChild(P)}),document.body.appendChild(c);let a=r instanceof HTMLElement?r.getBoundingClientRect():r,h=c.offsetWidth,y=c.offsetHeight,A=a.bottom+4,v=a.right-h;v<8&&(v=a.left),A+y>window.innerHeight-8&&(A=Math.max(8,a.top-y-4)),c.style.top=A+"px",c.style.left=Math.max(8,v)+"px";function E(){c.remove(),document.removeEventListener("click",m,!0),document.removeEventListener("keydown",L,!0),window.removeEventListener("scroll",E,!0),J===E&&(J=null)}function m(f){c.contains(f.target)||E()}function L(f){f.key==="Escape"&&E()}setTimeout(()=>{document.addEventListener("click",m,!0),document.addEventListener("keydown",L,!0),window.addEventListener("scroll",E,!0)},0),J=E}function ke(r,n={}){let c=n.apiBase||Ve,a=n.roots&&n.roots.length?n.roots:Ie.slice(),h=a.length===1?a[0]:null,y=n.mode||"attach",A=n.showSearch!==!1,v=n.showMultiSelect!==!1,E=n.showUpload!=null?n.showUpload:y==="attach",m=n.primaryClick||"copyPath",L=n.cloudAvailable!=null?n.cloudAvailable:typeof window<"u"&&window.__vidfarmCloudSpace===!0,f=window.__rkDirectoryHost||{},P=e=>(n.onAttach||f.onAttach||(()=>be("Attached "+e.length+" item(s)")))(e),N=(e,t)=>{let o=n.onPreview||f.onPreview;o?o(e,t):e[t]&&e[t].viewUrl&&window.open(e[t].viewUrl,"_blank","noopener")},T=e=>(n.onToast||f.onToast||be)(e),R=e=>Ge(e).then(()=>T("Copied "+e)).catch(()=>T("Couldn't copy path")),p=Be(n.initialPath,h),u="idle",g=[],M=[],G=null,V=!1,w=new Map,Q=!1,B=[],Z="idle",U=!1,de="local";function ye(){return de==="cloud"?"/cloud":""}function Be(e,t){let o=$(e||"");return o.root?X(o.root,o.folderPath):t?"/"+t:"/"}r.classList.add("rk-dir"),r.innerHTML="";let ve=i("div","rk-dir-search"),z=i("input","rk-dir-search-input");z.type="search",z.placeholder="Search files \u2014 meaning, name, or path\u2026",ve.appendChild(z);let j=i("div","rk-aichat-crumbs rk-dir-crumbs"),Y=i("div","rk-dir-selbar");Y.hidden=!0;let b=i("div","rk-aichat-files-body rk-dir-body"),k=i("label","rk-aichat-drop rk-dir-drop");k.hidden=!0;let te=i("span","rk-aichat-drop-text","Drop files here"),F=i("input");F.type="file",F.multiple=!0,F.hidden=!0,k.appendChild(te),k.appendChild(F);let ce=i("div","rk-dir-space"),ne=i("button","rk-dir-space-btn is-on","Local"),re=i("button","rk-dir-space-btn","Cloud");ne.type="button",re.type="button",ce.appendChild(ne),ce.appendChild(re);function we(e){de!==e&&(de=e,ne.classList.toggle("is-on",e==="local"),re.classList.toggle("is-on",e==="cloud"),Q=!1,B=[],z.value="",w.clear(),p=h?"/"+h:"/",u="idle",K(!0))}ne.addEventListener("click",()=>we("local")),re.addEventListener("click",()=>we("cloud")),L&&r.appendChild(ce),A&&r.appendChild(ve),r.appendChild(j),v&&r.appendChild(Y),r.appendChild(b),E&&r.appendChild(k);function Ce(e,t){let o=new URL(c+ye()+"/directory",window.location.href);return o.searchParams.set("path",e),t&&o.searchParams.set("offset",String(t)),o.toString()}function K(e){if(!U){if(!e&&u==="ready"){C();return}u="loading",C(),fetch(Ce(p),{credentials:"same-origin",headers:{accept:"application/json"}}).then(t=>{if(t.status===401||t.status===403)return u="auth",null;if(!t.ok)throw new Error("http "+t.status);return t.json()}).then(t=>{if(!U){if(!t){C();return}g=Ue(t.folders||[]),M=t.files||[],G=typeof t.next_offset=="number"?t.next_offset:null,u="ready",C()}}).catch(()=>{U||(u="error",C())})}}function Ue(e){return p!=="/"?e:e.filter(t=>a.indexOf(t.root)!==-1)}function je(){G==null||V||(V=!0,C(),fetch(Ce(p,G),{credentials:"same-origin",headers:{accept:"application/json"}}).then(e=>e.ok?e.json():null).then(e=>{if(V=!1,U||!e){C();return}M=M.concat(e.files||[]),G=typeof e.next_offset=="number"?e.next_offset:null,C()}).catch(()=>{V=!1,C()}))}let se;function Fe(){let e=z.value.trim();if(se&&window.clearTimeout(se),!e){Q=!1,B=[],C();return}se=window.setTimeout(()=>Ne(e),260)}function Ne(e){Q=!0,Z="loading",C();let t=h?"/"+h:p!=="/"?p:"";fetch(c+ye()+"/directory/search",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:e,path:t,mode:"auto",limit:40})}).then(o=>o.ok?o.json():null).then(o=>{U||(B=o&&o.results||[],Z="ready",C())}).catch(()=>{U||(Z="error",C())})}function I(e){let t=$(e);p=t.root?X(t.root,t.folderPath):"/",u="idle",Q=!1,z.value="",(n.onNavigate||(()=>{}))(p),K(!0)}function H(){return $(p).root}function oe(){return $(p).folderPath}function q(e){return!!e&&e!=="projects"}function ie(e){let t=H();if(!t){T("Open a root (/files, /temp, /raws) first");return}if(!q(t)){T("/projects is read-only");return}let o=(window.prompt("New folder name")||"").trim();if(!o)return;let s=he(e??oe()),l=X(t,s?s+"/"+o:o);fetch(c+"/directory/folders",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:l})}).then(d=>d.ok?d.json():d.json().then(x=>Promise.reject(new Error(x.error||"http "+d.status)))).then(d=>{I(d.path||(t===H()?p:"/"+t)),T("Created "+(d.path||o))}).catch(d=>T(d.message||"Couldn't create folder"))}function ae(e){let t=e.kind==="folder",o=(window.prompt(t?"Rename folder":"Rename file",e.name)||"").trim();!o||o===e.name||fetch(c+"/directory/rename",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:e.path,new_name:o,...t?{}:{file_id:e.id}})}).then(s=>s.ok?s.json():s.json().then(l=>Promise.reject(new Error(l.error||"http "+s.status)))).then(()=>{w.has(e.path)&&(w.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(w.values()))),K(!0),T("Renamed to "+o)}).catch(s=>T(s.message||"Couldn't rename"))}function ze(e,t){t?w.set(e.path,e):w.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(w.values())),De();let o=b.querySelector('[data-path="'+Qe(e.path)+'"]');o&&o.classList.toggle("is-selected",t)}function xe(){w.clear(),(n.onSelectionChange||(()=>{}))([]),C()}function pe(e,t,o){let s=i("button","rk-aichat-crumb"+(t?" is-current":""),e);return s.type="button",s.addEventListener("click",o),s}function Ye(){j.innerHTML="";let e=H(),t=oe();if(h||j.appendChild(pe("Files",p==="/",()=>I("/"))),!e)return;let o=(fe.find(l=>l.key===e)||{label:e}).label;h||j.appendChild(Ee()),j.appendChild(pe(o,!t,()=>I("/"+e)));let s="";if(t.split("/").filter(Boolean).forEach((l,d,x)=>{j.appendChild(Ee()),s=s?s+"/"+l:l;let S="/"+e+"/"+s;j.appendChild(pe(l,d===x.length-1,()=>I(S)))}),q(e)){let l=i("button","rk-dir-newfolder","+ Folder");l.type="button",l.title="New folder here (or right-click)",l.addEventListener("click",()=>ie()),j.appendChild(l)}}function Ee(){return i("span","rk-aichat-crumb-sep","/")}function De(){if(!v)return;let e=w.size;if(Y.hidden=e===0,e===0)return;Y.innerHTML="",Y.appendChild(i("span","rk-dir-selcount",e+" selected"));let t=()=>Array.from(w.values()),o=i("button","rk-dir-selbtn is-primary","Copy paths");o.type="button",o.addEventListener("click",()=>R(t().map(d=>d.path).join(`
2
+ `))),Y.appendChild(o);let s=[];y==="attach"&&s.push({label:"Attach",run:()=>{P(t()),xe()}}),s.push({label:"Copy paths",run:()=>R(t().map(d=>d.path).join(`
3
+ `))}),s.push({label:"Clear selection",run:xe});let l=i("button","rk-dir-selbtn is-ghost rk-dir-selmore","\u22EF");l.type="button",l.setAttribute("aria-label","More actions"),l.addEventListener("click",d=>{d.stopPropagation(),ge(l,s)}),Y.appendChild(l)}function Le(e){let t=i("input","rk-dir-check");return t.type="checkbox",t.checked=w.has(e.path),t.setAttribute("aria-label","Select "+e.name),t.addEventListener("click",o=>o.stopPropagation()),t.addEventListener("change",()=>ze(e,t.checked)),t}function Pe(e){let t=i("div","rk-aichat-frow rk-dir-row"+(w.has(e.path)?" is-selected":""));t.setAttribute("data-path",e.path),v&&t.appendChild(Le(e));let o=i("button","rk-aichat-fmainbtn");o.type="button",o.title="Copy path "+e.path,o.appendChild(He(e));let s=i("span","rk-aichat-fmain");s.appendChild(i("span","rk-aichat-fname",e.name));let l=e.meta&&typeof e.meta.description=="string"?e.meta.description:"";s.appendChild(i("span","rk-aichat-fmeta",l||"folder")),o.appendChild(s),o.addEventListener("click",()=>R(e.path)),t.appendChild(o);let d=i("button","rk-aichat-fadd rk-dir-open","Open \u203A");d.type="button",d.title="Open folder",d.addEventListener("click",S=>{S.stopPropagation(),I(e.path)}),t.appendChild(d);let x=[{label:"Open folder",run:()=>I(e.path)}];return q(e.root)&&(x.push({label:"New subfolder",run:()=>ie(e.folderPath)}),x.push({label:"Rename",run:()=>ae(e)})),x.push({label:"Copy path",run:()=>R(e.path)}),t.appendChild(Me(e,x)),t}function Te(e,t,o,s){let l=i("div","rk-aichat-frow rk-dir-row"+(w.has(e.path)?" is-selected":""));l.setAttribute("data-path",e.path),v&&l.appendChild(Le(e));let d=i("button","rk-aichat-fmainbtn");d.type="button";let x=m==="copyPath"?"Copy path ":m==="attach"?"Attach ":"Preview ";d.title=x+e.name,d.appendChild(He(e));let S=i("span","rk-aichat-fmain");S.appendChild(i("span","rk-aichat-fname",e.name));let ue=s?e.path:Xe(e.durationSec)||$e(e.sizeBytes)||e.contentType||"file";if(S.appendChild(i("span","rk-aichat-fmeta",ue)),d.appendChild(S),d.addEventListener("click",()=>{m==="attach"?P([e]):m==="preview"?N(t,o):R(e.path)}),l.appendChild(d),y==="attach"&&m==="preview"){let D=i("button","rk-aichat-fadd rk-dir-attach","+");D.type="button",D.title="Attach "+e.name,D.setAttribute("aria-label","Attach "+e.name),D.addEventListener("click",ee=>{ee.stopPropagation(),P([e])}),l.appendChild(D)}let O=[];return y==="attach"&&O.push({label:"Attach",run:()=>P([e])}),e.viewUrl&&O.push({label:"View",run:()=>window.open(e.viewUrl,"_blank","noopener")}),e.viewUrl&&O.push({label:"Preview",run:()=>N(t,o)}),(e.root==="files"||e.root==="temp")&&e.id&&O.push({label:"Rename",run:()=>ae(e)}),O.push({label:"Copy path",run:()=>R(e.path)}),l.appendChild(Me(e,O)),l}function Me(e,t){let o=i("button","rk-dir-kebab","\u22EF");return o.type="button",o.setAttribute("aria-label","More actions"),o.addEventListener("click",s=>{s.stopPropagation(),ge(o,t)}),o}function W(e,t,o){let s=i("div","rk-aichat-fstate");if(s.appendChild(i("div",void 0,e)),t){let l=i("a");l.href=t.href,l.textContent=t.label,s.appendChild(l)}if(o){let l=i("button",void 0,"Try again");l.type="button",l.addEventListener("click",()=>K(!0)),s.appendChild(l)}return s}function C(){if(!U){if(Ye(),De(),qe(),b.innerHTML="",Q){Ke();return}if(u==="loading"&&!M.length&&!g.length){b.appendChild(W("Loading your files\u2026"));return}if(u==="auth"){b.appendChild(W("Sign in to browse your files.",{href:"/login",label:"Sign in"}));return}if(u==="error"){b.appendChild(W("Couldn't reach your files.",void 0,!0));return}if(!g.length&&!M.length){b.appendChild(W(p==="/"?"No files yet.":"This folder is empty."));return}if(g.forEach(e=>b.appendChild(Pe(e))),M.forEach((e,t)=>b.appendChild(Te(e,M,t))),G!=null){let e=i("button","rk-aichat-loadmore",V?"Loading\u2026":"Load more");e.type="button",e.disabled=V,e.addEventListener("click",je),b.appendChild(e)}}}function Ke(){if(Z==="loading"&&!B.length){b.appendChild(W("Searching\u2026"));return}if(Z==="error"){b.appendChild(W("Search failed."));return}if(!B.length){b.appendChild(W("No matches."));return}let e=B.filter(t=>t.kind!=="folder");B.forEach((t,o)=>{t.kind==="folder"?b.appendChild(Pe(t)):b.appendChild(Te(t,e,e.indexOf(t),!0))})}let le=!1;function Se(){let e=H();return e==="files"?c+"/attachments/upload":e==="temp"?c+"/temporary-files/upload":null}function qe(){if(!E)return;let e=Se();if(k.hidden=!e||u==="auth",!k.hidden&&!le){let t=oe(),o=H()?(fe.find(s=>s.key===H())||{label:""}).label:"";te.textContent="Drop files into "+o+(t?" / "+t:"")}}function Re(e){let t=Se();if(!t||le||!e||!e.length)return;le=!0;let o=oe(),s=H(),l=Array.from(e),d=0,x=0,S=null;te.textContent="Uploading "+l.length+" file(s)\u2026";let ue=()=>{le=!1,x&&T(x+" of "+l.length+" failed");let D=s&&S!=null?X(s,S):null;D&&D!==p?I(D):K(!0)},O=D=>{if(D>=l.length){ue();return}let ee=new FormData;ee.append("file",l[D]),ee.append("folder_path",o),fetch(t,{method:"POST",credentials:"same-origin",body:ee}).then(_=>{if(!_.ok)throw new Error("http "+_.status);return _.json().catch(()=>null)}).then(_=>{d++;let Ae=_&&((_.file&&_.file.folderPath)??(_.attachment&&_.attachment.folderPath));typeof Ae=="string"&&S==null&&(S=Ae)}).catch(()=>{x++}).then(()=>O(D+1))};O(0)}function We(e){return g.concat(M,B).find(t=>t.path===e)}return b.addEventListener("contextmenu",e=>{let t=!!H(),o=e.target.closest(".rk-dir-row"),s={top:e.clientY,bottom:e.clientY,left:e.clientX,right:e.clientX},l=[],d=o?We(o.getAttribute("data-path")||""):void 0;d&&d.kind==="folder"?(l.push({label:"Open folder",run:()=>I(d.path)}),q(d.root)&&l.push({label:"New subfolder",run:()=>ie(d.folderPath)}),q(d.root)&&l.push({label:"Rename",run:()=>ae(d)}),l.push({label:"Copy path",run:()=>R(d.path)})):d&&(y==="attach"&&l.push({label:"Attach",run:()=>P([d])}),d.viewUrl&&l.push({label:"View",run:()=>window.open(d.viewUrl,"_blank","noopener")}),d.viewUrl&&l.push({label:"Preview",run:()=>N(M,M.indexOf(d))}),d.root!=="raws"&&q(d.root)&&d.id&&l.push({label:"Rename",run:()=>ae(d)}),l.push({label:"Copy path",run:()=>R(d.path)})),t&&q(H())&&l.push({label:"New folder here",run:()=>ie()}),l.length&&(e.preventDefault(),ge(s,l))}),z.addEventListener("input",Fe),k.addEventListener("click",e=>{(e.target===k||e.target===te)&&F.click()}),F.addEventListener("change",()=>{Re(F.files),F.value=""}),k.addEventListener("dragover",e=>{e.preventDefault(),k.classList.add("is-drag")}),k.addEventListener("dragleave",e=>{e.target===k&&k.classList.remove("is-drag")}),k.addEventListener("drop",e=>{e.preventDefault(),k.classList.remove("is-drag"),e.dataTransfer&&e.dataTransfer.files&&Re(e.dataTransfer.files)}),(n.onNavigate||(()=>{}))(p),K(!0),{refresh:()=>K(!0),navigate:I,getSelection:()=>Array.from(w.values()),getCurrentPath:()=>p,destroy:()=>{U=!0,J&&J(),r.innerHTML=""}}}function Qe(r){return window.CSS&&window.CSS.escape?window.CSS.escape(r):r.replace(/["\\]/g,"\\$&")}var Oe="rk-dirpick-style";function Ze(){if(document.getElementById(Oe))return;let r=document.createElement("style");r.id=Oe,r.textContent=[".rk-dirpick{position:fixed;inset:0;z-index:1200;display:grid;place-items:center;padding:20px;","background:rgba(28,25,23,.44);backdrop-filter:blur(2px);animation:rk-dirpick-fade .16s ease}","@keyframes rk-dirpick-fade{from{opacity:0}to{opacity:1}}",".rk-dirpick-panel{width:min(560px,100%);max-height:min(82vh,700px);display:flex;flex-direction:column;","background:var(--rk-surface,#fff);border:1px solid var(--rk-border,#e6e0d6);border-radius:var(--rk-r-3xl,20px);","box-shadow:var(--rk-shadow-lg,0 24px 60px rgba(28,25,23,.28));overflow:hidden}",".rk-dirpick-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 18px;","border-bottom:1px solid var(--rk-border,#e6e0d6)}",".rk-dirpick-title{font-family:var(--rk-font-display,inherit);font-weight:800;font-size:15px;color:var(--rk-ink,#1c1917)}",".rk-dirpick-close{border:0;background:transparent;font-size:22px;line-height:1;color:var(--rk-text-muted,#78716c);cursor:pointer;padding:0 4px}",".rk-dirpick-close:hover{color:var(--rk-ink,#1c1917)}",".rk-dirpick-hint{padding:10px 18px 0;font-size:12.5px;line-height:1.4;color:var(--rk-text-muted,#78716c)}",".rk-dirpick-mount{padding:12px 14px;overflow:auto;flex:1;min-height:0}",".rk-dirpick-foot{display:flex;align-items:center;gap:10px;padding:12px 18px;border-top:1px solid var(--rk-border,#e6e0d6)}",".rk-dirpick-dest{flex:1;min-width:0;font-size:12.5px;color:var(--rk-text-muted,#78716c);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",".rk-dirpick-dest b{color:var(--rk-ink,#1c1917);font-weight:700}",".rk-dirpick-btn{flex:none;min-height:36px;padding:0 16px;border-radius:999px;border:0;cursor:pointer;","font:inherit;font-size:13px;font-weight:800;background:var(--rk-gold-500,var(--rk-gold-600,#fcb900));color:var(--rk-ink,#1c1917)}",".rk-dirpick-btn:hover:not(:disabled){background:var(--rk-gold-600,#e0a500)}",".rk-dirpick-btn:disabled{opacity:.5;cursor:default}",".rk-dirpick-btn.is-ghost{background:transparent;border:1px solid var(--rk-border,#e6e0d6);color:var(--rk-ink,#1c1917)}"].join(""),document.head.appendChild(r)}function et(r={}){Ze();let n=r.select==="folder"?"folder":"file",c=!1,a=null,h=i("div","rk-dirpick"),y=i("div","rk-dirpick-panel"),A=i("div","rk-dirpick-head");A.appendChild(i("span","rk-dirpick-title",r.title||(n==="folder"?"Choose a folder":"Choose a file")));let v=i("button","rk-dirpick-close");v.type="button",v.setAttribute("aria-label","Close"),v.innerHTML="&times;",A.appendChild(v),y.appendChild(A),r.hint&&y.appendChild(i("div","rk-dirpick-hint",r.hint));let E=i("div","rk-dirpick-mount");y.appendChild(E);let m=null,L=null;function f(p){c||(c=!0,R(),p?(r.onPick||(()=>{}))(p):(r.onCancel||(()=>{}))())}function P(p){let u=$(p);if(!u.root)return null;let g=u.folderPath||"",M=g?g.split("/").filter(Boolean).pop()||g:u.root;return{path:X(u.root,g),root:u.root,folderPath:g,name:M,kind:"folder"}}function N(p){if(!m||!L)return;let u=P(p);if(u){m.innerHTML="",m.appendChild(document.createTextNode("Save to "));let g=i("b",void 0,u.path);m.appendChild(g),L.disabled=!1}else m.textContent="Open a folder (Files, Temp, \u2026) to choose a destination.",L.disabled=!0}if(n==="folder"){let p=i("div","rk-dirpick-foot");m=i("div","rk-dirpick-dest");let u=i("button","rk-dirpick-btn is-ghost","Cancel");u.type="button",u.addEventListener("click",()=>f(null)),L=i("button","rk-dirpick-btn",r.confirmLabel||"Use this folder"),L.type="button",L.addEventListener("click",()=>{let g=a?P(a.getCurrentPath()):null;g&&f(g)}),p.appendChild(m),p.appendChild(u),p.appendChild(L),y.appendChild(p)}h.appendChild(y),document.body.appendChild(h);function T(p){p.key==="Escape"&&f(null)}function R(){document.removeEventListener("keydown",T,!0);try{a&&a.destroy()}catch{}h.remove()}return v.addEventListener("click",()=>f(null)),h.addEventListener("click",p=>{p.target===h&&f(null)}),document.addEventListener("keydown",T,!0),a=ke(E,{roots:r.roots,initialPath:r.initialPath,apiBase:r.apiBase,mode:"standalone",showSearch:!0,showMultiSelect:!1,showUpload:r.allowUpload===!0,primaryClick:n==="file"?"attach":"copyPath",onNavigate:p=>N(p),onAttach:p=>{if(n!=="file")return;let u=p&&p[0];if(u){if(r.accept&&!r.accept(u)){be(r.rejectMessage||"That file can't be used here.");return}f(u)}}}),{close:()=>f(null)}}function tt(r){let n=r.dataset,c=(n.roots||"").split(",").map(a=>a.trim()).filter(Boolean);return{roots:c.length?c:void 0,initialPath:n.initialPath||void 0,mode:n.mode==="standalone"?"standalone":"attach",showSearch:n.showSearch!=="false",showMultiSelect:n.showMultiselect!=="false",showUpload:n.showUpload!=null?n.showUpload==="true":void 0,primaryClick:n.primaryClick||"copyPath",cloudAvailable:n.cloudAvailable!=null?n.cloudAvailable==="true":void 0}}function _e(){Array.prototype.slice.call(document.querySelectorAll("[data-rk-directory]")).forEach(n=>{n.getAttribute("data-rk-dir-mounted")!=="1"&&(n.setAttribute("data-rk-dir-mounted","1"),window.__rkDirectoryInstance=ke(n,tt(n)))})}window.__vidfarmDirectory={mount:ke,pick:et};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",_e):_e();window.dispatchEvent(new CustomEvent("vidfarm:directory-ready"));export{ke as createDirectoryExplorer,et as openDirectoryPicker};