weifuwu 0.60.0 → 0.61.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/README.md +23 -7
- package/dist/ai/agent.d.ts +29 -1
- package/dist/ai/client.d.ts +15 -0
- package/dist/ai/index.d.ts +2 -1
- package/dist/client/diff.d.ts +15 -0
- package/dist/client/hydration.d.ts +13 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.js +3 -2214
- package/dist/client/middleware/api.d.ts +2 -0
- package/dist/client/motion.d.ts +8 -0
- package/dist/client/registry.d.ts +34 -0
- package/dist/client/render.d.ts +13 -14
- package/dist/client/types.d.ts +28 -0
- package/dist/client/ui.d.ts +56 -0
- package/dist/components/Badge/Badge.d.ts +1 -1
- package/dist/components/Button/Button.d.ts +3 -0
- package/dist/components/Card/Card.d.ts +2 -0
- package/dist/components/Confirm/Confirm.d.ts +8 -1
- package/dist/components/Dropdown/Dropdown.d.ts +2 -0
- package/dist/components/Icon/Icon.d.ts +19 -0
- package/dist/components/Input/Input.d.ts +5 -0
- package/dist/components/Modal/Modal.d.ts +2 -0
- package/dist/components/PageHeader/PageHeader.d.ts +2 -0
- package/dist/components/StatCard/StatCard.d.ts +2 -0
- package/dist/components/Table/Table.d.ts +4 -0
- package/dist/components/Toast/Toast.d.ts +13 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +1 -3381
- package/dist/components/style.css +282 -134
- package/dist/core/router.d.ts +10 -10
- package/dist/core/serve.d.ts +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +523 -11
- package/dist/layout/weifuwu-layout.css +106 -17
- package/dist/messager/index.d.ts +107 -0
- package/dist/types.d.ts +2 -2
- package/dist/user/index.d.ts +3 -2
- package/package.json +1 -1
package/dist/client/index.js
CHANGED
|
@@ -1,2215 +1,4 @@
|
|
|
1
|
-
// src/client/vnode.ts
|
|
2
|
-
var ASYNC_MARK = "__wfAsyncComponent";
|
|
3
|
-
function asyncComponent(factory) {
|
|
4
|
-
const fn = factory;
|
|
5
|
-
fn[ASYNC_MARK] = true;
|
|
6
|
-
return fn;
|
|
7
|
-
}
|
|
8
|
-
function isAsyncComponent(type) {
|
|
9
|
-
return typeof type === "function" && type?.[ASYNC_MARK] === true;
|
|
10
|
-
}
|
|
11
|
-
var Fragment = /* @__PURE__ */ Symbol("Fragment");
|
|
12
|
-
var Portal = /* @__PURE__ */ Symbol("Portal");
|
|
13
|
-
function jsx(type, props, key) {
|
|
14
|
-
return {
|
|
15
|
-
type,
|
|
16
|
-
props: normalizeProps(props),
|
|
17
|
-
key: key ?? void 0
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
var jsxs = jsx;
|
|
21
|
-
function jsxDEV(type, props, key) {
|
|
22
|
-
return jsx(type, props, key);
|
|
23
|
-
}
|
|
24
|
-
function h(type, props, ...children) {
|
|
25
|
-
const p = normalizeProps(props ?? {});
|
|
26
|
-
if (children.length > 0) {
|
|
27
|
-
p.children = children.length === 1 ? children[0] : children;
|
|
28
|
-
}
|
|
29
|
-
return { type, props: p, key: props?.key ?? void 0 };
|
|
30
|
-
}
|
|
31
|
-
function normalizeProps(props) {
|
|
32
|
-
if (!props) return {};
|
|
33
|
-
const result = {};
|
|
34
|
-
for (const key of Object.keys(props)) {
|
|
35
|
-
if (key === "key") continue;
|
|
36
|
-
result[key] = props[key];
|
|
37
|
-
}
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
function createPortal(children, portalKey) {
|
|
41
|
-
return {
|
|
42
|
-
type: Portal,
|
|
43
|
-
props: { children, portalKey },
|
|
44
|
-
key: portalKey ?? void 0,
|
|
45
|
-
_placement: "remote"
|
|
46
|
-
};
|
|
47
|
-
}
|
|
1
|
+
var ge="__wfAsyncComponent";function qe(e){let t=e;return t[ge]=!0,t}function I(e){return typeof e=="function"&&e?.[ge]===!0}var W=Symbol("Fragment"),N=Symbol("Portal");function X(e,t,n){return{type:e,props:he(t),key:n??void 0}}var De=X;function Fe(e,t,n){return X(e,t,n)}function $e(e,t,...n){let o=he(t??{});return n.length>0&&(o.children=n.length===1?n[0]:n),{type:e,props:o,key:t?.key??void 0}}function he(e){if(!e)return{};let t={};for(let n of Object.keys(e))n!=="key"&&(t[n]=e[n]);return t}function Be(e,t){return{type:N,props:{children:e,portalKey:t},key:t??void 0,_placement:"remote"}}var Ke=0,A=new Map,F=[];function Ce(e){F.push(e)}var $=new WeakMap;function j(){$=new WeakMap}function Z(e,t){let n=$.get(e);if(n)return n;let o={promise:null};return o.promise=Promise.resolve().then(()=>e(t)).then(r=>{if(typeof r!="function")throw new Error(`asyncComponent factory <${e.name||"anonymous"}> must return a Component (initProps, ctx) => (props) => VNode.`);return o.resolved=r,r}),$.set(e,o),o}async function xe(e,t){return Z(e,t).promise}function we(e){return $.get(e)?.resolved}function ze(e){let t=e._child;if(t!=null)if(Array.isArray(t))for(let n of t)n&&typeof n=="object"&&_(n);else typeof t=="object"&&_(t)}function _(e){if(e==null||typeof e!="object")return;let t=e;if(t._id){if(t._customId&&A.delete(t._customId),A.delete(t._id),F.length>0){for(let n of F)n(t._id);if(t._customId)for(let n of F)n(t._customId)}t._id=void 0,t._customId=void 0,t._render=void 0,t._parentNode=void 0,t._refNode=void 0}if(t._child!=null){if(Array.isArray(t._child))for(let n of t._child)n&&typeof n=="object"&&_(n);else _(t._child);t._child=void 0}if(t.props?.children&&typeof t.type=="string"){let n=Array.isArray(t.props.children)?t.props.children:[t.props.children];for(let o of n)o&&typeof o=="object"&&_(o)}typeof t.props?.ref=="function"&&t.props.ref(null),t._remoteEl&&(ze(t),t._remoteEl.remove(),t._remoteEl=void 0)}function U(){return`_wf_${Ke++}`}var be=new WeakMap;function Ge(e){let t=be.get(e)??{count:0,warned:!1};t.count++,t.count>=3&&!t.warned&&(t.warned=!0,console.warn("[weifuwu] ref \u51FD\u6570\u6BCF\u6B21\u6E32\u67D3\u90FD\u53D8\u5316\uFF08\u5185\u8054 ref\uFF09\u2014\u2014ref \u56DE\u8C03\u5728\u6BCF\u6B21\u6E32\u67D3\u540E\u91CD\u65B0\u6267\u884C\uFF08\u6027\u80FD\u635F\u8017\uFF09\u3002\u628A ref \u5B9A\u4E49\u5230 mount \u4F5C\u7528\u57DF\uFF08\u7A33\u5B9A\u5F15\u7528\uFF09\uFF1Aconst listRef = (el) => {...}; return h('div', { ref: listRef })")),be.set(e,t)}function M(e,t,n,o,r){if(n==null){if(o==null)return null;let u=S(o,r);return u==null?null:(t&&t.parentNode?t.parentNode.insertBefore(u,t):e.appendChild(u),u)}if(o==null)return t?(_(n),t.remove()):_(n),null;let s=Te(n),i=Te(o);if(s!==i){_(n);let u=S(o,r);return u==null?null:(t?.parentNode&&t.parentNode.replaceChild(u,t),u)}if(i==="text")return t&&t.textContent!==String(o)&&(t.textContent=String(o)),t;let l=o,a=n;if(typeof l.type=="function"){let u=l.type;a._render&&(l._render=a._render,l._id=a._id,l._id&&A.set(l._id,l)),l._parentNode=e,l._refNode=t;let m=Object.create(r);if(m.ui=Object.create(r.ui),m.ui._selfId=l._id,m.ui._selfVNode=l,l._ctxVersion=a._ctxVersion??m.ui._ctxVersion??0,a._render&&Ye(a.props,l.props)&&!m.ui._dirtySet?.has(a._id)&&l._ctxVersion===m.ui._ctxVersion)return l._child=a._child,t;m.ui._dirtySet?.delete(a._id);let y;try{typeof l._render=="function"?y=l._render(l.props):y=ne(u,l.props,l,m)}catch(d){let p=r.ui?._errorHandler;p?(p(d),y=null):(console.error(`[weifuwu] Component render error in <${u?.name||"anonymous"}> (id: ${a._id??"?"}, phase: update)`,d),y=null)}let f=a._child;l._child=y;let c=M(e,t,f,y,m);return c||(l._refNode=null),c}if(l.type===W)return Ae(e,a,l,r),t;if(typeof l.type=="string"){if(t&&t.nodeType===1){let u=a.props?.ref,m=l.props?.ref;u!==m&&(typeof m=="function"&&m(t),typeof u=="function"&&typeof m=="function"&&Ge(t)),te(t,a.props,l.props),Ae(t,a,l,r)}else if(t){_(n);let u=S(o,r);return u==null?null:(t.parentNode?.replaceChild(u,t),u)}return t}if(l.type===N)return q(a,l,r),null;if(Array.isArray(o)){let u=Array.isArray(n)?n:[];return B(u,o),K(e,u,o,r),t}return t}var ve=new Map;function Je(e){let t=ve.get(e);return t||(t=`fn:${e.name||"anon"}`,ve.set(e,t)),t}function Te(e){if(e==null||typeof e=="boolean")return"null";if(typeof e=="string"||typeof e=="number")return"text";if(Array.isArray(e))return"array";let t=e;return typeof t.type=="function"?Je(t.type):t.type===W?"fragment":t.type===N?"portal":typeof t.type=="string"?"tag:"+t.type:"unknown"}function te(e,t,n){let o=t?Object.keys(t).filter(i=>i!=="children"&&i!=="key"&&i!=="innerHTML"):[],r=n?Object.keys(n).filter(i=>i!=="children"&&i!=="key"&&i!=="innerHTML"):[],s=new Set(r);for(let i of o)if(!s.has(i)){if(i==="ref")continue;i.startsWith("on")&&typeof t[i]=="function"?e.removeEventListener(i.slice(2).toLowerCase(),t[i]):i==="value"&&(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement)?e.value="":e.removeAttribute(i==="className"?"class":i)}for(let i of r){if(i==="ref")continue;let l=t?.[i],a=n?.[i];if(i==="innerHTML")a!==l&&(e.innerHTML=String(a??""));else if(a!==l)if(i==="class"||i==="className")e instanceof SVGElement?e.setAttribute("class",_e(a)):e.className=_e(a);else if(i==="style"&&typeof a=="object"){let u=e.style;for(let m of Object.keys(a)){let y=a[m];y!=null&&(u[m]=typeof y=="number"?y+"px":String(y))}}else if(i.startsWith("on")&&typeof a=="function"){let u=i.slice(2).toLowerCase();typeof l=="function"&&e.removeEventListener(u,l),e.addEventListener(u,a)}else i==="value"&&(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement)?e.value=String(a??""):a===!0?e.setAttribute(i,""):a!=null&&a!==!1?e.setAttribute(i,String(a)):i==="value"&&(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement)?e.value="":e.removeAttribute(i)}}function _e(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(Boolean).join(" "):e&&typeof e=="object"?Object.entries(e).filter(([,t])=>t).map(([t])=>t).join(" "):""}function ee(e){if(!(e==null||typeof e!="object"))return e.key}function B(e,t){if(!t.some(o=>o&&typeof o=="object"&&o.key!==void 0)){for(let o=0;o<t.length;o++){let r=t[o];r&&typeof r=="object"&&(r.key=o)}for(let o=0;o<e.length;o++){let r=e[o];r&&typeof r=="object"&&(r.key=o)}}}function Ae(e,t,n,o){let r=H(t.props?.children),s=H(n.props?.children);B(r,s),K(e,r,s,o)}function H(e){if(e==null)return[];if(!Array.isArray(e))return[e];let t=[];for(let n of e)Array.isArray(n)?t.push(...n):t.push(n);return t}function K(e,t,n,o){if(!n.some(f=>f&&typeof f=="object"&&f.key!==void 0)){let f=Math.max(t.length,n.length);for(let c=0;c<f;c++){let d=c<t.length?t[c]:null,p=c<n.length?n[c]:null;if(p==null){if(d!=null){_(d);let g=e.childNodes[c];g&&g.remove()}}else if(d==null){let g=S(p,o);g!=null&&e.appendChild(g)}else{let g=e.childNodes[c]||null;M(e,g,d,p,o)}}return}let s=0;for(let f=0;f<t.length;f++){let c=t[f];if(c==null||typeof c=="boolean")continue;if(ee(c)===void 0){let p=e.childNodes[s];p&&p.remove()}else c&&typeof c=="object"&&c._placement==="remote"||s++}let i=new Map,l=0;for(let f=0;f<t.length;f++){let c=ee(t[f]);if(c!==void 0){let d=t[f],p=d&&typeof d=="object"&&d._placement==="remote";i.set(c,{vnode:d,node:p?null:e.childNodes[l]||null,remote:!!p,index:l}),p||l++}}let a=n.map(f=>ee(f)),u=new Set(a);for(let f of i.keys())if(!u.has(f)){let c=i.get(f);_(c.vnode),c.node&&c.node?.remove(),i.delete(f)}let m=-1,y=e.firstChild;for(let f=0;f<n.length;f++){let c=a[f],d=n[f],p=c!==void 0?i.get(c):void 0,g=d&&typeof d=="object"&&d._placement==="remote";if(p)if(p.node)p.index<m&&e.insertBefore(p.node,y),m=Math.max(m,p.index),M(e,p.node,p.vnode,d,o),y=(p.node.parentNode===e?p.node:e.firstChild)?.nextSibling??null;else if(p.remote)q(p.vnode,d,o);else{let h=M(e,null,p.vnode,d,o);h!=null&&(e.insertBefore(h,y),y=h.nextSibling)}else if(g)V(d,o);else{let h=S(d,o);h!=null&&(e.insertBefore(h,y),y=h.nextSibling)}}}function Qe(e,t){if(e===t)return!0;if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}return e===t}function Ye(e,t){if(e===t)return!0;if(!e||!t)return!1;let n=new Set([...Object.keys(e),...Object.keys(t)]);for(let o of n)if(o!=="key"){if(o==="children"){if(!Qe(e[o],t[o]))return!1}else if(e[o]!==t[o])return!1}return!0}var oe="http://www.w3.org/2000/svg",re=new Set(["svg","path","circle","line","rect","text","g","polyline","polygon","ellipse","defs","use","clipPath","mask","linearGradient","radialGradient","stop","tspan"]);function Re(e,t){return S(e,t)}function S(e,t){if(e==null||typeof e=="boolean")return null;if(typeof e=="string"||typeof e=="number")return document.createTextNode(String(e));if(Array.isArray(e))return et(e,t);let n=e;if(n.type===N)return V(n,t),null;if(n.type===W){let i=document.createDocumentFragment(),l=n.props?.children==null?[]:Array.isArray(n.props.children)?n.props.children:[n.props.children];for(let a of l){let u=S(a,t);u!=null&&i.appendChild(u)}return i}if(typeof n.type=="function")return Ze(n.type,n.props,n,t);let o=n.type,r=re.has(o)?document.createElementNS(oe,o):document.createElement(o);n.el=r;let s;for(let[i,l]of Object.entries(n.props??{}))i==="children"||i==="key"||i==="value"||i==="innerHTML"||ke(r,i,l);if("value"in(n.props??{})&&r instanceof HTMLSelectElement?s=n.props.value:"value"in(n.props??{})&&ke(r,"value",n.props.value),"innerHTML"in(n.props??{}))r.innerHTML=String(n.props.innerHTML??"");else{let i=se(n.props?.children);for(let l of i){let a=S(l,t);if(a!=null&&(r.appendChild(a),l&&typeof l=="object"&&typeof l.type=="function")){let u=l;u._parentNode||(u._parentNode=r,u._refNode=a)}}}return s!==void 0&&(r.value=String(s)),typeof n.props?.ref=="function"&&n.props.ref(r),r}function Xe(e){let t=e.ui;t&&typeof t.render=="function"&&t.render(["_wf_root"])}function ne(e,t,n,o){let r;if(I(e)){if(r=we(e),!r)return Z(e,o).promise.then(()=>Xe(o),()=>{}),null}else r=e;let s=r(t,o);if(typeof s!="function")throw new Error(`Component ${e.name||"anonymous"} must return a render function. Use (init_props, ctx) => (props) => VNode pattern.`);return n._render=s,s(t)}function Ze(e,t,n,o){o.ui=o.ui??{},n._id||(n._id=U(),A.set(n._id,n));let r=Object.create(o);r.ui=Object.create(o.ui),r.ui._selfId=n._id,r.ui._selfVNode=n,n._ctxVersion=r.ui._ctxVersion??0;let s;try{s=ne(e,t,n,r)}catch(l){let a=o.ui?._errorHandler;a?(a(l),s=null):(console.error(`[weifuwu] Component render error in <${e.name||"anonymous"}> (id: ${n._id??"?"}, phase: mount)`,l),s=null)}if(s==null)return n._child=null,null;n._child=s;let i=S(s,r);return n._refNode||(n._refNode=i),i}function et(e,t){let n=document.createDocumentFragment();for(let o of e){let r=S(o,t);r!=null&&n.appendChild(r)}return n}function tt(){let e=document.getElementById("__wf_portal");return e||(e=document.createElement("div"),e.id="__wf_portal",e.style.cssText="position:fixed;inset:0;pointer-events:none;z-index:9999",document.body.appendChild(e)),e}function V(e,t){let n=tt(),o=document.createElement("div");o.style.pointerEvents="auto",n.appendChild(o),e._remoteEl=o;let r=H(e.props?.children);e._child=r;for(let s of r){let i=S(s,t);i!=null&&o.appendChild(i)}}function q(e,t,n){let o=e?._remoteEl;if(t._remoteEl=o,!o){V(t,n);return}let r=H(t.props?.children),s=e._child||[];t._child=r,B(s,r),K(o,s,r,n)}function se(e){if(e==null)return[];if(!Array.isArray(e))return[e];let t=[];for(let n of e)Array.isArray(n)?t.push(...n):t.push(n);return t}function ke(e,t,n){if(t==="class"||t==="className")e instanceof SVGElement?e.setAttribute("class",String(n??"")):e.className=String(n??"");else if(t==="style"&&typeof n=="object"&&n!==null){let o=e.style;for(let r of Object.keys(n)){let s=n[r];s!=null&&(o[r]=typeof s=="number"?s+"px":String(s))}}else t.startsWith("on")&&typeof n=="function"?e.addEventListener(t.slice(2).toLowerCase(),n):t==="value"&&(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement)?e.value=String(n??""):n===!0?e.setAttribute(t,""):n!=null&&n!==!1&&e.setAttribute(t,String(n))}function nt(e,t,n){e.innerHTML="";let o=S(t,n);o instanceof Node?e.appendChild(o):Array.isArray(o)&&o.forEach(r=>e.appendChild(r))}function ie(e){e.node=e.node?e.node.nextSibling:null}function ot(e,t){e.node&&e.node.parentNode?e.node.parentNode.insertBefore(t,e.node):e.parent.appendChild(t)}function rt(e,t){e.node&&e.node.parentNode?(e.node.parentNode.replaceChild(t,e.node),ie(e)):e.parent.appendChild(t)}async function D(e,t,n){if(e==null||typeof e=="boolean")return null;if(typeof e=="string"||typeof e=="number"){let l=String(e);if(n.node&&n.node.nodeType===3)return n.node.textContent!==l&&(n.node.textContent=l),ie(n),n.node;let a=document.createTextNode(l);return ot(n,a),a}if(Array.isArray(e)){let l=null;for(let a of e){let u=await D(a,t,n);u!=null&&!l&&(l=u)}return l}let o=e;if(o.type===N||o.type===W){let l=o.props?.children,a=l==null?[]:Array.isArray(l)?l:[l],u=null;for(let m of a){let y=await D(m,t,n);y!=null&&!u&&(u=y)}return u}if(typeof o.type=="function")return st(o,t,n);let r=o.type,s=o.props??{},i;if(n.node&&n.node.nodeType===1&&n.node.tagName.toLowerCase()===r.toLowerCase()?(i=n.node,ie(n)):(i=re.has(r)?document.createElementNS(oe,r):document.createElement(r),rt(n,i)),o.el=i,te(i,null,s),!("innerHTML"in s)){let l={parent:i,node:i.firstChild},a=se(s.children);for(let u of a){let m=await D(u,t,l);if(m!=null&&m.parentNode!==i&&i.appendChild(m),u&&typeof u=="object"&&typeof u.type=="function"){let y=u;y._parentNode||(y._parentNode=i,y._refNode=m)}}for(;l.node;){let u=l.node;l.node=u.nextSibling,u.parentNode?.removeChild(u)}}return"value"in s&&i instanceof HTMLSelectElement&&(i.value=String(s.value??"")),typeof s.ref=="function"&&s.ref(i),i}async function st(e,t,n){t.ui=t.ui??{},e._id||(e._id=U(),A.set(e._id,e));let o=Object.create(t);o.ui=Object.create(t.ui),o.ui._selfId=e._id,o.ui._selfVNode=e,e._ctxVersion=o.ui._ctxVersion??0;let r=e.type,s;try{let l;I(r)?l=await xe(r,o):l=r;let a=l(e.props??{},o);if(typeof a!="function")throw new Error(`Component ${r.name||"anonymous"} must return a render function. Use (init_props, ctx) => (props) => VNode pattern.`);e._render=a,s=a(e.props??{})}catch(l){let a=t.ui?._errorHandler;a?(a(l),s=null):(console.error(`[weifuwu] Component hydration error in <${r.name||"anonymous"}> (id: ${e._id??"?"})`,l),s=null)}if(s==null)return e._child=null,null;e._child=s;let i=await D(s,o,n);return e._refNode||(e._refNode=i),i}async function ae(e,t,n){let o={parent:e,node:e.firstChild};for(await D(t,n,o);o.node;){let r=o.node;o.node=r.nextSibling,r.parentNode?.removeChild(r)}}function le(e){let t=new WeakMap,n=new Set,o=s=>{if(s===null||typeof s!="object")return s;if(t.has(s))return t.get(s);let i=new Proxy(s,{set(l,a,u){if(Reflect.get(l,a)===u)return!0;Reflect.set(l,a,u),e();for(let y of n)y();return!0},get(l,a){let u=Reflect.get(l,a);return typeof u=="object"&&u!==null?o(u):u},deleteProperty(l,a){if(Reflect.has(l,a)){Reflect.deleteProperty(l,a),e();for(let u of n)u()}return!0}});return t.set(s,i),i},r=o({});return Object.defineProperty(r,"__watch",{value:s=>(n.add(s),()=>{n.delete(s)}),writable:!1,enumerable:!1}),r}function ue(e,t,n){let o=new AbortController,r=n?.signal;r&&(r.aborted?o.abort():r.addEventListener("abort",()=>o.abort(),{once:!0}));let s=n?.traceId??ct(),i=n?.record!==!1,l=[],a=(async()=>{let u;try{u=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json","X-Trace-Id":s,Accept:"text/event-stream",...n?.headers},body:JSON.stringify(t),signal:o.signal})}catch(m){if(o.signal.aborted)return;n?.onError?.({code:"provider_error",message:m instanceof Error?m.message:String(m)});return}if(!u.ok){n?.onError?.({code:ut(u.status),message:`HTTP ${u.status} ${u.statusText}`});return}try{for await(let{name:m,data:y}of at(u.body)){if(o.signal.aborted)return;lt(l,{name:m,data:y},i),it(m,y,n??{})}}catch(m){if(o.signal.aborted)return;n?.onError?.({code:"provider_error",message:m instanceof Error?m.message:String(m)})}})();return{abort:()=>o.abort(),done:a,traceId:s,events:l}}function it(e,t,n){switch(e){case"wf:token":return n.onToken?.(t.text);case"wf:tool_call":return n.onToolCall?.(t);case"wf:tool_result":return n.onToolResult?.(t);case"wf:tool_progress":return n.onToolProgress?.(t);case"wf:step":return n.onStep?.(t);case"wf:approval_request":return n.onApproval?.(t);case"wf:usage":return n.onUsage?.(t);case"wf:done":return n.onDone?.(t);case"wf:error":return n.onError?.(t);default:return n.onEvent?.(e,t)}}async function*at(e){let t=e.getReader(),n=new TextDecoder,o="";try{for(;;){let{done:r,value:s}=await t.read();if(r)break;o+=n.decode(s,{stream:!0});let i=o.split(`
|
|
48
2
|
|
|
49
|
-
|
|
50
|
-
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
51
|
-
var SVG_TAGS = /* @__PURE__ */ new Set(["svg", "path", "circle", "line", "rect", "text", "g", "polyline", "polygon", "ellipse", "defs", "use", "clipPath", "mask", "linearGradient", "radialGradient", "stop", "tspan"]);
|
|
52
|
-
var _idCounter = 0;
|
|
53
|
-
var idRegistry = /* @__PURE__ */ new Map();
|
|
54
|
-
function render(input, ctx) {
|
|
55
|
-
return renderValue(input, ctx);
|
|
56
|
-
}
|
|
57
|
-
function renderValue(v, ctx) {
|
|
58
|
-
if (v == null || typeof v === "boolean") return null;
|
|
59
|
-
if (typeof v === "string" || typeof v === "number") return document.createTextNode(String(v));
|
|
60
|
-
if (Array.isArray(v)) return renderArray(v, ctx);
|
|
61
|
-
const vnode = v;
|
|
62
|
-
if (vnode.type === Portal) {
|
|
63
|
-
renderPortal(vnode, ctx);
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
if (vnode.type === Fragment) {
|
|
67
|
-
const frag = document.createDocumentFragment();
|
|
68
|
-
const children = vnode.props?.children == null ? [] : Array.isArray(vnode.props.children) ? vnode.props.children : [vnode.props.children];
|
|
69
|
-
for (const child of children) {
|
|
70
|
-
const node = renderValue(child, ctx);
|
|
71
|
-
if (node != null) frag.appendChild(node);
|
|
72
|
-
}
|
|
73
|
-
return frag;
|
|
74
|
-
}
|
|
75
|
-
if (typeof vnode.type === "function") {
|
|
76
|
-
return renderComponent(vnode.type, vnode.props, vnode, ctx);
|
|
77
|
-
}
|
|
78
|
-
const tag = vnode.type;
|
|
79
|
-
const el = SVG_TAGS.has(tag) ? document.createElementNS(SVG_NS, tag) : document.createElement(tag);
|
|
80
|
-
vnode.el = el;
|
|
81
|
-
let selectValue;
|
|
82
|
-
for (const [key, value] of Object.entries(vnode.props ?? {})) {
|
|
83
|
-
if (key === "children" || key === "key" || key === "value" || key === "innerHTML") continue;
|
|
84
|
-
setProp(el, key, value);
|
|
85
|
-
}
|
|
86
|
-
if ("value" in (vnode.props ?? {}) && el instanceof HTMLSelectElement) {
|
|
87
|
-
selectValue = vnode.props.value;
|
|
88
|
-
} else if ("value" in (vnode.props ?? {})) {
|
|
89
|
-
setProp(el, "value", vnode.props.value);
|
|
90
|
-
}
|
|
91
|
-
if ("innerHTML" in (vnode.props ?? {})) {
|
|
92
|
-
el.innerHTML = String(vnode.props.innerHTML ?? "");
|
|
93
|
-
} else {
|
|
94
|
-
const flatChildren = flattenChildren(vnode.props?.children);
|
|
95
|
-
for (const child of flatChildren) {
|
|
96
|
-
const childNode = renderValue(child, ctx);
|
|
97
|
-
if (childNode == null) continue;
|
|
98
|
-
el.appendChild(childNode);
|
|
99
|
-
if (child && typeof child === "object" && typeof child.type === "function") {
|
|
100
|
-
const childVNode = child;
|
|
101
|
-
if (!childVNode._parentNode) {
|
|
102
|
-
childVNode._parentNode = el;
|
|
103
|
-
childVNode._refNode = childNode;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (selectValue !== void 0) {
|
|
109
|
-
;
|
|
110
|
-
el.value = String(selectValue);
|
|
111
|
-
}
|
|
112
|
-
if (typeof vnode.props?.ref === "function") vnode.props.ref(el);
|
|
113
|
-
return el;
|
|
114
|
-
}
|
|
115
|
-
var asyncFactoryCache = /* @__PURE__ */ new WeakMap();
|
|
116
|
-
function clearAsyncComponentCache() {
|
|
117
|
-
asyncFactoryCache = /* @__PURE__ */ new WeakMap();
|
|
118
|
-
}
|
|
119
|
-
function startAsyncFactory(Comp, ctx) {
|
|
120
|
-
const existing = asyncFactoryCache.get(Comp);
|
|
121
|
-
if (existing) return existing;
|
|
122
|
-
const entry = { promise: null };
|
|
123
|
-
entry.promise = Promise.resolve().then(() => Comp(ctx)).then((def) => {
|
|
124
|
-
if (typeof def !== "function") {
|
|
125
|
-
throw new Error(
|
|
126
|
-
`asyncComponent factory <${Comp.name || "anonymous"}> must return a Component (initProps, ctx) => (props) => VNode.`
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
entry.resolved = def;
|
|
130
|
-
return def;
|
|
131
|
-
});
|
|
132
|
-
asyncFactoryCache.set(Comp, entry);
|
|
133
|
-
return entry;
|
|
134
|
-
}
|
|
135
|
-
async function resolveAsyncFactory(Comp, ctx) {
|
|
136
|
-
return startAsyncFactory(Comp, ctx).promise;
|
|
137
|
-
}
|
|
138
|
-
function resolveAsyncFactorySync(Comp) {
|
|
139
|
-
return asyncFactoryCache.get(Comp)?.resolved;
|
|
140
|
-
}
|
|
141
|
-
function scheduleFullReRender(ctx) {
|
|
142
|
-
const ui = ctx.ui;
|
|
143
|
-
if (ui && typeof ui.render === "function") ui.render(["_wf_root"]);
|
|
144
|
-
}
|
|
145
|
-
function mountComponent(Comp, props, vnode, ctx) {
|
|
146
|
-
let def;
|
|
147
|
-
if (isAsyncComponent(Comp)) {
|
|
148
|
-
def = resolveAsyncFactorySync(Comp);
|
|
149
|
-
if (!def) {
|
|
150
|
-
void startAsyncFactory(Comp, ctx).promise.then(
|
|
151
|
-
() => scheduleFullReRender(ctx),
|
|
152
|
-
() => {
|
|
153
|
-
}
|
|
154
|
-
);
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
} else {
|
|
158
|
-
def = Comp;
|
|
159
|
-
}
|
|
160
|
-
let childVNode = def(props, ctx);
|
|
161
|
-
if (typeof childVNode !== "function") {
|
|
162
|
-
throw new Error(
|
|
163
|
-
`Component ${Comp.name || "anonymous"} must return a render function. Use (init_props, ctx) => (props) => VNode pattern.`
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
vnode._render = childVNode;
|
|
167
|
-
return childVNode(props);
|
|
168
|
-
}
|
|
169
|
-
function renderComponent(Comp, props, vnode, ctx) {
|
|
170
|
-
;
|
|
171
|
-
ctx.ui = ctx.ui ?? {};
|
|
172
|
-
if (!vnode._id) {
|
|
173
|
-
vnode._id = `_wf_${_idCounter++}`;
|
|
174
|
-
idRegistry.set(vnode._id, vnode);
|
|
175
|
-
}
|
|
176
|
-
const childCtx = Object.create(ctx);
|
|
177
|
-
childCtx.ui = Object.create(ctx.ui);
|
|
178
|
-
childCtx.ui._selfId = vnode._id;
|
|
179
|
-
childCtx.ui._selfVNode = vnode;
|
|
180
|
-
vnode._ctxVersion = childCtx.ui._ctxVersion ?? 0;
|
|
181
|
-
let childVNode;
|
|
182
|
-
try {
|
|
183
|
-
childVNode = mountComponent(Comp, props, vnode, childCtx);
|
|
184
|
-
} catch (e) {
|
|
185
|
-
const errHandler = ctx.ui?._errorHandler;
|
|
186
|
-
if (errHandler) {
|
|
187
|
-
errHandler(e);
|
|
188
|
-
childVNode = null;
|
|
189
|
-
} else {
|
|
190
|
-
console.error(
|
|
191
|
-
`[weifuwu] Component render error in <${Comp.name || "anonymous"}> (id: ${vnode._id ?? "?"}, phase: mount)`,
|
|
192
|
-
e
|
|
193
|
-
);
|
|
194
|
-
childVNode = null;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
if (childVNode == null) {
|
|
198
|
-
vnode._child = null;
|
|
199
|
-
return null;
|
|
200
|
-
}
|
|
201
|
-
vnode._child = childVNode;
|
|
202
|
-
const domNode = renderValue(childVNode, childCtx);
|
|
203
|
-
if (!vnode._refNode) {
|
|
204
|
-
;
|
|
205
|
-
vnode._refNode = domNode;
|
|
206
|
-
}
|
|
207
|
-
return domNode;
|
|
208
|
-
}
|
|
209
|
-
function renderArray(arr, ctx) {
|
|
210
|
-
const frag = document.createDocumentFragment();
|
|
211
|
-
for (const item of arr) {
|
|
212
|
-
const node = renderValue(item, ctx);
|
|
213
|
-
if (node != null) frag.appendChild(node);
|
|
214
|
-
}
|
|
215
|
-
return frag;
|
|
216
|
-
}
|
|
217
|
-
function ensurePortalContainer() {
|
|
218
|
-
let c = document.getElementById("__wf_portal");
|
|
219
|
-
if (!c) {
|
|
220
|
-
c = document.createElement("div");
|
|
221
|
-
c.id = "__wf_portal";
|
|
222
|
-
c.style.cssText = "position:fixed;inset:0;pointer-events:none;z-index:9999";
|
|
223
|
-
document.body.appendChild(c);
|
|
224
|
-
}
|
|
225
|
-
return c;
|
|
226
|
-
}
|
|
227
|
-
function renderPortal(vnode, ctx) {
|
|
228
|
-
const container = ensurePortalContainer();
|
|
229
|
-
const sub = document.createElement("div");
|
|
230
|
-
sub.style.pointerEvents = "auto";
|
|
231
|
-
container.appendChild(sub);
|
|
232
|
-
vnode._remoteEl = sub;
|
|
233
|
-
const children = normalize(vnode.props?.children);
|
|
234
|
-
vnode._child = children;
|
|
235
|
-
for (const child of children) {
|
|
236
|
-
const node = renderValue(child, ctx);
|
|
237
|
-
if (node != null) sub.appendChild(node);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
function patchPortal(oldV, newV, ctx) {
|
|
241
|
-
const sub = oldV?._remoteEl;
|
|
242
|
-
newV._remoteEl = sub;
|
|
243
|
-
if (!sub) {
|
|
244
|
-
renderPortal(newV, ctx);
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
const newChildren = normalize(newV.props?.children);
|
|
248
|
-
const oldChildren = oldV._child || [];
|
|
249
|
-
newV._child = newChildren;
|
|
250
|
-
ensureKeys(oldChildren, newChildren);
|
|
251
|
-
patchKeyedChildren(sub, oldChildren, newChildren, ctx);
|
|
252
|
-
}
|
|
253
|
-
function flattenChildren(children) {
|
|
254
|
-
if (children == null) return [];
|
|
255
|
-
if (!Array.isArray(children)) return [children];
|
|
256
|
-
const result = [];
|
|
257
|
-
for (const child of children) {
|
|
258
|
-
if (Array.isArray(child)) {
|
|
259
|
-
result.push(...child);
|
|
260
|
-
} else {
|
|
261
|
-
result.push(child);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
return result;
|
|
265
|
-
}
|
|
266
|
-
function setProp(el, key, value) {
|
|
267
|
-
if (key === "class" || key === "className") {
|
|
268
|
-
if (el instanceof SVGElement) el.setAttribute("class", String(value ?? ""));
|
|
269
|
-
else el.className = String(value ?? "");
|
|
270
|
-
} else if (key === "style" && typeof value === "object" && value !== null) {
|
|
271
|
-
const st = el.style;
|
|
272
|
-
for (const sk of Object.keys(value)) {
|
|
273
|
-
const sv = value[sk];
|
|
274
|
-
if (sv != null) st[sk] = typeof sv === "number" ? sv + "px" : String(sv);
|
|
275
|
-
}
|
|
276
|
-
} else if (key.startsWith("on") && typeof value === "function") {
|
|
277
|
-
el.addEventListener(key.slice(2).toLowerCase(), value);
|
|
278
|
-
} else if (key === "value" && (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement)) {
|
|
279
|
-
;
|
|
280
|
-
el.value = String(value ?? "");
|
|
281
|
-
} else if (value === true) {
|
|
282
|
-
el.setAttribute(key, "");
|
|
283
|
-
} else if (value != null && value !== false) {
|
|
284
|
-
el.setAttribute(key, String(value));
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
function patchValue(parent, oldNode, oldInput, newInput, ctx) {
|
|
288
|
-
if (oldInput == null) {
|
|
289
|
-
if (newInput == null) return null;
|
|
290
|
-
const node = renderValue(newInput, ctx);
|
|
291
|
-
if (node == null) return null;
|
|
292
|
-
if (oldNode && oldNode.parentNode) {
|
|
293
|
-
oldNode.parentNode.insertBefore(node, oldNode);
|
|
294
|
-
} else {
|
|
295
|
-
parent.appendChild(node);
|
|
296
|
-
}
|
|
297
|
-
return node;
|
|
298
|
-
}
|
|
299
|
-
if (newInput == null) {
|
|
300
|
-
if (oldNode) {
|
|
301
|
-
callRefCleanup(oldInput);
|
|
302
|
-
oldNode.remove();
|
|
303
|
-
} else {
|
|
304
|
-
callRefCleanup(oldInput);
|
|
305
|
-
}
|
|
306
|
-
return null;
|
|
307
|
-
}
|
|
308
|
-
const oldType = typeOf(oldInput);
|
|
309
|
-
const newType = typeOf(newInput);
|
|
310
|
-
if (oldType !== newType) {
|
|
311
|
-
callRefCleanup(oldInput);
|
|
312
|
-
const node = renderValue(newInput, ctx);
|
|
313
|
-
if (node == null) return null;
|
|
314
|
-
if (oldNode?.parentNode) {
|
|
315
|
-
oldNode.parentNode.replaceChild(node, oldNode);
|
|
316
|
-
}
|
|
317
|
-
return node;
|
|
318
|
-
}
|
|
319
|
-
if (newType === "text") {
|
|
320
|
-
if (oldNode && oldNode.textContent !== String(newInput)) {
|
|
321
|
-
oldNode.textContent = String(newInput);
|
|
322
|
-
}
|
|
323
|
-
return oldNode;
|
|
324
|
-
}
|
|
325
|
-
const newV = newInput;
|
|
326
|
-
const oldV = oldInput;
|
|
327
|
-
if (typeof newV.type === "function") {
|
|
328
|
-
const comp = newV.type;
|
|
329
|
-
if (oldV._render) {
|
|
330
|
-
newV._render = oldV._render;
|
|
331
|
-
newV._id = oldV._id;
|
|
332
|
-
if (newV._id) idRegistry.set(newV._id, newV);
|
|
333
|
-
}
|
|
334
|
-
newV._parentNode = parent;
|
|
335
|
-
newV._refNode = oldNode;
|
|
336
|
-
const childCtx = Object.create(ctx);
|
|
337
|
-
childCtx.ui = Object.create(ctx.ui);
|
|
338
|
-
childCtx.ui._selfId = newV._id;
|
|
339
|
-
childCtx.ui._selfVNode = newV;
|
|
340
|
-
newV._ctxVersion = oldV._ctxVersion ?? childCtx.ui._ctxVersion ?? 0;
|
|
341
|
-
if (oldV._render && componentPropsEqual(oldV.props, newV.props) && !childCtx.ui._dirtySet?.has(oldV._id) && newV._ctxVersion === childCtx.ui._ctxVersion) {
|
|
342
|
-
newV._child = oldV._child;
|
|
343
|
-
return oldNode;
|
|
344
|
-
}
|
|
345
|
-
;
|
|
346
|
-
childCtx.ui._dirtySet?.delete(oldV._id);
|
|
347
|
-
let childNew;
|
|
348
|
-
try {
|
|
349
|
-
if (typeof newV._render === "function") {
|
|
350
|
-
childNew = newV._render(newV.props);
|
|
351
|
-
} else {
|
|
352
|
-
childNew = mountComponent(comp, newV.props, newV, childCtx);
|
|
353
|
-
}
|
|
354
|
-
} catch (e) {
|
|
355
|
-
const errHandler = ctx.ui?._errorHandler;
|
|
356
|
-
if (errHandler) {
|
|
357
|
-
errHandler(e);
|
|
358
|
-
childNew = null;
|
|
359
|
-
} else {
|
|
360
|
-
console.error(
|
|
361
|
-
`[weifuwu] Component render error in <${comp?.name || "anonymous"}> (id: ${oldV._id ?? "?"}, phase: update)`,
|
|
362
|
-
e
|
|
363
|
-
);
|
|
364
|
-
childNew = null;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
const _prevChild = oldV._child;
|
|
368
|
-
newV._child = childNew;
|
|
369
|
-
const returnedNode = patchValue(parent, oldNode, _prevChild, childNew, childCtx);
|
|
370
|
-
if (!returnedNode) newV._refNode = null;
|
|
371
|
-
return returnedNode;
|
|
372
|
-
}
|
|
373
|
-
if (newV.type === Fragment) {
|
|
374
|
-
patchChildren(parent, oldV, newV, ctx);
|
|
375
|
-
return oldNode;
|
|
376
|
-
}
|
|
377
|
-
if (typeof newV.type === "string") {
|
|
378
|
-
if (oldNode && oldNode.nodeType === 1) {
|
|
379
|
-
const oldRef = oldV.props?.ref;
|
|
380
|
-
const newRef = newV.props?.ref;
|
|
381
|
-
if (oldRef !== newRef) {
|
|
382
|
-
if (typeof oldRef === "function") oldRef(null);
|
|
383
|
-
if (typeof newRef === "function") newRef(oldNode);
|
|
384
|
-
}
|
|
385
|
-
patchProps(oldNode, oldV.props, newV.props);
|
|
386
|
-
patchChildren(oldNode, oldV, newV, ctx);
|
|
387
|
-
} else if (oldNode) {
|
|
388
|
-
callRefCleanup(oldInput);
|
|
389
|
-
const node = renderValue(newInput, ctx);
|
|
390
|
-
if (node == null) return null;
|
|
391
|
-
oldNode.parentNode?.replaceChild(node, oldNode);
|
|
392
|
-
return node;
|
|
393
|
-
}
|
|
394
|
-
return oldNode;
|
|
395
|
-
}
|
|
396
|
-
if (newV.type === Portal) {
|
|
397
|
-
patchPortal(oldV, newV, ctx);
|
|
398
|
-
return null;
|
|
399
|
-
}
|
|
400
|
-
if (Array.isArray(newInput)) {
|
|
401
|
-
const oldArr = Array.isArray(oldInput) ? oldInput : [];
|
|
402
|
-
ensureKeys(oldArr, newInput);
|
|
403
|
-
patchKeyedChildren(parent, oldArr, newInput, ctx);
|
|
404
|
-
return oldNode;
|
|
405
|
-
}
|
|
406
|
-
return oldNode;
|
|
407
|
-
}
|
|
408
|
-
function typeOf(input) {
|
|
409
|
-
if (input == null || typeof input === "boolean") return "null";
|
|
410
|
-
if (typeof input === "string" || typeof input === "number") return "text";
|
|
411
|
-
if (Array.isArray(input)) return "array";
|
|
412
|
-
const v = input;
|
|
413
|
-
if (typeof v.type === "function") return `fn:${v.type.name || "anon"}`;
|
|
414
|
-
if (v.type === Fragment) return "fragment";
|
|
415
|
-
if (v.type === Portal) return "portal";
|
|
416
|
-
if (typeof v.type === "string") return "tag:" + v.type;
|
|
417
|
-
return "unknown";
|
|
418
|
-
}
|
|
419
|
-
function patchProps(el, oldProps, newProps) {
|
|
420
|
-
const oldKeys = oldProps ? Object.keys(oldProps).filter((k) => k !== "children" && k !== "key" && k !== "innerHTML") : [];
|
|
421
|
-
const newKeys = newProps ? Object.keys(newProps).filter((k) => k !== "children" && k !== "key" && k !== "innerHTML") : [];
|
|
422
|
-
for (const key of oldKeys) {
|
|
423
|
-
if (!newKeys.includes(key)) {
|
|
424
|
-
if (key === "ref") continue;
|
|
425
|
-
if (key.startsWith("on") && typeof oldProps[key] === "function") {
|
|
426
|
-
el.removeEventListener(key.slice(2).toLowerCase(), oldProps[key]);
|
|
427
|
-
} else if (key === "value" && (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement)) {
|
|
428
|
-
;
|
|
429
|
-
el.value = "";
|
|
430
|
-
} else {
|
|
431
|
-
el.removeAttribute(key === "className" ? "class" : key);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
for (const key of newKeys) {
|
|
436
|
-
if (key === "ref") continue;
|
|
437
|
-
const oldVal = oldProps?.[key];
|
|
438
|
-
const newVal = newProps?.[key];
|
|
439
|
-
if (key === "innerHTML") {
|
|
440
|
-
if (newVal !== oldVal) el.innerHTML = String(newVal ?? "");
|
|
441
|
-
} else if (newVal !== oldVal) {
|
|
442
|
-
if (key === "class" || key === "className") {
|
|
443
|
-
if (el instanceof SVGElement) el.setAttribute("class", classToString(newVal));
|
|
444
|
-
else el.className = classToString(newVal);
|
|
445
|
-
} else if (key === "style" && typeof newVal === "object") {
|
|
446
|
-
const st = el.style;
|
|
447
|
-
for (const sk of Object.keys(newVal)) {
|
|
448
|
-
const sv = newVal[sk];
|
|
449
|
-
if (sv != null) st[sk] = typeof sv === "number" ? sv + "px" : String(sv);
|
|
450
|
-
}
|
|
451
|
-
} else if (key.startsWith("on") && typeof newVal === "function") {
|
|
452
|
-
const eventName = key.slice(2).toLowerCase();
|
|
453
|
-
if (typeof oldVal === "function") el.removeEventListener(eventName, oldVal);
|
|
454
|
-
el.addEventListener(eventName, newVal);
|
|
455
|
-
} else if (key === "value" && (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement)) {
|
|
456
|
-
;
|
|
457
|
-
el.value = String(newVal ?? "");
|
|
458
|
-
} else if (newVal === true) {
|
|
459
|
-
el.setAttribute(key, "");
|
|
460
|
-
} else if (newVal != null && newVal !== false) {
|
|
461
|
-
el.setAttribute(key, String(newVal));
|
|
462
|
-
} else {
|
|
463
|
-
if (key === "value" && (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement)) {
|
|
464
|
-
;
|
|
465
|
-
el.value = "";
|
|
466
|
-
} else {
|
|
467
|
-
el.removeAttribute(key);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
function classToString(v) {
|
|
474
|
-
if (typeof v === "string") return v;
|
|
475
|
-
if (Array.isArray(v)) return v.filter(Boolean).join(" ");
|
|
476
|
-
if (v && typeof v === "object") {
|
|
477
|
-
return Object.entries(v).filter(([, b]) => b).map(([k]) => k).join(" ");
|
|
478
|
-
}
|
|
479
|
-
return "";
|
|
480
|
-
}
|
|
481
|
-
function getKey(input) {
|
|
482
|
-
if (input == null || typeof input !== "object") return void 0;
|
|
483
|
-
return input.key;
|
|
484
|
-
}
|
|
485
|
-
function ensureKeys(oldChildren, newChildren) {
|
|
486
|
-
const hasKey = newChildren.some((c) => c && typeof c === "object" && c.key !== void 0);
|
|
487
|
-
if (!hasKey) {
|
|
488
|
-
for (let i = 0; i < newChildren.length; i++) {
|
|
489
|
-
const c = newChildren[i];
|
|
490
|
-
if (c && typeof c === "object") c.key = i;
|
|
491
|
-
}
|
|
492
|
-
for (let i = 0; i < oldChildren.length; i++) {
|
|
493
|
-
const c = oldChildren[i];
|
|
494
|
-
if (c && typeof c === "object") c.key = i;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
function patchChildren(parent, oldVNode, newVNode, ctx) {
|
|
499
|
-
const oldChildren = normalize(oldVNode.props?.children);
|
|
500
|
-
const newChildren = normalize(newVNode.props?.children);
|
|
501
|
-
ensureKeys(oldChildren, newChildren);
|
|
502
|
-
patchKeyedChildren(parent, oldChildren, newChildren, ctx);
|
|
503
|
-
}
|
|
504
|
-
function normalize(children) {
|
|
505
|
-
if (children == null) return [];
|
|
506
|
-
if (!Array.isArray(children)) return [children];
|
|
507
|
-
const result = [];
|
|
508
|
-
for (const child of children) {
|
|
509
|
-
if (Array.isArray(child)) {
|
|
510
|
-
result.push(...child);
|
|
511
|
-
} else {
|
|
512
|
-
result.push(child);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
return result;
|
|
516
|
-
}
|
|
517
|
-
function patchKeyedChildren(parent, oldChildren, newChildren, ctx) {
|
|
518
|
-
const allUnkeyed = !newChildren.some((c) => c && typeof c === "object" && c.key !== void 0);
|
|
519
|
-
if (allUnkeyed) {
|
|
520
|
-
const len = Math.max(oldChildren.length, newChildren.length);
|
|
521
|
-
for (let i = 0; i < len; i++) {
|
|
522
|
-
const oldC = i < oldChildren.length ? oldChildren[i] : null;
|
|
523
|
-
const newC = i < newChildren.length ? newChildren[i] : null;
|
|
524
|
-
if (newC == null) {
|
|
525
|
-
if (oldC != null) {
|
|
526
|
-
callRefCleanup(oldC);
|
|
527
|
-
const node = parent.childNodes[i];
|
|
528
|
-
if (node) node.remove();
|
|
529
|
-
}
|
|
530
|
-
} else if (oldC == null) {
|
|
531
|
-
const node = renderValue(newC, ctx);
|
|
532
|
-
if (node != null) parent.appendChild(node);
|
|
533
|
-
} else {
|
|
534
|
-
const oldNode = parent.childNodes[i] || null;
|
|
535
|
-
patchValue(parent, oldNode, oldC, newC, ctx);
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
let rmIdx = 0;
|
|
541
|
-
for (let i = 0; i < oldChildren.length; i++) {
|
|
542
|
-
const child = oldChildren[i];
|
|
543
|
-
if (child == null || typeof child === "boolean") continue;
|
|
544
|
-
const key = getKey(child);
|
|
545
|
-
if (key === void 0) {
|
|
546
|
-
const node = parent.childNodes[rmIdx];
|
|
547
|
-
if (node) node.remove();
|
|
548
|
-
} else {
|
|
549
|
-
const isRemote = child && typeof child === "object" && child._placement === "remote";
|
|
550
|
-
if (!isRemote) rmIdx++;
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
const oldKeyMap = /* @__PURE__ */ new Map();
|
|
554
|
-
let domIdx = 0;
|
|
555
|
-
for (let i = 0; i < oldChildren.length; i++) {
|
|
556
|
-
const key = getKey(oldChildren[i]);
|
|
557
|
-
if (key !== void 0) {
|
|
558
|
-
const child = oldChildren[i];
|
|
559
|
-
const isRemote = child && typeof child === "object" && child._placement === "remote";
|
|
560
|
-
oldKeyMap.set(key, {
|
|
561
|
-
vnode: child,
|
|
562
|
-
node: isRemote ? null : parent.childNodes[domIdx] || null,
|
|
563
|
-
remote: !!isRemote,
|
|
564
|
-
index: domIdx
|
|
565
|
-
});
|
|
566
|
-
if (!isRemote) domIdx++;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
const newKeys = newChildren.map((c) => getKey(c));
|
|
570
|
-
for (const key of oldKeyMap.keys()) {
|
|
571
|
-
if (!newKeys.includes(key)) {
|
|
572
|
-
const entry = oldKeyMap.get(key);
|
|
573
|
-
callRefCleanup(entry.vnode);
|
|
574
|
-
if (entry.node) entry.node?.remove();
|
|
575
|
-
oldKeyMap.delete(key);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
let lastIndex = -1;
|
|
579
|
-
let nextRef = parent.firstChild;
|
|
580
|
-
for (let i = 0; i < newChildren.length; i++) {
|
|
581
|
-
const key = newKeys[i];
|
|
582
|
-
const newChild = newChildren[i];
|
|
583
|
-
const oldEntry = key !== void 0 ? oldKeyMap.get(key) : void 0;
|
|
584
|
-
const isRemote = newChild && typeof newChild === "object" && newChild._placement === "remote";
|
|
585
|
-
if (oldEntry) {
|
|
586
|
-
if (oldEntry.node) {
|
|
587
|
-
if (oldEntry.index < lastIndex) {
|
|
588
|
-
parent.insertBefore(oldEntry.node, nextRef);
|
|
589
|
-
}
|
|
590
|
-
lastIndex = Math.max(lastIndex, oldEntry.index);
|
|
591
|
-
patchValue(parent, oldEntry.node, oldEntry.vnode, newChild, ctx);
|
|
592
|
-
nextRef = (oldEntry.node.parentNode === parent ? oldEntry.node : parent.firstChild)?.nextSibling ?? null;
|
|
593
|
-
} else if (oldEntry.remote) {
|
|
594
|
-
patchPortal(oldEntry.vnode, newChild, ctx);
|
|
595
|
-
} else {
|
|
596
|
-
const newNode = patchValue(parent, null, oldEntry.vnode, newChild, ctx);
|
|
597
|
-
if (newNode != null) {
|
|
598
|
-
parent.insertBefore(newNode, nextRef);
|
|
599
|
-
nextRef = newNode.nextSibling;
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
} else if (isRemote) {
|
|
603
|
-
renderPortal(newChild, ctx);
|
|
604
|
-
} else {
|
|
605
|
-
const node = renderValue(newChild, ctx);
|
|
606
|
-
if (node != null) {
|
|
607
|
-
parent.insertBefore(node, nextRef);
|
|
608
|
-
nextRef = node.nextSibling;
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
function childrenEqual(a, b) {
|
|
614
|
-
if (a === b) return true;
|
|
615
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
616
|
-
if (a.length !== b.length) return false;
|
|
617
|
-
for (let i = 0; i < a.length; i++) {
|
|
618
|
-
if (a[i] !== b[i]) return false;
|
|
619
|
-
}
|
|
620
|
-
return true;
|
|
621
|
-
}
|
|
622
|
-
return a === b;
|
|
623
|
-
}
|
|
624
|
-
function componentPropsEqual(a, b) {
|
|
625
|
-
if (a === b) return true;
|
|
626
|
-
if (!a || !b) return false;
|
|
627
|
-
const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
628
|
-
for (const key of keys) {
|
|
629
|
-
if (key === "key") continue;
|
|
630
|
-
if (key === "children") {
|
|
631
|
-
if (!childrenEqual(a[key], b[key])) return false;
|
|
632
|
-
} else if (a[key] !== b[key]) {
|
|
633
|
-
return false;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
return true;
|
|
637
|
-
}
|
|
638
|
-
function cleanupPortalChildren(vnode) {
|
|
639
|
-
const child = vnode._child;
|
|
640
|
-
if (child == null) return;
|
|
641
|
-
if (Array.isArray(child)) {
|
|
642
|
-
for (const c of child) {
|
|
643
|
-
if (c && typeof c === "object") callRefCleanup(c);
|
|
644
|
-
}
|
|
645
|
-
} else if (typeof child === "object") {
|
|
646
|
-
callRefCleanup(child);
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
function callRefCleanup(input) {
|
|
650
|
-
if (input == null || typeof input !== "object") return;
|
|
651
|
-
const vnode = input;
|
|
652
|
-
if (vnode._id) {
|
|
653
|
-
if (vnode._customId) idRegistry.delete(vnode._customId);
|
|
654
|
-
idRegistry.delete(vnode._id);
|
|
655
|
-
vnode._id = void 0;
|
|
656
|
-
vnode._customId = void 0;
|
|
657
|
-
vnode._render = void 0;
|
|
658
|
-
vnode._parentNode = void 0;
|
|
659
|
-
vnode._refNode = void 0;
|
|
660
|
-
}
|
|
661
|
-
if (vnode._child != null) {
|
|
662
|
-
if (Array.isArray(vnode._child)) {
|
|
663
|
-
for (const child of vnode._child) {
|
|
664
|
-
if (child && typeof child === "object") callRefCleanup(child);
|
|
665
|
-
}
|
|
666
|
-
} else {
|
|
667
|
-
callRefCleanup(vnode._child);
|
|
668
|
-
}
|
|
669
|
-
vnode._child = void 0;
|
|
670
|
-
}
|
|
671
|
-
if (vnode.props?.children && typeof vnode.type === "string") {
|
|
672
|
-
const children = Array.isArray(vnode.props.children) ? vnode.props.children : [vnode.props.children];
|
|
673
|
-
for (const child of children) {
|
|
674
|
-
if (child && typeof child === "object") callRefCleanup(child);
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
if (typeof vnode.props?.ref === "function") vnode.props.ref(null);
|
|
678
|
-
if (vnode._remoteEl) {
|
|
679
|
-
cleanupPortalChildren(vnode);
|
|
680
|
-
vnode._remoteEl.remove();
|
|
681
|
-
vnode._remoteEl = void 0;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
function cursorAdvance(c) {
|
|
685
|
-
c.node = c.node ? c.node.nextSibling : null;
|
|
686
|
-
}
|
|
687
|
-
function cursorInsert(c, n) {
|
|
688
|
-
if (c.node && c.node.parentNode) c.node.parentNode.insertBefore(n, c.node);
|
|
689
|
-
else c.parent.appendChild(n);
|
|
690
|
-
}
|
|
691
|
-
function cursorReplace(c, n) {
|
|
692
|
-
if (c.node && c.node.parentNode) {
|
|
693
|
-
c.node.parentNode.replaceChild(n, c.node);
|
|
694
|
-
cursorAdvance(c);
|
|
695
|
-
} else {
|
|
696
|
-
c.parent.appendChild(n);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
async function renderValueHydrating(v, ctx, c) {
|
|
700
|
-
if (v == null || typeof v === "boolean") return null;
|
|
701
|
-
if (typeof v === "string" || typeof v === "number") {
|
|
702
|
-
const text = String(v);
|
|
703
|
-
if (c.node && c.node.nodeType === 3) {
|
|
704
|
-
if (c.node.textContent !== text) c.node.textContent = text;
|
|
705
|
-
cursorAdvance(c);
|
|
706
|
-
return c.node;
|
|
707
|
-
}
|
|
708
|
-
const tn = document.createTextNode(text);
|
|
709
|
-
cursorInsert(c, tn);
|
|
710
|
-
return tn;
|
|
711
|
-
}
|
|
712
|
-
if (Array.isArray(v)) {
|
|
713
|
-
let first = null;
|
|
714
|
-
for (const item of v) {
|
|
715
|
-
const n = await renderValueHydrating(item, ctx, c);
|
|
716
|
-
if (n != null && !first) first = n;
|
|
717
|
-
}
|
|
718
|
-
return first;
|
|
719
|
-
}
|
|
720
|
-
const vnode = v;
|
|
721
|
-
if (vnode.type === Portal || vnode.type === Fragment) {
|
|
722
|
-
const children = vnode.props?.children;
|
|
723
|
-
const arr = children == null ? [] : Array.isArray(children) ? children : [children];
|
|
724
|
-
let first = null;
|
|
725
|
-
for (const child of arr) {
|
|
726
|
-
const n = await renderValueHydrating(child, ctx, c);
|
|
727
|
-
if (n != null && !first) first = n;
|
|
728
|
-
}
|
|
729
|
-
return first;
|
|
730
|
-
}
|
|
731
|
-
if (typeof vnode.type === "function") {
|
|
732
|
-
return renderComponentHydrating(vnode, ctx, c);
|
|
733
|
-
}
|
|
734
|
-
const tag = vnode.type;
|
|
735
|
-
const props = vnode.props ?? {};
|
|
736
|
-
let el;
|
|
737
|
-
if (c.node && c.node.nodeType === 1 && c.node.tagName.toLowerCase() === tag.toLowerCase()) {
|
|
738
|
-
el = c.node;
|
|
739
|
-
cursorAdvance(c);
|
|
740
|
-
} else {
|
|
741
|
-
el = SVG_TAGS.has(tag) ? document.createElementNS(SVG_NS, tag) : document.createElement(tag);
|
|
742
|
-
cursorReplace(c, el);
|
|
743
|
-
}
|
|
744
|
-
vnode.el = el;
|
|
745
|
-
patchProps(el, null, props);
|
|
746
|
-
if ("innerHTML" in props) {
|
|
747
|
-
} else {
|
|
748
|
-
const childCursor = { parent: el, node: el.firstChild };
|
|
749
|
-
const children = flattenChildren(props.children);
|
|
750
|
-
for (const child of children) {
|
|
751
|
-
const n = await renderValueHydrating(child, ctx, childCursor);
|
|
752
|
-
if (n != null && n.parentNode !== el) el.appendChild(n);
|
|
753
|
-
if (child && typeof child === "object" && typeof child.type === "function") {
|
|
754
|
-
const childVNode = child;
|
|
755
|
-
if (!childVNode._parentNode) {
|
|
756
|
-
childVNode._parentNode = el;
|
|
757
|
-
childVNode._refNode = n;
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
while (childCursor.node) {
|
|
762
|
-
const n = childCursor.node;
|
|
763
|
-
childCursor.node = n.nextSibling;
|
|
764
|
-
n.parentNode?.removeChild(n);
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
if ("value" in props && el instanceof HTMLSelectElement) {
|
|
768
|
-
;
|
|
769
|
-
el.value = String(props.value ?? "");
|
|
770
|
-
}
|
|
771
|
-
if (typeof props.ref === "function") props.ref(el);
|
|
772
|
-
return el;
|
|
773
|
-
}
|
|
774
|
-
async function renderComponentHydrating(vnode, ctx, c) {
|
|
775
|
-
;
|
|
776
|
-
ctx.ui = ctx.ui ?? {};
|
|
777
|
-
if (!vnode._id) {
|
|
778
|
-
vnode._id = `_wf_${_idCounter++}`;
|
|
779
|
-
idRegistry.set(vnode._id, vnode);
|
|
780
|
-
}
|
|
781
|
-
const childCtx = Object.create(ctx);
|
|
782
|
-
childCtx.ui = Object.create(ctx.ui);
|
|
783
|
-
childCtx.ui._selfId = vnode._id;
|
|
784
|
-
childCtx.ui._selfVNode = vnode;
|
|
785
|
-
vnode._ctxVersion = childCtx.ui._ctxVersion ?? 0;
|
|
786
|
-
const Comp = vnode.type;
|
|
787
|
-
let childVNode;
|
|
788
|
-
try {
|
|
789
|
-
let def;
|
|
790
|
-
if (isAsyncComponent(Comp)) {
|
|
791
|
-
def = await resolveAsyncFactory(Comp, childCtx);
|
|
792
|
-
} else {
|
|
793
|
-
def = Comp;
|
|
794
|
-
}
|
|
795
|
-
const renderFn = def(vnode.props ?? {}, childCtx);
|
|
796
|
-
if (typeof renderFn !== "function") {
|
|
797
|
-
throw new Error(
|
|
798
|
-
`Component ${Comp.name || "anonymous"} must return a render function. Use (init_props, ctx) => (props) => VNode pattern.`
|
|
799
|
-
);
|
|
800
|
-
}
|
|
801
|
-
vnode._render = renderFn;
|
|
802
|
-
childVNode = renderFn(vnode.props ?? {});
|
|
803
|
-
} catch (e) {
|
|
804
|
-
const errHandler = ctx.ui?._errorHandler;
|
|
805
|
-
if (errHandler) {
|
|
806
|
-
errHandler(e);
|
|
807
|
-
childVNode = null;
|
|
808
|
-
} else {
|
|
809
|
-
console.error(
|
|
810
|
-
`[weifuwu] Component hydration error in <${Comp.name || "anonymous"}> (id: ${vnode._id ?? "?"})`,
|
|
811
|
-
e
|
|
812
|
-
);
|
|
813
|
-
childVNode = null;
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
if (childVNode == null) {
|
|
817
|
-
vnode._child = null;
|
|
818
|
-
return null;
|
|
819
|
-
}
|
|
820
|
-
vnode._child = childVNode;
|
|
821
|
-
const domNode = await renderValueHydrating(childVNode, childCtx, c);
|
|
822
|
-
if (!vnode._refNode) {
|
|
823
|
-
;
|
|
824
|
-
vnode._refNode = domNode;
|
|
825
|
-
}
|
|
826
|
-
return domNode;
|
|
827
|
-
}
|
|
828
|
-
async function hydrateVNode(container, vnode, ctx) {
|
|
829
|
-
const cursor = { parent: container, node: container.firstChild };
|
|
830
|
-
await renderValueHydrating(vnode, ctx, cursor);
|
|
831
|
-
while (cursor.node) {
|
|
832
|
-
const n = cursor.node;
|
|
833
|
-
cursor.node = n.nextSibling;
|
|
834
|
-
n.parentNode?.removeChild(n);
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
// src/client/reactive.ts
|
|
839
|
-
function createReactiveState(dirty) {
|
|
840
|
-
const proxyCache = /* @__PURE__ */ new WeakMap();
|
|
841
|
-
const watchers = /* @__PURE__ */ new Set();
|
|
842
|
-
const reactive = (target) => {
|
|
843
|
-
if (target === null || typeof target !== "object") return target;
|
|
844
|
-
if (proxyCache.has(target)) return proxyCache.get(target);
|
|
845
|
-
const proxy = new Proxy(target, {
|
|
846
|
-
set(target2, key, value) {
|
|
847
|
-
const old = Reflect.get(target2, key);
|
|
848
|
-
if (old === value) return true;
|
|
849
|
-
Reflect.set(target2, key, value);
|
|
850
|
-
dirty();
|
|
851
|
-
for (const w of watchers) w();
|
|
852
|
-
return true;
|
|
853
|
-
},
|
|
854
|
-
get(target2, key) {
|
|
855
|
-
const value = Reflect.get(target2, key);
|
|
856
|
-
if (typeof value === "object" && value !== null) return reactive(value);
|
|
857
|
-
return value;
|
|
858
|
-
},
|
|
859
|
-
deleteProperty(target2, key) {
|
|
860
|
-
if (Reflect.has(target2, key)) {
|
|
861
|
-
Reflect.deleteProperty(target2, key);
|
|
862
|
-
dirty();
|
|
863
|
-
for (const w of watchers) w();
|
|
864
|
-
}
|
|
865
|
-
return true;
|
|
866
|
-
}
|
|
867
|
-
});
|
|
868
|
-
proxyCache.set(target, proxy);
|
|
869
|
-
return proxy;
|
|
870
|
-
};
|
|
871
|
-
const root = reactive({});
|
|
872
|
-
Object.defineProperty(root, "__watch", {
|
|
873
|
-
value: (cb) => {
|
|
874
|
-
watchers.add(cb);
|
|
875
|
-
return () => {
|
|
876
|
-
watchers.delete(cb);
|
|
877
|
-
};
|
|
878
|
-
},
|
|
879
|
-
writable: false,
|
|
880
|
-
enumerable: false
|
|
881
|
-
});
|
|
882
|
-
return root;
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
// src/client/ai.ts
|
|
886
|
-
var RECORD_LIMIT = 1e3;
|
|
887
|
-
function aiStream(url, body, options) {
|
|
888
|
-
const controller = new AbortController();
|
|
889
|
-
const external = options?.signal;
|
|
890
|
-
if (external) {
|
|
891
|
-
if (external.aborted) controller.abort();
|
|
892
|
-
else external.addEventListener("abort", () => controller.abort(), { once: true });
|
|
893
|
-
}
|
|
894
|
-
const traceId = options?.traceId ?? randomId();
|
|
895
|
-
const record = options?.record !== false;
|
|
896
|
-
const events = [];
|
|
897
|
-
const done = (async () => {
|
|
898
|
-
let res;
|
|
899
|
-
try {
|
|
900
|
-
res = await fetch(url, {
|
|
901
|
-
method: "POST",
|
|
902
|
-
headers: {
|
|
903
|
-
"Content-Type": "application/json",
|
|
904
|
-
"X-Trace-Id": traceId,
|
|
905
|
-
Accept: "text/event-stream",
|
|
906
|
-
...options?.headers
|
|
907
|
-
},
|
|
908
|
-
body: JSON.stringify(body),
|
|
909
|
-
signal: controller.signal
|
|
910
|
-
});
|
|
911
|
-
} catch (err) {
|
|
912
|
-
if (controller.signal.aborted) return;
|
|
913
|
-
options?.onError?.({ code: "provider_error", message: err instanceof Error ? err.message : String(err) });
|
|
914
|
-
return;
|
|
915
|
-
}
|
|
916
|
-
if (!res.ok) {
|
|
917
|
-
options?.onError?.({
|
|
918
|
-
code: httpErrorCode(res.status),
|
|
919
|
-
message: `HTTP ${res.status} ${res.statusText}`
|
|
920
|
-
});
|
|
921
|
-
return;
|
|
922
|
-
}
|
|
923
|
-
try {
|
|
924
|
-
for await (const { name, data } of parseWfEvents(res.body)) {
|
|
925
|
-
if (controller.signal.aborted) return;
|
|
926
|
-
pushEvent(events, { name, data }, record);
|
|
927
|
-
dispatch(name, data, options ?? {});
|
|
928
|
-
}
|
|
929
|
-
} catch (err) {
|
|
930
|
-
if (controller.signal.aborted) return;
|
|
931
|
-
options?.onError?.({ code: "provider_error", message: err instanceof Error ? err.message : String(err) });
|
|
932
|
-
}
|
|
933
|
-
})();
|
|
934
|
-
return {
|
|
935
|
-
abort: () => controller.abort(),
|
|
936
|
-
done,
|
|
937
|
-
traceId,
|
|
938
|
-
events
|
|
939
|
-
};
|
|
940
|
-
}
|
|
941
|
-
function dispatch(name, data, o) {
|
|
942
|
-
switch (name) {
|
|
943
|
-
case "wf:token":
|
|
944
|
-
return o.onToken?.(data.text);
|
|
945
|
-
case "wf:tool_call":
|
|
946
|
-
return o.onToolCall?.(data);
|
|
947
|
-
case "wf:tool_result":
|
|
948
|
-
return o.onToolResult?.(data);
|
|
949
|
-
case "wf:tool_progress":
|
|
950
|
-
return o.onToolProgress?.(data);
|
|
951
|
-
case "wf:step":
|
|
952
|
-
return o.onStep?.(data);
|
|
953
|
-
case "wf:approval_request":
|
|
954
|
-
return o.onApproval?.(data);
|
|
955
|
-
case "wf:usage":
|
|
956
|
-
return o.onUsage?.(data);
|
|
957
|
-
case "wf:done":
|
|
958
|
-
return o.onDone?.(data);
|
|
959
|
-
case "wf:error":
|
|
960
|
-
return o.onError?.(data);
|
|
961
|
-
default:
|
|
962
|
-
return o.onEvent?.(name, data);
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
async function* parseWfEvents(stream) {
|
|
966
|
-
const reader = stream.getReader();
|
|
967
|
-
const decoder = new TextDecoder();
|
|
968
|
-
let buffer = "";
|
|
969
|
-
try {
|
|
970
|
-
while (true) {
|
|
971
|
-
const { done, value } = await reader.read();
|
|
972
|
-
if (done) break;
|
|
973
|
-
buffer += decoder.decode(value, { stream: true });
|
|
974
|
-
const blocks = buffer.split("\n\n");
|
|
975
|
-
buffer = blocks.pop() ?? "";
|
|
976
|
-
for (const block of blocks) {
|
|
977
|
-
let name = "message";
|
|
978
|
-
let data = "";
|
|
979
|
-
for (const line of block.split("\n")) {
|
|
980
|
-
if (line.startsWith("event: ")) name = line.slice(7);
|
|
981
|
-
else if (line.startsWith("data: ")) data += line.slice(6);
|
|
982
|
-
}
|
|
983
|
-
if (!data) continue;
|
|
984
|
-
try {
|
|
985
|
-
yield { name, data: JSON.parse(data) };
|
|
986
|
-
} catch {
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
} finally {
|
|
991
|
-
reader.releaseLock();
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
function pushEvent(events, e, record) {
|
|
995
|
-
if (!record) return;
|
|
996
|
-
if (events.length >= RECORD_LIMIT) events.shift();
|
|
997
|
-
events.push(e);
|
|
998
|
-
}
|
|
999
|
-
function httpErrorCode(status) {
|
|
1000
|
-
if (status === 401 || status === 403) return "auth_failed";
|
|
1001
|
-
if (status === 429) return "rate_limited";
|
|
1002
|
-
if (status >= 500) return "provider_error";
|
|
1003
|
-
return "invalid_request";
|
|
1004
|
-
}
|
|
1005
|
-
function randomId() {
|
|
1006
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
1007
|
-
return crypto.randomUUID();
|
|
1008
|
-
}
|
|
1009
|
-
return `trace-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
// src/client/use-chat.ts
|
|
1013
|
-
function toChatMessages(msgs) {
|
|
1014
|
-
return msgs.map((m) => ({ role: m.role, content: m.content }));
|
|
1015
|
-
}
|
|
1016
|
-
function uid() {
|
|
1017
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
1018
|
-
return crypto.randomUUID();
|
|
1019
|
-
}
|
|
1020
|
-
return `msg-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1021
|
-
}
|
|
1022
|
-
function createChatSession(state, transport, options) {
|
|
1023
|
-
if (options.initialMessages) {
|
|
1024
|
-
state.messages = structuredClone(options.initialMessages);
|
|
1025
|
-
} else if (state.messages === void 0) state.messages = [];
|
|
1026
|
-
if (state.input === void 0) state.input = "";
|
|
1027
|
-
if (state.streaming === void 0) state.streaming = false;
|
|
1028
|
-
if (state.error === void 0) state.error = null;
|
|
1029
|
-
if (state.usage === void 0) state.usage = null;
|
|
1030
|
-
if (state.step === void 0) state.step = null;
|
|
1031
|
-
let handle = null;
|
|
1032
|
-
function current() {
|
|
1033
|
-
if (!state.streaming) return void 0;
|
|
1034
|
-
const m = state.messages[state.messages.length - 1];
|
|
1035
|
-
return m && m.role === "assistant" && m.status === "streaming" ? m : void 0;
|
|
1036
|
-
}
|
|
1037
|
-
function apply(name, data, onEvent) {
|
|
1038
|
-
const m = current();
|
|
1039
|
-
switch (name) {
|
|
1040
|
-
case "wf:token":
|
|
1041
|
-
if (m) m.content += data.text;
|
|
1042
|
-
break;
|
|
1043
|
-
case "wf:tool_call": {
|
|
1044
|
-
if (m) {
|
|
1045
|
-
if (!m.toolCalls) m.toolCalls = [];
|
|
1046
|
-
m.toolCalls.push({ call: data, status: "running" });
|
|
1047
|
-
}
|
|
1048
|
-
break;
|
|
1049
|
-
}
|
|
1050
|
-
case "wf:tool_progress": {
|
|
1051
|
-
const p = data;
|
|
1052
|
-
const tc = m?.toolCalls?.find((t) => t.call.id === p.toolCallId);
|
|
1053
|
-
if (tc) tc.progress = p;
|
|
1054
|
-
break;
|
|
1055
|
-
}
|
|
1056
|
-
case "wf:tool_result": {
|
|
1057
|
-
const r = data;
|
|
1058
|
-
const tc = m?.toolCalls?.find((t) => t.call.id === r.id);
|
|
1059
|
-
if (tc) {
|
|
1060
|
-
tc.result = r;
|
|
1061
|
-
tc.status = r.ok ? "ok" : "error";
|
|
1062
|
-
}
|
|
1063
|
-
break;
|
|
1064
|
-
}
|
|
1065
|
-
case "wf:approval_request":
|
|
1066
|
-
if (m) m.approval = data;
|
|
1067
|
-
break;
|
|
1068
|
-
case "wf:usage":
|
|
1069
|
-
if (m) m.usage = data;
|
|
1070
|
-
break;
|
|
1071
|
-
case "wf:step":
|
|
1072
|
-
state.step = data;
|
|
1073
|
-
break;
|
|
1074
|
-
case "wf:done":
|
|
1075
|
-
if (m) {
|
|
1076
|
-
m.status = "done";
|
|
1077
|
-
m.approval = void 0;
|
|
1078
|
-
}
|
|
1079
|
-
state.streaming = false;
|
|
1080
|
-
state.step = null;
|
|
1081
|
-
break;
|
|
1082
|
-
case "wf:error":
|
|
1083
|
-
if (m) {
|
|
1084
|
-
m.status = "error";
|
|
1085
|
-
m.error = data;
|
|
1086
|
-
m.approval = void 0;
|
|
1087
|
-
}
|
|
1088
|
-
state.error = data;
|
|
1089
|
-
state.streaming = false;
|
|
1090
|
-
state.step = null;
|
|
1091
|
-
break;
|
|
1092
|
-
default:
|
|
1093
|
-
onEvent?.(name, data);
|
|
1094
|
-
break;
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
function startStream() {
|
|
1098
|
-
const body = options.body ? options.body(state.messages) : { messages: toChatMessages(state.messages) };
|
|
1099
|
-
handle = transport(options.url, body, {
|
|
1100
|
-
onToken: (t) => apply("wf:token", { text: t }),
|
|
1101
|
-
onToolCall: (c) => apply("wf:tool_call", c),
|
|
1102
|
-
onToolProgress: (p) => apply("wf:tool_progress", p),
|
|
1103
|
-
onToolResult: (r) => apply("wf:tool_result", r),
|
|
1104
|
-
onApproval: (req) => apply("wf:approval_request", req),
|
|
1105
|
-
onUsage: (u) => apply("wf:usage", u),
|
|
1106
|
-
onStep: (s) => apply("wf:step", s),
|
|
1107
|
-
onDone: (d) => apply("wf:done", d),
|
|
1108
|
-
onError: (e) => apply("wf:error", e),
|
|
1109
|
-
onEvent: (n, d) => apply(n, d, options.onEvent)
|
|
1110
|
-
}, { signal: options.signal, headers: options.headers });
|
|
1111
|
-
state.streaming = true;
|
|
1112
|
-
const m = current();
|
|
1113
|
-
if (m && handle?.traceId) m.id = handle.traceId;
|
|
1114
|
-
}
|
|
1115
|
-
function send() {
|
|
1116
|
-
if (state.streaming) return;
|
|
1117
|
-
const text = String(state.input ?? "").trim();
|
|
1118
|
-
if (!text) return;
|
|
1119
|
-
state.input = "";
|
|
1120
|
-
state.error = null;
|
|
1121
|
-
state.usage = null;
|
|
1122
|
-
state.step = null;
|
|
1123
|
-
state.messages.push(
|
|
1124
|
-
{ id: uid(), role: "user", content: text, status: "done" },
|
|
1125
|
-
{ id: uid(), role: "assistant", content: "", status: "streaming", toolCalls: [] }
|
|
1126
|
-
);
|
|
1127
|
-
startStream();
|
|
1128
|
-
}
|
|
1129
|
-
function stop() {
|
|
1130
|
-
handle?.abort();
|
|
1131
|
-
state.streaming = false;
|
|
1132
|
-
state.step = null;
|
|
1133
|
-
const m = state.messages[state.messages.length - 1];
|
|
1134
|
-
if (m && m.role === "assistant" && m.status === "streaming") {
|
|
1135
|
-
if (!m.content && (!m.toolCalls || m.toolCalls.length === 0)) {
|
|
1136
|
-
state.messages.pop();
|
|
1137
|
-
} else {
|
|
1138
|
-
m.status = "done";
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
function retry() {
|
|
1143
|
-
if (state.streaming) return;
|
|
1144
|
-
let idx = -1;
|
|
1145
|
-
for (let i = state.messages.length - 1; i >= 0; i--) {
|
|
1146
|
-
if (state.messages[i].role === "user") {
|
|
1147
|
-
idx = i;
|
|
1148
|
-
break;
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
if (idx === -1) return;
|
|
1152
|
-
state.messages.splice(idx + 1);
|
|
1153
|
-
state.error = null;
|
|
1154
|
-
state.usage = null;
|
|
1155
|
-
state.step = null;
|
|
1156
|
-
state.messages.push({ id: uid(), role: "assistant", content: "", status: "streaming", toolCalls: [] });
|
|
1157
|
-
startStream();
|
|
1158
|
-
}
|
|
1159
|
-
function clear() {
|
|
1160
|
-
handle?.abort();
|
|
1161
|
-
state.messages = [];
|
|
1162
|
-
state.input = "";
|
|
1163
|
-
state.streaming = false;
|
|
1164
|
-
state.error = null;
|
|
1165
|
-
state.usage = null;
|
|
1166
|
-
state.step = null;
|
|
1167
|
-
}
|
|
1168
|
-
async function approve(decision, note) {
|
|
1169
|
-
const m = state.messages[state.messages.length - 1];
|
|
1170
|
-
const req = m?.role === "assistant" ? m.approval : void 0;
|
|
1171
|
-
if (!req) return;
|
|
1172
|
-
m.approval = void 0;
|
|
1173
|
-
if (!options.approveUrl) return;
|
|
1174
|
-
try {
|
|
1175
|
-
await fetch(options.approveUrl, {
|
|
1176
|
-
method: "POST",
|
|
1177
|
-
headers: { "Content-Type": "application/json", ...options.headers },
|
|
1178
|
-
body: JSON.stringify({ id: req.id, decision, note }),
|
|
1179
|
-
signal: options.signal
|
|
1180
|
-
});
|
|
1181
|
-
} catch (err) {
|
|
1182
|
-
if (options.signal?.aborted) return;
|
|
1183
|
-
state.error = { code: "provider_error", message: err instanceof Error ? err.message : String(err) };
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
function dispose() {
|
|
1187
|
-
handle?.abort();
|
|
1188
|
-
handle = null;
|
|
1189
|
-
}
|
|
1190
|
-
return { send, stop, retry, clear, approve, dispose };
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
// src/client/app.ts
|
|
1194
|
-
function createApp() {
|
|
1195
|
-
const middlewares = [];
|
|
1196
|
-
let ctx = {};
|
|
1197
|
-
let container = null;
|
|
1198
|
-
let rootComponent = null;
|
|
1199
|
-
let oldVNode = null;
|
|
1200
|
-
let _rendering = false;
|
|
1201
|
-
let _dirtyBatch = /* @__PURE__ */ new Set();
|
|
1202
|
-
let _dirtyScheduled = false;
|
|
1203
|
-
const _mediaRegistry = /* @__PURE__ */ new Map();
|
|
1204
|
-
const _popupTrackers = /* @__PURE__ */ new Map();
|
|
1205
|
-
let _popupListenersReady = false;
|
|
1206
|
-
let _popupRaf = 0;
|
|
1207
|
-
function schedulePopupRecompute() {
|
|
1208
|
-
if (_popupRaf) return;
|
|
1209
|
-
_popupRaf = requestAnimationFrame(() => {
|
|
1210
|
-
_popupRaf = 0;
|
|
1211
|
-
const ids = [];
|
|
1212
|
-
for (const [id, t] of _popupTrackers) {
|
|
1213
|
-
if (!t.isOpen()) continue;
|
|
1214
|
-
const el = t.getEl();
|
|
1215
|
-
if (!el) continue;
|
|
1216
|
-
const p = t.compute(el.getBoundingClientRect());
|
|
1217
|
-
Object.assign(t.pos, p);
|
|
1218
|
-
ids.push(id);
|
|
1219
|
-
}
|
|
1220
|
-
if (ids.length > 0) ctx.ui.render(ids);
|
|
1221
|
-
});
|
|
1222
|
-
}
|
|
1223
|
-
function renderByIds(ids) {
|
|
1224
|
-
if (_rendering) return;
|
|
1225
|
-
_rendering = true;
|
|
1226
|
-
for (const id of ids) {
|
|
1227
|
-
const vnode = idRegistry.get(id);
|
|
1228
|
-
if (!vnode || !vnode._render) continue;
|
|
1229
|
-
ctx.ui._dirtySet?.delete(id);
|
|
1230
|
-
const oldChild = vnode._child;
|
|
1231
|
-
const newChild = vnode._render(vnode.props);
|
|
1232
|
-
vnode._child = newChild;
|
|
1233
|
-
if (oldChild && oldChild._placement === "remote" || newChild && newChild._placement === "remote") {
|
|
1234
|
-
if (oldChild && newChild) {
|
|
1235
|
-
patchPortal(oldChild, newChild, ctx);
|
|
1236
|
-
} else if (newChild) {
|
|
1237
|
-
renderPortal(newChild, ctx);
|
|
1238
|
-
} else if (oldChild) {
|
|
1239
|
-
callRefCleanup(oldChild);
|
|
1240
|
-
}
|
|
1241
|
-
continue;
|
|
1242
|
-
}
|
|
1243
|
-
if (!vnode._parentNode && vnode._refNode) {
|
|
1244
|
-
;
|
|
1245
|
-
vnode._parentNode = vnode._refNode.parentNode;
|
|
1246
|
-
}
|
|
1247
|
-
if (vnode._parentNode) {
|
|
1248
|
-
const newNode = patchValue(
|
|
1249
|
-
vnode._parentNode,
|
|
1250
|
-
vnode._refNode ?? null,
|
|
1251
|
-
oldChild,
|
|
1252
|
-
newChild,
|
|
1253
|
-
ctx
|
|
1254
|
-
);
|
|
1255
|
-
if (newNode && newNode !== vnode._refNode) {
|
|
1256
|
-
vnode._refNode = newNode;
|
|
1257
|
-
} else if (!newNode) {
|
|
1258
|
-
;
|
|
1259
|
-
vnode._refNode = null;
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
_rendering = false;
|
|
1264
|
-
flushDirtyBatch();
|
|
1265
|
-
}
|
|
1266
|
-
function flushDirtyBatch() {
|
|
1267
|
-
if (_dirtyBatch.size > 0 && !_dirtyScheduled) {
|
|
1268
|
-
_dirtyScheduled = true;
|
|
1269
|
-
queueMicrotask(() => {
|
|
1270
|
-
_dirtyScheduled = false;
|
|
1271
|
-
const batch = [..._dirtyBatch];
|
|
1272
|
-
_dirtyBatch.clear();
|
|
1273
|
-
if (batch.length > 0) renderByIds(batch);
|
|
1274
|
-
});
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
function getSelfId(uiObj) {
|
|
1278
|
-
return uiObj?._selfId ?? ctx.ui?._selfId;
|
|
1279
|
-
}
|
|
1280
|
-
const app = {
|
|
1281
|
-
get ctx() {
|
|
1282
|
-
return ctx;
|
|
1283
|
-
},
|
|
1284
|
-
use(mw) {
|
|
1285
|
-
middlewares.push(mw);
|
|
1286
|
-
return app;
|
|
1287
|
-
},
|
|
1288
|
-
async mount(rootSelector, RootComponent, options) {
|
|
1289
|
-
rootComponent = RootComponent;
|
|
1290
|
-
for (const mw of middlewares) {
|
|
1291
|
-
ctx = await mw(ctx);
|
|
1292
|
-
}
|
|
1293
|
-
const el = typeof rootSelector === "string" ? document.querySelector(rootSelector) : rootSelector;
|
|
1294
|
-
if (!el) throw new Error(`mount target not found: ${rootSelector}`);
|
|
1295
|
-
container = el;
|
|
1296
|
-
const hydrating = !!options?.hydrate;
|
|
1297
|
-
if (!hydrating) container.innerHTML = "";
|
|
1298
|
-
const dataCache = /* @__PURE__ */ new Map();
|
|
1299
|
-
const hydratedData = globalThis.__DATA__;
|
|
1300
|
-
if (hydratedData && typeof hydratedData === "object") {
|
|
1301
|
-
for (const [k, v] of Object.entries(hydratedData)) {
|
|
1302
|
-
dataCache.set(k, { value: v });
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
;
|
|
1306
|
-
ctx.data = {
|
|
1307
|
-
async get(key, fetcher) {
|
|
1308
|
-
const entry = dataCache.get(key);
|
|
1309
|
-
if (entry && "value" in entry) return entry.value;
|
|
1310
|
-
if (entry?.promise) return entry.promise;
|
|
1311
|
-
if (!fetcher) return void 0;
|
|
1312
|
-
const promise = Promise.resolve().then(() => fetcher()).then((val) => {
|
|
1313
|
-
dataCache.set(key, { value: val });
|
|
1314
|
-
return val;
|
|
1315
|
-
});
|
|
1316
|
-
dataCache.set(key, { promise });
|
|
1317
|
-
return promise;
|
|
1318
|
-
},
|
|
1319
|
-
set(key, value) {
|
|
1320
|
-
dataCache.set(key, { value });
|
|
1321
|
-
},
|
|
1322
|
-
has(key) {
|
|
1323
|
-
return dataCache.has(key);
|
|
1324
|
-
}
|
|
1325
|
-
};
|
|
1326
|
-
ctx.ui = {
|
|
1327
|
-
_selfId: "_wf_root",
|
|
1328
|
-
// ── ctx 版本号(供三态 skip 判定) ──
|
|
1329
|
-
_ctxVersion: 0,
|
|
1330
|
-
_dirtySet: /* @__PURE__ */ new Set(),
|
|
1331
|
-
bumpCtxVersion: function() {
|
|
1332
|
-
this._ctxVersion++;
|
|
1333
|
-
},
|
|
1334
|
-
/** 同步刷新(无参 = 当前组件,传参 = 指定组件列表) */
|
|
1335
|
-
render: function(ids) {
|
|
1336
|
-
if (!ids || ids.length === 0) {
|
|
1337
|
-
const selfId = getSelfId(this);
|
|
1338
|
-
if (selfId) ids = [selfId];
|
|
1339
|
-
else return;
|
|
1340
|
-
}
|
|
1341
|
-
renderByIds(ids);
|
|
1342
|
-
},
|
|
1343
|
-
/** 异步刷新(微任务批处理,无参 = 当前组件) */
|
|
1344
|
-
dirty: function(ids) {
|
|
1345
|
-
if (_rendering) return;
|
|
1346
|
-
if (!ids || ids.length === 0) {
|
|
1347
|
-
const selfId = getSelfId(this);
|
|
1348
|
-
if (selfId) ids = [selfId];
|
|
1349
|
-
else return;
|
|
1350
|
-
}
|
|
1351
|
-
for (const id of ids) {
|
|
1352
|
-
if (id) {
|
|
1353
|
-
_dirtyBatch.add(id);
|
|
1354
|
-
ctx.ui._dirtySet.add(id);
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
if (!_dirtyScheduled) {
|
|
1358
|
-
_dirtyScheduled = true;
|
|
1359
|
-
queueMicrotask(() => {
|
|
1360
|
-
_dirtyScheduled = false;
|
|
1361
|
-
const batch = [..._dirtyBatch];
|
|
1362
|
-
_dirtyBatch.clear();
|
|
1363
|
-
if (batch.length > 0) renderByIds(batch);
|
|
1364
|
-
});
|
|
1365
|
-
}
|
|
1366
|
-
},
|
|
1367
|
-
/** 创建响应式状态容器:$.x = val 自动触发 dirty() */
|
|
1368
|
-
$: function() {
|
|
1369
|
-
if (!this._$cache) {
|
|
1370
|
-
const selfId = getSelfId(this);
|
|
1371
|
-
this._$cache = createReactiveState(() => ctx.ui.dirty([selfId]));
|
|
1372
|
-
}
|
|
1373
|
-
return this._$cache;
|
|
1374
|
-
},
|
|
1375
|
-
/**
|
|
1376
|
-
* AI 对话会话(会话语义 + 工具调用内嵌 + HITL 审批)
|
|
1377
|
-
*
|
|
1378
|
-
* 用法(mount 阶段):
|
|
1379
|
-
* const $ = ctx.ui.useChat({ url: '/api/chat', approveUrl: '/api/approve' })
|
|
1380
|
-
* // 状态:$.messages / $.input / $.streaming / $.error / $.usage / $.step
|
|
1381
|
-
* // 操作:$.send() / $.stop() / $.retry() / $.clear() / $.approve('approved', note?)
|
|
1382
|
-
* // agent:msg.toolCalls(ToolCallCard 直接消费) / msg.approval(ApprovalCard)
|
|
1383
|
-
*
|
|
1384
|
-
* 返回组件同一个 $(WeakMap 缓存复用):chat 状态与页面状态共处一个容器。
|
|
1385
|
-
* 卸载时调用 $.dispose()(或经 ref cleanup)中止流,防泄漏。
|
|
1386
|
-
*/
|
|
1387
|
-
useChat: function(options2) {
|
|
1388
|
-
const state = this.$();
|
|
1389
|
-
const api2 = createChatSession(state, aiStream, options2);
|
|
1390
|
-
Object.assign(state, {
|
|
1391
|
-
send: api2.send,
|
|
1392
|
-
stop: api2.stop,
|
|
1393
|
-
retry: api2.retry,
|
|
1394
|
-
clear: api2.clear,
|
|
1395
|
-
approve: api2.approve,
|
|
1396
|
-
dispose: api2.dispose
|
|
1397
|
-
});
|
|
1398
|
-
return state;
|
|
1399
|
-
},
|
|
1400
|
-
/**
|
|
1401
|
-
* 响应式媒体查询:注册监听,值变化时自动 dirty
|
|
1402
|
-
*
|
|
1403
|
-
* 用法:
|
|
1404
|
-
* const $ = ctx.ui.$()
|
|
1405
|
-
* ctx.ui.useMedia('(max-width: 640px)', (v) => { $.isMobile = v })
|
|
1406
|
-
*
|
|
1407
|
-
* callback 会立即执行一次(取当前值),之后在变化时再次执行
|
|
1408
|
-
*/
|
|
1409
|
-
useMedia: function(query, callback) {
|
|
1410
|
-
const selfId = getSelfId(this);
|
|
1411
|
-
const key = `media:${selfId}:${query}`;
|
|
1412
|
-
if (!_mediaRegistry.has(key)) {
|
|
1413
|
-
const mql = window.matchMedia(query);
|
|
1414
|
-
callback(mql.matches);
|
|
1415
|
-
const handler = (e) => callback(e.matches);
|
|
1416
|
-
mql.addEventListener("change", handler);
|
|
1417
|
-
_mediaRegistry.set(key, { mql, handler });
|
|
1418
|
-
}
|
|
1419
|
-
},
|
|
1420
|
-
/**
|
|
1421
|
-
* 响应式断点:注册命名断点监听,值变化时自动 dirty
|
|
1422
|
-
*
|
|
1423
|
-
* 用法:
|
|
1424
|
-
* const $ = ctx.ui.$()
|
|
1425
|
-
* ctx.ui.useBreakpoint((vp) => { $.vp = vp })
|
|
1426
|
-
* // vp: 'mobile' | 'tablet' | 'desktop'
|
|
1427
|
-
*
|
|
1428
|
-
* 自定义断点:
|
|
1429
|
-
* ctx.ui.useBreakpoint(
|
|
1430
|
-
* { narrow: '(max-width: 480px)', wide: '(min-width: 1200px)' },
|
|
1431
|
-
* (vp) => { $.size = vp }
|
|
1432
|
-
* )
|
|
1433
|
-
*/
|
|
1434
|
-
useBreakpoint: function(bpsOrCallback, callback) {
|
|
1435
|
-
const bps = typeof bpsOrCallback === "function" ? { mobile: "(max-width: 639px)", tablet: "(min-width: 640px) and (max-width: 1023px)", desktop: "(min-width: 1024px)" } : bpsOrCallback;
|
|
1436
|
-
const cb = typeof bpsOrCallback === "function" ? bpsOrCallback : callback;
|
|
1437
|
-
const selfId = getSelfId(this);
|
|
1438
|
-
const key = `bp:${selfId}`;
|
|
1439
|
-
function evaluate() {
|
|
1440
|
-
for (const [name, query] of Object.entries(bps)) {
|
|
1441
|
-
if (window.matchMedia(query).matches) return name;
|
|
1442
|
-
}
|
|
1443
|
-
return Object.keys(bps)[0] ?? "";
|
|
1444
|
-
}
|
|
1445
|
-
if (!_mediaRegistry.has(key)) {
|
|
1446
|
-
cb(evaluate());
|
|
1447
|
-
const handlers = [];
|
|
1448
|
-
for (const query of Object.values(bps)) {
|
|
1449
|
-
const mql = window.matchMedia(query);
|
|
1450
|
-
const handler = () => cb(evaluate());
|
|
1451
|
-
mql.addEventListener("change", handler);
|
|
1452
|
-
handlers.push(() => mql.removeEventListener("change", handler));
|
|
1453
|
-
}
|
|
1454
|
-
_mediaRegistry.set(key, { mql: null, handler: null });
|
|
1455
|
-
}
|
|
1456
|
-
},
|
|
1457
|
-
/**
|
|
1458
|
-
* 弹层位置跟踪:滚动/resize 时自动重算 fixed 坐标
|
|
1459
|
-
*
|
|
1460
|
-
* 用法(mount 阶段):
|
|
1461
|
-
* const pos = ctx.ui.usePopupPosition({
|
|
1462
|
-
* el: () => inputEl, // ref 保存的锚定元素
|
|
1463
|
-
* isOpen: () => show, // 弹层是否显示
|
|
1464
|
-
* compute: (r) => ({ top: r.bottom + 4, left: r.left }),
|
|
1465
|
-
* })
|
|
1466
|
-
*
|
|
1467
|
-
* pos 是稳定对象,render 闭包直接读取 top/left;
|
|
1468
|
-
* 滚动/resize 时自动重算并定向刷新;打开弹层瞬间调用 pos.refresh()。
|
|
1469
|
-
*/
|
|
1470
|
-
usePopupPosition: function(options2) {
|
|
1471
|
-
const selfId = getSelfId(this);
|
|
1472
|
-
const pos = { top: 0, left: 0, refresh: () => {
|
|
1473
|
-
} };
|
|
1474
|
-
if (!selfId) return pos;
|
|
1475
|
-
const tracker = {
|
|
1476
|
-
pos,
|
|
1477
|
-
getEl: options2.el,
|
|
1478
|
-
isOpen: options2.isOpen,
|
|
1479
|
-
compute: options2.compute
|
|
1480
|
-
};
|
|
1481
|
-
_popupTrackers.set(selfId, tracker);
|
|
1482
|
-
if (!_popupListenersReady) {
|
|
1483
|
-
_popupListenersReady = true;
|
|
1484
|
-
window.addEventListener("scroll", schedulePopupRecompute, { capture: true, passive: true });
|
|
1485
|
-
window.addEventListener("resize", schedulePopupRecompute);
|
|
1486
|
-
}
|
|
1487
|
-
pos.refresh = () => {
|
|
1488
|
-
const el2 = tracker.getEl();
|
|
1489
|
-
if (!el2) return;
|
|
1490
|
-
Object.assign(pos, tracker.compute(el2.getBoundingClientRect()));
|
|
1491
|
-
};
|
|
1492
|
-
return pos;
|
|
1493
|
-
},
|
|
1494
|
-
/** 注册组件实例的自定义 ID(用于跨组件精准刷新) */
|
|
1495
|
-
selfId: function(name) {
|
|
1496
|
-
if (typeof name !== "string" || !name) {
|
|
1497
|
-
throw new Error(`[weifuwu] selfId requires a non-empty string, got ${typeof name}`);
|
|
1498
|
-
}
|
|
1499
|
-
if (idRegistry.has(name)) {
|
|
1500
|
-
throw new Error(
|
|
1501
|
-
`[weifuwu] Duplicate component ID: "${name}". Each component must have a unique custom ID.`
|
|
1502
|
-
);
|
|
1503
|
-
}
|
|
1504
|
-
const vnode = this._selfVNode;
|
|
1505
|
-
if (!vnode) return;
|
|
1506
|
-
vnode._customId = name;
|
|
1507
|
-
idRegistry.set(name, vnode);
|
|
1508
|
-
}
|
|
1509
|
-
};
|
|
1510
|
-
_rendering = true;
|
|
1511
|
-
oldVNode = wrapComponent(RootComponent, ctx);
|
|
1512
|
-
oldVNode._id = "_wf_root";
|
|
1513
|
-
oldVNode._parentNode = container;
|
|
1514
|
-
oldVNode._refNode = hydrating ? container.firstChild : null;
|
|
1515
|
-
idRegistry.set("_wf_root", oldVNode);
|
|
1516
|
-
if (hydrating) {
|
|
1517
|
-
await hydrateVNode(container, oldVNode, ctx);
|
|
1518
|
-
} else {
|
|
1519
|
-
const node = render(oldVNode, ctx);
|
|
1520
|
-
if (node instanceof Node) container.appendChild(node);
|
|
1521
|
-
}
|
|
1522
|
-
oldVNode._refNode = container.firstChild;
|
|
1523
|
-
_rendering = false;
|
|
1524
|
-
flushDirtyBatch();
|
|
1525
|
-
},
|
|
1526
|
-
destroy() {
|
|
1527
|
-
if (container) container.innerHTML = "";
|
|
1528
|
-
container = null;
|
|
1529
|
-
ctx = {};
|
|
1530
|
-
if (_popupListenersReady) {
|
|
1531
|
-
window.removeEventListener("scroll", schedulePopupRecompute, { capture: true });
|
|
1532
|
-
window.removeEventListener("resize", schedulePopupRecompute);
|
|
1533
|
-
_popupListenersReady = false;
|
|
1534
|
-
_popupTrackers.clear();
|
|
1535
|
-
}
|
|
1536
|
-
}
|
|
1537
|
-
};
|
|
1538
|
-
return app;
|
|
1539
|
-
}
|
|
1540
|
-
function wrapComponent(Comp, _ctx) {
|
|
1541
|
-
return { type: Comp, props: {}, key: void 0 };
|
|
1542
|
-
}
|
|
1543
|
-
|
|
1544
|
-
// src/client/route-match.ts
|
|
1545
|
-
function joinPaths(a, b) {
|
|
1546
|
-
if (!b || b === "/") return a || "/";
|
|
1547
|
-
const left = a.endsWith("/") ? a.slice(0, -1) : a;
|
|
1548
|
-
const right = b.startsWith("/") ? b : "/" + b;
|
|
1549
|
-
return left + right;
|
|
1550
|
-
}
|
|
1551
|
-
function compilePath(path) {
|
|
1552
|
-
const keys = [];
|
|
1553
|
-
const reStr = path.replace(/:(\w+)/g, (_, key) => {
|
|
1554
|
-
keys.push(key);
|
|
1555
|
-
return "([^/]+)";
|
|
1556
|
-
}).replace(/\*/g, ".*");
|
|
1557
|
-
return { re: new RegExp(`^${reStr}$`), keys };
|
|
1558
|
-
}
|
|
1559
|
-
function flattenRoutes(routes, basePath = "", chain = []) {
|
|
1560
|
-
const result = [];
|
|
1561
|
-
for (const route of routes) {
|
|
1562
|
-
const fullPath = joinPaths(basePath, route.path);
|
|
1563
|
-
const { re, keys } = compilePath(fullPath);
|
|
1564
|
-
const fullChain = [...chain, route];
|
|
1565
|
-
result.push({ re, keys, def: route, chain: fullChain });
|
|
1566
|
-
if (route.children) {
|
|
1567
|
-
result.push(...flattenRoutes(route.children, fullPath, fullChain));
|
|
1568
|
-
}
|
|
1569
|
-
}
|
|
1570
|
-
return result;
|
|
1571
|
-
}
|
|
1572
|
-
function matchRoute(path, routes) {
|
|
1573
|
-
let best = null;
|
|
1574
|
-
for (const fr of routes) {
|
|
1575
|
-
if (path.match(fr.re)) {
|
|
1576
|
-
if (!best || fr.chain.length > best.chain.length) best = fr;
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
return best;
|
|
1580
|
-
}
|
|
1581
|
-
function extractParams(path, match) {
|
|
1582
|
-
const params = {};
|
|
1583
|
-
const m = path.match(match.re);
|
|
1584
|
-
if (m) {
|
|
1585
|
-
for (let i = 0; i < match.keys.length; i++) {
|
|
1586
|
-
params[match.keys[i]] = decodeURIComponent(m[i + 1]);
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
return params;
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
|
-
// src/client/router.ts
|
|
1593
|
-
function router(opts) {
|
|
1594
|
-
const flatRoutes = flattenRoutes(opts.routes);
|
|
1595
|
-
const mode = opts.mode || "history";
|
|
1596
|
-
function getPath() {
|
|
1597
|
-
if (mode === "hash") {
|
|
1598
|
-
const hash = window.location.hash.replace(/^#/, "") || "/";
|
|
1599
|
-
return hash;
|
|
1600
|
-
}
|
|
1601
|
-
return window.location.pathname;
|
|
1602
|
-
}
|
|
1603
|
-
function resolve(path) {
|
|
1604
|
-
const match = matchRoute(path, flatRoutes);
|
|
1605
|
-
if (match) {
|
|
1606
|
-
const last = match.chain[match.chain.length - 1];
|
|
1607
|
-
return {
|
|
1608
|
-
path: match.def.path,
|
|
1609
|
-
params: extractParams(path, match),
|
|
1610
|
-
query: Object.fromEntries(new URLSearchParams(window.location.search)),
|
|
1611
|
-
chain: match.chain,
|
|
1612
|
-
title: last?.title ?? ""
|
|
1613
|
-
};
|
|
1614
|
-
}
|
|
1615
|
-
return {
|
|
1616
|
-
path,
|
|
1617
|
-
params: {},
|
|
1618
|
-
query: Object.fromEntries(new URLSearchParams(window.location.search)),
|
|
1619
|
-
chain: opts.notFound ? [{ component: opts.notFound, title: "Not Found" }] : [],
|
|
1620
|
-
title: ""
|
|
1621
|
-
};
|
|
1622
|
-
}
|
|
1623
|
-
return (ctx) => {
|
|
1624
|
-
const resolved = resolve(getPath());
|
|
1625
|
-
ctx.route = resolved;
|
|
1626
|
-
if (resolved.title) document.title = resolved.title;
|
|
1627
|
-
if (!ctx.app) ctx.app = {};
|
|
1628
|
-
ctx.app.navigate = (path) => {
|
|
1629
|
-
clearAsyncComponentCache();
|
|
1630
|
-
if (mode === "hash") {
|
|
1631
|
-
window.location.hash = "#" + path;
|
|
1632
|
-
const resolved2 = resolve(path);
|
|
1633
|
-
ctx.route = resolved2;
|
|
1634
|
-
} else {
|
|
1635
|
-
window.history.pushState({}, "", path);
|
|
1636
|
-
const resolved2 = resolve(path);
|
|
1637
|
-
ctx.route = resolved2;
|
|
1638
|
-
}
|
|
1639
|
-
if (ctx.route?.title) document.title = ctx.route.title;
|
|
1640
|
-
ctx.ui?.bumpCtxVersion?.();
|
|
1641
|
-
ctx.ui?.render();
|
|
1642
|
-
};
|
|
1643
|
-
const onPop = () => {
|
|
1644
|
-
clearAsyncComponentCache();
|
|
1645
|
-
const resolved2 = resolve(getPath());
|
|
1646
|
-
ctx.route = resolved2;
|
|
1647
|
-
if (ctx.route?.title) document.title = ctx.route.title;
|
|
1648
|
-
ctx.ui?.bumpCtxVersion?.();
|
|
1649
|
-
ctx.ui?.render();
|
|
1650
|
-
};
|
|
1651
|
-
window.addEventListener("popstate", onPop);
|
|
1652
|
-
if (mode === "hash") {
|
|
1653
|
-
window.addEventListener("hashchange", onPop);
|
|
1654
|
-
}
|
|
1655
|
-
return ctx;
|
|
1656
|
-
};
|
|
1657
|
-
}
|
|
1658
|
-
function RouteView(_props, ctx) {
|
|
1659
|
-
const _depth = ctx.route?._rvDepth ?? 0;
|
|
1660
|
-
return () => {
|
|
1661
|
-
const route = ctx.route;
|
|
1662
|
-
if (!route?.chain?.length || _depth >= route.chain.length) return null;
|
|
1663
|
-
const def = route.chain[_depth];
|
|
1664
|
-
const Comp = def.layout ?? def.component;
|
|
1665
|
-
if (!Comp) return null;
|
|
1666
|
-
if (def.layout) {
|
|
1667
|
-
route._rvDepth = _depth + 1;
|
|
1668
|
-
}
|
|
1669
|
-
return { type: Comp, props: {}, key: void 0 };
|
|
1670
|
-
};
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
// src/client/types.ts
|
|
1674
|
-
function extendCtx(ctx, fields) {
|
|
1675
|
-
return Object.assign(Object.create(ctx), fields);
|
|
1676
|
-
}
|
|
1677
|
-
|
|
1678
|
-
// src/client/middleware/ws.ts
|
|
1679
|
-
function ws(options = {}) {
|
|
1680
|
-
const wsUrl = options.url ?? "/ws";
|
|
1681
|
-
const reconnectInterval = options.reconnectInterval ?? 3e3;
|
|
1682
|
-
const maxReconnect = options.maxReconnect ?? 10;
|
|
1683
|
-
const pingIntervalMs = options.pingInterval ?? 3e4;
|
|
1684
|
-
const pingTimeoutMs = options.pingTimeout ?? 1e4;
|
|
1685
|
-
return (ctx) => {
|
|
1686
|
-
const messageHandlers = /* @__PURE__ */ new Set();
|
|
1687
|
-
let socket = null;
|
|
1688
|
-
let reconnectAttempts = 0;
|
|
1689
|
-
let reconnectTimer = null;
|
|
1690
|
-
let pingTimer = null;
|
|
1691
|
-
let pingTimeoutTimer = null;
|
|
1692
|
-
let destroyed = false;
|
|
1693
|
-
const wsClient = {
|
|
1694
|
-
isConnected: false,
|
|
1695
|
-
onMessage: (fn) => {
|
|
1696
|
-
messageHandlers.add(fn);
|
|
1697
|
-
return () => {
|
|
1698
|
-
messageHandlers.delete(fn);
|
|
1699
|
-
};
|
|
1700
|
-
},
|
|
1701
|
-
send: (msg) => {
|
|
1702
|
-
if (socket?.readyState === WebSocket.OPEN) {
|
|
1703
|
-
socket.send(JSON.stringify(msg));
|
|
1704
|
-
}
|
|
1705
|
-
},
|
|
1706
|
-
_connect: connect,
|
|
1707
|
-
/** 断开连接并清理所有定时器 */
|
|
1708
|
-
close: () => {
|
|
1709
|
-
destroyed = true;
|
|
1710
|
-
clearTimers();
|
|
1711
|
-
socket?.close();
|
|
1712
|
-
socket = null;
|
|
1713
|
-
wsClient.isConnected = false;
|
|
1714
|
-
}
|
|
1715
|
-
};
|
|
1716
|
-
async function connect() {
|
|
1717
|
-
if (destroyed) return;
|
|
1718
|
-
try {
|
|
1719
|
-
socket = new WebSocket(wsUrl);
|
|
1720
|
-
socket.onopen = () => {
|
|
1721
|
-
wsClient.isConnected = true;
|
|
1722
|
-
reconnectAttempts = 0;
|
|
1723
|
-
startPing();
|
|
1724
|
-
};
|
|
1725
|
-
socket.onmessage = (e) => {
|
|
1726
|
-
try {
|
|
1727
|
-
const data = JSON.parse(e.data);
|
|
1728
|
-
for (const handler of messageHandlers) handler(data);
|
|
1729
|
-
} catch {
|
|
1730
|
-
}
|
|
1731
|
-
resetPingTimeout();
|
|
1732
|
-
};
|
|
1733
|
-
socket.onclose = () => {
|
|
1734
|
-
wsClient.isConnected = false;
|
|
1735
|
-
clearTimers();
|
|
1736
|
-
if (!destroyed && reconnectAttempts < maxReconnect) {
|
|
1737
|
-
reconnectAttempts++;
|
|
1738
|
-
reconnectTimer = setTimeout(connect, reconnectInterval * Math.min(reconnectAttempts, 5));
|
|
1739
|
-
}
|
|
1740
|
-
};
|
|
1741
|
-
socket.onerror = () => {
|
|
1742
|
-
socket?.close();
|
|
1743
|
-
};
|
|
1744
|
-
} catch {
|
|
1745
|
-
if (!destroyed) {
|
|
1746
|
-
reconnectTimer = setTimeout(connect, reconnectInterval);
|
|
1747
|
-
}
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1750
|
-
function startPing() {
|
|
1751
|
-
if (pingIntervalMs <= 0) return;
|
|
1752
|
-
pingTimer = setInterval(() => {
|
|
1753
|
-
if (socket?.readyState === WebSocket.OPEN) {
|
|
1754
|
-
socket.send(JSON.stringify({ type: "ping" }));
|
|
1755
|
-
}
|
|
1756
|
-
pingTimeoutTimer = setTimeout(() => {
|
|
1757
|
-
socket?.close();
|
|
1758
|
-
}, pingTimeoutMs);
|
|
1759
|
-
}, pingIntervalMs);
|
|
1760
|
-
}
|
|
1761
|
-
function resetPingTimeout() {
|
|
1762
|
-
clearTimeout(pingTimeoutTimer);
|
|
1763
|
-
}
|
|
1764
|
-
function clearTimers() {
|
|
1765
|
-
clearInterval(pingTimer);
|
|
1766
|
-
clearTimeout(pingTimeoutTimer);
|
|
1767
|
-
clearTimeout(reconnectTimer);
|
|
1768
|
-
}
|
|
1769
|
-
connect();
|
|
1770
|
-
return extendCtx(ctx, { ws: wsClient });
|
|
1771
|
-
};
|
|
1772
|
-
}
|
|
1773
|
-
|
|
1774
|
-
// src/client/middleware/api.ts
|
|
1775
|
-
function api(options) {
|
|
1776
|
-
const opts = {
|
|
1777
|
-
baseURL: options?.baseURL ?? "",
|
|
1778
|
-
headers: { "Content-Type": "application/json", ...options?.headers }
|
|
1779
|
-
};
|
|
1780
|
-
const onRequest = options?.onRequest;
|
|
1781
|
-
const onResponse = options?.onResponse;
|
|
1782
|
-
const timeoutMs = options?.timeout ?? 0;
|
|
1783
|
-
async function request(method, url, body, reqOpts) {
|
|
1784
|
-
const fullURL = opts.baseURL + url;
|
|
1785
|
-
const init = {
|
|
1786
|
-
method,
|
|
1787
|
-
headers: { ...opts.headers, ...reqOpts?.headers }
|
|
1788
|
-
};
|
|
1789
|
-
const hasTimeout = timeoutMs > 0;
|
|
1790
|
-
const hasUserSignal = !!reqOpts?.signal;
|
|
1791
|
-
let abortController = null;
|
|
1792
|
-
let timer = null;
|
|
1793
|
-
if (hasTimeout || hasUserSignal) {
|
|
1794
|
-
abortController = new AbortController();
|
|
1795
|
-
init.signal = abortController.signal;
|
|
1796
|
-
if (hasTimeout) {
|
|
1797
|
-
timer = setTimeout(() => abortController.abort(new Error("Request timed out")), timeoutMs);
|
|
1798
|
-
}
|
|
1799
|
-
if (hasUserSignal) {
|
|
1800
|
-
reqOpts.signal.addEventListener("abort", () => abortController.abort());
|
|
1801
|
-
}
|
|
1802
|
-
}
|
|
1803
|
-
if (body !== void 0 && method !== "GET" && method !== "HEAD") {
|
|
1804
|
-
init.body = JSON.stringify(body);
|
|
1805
|
-
}
|
|
1806
|
-
let finalReq = { url: fullURL, init };
|
|
1807
|
-
if (onRequest) {
|
|
1808
|
-
finalReq = onRequest(finalReq);
|
|
1809
|
-
}
|
|
1810
|
-
try {
|
|
1811
|
-
const res = await fetch(finalReq.url, finalReq.init);
|
|
1812
|
-
if (onResponse) {
|
|
1813
|
-
return onResponse(res);
|
|
1814
|
-
}
|
|
1815
|
-
if (!res.ok) {
|
|
1816
|
-
const text = await res.text().catch(() => "");
|
|
1817
|
-
throw new ApiError(res.status, text || res.statusText);
|
|
1818
|
-
}
|
|
1819
|
-
const contentLength = res.headers.get("content-length");
|
|
1820
|
-
if (res.status === 204 || contentLength === "0") {
|
|
1821
|
-
return void 0;
|
|
1822
|
-
}
|
|
1823
|
-
const ct = (res.headers.get("content-type") || "").toLowerCase();
|
|
1824
|
-
if (ct.includes("application/json") || ct.includes("json")) {
|
|
1825
|
-
return res.json();
|
|
1826
|
-
}
|
|
1827
|
-
return res.text();
|
|
1828
|
-
} finally {
|
|
1829
|
-
if (timer) clearTimeout(timer);
|
|
1830
|
-
}
|
|
1831
|
-
}
|
|
1832
|
-
return (ctx) => {
|
|
1833
|
-
const client = {
|
|
1834
|
-
get: (url, reqOpts) => request("GET", url, void 0, reqOpts),
|
|
1835
|
-
post: (url, body, reqOpts) => request("POST", url, body, reqOpts),
|
|
1836
|
-
put: (url, body, reqOpts) => request("PUT", url, body, reqOpts),
|
|
1837
|
-
patch: (url, body, reqOpts) => request("PATCH", url, body, reqOpts),
|
|
1838
|
-
delete: (url, reqOpts) => request("DELETE", url, void 0, reqOpts)
|
|
1839
|
-
};
|
|
1840
|
-
return extendCtx(ctx, { api: client });
|
|
1841
|
-
};
|
|
1842
|
-
}
|
|
1843
|
-
var ApiError = class extends Error {
|
|
1844
|
-
status;
|
|
1845
|
-
body;
|
|
1846
|
-
constructor(status, body) {
|
|
1847
|
-
super(`API Error ${status}: ${body}`);
|
|
1848
|
-
this.name = "ApiError";
|
|
1849
|
-
this.status = status;
|
|
1850
|
-
this.body = body;
|
|
1851
|
-
}
|
|
1852
|
-
};
|
|
1853
|
-
|
|
1854
|
-
// src/client/middleware/auth.ts
|
|
1855
|
-
function decodeJWT(token) {
|
|
1856
|
-
try {
|
|
1857
|
-
const parts = token.split(".");
|
|
1858
|
-
if (parts.length !== 3) return null;
|
|
1859
|
-
const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
1860
|
-
return JSON.parse(atob(payload));
|
|
1861
|
-
} catch {
|
|
1862
|
-
return null;
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
function isTokenExpired(token) {
|
|
1866
|
-
const payload = decodeJWT(token);
|
|
1867
|
-
if (!payload?.exp) return true;
|
|
1868
|
-
return payload.exp * 1e3 - 3e4 < Date.now();
|
|
1869
|
-
}
|
|
1870
|
-
function auth(options) {
|
|
1871
|
-
const storage = options?.storage ?? localStorage;
|
|
1872
|
-
const tokenKey = options?.tokenKey ?? "weifuwu_token";
|
|
1873
|
-
const userKey = options?.userKey ?? "weifuwu_user";
|
|
1874
|
-
const refreshTokenKey = options?.refreshTokenKey ?? "weifuwu_refresh";
|
|
1875
|
-
const refreshEndpoint = options?.refreshEndpoint ?? "/api/auth/refresh";
|
|
1876
|
-
return (ctx) => {
|
|
1877
|
-
const savedToken = storage.getItem(tokenKey);
|
|
1878
|
-
const savedUserStr = storage.getItem(userKey);
|
|
1879
|
-
const authClient = {
|
|
1880
|
-
token: savedToken,
|
|
1881
|
-
user: savedUserStr ? JSON.parse(savedUserStr) : null,
|
|
1882
|
-
get isLoggedIn() {
|
|
1883
|
-
return this.token !== null;
|
|
1884
|
-
},
|
|
1885
|
-
login(newToken, newUser, refreshToken) {
|
|
1886
|
-
authClient.token = newToken;
|
|
1887
|
-
authClient.user = newUser;
|
|
1888
|
-
storage.setItem(tokenKey, newToken);
|
|
1889
|
-
storage.setItem(userKey, JSON.stringify(newUser));
|
|
1890
|
-
if (refreshToken) storage.setItem(refreshTokenKey, refreshToken);
|
|
1891
|
-
},
|
|
1892
|
-
logout() {
|
|
1893
|
-
authClient.token = null;
|
|
1894
|
-
authClient.user = null;
|
|
1895
|
-
storage.removeItem(tokenKey);
|
|
1896
|
-
storage.removeItem(userKey);
|
|
1897
|
-
storage.removeItem(refreshTokenKey);
|
|
1898
|
-
},
|
|
1899
|
-
setUser(newUser) {
|
|
1900
|
-
authClient.user = newUser;
|
|
1901
|
-
storage.setItem(userKey, JSON.stringify(newUser));
|
|
1902
|
-
},
|
|
1903
|
-
async refresh() {
|
|
1904
|
-
const rt = storage.getItem(refreshTokenKey);
|
|
1905
|
-
if (!rt) return false;
|
|
1906
|
-
try {
|
|
1907
|
-
const res = await fetch(refreshEndpoint, {
|
|
1908
|
-
method: "POST",
|
|
1909
|
-
headers: { "Content-Type": "application/json" },
|
|
1910
|
-
body: JSON.stringify({ refreshToken: rt })
|
|
1911
|
-
});
|
|
1912
|
-
if (!res.ok) {
|
|
1913
|
-
authClient.logout();
|
|
1914
|
-
return false;
|
|
1915
|
-
}
|
|
1916
|
-
const data = await res.json();
|
|
1917
|
-
authClient.token = data.token;
|
|
1918
|
-
storage.setItem(tokenKey, data.token);
|
|
1919
|
-
if (data.refreshToken) storage.setItem(refreshTokenKey, data.refreshToken);
|
|
1920
|
-
return true;
|
|
1921
|
-
} catch {
|
|
1922
|
-
return false;
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
};
|
|
1926
|
-
if (savedToken && isTokenExpired(savedToken)) {
|
|
1927
|
-
authClient.refresh().catch(() => {
|
|
1928
|
-
});
|
|
1929
|
-
}
|
|
1930
|
-
return extendCtx(ctx, { auth: authClient });
|
|
1931
|
-
};
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
// src/client/error-boundary.ts
|
|
1935
|
-
function ErrorBoundary(props, ctx) {
|
|
1936
|
-
let error = null;
|
|
1937
|
-
return (props2) => {
|
|
1938
|
-
if (error) {
|
|
1939
|
-
const fb = props2.fallback;
|
|
1940
|
-
if (typeof fb === "function") {
|
|
1941
|
-
return fb({ error });
|
|
1942
|
-
}
|
|
1943
|
-
return fb ?? null;
|
|
1944
|
-
}
|
|
1945
|
-
;
|
|
1946
|
-
ctx.ui._errorHandler = (err) => {
|
|
1947
|
-
error = err;
|
|
1948
|
-
ctx.ui.render();
|
|
1949
|
-
};
|
|
1950
|
-
const children = props2.children;
|
|
1951
|
-
try {
|
|
1952
|
-
return children ?? null;
|
|
1953
|
-
} catch (e) {
|
|
1954
|
-
error = e;
|
|
1955
|
-
const fb = props2.fallback;
|
|
1956
|
-
if (typeof fb === "function") {
|
|
1957
|
-
return fb({ error: e });
|
|
1958
|
-
}
|
|
1959
|
-
return fb ?? null;
|
|
1960
|
-
}
|
|
1961
|
-
};
|
|
1962
|
-
}
|
|
1963
|
-
|
|
1964
|
-
// src/client/locale/zh_CN.ts
|
|
1965
|
-
var zhCN = {
|
|
1966
|
-
components: {
|
|
1967
|
-
Button: { loading: "\u52A0\u8F7D\u4E2D..." },
|
|
1968
|
-
FileUpload: {
|
|
1969
|
-
placeholder: "\u70B9\u51FB\u6216\u62D6\u62FD\u4E0A\u4F20\u6587\u4EF6",
|
|
1970
|
-
supportedFormats: "\u652F\u6301\u683C\u5F0F: ",
|
|
1971
|
-
maxSize: "\u6700\u5927 ",
|
|
1972
|
-
remove: "\u5220\u9664"
|
|
1973
|
-
},
|
|
1974
|
-
Pagination: { ariaLabel: "\u5206\u9875" },
|
|
1975
|
-
ProgressBar: { ariaLabel: "\u8FDB\u5EA6" },
|
|
1976
|
-
Switch: { ariaLabel: "\u5207\u6362" },
|
|
1977
|
-
Breadcrumb: { ariaLabel: "\u9762\u5305\u5C51" },
|
|
1978
|
-
Modal: { ariaLabel: "\u5F39\u7A97" },
|
|
1979
|
-
Confirm: { confirmText: "\u786E\u5B9A", cancelText: "\u53D6\u6D88" },
|
|
1980
|
-
Drawer: { ariaLabel: "\u4FA7\u8FB9\u9762\u677F" },
|
|
1981
|
-
DatePicker: {
|
|
1982
|
-
w0: "\u65E5",
|
|
1983
|
-
w1: "\u4E00",
|
|
1984
|
-
w2: "\u4E8C",
|
|
1985
|
-
w3: "\u4E09",
|
|
1986
|
-
w4: "\u56DB",
|
|
1987
|
-
w5: "\u4E94",
|
|
1988
|
-
w6: "\u516D",
|
|
1989
|
-
hour: "\u65F6",
|
|
1990
|
-
minute: "\u5206",
|
|
1991
|
-
time: "\u65F6\u95F4",
|
|
1992
|
-
confirm: "\u786E\u5B9A",
|
|
1993
|
-
cancel: "\u53D6\u6D88",
|
|
1994
|
-
placeholder: "\u9009\u62E9\u65E5\u671F"
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
};
|
|
1998
|
-
|
|
1999
|
-
// src/client/locale/en_US.ts
|
|
2000
|
-
var enUS = {
|
|
2001
|
-
components: {
|
|
2002
|
-
Button: { loading: "Loading..." },
|
|
2003
|
-
FileUpload: {
|
|
2004
|
-
placeholder: "Click or drag to upload",
|
|
2005
|
-
supportedFormats: "Supported formats: ",
|
|
2006
|
-
maxSize: "Max size: ",
|
|
2007
|
-
remove: "Remove"
|
|
2008
|
-
},
|
|
2009
|
-
Pagination: { ariaLabel: "Pagination" },
|
|
2010
|
-
ProgressBar: { ariaLabel: "Progress" },
|
|
2011
|
-
Switch: { ariaLabel: "Toggle" },
|
|
2012
|
-
Breadcrumb: { ariaLabel: "Breadcrumb" },
|
|
2013
|
-
Modal: { ariaLabel: "Dialog" },
|
|
2014
|
-
Confirm: { confirmText: "OK", cancelText: "Cancel" },
|
|
2015
|
-
Drawer: { ariaLabel: "Panel" },
|
|
2016
|
-
DatePicker: {
|
|
2017
|
-
w0: "Su",
|
|
2018
|
-
w1: "Mo",
|
|
2019
|
-
w2: "Tu",
|
|
2020
|
-
w3: "We",
|
|
2021
|
-
w4: "Th",
|
|
2022
|
-
w5: "Fr",
|
|
2023
|
-
w6: "Sa",
|
|
2024
|
-
hour: "Hour",
|
|
2025
|
-
minute: "Min",
|
|
2026
|
-
time: "Time",
|
|
2027
|
-
confirm: "OK",
|
|
2028
|
-
cancel: "Cancel",
|
|
2029
|
-
placeholder: "Pick a date"
|
|
2030
|
-
}
|
|
2031
|
-
}
|
|
2032
|
-
};
|
|
2033
|
-
|
|
2034
|
-
// src/client/i18n.ts
|
|
2035
|
-
var LOCALE_PACKAGES = {
|
|
2036
|
-
"zh-CN": zhCN,
|
|
2037
|
-
"en-US": enUS
|
|
2038
|
-
};
|
|
2039
|
-
function resolveLang(locale) {
|
|
2040
|
-
if (LOCALE_PACKAGES[locale]) return locale;
|
|
2041
|
-
const prefix = locale.split("-")[0];
|
|
2042
|
-
const match = Object.keys(LOCALE_PACKAGES).find((k) => k.startsWith(prefix));
|
|
2043
|
-
return match ?? "zh-CN";
|
|
2044
|
-
}
|
|
2045
|
-
function i18n(opts = {}) {
|
|
2046
|
-
const { locale: raw = "zh-CN", messages = {}, components = {} } = opts;
|
|
2047
|
-
const lang = resolveLang(raw);
|
|
2048
|
-
const pkg = LOCALE_PACKAGES[lang];
|
|
2049
|
-
let merged = mergeLocales(pkg, messages, components);
|
|
2050
|
-
const state = {
|
|
2051
|
-
locale: lang,
|
|
2052
|
-
t: (key, fallback) => merged.messages?.[key] ?? fallback ?? key,
|
|
2053
|
-
setLocale: () => {
|
|
2054
|
-
},
|
|
2055
|
-
components: merged.components
|
|
2056
|
-
};
|
|
2057
|
-
return (ctx) => {
|
|
2058
|
-
;
|
|
2059
|
-
ctx.i18n = state;
|
|
2060
|
-
state.setLocale = (raw2) => {
|
|
2061
|
-
const lang2 = resolveLang(raw2);
|
|
2062
|
-
const pkg2 = LOCALE_PACKAGES[lang2];
|
|
2063
|
-
if (!pkg2) return;
|
|
2064
|
-
merged = mergeLocales(pkg2, messages, components);
|
|
2065
|
-
state.locale = lang2;
|
|
2066
|
-
state.components = merged.components;
|
|
2067
|
-
ctx?.ui?.bumpCtxVersion?.();
|
|
2068
|
-
ctx?.ui?.render();
|
|
2069
|
-
};
|
|
2070
|
-
return ctx;
|
|
2071
|
-
};
|
|
2072
|
-
}
|
|
2073
|
-
function mergeLocales(pkg, userMessages, userComponents) {
|
|
2074
|
-
return {
|
|
2075
|
-
messages: { ...pkg?.messages, ...userMessages },
|
|
2076
|
-
components: deepMerge(pkg?.components ?? {}, userComponents)
|
|
2077
|
-
};
|
|
2078
|
-
}
|
|
2079
|
-
function deepMerge(a, b) {
|
|
2080
|
-
const result = { ...a };
|
|
2081
|
-
for (const key of Object.keys(b)) {
|
|
2082
|
-
if (typeof b[key] === "object" && b[key] !== null && typeof result[key] === "object") {
|
|
2083
|
-
result[key] = { ...result[key], ...b[key] };
|
|
2084
|
-
} else {
|
|
2085
|
-
result[key] = b[key];
|
|
2086
|
-
}
|
|
2087
|
-
}
|
|
2088
|
-
return result;
|
|
2089
|
-
}
|
|
2090
|
-
|
|
2091
|
-
// src/client/scroll-lock.ts
|
|
2092
|
-
var lockedCount = 0;
|
|
2093
|
-
var originalOverflow = "";
|
|
2094
|
-
var originalPosition = "";
|
|
2095
|
-
var originalTop = "";
|
|
2096
|
-
var originalWidth = "";
|
|
2097
|
-
var scrollY = 0;
|
|
2098
|
-
function canLock() {
|
|
2099
|
-
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
2100
|
-
}
|
|
2101
|
-
function lockScroll() {
|
|
2102
|
-
lockedCount++;
|
|
2103
|
-
if (lockedCount > 1) return;
|
|
2104
|
-
if (!canLock()) return;
|
|
2105
|
-
scrollY = window.scrollY;
|
|
2106
|
-
const body = document.body;
|
|
2107
|
-
originalOverflow = body.style.overflow;
|
|
2108
|
-
originalPosition = body.style.position;
|
|
2109
|
-
originalTop = body.style.top;
|
|
2110
|
-
originalWidth = body.style.width;
|
|
2111
|
-
body.style.overflow = "hidden";
|
|
2112
|
-
const isIOS = /iPhone|iPad|iPod/.test(navigator.platform) || /Mac/.test(navigator.platform) && "ontouchend" in document;
|
|
2113
|
-
if (isIOS) {
|
|
2114
|
-
body.style.position = "fixed";
|
|
2115
|
-
body.style.top = `-${scrollY}px`;
|
|
2116
|
-
body.style.width = "100%";
|
|
2117
|
-
}
|
|
2118
|
-
}
|
|
2119
|
-
function unlockScroll() {
|
|
2120
|
-
lockedCount--;
|
|
2121
|
-
if (lockedCount > 0) return;
|
|
2122
|
-
if (!canLock()) return;
|
|
2123
|
-
const body = document.body;
|
|
2124
|
-
body.style.overflow = originalOverflow;
|
|
2125
|
-
body.style.position = originalPosition;
|
|
2126
|
-
body.style.top = originalTop;
|
|
2127
|
-
body.style.width = originalWidth;
|
|
2128
|
-
if (scrollY > 0) window.scrollTo(0, scrollY);
|
|
2129
|
-
}
|
|
2130
|
-
|
|
2131
|
-
// src/client/focus-trap.ts
|
|
2132
|
-
var FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
2133
|
-
function trapFocus(container) {
|
|
2134
|
-
const focusable = container.querySelectorAll(FOCUSABLE);
|
|
2135
|
-
if (focusable.length === 0) return () => {
|
|
2136
|
-
};
|
|
2137
|
-
const first = focusable[0];
|
|
2138
|
-
const last = focusable[focusable.length - 1];
|
|
2139
|
-
const handler = (e) => {
|
|
2140
|
-
if (e.key !== "Tab") return;
|
|
2141
|
-
if (e.shiftKey && document.activeElement === first) {
|
|
2142
|
-
e.preventDefault();
|
|
2143
|
-
last.focus();
|
|
2144
|
-
} else if (!e.shiftKey && document.activeElement === last) {
|
|
2145
|
-
e.preventDefault();
|
|
2146
|
-
first.focus();
|
|
2147
|
-
}
|
|
2148
|
-
};
|
|
2149
|
-
const prevFocused = document.activeElement;
|
|
2150
|
-
first.focus();
|
|
2151
|
-
container.addEventListener("keydown", handler);
|
|
2152
|
-
return () => {
|
|
2153
|
-
container.removeEventListener("keydown", handler);
|
|
2154
|
-
prevFocused?.focus();
|
|
2155
|
-
};
|
|
2156
|
-
}
|
|
2157
|
-
|
|
2158
|
-
// src/client/popup.ts
|
|
2159
|
-
function computeFixedPosRect(rect, placement = "bottom", gap = 6, center = true) {
|
|
2160
|
-
switch (placement) {
|
|
2161
|
-
case "bottom":
|
|
2162
|
-
return {
|
|
2163
|
-
top: rect.bottom + gap,
|
|
2164
|
-
left: center ? rect.left + rect.width / 2 : rect.left
|
|
2165
|
-
};
|
|
2166
|
-
case "top":
|
|
2167
|
-
return {
|
|
2168
|
-
top: rect.top - gap,
|
|
2169
|
-
left: center ? rect.left + rect.width / 2 : rect.left
|
|
2170
|
-
};
|
|
2171
|
-
case "left":
|
|
2172
|
-
return {
|
|
2173
|
-
top: center ? rect.top + rect.height / 2 : rect.top,
|
|
2174
|
-
left: rect.left - gap
|
|
2175
|
-
};
|
|
2176
|
-
case "right":
|
|
2177
|
-
return {
|
|
2178
|
-
top: center ? rect.top + rect.height / 2 : rect.top,
|
|
2179
|
-
left: rect.right + gap
|
|
2180
|
-
};
|
|
2181
|
-
}
|
|
2182
|
-
}
|
|
2183
|
-
function computeFixedPos(el, placement = "bottom", gap = 6, center = true) {
|
|
2184
|
-
return computeFixedPosRect(el.getBoundingClientRect(), placement, gap, center);
|
|
2185
|
-
}
|
|
2186
|
-
export {
|
|
2187
|
-
ApiError,
|
|
2188
|
-
ErrorBoundary,
|
|
2189
|
-
Fragment,
|
|
2190
|
-
Portal,
|
|
2191
|
-
RouteView,
|
|
2192
|
-
aiStream,
|
|
2193
|
-
api,
|
|
2194
|
-
asyncComponent,
|
|
2195
|
-
auth,
|
|
2196
|
-
computeFixedPos,
|
|
2197
|
-
computeFixedPosRect,
|
|
2198
|
-
createApp,
|
|
2199
|
-
createPortal,
|
|
2200
|
-
enUS,
|
|
2201
|
-
extendCtx,
|
|
2202
|
-
h,
|
|
2203
|
-
i18n,
|
|
2204
|
-
isAsyncComponent,
|
|
2205
|
-
jsx,
|
|
2206
|
-
jsxDEV,
|
|
2207
|
-
jsxs,
|
|
2208
|
-
lockScroll,
|
|
2209
|
-
router,
|
|
2210
|
-
toChatMessages,
|
|
2211
|
-
trapFocus,
|
|
2212
|
-
unlockScroll,
|
|
2213
|
-
ws,
|
|
2214
|
-
zhCN
|
|
2215
|
-
};
|
|
3
|
+
`);o=i.pop()??"";for(let l of i){let a="message",u="";for(let m of l.split(`
|
|
4
|
+
`))m.startsWith("event: ")?a=m.slice(7):m.startsWith("data: ")&&(u+=m.slice(6));if(u)try{yield{name:a,data:JSON.parse(u)}}catch{}}}}finally{t.releaseLock()}}function lt(e,t,n){n&&(e.length>=1e3&&e.shift(),e.push(t))}function ut(e){return e===401||e===403?"auth_failed":e===429?"rate_limited":e>=500?"provider_error":"invalid_request"}function ct(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`trace-${Date.now()}-${Math.random().toString(36).slice(2,10)}`}function Se(e){return e.map(t=>({role:t.role,content:t.content}))}function ce(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`msg-${Date.now()}-${Math.random().toString(36).slice(2,10)}`}function Ee(e,t,n){n.initialMessages?e.messages=structuredClone(n.initialMessages):e.messages===void 0&&(e.messages=[]),e.input===void 0&&(e.input=""),e.streaming===void 0&&(e.streaming=!1),e.error===void 0&&(e.error=null),e.usage===void 0&&(e.usage=null),e.step===void 0&&(e.step=null);let o=null;function r(){if(!e.streaming)return;let c=e.messages[e.messages.length-1];return c&&c.role==="assistant"&&c.status==="streaming"?c:void 0}function s(c,d,p){let g=r();switch(c){case"wf:token":g&&(g.content+=d.text);break;case"wf:tool_call":{g&&(g.toolCalls||(g.toolCalls=[]),g.toolCalls.push({call:d,status:"running"}));break}case"wf:tool_progress":{let h=d,w=g?.toolCalls?.find(v=>v.call.id===h.toolCallId);w&&(w.progress=h);break}case"wf:tool_result":{let h=d,w=g?.toolCalls?.find(v=>v.call.id===h.id);w&&(w.result=h,w.status=h.ok?"ok":"error");break}case"wf:approval_request":g&&(g.approval=d);break;case"wf:usage":g&&(g.usage=d);break;case"wf:step":e.step=d;break;case"wf:done":g&&(g.status="done",g.approval=void 0),e.streaming=!1,e.step=null;break;case"wf:error":g&&(g.status="error",g.error=d,g.approval=void 0),e.error=d,e.streaming=!1,e.step=null;break;default:p?.(c,d);break}}function i(){let c=n.body?n.body(e.messages):{messages:Se(e.messages)};o=t(n.url,c,{onToken:p=>s("wf:token",{text:p}),onToolCall:p=>s("wf:tool_call",p),onToolProgress:p=>s("wf:tool_progress",p),onToolResult:p=>s("wf:tool_result",p),onApproval:p=>s("wf:approval_request",p),onUsage:p=>s("wf:usage",p),onStep:p=>s("wf:step",p),onDone:p=>s("wf:done",p),onError:p=>s("wf:error",p),onEvent:(p,g)=>s(p,g,n.onEvent)},{signal:n.signal,headers:n.headers}),e.streaming=!0;let d=r();d&&o?.traceId&&(d.id=o.traceId)}function l(){if(e.streaming)return;let c=String(e.input??"").trim();c&&(e.input="",e.error=null,e.usage=null,e.step=null,e.messages.push({id:ce(),role:"user",content:c,status:"done"},{id:ce(),role:"assistant",content:"",status:"streaming",toolCalls:[]}),i())}function a(){o?.abort(),e.streaming=!1,e.step=null;let c=e.messages[e.messages.length-1];c&&c.role==="assistant"&&c.status==="streaming"&&(!c.content&&(!c.toolCalls||c.toolCalls.length===0)?e.messages.pop():c.status="done")}function u(){if(e.streaming)return;let c=-1;for(let d=e.messages.length-1;d>=0;d--)if(e.messages[d].role==="user"){c=d;break}c!==-1&&(e.messages.splice(c+1),e.error=null,e.usage=null,e.step=null,e.messages.push({id:ce(),role:"assistant",content:"",status:"streaming",toolCalls:[]}),i())}function m(){o?.abort(),e.messages=[],e.input="",e.streaming=!1,e.error=null,e.usage=null,e.step=null}async function y(c,d){let p=e.messages[e.messages.length-1],g=p?.role==="assistant"?p.approval:void 0;if(g&&(p.approval=void 0,!!n.approveUrl))try{await fetch(n.approveUrl,{method:"POST",headers:{"Content-Type":"application/json",...n.headers},body:JSON.stringify({id:g.id,decision:c,note:d}),signal:n.signal})}catch(h){if(n.signal?.aborted)return;e.error={code:"provider_error",message:h instanceof Error?h.message:String(h)}}}function f(){o?.abort(),o=null}return{send:l,stop:a,retry:u,clear:m,approve:y,dispose:f}}function Pe(e){let{ctx:t,renderByIds:n,getSelfId:o,dirtyBatch:r,dirtySet:s,mediaRegistry:i,popupTrackers:l,schedulePopupRecompute:a,ensurePopupListeners:u,isRendering:m}=e;return{_selfId:"_wf_root",_ctxVersion:0,_dirtySet:s,bumpCtxVersion:function(){this._ctxVersion++},render:function(f){if(!f||f.length===0){let c=o(this);if(c)f=[c];else return}n(f)},dirty:function(f){if(!m()){if(!f||f.length===0){let c=o(this);if(c)f=[c];else return}for(let c of f)c&&(r.add(c),s.add(c));this._dirtyScheduled||(this._dirtyScheduled=!0,queueMicrotask(()=>{this._dirtyScheduled=!1;let c=[...r];r.clear(),c.length>0&&n(c)}))}},$:function(){let f=this;if(!f._$cache){let c=o(this);f._$cache=le(()=>t.ui.dirty(c?[c]:void 0))}return f._$cache},useChat:function(f){let c=this.$(),d=Ee(c,ue,f);return Object.assign(c,{send:d.send,stop:d.stop,retry:d.retry,clear:d.clear,approve:d.approve,dispose:d.dispose}),c},useMedia:function(f,c){let p=`media:${o(this)}:${f}`;if(!i.has(p)){let g=window.matchMedia(f);c(g.matches);let h=w=>c(w.matches);g.addEventListener("change",h),i.set(p,{mql:g,handler:h})}},useBreakpoint:function(f,c){let d=typeof f=="function"?{mobile:"(max-width: 639px)",tablet:"(min-width: 640px) and (max-width: 1023px)",desktop:"(min-width: 1024px)"}:f,p=typeof f=="function"?f:c,h=`bp:${o(this)}`;function w(){for(let[v,C]of Object.entries(d))if(window.matchMedia(C).matches)return v;return Object.keys(d)[0]??""}if(!i.has(h)){p(w());let v=[];for(let C of Object.values(d)){let b=window.matchMedia(C),x=()=>p(w());b.addEventListener("change",x),v.push({mql:b,handler:x})}i.set(h,{mqls:v})}},usePopupPosition:function(f){let c=o(this),d={top:0,left:0,refresh:()=>{}};if(!c)return d;let p={pos:d,getEl:f.el,isOpen:f.isOpen,compute:f.compute};return l.set(c,p),u(),d.refresh=()=>{let g=p.getEl();g&&Object.assign(d,p.compute(g.getBoundingClientRect()))},d},useAsync:function(f){let c=o(this),d=le(()=>{t.ui&&t.ui.dirty(c?[c]:void 0)});d.loading=!0;let p=()=>{d.loading=!0,d.error=null,Promise.resolve().then(()=>f()).then(g=>{d.data=g,d.loading=!1}).catch(g=>{d.error=g,d.loading=!1})};return p(),d.reload=p,d},selfId:function(f){if(typeof f!="string"||!f)throw new Error(`[weifuwu] selfId requires a non-empty string, got ${typeof f}`);if(A.has(f))throw new Error(`[weifuwu] Duplicate component ID: "${f}". Each component must have a unique custom ID.`);let c=this._selfVNode;c&&(c._customId=f,A.set(f,c))}}}function ft(){let e=[],t={},n=null,o=null,r=null,s=!1,i=new Set,l=!1,a=new Map;function u(C){let b=a.get(C);b&&(b.mql&&b.handler&&b.mql.removeEventListener("change",b.handler),b.mqls?.forEach(({mql:x,handler:k})=>x.removeEventListener("change",k)),a.delete(C))}let m=new Map,y=!1,f=0;function c(){y||(y=!0,window.addEventListener("scroll",p,{capture:!0,passive:!0}),window.addEventListener("resize",p))}function d(){y&&(window.removeEventListener("scroll",p,{capture:!0}),window.removeEventListener("resize",p),y=!1)}function p(){f||(f=requestAnimationFrame(()=>{f=0;let C=[];for(let[b,x]of m){if(!x.isOpen())continue;let k=x.getEl();if(!k)continue;let R=x.compute(k.getBoundingClientRect());Object.assign(x.pos,R),C.push(b)}C.length>0&&t.ui.render(C)}))}function g(C){if(!s){s=!0;for(let b of C){let x=A.get(b);if(!x||!x._render)continue;t.ui._dirtySet?.delete(b);let k=x._child,R=x._render(x.props);if(x._child=R,k&&k._placement==="remote"||R&&R._placement==="remote"){k&&R?q(k,R,t):R?V(R,t):k&&_(k);continue}if(!x._parentNode&&x._refNode&&(x._parentNode=x._refNode.parentNode),x._parentNode){let E=M(x._parentNode,x._refNode??null,k,R,t);E&&E!==x._refNode?x._refNode=E:E||(x._refNode=null)}}s=!1,h()}}function h(){let C=t.ui;i.size>0&&!C._dirtyScheduled&&(C._dirtyScheduled=!0,queueMicrotask(()=>{C._dirtyScheduled=!1;let b=[...i];i.clear(),b.length>0&&g(b)}))}function w(C){return C?._selfId??t.ui?._selfId}let v={get ctx(){return t},use(C){return e.push(C),v},async mount(C,b,x){o=b;for(let T of e)t=await T(t);let k=typeof C=="string"?document.querySelector(C):C;if(!k)throw new Error(`mount target not found: ${C}`);n=k;let R=!!x?.hydrate;R||(n.innerHTML="");let E=new Map,Y=globalThis.__DATA__;if(Y&&typeof Y=="object")for(let[T,P]of Object.entries(Y))E.set(T,{value:P});if(t.data={async get(T,P){let O=E.get(T);if(O&&"value"in O)return O.value;if(O?.promise)return O.promise;if(!P)return;let me=Promise.resolve().then(()=>P()).then(ye=>(E.set(T,{value:ye}),ye));return E.set(T,{promise:me}),me},set(T,P){E.set(T,{value:P})},has(T){return E.has(T)}},Ce(T=>{for(let P of[...a.keys()])(P.startsWith(`media:${T}:`)||P===`bp:${T}`)&&u(P);m.delete(T)}),t.ui=Pe({ctx:t,renderByIds:g,getSelfId:w,dirtyBatch:i,dirtySet:new Set,mediaRegistry:a,popupTrackers:m,schedulePopupRecompute:p,ensurePopupListeners:c,destroyPopupListeners:d,isRendering:()=>s}),s=!0,r=dt(b,t),r._id="_wf_root",r._parentNode=n,r._refNode=R?n.firstChild:null,A.set("_wf_root",r),R)await ae(n,r,t);else{let T=Re(r,t);T instanceof Node&&n.appendChild(T)}r._refNode=n.firstChild,s=!1,h()},destroy(){d(),m.clear();for(let C of[...a.keys()])u(C);A.clear(),n&&(n.innerHTML=""),n=null,t={}}};return v}function dt(e,t){return{type:e,props:{},key:void 0}}function pt(e,t){if(!t||t==="/")return e||"/";let n=e.endsWith("/")?e.slice(0,-1):e,o=t.startsWith("/")?t:"/"+t;return n+o}function mt(e){let t=[],n=e.replace(/:(\w+)/g,(o,r)=>(t.push(r),"([^/]+)")).replace(/\*/g,".*");return{re:new RegExp(`^${n}$`),keys:t}}function fe(e,t="",n=[]){let o=[];for(let r of e){let s=pt(t,r.path),{re:i,keys:l}=mt(s),a=[...n,r];o.push({re:i,keys:l,def:r,chain:a}),r.children&&o.push(...fe(r.children,s,a))}return o}function Ne(e,t){let n=null;for(let o of t)e.match(o.re)&&(!n||o.chain.length>n.chain.length)&&(n=o);return n}function We(e,t){let n={},o=e.match(t.re);if(o)for(let r=0;r<t.keys.length;r++)n[t.keys[r]]=decodeURIComponent(o[r+1]);return n}function yt(e){let t=fe(e.routes),n=e.mode||"history";function o(){return n==="hash"?window.location.hash.replace(/^#/,"")||"/":window.location.pathname}function r(s){let i=Ne(s,t);if(i){let l=i.chain[i.chain.length-1];return{path:i.def.path,params:We(s,i),query:Object.fromEntries(new URLSearchParams(window.location.search)),chain:i.chain,title:l?.title??""}}return{path:s,params:{},query:Object.fromEntries(new URLSearchParams(window.location.search)),chain:e.notFound?[{component:e.notFound,title:"Not Found"}]:[],title:""}}return s=>{let i=r(o());s.route=i,i.title&&(document.title=i.title),s.app||(s.app={}),s.app.navigate=a=>{if(j(),n==="hash"){window.location.hash="#"+a;let u=r(a);s.route=u}else{window.history.pushState({},"",a);let u=r(a);s.route=u}s.route?.title&&(document.title=s.route.title),s.ui?.bumpCtxVersion?.(),s.ui?.render()};let l=()=>{j();let a=r(o());s.route=a,s.route?.title&&(document.title=s.route.title),s.ui?.bumpCtxVersion?.(),s.ui?.render()};return window.addEventListener("popstate",l),n==="hash"&&window.addEventListener("hashchange",l),s}}function gt(e,t){let n=t.route?._rvDepth??0;return()=>{let o=t.route;if(!o?.chain?.length||n>=o.chain.length)return null;let r=o.chain[n],s=r.layout??r.component;return s?(r.layout&&(o._rvDepth=n+1),{type:s,props:{},key:void 0}):null}}function L(e,t){return Object.assign(Object.create(e),t)}function ht(e={}){let t=e.url??"/ws",n=e.reconnectInterval??3e3,o=e.maxReconnect??10,r=e.pingInterval??3e4,s=e.pingTimeout??1e4;return i=>{let l=new Set,a=null,u=0,m=null,y=null,f=null,c=!1,d={isConnected:!1,onMessage:v=>(l.add(v),()=>{l.delete(v)}),send:v=>{a?.readyState===WebSocket.OPEN&&a.send(JSON.stringify(v))},_connect:p,close:()=>{c=!0,w(),a?.close(),a=null,d.isConnected=!1}};async function p(){if(!c)try{a=new WebSocket(t),a.onopen=()=>{d.isConnected=!0,u=0,g()},a.onmessage=v=>{try{let C=JSON.parse(v.data);for(let b of l)b(C)}catch{}h()},a.onclose=()=>{d.isConnected=!1,w(),!c&&u<o&&(u++,m=setTimeout(p,n*Math.min(u,5)))},a.onerror=()=>{a?.close()}}catch{c||(m=setTimeout(p,n))}}function g(){r<=0||(y=setInterval(()=>{a?.readyState===WebSocket.OPEN&&a.send(JSON.stringify({type:"ping"})),f=setTimeout(()=>{a?.close()},s)},r))}function h(){clearTimeout(f)}function w(){clearInterval(y),clearTimeout(f),clearTimeout(m)}return p(),L(i,{ws:d})}}function Ct(e){let t={baseURL:e?.baseURL??"",headers:{"Content-Type":"application/json",...e?.headers}},n=e?.onRequest,o=e?.onResponse,r=e?.timeout??0;async function s(i,l,a,u){let m=t.baseURL+l,y={method:i,headers:{...t.headers,...u?.headers}},f=e?.token?.();f&&!y.headers.Authorization&&(y.headers.Authorization=`Bearer ${f}`);let c=r>0,d=!!u?.signal,p=null,g=null;(c||d)&&(p=new AbortController,y.signal=p.signal,c&&(g=setTimeout(()=>p.abort(new Error("Request timed out")),r)),d&&u.signal.addEventListener("abort",()=>p.abort())),a!==void 0&&i!=="GET"&&i!=="HEAD"&&(y.body=JSON.stringify(a));let h={url:m,init:y};n&&(h=n(h));try{let w=await fetch(h.url,h.init);if(o)return o(w);if(!w.ok){let b=await w.text().catch(()=>"");throw new z(w.status,b||w.statusText)}let v=w.headers.get("content-length");if(w.status===204||v==="0")return;let C=(w.headers.get("content-type")||"").toLowerCase();return C.includes("application/json")||C.includes("json")?w.json():w.text()}finally{g&&clearTimeout(g)}}return i=>L(i,{api:{get:(a,u)=>s("GET",a,void 0,u),post:(a,u,m)=>s("POST",a,u,m),put:(a,u,m)=>s("PUT",a,u,m),patch:(a,u,m)=>s("PATCH",a,u,m),delete:(a,u)=>s("DELETE",a,void 0,u)}})}var z=class extends Error{status;body;constructor(t,n){super(`API Error ${t}: ${n}`),this.name="ApiError",this.status=t,this.body=n}};function xt(e){try{let t=e.split(".");if(t.length!==3)return null;let n=t[1].replace(/-/g,"+").replace(/_/g,"/");return JSON.parse(atob(n))}catch{return null}}function wt(e){let t=xt(e);return t?.exp?t.exp*1e3-3e4<Date.now():!0}function bt(e){let t=e?.storage??localStorage,n=e?.tokenKey??"weifuwu_token",o=e?.userKey??"weifuwu_user",r=e?.refreshTokenKey??"weifuwu_refresh",s=e?.refreshEndpoint??"/api/auth/refresh";return i=>{let l=t.getItem(n),a=t.getItem(o),u={token:l,user:a?JSON.parse(a):null,get isLoggedIn(){return this.token!==null},login(m,y,f){u.token=m,u.user=y,t.setItem(n,m),t.setItem(o,JSON.stringify(y)),f&&t.setItem(r,f)},logout(){u.token=null,u.user=null,t.removeItem(n),t.removeItem(o),t.removeItem(r)},setUser(m){u.user=m,t.setItem(o,JSON.stringify(m))},async refresh(){let m=t.getItem(r);if(!m)return!1;try{let y=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:m})});if(!y.ok)return u.logout(),!1;let f=await y.json();return u.token=f.token,t.setItem(n,f.token),f.refreshToken&&t.setItem(r,f.refreshToken),!0}catch{return!1}}};return l&&wt(l)&&u.refresh().catch(()=>{}),L(i,{auth:u})}}function vt(e,t){let n=null;return o=>{if(n){let s=o.fallback;return typeof s=="function"?s({error:n}):s??null}t.ui._errorHandler=s=>{n=s,t.ui.render()};let r=o.children;try{return r??null}catch(s){n=s;let i=o.fallback;return typeof i=="function"?i({error:s}):i??null}}}var de={components:{Button:{loading:"\u52A0\u8F7D\u4E2D..."},FileUpload:{placeholder:"\u70B9\u51FB\u6216\u62D6\u62FD\u4E0A\u4F20\u6587\u4EF6",supportedFormats:"\u652F\u6301\u683C\u5F0F: ",maxSize:"\u6700\u5927 ",remove:"\u5220\u9664"},Pagination:{ariaLabel:"\u5206\u9875"},ProgressBar:{ariaLabel:"\u8FDB\u5EA6"},Switch:{ariaLabel:"\u5207\u6362"},Breadcrumb:{ariaLabel:"\u9762\u5305\u5C51"},Modal:{ariaLabel:"\u5F39\u7A97"},Confirm:{confirmText:"\u786E\u5B9A",cancelText:"\u53D6\u6D88"},Drawer:{ariaLabel:"\u4FA7\u8FB9\u9762\u677F"},DatePicker:{w0:"\u65E5",w1:"\u4E00",w2:"\u4E8C",w3:"\u4E09",w4:"\u56DB",w5:"\u4E94",w6:"\u516D",hour:"\u65F6",minute:"\u5206",time:"\u65F6\u95F4",confirm:"\u786E\u5B9A",cancel:"\u53D6\u6D88",placeholder:"\u9009\u62E9\u65E5\u671F"}}};var pe={components:{Button:{loading:"Loading..."},FileUpload:{placeholder:"Click or drag to upload",supportedFormats:"Supported formats: ",maxSize:"Max size: ",remove:"Remove"},Pagination:{ariaLabel:"Pagination"},ProgressBar:{ariaLabel:"Progress"},Switch:{ariaLabel:"Toggle"},Breadcrumb:{ariaLabel:"Breadcrumb"},Modal:{ariaLabel:"Dialog"},Confirm:{confirmText:"OK",cancelText:"Cancel"},Drawer:{ariaLabel:"Panel"},DatePicker:{w0:"Su",w1:"Mo",w2:"Tu",w3:"We",w4:"Th",w5:"Fr",w6:"Sa",hour:"Hour",minute:"Min",time:"Time",confirm:"OK",cancel:"Cancel",placeholder:"Pick a date"}}};var G={"zh-CN":de,"en-US":pe};function Me(e){if(G[e])return e;let t=e.split("-")[0];return Object.keys(G).find(o=>o.startsWith(t))??"zh-CN"}function Tt(e={}){let{locale:t="zh-CN",messages:n={},components:o={}}=e,r=Me(t),s=G[r],i=Le(s,n,o),l={locale:r,t:(a,u)=>i.messages?.[a]??u??a,setLocale:()=>{},components:i.components};return a=>(a.i18n=l,l.setLocale=u=>{let m=Me(u),y=G[m];y&&(i=Le(y,n,o),l.locale=m,l.components=i.components,a?.ui?.bumpCtxVersion?.(),a?.ui?.render())},a)}function Le(e,t,n){return{messages:{...e?.messages,...t},components:_t(e?.components??{},n)}}function _t(e,t){let n={...e};for(let o of Object.keys(t))typeof t[o]=="object"&&t[o]!==null&&typeof n[o]=="object"?n[o]={...n[o],...t[o]}:n[o]=t[o];return n}var J=0,Ve="",Oe="",Ie="",je="",Q=0;function Ue(){return typeof window<"u"&&typeof document<"u"}function At(){if(J++,J>1||!Ue())return;Q=window.scrollY;let e=document.body;Ve=e.style.overflow,Oe=e.style.position,Ie=e.style.top,je=e.style.width,e.style.overflow="hidden",(/iPhone|iPad|iPod/.test(navigator.platform)||/Mac/.test(navigator.platform)&&"ontouchend"in document)&&(e.style.position="fixed",e.style.top=`-${Q}px`,e.style.width="100%")}function kt(){if(J--,J>0||!Ue())return;let e=document.body;e.style.overflow=Ve,e.style.position=Oe,e.style.top=Ie,e.style.width=je,Q>0&&window.scrollTo(0,Q)}var Rt='a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';function St(e){let t=e.querySelectorAll(Rt);if(t.length===0)return()=>{};let n=t[0],o=t[t.length-1],r=i=>{i.key==="Tab"&&(i.shiftKey&&document.activeElement===n?(i.preventDefault(),o.focus()):!i.shiftKey&&document.activeElement===o&&(i.preventDefault(),n.focus()))},s=document.activeElement;return queueMicrotask(()=>{n.focus()}),e.addEventListener("keydown",r),()=>{e.removeEventListener("keydown",r),s?.focus()}}function Et(e,t,n=400){let o=!1,r=()=>{o||(o=!0,e.removeEventListener("animationend",r),clearTimeout(s),t())};e.addEventListener("animationend",r);let s=setTimeout(r,n)}function He(e,t="bottom",n=6,o=!0){switch(t){case"bottom":return{top:e.bottom+n,left:o?e.left+e.width/2:e.left};case"top":return{top:e.top-n,left:o?e.left+e.width/2:e.left};case"left":return{top:o?e.top+e.height/2:e.top,left:e.left-n};case"right":return{top:o?e.top+e.height/2:e.top,left:e.right+n}}}function Pt(e,t="bottom",n=6,o=!0){return He(e.getBoundingClientRect(),t,n,o)}export{z as ApiError,vt as ErrorBoundary,W as Fragment,N as Portal,gt as RouteView,ue as aiStream,Et as animateOut,Ct as api,qe as asyncComponent,bt as auth,_ as callRefCleanup,j as clearAsyncComponentCache,Pt as computeFixedPos,He as computeFixedPosRect,ft as createApp,Be as createPortal,pe as enUS,L as extendCtx,$e as h,ae as hydrateVNode,Tt as i18n,I as isAsyncComponent,X as jsx,Fe as jsxDEV,De as jsxs,At as lockScroll,nt as mountVNode,M as patchValue,yt as router,Se as toChatMessages,St as trapFocus,kt as unlockScroll,ht as ws,de as zhCN};
|