@ai4b-team/fsaos-gateway-sdk 3.34.2 → 3.35.0

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/iife/ui.js CHANGED
@@ -1,3 +1,3 @@
1
- /* @fsaos/ui v2.0.0 — FSAOS UI Primitives — 2026-10-03T21:58:22.099Z */
1
+ /* @fsaos/ui v2.0.0 — FSAOS UI Primitives — 2026-10-03T22:17:01.442Z */
2
2
  "use strict";var __FSAOS_UI__=(()=>{var m=Object.create;var r=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var y=(e,i)=>()=>(i||e((i={exports:{}}).exports,i),i.exports),N=(e,i)=>{for(var a in i)r(e,a,{get:i[a],enumerable:!0})},s=(e,i,a,l)=>{if(i&&typeof i=="object"||typeof i=="function")for(let t of u(i))!h.call(e,t)&&t!==a&&r(e,t,{get:()=>i[t],enumerable:!(l=g(i,t))||l.enumerable});return e};var x=(e,i,a)=>(a=e!=null?m(f(e)):{},s(i||!e||!e.__esModule?r(a,"default",{value:e,enumerable:!0}):a,e)),b=e=>s(r({},"__esModule",{value:!0}),e);var d=y((V,c)=>{c.exports=React});var P={};N(P,{Badge:()=>z,Breadcrumbs:()=>A,Button:()=>D,Card:()=>w,DataView:()=>R,Detail:()=>_,Empty:()=>I,FilePreview:()=>O,Form:()=>F,Grid:()=>k,Image:()=>G,Link:()=>E,Page:()=>v,Router:()=>T,Sidebar:()=>S,Spinner:()=>B,Stack:()=>C,Table:()=>j,Tabs:()=>W,Video:()=>H});var n=x(d(),1);function o(){return(typeof window<"u"&&window.__FSAOS_CONFIG__||{}).edgeBaseUrl||""}function v(e){return(0,n.createElement)("div",{style:{minHeight:"100vh",display:"flex",flexDirection:"column"},className:e.className||""},e.children)}function C(e){let i=e.direction||"vertical";return(0,n.createElement)("div",{style:{display:"flex",flexDirection:i==="horizontal"?"row":"column",gap:e.gap||"0.5rem",padding:e.padding||"0",alignItems:e.align||"stretch",justifyContent:e.justify||"flex-start",flex:e.flex||"initial"},className:e.className||""},e.children)}function k(e){return(0,n.createElement)("div",{style:{display:"grid",gridTemplateColumns:"repeat("+(e.columns||3)+", 1fr)",gap:e.gap||"1rem",padding:e.padding||"0"},className:e.className||""},e.children)}function S(e){return(0,n.createElement)("div",{style:{display:"flex",flexDirection:"row",minHeight:"100vh"},className:e.className||""},e.children)}function w(e){return(0,n.createElement)("div",{style:{border:"1px solid var(--color-border, #e5e7eb)",borderRadius:"var(--border-radius, 0.5rem)",padding:e.padding||"1rem",background:"var(--color-surface, #fff)"},className:e.className||"",onClick:e.onClick},e.children)}function z(e){return(0,n.createElement)("span",{style:{display:"inline-flex",alignItems:"center",padding:"0.125rem 0.5rem",fontSize:"0.75rem",fontWeight:"500",borderRadius:"9999px",background:e.color||"#e5e7eb",color:e.textColor||"#374151"},className:e.className||""},e.children||e.label)}function B(e){let i=e.size||"1.5rem";return(0,n.createElement)("div",{style:{width:i,height:i,border:"2px solid #e5e7eb",borderTopColor:"var(--color-primary, #3b82f6)",borderRadius:"50%",animation:"fsaos-spin 0.6s linear infinite"}})}function D(e){return(0,n.createElement)("button",{style:{display:"inline-flex",alignItems:"center",justifyContent:"center",padding:"0.5rem 1rem",fontSize:"0.875rem",fontWeight:"500",borderRadius:"var(--border-radius, 0.375rem)",border:e.variant==="outline"?"1px solid var(--color-border, #d1d5db)":"none",background:e.variant==="outline"||e.variant==="ghost"?"transparent":"var(--color-primary, #3b82f6)",color:e.variant==="outline"||e.variant==="ghost"?"var(--color-text, #1a1a1a)":"#fff",cursor:e.disabled?"not-allowed":"pointer",opacity:e.disabled?"0.5":"1",gap:"0.5rem"},className:e.className||"",onClick:e.onClick,disabled:e.disabled},e.children||e.label)}function I(e){return(0,n.createElement)("div",{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:"3rem",color:"var(--color-text-secondary, #6b7280)",textAlign:"center"}},e.icon?(0,n.createElement)("div",{style:{fontSize:"2rem",marginBottom:"0.5rem"}},e.icon):null,(0,n.createElement)("div",{style:{fontWeight:500,marginBottom:"0.25rem"}},e.title||e.message||e.children||"No items"),e.description?(0,n.createElement)("div",{style:{fontSize:"0.875rem",opacity:.7}},e.description):null)}function R(e){return(0,n.createElement)("div",{className:e.className||""},e.children)}function j(e){return(0,n.createElement)("table",{className:e.className||""},e.children)}function F(e){return(0,n.createElement)("form",{className:e.className||"",onSubmit:e.onSubmit},e.children)}function _(e){return(0,n.createElement)("div",{className:e.className||""},e.children)}function T(e){return(0,n.createElement)("div",null,e.children)}function E(e){return(0,n.createElement)("a",{href:e.href||e.to,className:e.className||"",onClick:e.onClick},e.children)}function W(e){return(0,n.createElement)("div",{className:e.className||""},e.children)}function A(e){return(0,n.createElement)("nav",{className:e.className||""},e.children)}function G(e){return(0,n.createElement)("img",{src:e.src||(e.path?o()+e.path:""),alt:e.alt||"",className:e.className||"",style:e.style})}function H(e){return(0,n.createElement)("video",{src:e.src||(e.path?o()+e.path:""),controls:!0,className:e.className||""})}function O(e){return(0,n.createElement)("div",{className:e.className||""},e.children||"File preview")}return b(P);})();
3
3
  //# sourceMappingURL=ui.js.map
package/dist/index.cjs CHANGED
@@ -782,6 +782,10 @@ function listingTypes(filter) {
782
782
  }
783
783
  function affectsListing(query, filter, event) {
784
784
  if (containsChangedItem(query, event)) return true;
785
+ if (filter.spaceIds !== void 0) {
786
+ if (!filter.spaceIds.length) return false;
787
+ if (event.space_item_id !== void 0 && !filter.spaceIds.includes(event.space_item_id) && !filter.spaceIds.includes(event.old_space_item_id)) return false;
788
+ }
785
789
  const scope = filter.scope;
786
790
  const scoped = typeof scope === "string" && scope !== "__unscoped__";
787
791
  const hasPath = typeof event.path === "string" || typeof event.old_path === "string";
@@ -825,6 +829,29 @@ function clearInfiniteItemsRefreshes(client2) {
825
829
  pending2.delete(client2);
826
830
  }
827
831
 
832
+ // src/items-selection.ts
833
+ var SelectedSpaceContractError = class extends Error {
834
+ constructor() {
835
+ super("The server did not confirm the selected-Space listing contract");
836
+ }
837
+ };
838
+ function assertItemsSelection(requested, returned) {
839
+ if (!Array.isArray(returned) || returned.some((id) => typeof id !== "string") || JSON.stringify([...new Set(returned)].sort()) !== JSON.stringify(requested)) {
840
+ throw new SelectedSpaceContractError();
841
+ }
842
+ }
843
+ function normalizeItemsSelection(filter) {
844
+ if (!filter || filter.spaceIds === void 0) return filter;
845
+ return {
846
+ ...filter,
847
+ spaceIds: [...new Set(filter.spaceIds.map((id) => id.toLowerCase()))].sort(),
848
+ ...filter.limit !== void 0 ? { limit: Math.max(1, Math.min(filter.limit, 500)) } : {}
849
+ };
850
+ }
851
+ function unavailableItemsSelection(error) {
852
+ return error instanceof SelectedSpaceContractError || error instanceof EnforcementDeniedError || error instanceof GatewayRequestError && (error.payload?.error === "SPACE_SELECTION_UNAVAILABLE" || error.payload?.error === "QUERY_PARAMS_INVALID" || error.status === 401 || error.status === 403);
853
+ }
854
+
828
855
  // src/vfs-keys.ts
829
856
  function sk() {
830
857
  return getScope() ?? "__unscoped__";
@@ -847,7 +874,7 @@ var vfsKeys = {
847
874
  /** Search results (scope-aware — search is scoped). */
848
875
  search: (query, types) => ["vfs", sk(), "search", query, ...types ?? []],
849
876
  /** Items query (type-based listing with filters, scope-aware). */
850
- items: (type, filters) => ["vfs", sk(), "items", type, JSON.stringify(filters ?? {})],
877
+ items: (type, filters) => ["vfs", sk(), "items", type, JSON.stringify(normalizeItemsSelection(filters ?? {}))],
851
878
  /** All items queries for current scope (for broad invalidation). */
852
879
  allItems: () => ["vfs", sk(), "items"],
853
880
  /** Recursive tree at a path + depth (scope-aware). */
@@ -1737,12 +1764,15 @@ function itemsFilterFromQueryFilter(typeData, extra = {}) {
1737
1764
  return { ...filter, ...extra };
1738
1765
  }
1739
1766
  async function fetchItems(filter, options = {}) {
1767
+ filter = normalizeItemsSelection(filter);
1768
+ if (filter.spaceIds?.length === 0) return { items: [], total_hint: 0 };
1740
1769
  const params = {};
1741
1770
  if (filter.type) params.item_type = filter.type;
1742
1771
  if (filter.scope) {
1743
1772
  params.scope_path = filter.scope;
1744
1773
  }
1745
1774
  const filters = {};
1775
+ if (filter.spaceIds !== void 0) filters.space_ids = filter.spaceIds;
1746
1776
  if (filter.name) filters.name = filter.name;
1747
1777
  if (filter.tag) filters.tag = filter.tag;
1748
1778
  if (filter.parent_id) filters.parent_id = filter.parent_id;
@@ -1769,6 +1799,9 @@ async function fetchItems(filter, options = {}) {
1769
1799
  }
1770
1800
  try {
1771
1801
  const response = await gatewayCall("query", params);
1802
+ if (filter.spaceIds !== void 0) {
1803
+ assertItemsSelection(filter.spaceIds, response.selected_space_ids ?? response.content?.selected_space_ids);
1804
+ }
1772
1805
  const items = extractItems(response);
1773
1806
  for (const item of items) {
1774
1807
  getQueryClient().setQueryData(vfsKeys.item(item.path), item);
@@ -1776,7 +1809,7 @@ async function fetchItems(filter, options = {}) {
1776
1809
  return { items, total_hint: response.total ?? response.content?.total ?? items.length };
1777
1810
  } catch (err) {
1778
1811
  console.error(`[gateway] Failed to fetch items of type ${filter.type ?? "(any_of)"}:`, err);
1779
- if (options.throwOnError) throw err;
1812
+ if (options.throwOnError || filter.spaceIds !== void 0) throw err;
1780
1813
  return { items: [], total_hint: 0 };
1781
1814
  }
1782
1815
  }
@@ -2390,22 +2423,28 @@ function useResolve(params) {
2390
2423
  }
2391
2424
  function useItems(filter) {
2392
2425
  useScopeKey();
2393
- const stableFilter = React.useMemo(() => filter, [JSON.stringify(filter)]);
2394
- return reactQuery.useQuery({
2426
+ const selected = normalizeItemsSelection(filter);
2427
+ const stableFilter = React.useMemo(() => selected, [JSON.stringify(selected)]);
2428
+ const query = reactQuery.useQuery({
2395
2429
  queryKey: vfsKeys.items(
2396
2430
  stableFilter?.type ?? "",
2397
2431
  stableFilter
2398
2432
  ),
2399
2433
  queryFn: () => fetchItems(stableFilter),
2400
2434
  enabled: isListableItemsFilter(stableFilter),
2435
+ ...stableFilter?.spaceIds !== void 0 ? {
2436
+ retry: (attempt, error) => !unavailableItemsSelection(error) && attempt < 1
2437
+ } : {},
2401
2438
  select: (result) => result.items
2402
2439
  });
2440
+ return stableFilter?.spaceIds !== void 0 && unavailableItemsSelection(query.error) ? { ...query, data: void 0 } : query;
2403
2441
  }
2404
2442
  function useInfiniteItems(filter, options = {}) {
2405
2443
  const scopeKey = useScopeKey();
2406
2444
  const { realtime = false } = options;
2407
- const PAGE_SIZE = filter?.limit ?? 20;
2408
- const stableFilter = React.useMemo(() => filter, [JSON.stringify(filter)]);
2445
+ const selected = normalizeItemsSelection(filter);
2446
+ const PAGE_SIZE = selected?.limit ?? 20;
2447
+ const stableFilter = React.useMemo(() => selected, [JSON.stringify(selected)]);
2409
2448
  const stableKey = React.useMemo(() => ["vfs", getScope() ?? "__unscoped__", "infinite-items", stableFilter?.type ?? "", JSON.stringify(stableFilter ?? {})], [scopeKey, stableFilter]);
2410
2449
  const query = reactQuery.useInfiniteQuery({
2411
2450
  queryKey: stableKey,
@@ -2418,16 +2457,21 @@ function useInfiniteItems(filter, options = {}) {
2418
2457
  },
2419
2458
  initialPageParam: 0,
2420
2459
  getNextPageParam: (lastPage, _allPages, lastPageParam) => {
2460
+ if (stableFilter?.spaceIds !== void 0 && lastPage.total_hint !== void 0 && lastPageParam + lastPage.items.length >= lastPage.total_hint) return void 0;
2421
2461
  if (lastPage.items.length < PAGE_SIZE) return void 0;
2422
2462
  return lastPageParam + lastPage.items.length;
2423
2463
  },
2424
2464
  enabled: isListableItemsFilter(stableFilter),
2465
+ ...stableFilter?.spaceIds !== void 0 ? {
2466
+ retry: (attempt, error) => !unavailableItemsSelection(error) && attempt < 1
2467
+ } : {},
2425
2468
  // Realtime marks the cache stale only on relevant changes or reconnect.
2426
2469
  // Expanding a channel or handing it to another observer reuses its pages.
2427
2470
  staleTime: realtime ? Infinity : void 0,
2428
2471
  meta: realtime && stableFilter ? { infiniteItemsRealtime: { filter: stableFilter } } : {}
2429
2472
  });
2430
2473
  const allItems = React.useMemo(() => {
2474
+ if (stableFilter?.spaceIds !== void 0 && unavailableItemsSelection(query.error)) return [];
2431
2475
  if (!query.data?.pages) return [];
2432
2476
  const seen = /* @__PURE__ */ new Set();
2433
2477
  const flat = [];
@@ -2440,17 +2484,18 @@ function useInfiniteItems(filter, options = {}) {
2440
2484
  }
2441
2485
  }
2442
2486
  return flat;
2443
- }, [query.data?.pages]);
2487
+ }, [query.data?.pages, query.error, stableFilter]);
2488
+ const unavailable = stableFilter?.spaceIds !== void 0 && unavailableItemsSelection(query.error);
2444
2489
  return {
2445
2490
  allItems,
2446
2491
  refetch: query.refetch,
2447
2492
  fetchNextPage: query.fetchNextPage,
2448
2493
  isFetchingNextPage: query.isFetchingNextPage,
2449
- isExhausted: !query.hasNextPage,
2494
+ isExhausted: unavailable || !query.hasNextPage,
2450
2495
  isLoading: query.isLoading,
2451
2496
  isFetching: query.isFetching,
2452
2497
  error: query.error,
2453
- totalHint: query.data?.pages?.[0]?.total_hint
2498
+ totalHint: unavailable ? void 0 : query.data?.pages?.[0]?.total_hint
2454
2499
  };
2455
2500
  }
2456
2501
  function useInfiniteChildren(path) {
@@ -2758,10 +2803,15 @@ function useMounts() {
2758
2803
  useScopeKey();
2759
2804
  const version = React.useSyncExternalStore(subscribeMounts, getMountVersion, getMountVersion);
2760
2805
  const mounts = React.useMemo(() => getMounts(), [version]);
2806
+ const anchor = getAnchorRef();
2807
+ const selectedSpaces = React.useMemo(() => mounts.filter((ref) => ref.kind === "space" && (anchor?.kind === "account" || ref.id === anchor?.id)), [mounts, anchor]);
2808
+ const readSpaceIds = React.useMemo(() => selectedSpaces.map((ref) => ref.id).sort(), [selectedSpaces]);
2761
2809
  return {
2762
2810
  mounts,
2811
+ selectedSpaces,
2812
+ readSpaceIds,
2763
2813
  homeAnchor: getHomeAnchor(),
2764
- anchor: getAnchorRef(),
2814
+ anchor,
2765
2815
  setAnchor: selectMount,
2766
2816
  replaceMounts,
2767
2817
  mount,