Files
jerapah-flow/packages/web/src/api/hooks.js
T
nsrb 43e9370638 feat(scripts): enhance script return structure and context handling
- Introduced a new contract for script returns, requiring an object with `output`, `context`, and `skipRemaining` fields.
- Refactored existing scripts to align with the new return structure, ensuring compatibility with the updated context management.
- Added utility functions for normalizing context and step results, improving the handling of script execution context.
- Updated various scripts (e.g., fetch-binary, fetch-html, fetch-http) to return structured output and context, enhancing data flow and usability.
- Improved error handling for script returns, ensuring clearer feedback when invalid structures are returned.

This update significantly enhances the flexibility and clarity of script interactions within workflows.
2026-08-15 22:32:42 +07:00

392 lines
11 KiB
JavaScript

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { api } from "./client.js";
export function useBootstrap() {
return useQuery({
queryKey: ["bootstrap"],
queryFn: async () => (await api.get("/auth/bootstrap")).data,
});
}
export function useMe() {
return useQuery({
queryKey: ["me"],
queryFn: async () => {
try {
return (await api.get("/auth/me")).data;
} catch (err) {
if (err.response?.status === 401) return { user: null };
throw err;
}
},
retry: false,
});
}
export function useLogin() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (body) => (await api.post("/auth/login", body)).data,
onSuccess: (data) => {
qc.setQueryData(["me"], data);
qc.invalidateQueries({ queryKey: ["bootstrap"] });
},
});
}
export function useRegister() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (body) => (await api.post("/auth/register", body)).data,
onSuccess: (data) => {
qc.setQueryData(["me"], data);
qc.invalidateQueries({ queryKey: ["bootstrap"] });
},
});
}
export function useLogout() {
const qc = useQueryClient();
return useMutation({
mutationFn: async () => (await api.post("/auth/logout")).data,
onSuccess: () => {
qc.setQueryData(["me"], null);
qc.clear();
},
});
}
export function useDashboard() {
return useQuery({
queryKey: ["dashboard"],
queryFn: async () => (await api.get("/dashboard")).data,
refetchInterval: (query) =>
query.state.data?.running?.length ? 4000 : 15000,
});
}
export function useScripts() {
return useQuery({
queryKey: ["scripts"],
queryFn: async () => (await api.get("/scripts")).data.scripts,
});
}
export function useScript(name, enabled = true) {
return useQuery({
queryKey: ["scripts", name],
queryFn: async () => (await api.get(`/scripts/${encodeURIComponent(name)}`)).data,
enabled: Boolean(name) && enabled,
});
}
export function useSaveScript() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ name, content }) =>
(await api.put(`/scripts/${encodeURIComponent(name)}`, { content })).data,
onSuccess: (_data, vars) => {
qc.invalidateQueries({ queryKey: ["scripts"] });
qc.invalidateQueries({ queryKey: ["scripts", vars.name] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useDeleteScript() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (name) =>
(await api.delete(`/scripts/${encodeURIComponent(name)}`)).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["scripts"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useDryRunScript() {
return useMutation({
mutationFn: async ({ name, content, data, context, config, owner }) =>
(
await api.post(`/scripts/${encodeURIComponent(name)}/dry-run`, {
content,
data,
context,
config,
owner,
})
).data,
});
}
export function useWorkflows(owner) {
return useQuery({
queryKey: ["workflows", owner ?? "all"],
queryFn: async () => {
const params = owner ? { owner } : {};
return (await api.get("/workflows", { params })).data.workflows;
},
});
}
export function useWorkflow(owner, file, enabled = true) {
return useQuery({
queryKey: ["workflows", owner, file],
queryFn: async () =>
(await api.get(`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}`))
.data,
enabled: Boolean(owner && file) && enabled,
});
}
export function useOwners() {
return useQuery({
queryKey: ["owners"],
queryFn: async () => (await api.get("/owners")).data.owners,
});
}
export function useSaveWorkflow() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ owner, file, content }) =>
(
await api.put(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}`,
{ content },
)
).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["owners"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useSetWorkflowEnabled() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ owner, file, enabled }) =>
(
await api.patch(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}`,
{ enabled },
)
).data,
onSuccess: (_data, vars) => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["workflows", vars.owner, vars.file] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useDeleteWorkflow() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ owner, file }) =>
(
await api.delete(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}`,
)
).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useRunWorkflow() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ owner, file, data }) =>
(
await api.post(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}/run`,
data !== undefined ? { data } : {},
)
).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["runs"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useReregisterWorkflows() {
const qc = useQueryClient();
return useMutation({
mutationFn: async () => (await api.post("/workflows/reregister")).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["scripts"] });
qc.invalidateQueries({ queryKey: ["owners"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useRuns(filters = {}) {
const { owner, workflow, status, limit } = filters;
return useQuery({
queryKey: ["runs", { owner, workflow, status, limit }],
queryFn: async () => {
const params = {};
if (owner) params.owner = owner;
if (workflow) params.workflow = workflow;
if (status) params.status = status;
if (limit) params.limit = limit;
return (await api.get("/runs", { params })).data.runs;
},
});
}
export function useRun(id) {
return useQuery({
queryKey: ["runs", id],
queryFn: async () => (await api.get(`/runs/${encodeURIComponent(id)}`)).data,
enabled: Boolean(id),
refetchInterval: (query) =>
query.state.data?.status === "running" ? 2000 : false,
});
}
export function useUsers() {
return useQuery({
queryKey: ["users"],
queryFn: async () => (await api.get("/users")).data.users,
});
}
export function useCreateUser() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (body) => (await api.post("/users", body)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: ["users"] }),
});
}
export function useUpdateUser() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ id, ...body }) =>
(await api.patch(`/users/${encodeURIComponent(id)}`, body)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: ["users"] }),
});
}
export function useDeleteUser() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (id) =>
(await api.delete(`/users/${encodeURIComponent(id)}`)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: ["users"] }),
});
}
export function useSecrets(owner) {
return useQuery({
queryKey: ["secrets", owner ?? "all"],
queryFn: async () => {
const params = owner ? { owner } : {};
return (await api.get("/secrets", { params })).data.secrets;
},
});
}
export function useUpsertSecret() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (body) => (await api.put("/secrets", body)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: ["secrets"] }),
});
}
export function useDeleteSecret() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (id) =>
(await api.delete(`/secrets/${encodeURIComponent(id)}`)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: ["secrets"] }),
});
}
export function useKvNamespaces() {
return useQuery({
queryKey: ["kv", "namespaces"],
queryFn: async () => (await api.get("/kv/namespaces")).data.namespaces,
});
}
export function useKv(filters = {}) {
const { namespace, q, limit, offset } = filters;
return useQuery({
queryKey: ["kv", { namespace, q, limit, offset }],
queryFn: async () => {
const params = {};
if (namespace) params.namespace = namespace;
if (q) params.q = q;
if (limit != null) params.limit = limit;
if (offset != null) params.offset = offset;
return (await api.get("/kv", { params })).data;
},
});
}
export function useHttpPages() {
return useQuery({
queryKey: ["http-pages"],
queryFn: async () => (await api.get("/http-pages")).data.pages,
});
}
export function useUpsertHttpPage() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (body) => (await api.put("/http-pages", body)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: ["http-pages"] }),
});
}
export function useDeleteHttpPage() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (id) =>
(await api.delete(`/http-pages/${encodeURIComponent(id)}`)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: ["http-pages"] }),
});
}
export function useHttpAuths() {
return useQuery({
queryKey: ["http-auths"],
queryFn: async () => (await api.get("/http-auths")).data.auths,
});
}
export function useUpsertHttpAuth() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (body) => (await api.put("/http-auths", body)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: ["http-auths"] }),
});
}
export function useDeleteHttpAuth() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (id) =>
(await api.delete(`/http-auths/${encodeURIComponent(id)}`)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: ["http-auths"] }),
});
}
/** Fetch plaintext literals only (not encrypted secrets). */
export async function fetchHttpAuthLiterals(name) {
return (await api.get(`/http-auths/${encodeURIComponent(name)}/reveal`)).data;
}