Generated fetch clients are framework-agnostic - they accept plain objects as request payloads. But reactive frameworks wrap state in their own structures: SolidJS uses stores, Vue uses Ref. Passing these directly into a fetch client without unwrapping would produce incorrect request bodies.
Rather than requiring manual unwrapping before every request, KosmoJS provides an unwrap placeholder that each framework generator overrides with its own implementation. Fetch clients call unwrap internally, so reactive data flows through transparently without any extra steps.
π Implementation β
export type MaybeWrapped<T> = import("solid-js/store").Store<T> | T;
export { unwrap } from "solid-js/store";import { type Ref, unref } from "vue";
export type MaybeWrapped<T> = Ref<T> | T;
export function unwrap<T>(value: MaybeWrapped<T>): T {
return unref(value);
}// React state is always plain values - no unwrapping needed.
// The default no-op implementation is used as-is.
export type MaybeWrapped<T> = T;
export const unwrap = <T>(value: T): T => value;MaybeWrapped<T> signals that a value may be either a reactive wrapper or a plain value. unwrap extracts the plain value in either case - the caller never needs to know which it received.
π¦ Usage β
Pass reactive data directly into fetch client calls - unwrap is applied internally:
import { createStore } from "solid-js/store";
import fetchClients from "_/front/fetch";
export default function Page() {
const [formData, setFormData] = createStore({ name: "", email: "" });
const handleSubmit = async () => {
// store is unwrapped automatically inside the fetch client
await fetchClients["users"].POST([], { form: formData });
};
return <form onSubmit={handleSubmit}>...</form>;
}<script setup lang="ts">
import { ref } from "vue";
import fetchClients from "_/front/fetch";
const json = ref({ name: "", email: "" });
async function submit() {
// Ref is unwrapped automatically inside the fetch client
await fetchClients["users"].POST([], { json });
}
</script>
<template>
<form @submit.prevent="submit">...</form>
</template>π§ Custom Unwrap Logic β
For cases requiring custom unwrapping, pass an unwrap option directly to the fetch call - it overrides the generator-provided implementation for that request:
await fetchClients["users"].POST([], { json: data }, {
unwrap: (value) => { /* custom logic */ },
});This is an escape hatch for non-standard data structures or special serialization needs.