atmx-web 0.44.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/atmx.es.js +679 -0
- package/{src/core/vendor/axiom_runtime.js → dist/atmx.umd.js} +20 -18
- package/package.json +4 -1
- package/justfile +0 -8
- package/scripts/upload.sh +0 -61
- package/src/core/callback.ts +0 -92
- package/src/core/context.ts +0 -56
- package/src/core/query.ts +0 -162
- package/src/core/router.ts +0 -91
- package/src/core/types.ts +0 -49
- package/src/core/wasm.ts +0 -223
- package/src/dom/components/engine-status.ts +0 -62
- package/src/dom/indicators.ts +0 -36
- package/src/dom/lifecycle.ts +0 -379
- package/src/dom/scanner.ts +0 -125
- package/src/index.ts +0 -78
- package/src/resolver/evaluator.ts +0 -46
- package/src/resolver/render.ts +0 -196
- package/tsconfig.json +0 -25
- package/vite-env.d.ts +0 -11
- package/vite.config.ts +0 -27
- /package/{public → dist}/.axiom +0 -0
- /package/{public → dist}/axiom_runtime.wasm +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
let wasm_bindgen = (function(exports) {
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.atmx={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=function(e){return e[e.Complete=0]=`Complete`,e[e.NetworkSuccess=1]=`NetworkSuccess`,e[e.CacheHit=2]=`CacheHit`,e[e.CacheHitAndFetching=3]=`CacheHitAndFetching`,e[e.Error=4]=`Error`,e}({}),n=new Map;function r(e){window.axiom_web_callback=(r,i,a,o,s,c,l)=>{let u=n.get(r);if(!u){o&&e.axiom_free_memory(o,s),c&&e.axiom_free_memory(c,l);return}let d=null,f=null;if(o!==0&&s>0){let t=new Uint8Array(e.memory.buffer);d=new Uint8Array(t.subarray(o,o+s)),e.axiom_free_memory(o,s)}if(c!==0&&l>0){let t=new Uint8Array(e.memory.buffer),n=new Uint8Array(t.subarray(c,c+l));f=new TextDecoder().decode(n),e.axiom_free_memory(c,l)}if(i===t.Complete){u.onComplete(),n.delete(r);return}if(i===t.Error){let e;if(f)try{e=JSON.parse(f)}catch(t){e={stage:`ffiBoundary`,category:`runtime`,code:`JsonParseFailure`,message:`Parse failed: ${t}`,retryable:!1}}else e={stage:`runtime`,category:`unknown`,code:a.toString(),message:`Internal Wasm error`,retryable:!1};u.onResponse({eventType:i,error:e}),u.onComplete(),n.delete(r);return}if(d)try{let e=new TextDecoder().decode(d),a=JSON.parse(e);u.onResponse({eventType:i,data:a,isFetching:i===t.CacheHitAndFetching,isStreamChunk:u.isStream}),!u.isStream&&i===t.NetworkSuccess&&(u.onComplete(),n.delete(r))}catch(e){console.error(`ATMX: Failed to parse JSON response from Axiom`,e)}}}var i=new Map;function a(e,t){let n=t?.ir?.endpoints;if(!n)return;let r=Array.isArray(n)?n:Object.values(n);r.forEach(t=>{let n=`${e}.${t.name}`,r=t.parameters?.find(e=>e.source===`body`)?.name||null;i.set(n,{id:t.id,namespace:e,name:t.name,method:t.method?t.method.toUpperCase():`GET`,pathTemplate:t.path,isStream:t.isStream||!1,auth:t.auth||null,bodyParam:r})}),console.log(`🛣️ ATMX Router: Mapped ${r.length} endpoints for '${e}'.`)}function o(e){return i.get(e.trim())||null}function s(e,t){let n=e.pathTemplate,r={...t},i=n.match(/\{([^}]+)\}/g);if(i&&i.forEach(e=>{let t=e.replace(/[{}]/g,``);r[t]!==void 0&&(n=n.replace(e,encodeURIComponent(String(r[t]))),delete r[t])}),e.method===`GET`&&Object.keys(r).length>0){let e=new URLSearchParams;for(let[t,n]of Object.entries(r))n!=null&&e.append(t,String(n));let t=n.includes(`?`)?`&`:`?`;n+=`${t}${e.toString()}`;for(let e of Object.keys(r))delete r[e]}return{path:n,remainingArgs:r}}var c=`let wasm_bindgen = (function(exports) {
|
|
2
2
|
let script_src;
|
|
3
3
|
if (typeof document !== 'undefined' && document.currentScript !== null) {
|
|
4
4
|
script_src = new URL(document.currentScript.src, location.href).toString();
|
|
@@ -492,32 +492,32 @@ let wasm_bindgen = (function(exports) {
|
|
|
492
492
|
return addHeapObject(ret);
|
|
493
493
|
},
|
|
494
494
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
495
|
-
// Cast intrinsic for
|
|
495
|
+
// Cast intrinsic for \`Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 198, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref\`.
|
|
496
496
|
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2406);
|
|
497
497
|
return addHeapObject(ret);
|
|
498
498
|
},
|
|
499
499
|
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
500
|
-
// Cast intrinsic for
|
|
500
|
+
// Cast intrinsic for \`Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 62, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref\`.
|
|
501
501
|
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2239);
|
|
502
502
|
return addHeapObject(ret);
|
|
503
503
|
},
|
|
504
504
|
__wbindgen_cast_0000000000000003: function(arg0, arg1) {
|
|
505
|
-
// Cast intrinsic for
|
|
505
|
+
// Cast intrinsic for \`Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("MessageEvent")], shim_idx: 62, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref\`.
|
|
506
506
|
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2239_2);
|
|
507
507
|
return addHeapObject(ret);
|
|
508
508
|
},
|
|
509
509
|
__wbindgen_cast_0000000000000004: function(arg0, arg1) {
|
|
510
|
-
// Cast intrinsic for
|
|
510
|
+
// Cast intrinsic for \`Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 111, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref\`.
|
|
511
511
|
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2246);
|
|
512
512
|
return addHeapObject(ret);
|
|
513
513
|
},
|
|
514
514
|
__wbindgen_cast_0000000000000005: function(arg0, arg1) {
|
|
515
|
-
// Cast intrinsic for
|
|
515
|
+
// Cast intrinsic for \`Ref(Slice(U8)) -> NamedExternref("Uint8Array")\`.
|
|
516
516
|
const ret = getArrayU8FromWasm0(arg0, arg1);
|
|
517
517
|
return addHeapObject(ret);
|
|
518
518
|
},
|
|
519
519
|
__wbindgen_cast_0000000000000006: function(arg0, arg1) {
|
|
520
|
-
// Cast intrinsic for
|
|
520
|
+
// Cast intrinsic for \`Ref(String) -> Externref\`.
|
|
521
521
|
const ret = getStringFromWasm0(arg0, arg1);
|
|
522
522
|
return addHeapObject(ret);
|
|
523
523
|
},
|
|
@@ -587,23 +587,23 @@ let wasm_bindgen = (function(exports) {
|
|
|
587
587
|
// primitive types
|
|
588
588
|
const type = typeof val;
|
|
589
589
|
if (type == 'number' || type == 'boolean' || val == null) {
|
|
590
|
-
return
|
|
590
|
+
return \`\${val}\`;
|
|
591
591
|
}
|
|
592
592
|
if (type == 'string') {
|
|
593
|
-
return
|
|
593
|
+
return \`"\${val}"\`;
|
|
594
594
|
}
|
|
595
595
|
if (type == 'symbol') {
|
|
596
596
|
const description = val.description;
|
|
597
597
|
if (description == null) {
|
|
598
598
|
return 'Symbol';
|
|
599
599
|
} else {
|
|
600
|
-
return
|
|
600
|
+
return \`Symbol(\${description})\`;
|
|
601
601
|
}
|
|
602
602
|
}
|
|
603
603
|
if (type == 'function') {
|
|
604
604
|
const name = val.name;
|
|
605
605
|
if (typeof name == 'string' && name.length > 0) {
|
|
606
|
-
return
|
|
606
|
+
return \`Function(\${name})\`;
|
|
607
607
|
} else {
|
|
608
608
|
return 'Function';
|
|
609
609
|
}
|
|
@@ -622,7 +622,7 @@ let wasm_bindgen = (function(exports) {
|
|
|
622
622
|
return debug;
|
|
623
623
|
}
|
|
624
624
|
// Test for built-in
|
|
625
|
-
const builtInMatches =
|
|
625
|
+
const builtInMatches = /\\[object ([^\\]]+)\\]/.exec(toString.call(val));
|
|
626
626
|
let className;
|
|
627
627
|
if (builtInMatches && builtInMatches.length > 1) {
|
|
628
628
|
className = builtInMatches[1];
|
|
@@ -633,7 +633,7 @@ let wasm_bindgen = (function(exports) {
|
|
|
633
633
|
if (className == 'Object') {
|
|
634
634
|
// we're a user defined class or Object
|
|
635
635
|
// JSON.stringify avoids problems with cycles, and is generally much
|
|
636
|
-
// easier than looping through ownProperties of
|
|
636
|
+
// easier than looping through ownProperties of \`val\`.
|
|
637
637
|
try {
|
|
638
638
|
return 'Object(' + JSON.stringify(val) + ')';
|
|
639
639
|
} catch (_) {
|
|
@@ -642,9 +642,9 @@ let wasm_bindgen = (function(exports) {
|
|
|
642
642
|
}
|
|
643
643
|
// errors
|
|
644
644
|
if (val instanceof Error) {
|
|
645
|
-
return
|
|
645
|
+
return \`\${val.name}: \${val.message}\\n\${val.stack}\`;
|
|
646
646
|
}
|
|
647
|
-
// TODO we could test for more things here, like
|
|
647
|
+
// TODO we could test for more things here, like \`Set\`s and \`Map\`s.
|
|
648
648
|
return className;
|
|
649
649
|
}
|
|
650
650
|
|
|
@@ -809,7 +809,7 @@ let wasm_bindgen = (function(exports) {
|
|
|
809
809
|
const validResponse = module.ok && expectedResponseType(module.type);
|
|
810
810
|
|
|
811
811
|
if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
|
|
812
|
-
console.warn("
|
|
812
|
+
console.warn("\`WebAssembly.instantiateStreaming\` failed because your server does not serve Wasm with \`application/wasm\` MIME type. Falling back to \`WebAssembly.instantiate\` which is slower. Original error:\\n", e);
|
|
813
813
|
|
|
814
814
|
} else { throw e; }
|
|
815
815
|
}
|
|
@@ -843,7 +843,7 @@ let wasm_bindgen = (function(exports) {
|
|
|
843
843
|
if (Object.getPrototypeOf(module) === Object.prototype) {
|
|
844
844
|
({module} = module)
|
|
845
845
|
} else {
|
|
846
|
-
console.warn('using deprecated parameters for
|
|
846
|
+
console.warn('using deprecated parameters for \`initSync()\`; pass a single object instead')
|
|
847
847
|
}
|
|
848
848
|
}
|
|
849
849
|
|
|
@@ -868,7 +868,7 @@ let wasm_bindgen = (function(exports) {
|
|
|
868
868
|
}
|
|
869
869
|
|
|
870
870
|
if (module_or_path === undefined && script_src !== undefined) {
|
|
871
|
-
module_or_path = script_src.replace(
|
|
871
|
+
module_or_path = script_src.replace(/\\.js$/, "_bg.wasm");
|
|
872
872
|
}
|
|
873
873
|
const imports = __wbg_get_imports();
|
|
874
874
|
|
|
@@ -883,3 +883,5 @@ let wasm_bindgen = (function(exports) {
|
|
|
883
883
|
|
|
884
884
|
return Object.assign(__wbg_init, { initSync }, exports);
|
|
885
885
|
})({ __proto__: null });
|
|
886
|
+
`,l=null;function u(e){if(e.length===0)return 0;let t=l.axiom_malloc(e.length);return new Uint8Array(l.memory.buffer).set(e,t),t}function d(e){if(!e)return{ptr:0,len:0};let t=new TextEncoder().encode(e);return{ptr:u(t),len:t.length}}function f(){return`https://atmx.axiomcore.dev/latest/axiom_runtime.wasm`}async function p(e){let t=performance.now(),n={ok:!1,contracts:{},initDurationMs:0};try{if(!window.wasm_bindgen){let e=document.createElement(`script`);e.type=`text/javascript`,e.text=`${c}\nwindow.wasm_bindgen = wasm_bindgen;`,document.head.appendChild(e)}let t=window.wasm_bindgen,i=`${f()}?t=${Date.now()}`;try{l=await t(fetch(i))}catch(e){throw{stage:`ffiBoundary`,category:`network`,code:`WasmFetchFailed`,message:`Failed to download WASM engine: ${e.message}`,retryable:!0}}r(l),setInterval(()=>{l&&l.axiom_process_responses()},16);let o=d(``),s=l.axiom_wasm_initialize(o.ptr,o.len);if(l.axiom_free_memory(o.ptr,o.len),s!==0)throw{stage:`runtime`,category:`server`,code:`InitFailed`,message:`Engine init failed (Code: ${s})`,retryable:!1};for(let[t,r]of Object.entries(e.contracts))try{let i=await fetch(r.contractUrl);if(!i.ok)throw Error(`HTTP ${i.status}`);let o=await i.arrayBuffer(),s=0;try{let e=new TextDecoder().decode(o),n=JSON.parse(e),r=n?.ir?.endpoints;r&&(s=Array.isArray(r)?r.length:Object.keys(r).length),a(t,n)}catch(e){console.error(`ATMX: Failed to parse .axiom contract for '${t}'`,e)}let c=new Uint8Array(o),f=u(c),p=d(t),m=d(r.baseUrl),h=l.axiom_wasm_load_contract(p.ptr,p.len,m.ptr,m.len,f,c.length,0,0,0,0);if(l.axiom_free_memory(f,c.length),l.axiom_free_memory(p.ptr,p.len),l.axiom_free_memory(m.ptr,m.len),h!==0&&h!==-1)throw Error(`Load error (Code: ${h})`);e.debug&&console.log(`%c🔒 Axiom Contract Loaded: ${t} (${s} endpoints)`,`color: #10b981; font-weight: bold;`),n.contracts[t]={loaded:!0,endpointCount:s},document.dispatchEvent(new CustomEvent(`atmx:contract-loaded`,{detail:{namespace:t,endpointCount:s}}))}catch(e){n.contracts[t]={loaded:!1,endpointCount:0,error:e.message},console.error(`ATMX: Contract failed for ${t}`,e)}n.ok=!0}catch(e){n.ok=!1,n.error=e.stage?e:{stage:`runtime`,category:`unknown`,code:`FatalError`,message:e.message||String(e),retryable:!1}}return n.initDurationMs=Math.round(performance.now()-t),n}function m(e,t,n){if(!l)return;let r=d(e),i=d(t),a=d(n);l.axiom_wasm_set_auth_token(r.ptr,r.len,i.ptr,i.len,a.ptr,a.len),l.axiom_free_memory(r.ptr,r.len),l.axiom_free_memory(i.ptr,i.len),l.axiom_free_memory(a.ptr,a.len)}function h(e,t){if(!l)return;let n=d(e),r=d(t);l.axiom_wasm_clear_auth_token(n.ptr,n.len,r.ptr,r.len),l.axiom_free_memory(n.ptr,n.len),l.axiom_free_memory(r.ptr,r.len)}function g(e,t,n={}){if(e)try{let r=Object.keys(n),i=Object.values(n);return Function(`$data`,`$error`,`$state`,...r,`return (${e});`)(t.data||{},t.error||{},t,...i)}catch(t){console.error(`ATMX Eval Error: ${e}`,t);return}}function _(e,t,n={}){if(e)try{let r=Object.keys(n),i=Object.values(n);Function(`$data`,`$error`,`$state`,...r,e)(t.data||{},t.error||{},t,...i)}catch(t){console.error(`ATMX Action Error: ${e}`,t)}}function v(e,t){y(e,t,!0,{})}function y(e,t,n,r){if(!(!n&&(e.hasAttribute(`ax-query`)||e.hasAttribute(`ax-mutate`)))){if(e.hasAttribute(`ax-for`)){b(e,t,r);return}if(e.hasAttribute(`ax-when`)&&(e.getAttribute(`ax-when`).split(`,`).map(e=>e.trim()).includes(t.state)?(e.removeAttribute(`hidden`),e.style.removeProperty(`display`)):(e.setAttribute(`hidden`,`true`),e.style.setProperty(`display`,`none`,`important`))),e.hasAttribute(`ax-if`)&&(g(e.getAttribute(`ax-if`),t,r)?(e.removeAttribute(`hidden`),e.style.removeProperty(`display`)):(e.setAttribute(`hidden`,``),e.style.setProperty(`display`,`none`,`important`))),e.hasAttribute(`ax-text`)){let n=g(e.getAttribute(`ax-text`),t,r);e.textContent=n==null?``:String(n)}if(e.hasAttribute(`ax-error-for`)){let n=e.getAttribute(`ax-error-for`),r=``;if(t.state===`error`&&t.error?.code===`ValidationError`){let e=(t.error.details||``).split(`
|
|
887
|
+
`);for(let t of e)if(t.startsWith(n+`:`)){r=t.substring(n.length+1).trim();break}}r?(e.textContent=r,e.removeAttribute(`hidden`),e.style.removeProperty(`display`)):(e.setAttribute(`hidden`,``),e.style.setProperty(`display`,`none`,`important`))}Array.from(e.attributes).forEach(n=>{if(n.name.startsWith(`ax-bind:`)){let i=n.name.substring(8),a=g(n.value,t,r);a===!1||a==null?e.removeAttribute(i):e.setAttribute(i,a===!0?i:String(a))}}),Array.from(e.children).forEach(e=>{y(e,t,!1,r)})}}function b(e,t,n){e.style.display=`none`,e.hasAttribute(`data-ax-for-id`)||e.setAttribute(`data-ax-for-id`,Math.random().toString(36).substr(2,9));let r=e.getAttribute(`data-ax-for-id`),i=e.getAttribute(`ax-for`).match(/^\s*(?:(?:\(\s*([\w\$]+)\s*,\s*([\w\$]+)\s*\))|([\w\$]+))\s+in\s+(.+)$/);if(!i)return;let a=i[1]||i[3],o=i[2],s=i[4],c=g(s,t,n),l=e.parentElement;if(!l)return;let u=Array.from(l.querySelectorAll(`[data-ax-clone-of="${r}"]`));if(!c||!Array.isArray(c)){u.forEach(e=>e.remove());return}let d=e.getAttribute(`ax-key`),f=[];c.forEach((i,s)=>{let c={...n,[a]:i};o&&(c[o]=s);let p=String(s);d&&(p=String(g(d,t,c)));let m=u.find(e=>e.getAttribute(`data-ax-key`)===p);m||(m=e.cloneNode(!0),m.removeAttribute(`ax-for`),m.style.removeProperty(`display`),m.style.length===0&&m.removeAttribute(`style`),m.setAttribute(`data-ax-clone-of`,r),m.setAttribute(`data-ax-key`,p)),l.insertBefore(m,e),y(m,t,!1,c),f.push(m)}),u.forEach(e=>{f.includes(e)||e.remove()})}var x=new WeakMap;function S(e){return x.has(e)||x.set(e,{state:`idle`,isFetching:!1,isMutating:!1,source:null,data:null,error:null}),x.get(e)}function C(e){let t=e.parentElement;for(;t;){if(t.hasAttribute(`ax-query`)||t.hasAttribute(`ax-mutate`)){let e=x.get(t);if(e&&e.data)return e.data}t=t.parentElement}return{}}function w(e,t){let n=S(e);Object.assign(n,t),t.state===`loading`&&(n.isFetching=!0),t.state===`mutating`&&(n.isMutating=!0),(t.state===`success`||t.state===`data`&&t.isFetching===!1)&&(n.isFetching=!1,n.isMutating=!1),x.set(e,n),v(e,n)}var T=0,E=class{key;route;args;state;listeners=new Set;currentReqId=null;constructor(e,t,n){this.key=e,this.route=t,this.args=n,this.state={state:`idle`,isFetching:!1,source:null,data:null,error:null}}subscribe(e){this.listeners.add(e),e(this.state)}update(e){this.state={...this.state,...e},this.listeners.forEach(e=>e(this.state))}fetch(e=!1){if(this.state.isFetching&&!e)return;this.update({state:this.state.data?`data`:`loading`,isFetching:!0,error:null});let r=++T;this.currentReqId=r;let{path:i,remainingArgs:a}=s(this.route,this.args),o=new Uint8Array;Object.keys(a).length>0&&(o=new TextEncoder().encode(JSON.stringify(a))),H.debug&&(console.groupCollapsed(`%c➔ WASM QUERY [#${r}]`,`color: #7c3aed; font-weight: bold;`),console.log(`Namespace:`,this.route.namespace),console.log(`Endpoint ID:`,this.route.id),console.log(`Path:`,i),console.groupEnd()),n.set(r,{isStream:this.route.isStream,onResponse:e=>{if(this.currentReqId===r){if(H.debug){let t=e.eventType===1?`NetworkSuccess`:e.eventType===2?`CacheHit`:e.eventType===3?`CacheHitAndFetching`:e.eventType===4?`Error`:`Complete`;console.groupCollapsed(`%c← WASM RESP [#${r}]`,`color: #059669; font-weight: bold;`),console.log(`Event Type:`,t),e.data&&console.log(`Data:`,e.data),e.error&&console.log(`Error:`,e.error),console.groupEnd()}if(e.eventType===t.Error){this.update({state:`error`,error:e.error,isFetching:!1});return}if(e.data){let n=`network`,r=!1;e.eventType===t.CacheHit?(n=`cache`,r=!1):e.eventType===t.CacheHitAndFetching?(n=`cache`,r=!0):e.eventType===t.NetworkSuccess&&(n=`network`,r=!1),this.update({state:`data`,data:e.data,source:n,isFetching:r})}}},onComplete:()=>{this.currentReqId===r&&(H.debug&&console.log(`%c✔ Stream Complete [#${r}]`,`color: #94a3b8;`),this.update({isFetching:!1}))}});let c=d(this.route.namespace),f=d(this.route.method),p=d(i),m=u(o),h=d(``),g=d(``);l.axiom_wasm_call(r,c.ptr,c.len,this.route.id,f.ptr,f.len,p.ptr,p.len,h.ptr,h.len,g.ptr,g.len,m,o.length),l.axiom_free_memory(c.ptr,c.len),l.axiom_free_memory(f.ptr,f.len),l.axiom_free_memory(p.ptr,p.len),l.axiom_free_memory(h.ptr,h.len),l.axiom_free_memory(g.ptr,g.len)}},D=new Map,O=0;function k(e,t){let n=`ax-on:${t}`;e.hasAttribute(n)&&_(e.getAttribute(n),S(e))}function A(e,t,n){if(!H.debug)return;let r=e===`OUT`?`#7c3aed`:`#059669`,i=e===`OUT`?`➔ WASM CALL`:`← WASM RESP`;console.groupCollapsed(`%c${i} [#${t}]`,`color: ${r}; font-weight: bold;`),console.log(`Details:`,n),console.groupEnd()}function j(e,t){let n=t.trim().match(/^([\w\.]+)(?:\((.*)\))?$/);if(!n)return null;let r=n[1],i={};if(n[2]&&n[2].trim()!==``)try{let t=S(e),r=t.data||C(e);i=Function(`$data`,`$state`,`return (${n[2]});`)(r,t)||{}}catch(e){console.error(`ATMX Scope Error in "${t}":`,e)}return{target:r,args:i}}function M(e){let t=e.getAttribute(`ax-query`);if(!t)return;let n=j(e,t);if(!n)return;let r=o(n.target);if(!r){w(e,{state:`error`,error:{message:`Route not found: ${n.target}`}});return}let i=`${r.namespace}:${r.id}:${JSON.stringify(n.args)}`,a=D.get(i);a||(a=new E(i,r,n.args),D.set(i,a)),e._axListener||(e._axListener=t=>{w(e,t),(t.state===`data`||t.state===`error`)&&(k(e,t.state),e.dispatchEvent(new CustomEvent(`atmx:${t.state}`,{bubbles:!0,detail:t.data||t.error})))},a.subscribe(e._axListener)),a.fetch()}function N(e){let t=e.getAttribute(`ax-mutate`);if(!t)return;let n=j(e,t);if(!n)return;let r=o(n.target);if(!r){w(e,{state:`error`,error:{message:`Route not found: ${n.target}`}}),k(e,`error`);return}w(e,{state:`mutating`,error:null,data:null}),k(e,`mutating`);let i={};e instanceof HTMLFormElement&&new FormData(e).forEach((t,n)=>{let r=e.elements.namedItem(n),a=!1;r instanceof HTMLInputElement?a=r.type===`number`:r instanceof RadioNodeList&&r.length>0&&(a=r[0].type===`number`);let o=a&&t!==``?Number(t):t;if(n.includes(`.`)){let e=n.split(`.`),t=i;for(let n=0;n<e.length-1;n++)t[e[n]]||(t[e[n]]={}),t=t[e[n]];t[e[e.length-1]]=o}else i[n]=o});let{path:a,remainingArgs:c}=s(r,{...i,...n.args}),l=c;r.bodyParam&&c[r.bodyParam]!==void 0&&(l=c[r.bodyParam]);let u={},d=e.getAttribute(`ax-headers`);if(d)try{u=Function(`return (`+d+`);`)()||{}}catch(e){console.error(`ATMX: Invalid ax-headers syntax`,e)}let f=Object.entries(u).some(([e,t])=>e.toLowerCase()===`content-type`&&t.includes(`application/x-www-form-urlencoded`)),p=new Uint8Array;if(Object.keys(l).length>0)if(f){let e=new URLSearchParams;for(let[t,n]of Object.entries(l))e.append(t,String(n));p=new TextEncoder().encode(e.toString())}else p=new TextEncoder().encode(JSON.stringify(l));P(e,r.namespace,r.id,r.method,a,p,r.isStream,!0,u,f)}function P(e,t,r,i,a,o,s,c,f={},p=!1){let m=++O;A(`OUT`,m,{namespace:t,endpointId:r,method:i,path:a,headers:f,payload:o.length>0?p?new TextDecoder().decode(o):JSON.parse(new TextDecoder().decode(o)):null}),n.set(m,{isStream:s,onResponse:t=>F(e,t,c,m),onComplete:()=>{H.debug&&console.log(`%c✔ Stream Complete [#${m}]`,`color: #94a3b8;`)}});let h=d(t),g=d(i),_=d(a),v=d(``),y=d(Object.keys(f).length>0?JSON.stringify(f):``),b=u(o);l.axiom_wasm_call(m,h.ptr,h.len,r,g.ptr,g.len,_.ptr,_.len,v.ptr,v.len,y.ptr,y.len,b,o.length),l.axiom_free_memory(h.ptr,h.len),l.axiom_free_memory(g.ptr,g.len),l.axiom_free_memory(_.ptr,_.len),l.axiom_free_memory(v.ptr,v.len),l.axiom_free_memory(y.ptr,y.len),b&&l.axiom_free_memory(b,o.length)}function F(e,n,r,i){if(A(`IN`,i,{eventType:t[n.eventType],data:n.data,error:n.error}),n.eventType===t.Error){w(e,{state:`error`,error:n.error,isFetching:!1,isMutating:!1}),k(e,`error`),e.dispatchEvent(new CustomEvent(`atmx:error`,{bubbles:!0,detail:n.error}));return}if(n.data){let i=`network`,a=!1;n.eventType===t.CacheHit?i=`cache`:n.eventType===t.CacheHitAndFetching?(i=`cache`,a=!0):n.eventType===t.NetworkSuccess&&(i=`network`);let s=r?`success`:`data`;if(w(e,{state:s,data:n.data,source:i,isFetching:a,isMutating:!1}),r){let t=e.getAttribute(`ax-store-token`);if(t){let n=g(t,S(e));if(n){let t=o(j(e,e.getAttribute(`ax-mutate`)).target),r=e.getAttribute(`ax-token-header`)||`Authorization`;H.setAuthToken(t?.namespace||`default`,r,n)}}if(e.hasAttribute(`ax-clear-token`)){let t=o(j(e,e.getAttribute(`ax-mutate`)).target),n=e.getAttribute(`ax-token-header`)||`Authorization`;H.clearAuthToken(t?.namespace||`default`,n)}let n=e.getAttribute(`ax-refresh`);if(n){let e=n.split(`,`).map(e=>e.trim());for(let[t,n]of D.entries()){let t=`${n.route.namespace}.${n.route.name}`;e.includes(t)&&n.fetch(!0)}}}k(e,s),e.dispatchEvent(new CustomEvent(r?`atmx:success`:`atmx:data`,{bubbles:!0,detail:n.data}))}}var I=new IntersectionObserver(e=>{e.forEach(e=>{if(e.isIntersecting){let t=e.target;t.hasAttribute(`ax-query`)&&M(t),I.unobserve(t)}})});function L(e){e.querySelectorAll(`[\\:ax-query], [\\:ax-mutate]`).forEach(e=>{if(e.hasAttribute(`:ax-query`)){let t=g(e.getAttribute(`:ax-query`),S(e));t&&e.setAttribute(`ax-query`,String(t)),e.removeAttribute(`:ax-query`)}if(e.hasAttribute(`:ax-mutate`)){let t=g(e.getAttribute(`:ax-mutate`),S(e));t&&e.setAttribute(`ax-mutate`,String(t)),e.removeAttribute(`:ax-mutate`)}})}function R(e=document){L(e),e.querySelectorAll(`[ax-query]`).forEach(e=>{let t=e;w(t,{});let n=t.getAttribute(`ax-trigger`)||`load`;n===`load`?M(t):n===`intersect`?I.observe(t):t.addEventListener(n,e=>{e.preventDefault(),M(t)})}),e.querySelectorAll(`[ax-mutate]`).forEach(e=>{let t=e;w(t,{});let n=t.tagName===`FORM`?`submit`:`click`;t.addEventListener(n,e=>{(t.tagName===`A`||t.tagName===`BUTTON`||t.tagName===`FORM`)&&e.preventDefault(),N(t)})}),e.querySelectorAll(`[ax-trigger="refresh"]`).forEach(e=>{let t=e;t.addEventListener(`click`,e=>{e.preventDefault();let n=t.closest(`[ax-query]`);if(n){let e=j(n,n.getAttribute(`ax-query`));if(e){let t=o(e.target);if(t){let r=`${t.namespace}:${t.id}:${JSON.stringify(e.args)}`,i=D.get(r);i?i.fetch(!0):M(n)}}}})})}function z(){new MutationObserver(e=>{e.forEach(e=>{e.addedNodes.forEach(e=>{e instanceof HTMLElement&&R(e)})})}).observe(document.body,{childList:!0,subtree:!0})}var B=class extends HTMLElement{constructor(){super()}connectedCallback(){let e=this.getAttribute(`loading-text`)||`Initializing...`,t=this.getAttribute(`ready-text`)||`Online`,n=this.getAttribute(`error-text`)||`Failed to Connect`;this.renderState(`loading`,e,`text-amber-500 animate-pulse`),document.addEventListener(`atmx:ready`,()=>{this.renderState(`ready`,t,`text-green-600`)}),document.addEventListener(`atmx:error`,e=>{let t=e;t.detail&&t.detail.stage===`runtime`&&this.renderState(`error`,`${n}: ${t.detail.message}`,`text-red-600`)})}renderState(e,t,n){this.setAttribute(`data-state`,e);let r=this.querySelectorAll(`[data-ax-when]`);r.length>0?r.forEach(t=>{t.getAttribute(`data-ax-when`)===e?t.removeAttribute(`hidden`):t.setAttribute(`hidden`,``)}):(this.innerText=t,this.getAttribute(`class`)||(this.className=`text-xs font-bold ${n}`))}};typeof window<`u`&&!customElements.get(`ax-engine-status`)&&customElements.define(`ax-engine-status`,B);var V=`0.46.0`,H=new class{version=V;initialized=!1;debug=!1;async init(e){if(this.initialized)return{ok:!0,contracts:{},initDurationMs:0};let t=await p(e);return t.ok?(this.debug=e.debug||!1,z(),R(document.body),this.initialized=!0,this.debug&&console.log(`%c🚀 ATMX Debug Mode: Enabled`,`color: #2563eb; font-weight: bold;`),console.log(`✅ ATMX v${this.version} Online (${t.initDurationMs}ms). Reactive Engine Started.`),document.dispatchEvent(new CustomEvent(`atmx:ready`,{detail:t}))):(console.error(`❌ ATMX Initialization Failed:`,t.error),document.dispatchEvent(new CustomEvent(`atmx:error`,{detail:t.error}))),t}triggerQuery(e){let t=typeof e==`string`?document.querySelector(e):e;t&&t instanceof HTMLElement&&t.hasAttribute(`ax-query`)&&M(t)}on(e,t){document.addEventListener(`atmx:${e}`,t)}setAuthToken(e,t,n){m(e,t,n)}clearAuthToken(e,t){h(e,t)}};typeof window<`u`&&(window.atmx=H),e.ATMX_VERSION=V,e.atmx=H});
|
package/package.json
CHANGED
package/justfile
DELETED
package/scripts/upload.sh
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
set -e
|
|
3
|
-
|
|
4
|
-
# 1. Load credentials from .env
|
|
5
|
-
if [ -f .env ]; then
|
|
6
|
-
set -a
|
|
7
|
-
source .env
|
|
8
|
-
set +a
|
|
9
|
-
else
|
|
10
|
-
echo "❌ Error: .env file not found."
|
|
11
|
-
exit 1
|
|
12
|
-
fi
|
|
13
|
-
|
|
14
|
-
if [ -z "$CLOUDFLARE_ACCOUNT_ID" ] || [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
|
|
15
|
-
echo "❌ Error: Missing credentials in .env file."
|
|
16
|
-
exit 1
|
|
17
|
-
fi
|
|
18
|
-
|
|
19
|
-
# 2. Setup Variables
|
|
20
|
-
BUCKET_NAME="atmx"
|
|
21
|
-
ENDPOINT="https://${CLOUDFLARE_ACCOUNT_ID}.r2.cloudflarestorage.com"
|
|
22
|
-
DIST_DIR="./dist"
|
|
23
|
-
|
|
24
|
-
# Grab the version directly from package.json (e.g., "0.1.0")
|
|
25
|
-
VERSION=$(node -p "require('./package.json').version")
|
|
26
|
-
|
|
27
|
-
# We will upload to a versioned folder (v0.1.0) AND a "latest" folder
|
|
28
|
-
FOLDERS=("v$VERSION" "latest")
|
|
29
|
-
|
|
30
|
-
echo "🚀 Starting Upload for ATMX v$VERSION to Cloudflare R2..."
|
|
31
|
-
|
|
32
|
-
# 3. Upload loop
|
|
33
|
-
for FOLDER in "${FOLDERS[@]}"; do
|
|
34
|
-
echo "📁 Uploading to /$FOLDER/..."
|
|
35
|
-
|
|
36
|
-
# Upload UMD JS (for <script> tags)
|
|
37
|
-
aws s3 cp "$DIST_DIR/atmx.umd.js" "s3://$BUCKET_NAME/$FOLDER/atmx.umd.js" \
|
|
38
|
-
--endpoint-url "$ENDPOINT" \
|
|
39
|
-
--content-type "application/javascript" \
|
|
40
|
-
--cache-control "max-age=3600" \
|
|
41
|
-
--no-progress
|
|
42
|
-
|
|
43
|
-
# Upload ES JS (for ES module imports)
|
|
44
|
-
aws s3 cp "$DIST_DIR/atmx.es.js" "s3://$BUCKET_NAME/$FOLDER/atmx.es.js" \
|
|
45
|
-
--endpoint-url "$ENDPOINT" \
|
|
46
|
-
--content-type "application/javascript" \
|
|
47
|
-
--cache-control "max-age=3600" \
|
|
48
|
-
--no-progress
|
|
49
|
-
|
|
50
|
-
# Upload WASM (CRITICAL: Sets the application/wasm content-type)
|
|
51
|
-
aws s3 cp "$DIST_DIR/axiom_runtime.wasm" "s3://$BUCKET_NAME/$FOLDER/axiom_runtime.wasm" \
|
|
52
|
-
--endpoint-url "$ENDPOINT" \
|
|
53
|
-
--content-type "application/wasm" \
|
|
54
|
-
--cache-control "max-age=3600" \
|
|
55
|
-
--no-progress
|
|
56
|
-
done
|
|
57
|
-
|
|
58
|
-
echo "✅ Upload Complete!"
|
|
59
|
-
echo "🌐 Your files are now available at:"
|
|
60
|
-
echo " - https://atmx.axiomcore.dev/v$VERSION/atmx.umd.js"
|
|
61
|
-
echo " - https://atmx.axiomcore.dev/latest/atmx.umd.js"
|
package/src/core/callback.ts
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
// FILE: src/core/callback.ts
|
|
2
|
-
import { EventType, AxiomError, AxiomResponse } from './types';
|
|
3
|
-
|
|
4
|
-
// Store the active requests. We need to store a config object now, not just a callback function.
|
|
5
|
-
export const pendingRequests = new Map<number, {
|
|
6
|
-
isStream: boolean,
|
|
7
|
-
onResponse: (res: AxiomResponse) => void,
|
|
8
|
-
onComplete: () => void
|
|
9
|
-
}>();
|
|
10
|
-
|
|
11
|
-
export function setupWebCallback(wasm: any) {
|
|
12
|
-
(window as any).axiom_web_callback = (
|
|
13
|
-
reqId: number, eventType: number, errorCode: number,
|
|
14
|
-
dataPtr: number, dataLen: number, errPtr: number, errLen: number
|
|
15
|
-
) => {
|
|
16
|
-
const handler = pendingRequests.get(reqId);
|
|
17
|
-
if (!handler) {
|
|
18
|
-
// Memory must be freed even if JS abandoned the request!
|
|
19
|
-
if (dataPtr) wasm.axiom_free_memory(dataPtr, dataLen);
|
|
20
|
-
if (errPtr) wasm.axiom_free_memory(errPtr, errLen);
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
let dataBytes: Uint8Array | null = null;
|
|
25
|
-
let errorJson: string | null = null;
|
|
26
|
-
|
|
27
|
-
// 1. Read Payload Memory
|
|
28
|
-
if (dataPtr !== 0 && dataLen > 0) {
|
|
29
|
-
const memory = new Uint8Array(wasm.memory.buffer);
|
|
30
|
-
dataBytes = new Uint8Array(memory.subarray(dataPtr, dataPtr + dataLen));
|
|
31
|
-
wasm.axiom_free_memory(dataPtr, dataLen);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// 2. Read Error Memory
|
|
35
|
-
if (errPtr !== 0 && errLen > 0) {
|
|
36
|
-
const memory = new Uint8Array(wasm.memory.buffer);
|
|
37
|
-
const errBytes = new Uint8Array(memory.subarray(errPtr, errPtr + errLen));
|
|
38
|
-
errorJson = new TextDecoder().decode(errBytes);
|
|
39
|
-
wasm.axiom_free_memory(errPtr, errLen);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// 3. Handle Completion Signal
|
|
43
|
-
if (eventType === EventType.Complete) {
|
|
44
|
-
handler.onComplete();
|
|
45
|
-
pendingRequests.delete(reqId);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// 4. Handle Errors
|
|
50
|
-
if (eventType === EventType.Error) {
|
|
51
|
-
let richError: AxiomError;
|
|
52
|
-
if (errorJson) {
|
|
53
|
-
try { richError = JSON.parse(errorJson); }
|
|
54
|
-
catch (e) { richError = { stage: 'ffiBoundary', category: 'runtime', code: 'JsonParseFailure', message: `Parse failed: ${e}`, retryable: false }; }
|
|
55
|
-
} else {
|
|
56
|
-
richError = { stage: 'runtime', category: 'unknown', code: errorCode.toString(), message: 'Internal Wasm error', retryable: false };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
handler.onResponse({ eventType, error: richError });
|
|
60
|
-
|
|
61
|
-
// Clean up the request on a fatal error
|
|
62
|
-
handler.onComplete();
|
|
63
|
-
pendingRequests.delete(reqId);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// 5. Handle Data (Success, Cache, or Stream Chunk)
|
|
68
|
-
if (dataBytes) {
|
|
69
|
-
try {
|
|
70
|
-
const jsonString = new TextDecoder().decode(dataBytes);
|
|
71
|
-
const jsonData = JSON.parse(jsonString);
|
|
72
|
-
|
|
73
|
-
// Pass the data up to the Reactive Engine
|
|
74
|
-
handler.onResponse({
|
|
75
|
-
eventType,
|
|
76
|
-
data: jsonData,
|
|
77
|
-
isFetching: eventType === EventType.CacheHitAndFetching,
|
|
78
|
-
isStreamChunk: handler.isStream
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// If it's NOT a stream, a NetworkSuccess means the request is fully complete.
|
|
82
|
-
if (!handler.isStream && eventType === EventType.NetworkSuccess) {
|
|
83
|
-
handler.onComplete();
|
|
84
|
-
pendingRequests.delete(reqId);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
} catch (e) {
|
|
88
|
-
console.error("ATMX: Failed to parse JSON response from Axiom", e);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
package/src/core/context.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// FILE: src/core/context.ts
|
|
2
|
-
import { renderContext } from '../resolver/render';
|
|
3
|
-
|
|
4
|
-
export type AtmxState = 'idle' | 'loading' | 'mutating' | 'data' | 'success' | 'error';
|
|
5
|
-
|
|
6
|
-
export interface AtmxContextData {
|
|
7
|
-
state: AtmxState;
|
|
8
|
-
isFetching: boolean;
|
|
9
|
-
isMutating: boolean;
|
|
10
|
-
source: 'cache' | 'network' | null;
|
|
11
|
-
data: any;
|
|
12
|
-
error: any;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const contextRegistry = new WeakMap<HTMLElement, AtmxContextData>();
|
|
16
|
-
|
|
17
|
-
export function getContext(element: HTMLElement): AtmxContextData {
|
|
18
|
-
if (!contextRegistry.has(element)) {
|
|
19
|
-
contextRegistry.set(element, {
|
|
20
|
-
state: 'idle', isFetching: false, isMutating: false,
|
|
21
|
-
source: null, data: null, error: null
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
return contextRegistry.get(element)!;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* NEW: Recursively finds the nearest parent context that has actual data.
|
|
29
|
-
* This allows nested buttons to access $data from their parent queries.
|
|
30
|
-
*/
|
|
31
|
-
export function getClosestData(element: HTMLElement): any {
|
|
32
|
-
let current: HTMLElement | null = element.parentElement;
|
|
33
|
-
while (current) {
|
|
34
|
-
if (current.hasAttribute('ax-query') || current.hasAttribute('ax-mutate')) {
|
|
35
|
-
const ctx = contextRegistry.get(current);
|
|
36
|
-
if (ctx && ctx.data) return ctx.data;
|
|
37
|
-
}
|
|
38
|
-
current = current.parentElement;
|
|
39
|
-
}
|
|
40
|
-
return {}; // Return empty object if no parent data found
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function updateContext(element: HTMLElement, updates: Partial<AtmxContextData>) {
|
|
44
|
-
const current = getContext(element);
|
|
45
|
-
Object.assign(current, updates);
|
|
46
|
-
|
|
47
|
-
if (updates.state === 'loading') current.isFetching = true;
|
|
48
|
-
if (updates.state === 'mutating') current.isMutating = true;
|
|
49
|
-
if (updates.state === 'success' || (updates.state === 'data' && updates.isFetching === false)) {
|
|
50
|
-
current.isFetching = false;
|
|
51
|
-
current.isMutating = false;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
contextRegistry.set(element, current);
|
|
55
|
-
renderContext(element, current);
|
|
56
|
-
}
|
package/src/core/query.ts
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
// FILE: src/core/query.ts
|
|
2
|
-
import { wasmEngine, allocString, allocBytes } from "./wasm";
|
|
3
|
-
import { pendingRequests } from "./callback";
|
|
4
|
-
import { Route, buildRequestPath } from "./router";
|
|
5
|
-
import { AtmxContextData } from "./context";
|
|
6
|
-
import { EventType } from "./types";
|
|
7
|
-
import { atmx } from "../index";
|
|
8
|
-
|
|
9
|
-
let globalReqCounter = 0;
|
|
10
|
-
type Listener = (state: Partial<AtmxContextData>) => void;
|
|
11
|
-
|
|
12
|
-
export class ActiveQuery {
|
|
13
|
-
key: string;
|
|
14
|
-
route: Route;
|
|
15
|
-
args: Record<string, any>;
|
|
16
|
-
state: Partial<AtmxContextData>;
|
|
17
|
-
listeners: Set<Listener> = new Set();
|
|
18
|
-
currentReqId: number | null = null;
|
|
19
|
-
|
|
20
|
-
constructor(key: string, route: Route, args: Record<string, any>) {
|
|
21
|
-
this.key = key;
|
|
22
|
-
this.route = route;
|
|
23
|
-
this.args = args;
|
|
24
|
-
this.state = {
|
|
25
|
-
state: "idle",
|
|
26
|
-
isFetching: false,
|
|
27
|
-
source: null,
|
|
28
|
-
data: null,
|
|
29
|
-
error: null,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
subscribe(listener: Listener) {
|
|
34
|
-
this.listeners.add(listener);
|
|
35
|
-
listener(this.state); // Instantly hydrate the DOM element with current state
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
update(newState: Partial<AtmxContextData>) {
|
|
39
|
-
this.state = { ...this.state, ...newState };
|
|
40
|
-
this.listeners.forEach((l) => l(this.state)); // Broadcast to all DOM elements!
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
fetch(force: boolean = false) {
|
|
44
|
-
if (this.state.isFetching && !force) return;
|
|
45
|
-
|
|
46
|
-
this.update({
|
|
47
|
-
state: this.state.data ? "data" : "loading",
|
|
48
|
-
isFetching: true,
|
|
49
|
-
error: null,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const reqId = ++globalReqCounter;
|
|
53
|
-
this.currentReqId = reqId;
|
|
54
|
-
|
|
55
|
-
const { path, remainingArgs } = buildRequestPath(this.route, this.args);
|
|
56
|
-
|
|
57
|
-
let payloadBytes = new Uint8Array(0);
|
|
58
|
-
if (Object.keys(remainingArgs).length > 0) {
|
|
59
|
-
payloadBytes = new TextEncoder().encode(JSON.stringify(remainingArgs));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (atmx.debug) {
|
|
63
|
-
console.groupCollapsed(
|
|
64
|
-
`%c➔ WASM QUERY [#${reqId}]`,
|
|
65
|
-
`color: #7c3aed; font-weight: bold;`,
|
|
66
|
-
);
|
|
67
|
-
console.log("Namespace:", this.route.namespace);
|
|
68
|
-
console.log("Endpoint ID:", this.route.id);
|
|
69
|
-
console.log("Path:", path);
|
|
70
|
-
console.groupEnd();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
pendingRequests.set(reqId, {
|
|
74
|
-
isStream: this.route.isStream,
|
|
75
|
-
onResponse: (res) => {
|
|
76
|
-
if (this.currentReqId !== reqId) return;
|
|
77
|
-
|
|
78
|
-
if (atmx.debug) {
|
|
79
|
-
const evtName =
|
|
80
|
-
res.eventType === 1
|
|
81
|
-
? "NetworkSuccess"
|
|
82
|
-
: res.eventType === 2
|
|
83
|
-
? "CacheHit"
|
|
84
|
-
: res.eventType === 3
|
|
85
|
-
? "CacheHitAndFetching"
|
|
86
|
-
: res.eventType === 4
|
|
87
|
-
? "Error"
|
|
88
|
-
: "Complete";
|
|
89
|
-
console.groupCollapsed(
|
|
90
|
-
`%c← WASM RESP [#${reqId}]`,
|
|
91
|
-
`color: #059669; font-weight: bold;`,
|
|
92
|
-
);
|
|
93
|
-
console.log("Event Type:", evtName);
|
|
94
|
-
if (res.data) console.log("Data:", res.data);
|
|
95
|
-
if (res.error) console.log("Error:", res.error);
|
|
96
|
-
console.groupEnd();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (res.eventType === EventType.Error) {
|
|
100
|
-
this.update({ state: "error", error: res.error, isFetching: false });
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (res.data) {
|
|
105
|
-
let source: "cache" | "network" = "network";
|
|
106
|
-
let isFetching = false;
|
|
107
|
-
|
|
108
|
-
if (res.eventType === EventType.CacheHit) {
|
|
109
|
-
source = "cache";
|
|
110
|
-
isFetching = false;
|
|
111
|
-
} else if (res.eventType === EventType.CacheHitAndFetching) {
|
|
112
|
-
source = "cache";
|
|
113
|
-
isFetching = true;
|
|
114
|
-
} else if (res.eventType === EventType.NetworkSuccess) {
|
|
115
|
-
source = "network";
|
|
116
|
-
isFetching = false;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
this.update({ state: "data", data: res.data, source, isFetching });
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
onComplete: () => {
|
|
123
|
-
if (this.currentReqId !== reqId) return;
|
|
124
|
-
if (atmx.debug)
|
|
125
|
-
console.log(`%c✔ Stream Complete [#${reqId}]`, "color: #94a3b8;");
|
|
126
|
-
this.update({ isFetching: false });
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
const nsStr = allocString(this.route.namespace);
|
|
131
|
-
const mStr = allocString(this.route.method);
|
|
132
|
-
const pStr = allocString(path);
|
|
133
|
-
const payloadPtr = allocBytes(payloadBytes);
|
|
134
|
-
const tpStr = allocString(""); // Traceparent (empty for now)
|
|
135
|
-
const hStr = allocString(""); // Headers (empty for now)
|
|
136
|
-
|
|
137
|
-
wasmEngine.axiom_wasm_call(
|
|
138
|
-
reqId,
|
|
139
|
-
nsStr.ptr,
|
|
140
|
-
nsStr.len,
|
|
141
|
-
this.route.id,
|
|
142
|
-
mStr.ptr,
|
|
143
|
-
mStr.len,
|
|
144
|
-
pStr.ptr,
|
|
145
|
-
pStr.len,
|
|
146
|
-
tpStr.ptr,
|
|
147
|
-
tpStr.len,
|
|
148
|
-
hStr.ptr,
|
|
149
|
-
hStr.len,
|
|
150
|
-
payloadPtr,
|
|
151
|
-
payloadBytes.length,
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
wasmEngine.axiom_free_memory(nsStr.ptr, nsStr.len);
|
|
155
|
-
wasmEngine.axiom_free_memory(mStr.ptr, mStr.len);
|
|
156
|
-
wasmEngine.axiom_free_memory(pStr.ptr, pStr.len);
|
|
157
|
-
wasmEngine.axiom_free_memory(tpStr.ptr, tpStr.len);
|
|
158
|
-
wasmEngine.axiom_free_memory(hStr.ptr, hStr.len);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export const queryRegistry = new Map<string, ActiveQuery>();
|
package/src/core/router.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
// FILE: src/core/router.ts
|
|
2
|
-
|
|
3
|
-
export interface RouteAuth {
|
|
4
|
-
required: boolean;
|
|
5
|
-
methods: any[];
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface Route {
|
|
9
|
-
id: number;
|
|
10
|
-
namespace: string;
|
|
11
|
-
name: string;
|
|
12
|
-
method: string;
|
|
13
|
-
pathTemplate: string;
|
|
14
|
-
isStream: boolean;
|
|
15
|
-
auth?: RouteAuth | null;
|
|
16
|
-
bodyParam?: string | null; // <-- NEW
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const routes = new Map<string, Route>();
|
|
20
|
-
|
|
21
|
-
export function initRouter(namespace: string, contractJson: any) {
|
|
22
|
-
const endpoints = contractJson?.ir?.endpoints;
|
|
23
|
-
if (!endpoints) return;
|
|
24
|
-
|
|
25
|
-
const epList = Array.isArray(endpoints)
|
|
26
|
-
? endpoints
|
|
27
|
-
: Object.values(endpoints);
|
|
28
|
-
|
|
29
|
-
epList.forEach((ep: any) => {
|
|
30
|
-
const routeKey = `${namespace}.${ep.name}`;
|
|
31
|
-
|
|
32
|
-
// ✨ Detect which param belongs in the body
|
|
33
|
-
const bodyParam =
|
|
34
|
-
ep.parameters?.find((p: any) => p.source === "body")?.name || null;
|
|
35
|
-
|
|
36
|
-
routes.set(routeKey, {
|
|
37
|
-
id: ep.id,
|
|
38
|
-
namespace: namespace,
|
|
39
|
-
name: ep.name,
|
|
40
|
-
method: ep.method ? ep.method.toUpperCase() : "GET",
|
|
41
|
-
pathTemplate: ep.path,
|
|
42
|
-
isStream: ep.isStream || false,
|
|
43
|
-
auth: ep.auth || null,
|
|
44
|
-
bodyParam: bodyParam, // <-- NEW
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
console.log(
|
|
48
|
-
`🛣️ ATMX Router: Mapped ${epList.length} endpoints for '${namespace}'.`,
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function resolveRoute(rpcCall: string): Route | null {
|
|
53
|
-
return routes.get(rpcCall.trim()) || null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function buildRequestPath(
|
|
57
|
-
route: Route,
|
|
58
|
-
args: Record<string, any>,
|
|
59
|
-
): { path: string; remainingArgs: Record<string, any> } {
|
|
60
|
-
let finalPath = route.pathTemplate;
|
|
61
|
-
const remainingArgs = { ...args };
|
|
62
|
-
|
|
63
|
-
const pathMatches = finalPath.match(/\{([^}]+)\}/g);
|
|
64
|
-
if (pathMatches) {
|
|
65
|
-
pathMatches.forEach((match) => {
|
|
66
|
-
const key = match.replace(/[{}]/g, "");
|
|
67
|
-
if (remainingArgs[key] !== undefined) {
|
|
68
|
-
finalPath = finalPath.replace(
|
|
69
|
-
match,
|
|
70
|
-
encodeURIComponent(String(remainingArgs[key])),
|
|
71
|
-
);
|
|
72
|
-
delete remainingArgs[key];
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (route.method === "GET" && Object.keys(remainingArgs).length > 0) {
|
|
78
|
-
const params = new URLSearchParams();
|
|
79
|
-
for (const [key, value] of Object.entries(remainingArgs)) {
|
|
80
|
-
if (value !== undefined && value !== null) {
|
|
81
|
-
params.append(key, String(value));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
const separator = finalPath.includes("?") ? "&" : "?";
|
|
85
|
-
finalPath += `${separator}${params.toString()}`;
|
|
86
|
-
|
|
87
|
-
for (const key of Object.keys(remainingArgs)) delete remainingArgs[key];
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return { path: finalPath, remainingArgs };
|
|
91
|
-
}
|