@rslsp1/fa-app-tools 2.0.81 → 2.0.82

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
@@ -6,7 +6,7 @@ import { Node, Edge } from '@xyflow/react';
6
6
  import * as zustand_vanilla from 'zustand/vanilla';
7
7
  import { F as FeatureSliceId, b as SliceContract, a as PersistenceDescriptor, W as WorkspacePersistence, P as PersistedSlice, L as LoadResult, f as WriteResult, e as WorkspaceTabId, C as CommandResult, R as RequestContext, Q as QueryResult } from './contracts-DdYOMBl9.mjs';
8
8
 
9
- var version = "2.0.81";
9
+ var version = "2.0.82";
10
10
 
11
11
  declare function useOnClickOutside(ref: RefObject<HTMLElement | null>, handler: (e: MouseEvent | TouchEvent) => void): void;
12
12
 
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ import { Node, Edge } from '@xyflow/react';
6
6
  import * as zustand_vanilla from 'zustand/vanilla';
7
7
  import { F as FeatureSliceId, b as SliceContract, a as PersistenceDescriptor, W as WorkspacePersistence, P as PersistedSlice, L as LoadResult, f as WriteResult, e as WorkspaceTabId, C as CommandResult, R as RequestContext, Q as QueryResult } from './contracts-DdYOMBl9.js';
8
8
 
9
- var version = "2.0.81";
9
+ var version = "2.0.82";
10
10
 
11
11
  declare function useOnClickOutside(ref: RefObject<HTMLElement | null>, handler: (e: MouseEvent | TouchEvent) => void): void;
12
12
 
package/dist/index.js CHANGED
@@ -786,7 +786,7 @@ __export(index_exports, {
786
786
  module.exports = __toCommonJS(index_exports);
787
787
 
788
788
  // package.json
789
- var version = "2.0.81";
789
+ var version = "2.0.82";
790
790
 
791
791
  // src/hooks/useOnClickOutside.ts
792
792
  var import_react = require("react");
@@ -3692,6 +3692,21 @@ function validateTagBaseSelection(base, userId, contextId) {
3692
3692
  // src/hooks/useTagBase.ts
3693
3693
  var USER_ID_KEY = "aa-user-id";
3694
3694
  var CONTEXT_ID_KEY = "aa-context-id";
3695
+ var IDENTITY_NAMESPACE_KEY = "aa-identity-namespace";
3696
+ function readStoredNamespace() {
3697
+ try {
3698
+ return localStorage.getItem(IDENTITY_NAMESPACE_KEY);
3699
+ } catch {
3700
+ return null;
3701
+ }
3702
+ }
3703
+ function writeStoredNamespace(namespace) {
3704
+ try {
3705
+ if (namespace === null) localStorage.removeItem(IDENTITY_NAMESPACE_KEY);
3706
+ else localStorage.setItem(IDENTITY_NAMESPACE_KEY, namespace);
3707
+ } catch {
3708
+ }
3709
+ }
3695
3710
  function readStoredId(key) {
3696
3711
  try {
3697
3712
  const v = localStorage.getItem(key);
@@ -3728,6 +3743,16 @@ function useTagBase(token, namespace) {
3728
3743
  }, [selectedContextId]);
3729
3744
  const load = (0, import_react19.useCallback)(async () => {
3730
3745
  if (!token || !namespace) return;
3746
+ if (readStoredNamespace() !== namespace) {
3747
+ selectedUserIdRef.current = null;
3748
+ selectedContextIdRef.current = null;
3749
+ setSelectedUserId(null);
3750
+ setSelectedContextId(null);
3751
+ writeStoredId(USER_ID_KEY, null);
3752
+ writeStoredId(CONTEXT_ID_KEY, null);
3753
+ writeStoredNamespace(namespace);
3754
+ setPickerMessage(null);
3755
+ }
3731
3756
  setIsLoading(true);
3732
3757
  setError(null);
3733
3758
  try {
@@ -3766,16 +3791,19 @@ function useTagBase(token, namespace) {
3766
3791
  setSelectedContextId(null);
3767
3792
  writeStoredId(USER_ID_KEY, userId);
3768
3793
  writeStoredId(CONTEXT_ID_KEY, null);
3769
- }, []);
3794
+ writeStoredNamespace(namespace);
3795
+ }, [namespace]);
3770
3796
  const selectContext = (0, import_react19.useCallback)((contextId) => {
3771
3797
  setSelectedContextId(contextId);
3772
3798
  writeStoredId(CONTEXT_ID_KEY, contextId);
3773
- }, []);
3799
+ writeStoredNamespace(namespace);
3800
+ }, [namespace]);
3774
3801
  const resetSelection = (0, import_react19.useCallback)(() => {
3775
3802
  setSelectedUserId(null);
3776
3803
  setSelectedContextId(null);
3777
3804
  writeStoredId(USER_ID_KEY, null);
3778
3805
  writeStoredId(CONTEXT_ID_KEY, null);
3806
+ writeStoredNamespace(null);
3779
3807
  setPickerMessage(null);
3780
3808
  }, []);
3781
3809
  const validation = tagBase ? validateTagBaseSelection(tagBase, selectedUserId, selectedContextId) : { valid: false, reason: null };
@@ -17516,6 +17544,57 @@ function createFlowSzenenViewPort(options) {
17516
17544
  return port;
17517
17545
  }
17518
17546
 
17547
+ // src/lib/flowBootstrapTarget.ts
17548
+ var PROD_NAMESPACE = "app.art-by-rolands.de/";
17549
+ var DEV_NAMESPACE = "dev-app.art-by-rolands.de/";
17550
+ var SELECTABLE_NAMESPACES = [PROD_NAMESPACE, DEV_NAMESPACE];
17551
+ var DEFAULT_NAMESPACE = PROD_NAMESPACE;
17552
+ function environmentForNamespace(namespace) {
17553
+ if (!namespace) return null;
17554
+ if (namespace === DEV_NAMESPACE) return "dev";
17555
+ if (namespace === PROD_NAMESPACE) return "prod";
17556
+ return null;
17557
+ }
17558
+ function normalizeSelectableNamespace(namespace) {
17559
+ return namespace && SELECTABLE_NAMESPACES.includes(namespace) ? namespace : DEFAULT_NAMESPACE;
17560
+ }
17561
+ function resolveBootstrapTarget(input) {
17562
+ const { hostNamespace, serverNamespace, isProbingServer = false } = input;
17563
+ if (hostNamespace) {
17564
+ return {
17565
+ source: "host",
17566
+ phase: "ready",
17567
+ ready: true,
17568
+ namespace: hostNamespace,
17569
+ environment: environmentForNamespace(hostNamespace)
17570
+ };
17571
+ }
17572
+ if (serverNamespace) {
17573
+ return {
17574
+ source: "server",
17575
+ phase: "ready",
17576
+ ready: true,
17577
+ namespace: serverNamespace,
17578
+ environment: environmentForNamespace(serverNamespace)
17579
+ };
17580
+ }
17581
+ if (isProbingServer) {
17582
+ return { source: "server", phase: "probing", ready: false, namespace: null, environment: null };
17583
+ }
17584
+ const { selectedNamespace, isStartDialogOpen = false } = input;
17585
+ if (isStartDialogOpen) {
17586
+ return { source: "dialog", phase: "awaiting-choice", ready: false, namespace: null, environment: null };
17587
+ }
17588
+ const namespace = normalizeSelectableNamespace(selectedNamespace);
17589
+ return {
17590
+ source: "dialog",
17591
+ phase: "ready",
17592
+ ready: true,
17593
+ namespace,
17594
+ environment: environmentForNamespace(namespace)
17595
+ };
17596
+ }
17597
+
17519
17598
  // src/components/AvatarArchitectApp.tsx
17520
17599
  var import_jsx_runtime45 = require("react/jsx-runtime");
17521
17600
  function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia, buildInfo, initialHfToken, hfNamespace, allowDevNamespace, requireWorkspaceSelection = false, serverBaseUrl, onFetchServerProjects, onServerSave, onServerLoad, onServerDelete }) {
@@ -17542,27 +17621,33 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
17542
17621
  const [hfTokenInput, setHfTokenInput] = (0, import_react47.useState)(initialHfToken || "");
17543
17622
  const [isLoadingFromHF, setIsLoadingFromHF] = (0, import_react47.useState)(false);
17544
17623
  const [hfNamespaceLocal, setHfNamespaceLocal] = (0, import_react47.useState)(() => {
17545
- const KNOWN = ["app.art-by-rolands.de/", "dev-app.art-by-rolands.de/"];
17546
- const DEFAULT = "app.art-by-rolands.de/";
17547
17624
  try {
17548
- const stored = localStorage.getItem("aa-hf-namespace");
17549
- if (stored && KNOWN.includes(stored)) return stored;
17550
- localStorage.setItem("aa-hf-namespace", DEFAULT);
17551
- return DEFAULT;
17625
+ return normalizeSelectableNamespace(localStorage.getItem("aa-hf-namespace"));
17552
17626
  } catch {
17553
- return DEFAULT;
17627
+ return DEFAULT_NAMESPACE;
17554
17628
  }
17555
17629
  });
17556
17630
  const [hfNamespaceFromServer, setHfNamespaceFromServer] = (0, import_react47.useState)(null);
17631
+ const [serverProbeFailed, setServerProbeFailed] = (0, import_react47.useState)(false);
17557
17632
  (0, import_react47.useEffect)(() => {
17558
17633
  if (hfNamespace !== void 0 || !serverBaseUrl) return;
17559
17634
  fetch(`${serverBaseUrl}/api/status`).then((r) => r.json()).then((d) => {
17560
17635
  if (typeof d.hfNamespace === "string" && d.hfNamespace) setHfNamespaceFromServer(d.hfNamespace);
17561
- }).catch(() => {
17562
- });
17636
+ else setServerProbeFailed(true);
17637
+ }).catch(() => setServerProbeFailed(true));
17563
17638
  }, [hfNamespace, serverBaseUrl]);
17564
- const effectiveNamespace = hfNamespace ?? hfNamespaceFromServer ?? hfNamespaceLocal;
17565
- const szenenPort = (0, import_react47.useMemo)(() => hfToken ? createFlowSzenenViewPort({
17639
+ const [targetConfirmed, setTargetConfirmed] = (0, import_react47.useState)(false);
17640
+ const isDialogTarget = hfNamespace === void 0 && hfNamespaceFromServer === null && (!serverBaseUrl || serverProbeFailed);
17641
+ const isProbingServer = hfNamespace === void 0 && !!serverBaseUrl && hfNamespaceFromServer === null && !serverProbeFailed;
17642
+ const bootstrapTarget = resolveBootstrapTarget({
17643
+ hostNamespace: hfNamespace,
17644
+ serverNamespace: hfNamespaceFromServer,
17645
+ isProbingServer,
17646
+ selectedNamespace: hfNamespaceLocal,
17647
+ isStartDialogOpen: isDialogTarget && !targetConfirmed
17648
+ });
17649
+ const effectiveNamespace = bootstrapTarget.namespace ?? "";
17650
+ const szenenPort = (0, import_react47.useMemo)(() => hfToken && effectiveNamespace ? createFlowSzenenViewPort({
17566
17651
  generateText: onGeneratePrompt,
17567
17652
  token: hfToken,
17568
17653
  namespace: effectiveNamespace
@@ -17640,6 +17725,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
17640
17725
  } catch {
17641
17726
  }
17642
17727
  setLayoutChoice(choice);
17728
+ setTargetConfirmed(true);
17643
17729
  setShowStart(false);
17644
17730
  };
17645
17731
  const [nodes, setNodes] = (0, import_react47.useState)([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
@@ -18401,45 +18487,6 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
18401
18487
  const all = Object.entries(merged).flatMap(([cat, tags]) => tags.map((t) => ({ ...t, category: cat })));
18402
18488
  return { by_category: merged, all };
18403
18489
  };
18404
- if (requireWorkspaceSelection) {
18405
- if (!hfToken) {
18406
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("section", { className: "flow-workspace-picker__card", role: "alert", children: "HF-Token fehlt \u2014 User und Context koennen nicht aus der Tag-Base geladen werden." }) });
18407
- }
18408
- if (tagBaseResult.isLoading) {
18409
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("section", { className: "flow-workspace-picker__card", children: [
18410
- "Lade User und Contexts aus ",
18411
- effectiveNamespace,
18412
- "\u2026"
18413
- ] }) });
18414
- }
18415
- if (tagBaseResult.error) {
18416
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("section", { className: "flow-workspace-picker__card", role: "alert", children: [
18417
- "Tag-Base ",
18418
- effectiveNamespace,
18419
- " konnte nicht geladen werden: ",
18420
- tagBaseResult.error
18421
- ] }) });
18422
- }
18423
- if (!tagBaseResult.tagBase) {
18424
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("section", { className: "flow-workspace-picker__card", role: "alert", children: [
18425
- "Im Namespace ",
18426
- effectiveNamespace,
18427
- " fehlt tags-state-*.zip. Der Server muss zuerst die Tag-Base erzeugen."
18428
- ] }) });
18429
- }
18430
- if (tagBaseResult.needsPicker) {
18431
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
18432
- FlowWorkspacePicker,
18433
- {
18434
- tagBase: tagBaseResult.tagBase,
18435
- selectedUserId: tagBaseResult.selectedUserId,
18436
- message: tagBaseResult.pickerMessage,
18437
- onSelectUser: tagBaseResult.selectUser,
18438
- onSelectContext: tagBaseResult.selectContext
18439
- }
18440
- );
18441
- }
18442
- }
18443
18490
  if (isFullscreen && currentResult?.base64) {
18444
18491
  const fsRaw = currentResult.fullBase64 || currentResult.base64;
18445
18492
  const fsBase64 = fsRaw.startsWith("data:") ? fsRaw : `data:image/png;base64,${fsRaw}`;
@@ -18583,7 +18630,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
18583
18630
  }
18584
18631
  )
18585
18632
  ] }),
18586
- !hfNamespace && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center gap-3 w-full", children: [
18633
+ isDialogTarget && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center gap-3 w-full", children: [
18587
18634
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-white/25 text-[10px] uppercase tracking-widest font-bold flex-shrink-0", children: "State:" }),
18588
18635
  ["app.art-by-rolands.de/", "dev-app.art-by-rolands.de/"].map((ns, i) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
18589
18636
  "button",
@@ -18668,7 +18715,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
18668
18715
  "button",
18669
18716
  {
18670
18717
  type: "button",
18671
- disabled: !szenenPort,
18718
+ disabled: !szenenPort || !bootstrapTarget.ready,
18672
18719
  onClick: () => setShowSzenen(true),
18673
18720
  children: [
18674
18721
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "material-symbols-outlined", children: "movie" }),
@@ -18703,6 +18750,48 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
18703
18750
  ] })
18704
18751
  ] });
18705
18752
  }
18753
+ if (requireWorkspaceSelection) {
18754
+ if (!bootstrapTarget.ready) {
18755
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("section", { className: "flow-workspace-picker__card", children: "Zielraum wird bestimmt\u2026" }) });
18756
+ }
18757
+ if (!hfToken) {
18758
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("section", { className: "flow-workspace-picker__card", role: "alert", children: "HF-Token fehlt \u2014 User und Context koennen nicht aus der Tag-Base geladen werden." }) });
18759
+ }
18760
+ if (tagBaseResult.isLoading) {
18761
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("section", { className: "flow-workspace-picker__card", children: [
18762
+ "Lade User und Contexts aus ",
18763
+ effectiveNamespace,
18764
+ "\u2026"
18765
+ ] }) });
18766
+ }
18767
+ if (tagBaseResult.error) {
18768
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("section", { className: "flow-workspace-picker__card", role: "alert", children: [
18769
+ "Tag-Base ",
18770
+ effectiveNamespace,
18771
+ " konnte nicht geladen werden: ",
18772
+ tagBaseResult.error
18773
+ ] }) });
18774
+ }
18775
+ if (!tagBaseResult.tagBase) {
18776
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("section", { className: "flow-workspace-picker__card", role: "alert", children: [
18777
+ "Im Namespace ",
18778
+ effectiveNamespace,
18779
+ " fehlt tags-state-*.zip. Der Server muss zuerst die Tag-Base erzeugen."
18780
+ ] }) });
18781
+ }
18782
+ if (tagBaseResult.needsPicker) {
18783
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
18784
+ FlowWorkspacePicker,
18785
+ {
18786
+ tagBase: tagBaseResult.tagBase,
18787
+ selectedUserId: tagBaseResult.selectedUserId,
18788
+ message: tagBaseResult.pickerMessage,
18789
+ onSelectUser: tagBaseResult.selectUser,
18790
+ onSelectContext: tagBaseResult.selectContext
18791
+ }
18792
+ );
18793
+ }
18794
+ }
18706
18795
  if (layoutChoice === "mobile" || layoutChoice === "mobile-desktop") {
18707
18796
  const mdMode = layoutChoice === "mobile-desktop";
18708
18797
  const mdScale = mdMode ? window.innerWidth / 430 : 1;
package/dist/index.mjs CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  } from "./chunk-VBWQP7PO.mjs";
31
31
 
32
32
  // package.json
33
- var version = "2.0.81";
33
+ var version = "2.0.82";
34
34
 
35
35
  // src/hooks/useOnClickOutside.ts
36
36
  import { useEffect } from "react";
@@ -2922,6 +2922,21 @@ function validateTagBaseSelection(base, userId, contextId) {
2922
2922
  // src/hooks/useTagBase.ts
2923
2923
  var USER_ID_KEY = "aa-user-id";
2924
2924
  var CONTEXT_ID_KEY = "aa-context-id";
2925
+ var IDENTITY_NAMESPACE_KEY = "aa-identity-namespace";
2926
+ function readStoredNamespace() {
2927
+ try {
2928
+ return localStorage.getItem(IDENTITY_NAMESPACE_KEY);
2929
+ } catch {
2930
+ return null;
2931
+ }
2932
+ }
2933
+ function writeStoredNamespace(namespace) {
2934
+ try {
2935
+ if (namespace === null) localStorage.removeItem(IDENTITY_NAMESPACE_KEY);
2936
+ else localStorage.setItem(IDENTITY_NAMESPACE_KEY, namespace);
2937
+ } catch {
2938
+ }
2939
+ }
2925
2940
  function readStoredId(key) {
2926
2941
  try {
2927
2942
  const v = localStorage.getItem(key);
@@ -2958,6 +2973,16 @@ function useTagBase(token, namespace) {
2958
2973
  }, [selectedContextId]);
2959
2974
  const load = useCallback2(async () => {
2960
2975
  if (!token || !namespace) return;
2976
+ if (readStoredNamespace() !== namespace) {
2977
+ selectedUserIdRef.current = null;
2978
+ selectedContextIdRef.current = null;
2979
+ setSelectedUserId(null);
2980
+ setSelectedContextId(null);
2981
+ writeStoredId(USER_ID_KEY, null);
2982
+ writeStoredId(CONTEXT_ID_KEY, null);
2983
+ writeStoredNamespace(namespace);
2984
+ setPickerMessage(null);
2985
+ }
2961
2986
  setIsLoading(true);
2962
2987
  setError(null);
2963
2988
  try {
@@ -2996,16 +3021,19 @@ function useTagBase(token, namespace) {
2996
3021
  setSelectedContextId(null);
2997
3022
  writeStoredId(USER_ID_KEY, userId);
2998
3023
  writeStoredId(CONTEXT_ID_KEY, null);
2999
- }, []);
3024
+ writeStoredNamespace(namespace);
3025
+ }, [namespace]);
3000
3026
  const selectContext = useCallback2((contextId) => {
3001
3027
  setSelectedContextId(contextId);
3002
3028
  writeStoredId(CONTEXT_ID_KEY, contextId);
3003
- }, []);
3029
+ writeStoredNamespace(namespace);
3030
+ }, [namespace]);
3004
3031
  const resetSelection = useCallback2(() => {
3005
3032
  setSelectedUserId(null);
3006
3033
  setSelectedContextId(null);
3007
3034
  writeStoredId(USER_ID_KEY, null);
3008
3035
  writeStoredId(CONTEXT_ID_KEY, null);
3036
+ writeStoredNamespace(null);
3009
3037
  setPickerMessage(null);
3010
3038
  }, []);
3011
3039
  const validation = tagBase ? validateTagBaseSelection(tagBase, selectedUserId, selectedContextId) : { valid: false, reason: null };
@@ -5712,6 +5740,57 @@ function FlowWorkspacePicker({
5712
5740
  ] }) });
5713
5741
  }
5714
5742
 
5743
+ // src/lib/flowBootstrapTarget.ts
5744
+ var PROD_NAMESPACE = "app.art-by-rolands.de/";
5745
+ var DEV_NAMESPACE = "dev-app.art-by-rolands.de/";
5746
+ var SELECTABLE_NAMESPACES = [PROD_NAMESPACE, DEV_NAMESPACE];
5747
+ var DEFAULT_NAMESPACE = PROD_NAMESPACE;
5748
+ function environmentForNamespace(namespace) {
5749
+ if (!namespace) return null;
5750
+ if (namespace === DEV_NAMESPACE) return "dev";
5751
+ if (namespace === PROD_NAMESPACE) return "prod";
5752
+ return null;
5753
+ }
5754
+ function normalizeSelectableNamespace(namespace) {
5755
+ return namespace && SELECTABLE_NAMESPACES.includes(namespace) ? namespace : DEFAULT_NAMESPACE;
5756
+ }
5757
+ function resolveBootstrapTarget(input) {
5758
+ const { hostNamespace, serverNamespace, isProbingServer = false } = input;
5759
+ if (hostNamespace) {
5760
+ return {
5761
+ source: "host",
5762
+ phase: "ready",
5763
+ ready: true,
5764
+ namespace: hostNamespace,
5765
+ environment: environmentForNamespace(hostNamespace)
5766
+ };
5767
+ }
5768
+ if (serverNamespace) {
5769
+ return {
5770
+ source: "server",
5771
+ phase: "ready",
5772
+ ready: true,
5773
+ namespace: serverNamespace,
5774
+ environment: environmentForNamespace(serverNamespace)
5775
+ };
5776
+ }
5777
+ if (isProbingServer) {
5778
+ return { source: "server", phase: "probing", ready: false, namespace: null, environment: null };
5779
+ }
5780
+ const { selectedNamespace, isStartDialogOpen = false } = input;
5781
+ if (isStartDialogOpen) {
5782
+ return { source: "dialog", phase: "awaiting-choice", ready: false, namespace: null, environment: null };
5783
+ }
5784
+ const namespace = normalizeSelectableNamespace(selectedNamespace);
5785
+ return {
5786
+ source: "dialog",
5787
+ phase: "ready",
5788
+ ready: true,
5789
+ namespace,
5790
+ environment: environmentForNamespace(namespace)
5791
+ };
5792
+ }
5793
+
5715
5794
  // src/components/AvatarArchitectApp.tsx
5716
5795
  import { Fragment as Fragment11, jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
5717
5796
  function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia, buildInfo, initialHfToken, hfNamespace, allowDevNamespace, requireWorkspaceSelection = false, serverBaseUrl, onFetchServerProjects, onServerSave, onServerLoad, onServerDelete }) {
@@ -5738,27 +5817,33 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5738
5817
  const [hfTokenInput, setHfTokenInput] = useState25(initialHfToken || "");
5739
5818
  const [isLoadingFromHF, setIsLoadingFromHF] = useState25(false);
5740
5819
  const [hfNamespaceLocal, setHfNamespaceLocal] = useState25(() => {
5741
- const KNOWN = ["app.art-by-rolands.de/", "dev-app.art-by-rolands.de/"];
5742
- const DEFAULT = "app.art-by-rolands.de/";
5743
5820
  try {
5744
- const stored = localStorage.getItem("aa-hf-namespace");
5745
- if (stored && KNOWN.includes(stored)) return stored;
5746
- localStorage.setItem("aa-hf-namespace", DEFAULT);
5747
- return DEFAULT;
5821
+ return normalizeSelectableNamespace(localStorage.getItem("aa-hf-namespace"));
5748
5822
  } catch {
5749
- return DEFAULT;
5823
+ return DEFAULT_NAMESPACE;
5750
5824
  }
5751
5825
  });
5752
5826
  const [hfNamespaceFromServer, setHfNamespaceFromServer] = useState25(null);
5827
+ const [serverProbeFailed, setServerProbeFailed] = useState25(false);
5753
5828
  useEffect10(() => {
5754
5829
  if (hfNamespace !== void 0 || !serverBaseUrl) return;
5755
5830
  fetch(`${serverBaseUrl}/api/status`).then((r) => r.json()).then((d) => {
5756
5831
  if (typeof d.hfNamespace === "string" && d.hfNamespace) setHfNamespaceFromServer(d.hfNamespace);
5757
- }).catch(() => {
5758
- });
5832
+ else setServerProbeFailed(true);
5833
+ }).catch(() => setServerProbeFailed(true));
5759
5834
  }, [hfNamespace, serverBaseUrl]);
5760
- const effectiveNamespace = hfNamespace ?? hfNamespaceFromServer ?? hfNamespaceLocal;
5761
- const szenenPort = useMemo6(() => hfToken ? createFlowSzenenViewPort({
5835
+ const [targetConfirmed, setTargetConfirmed] = useState25(false);
5836
+ const isDialogTarget = hfNamespace === void 0 && hfNamespaceFromServer === null && (!serverBaseUrl || serverProbeFailed);
5837
+ const isProbingServer = hfNamespace === void 0 && !!serverBaseUrl && hfNamespaceFromServer === null && !serverProbeFailed;
5838
+ const bootstrapTarget = resolveBootstrapTarget({
5839
+ hostNamespace: hfNamespace,
5840
+ serverNamespace: hfNamespaceFromServer,
5841
+ isProbingServer,
5842
+ selectedNamespace: hfNamespaceLocal,
5843
+ isStartDialogOpen: isDialogTarget && !targetConfirmed
5844
+ });
5845
+ const effectiveNamespace = bootstrapTarget.namespace ?? "";
5846
+ const szenenPort = useMemo6(() => hfToken && effectiveNamespace ? createFlowSzenenViewPort({
5762
5847
  generateText: onGeneratePrompt,
5763
5848
  token: hfToken,
5764
5849
  namespace: effectiveNamespace
@@ -5836,6 +5921,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5836
5921
  } catch {
5837
5922
  }
5838
5923
  setLayoutChoice(choice);
5924
+ setTargetConfirmed(true);
5839
5925
  setShowStart(false);
5840
5926
  };
5841
5927
  const [nodes, setNodes] = useState25([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
@@ -6597,45 +6683,6 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
6597
6683
  const all = Object.entries(merged).flatMap(([cat, tags]) => tags.map((t) => ({ ...t, category: cat })));
6598
6684
  return { by_category: merged, all };
6599
6685
  };
6600
- if (requireWorkspaceSelection) {
6601
- if (!hfToken) {
6602
- return /* @__PURE__ */ jsx29("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ jsx29("section", { className: "flow-workspace-picker__card", role: "alert", children: "HF-Token fehlt \u2014 User und Context koennen nicht aus der Tag-Base geladen werden." }) });
6603
- }
6604
- if (tagBaseResult.isLoading) {
6605
- return /* @__PURE__ */ jsx29("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ jsxs27("section", { className: "flow-workspace-picker__card", children: [
6606
- "Lade User und Contexts aus ",
6607
- effectiveNamespace,
6608
- "\u2026"
6609
- ] }) });
6610
- }
6611
- if (tagBaseResult.error) {
6612
- return /* @__PURE__ */ jsx29("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ jsxs27("section", { className: "flow-workspace-picker__card", role: "alert", children: [
6613
- "Tag-Base ",
6614
- effectiveNamespace,
6615
- " konnte nicht geladen werden: ",
6616
- tagBaseResult.error
6617
- ] }) });
6618
- }
6619
- if (!tagBaseResult.tagBase) {
6620
- return /* @__PURE__ */ jsx29("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ jsxs27("section", { className: "flow-workspace-picker__card", role: "alert", children: [
6621
- "Im Namespace ",
6622
- effectiveNamespace,
6623
- " fehlt tags-state-*.zip. Der Server muss zuerst die Tag-Base erzeugen."
6624
- ] }) });
6625
- }
6626
- if (tagBaseResult.needsPicker) {
6627
- return /* @__PURE__ */ jsx29(
6628
- FlowWorkspacePicker,
6629
- {
6630
- tagBase: tagBaseResult.tagBase,
6631
- selectedUserId: tagBaseResult.selectedUserId,
6632
- message: tagBaseResult.pickerMessage,
6633
- onSelectUser: tagBaseResult.selectUser,
6634
- onSelectContext: tagBaseResult.selectContext
6635
- }
6636
- );
6637
- }
6638
- }
6639
6686
  if (isFullscreen && currentResult?.base64) {
6640
6687
  const fsRaw = currentResult.fullBase64 || currentResult.base64;
6641
6688
  const fsBase64 = fsRaw.startsWith("data:") ? fsRaw : `data:image/png;base64,${fsRaw}`;
@@ -6779,7 +6826,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
6779
6826
  }
6780
6827
  )
6781
6828
  ] }),
6782
- !hfNamespace && /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-3 w-full", children: [
6829
+ isDialogTarget && /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-3 w-full", children: [
6783
6830
  /* @__PURE__ */ jsx29("span", { className: "text-white/25 text-[10px] uppercase tracking-widest font-bold flex-shrink-0", children: "State:" }),
6784
6831
  ["app.art-by-rolands.de/", "dev-app.art-by-rolands.de/"].map((ns, i) => /* @__PURE__ */ jsx29(
6785
6832
  "button",
@@ -6864,7 +6911,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
6864
6911
  "button",
6865
6912
  {
6866
6913
  type: "button",
6867
- disabled: !szenenPort,
6914
+ disabled: !szenenPort || !bootstrapTarget.ready,
6868
6915
  onClick: () => setShowSzenen(true),
6869
6916
  children: [
6870
6917
  /* @__PURE__ */ jsx29("span", { className: "material-symbols-outlined", children: "movie" }),
@@ -6899,6 +6946,48 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
6899
6946
  ] })
6900
6947
  ] });
6901
6948
  }
6949
+ if (requireWorkspaceSelection) {
6950
+ if (!bootstrapTarget.ready) {
6951
+ return /* @__PURE__ */ jsx29("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ jsx29("section", { className: "flow-workspace-picker__card", children: "Zielraum wird bestimmt\u2026" }) });
6952
+ }
6953
+ if (!hfToken) {
6954
+ return /* @__PURE__ */ jsx29("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ jsx29("section", { className: "flow-workspace-picker__card", role: "alert", children: "HF-Token fehlt \u2014 User und Context koennen nicht aus der Tag-Base geladen werden." }) });
6955
+ }
6956
+ if (tagBaseResult.isLoading) {
6957
+ return /* @__PURE__ */ jsx29("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ jsxs27("section", { className: "flow-workspace-picker__card", children: [
6958
+ "Lade User und Contexts aus ",
6959
+ effectiveNamespace,
6960
+ "\u2026"
6961
+ ] }) });
6962
+ }
6963
+ if (tagBaseResult.error) {
6964
+ return /* @__PURE__ */ jsx29("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ jsxs27("section", { className: "flow-workspace-picker__card", role: "alert", children: [
6965
+ "Tag-Base ",
6966
+ effectiveNamespace,
6967
+ " konnte nicht geladen werden: ",
6968
+ tagBaseResult.error
6969
+ ] }) });
6970
+ }
6971
+ if (!tagBaseResult.tagBase) {
6972
+ return /* @__PURE__ */ jsx29("main", { className: "flow-workspace-picker", children: /* @__PURE__ */ jsxs27("section", { className: "flow-workspace-picker__card", role: "alert", children: [
6973
+ "Im Namespace ",
6974
+ effectiveNamespace,
6975
+ " fehlt tags-state-*.zip. Der Server muss zuerst die Tag-Base erzeugen."
6976
+ ] }) });
6977
+ }
6978
+ if (tagBaseResult.needsPicker) {
6979
+ return /* @__PURE__ */ jsx29(
6980
+ FlowWorkspacePicker,
6981
+ {
6982
+ tagBase: tagBaseResult.tagBase,
6983
+ selectedUserId: tagBaseResult.selectedUserId,
6984
+ message: tagBaseResult.pickerMessage,
6985
+ onSelectUser: tagBaseResult.selectUser,
6986
+ onSelectContext: tagBaseResult.selectContext
6987
+ }
6988
+ );
6989
+ }
6990
+ }
6902
6991
  if (layoutChoice === "mobile" || layoutChoice === "mobile-desktop") {
6903
6992
  const mdMode = layoutChoice === "mobile-desktop";
6904
6993
  const mdScale = mdMode ? window.innerWidth / 430 : 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rslsp1/fa-app-tools",
3
- "version": "2.0.81",
3
+ "version": "2.0.82",
4
4
  "description": "Shared tools and hooks for Fine Art flow apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",