Skip to main content

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​

ParameterTypeRequiredDescription
functionNamestringYesName of the exported server query function
argsRecord<string, unknown>NoArguments to pass to the query function

Return value​

PropertyTypeDescription
dataT | nullThe rows the query returned (an array; each row includes _id, _created_at and _updated_at), or null while loading or on error
isLoadingbooleantrue while the query is in flight
errorstring | nullError message if the query failed
refetch() => voidCall 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​

  • useQuery runs 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's args, and data is whatever the handler returns (see Handler-based Functions)
  • Queries are read-only - use useMutation for write operations
  • Multiple calls to useQuery with the same functionName and args are not deduplicated - if you need shared data, lift the state up