@diphyx/harlemify 6.3.1 → 6.4.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/README.md +0 -2
- package/dist/module.json +1 -1
- package/dist/runtime/composables/action.d.ts +14 -1
- package/dist/runtime/composables/action.js +17 -1
- package/dist/runtime/composables/view.d.ts +3 -0
- package/dist/runtime/composables/view.js +4 -4
- package/dist/runtime/core/types/action.d.ts +21 -0
- package/dist/runtime/core/utils/action.js +60 -3
- package/dist/runtime/index.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,8 +99,6 @@ await execute();
|
|
|
99
99
|
| Vue | `^3.5.0` |
|
|
100
100
|
| Zod | `^4.0.0` |
|
|
101
101
|
|
|
102
|
-
> **Note:** Early Nuxt 4 versions (e.g., 4.1.x) may have issues resolving the `#build` alias for module templates. If you encounter build errors related to `#build/harlemify.config`, upgrade to the latest Nuxt 4 release.
|
|
103
|
-
|
|
104
102
|
## Documentation
|
|
105
103
|
|
|
106
104
|
[https://diphyx.github.io/harlemify/](https://diphyx.github.io/harlemify/)
|
package/dist/module.json
CHANGED
|
@@ -3,6 +3,13 @@ import { ActionStatus, type ActionCall, type ActionApiCall, type ActionHandlerCa
|
|
|
3
3
|
export interface UseStoreActionOptions {
|
|
4
4
|
isolated?: boolean;
|
|
5
5
|
}
|
|
6
|
+
type ResolveCallOptions<C> = C extends ActionHandlerCall<infer P, any> ? ActionHandlerCallOptions<P> : C extends ActionApiCall<any> ? ActionApiCallOptions : ActionCallOptions;
|
|
7
|
+
export type IsolatedActionCall<C> = C extends ActionHandlerCall<infer P, any> ? {
|
|
8
|
+
payload: Readonly<Ref<P | undefined>>;
|
|
9
|
+
} : C extends ActionApiCall<any> ? {
|
|
10
|
+
params: Readonly<Ref<Record<string, string | number> | undefined>>;
|
|
11
|
+
query: Readonly<Ref<Record<string, unknown> | undefined>>;
|
|
12
|
+
} : object;
|
|
6
13
|
export type UseStoreAction<T, O = ActionCallOptions> = {
|
|
7
14
|
execute: (options?: Omit<O, "bind">) => Promise<T>;
|
|
8
15
|
error: Readonly<Ref<Error | null>>;
|
|
@@ -14,4 +21,10 @@ export declare function useIsolatedActionError(): Ref<Error | null>;
|
|
|
14
21
|
export declare function useIsolatedActionStatus(): Ref<ActionStatus>;
|
|
15
22
|
export declare function useStoreAction<A extends Record<string, ActionCall<any>>, K extends keyof A & string, T = Awaited<ReturnType<A[K]>>>(store: {
|
|
16
23
|
action: A;
|
|
17
|
-
}, key: K, options
|
|
24
|
+
}, key: K, options: UseStoreActionOptions & {
|
|
25
|
+
isolated: true;
|
|
26
|
+
}): UseStoreAction<T, ResolveCallOptions<A[K]>> & IsolatedActionCall<A[K]>;
|
|
27
|
+
export declare function useStoreAction<A extends Record<string, ActionCall<any>>, K extends keyof A & string, T = Awaited<ReturnType<A[K]>>>(store: {
|
|
28
|
+
action: A;
|
|
29
|
+
}, key: K, options?: UseStoreActionOptions): UseStoreAction<T, ResolveCallOptions<A[K]>>;
|
|
30
|
+
export {};
|
|
@@ -2,6 +2,7 @@ import { ref, computed } from "vue";
|
|
|
2
2
|
import {
|
|
3
3
|
ActionStatus
|
|
4
4
|
} from "../core/types/action.js";
|
|
5
|
+
import { snapshot } from "../core/utils/base.js";
|
|
5
6
|
export function useIsolatedActionError() {
|
|
6
7
|
return ref(null);
|
|
7
8
|
}
|
|
@@ -13,6 +14,9 @@ export function useStoreAction(store, key, options) {
|
|
|
13
14
|
if (!action) {
|
|
14
15
|
throw new Error(`Action "${key}" not found in store`);
|
|
15
16
|
}
|
|
17
|
+
const params = ref();
|
|
18
|
+
const query = ref();
|
|
19
|
+
const payload = ref();
|
|
16
20
|
let error;
|
|
17
21
|
let status;
|
|
18
22
|
let loading;
|
|
@@ -28,6 +32,9 @@ export function useStoreAction(store, key, options) {
|
|
|
28
32
|
reset = () => {
|
|
29
33
|
isolatedStatus.value = ActionStatus.IDLE;
|
|
30
34
|
isolatedError.value = null;
|
|
35
|
+
params.value = void 0;
|
|
36
|
+
query.value = void 0;
|
|
37
|
+
payload.value = void 0;
|
|
31
38
|
};
|
|
32
39
|
} else {
|
|
33
40
|
error = action.error;
|
|
@@ -41,6 +48,12 @@ export function useStoreAction(store, key, options) {
|
|
|
41
48
|
status,
|
|
42
49
|
error
|
|
43
50
|
};
|
|
51
|
+
if (!loading.value) {
|
|
52
|
+
const isolatedCall = callOptions;
|
|
53
|
+
params.value = snapshot(isolatedCall.params);
|
|
54
|
+
query.value = snapshot(isolatedCall.query);
|
|
55
|
+
payload.value = snapshot(isolatedCall.payload);
|
|
56
|
+
}
|
|
44
57
|
}
|
|
45
58
|
return action(callOptions);
|
|
46
59
|
}
|
|
@@ -49,6 +62,9 @@ export function useStoreAction(store, key, options) {
|
|
|
49
62
|
error,
|
|
50
63
|
status,
|
|
51
64
|
loading,
|
|
52
|
-
reset
|
|
65
|
+
reset,
|
|
66
|
+
params,
|
|
67
|
+
query,
|
|
68
|
+
payload
|
|
53
69
|
};
|
|
54
70
|
}
|
|
@@ -13,3 +13,6 @@ export type UseStoreView<T> = {
|
|
|
13
13
|
export declare function useStoreView<V extends Record<string, ViewCall>, K extends keyof V & string, T = V[K] extends ComputedRef<infer R> ? R : unknown>(store: {
|
|
14
14
|
view: V;
|
|
15
15
|
}, key: K): UseStoreView<T>;
|
|
16
|
+
export declare function useStoreView<V extends Record<string, ViewCall>, K extends keyof V & string, R, T = V[K] extends ComputedRef<infer U> ? U : unknown>(store: {
|
|
17
|
+
view: V;
|
|
18
|
+
}, key: K, resolver: (value: T) => R): UseStoreView<R>;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { watch } from "vue";
|
|
1
|
+
import { computed, watch } from "vue";
|
|
2
2
|
import { debounce, throttle } from "../core/utils/base.js";
|
|
3
|
-
export function useStoreView(store, key) {
|
|
3
|
+
export function useStoreView(store, key, resolver) {
|
|
4
4
|
if (!store.view[key]) {
|
|
5
5
|
throw new Error(`View "${key}" not found in store`);
|
|
6
6
|
}
|
|
7
7
|
const source = store.view[key];
|
|
8
|
-
const data = source;
|
|
8
|
+
const data = resolver ? computed(() => resolver(source.value)) : source;
|
|
9
9
|
function resolveCallback(callback, callbackOptions) {
|
|
10
10
|
if (callbackOptions?.debounce) {
|
|
11
11
|
return debounce(callback, callbackOptions.debounce);
|
|
@@ -18,7 +18,7 @@ export function useStoreView(store, key) {
|
|
|
18
18
|
function track(handler, trackOptions) {
|
|
19
19
|
const callback = resolveCallback(handler, trackOptions);
|
|
20
20
|
const stop = watch(
|
|
21
|
-
|
|
21
|
+
data,
|
|
22
22
|
(value) => {
|
|
23
23
|
callback(value);
|
|
24
24
|
},
|
|
@@ -44,6 +44,7 @@ export interface ActionApiRequest<MD extends ModelDefinitions, VD extends ViewDe
|
|
|
44
44
|
body?: ActionApiRequestValue<MD, VD, unknown>;
|
|
45
45
|
timeout?: ActionApiRequestValue<MD, VD, number>;
|
|
46
46
|
concurrent?: ActionConcurrent;
|
|
47
|
+
hooks?: ActionHooks;
|
|
47
48
|
}
|
|
48
49
|
export type ActionApiRequestShortcut<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>> = Omit<ActionApiRequest<MD, VD>, "method">;
|
|
49
50
|
export interface ActionApiCommitContext<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>> {
|
|
@@ -129,12 +130,32 @@ export interface ActionResolvedApi {
|
|
|
129
130
|
timeout?: number;
|
|
130
131
|
signal: AbortSignal;
|
|
131
132
|
}
|
|
133
|
+
export interface ActionHookRequest extends ActionResolvedApi {
|
|
134
|
+
error?: Error;
|
|
135
|
+
}
|
|
136
|
+
export interface ActionHookResponse {
|
|
137
|
+
status: number;
|
|
138
|
+
headers: Record<string, string>;
|
|
139
|
+
data: unknown;
|
|
140
|
+
}
|
|
141
|
+
export interface ActionHookPreContext {
|
|
142
|
+
request: Readonly<ActionResolvedApi>;
|
|
143
|
+
}
|
|
144
|
+
export interface ActionHookPostContext {
|
|
145
|
+
request: Readonly<ActionHookRequest>;
|
|
146
|
+
response?: Readonly<ActionHookResponse>;
|
|
147
|
+
}
|
|
148
|
+
export interface ActionHooks {
|
|
149
|
+
pre?: (context: ActionHookPreContext) => void | Promise<void>;
|
|
150
|
+
post?: (context: ActionHookPostContext) => void | Promise<void>;
|
|
151
|
+
}
|
|
132
152
|
export interface ActionCallTransformerOptions {
|
|
133
153
|
request?: (api: ActionResolvedApi) => ActionResolvedApi;
|
|
134
154
|
response?: (data: unknown) => unknown;
|
|
135
155
|
}
|
|
136
156
|
export interface ActionCallCommitOptions {
|
|
137
157
|
mode?: ModelOneMode | ModelManyMode | Record<string, ModelOneMode | ModelManyMode>;
|
|
158
|
+
options?: ModelOneCommitOptions | ModelManyCommitOptions | Record<string, ModelOneCommitOptions | ModelManyCommitOptions>;
|
|
138
159
|
}
|
|
139
160
|
export interface ActionApiCallOptions extends ActionCallBaseOptions {
|
|
140
161
|
params?: Record<string, string | number>;
|
|
@@ -96,6 +96,19 @@ function resolveCommitMode(commit, options) {
|
|
|
96
96
|
}
|
|
97
97
|
return commit.mode;
|
|
98
98
|
}
|
|
99
|
+
function resolveCommitOptions(commit, options) {
|
|
100
|
+
const override = options?.commit?.options;
|
|
101
|
+
if (!override) {
|
|
102
|
+
return commit.options;
|
|
103
|
+
}
|
|
104
|
+
const values = Object.values(override);
|
|
105
|
+
const perModel = values.length > 0 && values.every((value) => isPlainObject(value));
|
|
106
|
+
const resolved = perModel ? override[commit.model] : override;
|
|
107
|
+
if (!resolved) {
|
|
108
|
+
return commit.options;
|
|
109
|
+
}
|
|
110
|
+
return merge(resolved, commit.options);
|
|
111
|
+
}
|
|
99
112
|
function resolveCommitTransform(commit, data, context) {
|
|
100
113
|
if (typeof commit.transform === "function") {
|
|
101
114
|
return commit.transform(data, context);
|
|
@@ -120,6 +133,25 @@ function resolveConcurrent(definition, options) {
|
|
|
120
133
|
}
|
|
121
134
|
return ActionConcurrent.BLOCK;
|
|
122
135
|
}
|
|
136
|
+
async function executeHook(definition, hooks, key, context) {
|
|
137
|
+
const hook = hooks?.[key];
|
|
138
|
+
if (!hook) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
definition.logger?.debug("Action API hook", {
|
|
142
|
+
action: definition.key,
|
|
143
|
+
hook: key
|
|
144
|
+
});
|
|
145
|
+
try {
|
|
146
|
+
await hook(context);
|
|
147
|
+
} catch (error) {
|
|
148
|
+
definition.logger?.error("Action API hook error", {
|
|
149
|
+
action: definition.key,
|
|
150
|
+
hook: key,
|
|
151
|
+
error
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
123
155
|
async function executeApi(definition, api, options) {
|
|
124
156
|
try {
|
|
125
157
|
definition.logger?.debug("Action API request", {
|
|
@@ -137,7 +169,31 @@ async function executeApi(definition, api, options) {
|
|
|
137
169
|
body: api.body,
|
|
138
170
|
timeout: api.timeout,
|
|
139
171
|
signal: api.signal,
|
|
140
|
-
responseType: "json"
|
|
172
|
+
responseType: "json",
|
|
173
|
+
async onRequest() {
|
|
174
|
+
await executeHook(definition, definition.request.hooks, "pre", {
|
|
175
|
+
request: api
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
async onResponse({ response: response2 }) {
|
|
179
|
+
await executeHook(definition, definition.request.hooks, "post", {
|
|
180
|
+
request: api,
|
|
181
|
+
response: {
|
|
182
|
+
status: response2.status,
|
|
183
|
+
headers: Object.fromEntries(response2.headers),
|
|
184
|
+
data: response2._data
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
async onRequestError({ error }) {
|
|
189
|
+
await executeHook(definition, definition.request.hooks, "post", {
|
|
190
|
+
request: {
|
|
191
|
+
...api,
|
|
192
|
+
error
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
141
197
|
});
|
|
142
198
|
definition.logger?.debug("Action API response received", {
|
|
143
199
|
action: definition.key,
|
|
@@ -191,11 +247,12 @@ function executeCommit(definition, model, data, context, options) {
|
|
|
191
247
|
});
|
|
192
248
|
}
|
|
193
249
|
const mode = resolveCommitMode(commit, options);
|
|
250
|
+
const commitOptions = resolveCommitOptions(commit, options);
|
|
194
251
|
let value = resolveCommitTransform(commit, data, context);
|
|
195
252
|
if (!isEmptyRecord(target.aliases())) {
|
|
196
253
|
value = resolveAliasInbound(value, target.aliases());
|
|
197
254
|
}
|
|
198
|
-
plan.push({ commit, target, mode, value });
|
|
255
|
+
plan.push({ commit, target, mode, options: commitOptions, value });
|
|
199
256
|
}
|
|
200
257
|
} catch (error) {
|
|
201
258
|
const commitError = toError(error, ActionCommitError);
|
|
@@ -213,7 +270,7 @@ function executeCommit(definition, model, data, context, options) {
|
|
|
213
270
|
mode: entry.mode
|
|
214
271
|
});
|
|
215
272
|
try {
|
|
216
|
-
entry.target.commit(entry.mode, entry.value, entry.
|
|
273
|
+
entry.target.commit(entry.mode, entry.value, entry.options);
|
|
217
274
|
} catch (error) {
|
|
218
275
|
const commitError = toError(error, ActionCommitError);
|
|
219
276
|
definition.logger?.error("Action commit error", {
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -7,13 +7,13 @@ export type { ModelOneCommitOptions, ModelManyCommitOptions } from "./core/types
|
|
|
7
7
|
export { ViewClone } from "./core/types/view.js";
|
|
8
8
|
export type { ViewDefinitionOptions } from "./core/types/view.js";
|
|
9
9
|
export { ActionStatus, ActionConcurrent, ActionType, ActionApiMethod } from "./core/types/action.js";
|
|
10
|
-
export type { ActionCall, ActionApiCall, ActionApiCommitContext, ActionHandlerCall, ActionCallOptions, ActionCallBaseOptions, ActionApiCallOptions, ActionHandlerCallOptions, ActionCallTransformerOptions, ActionCallBindOptions, ActionCallCommitOptions, ActionHandlerOptions, ActionResolvedApi, } from "./core/types/action.js";
|
|
10
|
+
export type { ActionCall, ActionApiCall, ActionApiCommitContext, ActionHandlerCall, ActionCallOptions, ActionCallBaseOptions, ActionApiCallOptions, ActionHandlerCallOptions, ActionCallTransformerOptions, ActionCallBindOptions, ActionCallCommitOptions, ActionHandlerOptions, ActionResolvedApi, ActionHooks, ActionHookPreContext, ActionHookPostContext, ActionHookRequest, ActionHookResponse, } from "./core/types/action.js";
|
|
11
11
|
export { ActionApiError, ActionHandlerError, ActionCommitError, ActionConcurrentError, isError, toError, } from "./core/utils/error.js";
|
|
12
12
|
export type { ComposeCallback, ComposeCall, ComposeDefinitions, ComposeContext, StoreCompose, } from "./core/types/compose.js";
|
|
13
13
|
export { useStoreCompose } from "./composables/compose.js";
|
|
14
14
|
export type { UseStoreCompose } from "./composables/compose.js";
|
|
15
15
|
export { useIsolatedActionStatus, useIsolatedActionError, useStoreAction } from "./composables/action.js";
|
|
16
|
-
export type { UseStoreActionOptions, UseStoreAction } from "./composables/action.js";
|
|
16
|
+
export type { UseStoreActionOptions, UseStoreAction, IsolatedActionCall } from "./composables/action.js";
|
|
17
17
|
export { useStoreModel } from "./composables/model.js";
|
|
18
18
|
export type { UseStoreModelOptions, UseStoreModel } from "./composables/model.js";
|
|
19
19
|
export { useStoreView } from "./composables/view.js";
|