restructure project, add claudemd
This commit is contained in:
163
web/runtime/@solidjs/router/dist/data/action.js
vendored
Normal file
163
web/runtime/@solidjs/router/dist/data/action.js
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js";
|
||||
import { isServer } from "solid-js/web";
|
||||
import { useRouter } from "../routing.js";
|
||||
import { mockBase, setFunctionName } from "../utils.js";
|
||||
import { cacheKeyOp, hashKey, revalidate, query } from "./query.js";
|
||||
export const actions = /* #__PURE__ */ new Map();
|
||||
export function useSubmissions(fn, filter) {
|
||||
const router = useRouter();
|
||||
const subs = createMemo(() => router.submissions[0]().filter(s => s.url === fn.base && (!filter || filter(s.input))));
|
||||
return new Proxy([], {
|
||||
get(_, property) {
|
||||
if (property === $TRACK)
|
||||
return subs();
|
||||
if (property === "pending")
|
||||
return subs().some(sub => !sub.result);
|
||||
return subs()[property];
|
||||
},
|
||||
has(_, property) {
|
||||
return property in subs();
|
||||
}
|
||||
});
|
||||
}
|
||||
export function useSubmission(fn, filter) {
|
||||
const submissions = useSubmissions(fn, filter);
|
||||
return new Proxy({}, {
|
||||
get(_, property) {
|
||||
if ((submissions.length === 0 && property === "clear") || property === "retry")
|
||||
return () => { };
|
||||
return submissions[submissions.length - 1]?.[property];
|
||||
}
|
||||
});
|
||||
}
|
||||
export function useAction(action) {
|
||||
const r = useRouter();
|
||||
return (...args) => action.apply({ r }, args);
|
||||
}
|
||||
export function action(fn, options = {}) {
|
||||
function mutate(...variables) {
|
||||
const router = this.r;
|
||||
const form = this.f;
|
||||
const p = (router.singleFlight && fn.withOptions
|
||||
? fn.withOptions({ headers: { "X-Single-Flight": "true" } })
|
||||
: fn)(...variables);
|
||||
const [result, setResult] = createSignal();
|
||||
let submission;
|
||||
function handler(error) {
|
||||
return async (res) => {
|
||||
const result = await handleResponse(res, error, router.navigatorFactory());
|
||||
let retry = null;
|
||||
o.onComplete?.({
|
||||
...submission,
|
||||
result: result?.data,
|
||||
error: result?.error,
|
||||
pending: false,
|
||||
retry() {
|
||||
return (retry = submission.retry());
|
||||
}
|
||||
});
|
||||
if (retry)
|
||||
return retry;
|
||||
if (!result)
|
||||
return submission.clear();
|
||||
setResult(result);
|
||||
if (result.error && !form)
|
||||
throw result.error;
|
||||
return result.data;
|
||||
};
|
||||
}
|
||||
router.submissions[1](s => [
|
||||
...s,
|
||||
(submission = {
|
||||
input: variables,
|
||||
url,
|
||||
get result() {
|
||||
return result()?.data;
|
||||
},
|
||||
get error() {
|
||||
return result()?.error;
|
||||
},
|
||||
get pending() {
|
||||
return !result();
|
||||
},
|
||||
clear() {
|
||||
router.submissions[1](v => v.filter(i => i !== submission));
|
||||
},
|
||||
retry() {
|
||||
setResult(undefined);
|
||||
const p = fn(...variables);
|
||||
return p.then(handler(), handler(true));
|
||||
}
|
||||
})
|
||||
]);
|
||||
return p.then(handler(), handler(true));
|
||||
}
|
||||
const o = typeof options === "string" ? { name: options } : options;
|
||||
const name = o.name || (!isServer ? String(hashString(fn.toString())) : undefined);
|
||||
const url = fn.url || (name && `https://action/${name}`) || "";
|
||||
mutate.base = url;
|
||||
if (name)
|
||||
setFunctionName(mutate, name);
|
||||
return toAction(mutate, url);
|
||||
}
|
||||
function toAction(fn, url) {
|
||||
fn.toString = () => {
|
||||
if (!url)
|
||||
throw new Error("Client Actions need explicit names if server rendered");
|
||||
return url;
|
||||
};
|
||||
fn.with = function (...args) {
|
||||
const newFn = function (...passedArgs) {
|
||||
return fn.call(this, ...args, ...passedArgs);
|
||||
};
|
||||
newFn.base = fn.base;
|
||||
const uri = new URL(url, mockBase);
|
||||
uri.searchParams.set("args", hashKey(args));
|
||||
return toAction(newFn, (uri.origin === "https://action" ? uri.origin : "") + uri.pathname + uri.search);
|
||||
};
|
||||
fn.url = url;
|
||||
if (!isServer) {
|
||||
actions.set(url, fn);
|
||||
getOwner() && onCleanup(() => actions.delete(url));
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
const hashString = (s) => s.split("").reduce((a, b) => ((a << 5) - a + b.charCodeAt(0)) | 0, 0);
|
||||
async function handleResponse(response, error, navigate) {
|
||||
let data;
|
||||
let custom;
|
||||
let keys;
|
||||
let flightKeys;
|
||||
if (response instanceof Response) {
|
||||
if (response.headers.has("X-Revalidate"))
|
||||
keys = response.headers.get("X-Revalidate").split(",");
|
||||
if (response.customBody) {
|
||||
data = custom = await response.customBody();
|
||||
if (response.headers.has("X-Single-Flight")) {
|
||||
data = data._$value;
|
||||
delete custom._$value;
|
||||
flightKeys = Object.keys(custom);
|
||||
}
|
||||
}
|
||||
if (response.headers.has("Location")) {
|
||||
const locationUrl = response.headers.get("Location") || "/";
|
||||
if (locationUrl.startsWith("http")) {
|
||||
window.location.href = locationUrl;
|
||||
}
|
||||
else {
|
||||
navigate(locationUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (error)
|
||||
return { error: response };
|
||||
else
|
||||
data = response;
|
||||
// invalidate
|
||||
cacheKeyOp(keys, entry => (entry[0] = 0));
|
||||
// set cache
|
||||
flightKeys && flightKeys.forEach(k => query.set(k, custom[k]));
|
||||
// trigger revalidation
|
||||
await revalidate(keys, false);
|
||||
return data != null ? { data } : undefined;
|
||||
}
|
||||
Reference in New Issue
Block a user