@effect-app/vue 1.25.2 → 1.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/_cjs/makeClient2.cjs +270 -0
- package/_cjs/makeClient2.cjs.map +1 -0
- package/_cjs/mutate2.cjs +112 -0
- package/_cjs/mutate2.cjs.map +1 -0
- package/_cjs/query2.cjs +127 -0
- package/_cjs/query2.cjs.map +1 -0
- package/dist/makeClient2.d.ts +101 -0
- package/dist/makeClient2.d.ts.map +1 -0
- package/dist/makeClient2.js +223 -0
- package/dist/mutate2.d.ts +45 -0
- package/dist/mutate2.d.ts.map +1 -0
- package/dist/mutate2.js +86 -0
- package/dist/query2.d.ts +24 -0
- package/dist/query2.d.ts.map +1 -0
- package/dist/query2.js +119 -0
- package/package.json +33 -3
- package/src/makeClient2.ts +445 -0
- package/src/mutate2.ts +191 -0
- package/src/query2.ts +231 -0
package/dist/query2.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
5
|
+
import { isHttpRequestError, isHttpResponseError } from "@effect-app/core/http/http-client";
|
|
6
|
+
import * as Result from "@effect-rx/rx/Result";
|
|
7
|
+
import { useQuery } from "@tanstack/vue-query";
|
|
8
|
+
import { Cause, Effect, Option, Runtime, S } from "effect-app";
|
|
9
|
+
import { ServiceUnavailableError } from "effect-app/client";
|
|
10
|
+
import { computed, ref } from "vue";
|
|
11
|
+
import { makeQueryKey, reportRuntimeError } from "./internal.js";
|
|
12
|
+
export const makeQuery2 = (runtime) => {
|
|
13
|
+
// TODO: options
|
|
14
|
+
// declare function useQuery<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(options: UndefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>, queryClient?: QueryClient): UseQueryReturnType<TData, TError>;
|
|
15
|
+
// declare function useQuery<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(options: DefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>, queryClient?: QueryClient): UseQueryDefinedReturnType<TData, TError>;
|
|
16
|
+
// declare function useQuery<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(options: UseQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>, queryClient?: QueryClient): UseQueryReturnType<TData, TError>;
|
|
17
|
+
const useSafeQuery_ = (q, arg, options = {} // TODO
|
|
18
|
+
) => {
|
|
19
|
+
const runPromise = Runtime.runPromise(runtime.value);
|
|
20
|
+
const arr = arg;
|
|
21
|
+
const req = !arg
|
|
22
|
+
? undefined
|
|
23
|
+
: typeof arr === "function"
|
|
24
|
+
? {
|
|
25
|
+
get value() {
|
|
26
|
+
return arr();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
: ref(arg);
|
|
30
|
+
const queryKey = makeQueryKey(q.name);
|
|
31
|
+
const handler = q.handler;
|
|
32
|
+
const r = useQuery(Effect.isEffect(handler)
|
|
33
|
+
? {
|
|
34
|
+
...options,
|
|
35
|
+
retry: (retryCount, error) => {
|
|
36
|
+
if (Runtime.isFiberFailure(error)) {
|
|
37
|
+
const cause = error[Runtime.FiberFailureCauseId];
|
|
38
|
+
const sq = Cause.squash(cause);
|
|
39
|
+
if (!isHttpRequestError(sq) && !isHttpResponseError(sq) && !S.is(ServiceUnavailableError)(sq)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return retryCount < 5;
|
|
44
|
+
},
|
|
45
|
+
queryKey,
|
|
46
|
+
queryFn: ({ signal }) => runPromise(handler
|
|
47
|
+
.pipe(Effect.tapDefect(reportRuntimeError), Effect.withSpan(`query ${q.name}`, { captureStackTrace: false })), { signal })
|
|
48
|
+
}
|
|
49
|
+
: {
|
|
50
|
+
...options,
|
|
51
|
+
retry: (retryCount, error) => {
|
|
52
|
+
if (Runtime.isFiberFailure(error)) {
|
|
53
|
+
const cause = error[Runtime.FiberFailureCauseId];
|
|
54
|
+
const sq = Cause.squash(cause);
|
|
55
|
+
if (!isHttpRequestError(sq) && !isHttpResponseError(sq) && !S.is(ServiceUnavailableError)(sq)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return retryCount < 5;
|
|
60
|
+
},
|
|
61
|
+
queryKey: [...queryKey, req],
|
|
62
|
+
queryFn: ({ signal }) => runPromise(handler(req.value)
|
|
63
|
+
.pipe(Effect.tapDefect(reportRuntimeError), Effect.withSpan(`query ${q.name}`, { captureStackTrace: false })), { signal })
|
|
64
|
+
});
|
|
65
|
+
const result = computed(() => swrToQuery({
|
|
66
|
+
error: r.error.value ?? undefined,
|
|
67
|
+
data: r.data.value,
|
|
68
|
+
isValidating: r.isFetching.value
|
|
69
|
+
}));
|
|
70
|
+
const latestSuccess = computed(() => Option.getOrUndefined(Result.value(result.value)));
|
|
71
|
+
return [
|
|
72
|
+
result,
|
|
73
|
+
latestSuccess,
|
|
74
|
+
// one thing to keep in mind is that span will be disconnected as Context does not pass from outside.
|
|
75
|
+
(options) => Effect.promise(() => r.refetch(options)),
|
|
76
|
+
r
|
|
77
|
+
];
|
|
78
|
+
};
|
|
79
|
+
function swrToQuery(r) {
|
|
80
|
+
if (r.error) {
|
|
81
|
+
return Result.failureWithPrevious(r.error[Runtime.FiberFailureCauseId], r.data === undefined ? Option.none() : Option.some(Result.success(r.data)), r.isValidating);
|
|
82
|
+
}
|
|
83
|
+
if (r.data !== undefined) {
|
|
84
|
+
return Result.success(r.data, r.isValidating);
|
|
85
|
+
}
|
|
86
|
+
return Result.initial(r.isValidating);
|
|
87
|
+
}
|
|
88
|
+
function useSafeQuery(self,
|
|
89
|
+
/*
|
|
90
|
+
q:
|
|
91
|
+
| {
|
|
92
|
+
handler: (
|
|
93
|
+
req: I
|
|
94
|
+
) => Effect<
|
|
95
|
+
A,
|
|
96
|
+
E,
|
|
97
|
+
R
|
|
98
|
+
>
|
|
99
|
+
mapPath: (req: I) => string
|
|
100
|
+
name: string
|
|
101
|
+
}
|
|
102
|
+
| {
|
|
103
|
+
handler: Effect<
|
|
104
|
+
A,
|
|
105
|
+
E,
|
|
106
|
+
R
|
|
107
|
+
>
|
|
108
|
+
mapPath: string
|
|
109
|
+
name: string
|
|
110
|
+
},
|
|
111
|
+
*/
|
|
112
|
+
argOrOptions, options) {
|
|
113
|
+
return Effect.isEffect(self.handler)
|
|
114
|
+
? useSafeQuery_(self, undefined, argOrOptions)
|
|
115
|
+
: useSafeQuery_(self, argOrOptions, options);
|
|
116
|
+
}
|
|
117
|
+
return useSafeQuery;
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnkyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3F1ZXJ5Mi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx1REFBdUQ7QUFDdkQsc0RBQXNEO0FBQ3RELHdEQUF3RDtBQUN4RCw0REFBNEQ7QUFDNUQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLG1CQUFtQixFQUFFLE1BQU0sbUNBQW1DLENBQUE7QUFDM0YsT0FBTyxLQUFLLE1BQU0sTUFBTSxzQkFBc0IsQ0FBQTtBQVE5QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDOUMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDOUQsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDM0QsT0FBTyxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsTUFBTSxLQUFLLENBQUE7QUFFbkMsT0FBTyxFQUFFLFlBQVksRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQWtCaEUsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHLENBQUksT0FBZ0MsRUFBRSxFQUFFO0lBQ2hFLGdCQUFnQjtJQUNoQixzUkFBc1I7SUFDdFIsMlJBQTJSO0lBQzNSLHVSQUF1UjtJQUN2UixNQUFNLGFBQWEsR0FBRyxDQUNwQixDQW9CRyxFQUNILEdBQXdCLEVBQ3hCLFVBQXdFLEVBQUUsQ0FBQyxPQUFPO01BQ2xGLEVBQUU7UUFDRixNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUNwRCxNQUFNLEdBQUcsR0FBRyxHQUFHLENBQUE7UUFDZixNQUFNLEdBQUcsR0FBaUIsQ0FBQyxHQUFHO1lBQzVCLENBQUMsQ0FBQyxTQUFTO1lBQ1gsQ0FBQyxDQUFDLE9BQU8sR0FBRyxLQUFLLFVBQVU7Z0JBQzNCLENBQUMsQ0FBRTtvQkFDRCxJQUFJLEtBQUs7d0JBQ1AsT0FBUSxHQUFXLEVBQUUsQ0FBQTtvQkFDdkIsQ0FBQztpQkFDTTtnQkFDVCxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQ1osTUFBTSxRQUFRLEdBQUcsWUFBWSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNyQyxNQUFNLE9BQU8sR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFBO1FBQ3pCLE1BQU0sQ0FBQyxHQUFHLFFBQVEsQ0FDaEIsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7WUFDdEIsQ0FBQyxDQUFDO2dCQUNBLEdBQUcsT0FBTztnQkFDVixLQUFLLEVBQUUsQ0FBQyxVQUFVLEVBQUUsS0FBSyxFQUFFLEVBQUU7b0JBQzNCLElBQUksT0FBTyxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO3dCQUNsQyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBQUE7d0JBQ2hELE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUE7d0JBQzlCLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7NEJBQzlGLE9BQU8sS0FBSyxDQUFBO3dCQUNkLENBQUM7b0JBQ0gsQ0FBQztvQkFFRCxPQUFPLFVBQVUsR0FBRyxDQUFDLENBQUE7Z0JBQ3ZCLENBQUM7Z0JBQ0QsUUFBUTtnQkFDUixPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsQ0FDdEIsVUFBVSxDQUNSLE9BQU87cUJBQ0osSUFBSSxDQUNILE1BQU0sQ0FBQyxTQUFTLENBQUMsa0JBQWtCLENBQUMsRUFDcEMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxFQUFFLGlCQUFpQixFQUFFLEtBQUssRUFBRSxDQUFDLENBQ2pFLEVBQ0gsRUFBRSxNQUFNLEVBQUUsQ0FDWDthQUNKO1lBQ0QsQ0FBQyxDQUFDO2dCQUNBLEdBQUcsT0FBTztnQkFDVixLQUFLLEVBQUUsQ0FBQyxVQUFVLEVBQUUsS0FBSyxFQUFFLEVBQUU7b0JBQzNCLElBQUksT0FBTyxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO3dCQUNsQyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBQUE7d0JBQ2hELE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUE7d0JBQzlCLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7NEJBQzlGLE9BQU8sS0FBSyxDQUFBO3dCQUNkLENBQUM7b0JBQ0gsQ0FBQztvQkFFRCxPQUFPLFVBQVUsR0FBRyxDQUFDLENBQUE7Z0JBQ3ZCLENBQUM7Z0JBQ0QsUUFBUSxFQUFFLENBQUMsR0FBRyxRQUFRLEVBQUUsR0FBRyxDQUFDO2dCQUM1QixPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsQ0FDdEIsVUFBVSxDQUNSLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDO3FCQUNmLElBQUksQ0FDSCxNQUFNLENBQUMsU0FBUyxDQUFDLGtCQUFrQixDQUFDLEVBQ3BDLE1BQU0sQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxpQkFBaUIsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUNqRSxFQUNILEVBQUUsTUFBTSxFQUFFLENBQ1g7YUFDSixDQUNKLENBQUE7UUFFRCxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQzNCLFVBQVUsQ0FBQztZQUNULEtBQUssRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssSUFBSSxTQUFTO1lBQ2pDLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUs7WUFDbEIsWUFBWSxFQUFFLENBQUMsQ0FBQyxVQUFVLENBQUMsS0FBSztTQUNqQyxDQUFDLENBQ0gsQ0FBQTtRQUNELE1BQU0sYUFBYSxHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUN2RixPQUFPO1lBQ0wsTUFBTTtZQUNOLGFBQWE7WUFDYixxR0FBcUc7WUFDckcsQ0FBQyxPQUF3QixFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDdEUsQ0FBQztTQUNPLENBQUE7SUFDWixDQUFDLENBQUE7SUFFRCxTQUFTLFVBQVUsQ0FBTyxDQUl6QjtRQUNDLElBQUksQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ1osT0FBTyxNQUFNLENBQUMsbUJBQW1CLENBQy9CLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLEVBQ3BDLENBQUMsQ0FBQyxJQUFJLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsRUFDMUUsQ0FBQyxDQUFDLFlBQVksQ0FDZixDQUFBO1FBQ0gsQ0FBQztRQUNELElBQUksQ0FBQyxDQUFDLElBQUksS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUN6QixPQUFPLE1BQU0sQ0FBQyxPQUFPLENBQU8sQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUE7UUFDckQsQ0FBQztRQUVELE9BQU8sTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUE7SUFDdkMsQ0FBQztJQTZCRCxTQUFTLFlBQVksQ0FDbkIsSUFBUztJQUNUOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0lBc0JBO0lBQ0EsWUFBa0IsRUFDbEIsT0FBYTtRQUViLE9BQU8sTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO1lBQ2xDLENBQUMsQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLFNBQVMsRUFBRSxZQUFZLENBQUM7WUFDOUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxJQUFJLEVBQUUsWUFBWSxFQUFFLE9BQU8sQ0FBQyxDQUFBO0lBQ2hELENBQUM7SUFDRCxPQUFPLFlBQVksQ0FBQTtBQUNyQixDQUFDLENBQUEifQ==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/vue",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://github.com/effect-ts-app/libs/tree/main/packages/vue",
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
"@vueuse/core": "^11.1.0",
|
|
11
11
|
"query-string": "^9.1.1",
|
|
12
12
|
"@effect-app/core": "1.17.0",
|
|
13
|
+
"@effect-app/vue": "1.26.1",
|
|
13
14
|
"effect-app": "1.30.0",
|
|
14
|
-
"@effect-app/schema": "1.19.0"
|
|
15
|
-
"@effect-app/vue": "1.25.2"
|
|
15
|
+
"@effect-app/schema": "1.19.0"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
18
|
"@effect/platform": "^0.68.5",
|
|
@@ -102,6 +102,16 @@
|
|
|
102
102
|
"default": "./_cjs/makeClient.cjs"
|
|
103
103
|
}
|
|
104
104
|
},
|
|
105
|
+
"./makeClient2": {
|
|
106
|
+
"import": {
|
|
107
|
+
"types": "./dist/makeClient2.d.ts",
|
|
108
|
+
"default": "./dist/makeClient2.js"
|
|
109
|
+
},
|
|
110
|
+
"require": {
|
|
111
|
+
"types": "./dist/makeClient2.d.ts",
|
|
112
|
+
"default": "./_cjs/makeClient2.cjs"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
105
115
|
"./makeContext": {
|
|
106
116
|
"import": {
|
|
107
117
|
"types": "./dist/makeContext.d.ts",
|
|
@@ -132,6 +142,16 @@
|
|
|
132
142
|
"default": "./_cjs/mutate.cjs"
|
|
133
143
|
}
|
|
134
144
|
},
|
|
145
|
+
"./mutate2": {
|
|
146
|
+
"import": {
|
|
147
|
+
"types": "./dist/mutate2.d.ts",
|
|
148
|
+
"default": "./dist/mutate2.js"
|
|
149
|
+
},
|
|
150
|
+
"require": {
|
|
151
|
+
"types": "./dist/mutate2.d.ts",
|
|
152
|
+
"default": "./_cjs/mutate2.cjs"
|
|
153
|
+
}
|
|
154
|
+
},
|
|
135
155
|
"./query": {
|
|
136
156
|
"import": {
|
|
137
157
|
"types": "./dist/query.d.ts",
|
|
@@ -142,6 +162,16 @@
|
|
|
142
162
|
"default": "./_cjs/query.cjs"
|
|
143
163
|
}
|
|
144
164
|
},
|
|
165
|
+
"./query2": {
|
|
166
|
+
"import": {
|
|
167
|
+
"types": "./dist/query2.d.ts",
|
|
168
|
+
"default": "./dist/query2.js"
|
|
169
|
+
},
|
|
170
|
+
"require": {
|
|
171
|
+
"types": "./dist/query2.d.ts",
|
|
172
|
+
"default": "./_cjs/query2.cjs"
|
|
173
|
+
}
|
|
174
|
+
},
|
|
145
175
|
"./routeParams": {
|
|
146
176
|
"import": {
|
|
147
177
|
"types": "./dist/routeParams.d.ts",
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { flow, pipe, tuple } from "@effect-app/core/Function"
|
|
3
|
+
import type { MutationResult } from "@effect-app/vue"
|
|
4
|
+
import { Result } from "@effect-app/vue"
|
|
5
|
+
import * as Sentry from "@sentry/browser"
|
|
6
|
+
import { type MaybeRefOrGetter, type Pausable, useIntervalFn, type UseIntervalFnOptions } from "@vueuse/core"
|
|
7
|
+
import { Array, Cause, Effect, Exit, Match, Option, S } from "effect-app"
|
|
8
|
+
import { type SupportedErrors } from "effect-app/client"
|
|
9
|
+
import { Failure, Success } from "effect-app/Operations"
|
|
10
|
+
import { dropUndefinedT } from "effect-app/utils"
|
|
11
|
+
import { computed, type ComputedRef } from "vue"
|
|
12
|
+
import type { MakeIntlReturn } from "./makeIntl.js"
|
|
13
|
+
import type { MakeMutation2, MutationOptions } from "./mutate2.js"
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Use this after handling an error yourself, still continueing on the Error track, but the error will not be reported.
|
|
17
|
+
*/
|
|
18
|
+
export class SuppressErrors extends Cause.YieldableError {
|
|
19
|
+
readonly _tag = "SuppressErrors"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type ResponseErrors = S.ParseResult.ParseError | SupportedErrors | SuppressErrors
|
|
23
|
+
|
|
24
|
+
export function pauseWhileProcessing(
|
|
25
|
+
iv: Pausable,
|
|
26
|
+
pmf: () => Promise<unknown>
|
|
27
|
+
) {
|
|
28
|
+
return Promise
|
|
29
|
+
.resolve(iv.pause())
|
|
30
|
+
.then(() => pmf())
|
|
31
|
+
.finally(() => iv.resume())
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function useIntervalPauseWhileProcessing(
|
|
35
|
+
pmf: () => Promise<unknown>,
|
|
36
|
+
interval?: MaybeRefOrGetter<number>,
|
|
37
|
+
options?: Omit<UseIntervalFnOptions, "immediateCallback">
|
|
38
|
+
) {
|
|
39
|
+
const iv = useIntervalFn(
|
|
40
|
+
() => pauseWhileProcessing(iv, pmf),
|
|
41
|
+
interval,
|
|
42
|
+
options ? { ...options, immediateCallback: false } : options
|
|
43
|
+
)
|
|
44
|
+
return {
|
|
45
|
+
isActive: iv.isActive
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface Opts<A> extends MutationOptions {
|
|
50
|
+
suppressErrorToast?: boolean
|
|
51
|
+
suppressSuccessToast?: boolean
|
|
52
|
+
successToast?: (a: A) => any
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface Res<A, E> {
|
|
56
|
+
readonly loading: boolean
|
|
57
|
+
readonly data: A | undefined
|
|
58
|
+
readonly error: E | undefined
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type WithAction<A> = A & {
|
|
62
|
+
action: string
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// computed() takes a getter function and returns a readonly reactive ref
|
|
66
|
+
// object for the returned value from the getter.
|
|
67
|
+
type Resp<I, E, A, R> = readonly [
|
|
68
|
+
ComputedRef<Res<A, E>>,
|
|
69
|
+
WithAction<(I: I) => Effect<A, E, R>>
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
type ActResp<E, A, R> = readonly [
|
|
73
|
+
ComputedRef<Res<A, E>>,
|
|
74
|
+
WithAction<() => Effect<A, E, R>>
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
export function mutationResultToVue<A, E>(
|
|
78
|
+
mutationResult: MutationResult<A, E>
|
|
79
|
+
): Res<A, E> {
|
|
80
|
+
switch (mutationResult._tag) {
|
|
81
|
+
case "Loading": {
|
|
82
|
+
return { loading: true, data: undefined, error: undefined }
|
|
83
|
+
}
|
|
84
|
+
case "Success": {
|
|
85
|
+
return {
|
|
86
|
+
loading: false,
|
|
87
|
+
data: mutationResult.data,
|
|
88
|
+
error: undefined
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
case "Error": {
|
|
92
|
+
return {
|
|
93
|
+
loading: false,
|
|
94
|
+
data: undefined,
|
|
95
|
+
error: mutationResult.error
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
case "Initial": {
|
|
99
|
+
return { loading: false, data: undefined, error: undefined }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export const makeClient2 = <Locale extends string, R>(
|
|
105
|
+
useIntl: MakeIntlReturn<Locale>["useIntl"],
|
|
106
|
+
useToast: () => {
|
|
107
|
+
error: (message: string) => void
|
|
108
|
+
warning: (message: string) => void
|
|
109
|
+
success: (message: string) => void
|
|
110
|
+
},
|
|
111
|
+
useSafeMutation: MakeMutation2,
|
|
112
|
+
messages: Record<string, string | undefined> = {}
|
|
113
|
+
) => {
|
|
114
|
+
const useHandleRequestWithToast = () => {
|
|
115
|
+
const toast = useToast()
|
|
116
|
+
const { intl } = useIntl()
|
|
117
|
+
|
|
118
|
+
return handleRequestWithToast
|
|
119
|
+
/**
|
|
120
|
+
* Pass a function that returns a Promise.
|
|
121
|
+
* Returns an execution function which reports errors as Toast.
|
|
122
|
+
*/
|
|
123
|
+
function handleRequestWithToast<
|
|
124
|
+
E extends ResponseErrors,
|
|
125
|
+
A,
|
|
126
|
+
R,
|
|
127
|
+
Args extends unknown[]
|
|
128
|
+
>(
|
|
129
|
+
f: (...args: Args) => Effect<A, E, R>,
|
|
130
|
+
action: string,
|
|
131
|
+
options: Opts<A> = { suppressErrorToast: false }
|
|
132
|
+
) {
|
|
133
|
+
const message = messages[action] ?? action
|
|
134
|
+
const warnMessage = intl.value.formatMessage(
|
|
135
|
+
{ id: "handle.with_warnings" },
|
|
136
|
+
{ action: message }
|
|
137
|
+
)
|
|
138
|
+
const successMessage = intl.value.formatMessage(
|
|
139
|
+
{ id: "handle.success" },
|
|
140
|
+
{ action: message }
|
|
141
|
+
)
|
|
142
|
+
const errorMessage = intl.value.formatMessage(
|
|
143
|
+
{ id: "handle.with_errors" },
|
|
144
|
+
{ action: message }
|
|
145
|
+
)
|
|
146
|
+
return Object.assign(
|
|
147
|
+
flow(
|
|
148
|
+
f,
|
|
149
|
+
Effect.onExit(
|
|
150
|
+
Exit.matchEffect({
|
|
151
|
+
onSuccess: (r) =>
|
|
152
|
+
Effect.gen(function*() {
|
|
153
|
+
if (S.is(Failure)(r)) {
|
|
154
|
+
toast.warning(
|
|
155
|
+
warnMessage + r.message
|
|
156
|
+
? "\n" + r.message
|
|
157
|
+
: ""
|
|
158
|
+
)
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
toast.success(
|
|
163
|
+
successMessage
|
|
164
|
+
+ (S.is(Success)(r) && r.message
|
|
165
|
+
? "\n" + r.message
|
|
166
|
+
: "")
|
|
167
|
+
)
|
|
168
|
+
}),
|
|
169
|
+
onFailure: (err) =>
|
|
170
|
+
Effect.gen(function*() {
|
|
171
|
+
if (Cause.isInterruptedOnly(err)) {
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const fail = Cause.failureOption(err)
|
|
176
|
+
if (Option.isSome(fail)) {
|
|
177
|
+
if ((fail as any)._tag === "SuppressErrors") {
|
|
178
|
+
return Effect.succeed(void 0)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (!options.suppressErrorToast) {
|
|
182
|
+
toast.error(`${errorMessage}:\n` + renderError(fail.value))
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
console.warn(fail, fail.toString())
|
|
186
|
+
return
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const extra = {
|
|
190
|
+
action,
|
|
191
|
+
message: `Unexpected Error trying to ${action}`
|
|
192
|
+
}
|
|
193
|
+
Sentry.captureException(err, {
|
|
194
|
+
extra
|
|
195
|
+
})
|
|
196
|
+
console.error(err, extra)
|
|
197
|
+
|
|
198
|
+
toast.error(
|
|
199
|
+
intl.value.formatMessage(
|
|
200
|
+
{ id: "handle.unexpected_error" },
|
|
201
|
+
{
|
|
202
|
+
action: message,
|
|
203
|
+
error: JSON.stringify(err, undefined, 2)
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
)
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
)
|
|
210
|
+
),
|
|
211
|
+
{ action }
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function renderError(e: ResponseErrors): string {
|
|
216
|
+
return Match.value(e).pipe(
|
|
217
|
+
Match.tags({
|
|
218
|
+
// HttpErrorRequest: e =>
|
|
219
|
+
// intl.value.formatMessage(
|
|
220
|
+
// { id: "handle.request_error" },
|
|
221
|
+
// { error: `${e.error}` },
|
|
222
|
+
// ),
|
|
223
|
+
// HttpErrorResponse: e =>
|
|
224
|
+
// e.response.status >= 500 ||
|
|
225
|
+
// e.response.body._tag !== "Some" ||
|
|
226
|
+
// !e.response.body.value
|
|
227
|
+
// ? intl.value.formatMessage(
|
|
228
|
+
// { id: "handle.error_response" },
|
|
229
|
+
// {
|
|
230
|
+
// error: `${
|
|
231
|
+
// e.response.body._tag === "Some" && e.response.body.value
|
|
232
|
+
// ? parseError(e.response.body.value)
|
|
233
|
+
// : "Unknown"
|
|
234
|
+
// } (${e.response.status})`,
|
|
235
|
+
// },
|
|
236
|
+
// )
|
|
237
|
+
// : intl.value.formatMessage(
|
|
238
|
+
// { id: "handle.unexpected_error" },
|
|
239
|
+
// {
|
|
240
|
+
// error:
|
|
241
|
+
// JSON.stringify(e.response.body, undefined, 2) +
|
|
242
|
+
// "( " +
|
|
243
|
+
// e.response.status +
|
|
244
|
+
// ")",
|
|
245
|
+
// },
|
|
246
|
+
// ),
|
|
247
|
+
// ResponseError: e =>
|
|
248
|
+
// intl.value.formatMessage(
|
|
249
|
+
// { id: "handle.response_error" },
|
|
250
|
+
// { error: `${e.error}` },
|
|
251
|
+
// ),
|
|
252
|
+
ParseError: (e) => {
|
|
253
|
+
console.warn(e.toString())
|
|
254
|
+
return intl.value.formatMessage({ id: "validation.failed" })
|
|
255
|
+
}
|
|
256
|
+
}),
|
|
257
|
+
Match.orElse((e) =>
|
|
258
|
+
intl.value.formatMessage(
|
|
259
|
+
{ id: "handle.unexpected_error" },
|
|
260
|
+
{
|
|
261
|
+
error: `${e.message ?? e._tag ?? e}`
|
|
262
|
+
}
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Pass a function that returns an Effect, e.g from a client action, give it a name, and optionally pass an onSuccess callback.
|
|
271
|
+
* Returns a tuple with state ref and execution function which reports errors as Toast.
|
|
272
|
+
*/
|
|
273
|
+
const useAndHandleMutation: {
|
|
274
|
+
<I, E extends ResponseErrors, A, R>(
|
|
275
|
+
self: {
|
|
276
|
+
handler: (i: I) => Effect<A, E, R>
|
|
277
|
+
name: string
|
|
278
|
+
},
|
|
279
|
+
action: string,
|
|
280
|
+
options?: Opts<A>
|
|
281
|
+
): Resp<I, A, E, R>
|
|
282
|
+
<E extends ResponseErrors, A, R>(
|
|
283
|
+
self: {
|
|
284
|
+
handler: Effect<A, E, R>
|
|
285
|
+
name: string
|
|
286
|
+
},
|
|
287
|
+
action: string,
|
|
288
|
+
options?: Opts<A>
|
|
289
|
+
): ActResp<E, A, R>
|
|
290
|
+
} = (self: any, action: any, options?: Opts<any>) => {
|
|
291
|
+
const handleRequestWithToast = useHandleRequestWithToast()
|
|
292
|
+
const [a, b] = useSafeMutation(
|
|
293
|
+
{
|
|
294
|
+
handler: Effect.isEffect(self.handler)
|
|
295
|
+
? (pipe(
|
|
296
|
+
Effect.annotateCurrentSpan({ action }),
|
|
297
|
+
Effect.andThen(self.handler)
|
|
298
|
+
) as any)
|
|
299
|
+
: (...args: any[]) =>
|
|
300
|
+
pipe(
|
|
301
|
+
Effect.annotateCurrentSpan({ action }),
|
|
302
|
+
Effect.andThen(self.handler(...args))
|
|
303
|
+
),
|
|
304
|
+
name: self.name
|
|
305
|
+
},
|
|
306
|
+
dropUndefinedT({
|
|
307
|
+
queryInvalidation: options?.queryInvalidation
|
|
308
|
+
})
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
return tuple(
|
|
312
|
+
computed(() => mutationResultToVue(a.value)),
|
|
313
|
+
handleRequestWithToast(b as any, action, options)
|
|
314
|
+
)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function makeUseAndHandleMutation(
|
|
318
|
+
defaultOptions?: Opts<any>
|
|
319
|
+
) {
|
|
320
|
+
return ((self: any, action: any, options: any) => {
|
|
321
|
+
return useAndHandleMutation(
|
|
322
|
+
{
|
|
323
|
+
handler: self.handler,
|
|
324
|
+
name: self.name
|
|
325
|
+
},
|
|
326
|
+
action,
|
|
327
|
+
{ ...defaultOptions, ...options }
|
|
328
|
+
)
|
|
329
|
+
}) as {
|
|
330
|
+
<I, E extends ResponseErrors, A, R>(
|
|
331
|
+
self: {
|
|
332
|
+
handler: (i: I) => Effect<A, E, R>
|
|
333
|
+
name: string
|
|
334
|
+
},
|
|
335
|
+
action: string,
|
|
336
|
+
options?: Opts<A>
|
|
337
|
+
): Resp<I, A, E, R>
|
|
338
|
+
<E extends ResponseErrors, A>(
|
|
339
|
+
self: {
|
|
340
|
+
handler: Effect<A, E, R>
|
|
341
|
+
name: string
|
|
342
|
+
},
|
|
343
|
+
action: string,
|
|
344
|
+
options?: Opts<A>
|
|
345
|
+
): ActResp<E, A, R>
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const useSafeMutationWithState = <I, E, A>(self: {
|
|
350
|
+
handler: (i: I) => Effect<A, E, R>
|
|
351
|
+
name: string
|
|
352
|
+
}) => {
|
|
353
|
+
const [a, b] = useSafeMutation(self)
|
|
354
|
+
|
|
355
|
+
return tuple(
|
|
356
|
+
computed(() => mutationResultToVue(a.value)),
|
|
357
|
+
b
|
|
358
|
+
)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return {
|
|
362
|
+
useSafeMutationWithState,
|
|
363
|
+
useAndHandleMutation,
|
|
364
|
+
makeUseAndHandleMutation,
|
|
365
|
+
useHandleRequestWithToast
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export const mapHandler: {
|
|
370
|
+
<I, E, R, A, E2, A2, R2>(
|
|
371
|
+
self: {
|
|
372
|
+
handler: (i: I) => Effect<A, E, R>
|
|
373
|
+
name: string
|
|
374
|
+
mapPath: (i: I) => string
|
|
375
|
+
},
|
|
376
|
+
map: (i: I) => (handler: Effect<A, E, R>) => Effect<A2, E2, R2>
|
|
377
|
+
): {
|
|
378
|
+
handler: (i: I) => Effect<A2, E2, R2>
|
|
379
|
+
name: string
|
|
380
|
+
mapPath: (i: I) => string
|
|
381
|
+
}
|
|
382
|
+
<E, A, R, E2, A2, R2>(
|
|
383
|
+
self: {
|
|
384
|
+
handler: Effect<A, E, R>
|
|
385
|
+
name: string
|
|
386
|
+
mapPath: string
|
|
387
|
+
},
|
|
388
|
+
map: (handler: Effect<A, E, R>) => Effect<A2, E2, R2>
|
|
389
|
+
): {
|
|
390
|
+
handler: Effect<A2, E2, R2>
|
|
391
|
+
name: string
|
|
392
|
+
mapPath: string
|
|
393
|
+
}
|
|
394
|
+
} = (self: any, map: any): any => ({
|
|
395
|
+
...self,
|
|
396
|
+
handler: typeof self.handler === "function"
|
|
397
|
+
? (i: any) => map(i)((self.handler as (i: any) => Effect<any, any, any>)(i))
|
|
398
|
+
: map(self.handler)
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
export function composeQueries<
|
|
402
|
+
R extends Record<string, Result.Result<any, any>>
|
|
403
|
+
>(
|
|
404
|
+
results: R,
|
|
405
|
+
renderPreviousOnFailure?: boolean
|
|
406
|
+
): Result.Result<
|
|
407
|
+
{
|
|
408
|
+
[Property in keyof R]: R[Property] extends Result.Result<infer A, any> ? A
|
|
409
|
+
: never
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
[Property in keyof R]: R[Property] extends Result.Result<any, infer E> ? E
|
|
413
|
+
: never
|
|
414
|
+
}[keyof R]
|
|
415
|
+
> {
|
|
416
|
+
const values = renderPreviousOnFailure
|
|
417
|
+
? Object.values(results).map(orPrevious)
|
|
418
|
+
: Object.values(results)
|
|
419
|
+
const error = values.find(Result.isFailure)
|
|
420
|
+
if (error) {
|
|
421
|
+
return error
|
|
422
|
+
}
|
|
423
|
+
const initial = Array.findFirst(values, (x) => x._tag === "Initial" ? Option.some(x) : Option.none())
|
|
424
|
+
if (initial.value !== undefined) {
|
|
425
|
+
return initial.value
|
|
426
|
+
}
|
|
427
|
+
const loading = Array.findFirst(values, (x) => Result.isInitial(x) && x.waiting ? Option.some(x) : Option.none())
|
|
428
|
+
if (loading.value !== undefined) {
|
|
429
|
+
return loading.value
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const isRefreshing = values.some((x) => x.waiting)
|
|
433
|
+
|
|
434
|
+
const r = Object.entries(results).reduce((prev, [key, value]) => {
|
|
435
|
+
prev[key] = Result.value(value).value
|
|
436
|
+
return prev
|
|
437
|
+
}, {} as any)
|
|
438
|
+
return Result.success(r, isRefreshing)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function orPrevious<E, A>(result: Result.Result<A, E>) {
|
|
442
|
+
return Result.isFailure(result) && Option.isSome(result.previousValue)
|
|
443
|
+
? Result.success(result.previousValue.value, result.waiting)
|
|
444
|
+
: result
|
|
445
|
+
}
|