@ai4b-team/fsaos-gateway-sdk 3.26.2 → 3.27.1

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-09-06T15:05:48.892Z */
1
+ /* @fsaos/ui v2.0.0 — FSAOS UI Primitives — 2026-09-09T23:15:43.750Z */
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
@@ -173,6 +173,7 @@ __export(src_exports, {
173
173
  useLink: () => useLink,
174
174
  useList: () => useList,
175
175
  useMemberFocus: () => useMemberFocus,
176
+ useMintedAsset: () => useMintedAsset,
176
177
  useMounts: () => useMounts,
177
178
  useMove: () => useMove,
178
179
  useMutation: () => useMutation,
@@ -1775,7 +1776,29 @@ function pathSubscriptionMatches(subscribedPath, eventPath) {
1775
1776
  }
1776
1777
  var typedListeners = [];
1777
1778
  var activeScopes = /* @__PURE__ */ new Map();
1779
+ var scopeLeases = /* @__PURE__ */ new Map();
1778
1780
  var activePaths = /* @__PURE__ */ new Map();
1781
+ function scopeEventTypes(scopeId) {
1782
+ const leases = scopeLeases.get(scopeId);
1783
+ if (!leases) return [];
1784
+ return Array.from(
1785
+ new Set(Array.from(leases.values()).flatMap((lease) => lease.event_types))
1786
+ ).sort();
1787
+ }
1788
+ function sameEventTypes(a, b) {
1789
+ if (!a) return false;
1790
+ return a.length === b.length && a.every((eventType, index) => eventType === b[index]);
1791
+ }
1792
+ function refreshScopeSubscription(scopeId) {
1793
+ const eventTypes = scopeEventTypes(scopeId);
1794
+ if (eventTypes.length === 0) {
1795
+ activeScopes.delete(scopeId);
1796
+ return null;
1797
+ }
1798
+ const subscription = { scope_id: scopeId, event_types: eventTypes };
1799
+ activeScopes.set(scopeId, subscription);
1800
+ return subscription;
1801
+ }
1779
1802
  var pathStates = /* @__PURE__ */ new Map();
1780
1803
  var pathReadyWaiters = /* @__PURE__ */ new Map();
1781
1804
  var connectionState = "disconnected";
@@ -2035,15 +2058,47 @@ function subscribeToEvents(eventType, callback, filter) {
2035
2058
  };
2036
2059
  }
2037
2060
  function subscribeToScope(scopeId, eventTypes = ["vfs_change", "ccm_change"]) {
2038
- log("subscribeToScope:", scopeId, eventTypes);
2039
- activeScopes.set(scopeId, { scope_id: scopeId, event_types: eventTypes });
2040
- if (ws && ws.readyState === WebSocket.OPEN) {
2041
- sendMessage({ type: "subscribe", scope_id: scopeId, event_types: eventTypes });
2061
+ const leaseId = Symbol(scopeId);
2062
+ const normalizedEventTypes = Array.from(new Set(eventTypes)).sort();
2063
+ if (normalizedEventTypes.length === 0) return () => {
2064
+ };
2065
+ const leases = scopeLeases.get(scopeId) ?? /* @__PURE__ */ new Map();
2066
+ const previousEventTypes = activeScopes.get(scopeId)?.event_types;
2067
+ leases.set(leaseId, { event_types: normalizedEventTypes });
2068
+ scopeLeases.set(scopeId, leases);
2069
+ const subscription = refreshScopeSubscription(scopeId);
2070
+ if (!subscription) return () => {
2071
+ };
2072
+ log("subscribeToScope:", scopeId, subscription.event_types);
2073
+ if (ws && ws.readyState === WebSocket.OPEN && !sameEventTypes(previousEventTypes, subscription.event_types)) {
2074
+ sendMessage({
2075
+ type: "subscribe",
2076
+ scope_id: scopeId,
2077
+ event_types: subscription.event_types
2078
+ });
2042
2079
  }
2043
2080
  ensureConnection();
2081
+ let active = true;
2044
2082
  return () => {
2045
- activeScopes.delete(scopeId);
2046
- sendMessage({ type: "unsubscribe", scope_id: scopeId });
2083
+ if (!active) return;
2084
+ active = false;
2085
+ const currentLeases = scopeLeases.get(scopeId);
2086
+ if (!currentLeases?.delete(leaseId)) return;
2087
+ const previous = activeScopes.get(scopeId)?.event_types;
2088
+ if (currentLeases.size === 0) {
2089
+ scopeLeases.delete(scopeId);
2090
+ activeScopes.delete(scopeId);
2091
+ sendMessage({ type: "unsubscribe", scope_id: scopeId });
2092
+ } else {
2093
+ const next = refreshScopeSubscription(scopeId);
2094
+ if (next && ws && ws.readyState === WebSocket.OPEN && !sameEventTypes(previous, next.event_types)) {
2095
+ sendMessage({
2096
+ type: "subscribe",
2097
+ scope_id: scopeId,
2098
+ event_types: next.event_types
2099
+ });
2100
+ }
2101
+ }
2047
2102
  maybeDisconnect();
2048
2103
  };
2049
2104
  }
@@ -2070,6 +2125,7 @@ function disconnectSSE() {
2070
2125
  }
2071
2126
  typedListeners.length = 0;
2072
2127
  activeScopes.clear();
2128
+ scopeLeases.clear();
2073
2129
  activePaths.clear();
2074
2130
  pathStates.clear();
2075
2131
  pathReadyWaiters.clear();
@@ -4066,6 +4122,168 @@ function useArrangement(paramsOrPath) {
4066
4122
  applyTo
4067
4123
  };
4068
4124
  }
4125
+ function useMintedAsset(params) {
4126
+ const { origin, originField, fallbackUrl, mintError, scopeId, scopePath } = params;
4127
+ const sdkGeneration = useScopeKey();
4128
+ const session = getSessionEntry();
4129
+ const resolvedScopeId = scopeId ?? session?.scope_id ?? null;
4130
+ const originAccountScope = React.useMemo(() => {
4131
+ if (!origin) return null;
4132
+ const marker = "/accounts/";
4133
+ const markerIndex = origin.indexOf(marker);
4134
+ if (markerIndex === -1) return null;
4135
+ const accountEnd = origin.indexOf("/", markerIndex + marker.length);
4136
+ return accountEnd === -1 ? origin : origin.slice(0, accountEnd);
4137
+ }, [origin]);
4138
+ const resolvedScopePath = scopePath ?? originAccountScope ?? session?.scope_path ?? null;
4139
+ const resolvedOriginField = originField?.trim() || null;
4140
+ const correlationKey = `${sdkGeneration}
4141
+ ${resolvedScopeId ?? ""}
4142
+ ${resolvedScopePath ?? ""}
4143
+ ${resolvedOriginField ?? ""}
4144
+ ${origin ?? ""}`;
4145
+ const [found, setFound] = React.useState(null);
4146
+ const activeRef = React.useRef({
4147
+ key: correlationKey,
4148
+ found: null,
4149
+ earlyContentPaths: /* @__PURE__ */ new Set()
4150
+ });
4151
+ const currentFound = found?.key === correlationKey ? found : null;
4152
+ React.useLayoutEffect(() => {
4153
+ activeRef.current = {
4154
+ key: correlationKey,
4155
+ found: currentFound,
4156
+ earlyContentPaths: /* @__PURE__ */ new Set()
4157
+ };
4158
+ }, [correlationKey]);
4159
+ const recovery = reactQuery.useQuery({
4160
+ queryKey: [
4161
+ "vfs",
4162
+ resolvedScopePath ?? "__unscoped__",
4163
+ "minted-asset",
4164
+ resolvedOriginField ?? "",
4165
+ origin ?? ""
4166
+ ],
4167
+ queryFn: async () => {
4168
+ const response = await gatewayCall("query", {
4169
+ scope_path: resolvedScopePath,
4170
+ filters: { [`field.${resolvedOriginField}`]: origin },
4171
+ limit: 1
4172
+ });
4173
+ const rawItems = response.content?.items ?? response.items ?? [];
4174
+ const asset = rawItems[0] ? normalizeItem(rawItems[0]) : null;
4175
+ if (!asset) return null;
4176
+ const children = await fetchVfsChildren(asset.path);
4177
+ const hasBytes = children.some(
4178
+ (child) => child.item_type === "file" && Boolean(child.type_data?.file_ref)
4179
+ );
4180
+ return { asset, hasBytes };
4181
+ },
4182
+ enabled: Boolean(origin && resolvedScopePath && resolvedOriginField && !mintError),
4183
+ refetchInterval: (query) => {
4184
+ if (activeRef.current.key === correlationKey && activeRef.current.found?.hasBytes) {
4185
+ return false;
4186
+ }
4187
+ return query.state.data?.hasBytes ? false : 1500;
4188
+ }
4189
+ });
4190
+ React.useEffect(() => {
4191
+ const recovered = recovery.data;
4192
+ if (!recovered || activeRef.current.key !== correlationKey) return;
4193
+ const previous = activeRef.current.found;
4194
+ const next = {
4195
+ key: correlationKey,
4196
+ itemId: recovered.asset.id,
4197
+ itemPath: recovered.asset.path,
4198
+ displayName: typeof recovered.asset.type_data?.display_name === "string" ? recovered.asset.type_data.display_name : recovered.asset.name,
4199
+ hasBytes: recovered.hasBytes || Boolean(previous?.itemId === recovered.asset.id && previous.hasBytes)
4200
+ };
4201
+ activeRef.current.found = next;
4202
+ setFound(next);
4203
+ }, [recovery.data, correlationKey]);
4204
+ const waiting = Boolean(origin && resolvedScopeId) && !mintError && !currentFound?.hasBytes;
4205
+ React.useEffect(() => {
4206
+ if (!waiting || !resolvedScopeId) return;
4207
+ return subscribeToScope(
4208
+ resolvedScopeId,
4209
+ ["asset.materialized", "content.written"]
4210
+ );
4211
+ }, [waiting, resolvedScopeId]);
4212
+ React.useEffect(() => {
4213
+ if (!waiting || !origin || !resolvedScopeId) return;
4214
+ const generationKey = correlationKey;
4215
+ const payload = (data) => data?.payload ?? data;
4216
+ const eventScope = (data) => {
4217
+ const p = payload(data);
4218
+ const value = p?.scope_id ?? data?.scope_id;
4219
+ return typeof value === "string" ? value : void 0;
4220
+ };
4221
+ const contentPath = (data) => {
4222
+ const p = payload(data);
4223
+ const value = p?.item_path ?? data?.item_path;
4224
+ return typeof value === "string" && value ? value : void 0;
4225
+ };
4226
+ const belongsToAsset = (itemPath, assetPath) => {
4227
+ const normalizedAssetPath = assetPath.replace(/\/+$/, "");
4228
+ return itemPath === normalizedAssetPath || itemPath.startsWith(`${normalizedAssetPath}/`);
4229
+ };
4230
+ const unsubscribes = [
4231
+ subscribeToEvents("asset.materialized", (data) => {
4232
+ if (activeRef.current.key !== generationKey) return;
4233
+ const p = payload(data);
4234
+ if (typeof p?.item_id !== "string" || !p.item_id) return;
4235
+ const previous = activeRef.current.found;
4236
+ const itemPath = typeof p.item_path === "string" ? p.item_path : void 0;
4237
+ const hasBytes = Boolean(p.has_bytes) || Boolean(
4238
+ itemPath && Array.from(activeRef.current.earlyContentPaths).some((path) => belongsToAsset(path, itemPath))
4239
+ ) || Boolean(previous && previous.itemId === p.item_id && previous.hasBytes);
4240
+ const next = {
4241
+ key: generationKey,
4242
+ itemId: p.item_id,
4243
+ itemPath,
4244
+ displayName: typeof p.display_name === "string" ? p.display_name : void 0,
4245
+ hasBytes
4246
+ };
4247
+ activeRef.current.found = next;
4248
+ setFound(next);
4249
+ }, (data) => {
4250
+ const scope = eventScope(data);
4251
+ return (!scope || scope === resolvedScopeId) && payload(data)?.origin === origin;
4252
+ }),
4253
+ subscribeToEvents("content.written", (data) => {
4254
+ if (activeRef.current.key !== generationKey) return;
4255
+ const itemPath = contentPath(data);
4256
+ if (!itemPath) return;
4257
+ const previous = activeRef.current.found;
4258
+ if (!previous?.itemPath || !belongsToAsset(itemPath, previous.itemPath)) {
4259
+ activeRef.current.earlyContentPaths.add(itemPath);
4260
+ if (activeRef.current.earlyContentPaths.size > 128) {
4261
+ const oldest = activeRef.current.earlyContentPaths.values().next().value;
4262
+ if (oldest) activeRef.current.earlyContentPaths.delete(oldest);
4263
+ }
4264
+ return;
4265
+ }
4266
+ if (previous.hasBytes) return;
4267
+ const next = { ...previous, hasBytes: true };
4268
+ activeRef.current.found = next;
4269
+ setFound(next);
4270
+ }, (data) => {
4271
+ const scope = eventScope(data);
4272
+ return (!scope || scope === resolvedScopeId) && Boolean(contentPath(data));
4273
+ })
4274
+ ];
4275
+ return () => unsubscribes.forEach((fn) => fn());
4276
+ }, [waiting, origin, resolvedScopeId, correlationKey]);
4277
+ const state = mintError ? "failed" : !origin ? "idle" : currentFound ? currentFound.hasBytes ? "ready" : "materializing" : "pending";
4278
+ return {
4279
+ state,
4280
+ itemId: currentFound?.itemId,
4281
+ itemPath: currentFound?.itemPath,
4282
+ displayName: currentFound?.displayName,
4283
+ fallbackUrl: fallbackUrl ?? void 0,
4284
+ error: mintError ?? void 0
4285
+ };
4286
+ }
4069
4287
 
4070
4288
  // src/schema-utils.ts
4071
4289
  function keyToLabel(key) {
@@ -4863,6 +5081,7 @@ exports.useItems = useItems;
4863
5081
  exports.useLink = useLink;
4864
5082
  exports.useList = useList;
4865
5083
  exports.useMemberFocus = useMemberFocus;
5084
+ exports.useMintedAsset = useMintedAsset;
4866
5085
  exports.useMounts = useMounts;
4867
5086
  exports.useMove = useMove;
4868
5087
  exports.useMutation = useMutation;