@rslsp1/fa-app-tools 2.0.85 → 2.0.87

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.js CHANGED
@@ -260,13 +260,19 @@ var init_project = __esm({
260
260
  });
261
261
 
262
262
  // src/lib/hfEventTypes.ts
263
- var HF_BASE, HF_REPO, CURRENT_EVENT_VERSION;
263
+ function bildEndungFuer(mimeType) {
264
+ if (mimeType === "image/png") return "png";
265
+ if (mimeType === "image/webp") return "webp";
266
+ return "jpg";
267
+ }
268
+ var HF_BASE, HF_REPO, CURRENT_EVENT_VERSION, SPEICHERBARE_BILDTYPEN;
264
269
  var init_hfEventTypes = __esm({
265
270
  "src/lib/hfEventTypes.ts"() {
266
271
  "use strict";
267
272
  HF_BASE = "https://huggingface.co";
268
273
  HF_REPO = "RolandSch/fa-app-state";
269
274
  CURRENT_EVENT_VERSION = { major: 1, minor: 0 };
275
+ SPEICHERBARE_BILDTYPEN = ["image/png", "image/jpeg", "image/webp"];
270
276
  }
271
277
  });
272
278
 
@@ -297,8 +303,8 @@ async function mitGeduld(anfrage) {
297
303
  letzte = res;
298
304
  if (versuch === DROSSEL_VERSUCHE - 1) break;
299
305
  const angesagt = Number(res.headers.get("retry-after"));
300
- const warten = Number.isFinite(angesagt) && angesagt > 0 ? angesagt * 1e3 : DROSSEL_BASIS_MS * 2 ** versuch;
301
- await schlafen(warten);
306
+ const warten2 = Number.isFinite(angesagt) && angesagt > 0 ? angesagt * 1e3 : DROSSEL_BASIS_MS * 2 ** versuch;
307
+ await schlafen(warten2);
302
308
  }
303
309
  return letzte;
304
310
  }
@@ -631,7 +637,7 @@ async function hfLoadMetadata(token) {
631
637
  }
632
638
  }
633
639
  async function hfUploadImage(base64, id, token, mimeType = "image/jpeg") {
634
- const ext = mimeType === "image/png" ? "png" : "jpg";
640
+ const ext = bildEndungFuer(mimeType);
635
641
  const binary = atob(base64);
636
642
  const bytes = new Uint8Array(binary.length);
637
643
  for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
@@ -673,7 +679,7 @@ async function hfLoadImageAsBase64(id, token, namespace, filename, on404, mimeTy
673
679
  const result2 = await fetchBase64(`images/${filename}`);
674
680
  return result2 === "ABORT" ? null : result2;
675
681
  }
676
- const ext = mimeType === "image/png" ? "png" : "jpg";
682
+ const ext = bildEndungFuer(mimeType);
677
683
  const result = await fetchBase64(`images/${id}.${ext}`);
678
684
  return result === "ABORT" ? null : result;
679
685
  }
@@ -801,7 +807,7 @@ __export(index_exports, {
801
807
  module.exports = __toCommonJS(index_exports);
802
808
 
803
809
  // package.json
804
- var version = "2.0.85";
810
+ var version = "2.0.87";
805
811
 
806
812
  // src/hooks/useOnClickOutside.ts
807
813
  var import_react = require("react");
@@ -12007,8 +12013,8 @@ var BestandsBild = ({ port, mediaRef }) => {
12007
12013
  };
12008
12014
  var BatchBild = ({ port, bild }) => {
12009
12015
  const [phase] = usePortQuery(
12010
- () => port.imageLibrary ? port.imageLibrary.resolveImage(bild.media_ref) : Promise.resolve({ kind: "ok", value: null }),
12011
- [port, bild.media_ref]
12016
+ () => port.imageLibrary ? port.imageLibrary.resolveImage(bild.media_ref, bild.mime_type ?? null) : Promise.resolve({ kind: "ok", value: null }),
12017
+ [port, bild.media_ref, bild.mime_type]
12012
12018
  );
12013
12019
  return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("li", { "data-testid": `batchbild-${bild.media_ref}`, children: [
12014
12020
  phase.status === "ready" && phase.value && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
@@ -17438,9 +17444,117 @@ function createClientRunPort(options) {
17438
17444
  };
17439
17445
  }
17440
17446
 
17441
- // src/lib/szenen/hfImageLibrary.ts
17447
+ // src/lib/szenen/hfImageStore.ts
17442
17448
  init_hfStateService();
17443
17449
  init_hfEventLog();
17450
+ init_hfEventTypes();
17451
+ var LEERER_BESTAND = {
17452
+ metadata: [],
17453
+ tags: { by_category: {}, all: [] },
17454
+ meta: { consolidatedAt: 0, version: 1 }
17455
+ };
17456
+ var endungFuer = bildEndungFuer;
17457
+ function bildPfad(id, mimeType) {
17458
+ return `images/${id}.${endungFuer(mimeType)}`;
17459
+ }
17460
+ function typAusBytes(base64, vorgabe = "image/png") {
17461
+ const kopf = base64.slice(0, 16);
17462
+ if (kopf.startsWith("iVBORw0KGgo")) return "image/png";
17463
+ if (kopf.startsWith("/9j/")) return "image/jpeg";
17464
+ if (kopf.startsWith("UklGR")) return "image/webp";
17465
+ if (kopf.startsWith("R0lGOD")) return "image/gif";
17466
+ return vorgabe;
17467
+ }
17468
+ var warten = (ms) => new Promise((r) => setTimeout(r, ms));
17469
+ function createHfImageStore(options) {
17470
+ const { namespace, token } = options;
17471
+ const now = options.now ?? (() => Date.now());
17472
+ const versuche = options.leseVersuche ?? 4;
17473
+ const basisMs = options.leseBasisMs ?? 400;
17474
+ const schlafen2 = options.schlafen ?? warten;
17475
+ const abgelegt = /* @__PURE__ */ new Map();
17476
+ const bekanntePfade = /* @__PURE__ */ new Set();
17477
+ let gefalteterBestand = null;
17478
+ let laufenderAbgleich = null;
17479
+ async function bestandLesen() {
17480
+ const grundlage = gefalteterBestand ?? await loadHFState(namespace, token) ?? LEERER_BESTAND;
17481
+ const neue = await loadPendingEvents(
17482
+ namespace,
17483
+ token,
17484
+ grundlage.meta.consolidatedAt,
17485
+ bekanntePfade
17486
+ );
17487
+ const danach = neue.filter((e) => e.ts > grundlage.meta.consolidatedAt);
17488
+ gefalteterBestand = danach.length ? applyEvents(grundlage, danach) : grundlage;
17489
+ return gefalteterBestand;
17490
+ }
17491
+ function bestandAbgleichen() {
17492
+ if (!laufenderAbgleich) {
17493
+ laufenderAbgleich = bestandLesen().finally(() => {
17494
+ laufenderAbgleich = null;
17495
+ });
17496
+ }
17497
+ return laufenderAbgleich;
17498
+ }
17499
+ return {
17500
+ bestand: bestandAbgleichen,
17501
+ async putWithId(id, base64, mimeType, titel) {
17502
+ const echterTyp = typAusBytes(base64, mimeType);
17503
+ if (!SPEICHERBARE_BILDTYPEN.includes(echterTyp)) {
17504
+ throw new Error(
17505
+ `Das Bild ${id} ist ${echterTyp}; der Bildbestand kann nur ${SPEICHERBARE_BILDTYPEN.join(", ")} wahrheitsgemaess ablegen. Es wurde nichts geschrieben.`
17506
+ );
17507
+ }
17508
+ await hfUploadImage(base64, id, token, echterTyp);
17509
+ await writeHFEvent(namespace, token, "image_added", {
17510
+ id,
17511
+ prompt: titel ?? id,
17512
+ tags: [],
17513
+ timestamp: now(),
17514
+ mimeType: echterTyp
17515
+ }, []);
17516
+ abgelegt.set(id, { data: base64, mimeType: echterTyp });
17517
+ },
17518
+ async resolve(id, mimeType) {
17519
+ const eben = abgelegt.get(id);
17520
+ if (eben) return eben;
17521
+ const zustand = await bestandAbgleichen();
17522
+ const eintrag = zustand.metadata.find((e) => e.id === id);
17523
+ const typ = eintrag?.mimeType || mimeType || null;
17524
+ if (eintrag) {
17525
+ const base64 = await hfLoadImageAsBase64(
17526
+ id,
17527
+ token,
17528
+ void 0,
17529
+ eintrag.filename,
17530
+ void 0,
17531
+ eintrag.mimeType,
17532
+ false
17533
+ );
17534
+ if (base64) return { data: base64, mimeType: eintrag.mimeType || "image/jpeg" };
17535
+ }
17536
+ const pfadTyp = typ ?? "image/png";
17537
+ for (let versuch = 0; versuch < versuche; versuch += 1) {
17538
+ if (versuch > 0) await schlafen2(basisMs * 2 ** (versuch - 1));
17539
+ const base64 = await hfLoadImageAsBase64(
17540
+ id,
17541
+ token,
17542
+ void 0,
17543
+ void 0,
17544
+ void 0,
17545
+ pfadTyp,
17546
+ false
17547
+ );
17548
+ if (base64) return { data: base64, mimeType: pfadTyp };
17549
+ }
17550
+ throw new Error(
17551
+ `Das Bild ${id} ist auf HF nicht auffindbar. Geprueft: ${bildPfad(id, pfadTyp)} in ${versuche} Versuchen` + (eintrag ? " (im Bestand verzeichnet, aber nicht ladbar)." : " (nicht im Bestand verzeichnet).")
17552
+ );
17553
+ }
17554
+ };
17555
+ }
17556
+
17557
+ // src/lib/szenen/hfImageLibrary.ts
17444
17558
  function fehler2(nachricht, retryable = false) {
17445
17559
  return { kind: "error", message: nachricht, retryable };
17446
17560
  }
@@ -17455,14 +17569,16 @@ function alsBild(eintrag) {
17455
17569
  };
17456
17570
  }
17457
17571
  function createHfImageLibrary(options) {
17458
- const { namespace, token } = options;
17459
17572
  const newImageId = options.newImageId ?? (() => crypto.randomUUID());
17460
- const now = options.now ?? (() => Date.now());
17461
- const frisch = /* @__PURE__ */ new Map();
17573
+ const store = options.store ?? createHfImageStore({
17574
+ namespace: options.namespace,
17575
+ token: options.token,
17576
+ ...options.now ? { now: options.now } : {}
17577
+ });
17462
17578
  return {
17463
17579
  async listImages(query) {
17464
17580
  try {
17465
- const zustand = await loadHFState(namespace, token);
17581
+ const zustand = await store.bestand();
17466
17582
  const eintraege = zustand?.metadata ?? [];
17467
17583
  const gesucht = query?.search?.trim().toLowerCase();
17468
17584
  const gefiltert = gesucht ? eintraege.filter((e) => (e.prompt ?? "").toLowerCase().includes(gesucht) || e.id.toLowerCase().includes(gesucht)) : eintraege;
@@ -17476,54 +17592,18 @@ function createHfImageLibrary(options) {
17476
17592
  );
17477
17593
  }
17478
17594
  },
17479
- async resolveImage(mediaRef) {
17480
- const eben = frisch.get(mediaRef);
17481
- if (eben) return { kind: "ok", value: { data: eben.data, mime_type: eben.mimeType } };
17595
+ async resolveImage(mediaRef, mimeTypeHinweis) {
17482
17596
  try {
17483
- const zustand = await loadHFState(namespace, token);
17484
- const eintrag = (zustand?.metadata ?? []).find((e) => e.id === mediaRef);
17485
- if (eintrag) {
17486
- const base64 = await hfLoadImageAsBase64(
17487
- mediaRef,
17488
- token,
17489
- void 0,
17490
- eintrag.filename,
17491
- void 0,
17492
- eintrag.mimeType,
17493
- false
17494
- );
17495
- if (!base64) {
17496
- return fehler2(`Das Bild ${mediaRef} ist im Bestand verzeichnet, aber nicht ladbar.`, true);
17497
- }
17498
- return { kind: "ok", value: { data: base64, mime_type: eintrag.mimeType || "image/jpeg" } };
17499
- }
17500
- for (const mimeType of ["image/png", "image/jpeg"]) {
17501
- const base64 = await hfLoadImageAsBase64(mediaRef, token, void 0, void 0, void 0, mimeType, false);
17502
- if (base64) return { kind: "ok", value: { data: base64, mime_type: mimeType } };
17503
- }
17504
- return fehler2(
17505
- `Das Bild ${mediaRef} steht nicht im Bestand. Moeglicherweise hat der Abgleich es noch nicht uebertragen.`,
17506
- true
17507
- );
17597
+ const bild = await store.resolve(mediaRef, mimeTypeHinweis);
17598
+ return { kind: "ok", value: { data: bild.data, mime_type: bild.mimeType } };
17508
17599
  } catch (error) {
17509
- return fehler2(
17510
- `Das Bild ${mediaRef} konnte nicht geladen werden: ${error instanceof Error ? error.message : String(error)}`,
17511
- true
17512
- );
17600
+ return fehler2(error instanceof Error ? error.message : String(error), true);
17513
17601
  }
17514
17602
  },
17515
17603
  async putImage(input) {
17516
17604
  const id = newImageId();
17517
17605
  try {
17518
- await hfUploadImage(input.data, id, token, input.mime_type);
17519
- await writeHFEvent(namespace, token, "image_added", {
17520
- id,
17521
- prompt: input.title,
17522
- tags: [],
17523
- timestamp: now(),
17524
- mimeType: input.mime_type
17525
- }, []);
17526
- frisch.set(id, { mimeType: input.mime_type, data: input.data });
17606
+ await store.putWithId(id, input.data, input.mime_type, input.title);
17527
17607
  return {
17528
17608
  kind: "ok",
17529
17609
  value: { mediaRef: id, title: input.title, mimeType: input.mime_type, thumbUrl: null }
@@ -17650,6 +17730,11 @@ function alsBilder(rohe) {
17650
17730
  media_ref: b.media_ref,
17651
17731
  position: b.position,
17652
17732
  ...istText3(b.asset_id) ? { asset_id: b.asset_id } : {},
17733
+ // Der bestätigte MIME-Typ (Review 2026-08-18 §5 P2) muss durch das
17734
+ // Rücklesen hindurch: Genau hier braucht ihn der Lesepfad, um den
17735
+ // Dateipfad `images/<id>.<ext>` zu bilden, statt ihn zu erraten. Nur
17736
+ // gesetzt, wenn er im Ereignis steht — ältere Batches tragen ihn nicht.
17737
+ ...istText3(b.mime_type) ? { mime_type: b.mime_type } : {},
17653
17738
  model: b.model ?? null,
17654
17739
  seed: b.seed ?? null,
17655
17740
  width: b.width ?? null,
@@ -17731,8 +17816,6 @@ function createHfImageBatchHistory(options) {
17731
17816
  }
17732
17817
 
17733
17818
  // src/lib/szenen/hfImageBatchPersistence.ts
17734
- init_hfStateService();
17735
- init_hfEventLog();
17736
17819
  function fehler3(nachricht, retryable = true) {
17737
17820
  return { kind: "error", message: nachricht, retryable };
17738
17821
  }
@@ -17740,6 +17823,7 @@ async function legeBatchAb(options, input) {
17740
17823
  const { namespace, token, channel } = options;
17741
17824
  const newImageId = options.newImageId ?? ((batchId, position) => `${batchId}-${position}`);
17742
17825
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
17826
+ const store = options.store ?? createHfImageStore({ namespace, token });
17743
17827
  const itemId = itemIdForRun(input.runId);
17744
17828
  let vorhandeneEvents;
17745
17829
  try {
@@ -17758,15 +17842,14 @@ async function legeBatchAb(options, input) {
17758
17842
  for (let offset = 0; offset < input.images.length; offset++) {
17759
17843
  const bild = input.images[offset];
17760
17844
  const id = newImageId(input.generationBatchId, startPosition + offset);
17845
+ const echterTyp = typAusBytes(bild.imageBase64, bild.mimeType);
17761
17846
  try {
17762
- await hfUploadImage(bild.imageBase64, id, token, bild.mimeType);
17763
- await writeHFEvent(namespace, token, "image_added", {
17847
+ await store.putWithId(
17764
17848
  id,
17765
- prompt: input.title ?? `Batch ${input.generationBatchId}`,
17766
- tags: [],
17767
- timestamp: now().getTime(),
17768
- mimeType: bild.mimeType
17769
- }, []);
17849
+ bild.imageBase64,
17850
+ echterTyp,
17851
+ input.title ?? `Batch ${input.generationBatchId}`
17852
+ );
17770
17853
  } catch (error) {
17771
17854
  return fehler3(
17772
17855
  `Bild ${offset + 1}/${input.images.length} des Batches ${input.generationBatchId} konnte nicht im Bildbestand abgelegt werden: ${error instanceof Error ? error.message : String(error)}. Bereits abgelegte Bilder dieses Versuchs (${abgelegt.length}) bleiben im Bestand, geh\xF6ren aber zu keinem Batch, solange das Batch-Ereignis nicht geschrieben ist.`
@@ -17776,6 +17859,7 @@ async function legeBatchAb(options, input) {
17776
17859
  position: startPosition + offset,
17777
17860
  media_ref: id,
17778
17861
  asset_id: id,
17862
+ mime_type: echterTyp,
17779
17863
  model: bild.model ?? null,
17780
17864
  seed: bild.seed ?? null,
17781
17865
  width: bild.width ?? null,
@@ -17819,8 +17903,11 @@ function createHfImageGenerationBatchPersistence(options) {
17819
17903
  images: input.images.map((bild) => ({
17820
17904
  imageBase64: bild.imageBase64,
17821
17905
  // Flow liefert PNG-Base64 (bestehende Konvention, s. AvatarArchitectApp.tsx
17822
- // `data:image/png;base64,${base64}`); der gemeinsame Vertrag führt
17823
- // keinen MIME-Typ je Bild.
17906
+ // `data:image/png;base64,${base64}`), und der gemeinsame Vertrag führt
17907
+ // keinen MIME-Typ je Bild. Das ist deshalb nur die **Vorgabe**:
17908
+ // Entschieden wird nach den echten Bytes (Review §5 P2) — ein künftig
17909
+ // anders kodiertes Bild läge sonst unter einer Endung, unter der es
17910
+ // niemand sucht.
17824
17911
  mimeType: "image/png",
17825
17912
  model: bild.model ?? null,
17826
17913
  seed: bild.seed ?? null,
@@ -17841,6 +17928,8 @@ function createHfImageBatchWrite(options) {
17841
17928
  title: input.title,
17842
17929
  images: input.images.map((bild) => ({
17843
17930
  imageBase64: bild.imageBase64,
17931
+ // Vorgabe, kein Urteil — der Import bringt beliebig kodierte Bilder
17932
+ // mit, und der Typ wird aus den Bytes bestimmt (Review §5 P2).
17844
17933
  mimeType: "image/png",
17845
17934
  model: bild.model ?? null,
17846
17935
  seed: bild.seed ?? null,
@@ -18129,7 +18218,17 @@ function createFlowSzenenViewPort(options) {
18129
18218
  ...options.newRunId ? { newRunId: options.newRunId } : {},
18130
18219
  ...options.now ? { now: options.now } : {}
18131
18220
  });
18132
- const imageLibrary = options.imageLibrary ?? (options.namespace?.trim() && options.token?.trim() ? createHfImageLibrary({ namespace: options.namespace, token: options.token }) : void 0);
18221
+ const hatHfZugangsdaten = Boolean(options.namespace?.trim() && options.token?.trim());
18222
+ const bildSpeicher = hatHfZugangsdaten ? createHfImageStore({
18223
+ namespace: options.namespace,
18224
+ token: options.token,
18225
+ ...options.now ? { now: () => options.now().getTime() } : {}
18226
+ }) : void 0;
18227
+ const imageLibrary = options.imageLibrary ?? (bildSpeicher ? createHfImageLibrary({
18228
+ namespace: options.namespace,
18229
+ token: options.token,
18230
+ store: bildSpeicher
18231
+ }) : void 0);
18133
18232
  const derivation = createClientDerivationPort({
18134
18233
  store: elements,
18135
18234
  derivations: createEventLogDerivationPersistence(channel),
@@ -18139,11 +18238,11 @@ function createFlowSzenenViewPort(options) {
18139
18238
  ...options.now ? { now: options.now } : {}
18140
18239
  });
18141
18240
  const imageBatchHistory = createHfImageBatchHistory({ channel });
18142
- const hatHfZugangsdaten = Boolean(options.namespace?.trim() && options.token?.trim());
18143
- const imageBatchWrite = hatHfZugangsdaten ? createHfImageBatchWrite({
18241
+ const imageBatchWrite = bildSpeicher ? createHfImageBatchWrite({
18144
18242
  namespace: options.namespace,
18145
18243
  token: options.token,
18146
18244
  channel,
18245
+ store: bildSpeicher,
18147
18246
  ...options.newBatchImageId ? { newImageId: options.newBatchImageId } : {},
18148
18247
  ...options.now ? { now: options.now } : {}
18149
18248
  }) : void 0;
@@ -18157,6 +18256,9 @@ function createFlowSzenenViewPort(options) {
18157
18256
  namespace: options.namespace,
18158
18257
  token: options.token,
18159
18258
  channel,
18259
+ // Dieselbe Instanz wie der Bildbestand — sonst wäre das gerade
18260
+ // erzeugte Bild in der Laufansicht wieder unauffindbar (R1).
18261
+ store: bildSpeicher,
18160
18262
  ...options.newBatchImageId ? { newImageId: options.newBatchImageId } : {},
18161
18263
  ...options.now ? { now: options.now } : {}
18162
18264
  }),
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  SzenenView,
3
+ applyEvents,
3
4
  createFlowSzenenViewPort
4
- } from "./chunk-MILMVOK7.mjs";
5
+ } from "./chunk-ZVHEHQ7A.mjs";
5
6
  import "./chunk-FUY2OCVC.mjs";
6
7
  import {
7
8
  exportProjectToZip,
@@ -27,10 +28,10 @@ import {
27
28
  setHFToken,
28
29
  tsFromEventPath,
29
30
  writeHFEvent
30
- } from "./chunk-LFPOXNOZ.mjs";
31
+ } from "./chunk-NBUS7AWR.mjs";
31
32
 
32
33
  // package.json
33
- var version = "2.0.85";
34
+ var version = "2.0.87";
34
35
 
35
36
  // src/hooks/useOnClickOutside.ts
36
37
  import { useEffect } from "react";
@@ -2308,7 +2309,7 @@ var ProjectSyncTab = ({
2308
2309
  {
2309
2310
  onClick: async () => {
2310
2311
  try {
2311
- const { hfDownloadProject: hfDownloadProject2 } = await import("./hfStateService-PZH2IDKF.mjs");
2312
+ const { hfDownloadProject: hfDownloadProject2 } = await import("./hfStateService-W7KO2FOH.mjs");
2312
2313
  const file = await hfDownloadProject2(p.path, hfToken);
2313
2314
  onHfLoad(file);
2314
2315
  } catch (e) {
@@ -2532,75 +2533,6 @@ function toPromptImages(images) {
2532
2533
  // src/hooks/useHFState.ts
2533
2534
  import { useState as useState11, useEffect as useEffect7, useRef as useRef8, useCallback } from "react";
2534
2535
 
2535
- // src/lib/hfReducer.ts
2536
- function applyEvent(state, event) {
2537
- if (event.v.major > 1) return state;
2538
- switch (event.type) {
2539
- // SPEZ: image_added (state/spez/hf-state.spez.yaml)
2540
- case "image_added": {
2541
- const p = event.payload;
2542
- if (state.metadata.some((m) => m.id === p.id)) return state;
2543
- return { ...state, metadata: [...state.metadata, p] };
2544
- }
2545
- // SPEZ: task_requested (global/spez/task-queue.spez.yaml)
2546
- case "task_requested": {
2547
- const p = event.payload;
2548
- if (p.expiresAt && p.expiresAt < event.ts) return state;
2549
- const openTasks = { ...state.openTasks || {} };
2550
- openTasks[p.taskId] = p;
2551
- return { ...state, openTasks };
2552
- }
2553
- // SPEZ: task_completed (global/spez/task-queue.spez.yaml)
2554
- case "task_completed": {
2555
- const p = event.payload;
2556
- if (!state.openTasks || !state.openTasks[p.taskId]) return state;
2557
- const openTasks = { ...state.openTasks };
2558
- delete openTasks[p.taskId];
2559
- return { ...state, openTasks };
2560
- }
2561
- // SPEZ: tag_upserted (state/spez/hf-state.spez.yaml) — Legacy, wird nicht mehr erzeugt
2562
- case "tag_upserted": {
2563
- const p = event.payload;
2564
- const tags = state.tags;
2565
- const cat = tags.by_category[p.category] || [];
2566
- const existing = cat.find((t) => t.value === p.value);
2567
- const updated = { label: p.label, value: p.value, is_user_created: p.is_user_created, is_deleted: p.is_deleted };
2568
- const newCat = existing ? cat.map((t) => t.value === p.value ? { ...t, ...updated } : t) : [...cat, updated];
2569
- const newAll = tags.all.some((t) => t.value === p.value && t.category === p.category) ? tags.all.map((t) => t.value === p.value && t.category === p.category ? { ...t, ...updated, category: p.category } : t) : [...tags.all, { ...updated, category: p.category }];
2570
- return { ...state, tags: { by_category: { ...tags.by_category, [p.category]: newCat }, all: newAll } };
2571
- }
2572
- // SPEZ: thumb_added (state/spez/hf-state.spez.yaml)
2573
- case "thumb_added": {
2574
- const p = event.payload;
2575
- return {
2576
- ...state,
2577
- metadata: state.metadata.map((m) => m.id === p.id ? { ...m, hasThumb: true } : m)
2578
- };
2579
- }
2580
- // SPEZ: metadata_updated (state/spez/hf-state.spez.yaml)
2581
- case "metadata_updated": {
2582
- const p = event.payload;
2583
- return {
2584
- ...state,
2585
- metadata: state.metadata.map((m) => m.id === p.id ? { ...m, ...p.delta } : m)
2586
- };
2587
- }
2588
- // SPEZ: title_set (state/spez/hf-state.spez.yaml)
2589
- case "title_set": {
2590
- const p = event.payload;
2591
- return {
2592
- ...state,
2593
- metadata: state.metadata.map((m) => m.id === p.id ? { ...m, titleTs: event.ts } : m)
2594
- };
2595
- }
2596
- default:
2597
- return state;
2598
- }
2599
- }
2600
- function applyEvents(state, events) {
2601
- return events.reduce(applyEvent, state);
2602
- }
2603
-
2604
2536
  // src/lib/hfDag.ts
2605
2537
  function buildDag(events) {
2606
2538
  const dag = /* @__PURE__ */ new Map();
@@ -6856,7 +6788,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
6856
6788
  onClick: async () => {
6857
6789
  setIsLoadingFromHF(true);
6858
6790
  try {
6859
- const { hfListProjects: hfListProjects2, hfDownloadProject: hfDownloadProject2 } = await import("./hfStateService-PZH2IDKF.mjs");
6791
+ const { hfListProjects: hfListProjects2, hfDownloadProject: hfDownloadProject2 } = await import("./hfStateService-W7KO2FOH.mjs");
6860
6792
  const projects = await hfListProjects2(hfToken);
6861
6793
  if (projects.length > 0) {
6862
6794
  const file = await hfDownloadProject2(projects[0].path, hfToken);