@rslsp1/fa-app-tools 1.2.2 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -445,6 +445,6 @@ declare function buildLoopInstruction(rounds: Array<{
445
445
  declare function autoLabel(index: number): string;
446
446
  declare function buildReferenceImageMediaIds(images: SelectedLabImage[]): string[];
447
447
 
448
- declare const LIB_VERSION = "1.2.2";
448
+ declare const LIB_VERSION = "1.2.3";
449
449
 
450
450
  export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, LIB_VERSION, LabBlend, LabCompare, type LabFrame, LabImagePicker, type LabItem, LabLoop, LabRemix, type LabServices, LabsTab, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectMeta, type ProjectSettings, ProjectSyncTab, PromptTab, SectionLabel, type SelectedLabImage, type SelectedTag, SetupPanel, type SyncDiff, TagManagerPanel, type TagOption, type WorkspaceTags, autoLabel, buildBlendInstruction, buildCompareInstruction, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildLoopInstruction, buildPromptTabPayload, buildReferenceImageMediaIds, buildRemixInstruction, buildScanInstruction, cleanAiResponse, createFlowServices, exportProjectToZip, formatTreeToMarkdown, frameToGeneration, getFormattedTimestamp, groupGenerationsToLabItems, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
package/dist/index.d.ts CHANGED
@@ -445,6 +445,6 @@ declare function buildLoopInstruction(rounds: Array<{
445
445
  declare function autoLabel(index: number): string;
446
446
  declare function buildReferenceImageMediaIds(images: SelectedLabImage[]): string[];
447
447
 
448
- declare const LIB_VERSION = "1.2.2";
448
+ declare const LIB_VERSION = "1.2.3";
449
449
 
450
450
  export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, LIB_VERSION, LabBlend, LabCompare, type LabFrame, LabImagePicker, type LabItem, LabLoop, LabRemix, type LabServices, LabsTab, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectMeta, type ProjectSettings, ProjectSyncTab, PromptTab, SectionLabel, type SelectedLabImage, type SelectedTag, SetupPanel, type SyncDiff, TagManagerPanel, type TagOption, type WorkspaceTags, autoLabel, buildBlendInstruction, buildCompareInstruction, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildLoopInstruction, buildPromptTabPayload, buildReferenceImageMediaIds, buildRemixInstruction, buildScanInstruction, cleanAiResponse, createFlowServices, exportProjectToZip, formatTreeToMarkdown, frameToGeneration, getFormattedTimestamp, groupGenerationsToLabItems, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
package/dist/index.js CHANGED
@@ -738,34 +738,52 @@ var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagTogg
738
738
  var import_react7 = require("react");
739
739
  var import_react8 = require("motion/react");
740
740
  var import_jsx_runtime7 = require("react/jsx-runtime");
741
+ var PRESET_URLS = [
742
+ "https://jsonplaceholder.typicode.com/todos/1",
743
+ "https://huggingface.co/api/whoami-v2",
744
+ "https://esm.sh/@rslsp1/fa-app-tools@latest"
745
+ ];
741
746
  var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
742
747
  const workspaceInputRef = (0, import_react7.useRef)(null);
743
- const blobTestInputRef = (0, import_react7.useRef)(null);
744
- const [blobStatus, setBlobStatus] = (0, import_react7.useState)("idle");
745
- const [blobThumb, setBlobThumb] = (0, import_react7.useState)(null);
746
- const [blobError, setBlobError] = (0, import_react7.useState)(null);
747
- const handleBlobTest = async (file) => {
748
- setBlobStatus("loading");
749
- setBlobThumb(null);
750
- setBlobError(null);
751
- const blobUrl = URL.createObjectURL(file);
748
+ const [urlInput, setUrlInput] = (0, import_react7.useState)("");
749
+ const [testStatus, setTestStatus] = (0, import_react7.useState)("idle");
750
+ const [result, setResult] = (0, import_react7.useState)(null);
751
+ const [fetchError, setFetchError] = (0, import_react7.useState)(null);
752
+ const runTest = async (url) => {
753
+ if (!url.trim()) return;
754
+ setTestStatus("loading");
755
+ setResult(null);
756
+ setFetchError(null);
757
+ const t0 = Date.now();
752
758
  try {
753
- const res = await fetch(blobUrl);
754
- if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
755
- const blob = await res.blob();
756
- const dataUrl = await new Promise((resolve, reject) => {
757
- const reader = new FileReader();
758
- reader.onload = () => resolve(reader.result);
759
- reader.onerror = () => reject(new Error("FileReader failed"));
760
- reader.readAsDataURL(blob);
759
+ const res = await fetch(url.trim());
760
+ const durationMs = Date.now() - t0;
761
+ const contentType = res.headers.get("content-type") || "";
762
+ const headers = {};
763
+ res.headers.forEach((v, k) => {
764
+ headers[k] = v;
761
765
  });
762
- setBlobThumb(dataUrl);
763
- setBlobStatus("ok");
766
+ const blob = await res.blob();
767
+ const bodySize = blob.size;
768
+ const isImage = contentType.startsWith("image/");
769
+ let bodyPreview = "";
770
+ let imageDataUrl;
771
+ if (isImage) {
772
+ imageDataUrl = await new Promise((resolve, reject) => {
773
+ const reader = new FileReader();
774
+ reader.onload = () => resolve(reader.result);
775
+ reader.onerror = reject;
776
+ reader.readAsDataURL(blob);
777
+ });
778
+ } else {
779
+ const text = await blob.text();
780
+ bodyPreview = text.slice(0, 500);
781
+ }
782
+ setResult({ status: res.status, statusText: res.statusText, contentType, headers, bodyPreview, isImage, imageDataUrl, bodySize, durationMs });
783
+ setTestStatus("ok");
764
784
  } catch (e) {
765
- setBlobError(e.message || String(e));
766
- setBlobStatus("error");
767
- } finally {
768
- URL.revokeObjectURL(blobUrl);
785
+ setFetchError(e.message || String(e));
786
+ setTestStatus("error");
769
787
  }
770
788
  };
771
789
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react8.motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "absolute inset-0 p-6 flex flex-col gap-10 overflow-y-auto", children: [
@@ -783,42 +801,87 @@ var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
783
801
  ] }),
784
802
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-3", children: [
785
803
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-1", children: [
786
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionLabel, { children: "blob: URL Test" }),
787
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Testet ob fetch() auf blob: URLs funktioniert \u2014 lokale Datei \u2192 createObjectURL \u2192 fetch \u2192 base64." })
804
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionLabel, { children: "URL Fetch Diagnose" }),
805
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Testet ob fetch() auf externe URLs funktioniert." })
788
806
  ] }),
789
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
790
- PillButton,
791
- {
792
- variant: "outline",
793
- icon: blobStatus === "loading" ? "sync" : "image_search",
794
- onClick: () => blobTestInputRef.current?.click(),
795
- children: "Bild w\xE4hlen & testen"
796
- }
797
- ),
798
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
799
- "input",
807
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex flex-col gap-1", children: PRESET_URLS.map((u) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
808
+ "button",
800
809
  {
801
- ref: blobTestInputRef,
802
- type: "file",
803
- accept: "image/*",
804
- className: "hidden",
805
- onChange: (e) => {
806
- const f = e.target.files?.[0];
807
- if (f) handleBlobTest(f);
808
- e.target.value = "";
810
+ onClick: () => {
811
+ setUrlInput(u);
812
+ runTest(u);
813
+ },
814
+ className: "text-left px-2 py-1 rounded bg-white/3 border border-white/5 text-[9px] text-white/40 hover:text-white/70 hover:bg-white/6 font-mono truncate transition",
815
+ children: u
816
+ },
817
+ u
818
+ )) }),
819
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex gap-2", children: [
820
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
821
+ "input",
822
+ {
823
+ value: urlInput,
824
+ onChange: (e) => setUrlInput(e.target.value),
825
+ onKeyDown: (e) => e.key === "Enter" && runTest(urlInput),
826
+ placeholder: "https://...",
827
+ className: "flex-1 bg-white/5 border border-white/10 rounded-xl px-3 py-2 text-[11px] text-white/80 outline-none focus:border-white/20 placeholder:text-white/20 font-mono"
809
828
  }
810
- }
811
- ),
812
- blobStatus === "ok" && blobThumb && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-2", children: [
813
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { src: blobThumb, alt: "blob test", className: "w-full max-h-48 object-contain rounded-xl border border-white/10 bg-black/40" }),
814
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "text-[10px] text-green-400 font-mono flex items-center gap-1", children: [
815
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "check_circle" }),
816
- "blob: fetch \u2713 \u2014 base64 erfolgreich"
829
+ ),
830
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
831
+ "button",
832
+ {
833
+ onClick: () => runTest(urlInput),
834
+ disabled: testStatus === "loading" || !urlInput.trim(),
835
+ className: "px-3 py-2 bg-white/10 hover:bg-white/15 border border-white/10 rounded-xl text-white/60 transition disabled:opacity-40 shrink-0",
836
+ children: testStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[16px] animate-spin", children: "sync" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "send" })
837
+ }
838
+ )
839
+ ] }),
840
+ testStatus === "ok" && result && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-2 bg-white/3 border border-white/8 rounded-xl p-3 text-[10px] font-mono", children: [
841
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", children: [
842
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: `font-bold ${result.status < 400 ? "text-green-400" : "text-red-400"}`, children: [
843
+ result.status,
844
+ " ",
845
+ result.statusText
846
+ ] }),
847
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-white/30", children: "\xB7" }),
848
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "text-white/50", children: [
849
+ result.durationMs,
850
+ "ms"
851
+ ] }),
852
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-white/30", children: "\xB7" }),
853
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "text-white/50", children: [
854
+ (result.bodySize / 1024).toFixed(1),
855
+ " KB"
856
+ ] })
857
+ ] }),
858
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "text-white/40", children: [
859
+ "Content-Type: ",
860
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-white/70", children: result.contentType })
861
+ ] }),
862
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { className: "cursor-pointer", children: [
863
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("summary", { className: "text-white/30 hover:text-white/60 transition", children: [
864
+ "Headers (",
865
+ Object.keys(result.headers).length,
866
+ ")"
867
+ ] }),
868
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mt-1 space-y-0.5 pl-2 border-l border-white/10", children: Object.entries(result.headers).map(([k, v]) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "text-white/30", children: [
869
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "text-white/50", children: [
870
+ k,
871
+ ":"
872
+ ] }),
873
+ " ",
874
+ v
875
+ ] }, k)) })
876
+ ] }),
877
+ result.isImage && result.imageDataUrl ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { src: result.imageDataUrl, alt: "response", className: "w-full max-h-40 object-contain rounded-lg border border-white/10 bg-black/40 mt-1" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("pre", { className: "text-white/60 whitespace-pre-wrap break-all bg-black/30 rounded-lg p-2 max-h-40 overflow-y-auto text-[9px]", children: [
878
+ result.bodyPreview,
879
+ result.bodySize > 500 ? "\n\u2026" : ""
817
880
  ] })
818
881
  ] }),
819
- blobStatus === "error" && blobError && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "text-[10px] text-red-400 font-mono flex items-start gap-1", children: [
820
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[14px] shrink-0", children: "error" }),
821
- blobError
882
+ testStatus === "error" && fetchError && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "bg-red-900/20 border border-red-700/30 rounded-xl p-3 text-[10px] font-mono text-red-400 flex items-start gap-2", children: [
883
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[14px] shrink-0 mt-0.5", children: "error" }),
884
+ fetchError
822
885
  ] })
823
886
  ] }),
824
887
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "mt-auto p-4 bg-white/5 rounded-2xl border border-white/5 flex flex-col gap-2 opacity-50", children: [
@@ -4180,7 +4243,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4180
4243
  }
4181
4244
 
4182
4245
  // src/index.ts
4183
- var LIB_VERSION = "1.2.2";
4246
+ var LIB_VERSION = "1.2.3";
4184
4247
  // Annotate the CommonJS export names for ESM import in node:
4185
4248
  0 && (module.exports = {
4186
4249
  AvatarArchitectApp,
package/dist/index.mjs CHANGED
@@ -656,34 +656,52 @@ var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagTogg
656
656
  import { useRef as useRef2, useState as useState2 } from "react";
657
657
  import { motion as motion3 } from "motion/react";
658
658
  import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
659
+ var PRESET_URLS = [
660
+ "https://jsonplaceholder.typicode.com/todos/1",
661
+ "https://huggingface.co/api/whoami-v2",
662
+ "https://esm.sh/@rslsp1/fa-app-tools@latest"
663
+ ];
659
664
  var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
660
665
  const workspaceInputRef = useRef2(null);
661
- const blobTestInputRef = useRef2(null);
662
- const [blobStatus, setBlobStatus] = useState2("idle");
663
- const [blobThumb, setBlobThumb] = useState2(null);
664
- const [blobError, setBlobError] = useState2(null);
665
- const handleBlobTest = async (file) => {
666
- setBlobStatus("loading");
667
- setBlobThumb(null);
668
- setBlobError(null);
669
- const blobUrl = URL.createObjectURL(file);
666
+ const [urlInput, setUrlInput] = useState2("");
667
+ const [testStatus, setTestStatus] = useState2("idle");
668
+ const [result, setResult] = useState2(null);
669
+ const [fetchError, setFetchError] = useState2(null);
670
+ const runTest = async (url) => {
671
+ if (!url.trim()) return;
672
+ setTestStatus("loading");
673
+ setResult(null);
674
+ setFetchError(null);
675
+ const t0 = Date.now();
670
676
  try {
671
- const res = await fetch(blobUrl);
672
- if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
673
- const blob = await res.blob();
674
- const dataUrl = await new Promise((resolve, reject) => {
675
- const reader = new FileReader();
676
- reader.onload = () => resolve(reader.result);
677
- reader.onerror = () => reject(new Error("FileReader failed"));
678
- reader.readAsDataURL(blob);
677
+ const res = await fetch(url.trim());
678
+ const durationMs = Date.now() - t0;
679
+ const contentType = res.headers.get("content-type") || "";
680
+ const headers = {};
681
+ res.headers.forEach((v, k) => {
682
+ headers[k] = v;
679
683
  });
680
- setBlobThumb(dataUrl);
681
- setBlobStatus("ok");
684
+ const blob = await res.blob();
685
+ const bodySize = blob.size;
686
+ const isImage = contentType.startsWith("image/");
687
+ let bodyPreview = "";
688
+ let imageDataUrl;
689
+ if (isImage) {
690
+ imageDataUrl = await new Promise((resolve, reject) => {
691
+ const reader = new FileReader();
692
+ reader.onload = () => resolve(reader.result);
693
+ reader.onerror = reject;
694
+ reader.readAsDataURL(blob);
695
+ });
696
+ } else {
697
+ const text = await blob.text();
698
+ bodyPreview = text.slice(0, 500);
699
+ }
700
+ setResult({ status: res.status, statusText: res.statusText, contentType, headers, bodyPreview, isImage, imageDataUrl, bodySize, durationMs });
701
+ setTestStatus("ok");
682
702
  } catch (e) {
683
- setBlobError(e.message || String(e));
684
- setBlobStatus("error");
685
- } finally {
686
- URL.revokeObjectURL(blobUrl);
703
+ setFetchError(e.message || String(e));
704
+ setTestStatus("error");
687
705
  }
688
706
  };
689
707
  return /* @__PURE__ */ jsxs5(motion3.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "absolute inset-0 p-6 flex flex-col gap-10 overflow-y-auto", children: [
@@ -701,42 +719,87 @@ var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
701
719
  ] }),
702
720
  /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-3", children: [
703
721
  /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1", children: [
704
- /* @__PURE__ */ jsx7(SectionLabel, { children: "blob: URL Test" }),
705
- /* @__PURE__ */ jsx7("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Testet ob fetch() auf blob: URLs funktioniert \u2014 lokale Datei \u2192 createObjectURL \u2192 fetch \u2192 base64." })
722
+ /* @__PURE__ */ jsx7(SectionLabel, { children: "URL Fetch Diagnose" }),
723
+ /* @__PURE__ */ jsx7("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Testet ob fetch() auf externe URLs funktioniert." })
706
724
  ] }),
707
- /* @__PURE__ */ jsx7(
708
- PillButton,
709
- {
710
- variant: "outline",
711
- icon: blobStatus === "loading" ? "sync" : "image_search",
712
- onClick: () => blobTestInputRef.current?.click(),
713
- children: "Bild w\xE4hlen & testen"
714
- }
715
- ),
716
- /* @__PURE__ */ jsx7(
717
- "input",
725
+ /* @__PURE__ */ jsx7("div", { className: "flex flex-col gap-1", children: PRESET_URLS.map((u) => /* @__PURE__ */ jsx7(
726
+ "button",
718
727
  {
719
- ref: blobTestInputRef,
720
- type: "file",
721
- accept: "image/*",
722
- className: "hidden",
723
- onChange: (e) => {
724
- const f = e.target.files?.[0];
725
- if (f) handleBlobTest(f);
726
- e.target.value = "";
728
+ onClick: () => {
729
+ setUrlInput(u);
730
+ runTest(u);
731
+ },
732
+ className: "text-left px-2 py-1 rounded bg-white/3 border border-white/5 text-[9px] text-white/40 hover:text-white/70 hover:bg-white/6 font-mono truncate transition",
733
+ children: u
734
+ },
735
+ u
736
+ )) }),
737
+ /* @__PURE__ */ jsxs5("div", { className: "flex gap-2", children: [
738
+ /* @__PURE__ */ jsx7(
739
+ "input",
740
+ {
741
+ value: urlInput,
742
+ onChange: (e) => setUrlInput(e.target.value),
743
+ onKeyDown: (e) => e.key === "Enter" && runTest(urlInput),
744
+ placeholder: "https://...",
745
+ className: "flex-1 bg-white/5 border border-white/10 rounded-xl px-3 py-2 text-[11px] text-white/80 outline-none focus:border-white/20 placeholder:text-white/20 font-mono"
727
746
  }
728
- }
729
- ),
730
- blobStatus === "ok" && blobThumb && /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
731
- /* @__PURE__ */ jsx7("img", { src: blobThumb, alt: "blob test", className: "w-full max-h-48 object-contain rounded-xl border border-white/10 bg-black/40" }),
732
- /* @__PURE__ */ jsxs5("p", { className: "text-[10px] text-green-400 font-mono flex items-center gap-1", children: [
733
- /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[14px]", children: "check_circle" }),
734
- "blob: fetch \u2713 \u2014 base64 erfolgreich"
747
+ ),
748
+ /* @__PURE__ */ jsx7(
749
+ "button",
750
+ {
751
+ onClick: () => runTest(urlInput),
752
+ disabled: testStatus === "loading" || !urlInput.trim(),
753
+ className: "px-3 py-2 bg-white/10 hover:bg-white/15 border border-white/10 rounded-xl text-white/60 transition disabled:opacity-40 shrink-0",
754
+ children: testStatus === "loading" ? /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[16px] animate-spin", children: "sync" }) : /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[16px]", children: "send" })
755
+ }
756
+ )
757
+ ] }),
758
+ testStatus === "ok" && result && /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2 bg-white/3 border border-white/8 rounded-xl p-3 text-[10px] font-mono", children: [
759
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
760
+ /* @__PURE__ */ jsxs5("span", { className: `font-bold ${result.status < 400 ? "text-green-400" : "text-red-400"}`, children: [
761
+ result.status,
762
+ " ",
763
+ result.statusText
764
+ ] }),
765
+ /* @__PURE__ */ jsx7("span", { className: "text-white/30", children: "\xB7" }),
766
+ /* @__PURE__ */ jsxs5("span", { className: "text-white/50", children: [
767
+ result.durationMs,
768
+ "ms"
769
+ ] }),
770
+ /* @__PURE__ */ jsx7("span", { className: "text-white/30", children: "\xB7" }),
771
+ /* @__PURE__ */ jsxs5("span", { className: "text-white/50", children: [
772
+ (result.bodySize / 1024).toFixed(1),
773
+ " KB"
774
+ ] })
775
+ ] }),
776
+ /* @__PURE__ */ jsxs5("div", { className: "text-white/40", children: [
777
+ "Content-Type: ",
778
+ /* @__PURE__ */ jsx7("span", { className: "text-white/70", children: result.contentType })
779
+ ] }),
780
+ /* @__PURE__ */ jsxs5("details", { className: "cursor-pointer", children: [
781
+ /* @__PURE__ */ jsxs5("summary", { className: "text-white/30 hover:text-white/60 transition", children: [
782
+ "Headers (",
783
+ Object.keys(result.headers).length,
784
+ ")"
785
+ ] }),
786
+ /* @__PURE__ */ jsx7("div", { className: "mt-1 space-y-0.5 pl-2 border-l border-white/10", children: Object.entries(result.headers).map(([k, v]) => /* @__PURE__ */ jsxs5("div", { className: "text-white/30", children: [
787
+ /* @__PURE__ */ jsxs5("span", { className: "text-white/50", children: [
788
+ k,
789
+ ":"
790
+ ] }),
791
+ " ",
792
+ v
793
+ ] }, k)) })
794
+ ] }),
795
+ result.isImage && result.imageDataUrl ? /* @__PURE__ */ jsx7("img", { src: result.imageDataUrl, alt: "response", className: "w-full max-h-40 object-contain rounded-lg border border-white/10 bg-black/40 mt-1" }) : /* @__PURE__ */ jsxs5("pre", { className: "text-white/60 whitespace-pre-wrap break-all bg-black/30 rounded-lg p-2 max-h-40 overflow-y-auto text-[9px]", children: [
796
+ result.bodyPreview,
797
+ result.bodySize > 500 ? "\n\u2026" : ""
735
798
  ] })
736
799
  ] }),
737
- blobStatus === "error" && blobError && /* @__PURE__ */ jsxs5("p", { className: "text-[10px] text-red-400 font-mono flex items-start gap-1", children: [
738
- /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[14px] shrink-0", children: "error" }),
739
- blobError
800
+ testStatus === "error" && fetchError && /* @__PURE__ */ jsxs5("div", { className: "bg-red-900/20 border border-red-700/30 rounded-xl p-3 text-[10px] font-mono text-red-400 flex items-start gap-2", children: [
801
+ /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[14px] shrink-0 mt-0.5", children: "error" }),
802
+ fetchError
740
803
  ] })
741
804
  ] }),
742
805
  /* @__PURE__ */ jsxs5("div", { className: "mt-auto p-4 bg-white/5 rounded-2xl border border-white/5 flex flex-col gap-2 opacity-50", children: [
@@ -4098,7 +4161,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4098
4161
  }
4099
4162
 
4100
4163
  // src/index.ts
4101
- var LIB_VERSION = "1.2.2";
4164
+ var LIB_VERSION = "1.2.3";
4102
4165
  export {
4103
4166
  AvatarArchitectApp,
4104
4167
  CollapsibleCard,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rslsp1/fa-app-tools",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Shared tools and hooks for Fine Art flow apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",