@pkhex-everywhere/react 0.1.0 → 0.2.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/CHANGELOG.md +16 -0
- package/README.md +53 -9
- package/dist/RequireGame.d.ts +5 -0
- package/dist/generated/hooks.d.ts +26 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +56 -6
- package/dist/useEngineStatus.d.ts +2 -0
- package/dist/useQuery.d.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @pkhex-everywhere/react
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- fb0df12: Binary inputs take `Uint8Array`, `ArrayBuffer`, `Blob` or `File`, and binary outputs return `Uint8Array`. `game.load(data, fileName?)` takes the name from a `File`. Generated methods and hooks document whether they need a loaded save or an open draft. A missing draft fails with the new `no-draft` error code instead of `not-found`.
|
|
8
|
+
- 938f28c: `createEngine()` starts downloading the runtime as soon as it's created in a browser (`{ lazy: true }` opts out) and reports `engine.status` with file download progress through `engine.onStatusChange`. `wasmHost()` returns one shared runtime per page, so several engines on a page all get changes and events.
|
|
9
|
+
- eab17a2: `react` adds `useEngineStatus()` and `<RequireGame fallback>`, and `useQuery` rewrites `no-save` and `no-draft` messages to name the call and the fix. `engine` no longer exports `createClient`, `affects`, `queryTopics`, `Invoke`, `AssemblyExports` or `EngineExports`, and `engine.call` is gone.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [fb0df12]
|
|
14
|
+
- Updated dependencies [938f28c]
|
|
15
|
+
- Updated dependencies [38e32c9]
|
|
16
|
+
- Updated dependencies [eab17a2]
|
|
17
|
+
- @pkhex-everywhere/engine@0.2.0
|
|
18
|
+
|
|
3
19
|
## 0.1.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -10,38 +10,82 @@ npm install @pkhex-everywhere/engine @pkhex-everywhere/react
|
|
|
10
10
|
|
|
11
11
|
## Example
|
|
12
12
|
|
|
13
|
+
This app opens a save from a file input, lists the party and downloads the edited save:
|
|
14
|
+
|
|
13
15
|
```tsx
|
|
14
|
-
import { Suspense } from 'react'
|
|
16
|
+
import { Suspense, type ChangeEvent } from 'react'
|
|
15
17
|
import { createEngine } from '@pkhex-everywhere/engine'
|
|
16
|
-
import { EngineProvider, useParty } from '@pkhex-everywhere/react'
|
|
18
|
+
import { EngineProvider, RequireGame, useEngineStatus, useLoadedGame, useParty } from '@pkhex-everywhere/react'
|
|
17
19
|
|
|
18
20
|
const engine = createEngine()
|
|
19
21
|
|
|
22
|
+
function Booting() {
|
|
23
|
+
const { loaded, total } = useEngineStatus()
|
|
24
|
+
return <progress value={loaded} max={total || 1} />
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function OpenSave() {
|
|
28
|
+
const { load } = useLoadedGame()
|
|
29
|
+
const open = (event: ChangeEvent<HTMLInputElement>) => {
|
|
30
|
+
const file = event.target.files?.[0]
|
|
31
|
+
if (file) void load(file)
|
|
32
|
+
}
|
|
33
|
+
return <input type="file" onChange={open} />
|
|
34
|
+
}
|
|
35
|
+
|
|
20
36
|
function Party() {
|
|
21
37
|
const { party } = useParty()
|
|
22
38
|
return (
|
|
23
|
-
<ul>
|
|
39
|
+
<ul id="party">
|
|
24
40
|
{party.map((pokemon) => (
|
|
25
|
-
<li key={pokemon.id}>
|
|
26
|
-
{pokemon.species} Lv. {pokemon.level}
|
|
27
|
-
</li>
|
|
41
|
+
<li key={pokemon.id}>{pokemon.species}</li>
|
|
28
42
|
))}
|
|
29
43
|
</ul>
|
|
30
44
|
)
|
|
31
45
|
}
|
|
32
46
|
|
|
47
|
+
function Download() {
|
|
48
|
+
const { export: exportSave } = useLoadedGame()
|
|
49
|
+
const download = async () => {
|
|
50
|
+
const { bytes, fileName } = await exportSave()
|
|
51
|
+
const url = URL.createObjectURL(new Blob([bytes]))
|
|
52
|
+
const link = document.createElement('a')
|
|
53
|
+
link.href = url
|
|
54
|
+
link.download = fileName
|
|
55
|
+
link.click()
|
|
56
|
+
setTimeout(() => URL.revokeObjectURL(url))
|
|
57
|
+
}
|
|
58
|
+
return <button onClick={download}>Download</button>
|
|
59
|
+
}
|
|
60
|
+
|
|
33
61
|
export function App() {
|
|
34
62
|
return (
|
|
35
63
|
<EngineProvider engine={engine}>
|
|
36
|
-
<Suspense fallback=
|
|
37
|
-
<
|
|
64
|
+
<Suspense fallback={<Booting />}>
|
|
65
|
+
<RequireGame fallback={<OpenSave />}>
|
|
66
|
+
<Party />
|
|
67
|
+
<Download />
|
|
68
|
+
</RequireGame>
|
|
38
69
|
</Suspense>
|
|
39
70
|
</EngineProvider>
|
|
40
71
|
)
|
|
41
72
|
}
|
|
42
73
|
```
|
|
43
74
|
|
|
44
|
-
|
|
75
|
+
The Suspense fallback shows the runtime download with `useEngineStatus()`. `<RequireGame>` renders its fallback until a save is loaded, then its children. If the runtime fails to load, the hooks throw the error to the nearest error boundary.
|
|
76
|
+
|
|
77
|
+
CI builds this app from the packed packages and runs it.
|
|
78
|
+
|
|
79
|
+
## Hooks that need a save
|
|
80
|
+
|
|
81
|
+
Most hooks throw `no-save` when no save is loaded, so render them inside `<RequireGame>`. Hover a hook to see what it needs. A hook that runs without a save fails with a message naming the call and the fix, and the error's `code` stays `no-save`. The same goes for `no-draft`.
|
|
82
|
+
|
|
83
|
+
These work without a save:
|
|
84
|
+
|
|
85
|
+
- `useEngineStatus()`
|
|
86
|
+
- `useEngine()`
|
|
87
|
+
- `useLoadedGame()`, where `game` is `null` until a save is loaded
|
|
88
|
+
- `useQuery` with `game.get`, `game.version`, `game.blankVersions`, `catalog.names` and the `plugins.*` queries
|
|
45
89
|
|
|
46
90
|
## License
|
|
47
91
|
|
|
@@ -1,43 +1,66 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Binary, ItemHandle, PokemonHandle, PokemonPatch, TrainerGender } from '@pkhex-everywhere/engine';
|
|
2
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
2
3
|
export declare function useBox(): {
|
|
4
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
3
5
|
addEncounter: (index: number) => Promise<import("@pkhex-everywhere/engine").AddedPokemon>;
|
|
4
|
-
|
|
6
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
7
|
+
addFromFile: (bytes: Binary) => Promise<import("@pkhex-everywhere/engine").AddedPokemon>;
|
|
5
8
|
box: import("@pkhex-everywhere/engine").PokemonSummary[];
|
|
6
9
|
};
|
|
10
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
7
11
|
export declare function useEvents(): {
|
|
12
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
8
13
|
giveTickets: (includeOldSeaMap: boolean) => Promise<string[]>;
|
|
14
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
9
15
|
setFlag: (index: number, value: boolean) => Promise<void>;
|
|
16
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
10
17
|
setWork: (index: number, value: number) => Promise<void>;
|
|
11
18
|
events: import("@pkhex-everywhere/engine").SaveEvents | null;
|
|
12
19
|
};
|
|
13
20
|
export declare function useLoadedGame(): {
|
|
14
21
|
close: () => Promise<void>;
|
|
22
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
15
23
|
export: () => Promise<import("@pkhex-everywhere/engine").ExportedSave>;
|
|
16
24
|
file: () => Promise<import("@pkhex-everywhere/engine").LoadedSave | null>;
|
|
17
|
-
load: (data:
|
|
25
|
+
load: (data: Binary, fileName?: string | null) => Promise<void>;
|
|
18
26
|
loadBlank: (version: number) => Promise<void>;
|
|
19
27
|
game: import("@pkhex-everywhere/engine").SaveSummary | null;
|
|
20
28
|
};
|
|
29
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
21
30
|
export declare function useInventory(): {
|
|
31
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
22
32
|
setItem: (at: ItemHandle, count: number) => Promise<void>;
|
|
23
33
|
inventory: import("@pkhex-everywhere/engine").Pouch[];
|
|
24
34
|
};
|
|
35
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
25
36
|
export declare function useParty(): {
|
|
26
37
|
party: import("@pkhex-everywhere/engine").PokemonSummary[];
|
|
27
38
|
};
|
|
39
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
28
40
|
export declare function usePokemon(at: PokemonHandle): {
|
|
41
|
+
/** Requires a loaded save and an open draft; throws `no-save` or `no-draft` otherwise. Wrap in `<RequireGame>`. */
|
|
29
42
|
addToBox: () => Promise<import("@pkhex-everywhere/engine").AddedPokemon>;
|
|
43
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
30
44
|
clone: () => Promise<void>;
|
|
45
|
+
/** Requires a loaded save and an open draft; throws `no-save` or `no-draft` otherwise. Wrap in `<RequireGame>`. */
|
|
31
46
|
commit: () => Promise<import("@pkhex-everywhere/engine").PokemonId>;
|
|
47
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
32
48
|
edit: () => Promise<void>;
|
|
49
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
33
50
|
setLevel: (level: number) => Promise<void>;
|
|
51
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
34
52
|
update: (patch: PokemonPatch) => Promise<void>;
|
|
35
53
|
pokemon: import("@pkhex-everywhere/engine").PokemonSummary;
|
|
36
54
|
};
|
|
55
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
37
56
|
export declare function useTrainer(): {
|
|
57
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
38
58
|
setBattlePoints: (value: number) => Promise<void>;
|
|
59
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
39
60
|
setGender: (gender: TrainerGender) => Promise<void>;
|
|
61
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
40
62
|
setMoney: (amount: number) => Promise<void>;
|
|
63
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
41
64
|
setName: (name: string) => Promise<void>;
|
|
42
65
|
trainer: import("@pkhex-everywhere/engine").TrainerCard;
|
|
43
66
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { EngineProvider, useEngine } from './EngineProvider';
|
|
2
2
|
export { useQuery, type CallArgs, type CallResult } from './useQuery';
|
|
3
|
+
export { useEngineStatus } from './useEngineStatus';
|
|
4
|
+
export { RequireGame } from './RequireGame';
|
|
3
5
|
export * from './generated/hooks';
|
|
4
6
|
export { usePokemonDetails } from './usePokemonDetails';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createContext, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
2
|
-
import { EngineError
|
|
2
|
+
import { EngineError } from "@pkhex-everywhere/engine";
|
|
3
|
+
import { affects, call, queryTopics } from "@pkhex-everywhere/engine/internal";
|
|
3
4
|
import { jsx } from "react/jsx-runtime";
|
|
4
5
|
//#region src/cache.ts
|
|
5
6
|
var QueryCache = class {
|
|
@@ -91,33 +92,59 @@ function useEngine() {
|
|
|
91
92
|
}
|
|
92
93
|
//#endregion
|
|
93
94
|
//#region src/useQuery.ts
|
|
94
|
-
|
|
95
|
+
var fixes = {
|
|
96
|
+
"no-save": (name) => `${name} needs a loaded save. Load one with useLoadedGame().load(file) and wrap the component in <RequireGame>.`,
|
|
97
|
+
"no-draft": (name) => `${name} needs an open draft. Open one with usePokemon(at).edit() or .clone() first.`
|
|
98
|
+
};
|
|
99
|
+
function explain(name, error) {
|
|
100
|
+
if (!(error instanceof EngineError)) return error;
|
|
101
|
+
const fix = fixes[error.code];
|
|
102
|
+
return fix ? new EngineError(error.code, fix(name)) : error;
|
|
103
|
+
}
|
|
104
|
+
function useQuery(name, ...args) {
|
|
95
105
|
const { engine, cache } = useEngineContext();
|
|
96
|
-
const key = JSON.stringify([
|
|
97
|
-
const
|
|
106
|
+
const key = JSON.stringify([name, args]);
|
|
107
|
+
const load = () => call(engine, name, args).catch((error) => {
|
|
108
|
+
throw explain(name, error);
|
|
109
|
+
});
|
|
110
|
+
const entry = useSyncExternalStore(cache.subscribe, () => cache.peek(key)) ?? cache.get(key, queryTopics[name], load);
|
|
98
111
|
if (entry.status === "pending") throw entry.promise;
|
|
99
112
|
if (entry.status === "error") throw entry.error;
|
|
100
113
|
return entry.value;
|
|
101
114
|
}
|
|
102
115
|
//#endregion
|
|
116
|
+
//#region src/useEngineStatus.ts
|
|
117
|
+
function useEngineStatus() {
|
|
118
|
+
const engine = useEngine();
|
|
119
|
+
const read = () => engine.status;
|
|
120
|
+
return useSyncExternalStore(engine.onStatusChange, read, read);
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
103
123
|
//#region src/generated/hooks.ts
|
|
124
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
104
125
|
function useBox() {
|
|
105
126
|
const engine = useEngine();
|
|
106
127
|
return {
|
|
107
128
|
box: useQuery("box.get"),
|
|
108
129
|
...useMemo(() => ({
|
|
130
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
109
131
|
addEncounter: (index) => engine.box.addEncounter(index),
|
|
132
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
110
133
|
addFromFile: (bytes) => engine.box.addFromFile(bytes)
|
|
111
134
|
}), [engine])
|
|
112
135
|
};
|
|
113
136
|
}
|
|
137
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
114
138
|
function useEvents() {
|
|
115
139
|
const engine = useEngine();
|
|
116
140
|
return {
|
|
117
141
|
events: useQuery("events.get"),
|
|
118
142
|
...useMemo(() => ({
|
|
143
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
119
144
|
giveTickets: (includeOldSeaMap) => engine.events.giveTickets(includeOldSeaMap),
|
|
145
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
120
146
|
setFlag: (index, value) => engine.events.setFlag(index, value),
|
|
147
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
121
148
|
setWork: (index, value) => engine.events.setWork(index, value)
|
|
122
149
|
}), [engine])
|
|
123
150
|
};
|
|
@@ -128,6 +155,7 @@ function useLoadedGame() {
|
|
|
128
155
|
game: useQuery("game.get"),
|
|
129
156
|
...useMemo(() => ({
|
|
130
157
|
close: () => engine.game.close(),
|
|
158
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
131
159
|
export: () => engine.game.export(),
|
|
132
160
|
file: () => engine.game.file(),
|
|
133
161
|
load: (data, fileName) => engine.game.load(data, fileName),
|
|
@@ -135,16 +163,21 @@ function useLoadedGame() {
|
|
|
135
163
|
}), [engine])
|
|
136
164
|
};
|
|
137
165
|
}
|
|
166
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
138
167
|
function useInventory() {
|
|
139
168
|
const engine = useEngine();
|
|
140
169
|
return {
|
|
141
170
|
inventory: useQuery("inventory.get"),
|
|
142
|
-
...useMemo(() => ({
|
|
171
|
+
...useMemo(() => ({
|
|
172
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
173
|
+
setItem: (at, count) => engine.inventory.setItem(at, count) }), [engine])
|
|
143
174
|
};
|
|
144
175
|
}
|
|
176
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
145
177
|
function useParty() {
|
|
146
178
|
return { party: useQuery("party.get") };
|
|
147
179
|
}
|
|
180
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
148
181
|
function usePokemon(at) {
|
|
149
182
|
const engine = useEngine();
|
|
150
183
|
const pokemon = useQuery("pokemon.get", at);
|
|
@@ -152,28 +185,45 @@ function usePokemon(at) {
|
|
|
152
185
|
return {
|
|
153
186
|
pokemon,
|
|
154
187
|
...useMemo(() => ({
|
|
188
|
+
/** Requires a loaded save and an open draft; throws `no-save` or `no-draft` otherwise. Wrap in `<RequireGame>`. */
|
|
155
189
|
addToBox: () => engine.pokemon.addToBox(),
|
|
190
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
156
191
|
clone: () => engine.pokemon.clone(at),
|
|
192
|
+
/** Requires a loaded save and an open draft; throws `no-save` or `no-draft` otherwise. Wrap in `<RequireGame>`. */
|
|
157
193
|
commit: () => engine.pokemon.commit(),
|
|
194
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
158
195
|
edit: () => engine.pokemon.edit(at),
|
|
196
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
159
197
|
setLevel: (level) => engine.pokemon.setLevel(at, level),
|
|
198
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
160
199
|
update: (patch) => engine.pokemon.update(at, patch)
|
|
161
200
|
}), [engine, key])
|
|
162
201
|
};
|
|
163
202
|
}
|
|
203
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
164
204
|
function useTrainer() {
|
|
165
205
|
const engine = useEngine();
|
|
166
206
|
return {
|
|
167
207
|
trainer: useQuery("trainer.get"),
|
|
168
208
|
...useMemo(() => ({
|
|
209
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
169
210
|
setBattlePoints: (value) => engine.trainer.setBattlePoints(value),
|
|
211
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
170
212
|
setGender: (gender) => engine.trainer.setGender(gender),
|
|
213
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
171
214
|
setMoney: (amount) => engine.trainer.setMoney(amount),
|
|
215
|
+
/** Requires a loaded save; throws `no-save` otherwise. Wrap in `<RequireGame>`. */
|
|
172
216
|
setName: (name) => engine.trainer.setName(name)
|
|
173
217
|
}), [engine])
|
|
174
218
|
};
|
|
175
219
|
}
|
|
176
220
|
//#endregion
|
|
221
|
+
//#region src/RequireGame.tsx
|
|
222
|
+
function RequireGame({ fallback = null, children }) {
|
|
223
|
+
const { game } = useLoadedGame();
|
|
224
|
+
return game ? children : fallback;
|
|
225
|
+
}
|
|
226
|
+
//#endregion
|
|
177
227
|
//#region src/usePokemonDetails.ts
|
|
178
228
|
function usePokemonDetails(at) {
|
|
179
229
|
const engine = useEngine();
|
|
@@ -185,4 +235,4 @@ function usePokemonDetails(at) {
|
|
|
185
235
|
};
|
|
186
236
|
}
|
|
187
237
|
//#endregion
|
|
188
|
-
export { EngineProvider, useBox, useEngine, useEvents, useInventory, useLoadedGame, useParty, usePokemon, usePokemonDetails, useQuery, useTrainer };
|
|
238
|
+
export { EngineProvider, RequireGame, useBox, useEngine, useEngineStatus, useEvents, useInventory, useLoadedGame, useParty, usePokemon, usePokemonDetails, useQuery, useTrainer };
|
package/dist/useQuery.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ type Lookup<T, Path extends string> = Path extends `${infer Head}.${infer Rest}`
|
|
|
3
3
|
type CallFunction<Name extends CallName> = Extract<Lookup<EngineClient, Name>, (...args: never[]) => Promise<unknown>>;
|
|
4
4
|
export type CallArgs<Name extends CallName> = Parameters<CallFunction<Name>>;
|
|
5
5
|
export type CallResult<Name extends CallName> = Awaited<ReturnType<CallFunction<Name>>>;
|
|
6
|
-
export declare function useQuery<Name extends QueryName>(
|
|
6
|
+
export declare function useQuery<Name extends QueryName>(name: Name, ...args: CallArgs<Name>): CallResult<Name>;
|
|
7
7
|
export {};
|