useQuery
Call a server-side query function and return its result. The query runs once on mount and can be manually refetched.
Signature
const { data, isLoading, error, refetch } = useQuery<T>(functionName: string, args?: Record<string, unknown>);
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
functionName | string | Yes | Name of the exported server query function |
args | Record<string, unknown> | No | Arguments to pass to the query function |
Return value
| Property | Type | Description |
|---|---|---|
data | T | null | The rows the query returned (an array; each row includes _id, _created_at and _updated_at), or null while loading or on error |
isLoading | boolean | true while the query is in flight |
error | string | null | Error message if the query failed |
refetch | () => void | Call to re-run the query |
Example
Define the server function in server/functions.ts:
// server/functions.ts
import { queryRows } from "@zaflun/lumio-sdk/server";
export const getRules = queryRows("rules");
Use it in a surface:
import { useQuery, List, Text, Button } from "@zaflun/lumio-sdk";
function RuleList() {
const { data: rules, isLoading, error, refetch } = useQuery("getRules");
if (isLoading) return <Text content="Loading..." variant="muted" />;
if (error) return <Text content={`Error: ${error}`} variant="muted" />;
return (
<>
<Button label="Refresh" onClick={refetch} />
<List
items={(rules ?? []).map((rule) => ({
id: rule._id,
label: rule.text,
}))}
/>
</>
);
}
Example with arguments
// server/functions.ts
import { queryRows, filter, arg } from "@zaflun/lumio-sdk/server";
export const getRulesByStatus = queryRows("rules", {
filter: filter("revealed", "=", arg("revealed")),
});
const { data: revealedRules } = useQuery("getRulesByStatus", { revealed: true });
const { data: hiddenRules } = useQuery("getRulesByStatus", { revealed: false });
Auto-refetch on storage change
useQuery does not auto-refetch when storage changes. After a mutation, call refetch() manually:
const { data, refetch } = useQuery("getRules");
const { mutate: addRule } = useMutation("addRule");
const handleAdd = async () => {
await addRule({ text: "New rule" });
refetch(); // manually refresh the list
};
How the call is resolved
useQuery sends only the function name and args. Lumio looks the name up in the functions.json of the version the installation runs and binds each arg() value as a typed SQL parameter. Your extension cannot send a table or a filter of its own, and a function marked editorOnly runs only in the Lumio dashboard: from an OBS overlay or widget it fails with Editor-only function called outside editor.
Errors are reported in error with the API's message, e.g. Unknown server function: getRule for a name the installed version does not export, or invalid value for column `revealed`: expected a boolean for a mistyped argument. The JSON-RPC error codes are the same as for useMutation.
Notes
useQueryruns on mount automatically - no need to call anything to initiate the first load- The query is rate limited to 100 calls per minute per installation
- A handler-based
query()runs on the Bot Module Worker: the params become the handler'sargs, anddatais whatever the handler returns (see Handler-based Functions) - Queries are read-only - use
useMutationfor write operations - Multiple calls to
useQuerywith the samefunctionNameandargsare not deduplicated - if you need shared data, lift the state up