baked-recipe-admin
Version:
Baked is an opinionated framework for .NET in backend and Nuxt in frontend. This is a recipe package that brings together all the components one needs for an Admin UI.
204 lines (159 loc) • 4.68 kB
JavaScript
import { useRuntimeConfig } from "#app";
import { useComposableResolver, useUnref } from "#imports";
export default function() {
const datas = {
"Composite": Composite({ parentFetch: fetch, parentFetchParameters: fetchParameters }),
"Computed": Computed(),
"Injected": Injected(),
"Inline": Inline(),
"Remote": Remote({ parentFetch: fetch })
};
function shouldLoad(dataType) {
return datas[dataType]?.fetch !== undefined;
}
function get({ data, injectedData }) {
const type = data?.type;
if(!type) { return null; }
if(!datas[type]) { return null; }
if(!datas[type].get) { return null; }
return datas[type].get({ data, injectedData });
}
async function fetch({ data, injectedData }) {
const fetcher = datas[data?.type];
if(!fetcher) { throw new Error(`${data?.type} is not a valid data type`); }
return fetcher.get
? fetcher.get({ data, injectedData })
: await fetcher.fetch({ data, injectedData });
}
async function fetchParameters({ data, injectedData }) {
const fetcher = datas[data?.type];
return fetcher?.fetchParameters
? fetcher.fetchParameters({ data, injectedData })
: [];
}
return {
shouldLoad,
get,
fetch,
fetchParameters
};
}
function Composite({ parentFetch, parentFetchParameters }) {
const unref = useUnref();
async function fetch({ data, injectedData }) {
const result = {};
for(const part of data.parts) {
Object.assign(
result,
unref.deepUnref(await parentFetch({ data: part, injectedData }))
);
}
return result;
}
async function fetchParameters({ data, injectedData }) {
const result = [];
for(const part of data.parts) {
result.push(
...unref.deepUnref(await parentFetchParameters({ data: part, injectedData }))
);
}
return result;
}
return {
fetch,
fetchParameters
};
}
function Computed() {
const composableResolver = useComposableResolver();
async function fetch({ data }) {
const composable = (await composableResolver.resolve(data.composable)).default();
if(composable.compute) {
return composable.compute(...(data.args || []));
}
if(composable.computeAsync) {
return await composable.computeAsync(...(data.args || []));
}
throw new Error("Data composable should have either `compute` or `computeAsync`");
}
function fetchParameters({ data }) {
return data.args;
}
return {
fetch,
fetchParameters
};
}
function Injected() {
function get({ data, injectedData }) {
const result = injectedData[data.key];
if(!data.prop) { return result; }
return result.value?.[data.prop];
}
return {
get
};
}
function Inline() {
function get({ data }) {
return data.value;
}
return {
get
};
}
function Remote({ parentFetch }) {
const { public: { composables } } = useRuntimeConfig();
const unref = useUnref();
async function fetch({ data, injectedData }) {
const baseURL = composables.useDataFetcher.baseURL;
const headers = await fetchHeaders({ data, injectedData });
const query = await fetchQuery({ data, injectedData });
const options = { baseURL, headers: headers, query: query };
if(data.attributes) {
options.attributes = data.attributes;
}
const retry = composables?.useDataFetcher?.retry ?? false;
if(retry) {
return await fetchWithRetry(data.path, options, retry);
}
return await $fetch(data.path, { ...options, retry: false });
}
async function fetchHeaders({ data, injectedData }) {
return data.headers
? unref.deepUnref(await parentFetch({ data: data.headers, injectedData }))
: { };
}
async function fetchQuery({ data, injectedData }) {
return data.query
? unref.deepUnref(await parentFetch({ data: data.query, injectedData }))
: { };
}
async function fetchParameters(options) {
return Object.values(await fetchQuery(options));
}
async function fetchWithRetry(url, options,
{ maxRetry = Number.MAX_VALUE, delay = 200 } = { }
) {
let lastError = null;
for(let i = -1; i < maxRetry; i++) { // i starts at -1 to allow for the first attempt
try {
return await $fetch(url, { ...options, retry: false });
} catch (error) {
lastError = error;
if(error.response) { // server is up and returned and error
break;
}
await wait(delay);
}
}
throw lastError;
}
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
return {
fetch,
fetchParameters
};
}