@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/szenen.js CHANGED
@@ -59,6 +59,7 @@ __export(szenen_exports, {
59
59
  areasFor: () => areasFor,
60
60
  assessDerivationResponse: () => assessDerivationResponse,
61
61
  batchesForPromptRun: () => batchesForPromptRun,
62
+ bildPfad: () => bildPfad,
62
63
  buildDerivationSystemInstruction: () => buildSystemInstruction2,
63
64
  buildDerivationUserPrompt: () => buildUserPrompt2,
64
65
  buildSystemInstruction: () => buildSystemInstruction,
@@ -114,6 +115,7 @@ __export(szenen_exports, {
114
115
  createHfImageBatchWrite: () => createHfImageBatchWrite,
115
116
  createHfImageGenerationBatchPersistence: () => createHfImageGenerationBatchPersistence,
116
117
  createHfImageLibrary: () => createHfImageLibrary,
118
+ createHfImageStore: () => createHfImageStore,
117
119
  createImageGenerationPort: () => createImageGenerationPort,
118
120
  createInMemoryEventChannel: () => createInMemoryEventChannel,
119
121
  createMemoryViewPort: () => createMemoryViewPort,
@@ -172,6 +174,7 @@ __export(szenen_exports, {
172
174
  showChain: () => showChain,
173
175
  simulatedAnswerFor: () => simulatedAnswerFor,
174
176
  totalModelCalls: () => totalModelCalls,
177
+ typAusBytes: () => typAusBytes,
175
178
  unclassifiedPublishRules: () => unclassifiedPublishRules,
176
179
  unsupportedReason: () => unsupportedReason,
177
180
  validateAgainst: () => validateAgainst,
@@ -7563,6 +7566,12 @@ function createHfElementStore(options) {
7563
7566
  var HF_BASE = "https://huggingface.co";
7564
7567
  var HF_REPO = "RolandSch/fa-app-state";
7565
7568
  var CURRENT_EVENT_VERSION = { major: 1, minor: 0 };
7569
+ var SPEICHERBARE_BILDTYPEN = ["image/png", "image/jpeg", "image/webp"];
7570
+ function bildEndungFuer(mimeType) {
7571
+ if (mimeType === "image/png") return "png";
7572
+ if (mimeType === "image/webp") return "webp";
7573
+ return "jpg";
7574
+ }
7566
7575
 
7567
7576
  // src/lib/hfEventLog.ts
7568
7577
  function treeUrl(namespace, subdir = "") {
@@ -7595,8 +7604,8 @@ async function mitGeduld(anfrage) {
7595
7604
  letzte = res;
7596
7605
  if (versuch === DROSSEL_VERSUCHE - 1) break;
7597
7606
  const angesagt = Number(res.headers.get("retry-after"));
7598
- const warten = Number.isFinite(angesagt) && angesagt > 0 ? angesagt * 1e3 : DROSSEL_BASIS_MS * 2 ** versuch;
7599
- await schlafen(warten);
7607
+ const warten2 = Number.isFinite(angesagt) && angesagt > 0 ? angesagt * 1e3 : DROSSEL_BASIS_MS * 2 ** versuch;
7608
+ await schlafen(warten2);
7600
7609
  }
7601
7610
  return letzte;
7602
7611
  }
@@ -9305,7 +9314,7 @@ async function loadHFState(namespace, token) {
9305
9314
  };
9306
9315
  }
9307
9316
  async function hfUploadImage(base64, id, token, mimeType = "image/jpeg") {
9308
- const ext = mimeType === "image/png" ? "png" : "jpg";
9317
+ const ext = bildEndungFuer(mimeType);
9309
9318
  const binary = atob(base64);
9310
9319
  const bytes = new Uint8Array(binary.length);
9311
9320
  for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
@@ -9347,11 +9356,187 @@ async function hfLoadImageAsBase64(id, token, namespace, filename, on404, mimeTy
9347
9356
  const result2 = await fetchBase64(`images/${filename}`);
9348
9357
  return result2 === "ABORT" ? null : result2;
9349
9358
  }
9350
- const ext = mimeType === "image/png" ? "png" : "jpg";
9359
+ const ext = bildEndungFuer(mimeType);
9351
9360
  const result = await fetchBase64(`images/${id}.${ext}`);
9352
9361
  return result === "ABORT" ? null : result;
9353
9362
  }
9354
9363
 
9364
+ // src/lib/hfReducer.ts
9365
+ function applyEvent(state, event) {
9366
+ if (event.v.major > 1) return state;
9367
+ switch (event.type) {
9368
+ // SPEZ: image_added (state/spez/hf-state.spez.yaml)
9369
+ case "image_added": {
9370
+ const p = event.payload;
9371
+ if (state.metadata.some((m) => m.id === p.id)) return state;
9372
+ return { ...state, metadata: [...state.metadata, p] };
9373
+ }
9374
+ // SPEZ: task_requested (global/spez/task-queue.spez.yaml)
9375
+ case "task_requested": {
9376
+ const p = event.payload;
9377
+ if (p.expiresAt && p.expiresAt < event.ts) return state;
9378
+ const openTasks = { ...state.openTasks || {} };
9379
+ openTasks[p.taskId] = p;
9380
+ return { ...state, openTasks };
9381
+ }
9382
+ // SPEZ: task_completed (global/spez/task-queue.spez.yaml)
9383
+ case "task_completed": {
9384
+ const p = event.payload;
9385
+ if (!state.openTasks || !state.openTasks[p.taskId]) return state;
9386
+ const openTasks = { ...state.openTasks };
9387
+ delete openTasks[p.taskId];
9388
+ return { ...state, openTasks };
9389
+ }
9390
+ // SPEZ: tag_upserted (state/spez/hf-state.spez.yaml) — Legacy, wird nicht mehr erzeugt
9391
+ case "tag_upserted": {
9392
+ const p = event.payload;
9393
+ const tags = state.tags;
9394
+ const cat = tags.by_category[p.category] || [];
9395
+ const existing = cat.find((t) => t.value === p.value);
9396
+ const updated = { label: p.label, value: p.value, is_user_created: p.is_user_created, is_deleted: p.is_deleted };
9397
+ const newCat = existing ? cat.map((t) => t.value === p.value ? { ...t, ...updated } : t) : [...cat, updated];
9398
+ 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 }];
9399
+ return { ...state, tags: { by_category: { ...tags.by_category, [p.category]: newCat }, all: newAll } };
9400
+ }
9401
+ // SPEZ: thumb_added (state/spez/hf-state.spez.yaml)
9402
+ case "thumb_added": {
9403
+ const p = event.payload;
9404
+ return {
9405
+ ...state,
9406
+ metadata: state.metadata.map((m) => m.id === p.id ? { ...m, hasThumb: true } : m)
9407
+ };
9408
+ }
9409
+ // SPEZ: metadata_updated (state/spez/hf-state.spez.yaml)
9410
+ case "metadata_updated": {
9411
+ const p = event.payload;
9412
+ return {
9413
+ ...state,
9414
+ metadata: state.metadata.map((m) => m.id === p.id ? { ...m, ...p.delta } : m)
9415
+ };
9416
+ }
9417
+ // SPEZ: title_set (state/spez/hf-state.spez.yaml)
9418
+ case "title_set": {
9419
+ const p = event.payload;
9420
+ return {
9421
+ ...state,
9422
+ metadata: state.metadata.map((m) => m.id === p.id ? { ...m, titleTs: event.ts } : m)
9423
+ };
9424
+ }
9425
+ default:
9426
+ return state;
9427
+ }
9428
+ }
9429
+ function applyEvents(state, events) {
9430
+ return events.reduce(applyEvent, state);
9431
+ }
9432
+
9433
+ // src/lib/szenen/hfImageStore.ts
9434
+ var LEERER_BESTAND = {
9435
+ metadata: [],
9436
+ tags: { by_category: {}, all: [] },
9437
+ meta: { consolidatedAt: 0, version: 1 }
9438
+ };
9439
+ var endungFuer = bildEndungFuer;
9440
+ function bildPfad(id, mimeType) {
9441
+ return `images/${id}.${endungFuer(mimeType)}`;
9442
+ }
9443
+ function typAusBytes(base64, vorgabe = "image/png") {
9444
+ const kopf = base64.slice(0, 16);
9445
+ if (kopf.startsWith("iVBORw0KGgo")) return "image/png";
9446
+ if (kopf.startsWith("/9j/")) return "image/jpeg";
9447
+ if (kopf.startsWith("UklGR")) return "image/webp";
9448
+ if (kopf.startsWith("R0lGOD")) return "image/gif";
9449
+ return vorgabe;
9450
+ }
9451
+ var warten = (ms) => new Promise((r) => setTimeout(r, ms));
9452
+ function createHfImageStore(options) {
9453
+ const { namespace, token } = options;
9454
+ const now = options.now ?? (() => Date.now());
9455
+ const versuche = options.leseVersuche ?? 4;
9456
+ const basisMs = options.leseBasisMs ?? 400;
9457
+ const schlafen2 = options.schlafen ?? warten;
9458
+ const abgelegt = /* @__PURE__ */ new Map();
9459
+ const bekanntePfade = /* @__PURE__ */ new Set();
9460
+ let gefalteterBestand = null;
9461
+ let laufenderAbgleich = null;
9462
+ async function bestandLesen() {
9463
+ const grundlage = gefalteterBestand ?? await loadHFState(namespace, token) ?? LEERER_BESTAND;
9464
+ const neue = await loadPendingEvents(
9465
+ namespace,
9466
+ token,
9467
+ grundlage.meta.consolidatedAt,
9468
+ bekanntePfade
9469
+ );
9470
+ const danach = neue.filter((e) => e.ts > grundlage.meta.consolidatedAt);
9471
+ gefalteterBestand = danach.length ? applyEvents(grundlage, danach) : grundlage;
9472
+ return gefalteterBestand;
9473
+ }
9474
+ function bestandAbgleichen() {
9475
+ if (!laufenderAbgleich) {
9476
+ laufenderAbgleich = bestandLesen().finally(() => {
9477
+ laufenderAbgleich = null;
9478
+ });
9479
+ }
9480
+ return laufenderAbgleich;
9481
+ }
9482
+ return {
9483
+ bestand: bestandAbgleichen,
9484
+ async putWithId(id, base64, mimeType, titel) {
9485
+ const echterTyp = typAusBytes(base64, mimeType);
9486
+ if (!SPEICHERBARE_BILDTYPEN.includes(echterTyp)) {
9487
+ throw new Error(
9488
+ `Das Bild ${id} ist ${echterTyp}; der Bildbestand kann nur ${SPEICHERBARE_BILDTYPEN.join(", ")} wahrheitsgemaess ablegen. Es wurde nichts geschrieben.`
9489
+ );
9490
+ }
9491
+ await hfUploadImage(base64, id, token, echterTyp);
9492
+ await writeHFEvent(namespace, token, "image_added", {
9493
+ id,
9494
+ prompt: titel ?? id,
9495
+ tags: [],
9496
+ timestamp: now(),
9497
+ mimeType: echterTyp
9498
+ }, []);
9499
+ abgelegt.set(id, { data: base64, mimeType: echterTyp });
9500
+ },
9501
+ async resolve(id, mimeType) {
9502
+ const eben = abgelegt.get(id);
9503
+ if (eben) return eben;
9504
+ const zustand = await bestandAbgleichen();
9505
+ const eintrag = zustand.metadata.find((e) => e.id === id);
9506
+ const typ = eintrag?.mimeType || mimeType || null;
9507
+ if (eintrag) {
9508
+ const base64 = await hfLoadImageAsBase64(
9509
+ id,
9510
+ token,
9511
+ void 0,
9512
+ eintrag.filename,
9513
+ void 0,
9514
+ eintrag.mimeType,
9515
+ false
9516
+ );
9517
+ if (base64) return { data: base64, mimeType: eintrag.mimeType || "image/jpeg" };
9518
+ }
9519
+ const pfadTyp = typ ?? "image/png";
9520
+ for (let versuch = 0; versuch < versuche; versuch += 1) {
9521
+ if (versuch > 0) await schlafen2(basisMs * 2 ** (versuch - 1));
9522
+ const base64 = await hfLoadImageAsBase64(
9523
+ id,
9524
+ token,
9525
+ void 0,
9526
+ void 0,
9527
+ void 0,
9528
+ pfadTyp,
9529
+ false
9530
+ );
9531
+ if (base64) return { data: base64, mimeType: pfadTyp };
9532
+ }
9533
+ throw new Error(
9534
+ `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).")
9535
+ );
9536
+ }
9537
+ };
9538
+ }
9539
+
9355
9540
  // src/lib/szenen/hfImageLibrary.ts
9356
9541
  function fehler(nachricht, retryable = false) {
9357
9542
  return { kind: "error", message: nachricht, retryable };
@@ -9367,14 +9552,16 @@ function alsBild(eintrag) {
9367
9552
  };
9368
9553
  }
9369
9554
  function createHfImageLibrary(options) {
9370
- const { namespace, token } = options;
9371
9555
  const newImageId = options.newImageId ?? (() => crypto.randomUUID());
9372
- const now = options.now ?? (() => Date.now());
9373
- const frisch = /* @__PURE__ */ new Map();
9556
+ const store = options.store ?? createHfImageStore({
9557
+ namespace: options.namespace,
9558
+ token: options.token,
9559
+ ...options.now ? { now: options.now } : {}
9560
+ });
9374
9561
  return {
9375
9562
  async listImages(query) {
9376
9563
  try {
9377
- const zustand = await loadHFState(namespace, token);
9564
+ const zustand = await store.bestand();
9378
9565
  const eintraege = zustand?.metadata ?? [];
9379
9566
  const gesucht = query?.search?.trim().toLowerCase();
9380
9567
  const gefiltert = gesucht ? eintraege.filter((e) => (e.prompt ?? "").toLowerCase().includes(gesucht) || e.id.toLowerCase().includes(gesucht)) : eintraege;
@@ -9388,54 +9575,18 @@ function createHfImageLibrary(options) {
9388
9575
  );
9389
9576
  }
9390
9577
  },
9391
- async resolveImage(mediaRef) {
9392
- const eben = frisch.get(mediaRef);
9393
- if (eben) return { kind: "ok", value: { data: eben.data, mime_type: eben.mimeType } };
9578
+ async resolveImage(mediaRef, mimeTypeHinweis) {
9394
9579
  try {
9395
- const zustand = await loadHFState(namespace, token);
9396
- const eintrag = (zustand?.metadata ?? []).find((e) => e.id === mediaRef);
9397
- if (eintrag) {
9398
- const base64 = await hfLoadImageAsBase64(
9399
- mediaRef,
9400
- token,
9401
- void 0,
9402
- eintrag.filename,
9403
- void 0,
9404
- eintrag.mimeType,
9405
- false
9406
- );
9407
- if (!base64) {
9408
- return fehler(`Das Bild ${mediaRef} ist im Bestand verzeichnet, aber nicht ladbar.`, true);
9409
- }
9410
- return { kind: "ok", value: { data: base64, mime_type: eintrag.mimeType || "image/jpeg" } };
9411
- }
9412
- for (const mimeType of ["image/png", "image/jpeg"]) {
9413
- const base64 = await hfLoadImageAsBase64(mediaRef, token, void 0, void 0, void 0, mimeType, false);
9414
- if (base64) return { kind: "ok", value: { data: base64, mime_type: mimeType } };
9415
- }
9416
- return fehler(
9417
- `Das Bild ${mediaRef} steht nicht im Bestand. Moeglicherweise hat der Abgleich es noch nicht uebertragen.`,
9418
- true
9419
- );
9580
+ const bild = await store.resolve(mediaRef, mimeTypeHinweis);
9581
+ return { kind: "ok", value: { data: bild.data, mime_type: bild.mimeType } };
9420
9582
  } catch (error) {
9421
- return fehler(
9422
- `Das Bild ${mediaRef} konnte nicht geladen werden: ${error instanceof Error ? error.message : String(error)}`,
9423
- true
9424
- );
9583
+ return fehler(error instanceof Error ? error.message : String(error), true);
9425
9584
  }
9426
9585
  },
9427
9586
  async putImage(input) {
9428
9587
  const id = newImageId();
9429
9588
  try {
9430
- await hfUploadImage(input.data, id, token, input.mime_type);
9431
- await writeHFEvent(namespace, token, "image_added", {
9432
- id,
9433
- prompt: input.title,
9434
- tags: [],
9435
- timestamp: now(),
9436
- mimeType: input.mime_type
9437
- }, []);
9438
- frisch.set(id, { mimeType: input.mime_type, data: input.data });
9589
+ await store.putWithId(id, input.data, input.mime_type, input.title);
9439
9590
  return {
9440
9591
  kind: "ok",
9441
9592
  value: { mediaRef: id, title: input.title, mimeType: input.mime_type, thumbUrl: null }
@@ -11142,6 +11293,11 @@ function alsBilder(rohe) {
11142
11293
  media_ref: b.media_ref,
11143
11294
  position: b.position,
11144
11295
  ...istText4(b.asset_id) ? { asset_id: b.asset_id } : {},
11296
+ // Der bestätigte MIME-Typ (Review 2026-08-18 §5 P2) muss durch das
11297
+ // Rücklesen hindurch: Genau hier braucht ihn der Lesepfad, um den
11298
+ // Dateipfad `images/<id>.<ext>` zu bilden, statt ihn zu erraten. Nur
11299
+ // gesetzt, wenn er im Ereignis steht — ältere Batches tragen ihn nicht.
11300
+ ...istText4(b.mime_type) ? { mime_type: b.mime_type } : {},
11145
11301
  model: b.model ?? null,
11146
11302
  seed: b.seed ?? null,
11147
11303
  width: b.width ?? null,
@@ -11230,6 +11386,7 @@ async function legeBatchAb(options, input) {
11230
11386
  const { namespace, token, channel } = options;
11231
11387
  const newImageId = options.newImageId ?? ((batchId, position) => `${batchId}-${position}`);
11232
11388
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
11389
+ const store = options.store ?? createHfImageStore({ namespace, token });
11233
11390
  const itemId = itemIdForRun(input.runId);
11234
11391
  let vorhandeneEvents;
11235
11392
  try {
@@ -11248,15 +11405,14 @@ async function legeBatchAb(options, input) {
11248
11405
  for (let offset = 0; offset < input.images.length; offset++) {
11249
11406
  const bild = input.images[offset];
11250
11407
  const id = newImageId(input.generationBatchId, startPosition + offset);
11408
+ const echterTyp = typAusBytes(bild.imageBase64, bild.mimeType);
11251
11409
  try {
11252
- await hfUploadImage(bild.imageBase64, id, token, bild.mimeType);
11253
- await writeHFEvent(namespace, token, "image_added", {
11410
+ await store.putWithId(
11254
11411
  id,
11255
- prompt: input.title ?? `Batch ${input.generationBatchId}`,
11256
- tags: [],
11257
- timestamp: now().getTime(),
11258
- mimeType: bild.mimeType
11259
- }, []);
11412
+ bild.imageBase64,
11413
+ echterTyp,
11414
+ input.title ?? `Batch ${input.generationBatchId}`
11415
+ );
11260
11416
  } catch (error) {
11261
11417
  return fehler3(
11262
11418
  `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.`
@@ -11266,6 +11422,7 @@ async function legeBatchAb(options, input) {
11266
11422
  position: startPosition + offset,
11267
11423
  media_ref: id,
11268
11424
  asset_id: id,
11425
+ mime_type: echterTyp,
11269
11426
  model: bild.model ?? null,
11270
11427
  seed: bild.seed ?? null,
11271
11428
  width: bild.width ?? null,
@@ -11309,8 +11466,11 @@ function createHfImageGenerationBatchPersistence(options) {
11309
11466
  images: input.images.map((bild) => ({
11310
11467
  imageBase64: bild.imageBase64,
11311
11468
  // Flow liefert PNG-Base64 (bestehende Konvention, s. AvatarArchitectApp.tsx
11312
- // `data:image/png;base64,${base64}`); der gemeinsame Vertrag führt
11313
- // keinen MIME-Typ je Bild.
11469
+ // `data:image/png;base64,${base64}`), und der gemeinsame Vertrag führt
11470
+ // keinen MIME-Typ je Bild. Das ist deshalb nur die **Vorgabe**:
11471
+ // Entschieden wird nach den echten Bytes (Review §5 P2) — ein künftig
11472
+ // anders kodiertes Bild läge sonst unter einer Endung, unter der es
11473
+ // niemand sucht.
11314
11474
  mimeType: "image/png",
11315
11475
  model: bild.model ?? null,
11316
11476
  seed: bild.seed ?? null,
@@ -11331,6 +11491,8 @@ function createHfImageBatchWrite(options) {
11331
11491
  title: input.title,
11332
11492
  images: input.images.map((bild) => ({
11333
11493
  imageBase64: bild.imageBase64,
11494
+ // Vorgabe, kein Urteil — der Import bringt beliebig kodierte Bilder
11495
+ // mit, und der Typ wird aus den Bytes bestimmt (Review §5 P2).
11334
11496
  mimeType: "image/png",
11335
11497
  model: bild.model ?? null,
11336
11498
  seed: bild.seed ?? null,
@@ -11404,7 +11566,17 @@ function createFlowSzenenViewPort(options) {
11404
11566
  ...options.newRunId ? { newRunId: options.newRunId } : {},
11405
11567
  ...options.now ? { now: options.now } : {}
11406
11568
  });
11407
- const imageLibrary = options.imageLibrary ?? (options.namespace?.trim() && options.token?.trim() ? createHfImageLibrary({ namespace: options.namespace, token: options.token }) : void 0);
11569
+ const hatHfZugangsdaten = Boolean(options.namespace?.trim() && options.token?.trim());
11570
+ const bildSpeicher = hatHfZugangsdaten ? createHfImageStore({
11571
+ namespace: options.namespace,
11572
+ token: options.token,
11573
+ ...options.now ? { now: () => options.now().getTime() } : {}
11574
+ }) : void 0;
11575
+ const imageLibrary = options.imageLibrary ?? (bildSpeicher ? createHfImageLibrary({
11576
+ namespace: options.namespace,
11577
+ token: options.token,
11578
+ store: bildSpeicher
11579
+ }) : void 0);
11408
11580
  const derivation = createClientDerivationPort({
11409
11581
  store: elements,
11410
11582
  derivations: createEventLogDerivationPersistence(channel),
@@ -11414,11 +11586,11 @@ function createFlowSzenenViewPort(options) {
11414
11586
  ...options.now ? { now: options.now } : {}
11415
11587
  });
11416
11588
  const imageBatchHistory = createHfImageBatchHistory({ channel });
11417
- const hatHfZugangsdaten = Boolean(options.namespace?.trim() && options.token?.trim());
11418
- const imageBatchWrite = hatHfZugangsdaten ? createHfImageBatchWrite({
11589
+ const imageBatchWrite = bildSpeicher ? createHfImageBatchWrite({
11419
11590
  namespace: options.namespace,
11420
11591
  token: options.token,
11421
11592
  channel,
11593
+ store: bildSpeicher,
11422
11594
  ...options.newBatchImageId ? { newImageId: options.newBatchImageId } : {},
11423
11595
  ...options.now ? { now: options.now } : {}
11424
11596
  }) : void 0;
@@ -11432,6 +11604,9 @@ function createFlowSzenenViewPort(options) {
11432
11604
  namespace: options.namespace,
11433
11605
  token: options.token,
11434
11606
  channel,
11607
+ // Dieselbe Instanz wie der Bildbestand — sonst wäre das gerade
11608
+ // erzeugte Bild in der Laufansicht wieder unauffindbar (R1).
11609
+ store: bildSpeicher,
11435
11610
  ...options.newBatchImageId ? { newImageId: options.newBatchImageId } : {},
11436
11611
  ...options.now ? { now: options.now } : {}
11437
11612
  }),
@@ -12915,8 +13090,8 @@ var BestandsBild = ({ port, mediaRef }) => {
12915
13090
  };
12916
13091
  var BatchBild = ({ port, bild }) => {
12917
13092
  const [phase] = usePortQuery(
12918
- () => port.imageLibrary ? port.imageLibrary.resolveImage(bild.media_ref) : Promise.resolve({ kind: "ok", value: null }),
12919
- [port, bild.media_ref]
13093
+ () => port.imageLibrary ? port.imageLibrary.resolveImage(bild.media_ref, bild.mime_type ?? null) : Promise.resolve({ kind: "ok", value: null }),
13094
+ [port, bild.media_ref, bild.mime_type]
12920
13095
  );
12921
13096
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { "data-testid": `batchbild-${bild.media_ref}`, children: [
12922
13097
  phase.status === "ready" && phase.value && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
@@ -14961,6 +15136,7 @@ var SzenenView = ({
14961
15136
  areasFor,
14962
15137
  assessDerivationResponse,
14963
15138
  batchesForPromptRun,
15139
+ bildPfad,
14964
15140
  buildDerivationSystemInstruction,
14965
15141
  buildDerivationUserPrompt,
14966
15142
  buildSystemInstruction,
@@ -15016,6 +15192,7 @@ var SzenenView = ({
15016
15192
  createHfImageBatchWrite,
15017
15193
  createHfImageGenerationBatchPersistence,
15018
15194
  createHfImageLibrary,
15195
+ createHfImageStore,
15019
15196
  createImageGenerationPort,
15020
15197
  createInMemoryEventChannel,
15021
15198
  createMemoryViewPort,
@@ -15074,6 +15251,7 @@ var SzenenView = ({
15074
15251
  showChain,
15075
15252
  simulatedAnswerFor,
15076
15253
  totalModelCalls,
15254
+ typAusBytes,
15077
15255
  unclassifiedPublishRules,
15078
15256
  unsupportedReason,
15079
15257
  validateAgainst,
package/dist/szenen.mjs CHANGED
@@ -26,6 +26,7 @@ import {
26
26
  areasFor,
27
27
  assessDerivationResponse,
28
28
  batchesForPromptRun,
29
+ bildPfad,
29
30
  buildSystemInstruction,
30
31
  buildSystemInstruction2,
31
32
  buildUserPrompt,
@@ -75,6 +76,7 @@ import {
75
76
  createHfImageBatchWrite,
76
77
  createHfImageGenerationBatchPersistence,
77
78
  createHfImageLibrary,
79
+ createHfImageStore,
78
80
  createImageGenerationPort,
79
81
  createSimulationSceneDerivationPort,
80
82
  createSimulationTextGenerationPort,
@@ -123,6 +125,7 @@ import {
123
125
  scopeOfPath,
124
126
  showChain,
125
127
  simulatedAnswerFor,
128
+ typAusBytes,
126
129
  unclassifiedPublishRules,
127
130
  unsupportedReason,
128
131
  validateAgainst,
@@ -130,7 +133,7 @@ import {
130
133
  validateElementVersion,
131
134
  validatePayload,
132
135
  withReference
133
- } from "./chunk-MILMVOK7.mjs";
136
+ } from "./chunk-ZVHEHQ7A.mjs";
134
137
  import {
135
138
  ContractViolation,
136
139
  STYLE_PAYLOAD,
@@ -144,7 +147,7 @@ import {
144
147
  preferredVersionId,
145
148
  resolvePreferredHead
146
149
  } from "./chunk-FUY2OCVC.mjs";
147
- import "./chunk-LFPOXNOZ.mjs";
150
+ import "./chunk-NBUS7AWR.mjs";
148
151
 
149
152
  // src/lib/szenen/providerCheckStore.ts
150
153
  function collectProviderChecks(events) {
@@ -1477,6 +1480,7 @@ export {
1477
1480
  areasFor,
1478
1481
  assessDerivationResponse,
1479
1482
  batchesForPromptRun,
1483
+ bildPfad,
1480
1484
  buildSystemInstruction as buildDerivationSystemInstruction,
1481
1485
  buildUserPrompt as buildDerivationUserPrompt,
1482
1486
  buildSystemInstruction2 as buildSystemInstruction,
@@ -1532,6 +1536,7 @@ export {
1532
1536
  createHfImageBatchWrite,
1533
1537
  createHfImageGenerationBatchPersistence,
1534
1538
  createHfImageLibrary,
1539
+ createHfImageStore,
1535
1540
  createImageGenerationPort,
1536
1541
  createInMemoryEventChannel,
1537
1542
  createMemoryViewPort,
@@ -1590,6 +1595,7 @@ export {
1590
1595
  showChain,
1591
1596
  simulatedAnswerFor,
1592
1597
  totalModelCalls,
1598
+ typAusBytes,
1593
1599
  unclassifiedPublishRules,
1594
1600
  unsupportedReason,
1595
1601
  validateAgainst,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rslsp1/fa-app-tools",
3
- "version": "2.0.85",
3
+ "version": "2.0.87",
4
4
  "description": "Shared tools and hooks for Fine Art flow apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -1,73 +0,0 @@
1
- import { T as TextGenerationPort } from './contracts-DdYOMBl9.mjs';
2
-
3
- declare function buildGenerationPrompt(hierarchyText: string, mode?: 'literal' | 'creative'): string;
4
- declare function buildFallbackPrompt(hierarchyText: string): string;
5
- declare function cleanAiResponse(text: string): string;
6
- declare function buildImageGenerationOptions(prompt: string, aspectRatio: string, model: string, referenceMediaId?: string): Record<string, any>;
7
- interface SelectedTag {
8
- label: string;
9
- value: string;
10
- category: string;
11
- }
12
- declare function buildPromptTabPayload(selectedTags: SelectedTag[], instructions: string, rules: string, treeText?: string): string;
13
- declare function parsePromptResponse(raw: string): {
14
- prompt: string;
15
- feedback: string | null;
16
- };
17
- interface FlowSdkImage {
18
- base64: string;
19
- mimeType: string;
20
- }
21
- interface FlowTextGenerationOptions {
22
- images?: FlowSdkImage[];
23
- systemInstruction?: string;
24
- responseFormat?: 'text' | 'json';
25
- thinkingLevel?: 'low' | 'medium' | 'high';
26
- }
27
- interface FlowSdk {
28
- generate: {
29
- image: (options: Record<string, any>) => Promise<{
30
- base64: string;
31
- mediaId: string;
32
- }>;
33
- text: (prompt: string, options?: {
34
- systemInstruction?: string;
35
- thinkingLevel?: string;
36
- images?: FlowSdkImage[];
37
- }) => Promise<{
38
- text: string;
39
- }>;
40
- };
41
- download: (args: {
42
- base64: string;
43
- mimeType: string;
44
- filename: string;
45
- }) => Promise<void>;
46
- media: {
47
- selectMultiple: (args: {
48
- filter: string;
49
- }) => Promise<any[]>;
50
- };
51
- }
52
- declare function createFlowServices(Flow: FlowSdk): {
53
- generateImage: (options: Record<string, any>) => Promise<{
54
- base64: string;
55
- mediaId: string;
56
- }>;
57
- generateText: (text: string, options?: FlowTextGenerationOptions) => Promise<string>;
58
- };
59
- declare function interpretSdkError(err: any): Error;
60
-
61
- type FlowGenerateText = (prompt: string, options?: FlowTextGenerationOptions) => Promise<string>;
62
- interface CreateFlowTextGenerationPortOptions {
63
- provider?: string;
64
- modelId?: string;
65
- }
66
- /**
67
- * Adapts the existing Flow SDK service to the host-neutral Szenen contract.
68
- * It deliberately does not parse or validate the response: that happens once
69
- * in `runPromptDerivation`, identically for every host.
70
- */
71
- declare function createFlowTextGenerationPort(generateText: FlowGenerateText, options?: CreateFlowTextGenerationPortOptions): TextGenerationPort;
72
-
73
- export { type CreateFlowTextGenerationPortOptions as C, type FlowGenerateText as F, type SelectedTag as S, type FlowSdk as a, type FlowTextGenerationOptions as b, buildFallbackPrompt as c, buildGenerationPrompt as d, buildImageGenerationOptions as e, buildPromptTabPayload as f, cleanAiResponse as g, createFlowServices as h, createFlowTextGenerationPort as i, interpretSdkError as j, parsePromptResponse as p };