@rslsp1/fa-app-tools 1.3.11 → 1.3.13

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
@@ -479,6 +479,6 @@ declare function hfLoadMetadata(token: string): Promise<any[]>;
479
479
  declare function hfUploadImage(base64: string, id: string, token: string, mimeType?: string): Promise<void>;
480
480
  declare function hfLoadImageAsBase64(id: string, token: string): Promise<string | null>;
481
481
 
482
- declare const LIB_VERSION = "1.3.11";
482
+ declare const LIB_VERSION = "1.3.13";
483
483
 
484
484
  export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, type HFMetadataEntry, 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, getHFToken, groupGenerationsToLabItems, hfDeleteProject, hfDownloadProject, hfListProjects, hfLoadImageAsBase64, hfLoadMetadata, hfLoadTags, hfSaveMetadata, hfSaveTags, hfUploadImage, hfUploadProjectForm, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, setHFToken, useKeyboardNavigation, useOnClickOutside };
package/dist/index.d.ts CHANGED
@@ -479,6 +479,6 @@ declare function hfLoadMetadata(token: string): Promise<any[]>;
479
479
  declare function hfUploadImage(base64: string, id: string, token: string, mimeType?: string): Promise<void>;
480
480
  declare function hfLoadImageAsBase64(id: string, token: string): Promise<string | null>;
481
481
 
482
- declare const LIB_VERSION = "1.3.11";
482
+ declare const LIB_VERSION = "1.3.13";
483
483
 
484
484
  export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, type HFMetadataEntry, 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, getHFToken, groupGenerationsToLabItems, hfDeleteProject, hfDownloadProject, hfListProjects, hfLoadImageAsBase64, hfLoadMetadata, hfLoadTags, hfSaveMetadata, hfSaveTags, hfUploadImage, hfUploadProjectForm, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, setHFToken, useKeyboardNavigation, useOnClickOutside };
package/dist/index.js CHANGED
@@ -3474,6 +3474,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3474
3474
  const [isLoadingFromHF, setIsLoadingFromHF] = (0, import_react21.useState)(false);
3475
3475
  const [hfMetadata, setHfMetadata] = (0, import_react21.useState)([]);
3476
3476
  const hfTagSaveTimer = (0, import_react21.useRef)(null);
3477
+ const hfMetaSaveQueue = (0, import_react21.useRef)(Promise.resolve());
3477
3478
  const wsInputRef = (0, import_react21.useRef)(null);
3478
3479
  const startApp = (choice) => {
3479
3480
  try {
@@ -3747,15 +3748,18 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3747
3748
  };
3748
3749
  hfUploadImage(base64, genId, hfToken).catch(() => {
3749
3750
  });
3750
- hfLoadMetadata(hfToken).then((existing) => {
3751
- const ids = new Set((existing || []).map((e) => e.id));
3752
- if (!ids.has(genId)) {
3753
- const next = [...existing || [], entry];
3754
- hfSaveMetadata(next, hfToken).catch(() => {
3755
- });
3756
- setHfMetadata(next);
3751
+ const token = hfToken;
3752
+ hfMetaSaveQueue.current = hfMetaSaveQueue.current.then(async () => {
3753
+ try {
3754
+ const existing = await hfLoadMetadata(token);
3755
+ const ids = new Set((existing || []).map((e) => e.id));
3756
+ if (!ids.has(genId)) {
3757
+ const next = [...existing || [], entry];
3758
+ await hfSaveMetadata(next, token);
3759
+ setHfMetadata(next);
3760
+ }
3761
+ } catch {
3757
3762
  }
3758
- }).catch(() => {
3759
3763
  });
3760
3764
  }
3761
3765
  } catch (err) {
@@ -4048,7 +4052,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4048
4052
  const entries = await hfLoadMetadata(token);
4049
4053
  if (!Array.isArray(entries) || entries.length === 0) return;
4050
4054
  setHfMetadata(entries);
4051
- const skeletons = entries.map((e) => ({
4055
+ const hfIds = new Set(entries.map((e) => e.id));
4056
+ const hfSkeletons = entries.map((e) => ({
4052
4057
  id: e.id,
4053
4058
  nodeId: e.id,
4054
4059
  prompt: e.prompt,
@@ -4058,15 +4063,22 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4058
4063
  timestamp: e.timestamp,
4059
4064
  status: "done"
4060
4065
  }));
4061
- setGalleryItems(skeletons);
4062
- setHistory(skeletons);
4063
- if (skeletons.length > 0) setCurrentResult(skeletons[0]);
4066
+ setGalleryItems((prev) => {
4067
+ const localOnly = prev.filter((g) => !hfIds.has(g.id));
4068
+ const merged = hfSkeletons.map((s) => prev.find((g) => g.id === s.id) ?? s);
4069
+ return [...localOnly, ...merged];
4070
+ });
4071
+ setHistory((prev) => {
4072
+ const localOnly = prev.filter((g) => !hfIds.has(g.id));
4073
+ const merged = hfSkeletons.map((s) => prev.find((g) => g.id === s.id) ?? s);
4074
+ return [...localOnly, ...merged];
4075
+ });
4064
4076
  for (const entry of entries) {
4065
4077
  hfLoadImageAsBase64(entry.id, token).then((b64) => {
4066
4078
  if (!b64) return;
4067
4079
  const prefix = `data:${entry.mimeType || "image/jpeg"};base64,`;
4068
- setGalleryItems((prev) => prev.map((g) => g.id === entry.id ? { ...g, base64: prefix + b64 } : g));
4069
- setHistory((prev) => prev.map((g) => g.id === entry.id ? { ...g, base64: prefix + b64 } : g));
4080
+ setGalleryItems((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
4081
+ setHistory((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
4070
4082
  }).catch(() => {
4071
4083
  });
4072
4084
  }
@@ -4084,9 +4096,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4084
4096
  for (const cat of allCategories) {
4085
4097
  const localTags = local.by_category[cat] || [];
4086
4098
  const remoteTags = remote.by_category[cat] || [];
4099
+ const remoteMap = new Map(remoteTags.map((t) => [t.value, t]));
4087
4100
  const localValues = new Set(localTags.map((t) => t.value));
4101
+ const mergedLocal = localTags.map((t) => {
4102
+ const remote2 = remoteMap.get(t.value);
4103
+ return remote2?.is_deleted ? { ...t, is_deleted: true } : t;
4104
+ });
4088
4105
  const onlyInRemote = remoteTags.filter((t) => !localValues.has(t.value));
4089
- merged[cat] = [...localTags, ...onlyInRemote];
4106
+ merged[cat] = [...mergedLocal, ...onlyInRemote];
4090
4107
  }
4091
4108
  const all = Object.entries(merged).flatMap(([cat, tags]) => tags.map((t) => ({ ...t, category: cat })));
4092
4109
  return { by_category: merged, all };
@@ -4903,7 +4920,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4903
4920
 
4904
4921
  // src/index.ts
4905
4922
  init_hfStateService();
4906
- var LIB_VERSION = "1.3.11";
4923
+ var LIB_VERSION = "1.3.13";
4907
4924
  // Annotate the CommonJS export names for ESM import in node:
4908
4925
  0 && (module.exports = {
4909
4926
  AvatarArchitectApp,
package/dist/index.mjs CHANGED
@@ -2917,6 +2917,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2917
2917
  const [isLoadingFromHF, setIsLoadingFromHF] = useState14(false);
2918
2918
  const [hfMetadata, setHfMetadata] = useState14([]);
2919
2919
  const hfTagSaveTimer = useRef6(null);
2920
+ const hfMetaSaveQueue = useRef6(Promise.resolve());
2920
2921
  const wsInputRef = useRef6(null);
2921
2922
  const startApp = (choice) => {
2922
2923
  try {
@@ -3190,15 +3191,18 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3190
3191
  };
3191
3192
  hfUploadImage(base64, genId, hfToken).catch(() => {
3192
3193
  });
3193
- hfLoadMetadata(hfToken).then((existing) => {
3194
- const ids = new Set((existing || []).map((e) => e.id));
3195
- if (!ids.has(genId)) {
3196
- const next = [...existing || [], entry];
3197
- hfSaveMetadata(next, hfToken).catch(() => {
3198
- });
3199
- setHfMetadata(next);
3194
+ const token = hfToken;
3195
+ hfMetaSaveQueue.current = hfMetaSaveQueue.current.then(async () => {
3196
+ try {
3197
+ const existing = await hfLoadMetadata(token);
3198
+ const ids = new Set((existing || []).map((e) => e.id));
3199
+ if (!ids.has(genId)) {
3200
+ const next = [...existing || [], entry];
3201
+ await hfSaveMetadata(next, token);
3202
+ setHfMetadata(next);
3203
+ }
3204
+ } catch {
3200
3205
  }
3201
- }).catch(() => {
3202
3206
  });
3203
3207
  }
3204
3208
  } catch (err) {
@@ -3491,7 +3495,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3491
3495
  const entries = await hfLoadMetadata(token);
3492
3496
  if (!Array.isArray(entries) || entries.length === 0) return;
3493
3497
  setHfMetadata(entries);
3494
- const skeletons = entries.map((e) => ({
3498
+ const hfIds = new Set(entries.map((e) => e.id));
3499
+ const hfSkeletons = entries.map((e) => ({
3495
3500
  id: e.id,
3496
3501
  nodeId: e.id,
3497
3502
  prompt: e.prompt,
@@ -3501,15 +3506,22 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3501
3506
  timestamp: e.timestamp,
3502
3507
  status: "done"
3503
3508
  }));
3504
- setGalleryItems(skeletons);
3505
- setHistory(skeletons);
3506
- if (skeletons.length > 0) setCurrentResult(skeletons[0]);
3509
+ setGalleryItems((prev) => {
3510
+ const localOnly = prev.filter((g) => !hfIds.has(g.id));
3511
+ const merged = hfSkeletons.map((s) => prev.find((g) => g.id === s.id) ?? s);
3512
+ return [...localOnly, ...merged];
3513
+ });
3514
+ setHistory((prev) => {
3515
+ const localOnly = prev.filter((g) => !hfIds.has(g.id));
3516
+ const merged = hfSkeletons.map((s) => prev.find((g) => g.id === s.id) ?? s);
3517
+ return [...localOnly, ...merged];
3518
+ });
3507
3519
  for (const entry of entries) {
3508
3520
  hfLoadImageAsBase64(entry.id, token).then((b64) => {
3509
3521
  if (!b64) return;
3510
3522
  const prefix = `data:${entry.mimeType || "image/jpeg"};base64,`;
3511
- setGalleryItems((prev) => prev.map((g) => g.id === entry.id ? { ...g, base64: prefix + b64 } : g));
3512
- setHistory((prev) => prev.map((g) => g.id === entry.id ? { ...g, base64: prefix + b64 } : g));
3523
+ setGalleryItems((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
3524
+ setHistory((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
3513
3525
  }).catch(() => {
3514
3526
  });
3515
3527
  }
@@ -3527,9 +3539,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
3527
3539
  for (const cat of allCategories) {
3528
3540
  const localTags = local.by_category[cat] || [];
3529
3541
  const remoteTags = remote.by_category[cat] || [];
3542
+ const remoteMap = new Map(remoteTags.map((t) => [t.value, t]));
3530
3543
  const localValues = new Set(localTags.map((t) => t.value));
3544
+ const mergedLocal = localTags.map((t) => {
3545
+ const remote2 = remoteMap.get(t.value);
3546
+ return remote2?.is_deleted ? { ...t, is_deleted: true } : t;
3547
+ });
3531
3548
  const onlyInRemote = remoteTags.filter((t) => !localValues.has(t.value));
3532
- merged[cat] = [...localTags, ...onlyInRemote];
3549
+ merged[cat] = [...mergedLocal, ...onlyInRemote];
3533
3550
  }
3534
3551
  const all = Object.entries(merged).flatMap(([cat, tags]) => tags.map((t) => ({ ...t, category: cat })));
3535
3552
  return { by_category: merged, all };
@@ -4345,7 +4362,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4345
4362
  }
4346
4363
 
4347
4364
  // src/index.ts
4348
- var LIB_VERSION = "1.3.11";
4365
+ var LIB_VERSION = "1.3.13";
4349
4366
  export {
4350
4367
  AvatarArchitectApp,
4351
4368
  CollapsibleCard,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rslsp1/fa-app-tools",
3
- "version": "1.3.11",
3
+ "version": "1.3.13",
4
4
  "description": "Shared tools and hooks for Fine Art flow apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",