@fusedio/widget-sdk 0.1.1 → 0.3.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/bridge.d.ts CHANGED
@@ -87,6 +87,15 @@ export interface RoutingBridge {
87
87
  export interface SqlQueryOptions {
88
88
  defaultLimit?: number;
89
89
  signal?: AbortSignal;
90
+ /**
91
+ * Optional binding identity (chunk-2 MCP-host seam). When the host resolves
92
+ * data server-side (the MCP Apps renderer), it stamps a `_queryId` into each
93
+ * data-bound node's props and the SDK threads it here so the static bridge can
94
+ * look up the pre-resolved rows by id. The workbench bridge ignores this field
95
+ * (it runs the query against DuckDB regardless), so it is fully
96
+ * backward-compatible.
97
+ */
98
+ queryId?: string;
90
99
  }
91
100
  export interface SqlQueryResult {
92
101
  rows: ReadonlyArray<Record<string, unknown>>;
package/dist/bundle.js CHANGED
@@ -1,2 +1,2 @@
1
- var ir="parameter-updates",ae=(o=>(o.PARAM="param",o.RANGE="range",o.VIEWPORT="viewport",o.CLEAR="clear",o))(ae||{});function ur(e){if(typeof e!="object"||e===null)return!1;let n=e;return typeof n.type=="string"&&Object.values(ae).includes(n.type)&&typeof n.parameter=="string"&&"values"in n}import{createContext as ye,useContext as Re}from"react";var be=ye(null);be.displayName="FusedWidgetBridgeContext";function y(){let e=Re(be);if(!e)throw new Error("useFusedWidgetBridge: no FusedWidgetBridgeContext provider in the tree. Wrap your components with the workbench's <JsonUiProvider> or the test harness's <FusedWidgetBridgeContext.Provider value={createTestBridge()}>.");return e}var he=ye(null);he.displayName="JsonUiNodeOverrideContext";function V(){let e=y(),n=Re(he);return n?{udfUniqueId:n.udfUniqueId??e.node.udfUniqueId,udfName:n.udfName??e.node.udfName,configHash:n.configHash??e.node.configHash}:{udfUniqueId:e.node.udfUniqueId,udfName:e.node.udfName,configHash:e.node.configHash}}import{createContext as nn,useCallback as ve,useContext as rn,useRef as we,useSyncExternalStore as tn}from"react";function dr(){let e=new Map,n=new Set,r=t=>{n.forEach(o=>{o.names.has(t)&&o.cb()})};return{get(t){return e.get(t)},getSnapshot(t){let o={};for(let i of t)e.has(i)&&(o[i]=e.get(i));return o},getAll(){let t={};return e.forEach((o,i)=>{t[i]=o}),t},setField(t,o){e.has(t)&&Object.is(e.get(t),o)||(e.set(t,o),r(t))},removeField(t){e.has(t)&&(e.delete(t),r(t))},subscribe(t,o){let i={names:new Set(t),cb:o};return n.add(i),()=>{n.delete(i)}}}}var Ue=nn({store:null,isInForm:!1});Ue.displayName="JsonUiFormContext";function on(){return rn(Ue)}var xe=Object.freeze({});function j(e){let{store:n,isInForm:r}=on(),t=un(e),o=ve(f=>n?n.subscribe(t,f):()=>{},[n,t]),i=we(xe),l=ve(()=>{if(!n)return xe;let f=n.getSnapshot(t),a=i.current;return sn(a,f)?a:(i.current=f,f)},[n,t]),s=tn(o,l,l);return{inForm:r,values:s}}function sn(e,n){if(e===n)return!0;let r=Object.keys(e),t=Object.keys(n);if(r.length!==t.length)return!1;for(let o of r)if(!Object.is(e[o],n[o]))return!1;return!0}function un(e){let n=we(e),r=n.current;return r!==e&&(r.length!==e.length||r.some((t,o)=>t!==e[o]))&&(n.current=e),n.current}function an(e){return e}function ln(e){return e}import{useCallback as X,useEffect as J,useMemo as Y,useRef as I,useState as cn}from"react";function fn({param:e,debounceMs:n=300,readOnly:r=!1,defaultValue:t,broadcastDefaultValue:o=!0,validate:i,preprocess:l}){let s=y(),{configHash:f}=V(),a=!!e,R=(u,c)=>{if(!e)return;if(u==="Cleared"){s.log.log(`Cleared param "${e}"`,"info",f);return}let d=JSON.stringify(c),N=d&&d.length>100?d.slice(0,100)+"\u2026":d;s.log.log(`${u} param "${e}" = ${N}`,"info",f)},p=Y(()=>l??gn(t),[l]),C=Y(()=>i??dn(t),[i]),g=Y(()=>e?[e]:[],[e]),{inForm:b,values:h}=j(g),P=e?h[e]:void 0,T=Y(()=>{if(!(!a||!e))return s.params.getSnapshot(e)},[s,a,e]),v=()=>{let u=b&&P!==void 0?P:T;if(u==null)return t;let c=p(u);return C(c)?c:t},[D,w]=cn(v),x=I(D);x.current=D;let m=I(null),A=I(!1),L=I(!1),F=I({enabled:a,param:e});F.current={enabled:a,param:e};let E=I(s);E.current=s;let Q=I(e);J(()=>{let u=Q.current;Q.current=e,u&&u!==e&&s.params.clear(u)},[s,e]),J(()=>{if(!a||!e||A.current)return;let u=b&&P!==void 0?P:s.params.getSnapshot(e);if(u==null)return;let c=p(u);c!==x.current&&C(c)&&(w(c),R("Received",u))},[s,e,a,b,P,p,C]),J(()=>!a||!e?void 0:s.params.subscribe(e,()=>{if(A.current)return;let c=s.params.getSnapshot(e);if(c==null)return;let d=p(c);d!==x.current&&C(d)&&(w(d),R("Received",c))}),[s,e,a,p,C]);let M=X(u=>{!a||!e||(s.params.set(e,u,"param"),s.edges.stopLoading(),R("Broadcast",u))},[s,a,e]),q=X(()=>{!a||r||(m.current&&(clearTimeout(m.current),m.current=null),s.edges.startLoading(),M(x.current),A.current=!1)},[s,M,a,r]),U=X(u=>{m.current&&(clearTimeout(m.current),m.current=null),w(u),x.current=u,A.current=!1,!(!a||!e||r)&&(s.params.clear(e),s.edges.stopLoading(),R("Cleared",null))},[s,a,e,r]);J(()=>{L.current=!1},[e,a]),J(()=>{if(!a||!e||r||!o||L.current)return;let u=s.params.getSnapshot(e);if(u!=null){L.current=!0;return}if(x.current===""){L.current=!0;return}M(x.current),L.current=!0},[s,a,e,r,o,M]);let _=X(u=>{w(u),!(!a||r)&&(A.current=!0,s.edges.startLoading(),m.current&&clearTimeout(m.current),m.current=setTimeout(()=>{M(u),A.current=!1},n))},[s,M,n,a,r]);return J(()=>()=>{m.current&&clearTimeout(m.current);let{enabled:u,param:c}=F.current;!u||!c||E.current.params.clear(c)},[]),{value:D,setValue:_,broadcastNow:q,clearValue:U}}function dn(e){return typeof e=="string"?(n=>typeof n=="string"):typeof e=="number"?(n=>typeof n=="number"):typeof e=="boolean"?(n=>typeof n=="boolean"):Array.isArray(e)?(n=>Array.isArray(n)):e!==null&&typeof e=="object"?(n=>n!==null&&typeof n=="object"&&!Array.isArray(n)):(n=>!0)}function gn(e){return typeof e=="string"?n=>typeof n=="string"?n:Array.isArray(n)?n.join(","):n!==null&&typeof n=="object"?JSON.stringify(n):String(n):n=>n}import{useCallback as ke,useRef as Pe,useSyncExternalStore as pn}from"react";var Ce=Object.freeze({});function Z(e){let n=y(),r=Sn(e),t=ke(l=>r.length===0?()=>{}:n.params.subscribeMany(r,l),[n,r]),o=Pe(Ce),i=ke(()=>{if(r.length===0)return Ce;let l=n.params.getSnapshotMany(r),s=o.current;return mn(s,l)?s:(o.current=l,l)},[n,r]);return pn(t,i,i)}function mn(e,n){if(e===n)return!0;let r=Object.keys(e),t=Object.keys(n);if(r.length!==t.length)return!1;for(let o of r)if(!Object.is(e[o],n[o]))return!1;return!0}function Sn(e){let n=Pe(e),r=n.current;return r!==e&&(r.length!==e.length||r.some((t,o)=>t!==e[o]))&&(n.current=e),n.current}import{useCallback as le,useRef as yn,useSyncExternalStore as Rn}from"react";function bn(){let e=y(),n=le(l=>e.routing.subscribeAllowedSources(l),[e]),r=yn(null),t=le(()=>{let l=e.routing.getAllowedSources(),s=r.current;return hn(s,l)?s:(r.current=l,l)},[e]),o=Rn(n,t,t),i=le((l,s)=>!o||o.length===0||!l&&!s?!0:o.some(f=>f.udfUniqueId&&f.udfUniqueId===l||f.udfName&&f.udfName===s),[o]);return{allowedSources:o,isAllowedSource:i}}function hn(e,n){return e===n?!0:e===null||n===null||e.length!==n.length?!1:e.every((r,t)=>r.udfUniqueId===n[t].udfUniqueId&&r.udfName===n[t].udfName)}import{useCallback as Ee,useRef as vn,useSyncExternalStore as xn}from"react";function wn(){let e=y(),n=Ee(o=>e.routing.subscribeAllowedSources(o),[e]),r=vn(null),t=Ee(()=>{let o=e.routing.getAllowedUdfNames(),i=r.current;return Un(i,o)?i:(r.current=o,o)},[e]);return xn(n,t,t)}function Un(e,n){if(e===n)return!0;if(e===null||n===null||e.size!==n.size)return!1;for(let r of e)if(!n.has(r))return!1;return!0}import{useEffect as kn,useMemo as $,useRef as Cn,useState as Ae,useSyncExternalStore as Pn,useCallback as Le}from"react";var Fe=/\$([a-zA-Z_][a-zA-Z0-9_]*)/g,En=/\{\{[\s\S]*?\}\}/,Te=/\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\b/g;function ce(e,n={}){let r=e??"",t=n.preserveMissingParams??!1,o=y(),i=$(()=>An(r),[r]),l=Z(i),{inForm:s,values:f}=j(i),a=$(()=>s?{...l,...f}:l,[l,f,s]),R=$(()=>En.test(r),[r]),p=$(()=>R?"":Ln(r,a,t),[r,a,t,R]),C=$(()=>{if(!R)return[];let w=new Set,x=[];Te.lastIndex=0;let m;for(;(m=Te.exec(r))!==null;)w.has(m[1])||(w.add(m[1]),x.push(m[1]));return x},[r,R]),g=Fn(o,C),[b,h]=Ae(()=>({key:"",value:""})),[P,T]=Ae(!1),v=$(()=>JSON.stringify({template:r,paramValues:a,preserveMissingParams:t,tick:g}),[r,a,t,g]);return kn(()=>{if(!R){T(!1);return}let w=!1,x=new AbortController;return T(!0),o.template.render(r,a,{preserveMissingParams:t,signal:x.signal}).then(m=>{w||(h(A=>A.key===v&&A.value===m.value?A:{key:v,value:m.value}),T(m.loading))},m=>{w||m?.name!=="AbortError"&&T(!1)}),()=>{w=!0,x.abort()}},[o,R,r,a,t,v]),{value:$(()=>{if(!R)return p;if(b.key===v)return b.value;try{return o.template.renderLoading(r,a,{preserveMissingParams:t})}catch{return r}},[o,R,p,b,v,r,a,t]),loading:R?P:!1}}function An(e){let n=[],r=new Set;for(let t of e.matchAll(Fe)){let o=t[1];r.has(o)||(r.add(o),n.push(o))}return n}function Ln(e,n,r){return e.replace(Fe,(t,o)=>{let i=n[o];return i==null?r?t:"":Tn(i)})}function Tn(e){return e==null?"":typeof e=="string"?e:typeof e=="number"||typeof e=="boolean"?String(e):JSON.stringify(e)??""}function Fn(e,n){let r=Cn(0),t=n.slice().sort().join("|"),o=Le(l=>{let s=()=>{r.current+=1,l()},f=[e.template.subscribe(s)];for(let a of n)f.push(e.udfs.subscribeOutput(a,s));return()=>f.forEach(a=>a())},[e,t]),i=Le(()=>r.current,[]);return Pn(o,i,i)}import{useCallback as ee,useEffect as Dn,useMemo as ne,useRef as On,useState as De,useSyncExternalStore as Nn}from"react";function Oe(e){let n=y(),r=ee(i=>e?n.udfs.subscribeOutput(e,i):()=>{},[n,e]),t=On(void 0),o=ee(()=>{if(!e)return;let i=n.udfs.getOutputSnapshot(e),l=t.current;return Mn(l,i)?l:(t.current=i,i)},[n,e]);return Nn(r,o,o)}function Ne(){let e=y();return ee(n=>e.udfs.requestReexecute(n),[e])}function Mn(e,n){return e===n?!0:!e||!n?!1:e.data===n.data&&e.isExecutionInProgress===n.isExecutionInProgress&&e.error===n.error&&e.vfsFilename===n.vfsFilename}var Me=/^\{\{(\w+)\.(\w+)(?:\[(\d+)\])?\}\}$/;function re(e){return!e||typeof e!="string"?!1:Me.test(e)}function fe(e){if(!re(e))return null;let n=e.match(Me);if(!n)return null;let[,r,t,o]=n,i=o!==void 0?parseInt(o,10):void 0;return{udfName:r,columnName:t,index:i}}function Bn(e){return!!e&&typeof e=="object"&&typeof e.getRows=="function"}function de({udfName:e,sampleSize:n=200}){let r=Oe(e),t=Ne(),[o,i]=De([]),[l,s]=De([]);Dn(()=>{let a=!1,R=r?.data;if(!R||!Bn(R)){i([]),s([]);return}return(async()=>{try{let p=await R.getRows(0,Math.max(0,n));if(a)return;let C=p.map(b=>{let h=b;return h&&typeof h=="object"&&h.properties&&typeof h.properties=="object"?h.properties:b});i(C);let g=Array.from(new Set(C.flatMap(b=>Object.keys(b??{}))));s(g)}catch{if(a)return;i([]),s([])}})(),()=>{a=!0}},[r?.data,n]);let f=ee(()=>{e&&t(e)},[t,e]);return{loading:r?.isExecutionInProgress??!1,errorMessage:r?.error??null,isError:!!r?.error,columns:l,rows:o,requestReexecute:f}}function qn(e,n=200){let r=re(e),t=ne(()=>r?fe(e):null,[r,e]),{rows:o,loading:i}=de({udfName:t?.udfName,sampleSize:n});return{values:ne(()=>!t||!t.columnName?[]:o.map(s=>s?.[t.columnName]).filter(s=>s!=null),[o,t]),loading:r?i:!1}}function _n(e,n=200){let r=re(e),t=ne(()=>r?fe(e):null,[r,e]),{rows:o,loading:i}=de({udfName:t?.udfName,sampleSize:n});return{value:ne(()=>{if(!t||!t.columnName||t.index===void 0)return null;let s=o[t.index];if(!s)return null;let f=s[t.columnName];return f!==void 0?f:null},[o,t]),loading:r?i:!1}}import{useCallback as Ke,useEffect as z,useMemo as O,useRef as Hn,useState as B}from"react";import{useCallback as te,useMemo as Qn,useRef as ge,useSyncExternalStore as In}from"react";var Be=Object.freeze([]);function oe(){let e=y(),{configHash:n}=V(),r=ge(e);r.current=e;let t=ge(n);t.current=n;let o=te((i,l="info")=>{r.current.log.log(i,l,t.current)},[]);return Qn(()=>({log:o}),[o])}function $n(e){let n=y(),r=te(i=>e?n.log.subscribeLogs(e,i):()=>{},[n,e]),t=ge(Be),o=te(()=>{if(!e)return Be;let i=n.log.getLogsSnapshot(e);return i===t.current?t.current:(t.current=i,i)},[n,e]);return In(r,o,o)}function Vn(e){let n=y();return te(()=>{e&&n.log.clearLogs(e)},[n,e])}function se(){let e=y();return{startLoading:e.edges.startLoading,stopLoading:e.edges.stopLoading}}var pe=/\$([a-zA-Z_][a-zA-Z0-9_]*)/g,qe=/\{\{(\w+)(?:\?([^}]*))?\}\}/g,me=/'((?:s3|gs|fd):\/\/[^'\n]+)'/g;function jn(e){return e==null?"''":typeof e=="number"&&!Number.isNaN(e)?String(e):typeof e=="boolean"?e?"TRUE":"FALSE":`'${String(e).replace(/'/g,"''")}'`}function Jn(e,n){let r=!1;for(let t=0;t<n;t++)if(e[t]==="'"){if(r&&e[t+1]==="'"){t++;continue}r=!r}return r}function _e(e,n){return e.replace(pe,(r,t,o)=>{let i=n[t],l=i==null?"":String(i);return Jn(e,o)?l.replace(/'/g,"''"):jn(i)})}function Qe(e){let n=new Set,r=[];pe.lastIndex=0;for(let t of e.matchAll(pe)){let o=t[1];n.has(o)||(n.add(o),r.push(o))}return r}function Wn(e){if(!e)return null;let n={},r=!1;for(let t of e.split(/[&,]/)){if(!t)continue;let o=t.indexOf("=");if(o===-1)continue;let i=t.slice(0,o),l=t.slice(o+1),s,f;try{s=decodeURIComponent(i),f=decodeURIComponent(l)}catch{s=i,f=l}s&&(n[s]=f,r=!0)}return r?n:null}function Ie(e){let n=[],r;for(qe.lastIndex=0;(r=qe.exec(e))!==null;){let[t,o,i]=r;n.push({match:t,name:o,overrides:Wn(i),start:r.index,end:r.index+t.length})}return n}function $e(e){if(!e)return[];let n=new Set,r=[];me.lastIndex=0;let t;for(;(t=me.exec(e))!==null;){let o=t[1];n.has(o)||(n.add(o),r.push(o))}return r}function Ve(e,n){return e&&e.replace(me,(r,t)=>{let o=n[t];return o?`'${o}'`:r})}var je=/^\$([a-zA-Z_][a-zA-Z0-9_]*)$/;function Je(e){let n=e.trim(),r=je.exec(n);return r?r[1]:null}function We(e,n){let r=je.exec(e);if(!r)return{value:e,unresolved:!1};let t=r[1];if(!(t in n))return{value:e,unresolved:!0};let o=n[t];return o==null?{value:"",unresolved:!1}:{value:String(o),unresolved:!1}}function zn(e){return Object.keys(e).sort().map(n=>`${n}=${e[n]}`).join("&")}function ze(e,n){return n?`${e}#${zn(n)}`:e}var Ze=500,W=Object.freeze([]),G=Object.freeze([]);function He(e,n){if(/\bLIMIT\b/i.test(e))return e;let r=e.trimEnd();return`${r.endsWith(";")?r.slice(0,-1):r} LIMIT ${n}`}function Kn(e){return`"${e.replace(/"/g,'""')}"`}function Zn(e,n,r,t,o,i){let l=e.match(/^\$([a-zA-Z_][a-zA-Z0-9_]*)$/);if(l){let f=o[l[1]];return f==null?"":He(String(f),i)}let s=e;for(let f=n.length-1;f>=0;f--){let{raw:a,key:R,resolvedOverrides:p}=n[f],g=p===null&&t?t[a.name]:void 0,b;g?b=Kn(g.relationName):b=`'${r.get(R)??`${a.name}.parquet`}'`,s=s.slice(0,a.start)+b+s.slice(a.end)}return s=He(s,i),_e(s,o)}function Ge({sql:e,enabled:n=!0,maxRows:r=Ze,sourceOverrides:t}){let o=y(),{startLoading:i,stopLoading:l}=se(),{log:s}=oe(),[f,a]=B(""),[R,p]=B(!1),[C,g]=B(null),[b,h]=B(0),P=O(()=>e?Ie(e):[],[e]),T=O(()=>t?P.filter(u=>u.overrides!==null||!t[u.name]):P,[P,t]),v=O(()=>{let u=new Set;for(let c of T)if(c.overrides)for(let d of Object.values(c.overrides)){let N=Je(d);N&&u.add(N)}return Array.from(u)},[T]),D=O(()=>e?Qe(e):[],[e]),w=O(()=>{let u=new Set,c=[];for(let d of D)u.has(d)||(u.add(d),c.push(d));for(let d of v)u.has(d)||(u.add(d),c.push(d));return c},[D,v]),x=Z(w),{inForm:m,values:A}=j(w),L=O(()=>m?{...x,...A}:x,[m,x,A]),F=O(()=>T.map(u=>{if(!u.overrides)return{raw:u,key:u.name,resolvedOverrides:null,unresolved:!1};let c={},d=!1;for(let[N,H]of Object.entries(u.overrides)){let S=We(H,L);S.unresolved&&(d=!0),c[N]=S.value}return{raw:u,key:ze(u.name,c),resolvedOverrides:c,unresolved:d}}),[T,L]),E=O(()=>{let u=new Set,c=[];for(let d of F)d.unresolved||u.has(d.key)||(u.add(d.key),c.push({name:d.raw.name,key:d.key,overrides:d.resolvedOverrides??void 0}));return c},[F]),Q=O(()=>E.map(u=>`${u.key}|${u.name}|${u.overrides?Object.entries(u.overrides).sort(([c],[d])=>c.localeCompare(d)).map(([c,d])=>`${c}=${d}`).join(","):""}`).join(`
2
- `),[E]),M=Ke(()=>{h(u=>u+1)},[]);z(()=>{if(!n||E.length===0)return;let u=E.map(c=>o.udfs.subscribeOutput(c.name,()=>{h(d=>d+1)}));return()=>{u.forEach(c=>c())}},[o,n,E]),z(()=>{R?i():l()},[R,i,l]);let q=O(()=>{if(!t)return null;for(let u of P){if(u.overrides!==null)continue;let c=t[u.name];if(c?.error)return c.error}return null},[P,t]),U=O(()=>t?P.some(u=>u.overrides===null&&t[u.name]?.loading):!1,[P,t]),_=F.some(u=>u.unresolved);return z(()=>{if(!n||!e){a(""),p(!1),g(null);return}if(q){a(""),g(q),p(!1),s(`SQL preprocessing: ${q}`,"error");return}if(U||_){a(""),g(null),p(!0);return}let u=!1;return p(!0),g(null),(async()=>{let c=new Map,d;if(E.length>0)try{let S=await o.sql.resolveVfsFilenames(E);if(u)return;if(S instanceof Map)for(let k of F){if(k.resolvedOverrides)continue;let K=S.get(k.raw.name);K&&c.set(k.key,K)}else c=S.filenames,d=S.errors}catch(S){if(u)return;let k=S instanceof Error?S.message:typeof S=="string"?S:"VFS registration failed";a(""),g(k),p(!1),s(`SQL preprocessing: ${k}`,"error");return}if(d)for(let S of F){let k=d.get(S.key);if(k){if(u)return;a(""),g(k),p(!1),s(`SQL preprocessing: ${k}`,"error");return}}for(let S of F)if(!(S.unresolved||S.resolvedOverrides===null&&t?.[S.raw.name]!==void 0)&&!c.has(S.key)){if(u)return;a(""),g(null),p(!0);return}let N;try{N=Zn(e,F,c,t,L,r)}catch(S){if(u)return;let k=S instanceof Error?S.message:typeof S=="string"?S:"SQL preprocessing failed";a(""),g(k),p(!1),s(`SQL preprocessing failed: ${k}`,"error");return}let H=$e(N);if(H.length===0){if(u)return;a(N),g(null),p(!1),s("SQL preprocessing completed");return}try{let S={},k=await Promise.all(H.map(ue=>o.signUrl(ue)));if(u)return;H.forEach((ue,en)=>{S[ue]=k[en].signed});let K=Ve(N,S);a(K),g(null),p(!1),s("SQL preprocessing completed")}catch(S){if(u)return;let k=S instanceof Error?S.message:typeof S=="string"?S:"URL signing failed";a(""),g(k),p(!1),s(`SQL preprocessing failed: ${k}`,"error")}})(),()=>{u=!0}},[o,n,e,Q,F,L,t,q,U,_,r,b,s,E]),{processedSql:f,loading:R,error:C,refetch:M}}function Gn({sql:e,enabled:n=!0,maxRows:r=Ze,sourceOverrides:t}){let o=y(),{startLoading:i,stopLoading:l}=se(),{log:s}=oe(),[f,a]=B(W),[R,p]=B(G),[C,g]=B(!1),[b,h]=B(null),[P,T]=B(0),{processedSql:v,loading:D,error:w,refetch:x}=Ge({sql:e,enabled:n,maxRows:r,sourceOverrides:t}),m=Hn(""),A=n&&!!e&&!!v&&!D&&!w&&v!==m.current,L=D||C||A;z(()=>{L?i():l()},[L,i,l]);let F=Ke(()=>{m.current="",x(),T(E=>E+1)},[x]);return z(()=>{if(!n||!e){m.current="",a(W),p(G),g(!1),h(null);return}if(w){m.current="",h(w),a(W),p(G),g(!1);return}if(D||!v){m.current="",g(!1);return}let E=!1,Q=new AbortController;m.current=v,g(!0),h(null);let M=v.length>120?v.slice(0,120)+"\u2026":v;s(`SQL query started: ${M}`);let q=performance.now();return o.sql.query(v,{signal:Q.signal}).then(U=>{if(E)return;let _=Math.round(performance.now()-q);if(U.error){a(W),p(G),h(U.error),g(!1),s(`SQL failed (${_}ms): ${U.error}`,"error");return}a(U.rows.length===0?W:U.rows),p(U.columns),h(null),g(!1),s(`SQL completed: ${U.rows.length} row${U.rows.length!==1?"s":""} in ${_}ms`)},U=>{if(E||U?.name==="AbortError")return;let _=Math.round(performance.now()-q),u=U instanceof Error?U.message:typeof U=="string"?U:"SQL query failed";h(u),a(W),p(G),g(!1),s(`SQL failed (${_}ms): ${u}`,"error")}),()=>{E=!0,Q.abort()}},[o,n,e,v,D,w,P,s]),{rows:f,columns:R,loading:L,error:b,refetch:F}}function Xn(e,n=!0){let r=y(),[t,o]=B({filenames:new Map,loading:!1}),i=O(()=>e.slice().sort().join("|"),[e]);return z(()=>{if(!n||e.length===0){o({filenames:new Map,loading:!1});return}let l=!1;return o(s=>({...s,loading:!0,error:void 0})),r.sql.resolveVfsFilenames(e).then(s=>{if(l)return;let f=s instanceof Map?s:s.filenames;o({filenames:f,loading:!1})},s=>{l||o({filenames:new Map,loading:!1,error:s instanceof Error?s.message:String(s)})}),()=>{l=!0}},[r,i,n]),t}import{useCallback as Xe,useEffect as Yn,useState as ie}from"react";var Ye=["s3://","gs://","fd://"];function Se(e){return Ye.some(n=>e.startsWith(n))}function er(){let e=y();return{signUrl:Xe(r=>e.signUrl(r),[e])}}function nr(e){let n=y(),{value:r,loading:t}=ce(e),[o,i]=ie(null),[l,s]=ie(null),[f,a]=ie(!1),[R,p]=ie(0);Yn(()=>{if(t)return;if(!r){i(null),s(null),a(!1);return}if(!Se(r)){i(r),s(null),a(!1);return}let g=!1;return a(!0),s(null),n.signUrl(r).then(({signed:b})=>{g||i(b??r)}).catch(b=>{g||(s(b instanceof Error?b.message:"Failed to load media"),i(null))}).finally(()=>{g||a(!1)}),()=>{g=!0}},[n,t,r,R]);let C=Xe(async()=>{if(!r||!Se(r))return r??null;let{signed:g}=await n.signUrl(r),b=g??r;return i(b),s(null),p(h=>h+1),b},[n,r]);return{src:o,loading:t||f,error:l,refreshSignedUrl:C,resolvedSrc:r,needsSigning:!!(r&&Se(r))}}import{useEffect as rr,useState as tr}from"react";function or(e,n){let r=y(),[t,o]=tr({status:"idle"});return rr(()=>{if(!n||!e?.trim()){o({status:"idle"});return}let i=!1;return o({status:"checking"}),r.uploads.checkAccess(e).then(l=>{i||(l.ok?o({status:"allowed"}):o({status:"denied",message:l.message??"Upload access denied."}))}),()=>{i=!0}},[r,e,n]),t}function sr(){return V()}export{Ue as FormContext,be as FusedWidgetBridgeContext,he as JsonUiNodeOverrideContext,ir as PARAMETER_BROADCAST_CHANNEL,ae as ParameterMessageType,me as SIGNABLE_URL_LITERAL_REGEX,Ye as SIGNED_URL_SCHEMES,pe as SQL_PARAM_REGEX,qe as SQL_SOURCE_PLACEHOLDER_REGEX,zn as canonicalOverrideKey,ze as computePlaceholderKey,dr as createFormParamsStore,ln as defineCatalog,an as defineComponent,jn as escapeSqlValue,$e as extractSignableUrls,Qe as extractSqlParams,Je as getDollarRefName,ur as isStandardMessage,re as isUdfQuery,Wn as parseOverridesString,Ie as parseSqlUdfPlaceholders,fe as parseUdfColumnQuery,We as resolveOverrideValue,Ve as rewriteSignedUrls,_e as substituteSqlParams,bn as useAllowedSources,wn as useAllowedUdfNames,Z as useCanvasParams,Gn as useDuckDbSqlQuery,Ge as useDuckDbSqlQueryPreprocessing,on as useFormContext,j as useFormParams,fn as useFusedParam,y as useFusedWidgetBridge,se as useJsonUiEdgeAnimation,oe as useJsonUiLog,Vn as useJsonUiLogClear,$n as useJsonUiLogs,V as useJsonUiNode,sr as useJsonUiUdfInfo,nr as useMediaSrc,ce as useParamSubstitution,Ne as useRequestUdfReexecute,_n as useUdfColumnValue,qn as useUdfColumnValues,de as useUdfDataFrameSample,Oe as useUdfOutputByName,or as useUploadAccessCheck,er as useUrlSigning,Xn as useVfsRegistration};
1
+ var xr="parameter-updates",ce=(o=>(o.PARAM="param",o.RANGE="range",o.VIEWPORT="viewport",o.CLEAR="clear",o))(ce||{});function br(e){if(typeof e!="object"||e===null)return!1;let n=e;return typeof n.type=="string"&&Object.values(ce).includes(n.type)&&typeof n.parameter=="string"&&"values"in n}import{createContext as ke,useContext as Ce}from"react";var Pe=ke(null);Pe.displayName="FusedWidgetBridgeContext";function v(){let e=Ce(Pe);if(!e)throw new Error("useFusedWidgetBridge: no FusedWidgetBridgeContext provider in the tree. Wrap your components with the workbench's <JsonUiProvider> or the test harness's <FusedWidgetBridgeContext.Provider value={createTestBridge()}>.");return e}var Ee=ke(null);Ee.displayName="JsonUiNodeOverrideContext";function j(){let e=v(),n=Ce(Ee);return n?{udfUniqueId:n.udfUniqueId??e.node.udfUniqueId,udfName:n.udfName??e.node.udfName,configHash:n.configHash??e.node.configHash}:{udfUniqueId:e.node.udfUniqueId,udfName:e.node.udfName,configHash:e.node.configHash}}import{createContext as dn,useCallback as Ae,useContext as fn,useRef as Le,useSyncExternalStore as gn}from"react";function Cr(){let e=new Map,n=new Set,r=t=>{n.forEach(o=>{o.names.has(t)&&o.cb()})};return{get(t){return e.get(t)},getSnapshot(t){let o={};for(let s of t)e.has(s)&&(o[s]=e.get(s));return o},getAll(){let t={};return e.forEach((o,s)=>{t[s]=o}),t},setField(t,o){e.has(t)&&Object.is(e.get(t),o)||(e.set(t,o),r(t))},removeField(t){e.has(t)&&(e.delete(t),r(t))},subscribe(t,o){let s={names:new Set(t),cb:o};return n.add(s),()=>{n.delete(s)}}}}var Fe=dn({store:null,isInForm:!1});Fe.displayName="JsonUiFormContext";function de(){return fn(Fe)}var Oe=Object.freeze({});function W(e){let{store:n,isInForm:r}=de(),t=mn(e),o=Ae(c=>n?n.subscribe(t,c):()=>{},[n,t]),s=Le(Oe),u=Ae(()=>{if(!n)return Oe;let c=n.getSnapshot(t),l=s.current;return pn(l,c)?l:(s.current=c,c)},[n,t]),i=gn(o,u,u);return{inForm:r,values:i}}function pn(e,n){if(e===n)return!0;let r=Object.keys(e),t=Object.keys(n);if(r.length!==t.length)return!1;for(let o of r)if(!Object.is(e[o],n[o]))return!1;return!0}function mn(e){let n=Le(e),r=n.current;return r!==e&&(r.length!==e.length||r.some((t,o)=>t!==e[o]))&&(n.current=e),n.current}function Sn(e){return e}function yn(e){return e}import{useCallback as ee,useEffect as z,useMemo as ne,useRef as J,useState as Rn}from"react";function fe({param:e,debounceMs:n=300,readOnly:r=!1,defaultValue:t,broadcastDefaultValue:o=!0,validate:s,preprocess:u}){let i=v(),{configHash:c}=j(),l=!!e,x=(d,f)=>{if(!e)return;if(d==="Cleared"){i.log.log(`Cleared param "${e}"`,"info",c);return}let a=JSON.stringify(f),g=a&&a.length>100?a.slice(0,100)+"\u2026":a;i.log.log(`${d} param "${e}" = ${g}`,"info",c)},b=ne(()=>u??xn(t),[u]),w=ne(()=>s??vn(t),[s]),S=ne(()=>e?[e]:[],[e]),{inForm:p,values:h}=W(S),E=e?h[e]:void 0,q=ne(()=>{if(!(!l||!e))return i.params.getSnapshot(e)},[i,l,e]),k=()=>{let d=p&&E!==void 0?E:q;if(d==null)return t;let f=b(d);return w(f)?f:t},[N,O]=Rn(k),U=J(N);U.current=N;let y=J(null),C=J(!1),D=J(!1),T=J({enabled:l,param:e});T.current={enabled:l,param:e};let M=J(i);M.current=i;let L=J(e);z(()=>{let d=L.current;L.current=e,d&&d!==e&&i.params.clear(d)},[i,e]),z(()=>{if(!l||!e||C.current)return;let d=p&&E!==void 0?E:i.params.getSnapshot(e);if(d==null)return;let f=b(d);f!==U.current&&w(f)&&(O(f),x("Received",d))},[i,e,l,p,E,b,w]),z(()=>!l||!e?void 0:i.params.subscribe(e,()=>{if(C.current)return;let f=i.params.getSnapshot(e);if(f==null)return;let a=b(f);a!==U.current&&w(a)&&(O(a),x("Received",f))}),[i,e,l,b,w]);let A=ee(d=>{!l||!e||(i.params.set(e,d,"param"),i.edges.stopLoading(),x("Broadcast",d))},[i,l,e]),I=ee(()=>{!l||r||(y.current&&(clearTimeout(y.current),y.current=null),i.edges.startLoading(),A(U.current),C.current=!1)},[i,A,l,r]),$=ee(d=>{y.current&&(clearTimeout(y.current),y.current=null),O(d),U.current=d,C.current=!1,!(!l||!e||r)&&(i.params.clear(e),i.edges.stopLoading(),x("Cleared",null))},[i,l,e,r]);z(()=>{D.current=!1},[e,l]),z(()=>{if(!l||!e||r||!o||D.current)return;let d=i.params.getSnapshot(e);if(d!=null){D.current=!0;return}if(U.current===""){D.current=!0;return}A(U.current),D.current=!0},[i,l,e,r,o,A]);let Q=ee(d=>{O(d),!(!l||r)&&(C.current=!0,i.edges.startLoading(),y.current&&clearTimeout(y.current),y.current=setTimeout(()=>{A(d),C.current=!1},n))},[i,A,n,l,r]);return z(()=>()=>{y.current&&clearTimeout(y.current);let{enabled:d,param:f}=T.current;!d||!f||M.current.params.clear(f)},[]),{value:N,setValue:Q,broadcastNow:I,clearValue:$}}function vn(e){return typeof e=="string"?(n=>typeof n=="string"):typeof e=="number"?(n=>typeof n=="number"):typeof e=="boolean"?(n=>typeof n=="boolean"):Array.isArray(e)?(n=>Array.isArray(n)):e!==null&&typeof e=="object"?(n=>n!==null&&typeof n=="object"&&!Array.isArray(n)):(n=>!0)}function xn(e){return typeof e=="string"?n=>typeof n=="string"?n:Array.isArray(n)?n.join(","):n!==null&&typeof n=="object"?JSON.stringify(n):String(n):n=>n}import{useEffect as Te}from"react";function bn(e){let n=de(),r=e.param,t=!!(n.isInForm&&r),{value:o,setValue:s,broadcastNow:u,clearValue:i}=fe({...e,param:t?void 0:e.param}),c=n.store;return Te(()=>{!t||!r||!c||c.setField(r,o)},[o,t,r,c]),Te(()=>{if(!(!t||!r||!c))return()=>{c.removeField(r)}},[t,r,c]),{value:o,setValue:s,broadcastNow:u,clearValue:i,isInForm:n.isInForm}}import{useCallback as qe,useRef as De,useSyncExternalStore as hn}from"react";var Ne=Object.freeze({});function Y(e){let n=v(),r=wn(e),t=qe(u=>r.length===0?()=>{}:n.params.subscribeMany(r,u),[n,r]),o=De(Ne),s=qe(()=>{if(r.length===0)return Ne;let u=n.params.getSnapshotMany(r),i=o.current;return Un(i,u)?i:(o.current=u,u)},[n,r]);return hn(t,s,s)}function Un(e,n){if(e===n)return!0;let r=Object.keys(e),t=Object.keys(n);if(r.length!==t.length)return!1;for(let o of r)if(!Object.is(e[o],n[o]))return!1;return!0}function wn(e){let n=De(e),r=n.current;return r!==e&&(r.length!==e.length||r.some((t,o)=>t!==e[o]))&&(n.current=e),n.current}import{useCallback as ge,useRef as kn,useSyncExternalStore as Cn}from"react";function Pn(){let e=v(),n=ge(u=>e.routing.subscribeAllowedSources(u),[e]),r=kn(null),t=ge(()=>{let u=e.routing.getAllowedSources(),i=r.current;return En(i,u)?i:(r.current=u,u)},[e]),o=Cn(n,t,t),s=ge((u,i)=>!o||o.length===0||!u&&!i?!0:o.some(c=>c.udfUniqueId&&c.udfUniqueId===u||c.udfName&&c.udfName===i),[o]);return{allowedSources:o,isAllowedSource:s}}function En(e,n){return e===n?!0:e===null||n===null||e.length!==n.length?!1:e.every((r,t)=>r.udfUniqueId===n[t].udfUniqueId&&r.udfName===n[t].udfName)}import{useCallback as Be,useRef as An,useSyncExternalStore as On}from"react";function Ln(){let e=v(),n=Be(o=>e.routing.subscribeAllowedSources(o),[e]),r=An(null),t=Be(()=>{let o=e.routing.getAllowedUdfNames(),s=r.current;return Fn(s,o)?s:(r.current=o,o)},[e]);return On(n,t,t)}function Fn(e,n){if(e===n)return!0;if(e===null||n===null||e.size!==n.size)return!1;for(let r of e)if(!n.has(r))return!1;return!0}import{useEffect as Tn,useMemo as V,useRef as qn,useState as Me,useSyncExternalStore as Nn,useCallback as Ie}from"react";var Qe=/\$([a-zA-Z_][a-zA-Z0-9_]*)/g,Dn=/\{\{[\s\S]*?\}\}/,_e=/\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\b/g;function pe(e,n={}){let r=e??"",t=n.preserveMissingParams??!1,o=v(),s=V(()=>Bn(r),[r]),u=Y(s),{inForm:i,values:c}=W(s),l=V(()=>i?{...u,...c}:u,[u,c,i]),x=V(()=>Dn.test(r),[r]),b=V(()=>x?"":Mn(r,l,t),[r,l,t,x]),w=V(()=>{if(!x)return[];let O=new Set,U=[];_e.lastIndex=0;let y;for(;(y=_e.exec(r))!==null;)O.has(y[1])||(O.add(y[1]),U.push(y[1]));return U},[r,x]),S=_n(o,w),[p,h]=Me(()=>({key:"",value:""})),[E,q]=Me(!1),k=V(()=>JSON.stringify({template:r,paramValues:l,preserveMissingParams:t,tick:S}),[r,l,t,S]);return Tn(()=>{if(!x){q(!1);return}let O=!1,U=new AbortController;return q(!0),o.template.render(r,l,{preserveMissingParams:t,signal:U.signal}).then(y=>{O||(h(C=>C.key===k&&C.value===y.value?C:{key:k,value:y.value}),q(y.loading))},y=>{O||y?.name!=="AbortError"&&q(!1)}),()=>{O=!0,U.abort()}},[o,x,r,l,t,k]),{value:V(()=>{if(!x)return b;if(p.key===k)return p.value;try{return o.template.renderLoading(r,l,{preserveMissingParams:t})}catch{return r}},[o,x,b,p,k,r,l,t]),loading:x?E:!1}}function Bn(e){let n=[],r=new Set;for(let t of e.matchAll(Qe)){let o=t[1];r.has(o)||(r.add(o),n.push(o))}return n}function Mn(e,n,r){return e.replace(Qe,(t,o)=>{let s=n[o];return s==null?r?t:"":In(s)})}function In(e){return e==null?"":typeof e=="string"?e:typeof e=="number"||typeof e=="boolean"?String(e):JSON.stringify(e)??""}function _n(e,n){let r=qn(0),t=n.slice().sort().join("|"),o=Ie(u=>{let i=()=>{r.current+=1,u()},c=[e.template.subscribe(i)];for(let l of n)c.push(e.udfs.subscribeOutput(l,i));return()=>c.forEach(l=>l())},[e,t]),s=Ie(()=>r.current,[]);return Nn(o,s,s)}import{useCallback as re,useEffect as Qn,useMemo as te,useRef as Jn,useState as Je,useSyncExternalStore as Vn}from"react";function Ve(e){let n=v(),r=re(s=>e?n.udfs.subscribeOutput(e,s):()=>{},[n,e]),t=Jn(void 0),o=re(()=>{if(!e)return;let s=n.udfs.getOutputSnapshot(e),u=t.current;return $n(u,s)?u:(t.current=s,s)},[n,e]);return Vn(r,o,o)}function $e(){let e=v();return re(n=>e.udfs.requestReexecute(n),[e])}function $n(e,n){return e===n?!0:!e||!n?!1:e.data===n.data&&e.isExecutionInProgress===n.isExecutionInProgress&&e.error===n.error&&e.vfsFilename===n.vfsFilename}var je=/^\{\{(\w+)\.(\w+)(?:\[(\d+)\])?\}\}$/;function oe(e){return!e||typeof e!="string"?!1:je.test(e)}function me(e){if(!oe(e))return null;let n=e.match(je);if(!n)return null;let[,r,t,o]=n,s=o!==void 0?parseInt(o,10):void 0;return{udfName:r,columnName:t,index:s}}function jn(e){return!!e&&typeof e=="object"&&typeof e.getRows=="function"}function Se({udfName:e,sampleSize:n=200}){let r=Ve(e),t=$e(),[o,s]=Je([]),[u,i]=Je([]);Qn(()=>{let l=!1,x=r?.data;if(!x||!jn(x)){s([]),i([]);return}return(async()=>{try{let b=await x.getRows(0,Math.max(0,n));if(l)return;let w=b.map(p=>{let h=p;return h&&typeof h=="object"&&h.properties&&typeof h.properties=="object"?h.properties:p});s(w);let S=Array.from(new Set(w.flatMap(p=>Object.keys(p??{}))));i(S)}catch{if(l)return;s([]),i([])}})(),()=>{l=!0}},[r?.data,n]);let c=re(()=>{e&&t(e)},[t,e]);return{loading:r?.isExecutionInProgress??!1,errorMessage:r?.error??null,isError:!!r?.error,columns:u,rows:o,requestReexecute:c}}function Wn(e,n=200){let r=oe(e),t=te(()=>r?me(e):null,[r,e]),{rows:o,loading:s}=Se({udfName:t?.udfName,sampleSize:n});return{values:te(()=>!t||!t.columnName?[]:o.map(i=>i?.[t.columnName]).filter(i=>i!=null),[o,t]),loading:r?s:!1}}function zn(e,n=200){let r=oe(e),t=te(()=>r?me(e):null,[r,e]),{rows:o,loading:s}=Se({udfName:t?.udfName,sampleSize:n});return{value:te(()=>{if(!t||!t.columnName||t.index===void 0)return null;let i=o[t.index];if(!i)return null;let c=i[t.columnName];return c!==void 0?c:null},[o,t]),loading:r?s:!1}}import{useCallback as on,useEffect as K,useMemo as F,useRef as ur,useState as B}from"react";import{createContext as Hn,useContext as Kn}from"react";var ye=Hn({});ye.displayName="JsonUiBindingContext";function Re(){return Kn(ye)}import{useCallback as se,useMemo as Zn,useRef as ve,useSyncExternalStore as Gn}from"react";var We=Object.freeze([]);function ie(){let e=v(),{configHash:n}=j(),r=ve(e);r.current=e;let t=ve(n);t.current=n;let o=se((s,u="info")=>{r.current.log.log(s,u,t.current)},[]);return Zn(()=>({log:o}),[o])}function Yn(e){let n=v(),r=se(s=>e?n.log.subscribeLogs(e,s):()=>{},[n,e]),t=ve(We),o=se(()=>{if(!e)return We;let s=n.log.getLogsSnapshot(e);return s===t.current?t.current:(t.current=s,s)},[n,e]);return Gn(r,o,o)}function Xn(e){let n=v();return se(()=>{e&&n.log.clearLogs(e)},[n,e])}function ue(){let e=v();return{startLoading:e.edges.startLoading,stopLoading:e.edges.stopLoading}}import{createContext as er,useContext as nr}from"react";var rr=Object.freeze({}),xe=er(rr);xe.displayName="SqlSourceOverrideContext";function be(){return nr(xe)}var he=/\$([a-zA-Z_][a-zA-Z0-9_]*)/g,ze=/\{\{(\w+)(?:\?([^}]*))?\}\}/g,Ue=/'((?:s3|gs|fd):\/\/[^'\n]+)'/g;function tr(e){return e==null?"''":typeof e=="number"&&!Number.isNaN(e)?String(e):typeof e=="boolean"?e?"TRUE":"FALSE":`'${String(e).replace(/'/g,"''")}'`}function or(e,n){let r=!1;for(let t=0;t<n;t++)if(e[t]==="'"){if(r&&e[t+1]==="'"){t++;continue}r=!r}return r}function He(e,n){return e.replace(he,(r,t,o)=>{let s=n[t],u=s==null?"":String(s);return or(e,o)?u.replace(/'/g,"''"):tr(s)})}function Ke(e){let n=new Set,r=[];he.lastIndex=0;for(let t of e.matchAll(he)){let o=t[1];n.has(o)||(n.add(o),r.push(o))}return r}function sr(e){if(!e)return null;let n={},r=!1;for(let t of e.split(/[&,]/)){if(!t)continue;let o=t.indexOf("=");if(o===-1)continue;let s=t.slice(0,o),u=t.slice(o+1),i,c;try{i=decodeURIComponent(s),c=decodeURIComponent(u)}catch{i=s,c=u}i&&(n[i]=c,r=!0)}return r?n:null}function Ze(e){let n=[],r;for(ze.lastIndex=0;(r=ze.exec(e))!==null;){let[t,o,s]=r;n.push({match:t,name:o,overrides:sr(s),start:r.index,end:r.index+t.length})}return n}function Ge(e){if(!e)return[];let n=new Set,r=[];Ue.lastIndex=0;let t;for(;(t=Ue.exec(e))!==null;){let o=t[1];n.has(o)||(n.add(o),r.push(o))}return r}function Ye(e,n){return e&&e.replace(Ue,(r,t)=>{let o=n[t];return o?`'${o}'`:r})}var Xe=/^\$([a-zA-Z_][a-zA-Z0-9_]*)$/;function en(e){let n=e.trim(),r=Xe.exec(n);return r?r[1]:null}function nn(e,n){let r=Xe.exec(e);if(!r)return{value:e,unresolved:!1};let t=r[1];if(!(t in n))return{value:e,unresolved:!0};let o=n[t];return o==null?{value:"",unresolved:!1}:{value:String(o),unresolved:!1}}function ir(e){return Object.keys(e).sort().map(n=>`${n}=${e[n]}`).join("&")}function rn(e,n){return n?`${e}#${ir(n)}`:e}var sn=500,H=Object.freeze([]),X=Object.freeze([]);function tn(e,n){if(/\bLIMIT\b/i.test(e))return e;let r=e.trimEnd();return`${r.endsWith(";")?r.slice(0,-1):r} LIMIT ${n}`}function ar(e){return`"${e.replace(/"/g,'""')}"`}function lr(e,n,r,t,o,s){let u=e.match(/^\$([a-zA-Z_][a-zA-Z0-9_]*)$/);if(u){let c=o[u[1]];return c==null?"":tn(String(c),s)}let i=e;for(let c=n.length-1;c>=0;c--){let{raw:l,key:x,resolvedOverrides:b}=n[c],S=b===null&&t?t[l.name]:void 0,p;S?p=ar(S.relationName):p=`'${r.get(x)??`${l.name}.parquet`}'`,i=i.slice(0,l.start)+p+i.slice(l.end)}return i=tn(i,s),He(i,o)}function un({sql:e,enabled:n=!0,maxRows:r=sn,sourceOverrides:t}){let o=v(),s=be(),u=F(()=>{let a=Object.keys(s).length>0;return t?a?{...s,...t}:t:a?s:void 0},[s,t]),{startLoading:i,stopLoading:c}=ue(),{log:l}=ie(),[x,b]=B(""),[w,S]=B(!1),[p,h]=B(null),[E,q]=B(0),k=F(()=>e?Ze(e):[],[e]),N=F(()=>u?k.filter(a=>a.overrides!==null||!u[a.name]):k,[k,u]),O=F(()=>{let a=new Set;for(let g of N)if(g.overrides)for(let R of Object.values(g.overrides)){let _=en(R);_&&a.add(_)}return Array.from(a)},[N]),U=F(()=>e?Ke(e):[],[e]),y=F(()=>{let a=new Set,g=[];for(let R of U)a.has(R)||(a.add(R),g.push(R));for(let R of O)a.has(R)||(a.add(R),g.push(R));return g},[U,O]),C=Y(y),{inForm:D,values:T}=W(y),M=F(()=>D?{...C,...T}:C,[D,C,T]),L=F(()=>N.map(a=>{if(!a.overrides)return{raw:a,key:a.name,resolvedOverrides:null,unresolved:!1};let g={},R=!1;for(let[_,Z]of Object.entries(a.overrides)){let m=nn(Z,M);m.unresolved&&(R=!0),g[_]=m.value}return{raw:a,key:rn(a.name,g),resolvedOverrides:g,unresolved:R}}),[N,M]),A=F(()=>{let a=new Set,g=[];for(let R of L)R.unresolved||a.has(R.key)||(a.add(R.key),g.push({name:R.raw.name,key:R.key,overrides:R.resolvedOverrides??void 0}));return g},[L]),I=F(()=>A.map(a=>`${a.key}|${a.name}|${a.overrides?Object.entries(a.overrides).sort(([g],[R])=>g.localeCompare(R)).map(([g,R])=>`${g}=${R}`).join(","):""}`).join(`
2
+ `),[A]),$=on(()=>{q(a=>a+1)},[]);K(()=>{if(!n||A.length===0)return;let a=A.map(g=>o.udfs.subscribeOutput(g.name,()=>{q(R=>R+1)}));return()=>{a.forEach(g=>g())}},[o,n,A]),K(()=>{w?i():c()},[w,i,c]);let Q=F(()=>{if(!u)return null;for(let a of k){if(a.overrides!==null)continue;let g=u[a.name];if(g?.error)return g.error}return null},[k,u]),d=F(()=>u?k.some(a=>a.overrides===null&&u[a.name]?.loading):!1,[k,u]),f=L.some(a=>a.unresolved);return K(()=>{if(!n||!e){b(""),S(!1),h(null);return}if(Q){b(""),h(Q),S(!1),l(`SQL preprocessing: ${Q}`,"error");return}if(d||f){b(""),h(null),S(!0);return}let a=!1;return S(!0),h(null),(async()=>{let g=new Map,R;if(A.length>0)try{let m=await o.sql.resolveVfsFilenames(A);if(a)return;if(m instanceof Map)for(let P of L){if(P.resolvedOverrides)continue;let G=m.get(P.raw.name);G&&g.set(P.key,G)}else g=m.filenames,R=m.errors}catch(m){if(a)return;let P=m instanceof Error?m.message:typeof m=="string"?m:"VFS registration failed";b(""),h(P),S(!1),l(`SQL preprocessing: ${P}`,"error");return}if(R)for(let m of L){let P=R.get(m.key);if(P){if(a)return;b(""),h(P),S(!1),l(`SQL preprocessing: ${P}`,"error");return}}for(let m of L)if(!(m.unresolved||m.resolvedOverrides===null&&u?.[m.raw.name]!==void 0)&&!g.has(m.key)){if(a)return;b(""),h(null),S(!0);return}let _;try{_=lr(e,L,g,u,M,r)}catch(m){if(a)return;let P=m instanceof Error?m.message:typeof m=="string"?m:"SQL preprocessing failed";b(""),h(P),S(!1),l(`SQL preprocessing failed: ${P}`,"error");return}let Z=Ge(_);if(Z.length===0){if(a)return;b(_),h(null),S(!1),l("SQL preprocessing completed");return}try{let m={},P=await Promise.all(Z.map(le=>o.signUrl(le)));if(a)return;Z.forEach((le,cn)=>{m[le]=P[cn].signed});let G=Ye(_,m);b(G),h(null),S(!1),l("SQL preprocessing completed")}catch(m){if(a)return;let P=m instanceof Error?m.message:typeof m=="string"?m:"URL signing failed";b(""),h(P),S(!1),l(`SQL preprocessing failed: ${P}`,"error")}})(),()=>{a=!0}},[o,n,e,I,L,M,u,Q,d,f,r,E,l,A]),{processedSql:x,loading:w,error:p,refetch:$}}function cr({sql:e,enabled:n=!0,maxRows:r=sn,sourceOverrides:t,queryId:o}){let s=v(),{startLoading:u,stopLoading:i}=ue(),{log:c}=ie(),{queryId:l}=Re(),x=o??l,[b,w]=B(H),[S,p]=B(X),[h,E]=B(!1),[q,k]=B(null),[N,O]=B(0),{processedSql:U,loading:y,error:C,refetch:D}=un({sql:e,enabled:n,maxRows:r,sourceOverrides:t}),T=ur(""),M=n&&!!e&&!!U&&!y&&!C&&U!==T.current,L=y||h||M;K(()=>{L?u():i()},[L,u,i]);let A=on(()=>{T.current="",D(),O(I=>I+1)},[D]);return K(()=>{if(!n||!e){T.current="",w(H),p(X),E(!1),k(null);return}if(C){T.current="",k(C),w(H),p(X),E(!1);return}if(y||!U){T.current="",E(!1);return}let I=!1,$=new AbortController;T.current=U,E(!0),k(null);let Q=U.length>120?U.slice(0,120)+"\u2026":U;c(`SQL query started: ${Q}`);let d=performance.now();return s.sql.query(U,{signal:$.signal,queryId:x}).then(f=>{if(I)return;let a=Math.round(performance.now()-d);if(f.error){w(H),p(X),k(f.error),E(!1),c(`SQL failed (${a}ms): ${f.error}`,"error");return}w(f.rows.length===0?H:f.rows),p(f.columns),k(null),E(!1),c(`SQL completed: ${f.rows.length} row${f.rows.length!==1?"s":""} in ${a}ms`)},f=>{if(I||f?.name==="AbortError")return;let a=Math.round(performance.now()-d),g=f instanceof Error?f.message:typeof f=="string"?f:"SQL query failed";k(g),w(H),p(X),E(!1),c(`SQL failed (${a}ms): ${g}`,"error")}),()=>{I=!0,$.abort()}},[s,n,e,U,y,C,N,c,x]),{rows:b,columns:S,loading:L,error:q,refetch:A}}function dr(e,n=!0){let r=v(),[t,o]=B({filenames:new Map,loading:!1}),s=F(()=>e.slice().sort().join("|"),[e]);return K(()=>{if(!n||e.length===0){o({filenames:new Map,loading:!1});return}let u=!1;return o(i=>({...i,loading:!0,error:void 0})),r.sql.resolveVfsFilenames(e).then(i=>{if(u)return;let c=i instanceof Map?i:i.filenames;o({filenames:c,loading:!1})},i=>{u||o({filenames:new Map,loading:!1,error:i instanceof Error?i.message:String(i)})}),()=>{u=!0}},[r,s,n]),t}import{useCallback as an,useEffect as fr,useState as ae}from"react";var ln=["s3://","gs://","fd://"];function we(e){return ln.some(n=>e.startsWith(n))}function gr(){let e=v();return{signUrl:an(r=>e.signUrl(r),[e])}}function pr(e){let n=v(),{value:r,loading:t}=pe(e),[o,s]=ae(null),[u,i]=ae(null),[c,l]=ae(!1),[x,b]=ae(0);fr(()=>{if(t)return;if(!r){s(null),i(null),l(!1);return}if(!we(r)){s(r),i(null),l(!1);return}let S=!1;return l(!0),i(null),n.signUrl(r).then(({signed:p})=>{S||s(p??r)}).catch(p=>{S||(i(p instanceof Error?p.message:"Failed to load media"),s(null))}).finally(()=>{S||l(!1)}),()=>{S=!0}},[n,t,r,x]);let w=an(async()=>{if(!r||!we(r))return r??null;let{signed:S}=await n.signUrl(r),p=S??r;return s(p),i(null),b(h=>h+1),p},[n,r]);return{src:o,loading:t||c,error:u,refreshSignedUrl:w,resolvedSrc:r,needsSigning:!!(r&&we(r))}}import{useEffect as mr,useState as Sr}from"react";function yr(e,n){let r=v(),[t,o]=Sr({status:"idle"});return mr(()=>{if(!n||!e?.trim()){o({status:"idle"});return}let s=!1;return o({status:"checking"}),r.uploads.checkAccess(e).then(u=>{s||(u.ok?o({status:"allowed"}):o({status:"denied",message:u.message??"Upload access denied."}))}),()=>{s=!0}},[r,e,n]),t}function Rr(){return j()}function vr(e){if(!e)return{};let n={};for(let r of e.split(";")){let t=r.indexOf(":");if(t===-1)continue;let o=r.slice(0,t).trim(),s=r.slice(t+1).trim();if(!o||!s)continue;let u=o.replace(/-([a-z])/g,(i,c)=>c.toUpperCase());n[u]=s}return n}export{Fe as FormContext,Pe as FusedWidgetBridgeContext,ye as JsonUiBindingContext,Ee as JsonUiNodeOverrideContext,xr as PARAMETER_BROADCAST_CHANNEL,ce as ParameterMessageType,Ue as SIGNABLE_URL_LITERAL_REGEX,ln as SIGNED_URL_SCHEMES,he as SQL_PARAM_REGEX,ze as SQL_SOURCE_PLACEHOLDER_REGEX,xe as SqlSourceOverrideContext,ir as canonicalOverrideKey,rn as computePlaceholderKey,Cr as createFormParamsStore,yn as defineCatalog,Sn as defineComponent,tr as escapeSqlValue,Ge as extractSignableUrls,Ke as extractSqlParams,en as getDollarRefName,br as isStandardMessage,oe as isUdfQuery,sr as parseOverridesString,Ze as parseSqlUdfPlaceholders,vr as parseStyle,me as parseUdfColumnQuery,nn as resolveOverrideValue,Ye as rewriteSignedUrls,He as substituteSqlParams,Pn as useAllowedSources,Ln as useAllowedUdfNames,Y as useCanvasParams,cr as useDuckDbSqlQuery,un as useDuckDbSqlQueryPreprocessing,de as useFormContext,W as useFormParams,fe as useFusedParam,bn as useFusedParamWithForm,v as useFusedWidgetBridge,Re as useJsonUiBinding,ue as useJsonUiEdgeAnimation,ie as useJsonUiLog,Xn as useJsonUiLogClear,Yn as useJsonUiLogs,j as useJsonUiNode,Rr as useJsonUiUdfInfo,pr as useMediaSrc,pe as useParamSubstitution,$e as useRequestUdfReexecute,be as useSqlSourceOverrides,zn as useUdfColumnValue,Wn as useUdfColumnValues,Se as useUdfDataFrameSample,Ve as useUdfOutputByName,yr as useUploadAccessCheck,gr as useUrlSigning,dr as useVfsRegistration};
@@ -5,7 +5,7 @@ import type { CatalogComponentDefinition } from "./define-component";
5
5
  * export default defineCatalog({
6
6
  * components: { "kebab-key": defineComponent({...}), ... },
7
7
  * skill, // string imported from "../SKILL.md" (esbuild text loader)
8
- * summary, // ≤120-char headline; REQUIRED when skill is present
8
+ * summary, // ≤240-char headline; REQUIRED when skill is present
9
9
  * });
10
10
  *
11
11
  * `skill` and `summary` are co-required at the **type level** via function
@@ -36,9 +36,11 @@ export interface CatalogDefinitionWithSkill extends CatalogDefinitionBase {
36
36
  */
37
37
  skill: string;
38
38
  /**
39
- * ≤120-char headline shown in the system prompt's
39
+ * ≤240-char headline shown in the system prompt's
40
40
  * `<available_catalog_skills>` block so the AI can decide whether the
41
- * catalog is relevant before fetching the full skill.
41
+ * catalog is relevant before fetching the full skill. A longer summary is
42
+ * truncated to 240 chars by the workbench loader (with a console warning)
43
+ * rather than failing the catalog load.
42
44
  */
43
45
  summary: string;
44
46
  }
@@ -0,0 +1,7 @@
1
+ export interface JsonUiBinding {
2
+ /** Resolver-stamped query id for this node (e.g. `"q0"`); undefined elsewhere. */
3
+ queryId?: string;
4
+ }
5
+ export declare const JsonUiBindingContext: import("react").Context<JsonUiBinding>;
6
+ /** Read the current node's data-binding identity. `{}` when no provider is present. */
7
+ export declare function useJsonUiBinding(): JsonUiBinding;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsonUiBindingContext = void 0;
4
+ exports.useJsonUiBinding = useJsonUiBinding;
5
+ /**
6
+ * JsonUiBindingContext — per-node data-binding identity (chunk-2 MCP-host seam).
7
+ *
8
+ * When a host resolves a widget's data server-side (the MCP Apps renderer), it
9
+ * stamps a deterministic `_queryId` into each data-bound node's props and wraps
10
+ * that node's renderer in a `<JsonUiBindingContext.Provider value={{queryId}}>`.
11
+ * SDK data hooks (currently `useDuckDbSqlQuery`) read the id via
12
+ * `useJsonUiBinding()` and thread it into `bridge.sql.query(sql, { queryId })`,
13
+ * letting the static MCP bridge look up the pre-resolved rows by id instead of
14
+ * running DuckDB in the sandbox.
15
+ *
16
+ * The default value is `{}` (no binding). In every other host (workbench, test
17
+ * harness, mobile) the provider is absent, `queryId` is `undefined`, and the
18
+ * hooks behave exactly as before — so this seam is fully backward-compatible and
19
+ * data-bound components never need editing.
20
+ */
21
+ const react_1 = require("react");
22
+ exports.JsonUiBindingContext = (0, react_1.createContext)({});
23
+ exports.JsonUiBindingContext.displayName = "JsonUiBindingContext";
24
+ /** Read the current node's data-binding identity. `{}` when no provider is present. */
25
+ function useJsonUiBinding() {
26
+ return (0, react_1.useContext)(exports.JsonUiBindingContext);
27
+ }
@@ -0,0 +1,16 @@
1
+ export interface SqlSourceOverride {
2
+ /** In-memory DuckDB relation name to substitute for the `{{name}}` placeholder. */
3
+ relationName: string;
4
+ /** Error from materializing the source, if any. */
5
+ error?: string;
6
+ /** True while the source is still materializing. */
7
+ loading?: boolean;
8
+ }
9
+ export type SqlSourceOverrideMap = Record<string, SqlSourceOverride>;
10
+ /**
11
+ * Provided by hosts that expose named in-memory SQL sources to descendant
12
+ * widgets. Defaults to empty — most hosts and most subtrees have no overrides.
13
+ */
14
+ export declare const SqlSourceOverrideContext: import("react").Context<SqlSourceOverrideMap>;
15
+ /** Read the ancestor-provided SQL source overrides (empty map when none). */
16
+ export declare function useSqlSourceOverrides(): SqlSourceOverrideMap;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SqlSourceOverrideContext = void 0;
4
+ exports.useSqlSourceOverrides = useSqlSourceOverrides;
5
+ /**
6
+ * Host-provided SQL source overrides.
7
+ *
8
+ * Lets a host replace `{{name}}` SQL placeholders with an in-memory DuckDB
9
+ * relation instead of the UDF's VFS Parquet file. The Fused workbench's
10
+ * `sql-runner` component provides these for its descendant json-ui widgets
11
+ * (so a chart/metric/text nested under a sql-runner reads its in-memory tab);
12
+ * other hosts (MCP, test harness) leave it empty.
13
+ *
14
+ * The SDK SQL hooks (`useDuckDbSqlQuery` / `useDuckDbSqlQueryPreprocessing`)
15
+ * read this context automatically and merge it with any explicit
16
+ * `sourceOverrides` option, so component authors never thread it manually.
17
+ */
18
+ const react_1 = require("react");
19
+ const EMPTY_OVERRIDES = Object.freeze({});
20
+ /**
21
+ * Provided by hosts that expose named in-memory SQL sources to descendant
22
+ * widgets. Defaults to empty — most hosts and most subtrees have no overrides.
23
+ */
24
+ exports.SqlSourceOverrideContext = (0, react_1.createContext)(EMPTY_OVERRIDES);
25
+ exports.SqlSourceOverrideContext.displayName = "SqlSourceOverrideContext";
26
+ /** Read the ancestor-provided SQL source overrides (empty map when none). */
27
+ function useSqlSourceOverrides() {
28
+ return (0, react_1.useContext)(exports.SqlSourceOverrideContext);
29
+ }
@@ -24,6 +24,12 @@ export interface UseDuckDbSqlQueryOptions {
24
24
  }>;
25
25
  /** @deprecated Use `maxRows` — kept temporarily for the SDK's existing surface. */
26
26
  defaultLimit?: number;
27
+ /**
28
+ * Binding identity for server-resolved data (MCP-host seam). When omitted,
29
+ * the hook falls back to `useJsonUiBinding()`. Threaded into
30
+ * `bridge.sql.query(sql, { queryId })`; the workbench bridge ignores it.
31
+ */
32
+ queryId?: string;
27
33
  }
28
34
  export interface UseDuckDbSqlQueryResult {
29
35
  rows: ReadonlyArray<Record<string, unknown>>;
@@ -43,13 +49,13 @@ export interface UseDuckDbSqlQueryPreprocessingResult {
43
49
  * Preprocess SQL: resolve placeholders, register UDFs via the bridge,
44
50
  * substitute params, sign URLs, append LIMIT. Returns the prepared SQL.
45
51
  */
46
- export declare function useDuckDbSqlQueryPreprocessing({ sql, enabled, maxRows, sourceOverrides, }: UseDuckDbSqlQueryOptions): UseDuckDbSqlQueryPreprocessingResult;
52
+ export declare function useDuckDbSqlQueryPreprocessing({ sql, enabled, maxRows, sourceOverrides: explicitSourceOverrides, }: UseDuckDbSqlQueryOptions): UseDuckDbSqlQueryPreprocessingResult;
47
53
  /**
48
54
  * Execute a DuckDB SQL query against UDF Parquet outputs. Uses
49
55
  * `useDuckDbSqlQueryPreprocessing` to prepare the SQL string, then runs
50
56
  * it via the bridge.
51
57
  */
52
- export declare function useDuckDbSqlQuery({ sql, enabled, maxRows, sourceOverrides, }: UseDuckDbSqlQueryOptions): UseDuckDbSqlQueryResult;
58
+ export declare function useDuckDbSqlQuery({ sql, enabled, maxRows, sourceOverrides, queryId: queryIdOption, }: UseDuckDbSqlQueryOptions): UseDuckDbSqlQueryResult;
53
59
  /**
54
60
  * Resolve UDF names to VFS filenames, registering them in DuckDB if needed.
55
61
  * Exposed for advanced use cases (e.g. building your own query string).
@@ -21,9 +21,11 @@ exports.useVfsRegistration = useVfsRegistration;
21
21
  const react_1 = require("react");
22
22
  const bridge_1 = require("../bridge");
23
23
  const form_1 = require("../form");
24
+ const json_ui_binding_1 = require("./json-ui-binding");
24
25
  const use_json_ui_log_1 = require("./use-json-ui-log");
25
26
  const use_json_ui_edge_animation_1 = require("./use-json-ui-edge-animation");
26
27
  const use_canvas_params_1 = require("./use-canvas-params");
28
+ const sql_source_overrides_1 = require("./sql-source-overrides");
27
29
  const sql_placeholders_1 = require("../utils/sql-placeholders");
28
30
  const DEFAULT_MAX_ROWS = 500;
29
31
  const EMPTY_ROWS = Object.freeze([]);
@@ -74,8 +76,22 @@ function buildProcessedSql(sql, resolved, fileNameMap, sourceOverrides, sqlParam
74
76
  * Preprocess SQL: resolve placeholders, register UDFs via the bridge,
75
77
  * substitute params, sign URLs, append LIMIT. Returns the prepared SQL.
76
78
  */
77
- function useDuckDbSqlQueryPreprocessing({ sql, enabled = true, maxRows = DEFAULT_MAX_ROWS, sourceOverrides, }) {
79
+ function useDuckDbSqlQueryPreprocessing({ sql, enabled = true, maxRows = DEFAULT_MAX_ROWS, sourceOverrides: explicitSourceOverrides, }) {
78
80
  const bridge = (0, bridge_1.useFusedWidgetBridge)();
81
+ // Auto-detect host-provided source overrides (e.g. the workbench's
82
+ // sql-runner exposes in-memory relations to descendants) and merge them with
83
+ // any explicit option. Explicit overrides win on key collision. Component
84
+ // authors never thread this manually.
85
+ const contextSourceOverrides = (0, sql_source_overrides_1.useSqlSourceOverrides)();
86
+ const sourceOverrides = (0, react_1.useMemo)(() => {
87
+ const hasContext = Object.keys(contextSourceOverrides).length > 0;
88
+ if (!explicitSourceOverrides) {
89
+ return hasContext ? contextSourceOverrides : undefined;
90
+ }
91
+ if (!hasContext)
92
+ return explicitSourceOverrides;
93
+ return { ...contextSourceOverrides, ...explicitSourceOverrides };
94
+ }, [contextSourceOverrides, explicitSourceOverrides]);
79
95
  const { startLoading: startEdgeLoading, stopLoading: stopEdgeLoading } = (0, use_json_ui_edge_animation_1.useJsonUiEdgeAnimation)();
80
96
  const { log } = (0, use_json_ui_log_1.useJsonUiLog)();
81
97
  const [processedSql, setProcessedSql] = (0, react_1.useState)("");
@@ -407,10 +423,15 @@ function useDuckDbSqlQueryPreprocessing({ sql, enabled = true, maxRows = DEFAULT
407
423
  * `useDuckDbSqlQueryPreprocessing` to prepare the SQL string, then runs
408
424
  * it via the bridge.
409
425
  */
410
- function useDuckDbSqlQuery({ sql, enabled = true, maxRows = DEFAULT_MAX_ROWS, sourceOverrides, }) {
426
+ function useDuckDbSqlQuery({ sql, enabled = true, maxRows = DEFAULT_MAX_ROWS, sourceOverrides, queryId: queryIdOption, }) {
411
427
  const bridge = (0, bridge_1.useFusedWidgetBridge)();
412
428
  const { startLoading: startEdgeLoading, stopLoading: stopEdgeLoading } = (0, use_json_ui_edge_animation_1.useJsonUiEdgeAnimation)();
413
429
  const { log } = (0, use_json_ui_log_1.useJsonUiLog)();
430
+ // Server-resolved data seam: explicit option wins, else fall back to the
431
+ // per-node binding context. `undefined` in every non-MCP host (no behavior
432
+ // change for the workbench).
433
+ const { queryId: queryIdBinding } = (0, json_ui_binding_1.useJsonUiBinding)();
434
+ const queryId = queryIdOption ?? queryIdBinding;
414
435
  const [rows, setRows] = (0, react_1.useState)(EMPTY_ROWS);
415
436
  const [columns, setColumns] = (0, react_1.useState)(EMPTY_COLUMNS);
416
437
  const [queryLoading, setQueryLoading] = (0, react_1.useState)(false);
@@ -475,7 +496,7 @@ function useDuckDbSqlQuery({ sql, enabled = true, maxRows = DEFAULT_MAX_ROWS, so
475
496
  : processedSql;
476
497
  log(`SQL query started: ${truncatedSql}`);
477
498
  const t0 = performance.now();
478
- bridge.sql.query(processedSql, { signal: controller.signal }).then((result) => {
499
+ bridge.sql.query(processedSql, { signal: controller.signal, queryId }).then((result) => {
479
500
  if (cancelled)
480
501
  return;
481
502
  const elapsed = Math.round(performance.now() - t0);
@@ -522,6 +543,7 @@ function useDuckDbSqlQuery({ sql, enabled = true, maxRows = DEFAULT_MAX_ROWS, so
522
543
  preprocessingError,
523
544
  fetchKey,
524
545
  log,
546
+ queryId,
525
547
  ]);
526
548
  return { rows, columns, loading, error, refetch };
527
549
  }
@@ -0,0 +1,18 @@
1
+ import type { UseFusedParamOptions, UseFusedParamReturn } from "../types";
2
+ /**
3
+ * Form-aware variant of {@link useFusedParam}.
4
+ *
5
+ * When the component is rendered inside a built-in Form, the field becomes
6
+ * local state (its value is NOT broadcast to the canvas) and its live value is
7
+ * mirrored into the form's subscription store, so sibling components (a
8
+ * dropdown's SQL options, a chart, a text binding, …) can react to it before
9
+ * the form is submitted. Outside a form it behaves exactly like
10
+ * `useFusedParam` — two-way canvas binding with debounced broadcast.
11
+ *
12
+ * Requires a `FusedWidgetBridgeContext` ancestor (like `useFusedParam`) and a
13
+ * `FormContext` ancestor for the in-form behavior (the built-in Form component
14
+ * provides one).
15
+ */
16
+ export declare function useFusedParamWithForm<T extends string | number>(options: UseFusedParamOptions<T>): UseFusedParamReturn<T> & {
17
+ isInForm: boolean;
18
+ };
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useFusedParamWithForm = useFusedParamWithForm;
4
+ const react_1 = require("react");
5
+ const form_1 = require("../form");
6
+ const use_fused_param_1 = require("./use-fused-param");
7
+ /**
8
+ * Form-aware variant of {@link useFusedParam}.
9
+ *
10
+ * When the component is rendered inside a built-in Form, the field becomes
11
+ * local state (its value is NOT broadcast to the canvas) and its live value is
12
+ * mirrored into the form's subscription store, so sibling components (a
13
+ * dropdown's SQL options, a chart, a text binding, …) can react to it before
14
+ * the form is submitted. Outside a form it behaves exactly like
15
+ * `useFusedParam` — two-way canvas binding with debounced broadcast.
16
+ *
17
+ * Requires a `FusedWidgetBridgeContext` ancestor (like `useFusedParam`) and a
18
+ * `FormContext` ancestor for the in-form behavior (the built-in Form component
19
+ * provides one).
20
+ */
21
+ function useFusedParamWithForm(options) {
22
+ const formContext = (0, form_1.useFormContext)();
23
+ const param = options.param;
24
+ const isFormField = Boolean(formContext.isInForm && param);
25
+ // Hook handles both cases: with param (canvas sync) or without (local state).
26
+ // Disable canvas messaging when inside a form by withholding the param.
27
+ const { value, setValue, broadcastNow, clearValue } = (0, use_fused_param_1.useFusedParam)({
28
+ ...options,
29
+ param: isFormField ? undefined : options.param,
30
+ });
31
+ // Mirror the live value into the form's subscription store so sibling
32
+ // components can react to it. Value updates use a dedicated effect so we
33
+ // don't briefly remove the field from the store between renders —
34
+ // unregistration runs only when the binding (store/param) actually changes
35
+ // or on unmount.
36
+ const store = formContext.store;
37
+ (0, react_1.useEffect)(() => {
38
+ if (!isFormField || !param || !store)
39
+ return;
40
+ store.setField(param, value);
41
+ }, [value, isFormField, param, store]);
42
+ (0, react_1.useEffect)(() => {
43
+ if (!isFormField || !param || !store)
44
+ return;
45
+ return () => {
46
+ store.removeField(param);
47
+ };
48
+ }, [isFormField, param, store]);
49
+ return {
50
+ value,
51
+ setValue,
52
+ broadcastNow,
53
+ clearValue,
54
+ isInForm: formContext.isInForm,
55
+ };
56
+ }
package/dist/index.d.ts CHANGED
@@ -21,15 +21,19 @@ export * from "./types";
21
21
  export { defineComponent, type CatalogComponentDefinition, } from "./define-component";
22
22
  export { defineCatalog, type CatalogDefinition, type CatalogDefinitionBase, type CatalogDefinitionWithSkill, } from "./define-catalog";
23
23
  export { useFusedParam } from "./hooks/use-fused-param";
24
+ export { useFusedParamWithForm } from "./hooks/use-fused-param-with-form";
24
25
  export { useCanvasParams } from "./hooks/use-canvas-params";
25
26
  export { useAllowedSources } from "./hooks/use-allowed-sources";
26
27
  export { useAllowedUdfNames } from "./hooks/use-allowed-udf-names";
27
28
  export { useParamSubstitution } from "./hooks/use-param-substitution";
28
29
  export { useUdfOutputByName, useRequestUdfReexecute, useUdfDataFrameSample, useUdfColumnValue, useUdfColumnValues, isUdfQuery, parseUdfColumnQuery, type ParsedUdfQuery, type UseUdfDataFrameSampleOptions, type UseUdfDataFrameSampleResult, type UseUdfColumnValueResult, type UseUdfColumnValuesResult, } from "./hooks/use-udf-output";
29
30
  export { useDuckDbSqlQuery, useDuckDbSqlQueryPreprocessing, useVfsRegistration, type UseDuckDbSqlQueryOptions, type UseDuckDbSqlQueryResult, type UseDuckDbSqlQueryPreprocessingResult, } from "./hooks/use-duckdb-sql";
31
+ export { SqlSourceOverrideContext, useSqlSourceOverrides, type SqlSourceOverride, type SqlSourceOverrideMap, } from "./hooks/sql-source-overrides";
30
32
  export { useUrlSigning, useMediaSrc, SIGNED_URL_SCHEMES, type UseMediaSrcResult, } from "./hooks/use-url-signing";
31
33
  export { useUploadAccessCheck, type UploadAccessState, } from "./hooks/use-upload-access-check";
32
34
  export { useJsonUiLog, useJsonUiLogs, useJsonUiLogClear, } from "./hooks/use-json-ui-log";
33
35
  export { useJsonUiUdfInfo } from "./hooks/use-json-ui-udf-info";
34
36
  export { useJsonUiEdgeAnimation } from "./hooks/use-json-ui-edge-animation";
37
+ export { JsonUiBindingContext, useJsonUiBinding, type JsonUiBinding, } from "./hooks/json-ui-binding";
35
38
  export * from "./utils/sql-placeholders";
39
+ export { parseStyle } from "./utils/parse-style";
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
30
30
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
31
31
  };
32
32
  Object.defineProperty(exports, "__esModule", { value: true });
33
- exports.useJsonUiEdgeAnimation = exports.useJsonUiUdfInfo = exports.useJsonUiLogClear = exports.useJsonUiLogs = exports.useJsonUiLog = exports.useUploadAccessCheck = exports.SIGNED_URL_SCHEMES = exports.useMediaSrc = exports.useUrlSigning = exports.useVfsRegistration = exports.useDuckDbSqlQueryPreprocessing = exports.useDuckDbSqlQuery = exports.parseUdfColumnQuery = exports.isUdfQuery = exports.useUdfColumnValues = exports.useUdfColumnValue = exports.useUdfDataFrameSample = exports.useRequestUdfReexecute = exports.useUdfOutputByName = exports.useParamSubstitution = exports.useAllowedUdfNames = exports.useAllowedSources = exports.useCanvasParams = exports.useFusedParam = exports.defineCatalog = exports.defineComponent = void 0;
33
+ exports.parseStyle = exports.useJsonUiBinding = exports.JsonUiBindingContext = exports.useJsonUiEdgeAnimation = exports.useJsonUiUdfInfo = exports.useJsonUiLogClear = exports.useJsonUiLogs = exports.useJsonUiLog = exports.useUploadAccessCheck = exports.SIGNED_URL_SCHEMES = exports.useMediaSrc = exports.useUrlSigning = exports.useSqlSourceOverrides = exports.SqlSourceOverrideContext = exports.useVfsRegistration = exports.useDuckDbSqlQueryPreprocessing = exports.useDuckDbSqlQuery = exports.parseUdfColumnQuery = exports.isUdfQuery = exports.useUdfColumnValues = exports.useUdfColumnValue = exports.useUdfDataFrameSample = exports.useRequestUdfReexecute = exports.useUdfOutputByName = exports.useParamSubstitution = exports.useAllowedUdfNames = exports.useAllowedSources = exports.useCanvasParams = exports.useFusedParamWithForm = exports.useFusedParam = exports.defineCatalog = exports.defineComponent = void 0;
34
34
  // ── Part 1: Provider contract ────────────────────────────────────────────────
35
35
  __exportStar(require("./protocol"), exports);
36
36
  __exportStar(require("./bridge"), exports);
@@ -45,6 +45,8 @@ Object.defineProperty(exports, "defineCatalog", { enumerable: true, get: functio
45
45
  // ── Part 2: Hooks ────────────────────────────────────────────────────────────
46
46
  var use_fused_param_1 = require("./hooks/use-fused-param");
47
47
  Object.defineProperty(exports, "useFusedParam", { enumerable: true, get: function () { return use_fused_param_1.useFusedParam; } });
48
+ var use_fused_param_with_form_1 = require("./hooks/use-fused-param-with-form");
49
+ Object.defineProperty(exports, "useFusedParamWithForm", { enumerable: true, get: function () { return use_fused_param_with_form_1.useFusedParamWithForm; } });
48
50
  var use_canvas_params_1 = require("./hooks/use-canvas-params");
49
51
  Object.defineProperty(exports, "useCanvasParams", { enumerable: true, get: function () { return use_canvas_params_1.useCanvasParams; } });
50
52
  var use_allowed_sources_1 = require("./hooks/use-allowed-sources");
@@ -65,6 +67,9 @@ var use_duckdb_sql_1 = require("./hooks/use-duckdb-sql");
65
67
  Object.defineProperty(exports, "useDuckDbSqlQuery", { enumerable: true, get: function () { return use_duckdb_sql_1.useDuckDbSqlQuery; } });
66
68
  Object.defineProperty(exports, "useDuckDbSqlQueryPreprocessing", { enumerable: true, get: function () { return use_duckdb_sql_1.useDuckDbSqlQueryPreprocessing; } });
67
69
  Object.defineProperty(exports, "useVfsRegistration", { enumerable: true, get: function () { return use_duckdb_sql_1.useVfsRegistration; } });
70
+ var sql_source_overrides_1 = require("./hooks/sql-source-overrides");
71
+ Object.defineProperty(exports, "SqlSourceOverrideContext", { enumerable: true, get: function () { return sql_source_overrides_1.SqlSourceOverrideContext; } });
72
+ Object.defineProperty(exports, "useSqlSourceOverrides", { enumerable: true, get: function () { return sql_source_overrides_1.useSqlSourceOverrides; } });
68
73
  var use_url_signing_1 = require("./hooks/use-url-signing");
69
74
  Object.defineProperty(exports, "useUrlSigning", { enumerable: true, get: function () { return use_url_signing_1.useUrlSigning; } });
70
75
  Object.defineProperty(exports, "useMediaSrc", { enumerable: true, get: function () { return use_url_signing_1.useMediaSrc; } });
@@ -79,5 +84,10 @@ var use_json_ui_udf_info_1 = require("./hooks/use-json-ui-udf-info");
79
84
  Object.defineProperty(exports, "useJsonUiUdfInfo", { enumerable: true, get: function () { return use_json_ui_udf_info_1.useJsonUiUdfInfo; } });
80
85
  var use_json_ui_edge_animation_1 = require("./hooks/use-json-ui-edge-animation");
81
86
  Object.defineProperty(exports, "useJsonUiEdgeAnimation", { enumerable: true, get: function () { return use_json_ui_edge_animation_1.useJsonUiEdgeAnimation; } });
87
+ var json_ui_binding_1 = require("./hooks/json-ui-binding");
88
+ Object.defineProperty(exports, "JsonUiBindingContext", { enumerable: true, get: function () { return json_ui_binding_1.JsonUiBindingContext; } });
89
+ Object.defineProperty(exports, "useJsonUiBinding", { enumerable: true, get: function () { return json_ui_binding_1.useJsonUiBinding; } });
82
90
  // ── Pure utilities (re-exported for advanced workbench paths) ────────────────
83
91
  __exportStar(require("./utils/sql-placeholders"), exports);
92
+ var parse_style_1 = require("./utils/parse-style");
93
+ Object.defineProperty(exports, "parseStyle", { enumerable: true, get: function () { return parse_style_1.parseStyle; } });
@@ -0,0 +1,9 @@
1
+ import type { CSSProperties } from "react";
2
+ /**
3
+ * Parses a plain CSS string into a React CSSProperties object.
4
+ * e.g. "color: red; font-size: 16px" → { color: "red", fontSize: "16px" }
5
+ *
6
+ * Pure — no bridge, no context. Used by every json-ui component that accepts
7
+ * a `style` string prop, across all hosts (workbench, MCP, test harness).
8
+ */
9
+ export declare function parseStyle(style: string | undefined): CSSProperties;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseStyle = parseStyle;
4
+ /**
5
+ * Parses a plain CSS string into a React CSSProperties object.
6
+ * e.g. "color: red; font-size: 16px" → { color: "red", fontSize: "16px" }
7
+ *
8
+ * Pure — no bridge, no context. Used by every json-ui component that accepts
9
+ * a `style` string prop, across all hosts (workbench, MCP, test harness).
10
+ */
11
+ function parseStyle(style) {
12
+ if (!style)
13
+ return {};
14
+ const result = {};
15
+ for (const declaration of style.split(";")) {
16
+ const colonIdx = declaration.indexOf(":");
17
+ if (colonIdx === -1)
18
+ continue;
19
+ const property = declaration.slice(0, colonIdx).trim();
20
+ const value = declaration.slice(colonIdx + 1).trim();
21
+ if (!property || !value)
22
+ continue;
23
+ const camelCase = property.replace(/-([a-z])/g, (_, l) => l.toUpperCase());
24
+ result[camelCase] = value;
25
+ }
26
+ return result;
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusedio/widget-sdk",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "SDK for building custom json-ui components for the Fused workbench",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",