atmx-react 0.43.0 → 0.47.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/index.d.mts +135 -0
- package/dist/index.d.ts +135 -0
- package/dist/index.js +628 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +602 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +13 -10
- package/src/components/AxGet.tsx +0 -19
- package/src/components/AxMutation.tsx +0 -48
- package/src/components/AxQuery.tsx +0 -41
- package/src/components/AxTrigger.tsx +0 -36
- package/src/components/AxWhen.tsx +0 -54
- package/src/context/AxiomDataContext.tsx +0 -27
- package/src/context/AxiomProvider.tsx +0 -97
- package/src/core/ActiveQuery.ts +0 -217
- package/src/core/QueryManager.ts +0 -40
- package/src/hooks/useAxiom.ts +0 -13
- package/src/hooks/useAxiomMutation.ts +0 -236
- package/src/hooks/useAxiomQuery.ts +0 -41
- package/src/index.ts +0 -39
- package/src/utils/core-bridge.ts +0 -62
- package/tsconfig.json +0 -27
- package/tsup.config.ts +0 -11
package/package.json
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atmx-react",
|
|
3
|
-
"
|
|
3
|
+
"files": [
|
|
4
|
+
"dist"
|
|
5
|
+
],
|
|
6
|
+
"version": "0.47.0",
|
|
4
7
|
"description": "React bindings for ATMX and Axiom Core WASM runtime",
|
|
5
8
|
"main": "./dist/index.js",
|
|
6
9
|
"module": "./dist/index.mjs",
|
|
@@ -12,18 +15,18 @@
|
|
|
12
15
|
"clean": "rm -rf dist"
|
|
13
16
|
},
|
|
14
17
|
"peerDependencies": {
|
|
15
|
-
"react": "^18.0.0",
|
|
16
|
-
"react-dom": "^18.0.0"
|
|
18
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
19
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"atmx-web": "^0.47.0"
|
|
17
23
|
},
|
|
18
24
|
"devDependencies": {
|
|
19
|
-
"@types/react": "^
|
|
20
|
-
"@types/react-dom": "^
|
|
21
|
-
"react": "^
|
|
22
|
-
"react-dom": "^
|
|
25
|
+
"@types/react": "^19.0.0",
|
|
26
|
+
"@types/react-dom": "^19.0.0",
|
|
27
|
+
"react": "^19.0.0",
|
|
28
|
+
"react-dom": "^19.0.0",
|
|
23
29
|
"tsup": "^8.5.1",
|
|
24
30
|
"typescript": "^5.9.3"
|
|
25
|
-
},
|
|
26
|
-
"dependencies": {
|
|
27
|
-
"atmx-web": "^0.42.0"
|
|
28
31
|
}
|
|
29
32
|
}
|
package/src/components/AxGet.tsx
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// src/components/AxGet.tsx
|
|
2
|
-
import { AxiomQueryDef, AxiomError } from '../utils/core-bridge';
|
|
3
|
-
import { useAxiomQuery } from '../hooks/useAxiomQuery';
|
|
4
|
-
|
|
5
|
-
interface AxGetProps<T> {
|
|
6
|
-
query: AxiomQueryDef<T>;
|
|
7
|
-
children: (props: {
|
|
8
|
-
data: T | null;
|
|
9
|
-
isLoading: boolean;
|
|
10
|
-
error: AxiomError | null;
|
|
11
|
-
refetch: () => void;
|
|
12
|
-
}) => React.ReactNode;
|
|
13
|
-
enabled?: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function AxGet<T>({ query, children, enabled }: AxGetProps<T>) {
|
|
17
|
-
const result = useAxiomQuery<T>(query, { enabled });
|
|
18
|
-
return <>{children(result)}</>;
|
|
19
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// src/components/AxMutation.tsx
|
|
2
|
-
import { ReactNode } from 'react';
|
|
3
|
-
import { useAxiomMutation } from '../hooks/useAxiomMutation';
|
|
4
|
-
import { AxiomError, AxiomQueryDef } from '../utils/core-bridge';
|
|
5
|
-
|
|
6
|
-
interface AxMutationRenderProps<T, A> {
|
|
7
|
-
/** The function to trigger the request, with fully typed arguments */
|
|
8
|
-
execute: (args: A) => void;
|
|
9
|
-
/** The decoded data returned from the mutation */
|
|
10
|
-
data: T | null;
|
|
11
|
-
isLoading: boolean;
|
|
12
|
-
error: AxiomError | null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface AxMutationProps<T, A> {
|
|
16
|
-
/** The SDK method to use, e.g., mutation={sdk.createUser} */
|
|
17
|
-
mutation: (args: A) => AxiomQueryDef<T>;
|
|
18
|
-
/** Render prop function */
|
|
19
|
-
children: (props: AxMutationRenderProps<T, A>) => ReactNode;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function AxMutation<T = any, A = any>({
|
|
23
|
-
mutation,
|
|
24
|
-
children
|
|
25
|
-
}: AxMutationProps<T, A>) {
|
|
26
|
-
// Now correctly passing the SDK function to the refactored hook
|
|
27
|
-
const result = useAxiomMutation<T, A>(mutation);
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<>
|
|
31
|
-
{children({
|
|
32
|
-
execute: result.execute,
|
|
33
|
-
data: result.data,
|
|
34
|
-
isLoading: result.isLoading,
|
|
35
|
-
error: result.error
|
|
36
|
-
})}
|
|
37
|
-
</>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* A semantic alias for mutations.
|
|
43
|
-
* Since the SDK already knows the HTTP method (POST/PUT),
|
|
44
|
-
* this is just for better code readability.
|
|
45
|
-
*/
|
|
46
|
-
export function AxPost<T = any, A = any>(props: AxMutationProps<T, A>) {
|
|
47
|
-
return <AxMutation {...props} />;
|
|
48
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// FILE: src/components/AxQuery.tsx
|
|
2
|
-
import { ReactNode } from "react";
|
|
3
|
-
import { AxiomQueryDef, AxiomState } from "../utils/core-bridge";
|
|
4
|
-
import { useAxiomQuery } from "../hooks/useAxiomQuery";
|
|
5
|
-
import { AxiomDataContext } from "../context/AxiomDataContext";
|
|
6
|
-
|
|
7
|
-
export interface AxQueryProps<T> {
|
|
8
|
-
call: AxiomQueryDef<T>;
|
|
9
|
-
children:
|
|
10
|
-
| ReactNode
|
|
11
|
-
| ((props: {
|
|
12
|
-
data: T | null;
|
|
13
|
-
state: AxiomState<T>;
|
|
14
|
-
refetch: () => void;
|
|
15
|
-
}) => ReactNode);
|
|
16
|
-
enabled?: boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function AxQuery<T>({
|
|
20
|
-
call,
|
|
21
|
-
children,
|
|
22
|
-
enabled = true,
|
|
23
|
-
}: AxQueryProps<T>) {
|
|
24
|
-
const result = useAxiomQuery<T>(call, { enabled });
|
|
25
|
-
|
|
26
|
-
const content =
|
|
27
|
-
typeof children === "function"
|
|
28
|
-
? children({
|
|
29
|
-
data: result.data,
|
|
30
|
-
state: result.state,
|
|
31
|
-
refetch: result.refetch,
|
|
32
|
-
})
|
|
33
|
-
: children;
|
|
34
|
-
|
|
35
|
-
// Provide the state downwards so nested components (or AxWhen) can inherit it!
|
|
36
|
-
return (
|
|
37
|
-
<AxiomDataContext.Provider value={result.state}>
|
|
38
|
-
{content}
|
|
39
|
-
</AxiomDataContext.Provider>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// src/components/AxTrigger.tsx
|
|
2
|
-
import { useEffect, useRef, ReactNode } from 'react';
|
|
3
|
-
|
|
4
|
-
interface AxTriggerProps {
|
|
5
|
-
onTrigger: () => void;
|
|
6
|
-
once?: boolean;
|
|
7
|
-
children?: ReactNode;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const AxTrigger: React.FC<AxTriggerProps> = ({ onTrigger, once = true, children }) => {
|
|
11
|
-
const elementRef = useRef<HTMLDivElement>(null);
|
|
12
|
-
const hasTriggered = useRef(false);
|
|
13
|
-
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
const observer = new IntersectionObserver((entries) => {
|
|
16
|
-
entries.forEach(entry => {
|
|
17
|
-
if (entry.isIntersecting) {
|
|
18
|
-
if (once && hasTriggered.current) return;
|
|
19
|
-
|
|
20
|
-
onTrigger();
|
|
21
|
-
hasTriggered.current = true;
|
|
22
|
-
|
|
23
|
-
if (once) observer.unobserve(entry.target);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
}, { threshold: 0.1 });
|
|
27
|
-
|
|
28
|
-
if (elementRef.current) {
|
|
29
|
-
observer.observe(elementRef.current);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return () => observer.disconnect();
|
|
33
|
-
}, [onTrigger, once]);
|
|
34
|
-
|
|
35
|
-
return <div ref={elementRef}>{children}</div>;
|
|
36
|
-
};
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
// FILE: src/components/AxWhen.tsx
|
|
2
|
-
import { ReactNode, useContext } from "react";
|
|
3
|
-
import { AxiomDataContext } from "../context/AxiomDataContext";
|
|
4
|
-
|
|
5
|
-
interface AxWhenProps {
|
|
6
|
-
/** Explicit state object from a hook (e.g. sdk.users.useGetUser) */
|
|
7
|
-
value?: {
|
|
8
|
-
status: string;
|
|
9
|
-
data?: any;
|
|
10
|
-
isFetching?: boolean;
|
|
11
|
-
isMutating?: boolean;
|
|
12
|
-
};
|
|
13
|
-
/** Comma-separated states: "idle, loading, mutating, data, success, error" */
|
|
14
|
-
is: string;
|
|
15
|
-
children: ReactNode;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function AxWhen({ value, is, children }: AxWhenProps) {
|
|
19
|
-
// Use useContext directly instead of the throwing hook useAxiomContext
|
|
20
|
-
const context = useContext(AxiomDataContext);
|
|
21
|
-
const stateObj = value || context;
|
|
22
|
-
|
|
23
|
-
// If no value is provided and we aren't inside a scope, render nothing
|
|
24
|
-
if (!stateObj) return null;
|
|
25
|
-
|
|
26
|
-
const expectedStates = is.split(",").map((s) => s.trim().toLowerCase());
|
|
27
|
-
|
|
28
|
-
let currentState = "idle";
|
|
29
|
-
|
|
30
|
-
if (stateObj.isMutating) {
|
|
31
|
-
currentState = "mutating";
|
|
32
|
-
} else if (stateObj.status === "loading") {
|
|
33
|
-
currentState = "loading";
|
|
34
|
-
} else if (stateObj.status === "error") {
|
|
35
|
-
currentState = "error";
|
|
36
|
-
} else if (stateObj.status === "success" || stateObj.data) {
|
|
37
|
-
currentState = "data";
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Handle 'success' as a distinct semantic state for Mutations
|
|
41
|
-
if (
|
|
42
|
-
expectedStates.includes("success") &&
|
|
43
|
-
stateObj.status === "success" &&
|
|
44
|
-
!stateObj.isMutating
|
|
45
|
-
) {
|
|
46
|
-
currentState = "success";
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (expectedStates.includes(currentState)) {
|
|
50
|
-
return <>{children}</>;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// FILE: src/context/AxiomDataContext.tsx
|
|
2
|
-
import { createContext, useContext } from "react";
|
|
3
|
-
import { AxiomState } from "../utils/core-bridge";
|
|
4
|
-
|
|
5
|
-
export const AxiomDataContext = createContext<AxiomState<any> | null>(null);
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Throwing version: Use this when you absolutely expect to be inside a scope.
|
|
9
|
-
*/
|
|
10
|
-
export function useAxiomContext<T>(): AxiomState<T> {
|
|
11
|
-
const context = useContext(AxiomDataContext);
|
|
12
|
-
if (!context) {
|
|
13
|
-
throw new Error(
|
|
14
|
-
"useAxiomContext must be used within an <AxQuery> or <AxMutate> scope.",
|
|
15
|
-
);
|
|
16
|
-
}
|
|
17
|
-
return context as AxiomState<T>;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Safe version: Returns T or an empty object.
|
|
22
|
-
* Used for Context Inheritance ($data access).
|
|
23
|
-
*/
|
|
24
|
-
export function useAxiomData<T>(): T {
|
|
25
|
-
const context = useContext(AxiomDataContext);
|
|
26
|
-
return (context?.data || {}) as T;
|
|
27
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// FILE: src/context/AxiomProvider.tsx
|
|
2
|
-
import React, {
|
|
3
|
-
createContext,
|
|
4
|
-
useEffect,
|
|
5
|
-
useState,
|
|
6
|
-
useRef,
|
|
7
|
-
ReactNode,
|
|
8
|
-
} from "react";
|
|
9
|
-
import { initWasm, AtmxConfig } from "../utils/core-bridge";
|
|
10
|
-
|
|
11
|
-
export interface AxiomContextState {
|
|
12
|
-
isReady: boolean;
|
|
13
|
-
error: Error | null;
|
|
14
|
-
config: AtmxConfig | null;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const AxiomContext = createContext<AxiomContextState | undefined>(
|
|
18
|
-
undefined,
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
export interface AxiomProviderProps {
|
|
22
|
-
configUrl?: string;
|
|
23
|
-
config?: AtmxConfig;
|
|
24
|
-
children: ReactNode;
|
|
25
|
-
fallback?: ReactNode;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const AxiomProvider: React.FC<AxiomProviderProps> = ({
|
|
29
|
-
configUrl,
|
|
30
|
-
config,
|
|
31
|
-
children,
|
|
32
|
-
fallback,
|
|
33
|
-
}) => {
|
|
34
|
-
const [state, setState] = useState<AxiomContextState>({
|
|
35
|
-
isReady: false,
|
|
36
|
-
error: null,
|
|
37
|
-
config: null,
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const initStarted = useRef(false);
|
|
41
|
-
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
if (initStarted.current) return;
|
|
44
|
-
initStarted.current = true;
|
|
45
|
-
|
|
46
|
-
const bootSequence = async () => {
|
|
47
|
-
try {
|
|
48
|
-
let finalConfig: AtmxConfig;
|
|
49
|
-
if (configUrl) {
|
|
50
|
-
const res = await fetch(configUrl);
|
|
51
|
-
if (!res.ok)
|
|
52
|
-
throw new Error(`Failed to load config from ${configUrl}`);
|
|
53
|
-
finalConfig = await res.json();
|
|
54
|
-
} else if (config) {
|
|
55
|
-
finalConfig = config;
|
|
56
|
-
} else {
|
|
57
|
-
throw new Error(
|
|
58
|
-
"AxiomProvider requires either 'configUrl' or 'config' prop.",
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
!finalConfig.contracts ||
|
|
64
|
-
Object.keys(finalConfig.contracts).length === 0
|
|
65
|
-
) {
|
|
66
|
-
throw new Error("No contracts defined in ATMX config.");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// 1. Initialize Wasm Engine (Handles ALL contracts natively!)
|
|
70
|
-
await initWasm(finalConfig);
|
|
71
|
-
|
|
72
|
-
console.log(`⚛️ ATMX-React: Provider ready.`);
|
|
73
|
-
setState({ isReady: true, error: null, config: finalConfig });
|
|
74
|
-
} catch (err: any) {
|
|
75
|
-
console.error("ATMX Provider Boot Error:", err);
|
|
76
|
-
setState({ isReady: false, error: err, config: null });
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
bootSequence();
|
|
81
|
-
}, [configUrl, config]);
|
|
82
|
-
|
|
83
|
-
if (state.error)
|
|
84
|
-
return (
|
|
85
|
-
<div style={{ color: "red", padding: "20px", fontFamily: "monospace" }}>
|
|
86
|
-
<strong>ATMX Initialization Failed:</strong>
|
|
87
|
-
<br />
|
|
88
|
-
{state.error.message}
|
|
89
|
-
</div>
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
if (!state.isReady) return <>{fallback || null}</>;
|
|
93
|
-
|
|
94
|
-
return (
|
|
95
|
-
<AxiomContext.Provider value={state}>{children}</AxiomContext.Provider>
|
|
96
|
-
);
|
|
97
|
-
};
|
package/src/core/ActiveQuery.ts
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
// FILE: src/core/ActiveQuery.ts
|
|
2
|
-
import {
|
|
3
|
-
AxiomState,
|
|
4
|
-
AxiomQueryDef,
|
|
5
|
-
wasmEngine,
|
|
6
|
-
allocString,
|
|
7
|
-
allocBytes,
|
|
8
|
-
pendingRequests,
|
|
9
|
-
getNextReqId,
|
|
10
|
-
buildRequestPath,
|
|
11
|
-
Route,
|
|
12
|
-
} from "../utils/core-bridge";
|
|
13
|
-
|
|
14
|
-
type Listener<T> = (state: AxiomState<T>) => void;
|
|
15
|
-
|
|
16
|
-
export class ActiveQuery<T> {
|
|
17
|
-
public queryKey: string;
|
|
18
|
-
public def: AxiomQueryDef<T>;
|
|
19
|
-
private state: AxiomState<T>;
|
|
20
|
-
private listeners: Set<Listener<T>> = new Set();
|
|
21
|
-
private currentReqId: number | null = null;
|
|
22
|
-
|
|
23
|
-
constructor(queryKey: string, def: AxiomQueryDef<T>) {
|
|
24
|
-
this.queryKey = queryKey;
|
|
25
|
-
this.def = def;
|
|
26
|
-
this.state = {
|
|
27
|
-
status: "idle",
|
|
28
|
-
data: null,
|
|
29
|
-
error: null,
|
|
30
|
-
isFetching: false,
|
|
31
|
-
isMutating: false,
|
|
32
|
-
source: null,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public getState(): AxiomState<T> {
|
|
37
|
-
return this.state;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
public subscribe(listener: Listener<T>): () => void {
|
|
41
|
-
this.listeners.add(listener);
|
|
42
|
-
return () => this.listeners.delete(listener);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private updateState(partial: Partial<AxiomState<T>>) {
|
|
46
|
-
this.state = { ...this.state, ...partial };
|
|
47
|
-
this.listeners.forEach((l) => l(this.state));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
public fetch(force: boolean = false, debug: boolean = false) {
|
|
51
|
-
if (this.state.isFetching && !force) return;
|
|
52
|
-
|
|
53
|
-
this.updateState({
|
|
54
|
-
isFetching: true,
|
|
55
|
-
status: this.state.data ? "success" : "loading",
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const reqId = getNextReqId();
|
|
59
|
-
this.currentReqId = reqId;
|
|
60
|
-
|
|
61
|
-
// FIX: Bypass the dictionary lookup. We already have the metadata from the generated SDK!
|
|
62
|
-
const syntheticRoute: Route = {
|
|
63
|
-
id: this.def.endpointId,
|
|
64
|
-
namespace: this.def.namespace,
|
|
65
|
-
name: this.def.name || "unknown",
|
|
66
|
-
method: this.def.method,
|
|
67
|
-
pathTemplate: this.def.path,
|
|
68
|
-
isStream: !!this.def.isStream,
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// Auto-interpolate {path_params} and ?query_params
|
|
72
|
-
const { path } = buildRequestPath(syntheticRoute, this.def.args);
|
|
73
|
-
|
|
74
|
-
if (debug) {
|
|
75
|
-
console.groupCollapsed(
|
|
76
|
-
`%c➔ WASM QUERY [#${reqId}]`,
|
|
77
|
-
`color: #7c3aed; font-weight: bold;`,
|
|
78
|
-
);
|
|
79
|
-
console.log("Namespace:", this.def.namespace);
|
|
80
|
-
console.log("Endpoint ID:", this.def.endpointId);
|
|
81
|
-
console.log("Path:", path);
|
|
82
|
-
console.groupEnd();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
pendingRequests.set(reqId, {
|
|
86
|
-
isStream: !!this.def.isStream,
|
|
87
|
-
onResponse: (response) => {
|
|
88
|
-
if (this.currentReqId !== reqId) return;
|
|
89
|
-
|
|
90
|
-
if (debug) {
|
|
91
|
-
const evtName =
|
|
92
|
-
response.eventType === 1
|
|
93
|
-
? "NetworkSuccess"
|
|
94
|
-
: response.eventType === 2
|
|
95
|
-
? "CacheHit"
|
|
96
|
-
: response.eventType === 3
|
|
97
|
-
? "CacheHitAndFetching"
|
|
98
|
-
: response.eventType === 4
|
|
99
|
-
? "Error"
|
|
100
|
-
: "Complete";
|
|
101
|
-
console.groupCollapsed(
|
|
102
|
-
`%c← WASM RESP [#${reqId}]`,
|
|
103
|
-
`color: #059669; font-weight: bold;`,
|
|
104
|
-
);
|
|
105
|
-
console.log("Event Type:", evtName);
|
|
106
|
-
if (response.data) console.log("Data:", response.data);
|
|
107
|
-
if (response.error) console.log("Error:", response.error);
|
|
108
|
-
console.groupEnd();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (response.eventType === 4) {
|
|
112
|
-
this.updateState({
|
|
113
|
-
status: "error",
|
|
114
|
-
error: response.error || null,
|
|
115
|
-
isFetching: false,
|
|
116
|
-
});
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (response.data) {
|
|
121
|
-
try {
|
|
122
|
-
const decodedData = this.def.decoder(response.data);
|
|
123
|
-
let source: "cache" | "network" = "network";
|
|
124
|
-
let isFetching = false;
|
|
125
|
-
|
|
126
|
-
if (response.eventType === 2) {
|
|
127
|
-
source = "cache";
|
|
128
|
-
isFetching = false;
|
|
129
|
-
} else if (response.eventType === 3) {
|
|
130
|
-
source = "cache";
|
|
131
|
-
isFetching = true;
|
|
132
|
-
} else if (response.eventType === 1) {
|
|
133
|
-
source = "network";
|
|
134
|
-
isFetching = false;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
this.updateState({
|
|
138
|
-
status: "success",
|
|
139
|
-
data: decodedData,
|
|
140
|
-
error: null,
|
|
141
|
-
isFetching,
|
|
142
|
-
source,
|
|
143
|
-
});
|
|
144
|
-
} catch (e) {
|
|
145
|
-
this.updateState({
|
|
146
|
-
status: "error",
|
|
147
|
-
error: { message: "Decoding failed", details: String(e) } as any,
|
|
148
|
-
isFetching: false,
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
onComplete: () => {
|
|
154
|
-
if (this.currentReqId !== reqId) return;
|
|
155
|
-
this.updateState({ isFetching: false });
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
const isFormUrlEncoded = Object.entries(this.def.headers || {}).some(
|
|
160
|
-
([k, v]) =>
|
|
161
|
-
k.toLowerCase() === "content-type" &&
|
|
162
|
-
v.includes("application/x-www-form-urlencoded"),
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
let payloadPtr = 0,
|
|
166
|
-
payloadLen = 0;
|
|
167
|
-
if (this.def.payload !== undefined && this.def.payload !== null) {
|
|
168
|
-
const safePayload = this.def.serializer
|
|
169
|
-
? this.def.serializer(this.def.payload)
|
|
170
|
-
: this.def.payload;
|
|
171
|
-
let payloadBytes: Uint8Array;
|
|
172
|
-
|
|
173
|
-
if (isFormUrlEncoded && typeof safePayload === "object") {
|
|
174
|
-
const params = new URLSearchParams();
|
|
175
|
-
for (const [k, v] of Object.entries(safePayload))
|
|
176
|
-
params.append(k, String(v));
|
|
177
|
-
payloadBytes = new TextEncoder().encode(params.toString());
|
|
178
|
-
} else {
|
|
179
|
-
payloadBytes = new TextEncoder().encode(JSON.stringify(safePayload));
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
payloadPtr = allocBytes(payloadBytes);
|
|
183
|
-
payloadLen = payloadBytes.length;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const nsStr = allocString(this.def.namespace);
|
|
187
|
-
const mStr = allocString(this.def.method);
|
|
188
|
-
const pStr = allocString(path);
|
|
189
|
-
const tpStr = allocString("");
|
|
190
|
-
const hStr = allocString(
|
|
191
|
-
this.def.headers ? JSON.stringify(this.def.headers) : "",
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
wasmEngine.axiom_wasm_call(
|
|
195
|
-
reqId,
|
|
196
|
-
nsStr.ptr,
|
|
197
|
-
nsStr.len,
|
|
198
|
-
this.def.endpointId,
|
|
199
|
-
mStr.ptr,
|
|
200
|
-
mStr.len,
|
|
201
|
-
pStr.ptr,
|
|
202
|
-
pStr.len,
|
|
203
|
-
tpStr.ptr,
|
|
204
|
-
tpStr.len,
|
|
205
|
-
hStr.ptr,
|
|
206
|
-
hStr.len,
|
|
207
|
-
payloadPtr,
|
|
208
|
-
payloadLen,
|
|
209
|
-
);
|
|
210
|
-
|
|
211
|
-
wasmEngine.axiom_free_memory(nsStr.ptr, nsStr.len);
|
|
212
|
-
wasmEngine.axiom_free_memory(mStr.ptr, mStr.len);
|
|
213
|
-
wasmEngine.axiom_free_memory(pStr.ptr, pStr.len);
|
|
214
|
-
wasmEngine.axiom_free_memory(tpStr.ptr, tpStr.len);
|
|
215
|
-
wasmEngine.axiom_free_memory(hStr.ptr, hStr.len);
|
|
216
|
-
}
|
|
217
|
-
}
|
package/src/core/QueryManager.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// FILE: src/core/QueryManager.ts
|
|
2
|
-
import { ActiveQuery } from "./ActiveQuery";
|
|
3
|
-
import { AxiomQueryDef } from "../utils/core-bridge";
|
|
4
|
-
|
|
5
|
-
class QueryManager {
|
|
6
|
-
private queries = new Map<string, ActiveQuery<any>>();
|
|
7
|
-
|
|
8
|
-
private buildKey(
|
|
9
|
-
namespace: string,
|
|
10
|
-
endpointId: number,
|
|
11
|
-
args: Record<string, any>,
|
|
12
|
-
): string {
|
|
13
|
-
// EXACT ATMX Core Cache Key Match!
|
|
14
|
-
return `${namespace}:${endpointId}:${JSON.stringify(args)}`;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
public getQuery<T>(def: AxiomQueryDef<T>): ActiveQuery<T> {
|
|
18
|
-
const key = this.buildKey(def.namespace, def.endpointId, def.args);
|
|
19
|
-
|
|
20
|
-
if (this.queries.has(key)) {
|
|
21
|
-
return this.queries.get(key) as ActiveQuery<T>;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const newQuery = new ActiveQuery<T>(key, def);
|
|
25
|
-
this.queries.set(key, newQuery);
|
|
26
|
-
return newQuery;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
public invalidate(
|
|
30
|
-
namespace: string,
|
|
31
|
-
endpointId: number,
|
|
32
|
-
args: Record<string, any>,
|
|
33
|
-
) {
|
|
34
|
-
const key = this.buildKey(namespace, endpointId, args);
|
|
35
|
-
const query = this.queries.get(key);
|
|
36
|
-
if (query) query.fetch(true);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export const axiomQueryManager = new QueryManager();
|
package/src/hooks/useAxiom.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// src/hooks/useAxiom.ts
|
|
2
|
-
import { useContext } from 'react';
|
|
3
|
-
import { AxiomContext } from '../context/AxiomProvider';
|
|
4
|
-
|
|
5
|
-
export const useAxiom = () => {
|
|
6
|
-
const context = useContext(AxiomContext);
|
|
7
|
-
|
|
8
|
-
if (context === undefined) {
|
|
9
|
-
throw new Error("useAxiom must be used within an <AxiomProvider>. Did you forget to wrap your app?");
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return context;
|
|
13
|
-
};
|