@diphyx/harlemify 5.0.0 → 5.2.0
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 +31 -41
- package/dist/module.d.mts +3 -3
- package/dist/module.d.ts +3 -3
- package/dist/module.json +1 -1
- package/dist/runtime/composables/action.d.ts +16 -3
- package/dist/runtime/composables/action.js +50 -4
- package/dist/runtime/composables/model.d.ts +22 -0
- package/dist/runtime/composables/model.js +32 -0
- package/dist/runtime/composables/view.d.ts +33 -0
- package/dist/runtime/composables/view.js +54 -0
- package/dist/runtime/core/layers/action.js +52 -32
- package/dist/runtime/core/layers/model.js +5 -18
- package/dist/runtime/core/layers/view.js +5 -19
- package/dist/runtime/core/types/action.d.ts +36 -14
- package/dist/runtime/core/types/store.d.ts +3 -3
- package/dist/runtime/core/types/view.d.ts +3 -3
- package/dist/runtime/core/utils/action.js +35 -23
- package/dist/runtime/core/utils/base.d.ts +12 -0
- package/dist/runtime/core/utils/base.js +105 -1
- package/dist/runtime/index.d.ts +7 -2
- package/dist/runtime/index.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
> Factory-driven state management for Nuxt powered by [Harlem](https://harlemjs.com/)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Define your data **shape** once with Zod — get typed **models**, computed **views**, and async **actions** with a single `createStore` call.
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **SSR
|
|
7
|
+
- **Schema-first** — Define your data shape once, get TypeScript types and validation automatically
|
|
8
|
+
- **Reactive state** — Single items and collections with built-in mutations
|
|
9
|
+
- **Computed views** — Derived read-only state that updates when models change
|
|
10
|
+
- **API integration** — Declarative HTTP actions that fetch and commit data in one step
|
|
11
|
+
- **Status tracking** — Every action exposes loading, error, and status reactively
|
|
12
|
+
- **Concurrency control** — Block, skip, cancel, or allow parallel calls per action
|
|
13
|
+
- **Vue composables** — Reactive helpers for actions, models, and views in components
|
|
14
|
+
- **SSR ready** — Server-side rendering with automatic state hydration
|
|
15
15
|
|
|
16
16
|
## Install
|
|
17
17
|
|
|
@@ -19,37 +19,23 @@
|
|
|
19
19
|
npm install @diphyx/harlemify
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
## Setup
|
|
23
|
-
|
|
24
22
|
```typescript
|
|
25
23
|
// nuxt.config.ts
|
|
26
24
|
export default defineNuxtConfig({
|
|
27
25
|
modules: ["@diphyx/harlemify"],
|
|
28
|
-
harlemify: {
|
|
29
|
-
action: {
|
|
30
|
-
endpoint: "https://api.example.com",
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
26
|
});
|
|
34
27
|
```
|
|
35
28
|
|
|
36
29
|
## Usage
|
|
37
30
|
|
|
38
31
|
```typescript
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}),
|
|
47
|
-
name: factory.string(),
|
|
48
|
-
email: factory.email(),
|
|
49
|
-
};
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
export type User = ShapeInfer<typeof userShape>;
|
|
32
|
+
const userShape = shape((factory) => ({
|
|
33
|
+
id: factory.number().meta({
|
|
34
|
+
identifier: true,
|
|
35
|
+
}),
|
|
36
|
+
name: factory.string(),
|
|
37
|
+
email: factory.email(),
|
|
38
|
+
}));
|
|
53
39
|
|
|
54
40
|
export const userStore = createStore({
|
|
55
41
|
name: "users",
|
|
@@ -65,13 +51,17 @@ export const userStore = createStore({
|
|
|
65
51
|
users: from("list"),
|
|
66
52
|
};
|
|
67
53
|
},
|
|
68
|
-
action({ api
|
|
54
|
+
action({ api }) {
|
|
69
55
|
return {
|
|
70
|
-
list: api.get(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
56
|
+
list: api.get(
|
|
57
|
+
{
|
|
58
|
+
url: "/users",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
model: "list",
|
|
62
|
+
mode: ModelManyMode.SET,
|
|
63
|
+
},
|
|
64
|
+
),
|
|
75
65
|
};
|
|
76
66
|
},
|
|
77
67
|
});
|
|
@@ -79,15 +69,15 @@ export const userStore = createStore({
|
|
|
79
69
|
|
|
80
70
|
```vue
|
|
81
71
|
<script setup>
|
|
82
|
-
const {
|
|
72
|
+
const { execute, loading } = useStoreAction(userStore, "list");
|
|
73
|
+
const { data } = useStoreView(userStore, "users");
|
|
83
74
|
|
|
84
|
-
await
|
|
75
|
+
await execute();
|
|
85
76
|
</script>
|
|
86
77
|
|
|
87
78
|
<template>
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
<li v-for="user in view.users.value" :key="user.id">{{ user.name }}</li>
|
|
79
|
+
<ul v-if="!loading">
|
|
80
|
+
<li v-for="user in data.value" :key="user.id">{{ user.name }}</li>
|
|
91
81
|
</ul>
|
|
92
82
|
</template>
|
|
93
83
|
```
|
package/dist/module.d.mts
CHANGED
|
@@ -4,13 +4,13 @@ interface RuntimeModelConfig {
|
|
|
4
4
|
identifier?: string;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
interface RuntimeViewConfig {
|
|
8
|
+
clone?: ViewClone;
|
|
9
|
+
}
|
|
7
10
|
declare enum ViewClone {
|
|
8
11
|
SHALLOW = "shallow",
|
|
9
12
|
DEEP = "deep"
|
|
10
13
|
}
|
|
11
|
-
interface RuntimeViewConfig {
|
|
12
|
-
clone?: ViewClone;
|
|
13
|
-
}
|
|
14
14
|
|
|
15
15
|
interface RuntimeActionConfig {
|
|
16
16
|
endpoint?: string;
|
package/dist/module.d.ts
CHANGED
|
@@ -4,13 +4,13 @@ interface RuntimeModelConfig {
|
|
|
4
4
|
identifier?: string;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
interface RuntimeViewConfig {
|
|
8
|
+
clone?: ViewClone;
|
|
9
|
+
}
|
|
7
10
|
declare enum ViewClone {
|
|
8
11
|
SHALLOW = "shallow",
|
|
9
12
|
DEEP = "deep"
|
|
10
13
|
}
|
|
11
|
-
interface RuntimeViewConfig {
|
|
12
|
-
clone?: ViewClone;
|
|
13
|
-
}
|
|
14
14
|
|
|
15
15
|
interface RuntimeActionConfig {
|
|
16
16
|
endpoint?: string;
|
package/dist/module.json
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import { type Ref } from "vue";
|
|
2
|
-
import { ActionStatus } from "../core/types/action.js";
|
|
3
|
-
export
|
|
1
|
+
import { type ComputedRef, type Ref } from "vue";
|
|
2
|
+
import { ActionStatus, type ActionCall, type ActionCallOptions } from "../core/types/action.js";
|
|
3
|
+
export interface UseStoreActionOptions {
|
|
4
|
+
isolated?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export type UseStoreAction<T> = {
|
|
7
|
+
execute: (options?: ActionCallOptions) => Promise<T>;
|
|
8
|
+
error: Readonly<Ref<Error | null>>;
|
|
9
|
+
status: Readonly<Ref<ActionStatus>>;
|
|
10
|
+
loading: ComputedRef<boolean>;
|
|
11
|
+
reset: () => void;
|
|
12
|
+
};
|
|
4
13
|
export declare function useIsolatedActionError(): Ref<Error | null>;
|
|
14
|
+
export declare function useIsolatedActionStatus(): Ref<ActionStatus>;
|
|
15
|
+
export declare function useStoreAction<A extends Record<string, ActionCall<any>>, K extends keyof A & string, T = Awaited<ReturnType<A[K]>>>(store: {
|
|
16
|
+
action: A;
|
|
17
|
+
}, key: K, options?: UseStoreActionOptions): UseStoreAction<T>;
|
|
@@ -1,8 +1,54 @@
|
|
|
1
|
-
import { ref } from "vue";
|
|
2
|
-
import {
|
|
1
|
+
import { ref, computed } from "vue";
|
|
2
|
+
import {
|
|
3
|
+
ActionStatus
|
|
4
|
+
} from "../core/types/action.js";
|
|
5
|
+
export function useIsolatedActionError() {
|
|
6
|
+
return ref(null);
|
|
7
|
+
}
|
|
3
8
|
export function useIsolatedActionStatus() {
|
|
4
9
|
return ref(ActionStatus.IDLE);
|
|
5
10
|
}
|
|
6
|
-
export function
|
|
7
|
-
|
|
11
|
+
export function useStoreAction(store, key, options) {
|
|
12
|
+
const action = store.action[key];
|
|
13
|
+
if (!action) {
|
|
14
|
+
throw new Error(`Action "${key}" not found in store`);
|
|
15
|
+
}
|
|
16
|
+
let error;
|
|
17
|
+
let status;
|
|
18
|
+
let loading;
|
|
19
|
+
let reset;
|
|
20
|
+
if (options?.isolated) {
|
|
21
|
+
const isolatedError = useIsolatedActionError();
|
|
22
|
+
const isolatedStatus = useIsolatedActionStatus();
|
|
23
|
+
error = isolatedError;
|
|
24
|
+
status = isolatedStatus;
|
|
25
|
+
loading = computed(() => {
|
|
26
|
+
return isolatedStatus.value === ActionStatus.PENDING;
|
|
27
|
+
});
|
|
28
|
+
reset = () => {
|
|
29
|
+
isolatedStatus.value = ActionStatus.IDLE;
|
|
30
|
+
isolatedError.value = null;
|
|
31
|
+
};
|
|
32
|
+
} else {
|
|
33
|
+
error = action.error;
|
|
34
|
+
status = action.status;
|
|
35
|
+
loading = action.loading;
|
|
36
|
+
reset = action.reset;
|
|
37
|
+
}
|
|
38
|
+
function execute(callOptions = {}) {
|
|
39
|
+
if (options?.isolated) {
|
|
40
|
+
callOptions.bind = {
|
|
41
|
+
status,
|
|
42
|
+
error
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return action(callOptions);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
execute,
|
|
49
|
+
error,
|
|
50
|
+
status,
|
|
51
|
+
loading,
|
|
52
|
+
reset
|
|
53
|
+
};
|
|
8
54
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ModelCall, ModelOneCall, ModelManyCall, ModelOneCommit, ModelManyCommit, StoreModel, ModelDefinitions } from "../core/types/model.js";
|
|
2
|
+
export interface UseStoreModelOptions {
|
|
3
|
+
debounce?: number;
|
|
4
|
+
throttle?: number;
|
|
5
|
+
}
|
|
6
|
+
type UseStoreModelOne<C extends ModelOneCommit<any>> = {
|
|
7
|
+
set: C["set"];
|
|
8
|
+
reset: C["reset"];
|
|
9
|
+
patch: C["patch"];
|
|
10
|
+
};
|
|
11
|
+
type UseStoreModelMany<C extends ModelManyCommit<any>> = {
|
|
12
|
+
set: C["set"];
|
|
13
|
+
reset: C["reset"];
|
|
14
|
+
patch: C["patch"];
|
|
15
|
+
add: C["add"];
|
|
16
|
+
remove: C["remove"];
|
|
17
|
+
};
|
|
18
|
+
export type UseStoreModel<M extends ModelCall<any> = ModelCall<any>> = M extends ModelManyCall<infer S> ? UseStoreModelMany<ModelManyCommit<S>> : M extends ModelOneCall<infer S> ? UseStoreModelOne<ModelOneCommit<S>> : never;
|
|
19
|
+
export declare function useStoreModel<M extends StoreModel<ModelDefinitions>, K extends keyof M & string>(store: {
|
|
20
|
+
model: M;
|
|
21
|
+
}, key: K, options?: UseStoreModelOptions): UseStoreModel<M[K]>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { debounce, throttle } from "../core/utils/base.js";
|
|
2
|
+
function isMany(model) {
|
|
3
|
+
return "add" in model && typeof model.add === "function";
|
|
4
|
+
}
|
|
5
|
+
function wrapCommit(commit, options) {
|
|
6
|
+
if (options?.debounce) {
|
|
7
|
+
return debounce(commit, options.debounce);
|
|
8
|
+
}
|
|
9
|
+
if (options?.throttle) {
|
|
10
|
+
return throttle(commit, options.throttle);
|
|
11
|
+
}
|
|
12
|
+
return commit;
|
|
13
|
+
}
|
|
14
|
+
export function useStoreModel(store, key, options) {
|
|
15
|
+
const model = store.model[key];
|
|
16
|
+
if (!model) {
|
|
17
|
+
throw new Error(`Model "${key}" not found in store`);
|
|
18
|
+
}
|
|
19
|
+
let output = {
|
|
20
|
+
set: wrapCommit(model.set.bind(model), options),
|
|
21
|
+
reset: wrapCommit(model.reset.bind(model), options),
|
|
22
|
+
patch: wrapCommit(model.patch.bind(model), options)
|
|
23
|
+
};
|
|
24
|
+
if (isMany(model)) {
|
|
25
|
+
output = {
|
|
26
|
+
...output,
|
|
27
|
+
add: wrapCommit(model.add.bind(model), options),
|
|
28
|
+
remove: wrapCommit(model.remove.bind(model), options)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return output;
|
|
32
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ComputedRef, type WatchStopHandle } from "vue";
|
|
2
|
+
import type { ViewCall } from "../core/types/view.js";
|
|
3
|
+
export interface UseStoreViewTrackOptions {
|
|
4
|
+
deep?: boolean;
|
|
5
|
+
immediate?: boolean;
|
|
6
|
+
debounce?: number;
|
|
7
|
+
throttle?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface UseStoreViewOptions<T> {
|
|
10
|
+
proxy?: boolean;
|
|
11
|
+
default?: T;
|
|
12
|
+
}
|
|
13
|
+
export type UseStoreViewData<T> = {
|
|
14
|
+
value: T;
|
|
15
|
+
} & (T extends Record<string, unknown> ? {
|
|
16
|
+
[K in keyof T]: T[K];
|
|
17
|
+
} : Record<string, unknown>);
|
|
18
|
+
export type UseStoreViewProxy<T> = {
|
|
19
|
+
data: UseStoreViewData<T>;
|
|
20
|
+
track: (handler: (value: T) => void, options?: UseStoreViewTrackOptions) => WatchStopHandle;
|
|
21
|
+
};
|
|
22
|
+
export type UseStoreViewComputed<T> = {
|
|
23
|
+
data: ComputedRef<T>;
|
|
24
|
+
track: (handler: (value: T) => void, options?: UseStoreViewTrackOptions) => WatchStopHandle;
|
|
25
|
+
};
|
|
26
|
+
export declare function useStoreView<V extends Record<string, ViewCall>, K extends keyof V & string, T = V[K] extends ComputedRef<infer R> ? R : unknown>(store: {
|
|
27
|
+
view: V;
|
|
28
|
+
}, key: K, options: UseStoreViewOptions<T> & {
|
|
29
|
+
proxy: false;
|
|
30
|
+
}): UseStoreViewComputed<T>;
|
|
31
|
+
export declare function useStoreView<V extends Record<string, ViewCall>, K extends keyof V & string, T = V[K] extends ComputedRef<infer R> ? R : unknown>(store: {
|
|
32
|
+
view: V;
|
|
33
|
+
}, key: K, options?: UseStoreViewOptions<T>): UseStoreViewProxy<T>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { computed, watch } from "vue";
|
|
2
|
+
import { debounce, throttle, toReactiveProxy } from "../core/utils/base.js";
|
|
3
|
+
function resolveDefault(view, defaultValue) {
|
|
4
|
+
if (defaultValue === void 0) {
|
|
5
|
+
return view;
|
|
6
|
+
}
|
|
7
|
+
return computed(() => {
|
|
8
|
+
const value = view.value;
|
|
9
|
+
if (value == null) {
|
|
10
|
+
return defaultValue;
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function resolveData(source, proxy) {
|
|
16
|
+
if (proxy !== false) {
|
|
17
|
+
return toReactiveProxy(source);
|
|
18
|
+
}
|
|
19
|
+
return source;
|
|
20
|
+
}
|
|
21
|
+
export function useStoreView(store, key, options) {
|
|
22
|
+
if (!store.view[key]) {
|
|
23
|
+
throw new Error(`View "${key}" not found in store`);
|
|
24
|
+
}
|
|
25
|
+
const source = resolveDefault(store.view[key], options?.default);
|
|
26
|
+
const data = resolveData(source, options?.proxy);
|
|
27
|
+
function resolveCallback(callback, callbackOptions) {
|
|
28
|
+
if (callbackOptions?.debounce) {
|
|
29
|
+
return debounce(callback, callbackOptions.debounce);
|
|
30
|
+
}
|
|
31
|
+
if (callbackOptions?.throttle) {
|
|
32
|
+
return throttle(callback, callbackOptions.throttle);
|
|
33
|
+
}
|
|
34
|
+
return callback;
|
|
35
|
+
}
|
|
36
|
+
function track(handler, trackOptions) {
|
|
37
|
+
const callback = resolveCallback(handler, trackOptions);
|
|
38
|
+
const stop = watch(
|
|
39
|
+
source,
|
|
40
|
+
(value) => {
|
|
41
|
+
callback(value);
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
deep: trackOptions?.deep,
|
|
45
|
+
immediate: trackOptions?.immediate
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
return stop;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
data,
|
|
52
|
+
track
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -1,46 +1,69 @@
|
|
|
1
|
+
import { wrapBaseDefinition } from "../utils/base.js";
|
|
1
2
|
import {
|
|
2
3
|
ActionApiMethod
|
|
3
4
|
} from "../types/action.js";
|
|
4
5
|
export function createActionFactory(config, logger) {
|
|
5
6
|
function apiCall(request, commit) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
let key = "";
|
|
15
|
-
return {
|
|
16
|
-
get key() {
|
|
17
|
-
return key;
|
|
7
|
+
return wrapBaseDefinition({
|
|
8
|
+
request: {
|
|
9
|
+
endpoint: config?.endpoint,
|
|
10
|
+
headers: config?.headers,
|
|
11
|
+
query: config?.query,
|
|
12
|
+
timeout: config?.timeout,
|
|
13
|
+
concurrent: config?.concurrent,
|
|
14
|
+
...request
|
|
18
15
|
},
|
|
19
|
-
setKey(value) {
|
|
20
|
-
key = value;
|
|
21
|
-
},
|
|
22
|
-
request: mergedRequest,
|
|
23
16
|
commit,
|
|
24
17
|
logger
|
|
25
|
-
};
|
|
18
|
+
});
|
|
26
19
|
}
|
|
27
20
|
function apiGet(request, commit) {
|
|
28
21
|
return apiCall({ ...request, method: ActionApiMethod.GET }, commit);
|
|
29
22
|
}
|
|
30
23
|
function apiHead(request, commit) {
|
|
31
|
-
return apiCall(
|
|
24
|
+
return apiCall(
|
|
25
|
+
{
|
|
26
|
+
...request,
|
|
27
|
+
method: ActionApiMethod.HEAD
|
|
28
|
+
},
|
|
29
|
+
commit
|
|
30
|
+
);
|
|
32
31
|
}
|
|
33
32
|
function apiPost(request, commit) {
|
|
34
|
-
return apiCall(
|
|
33
|
+
return apiCall(
|
|
34
|
+
{
|
|
35
|
+
...request,
|
|
36
|
+
method: ActionApiMethod.POST
|
|
37
|
+
},
|
|
38
|
+
commit
|
|
39
|
+
);
|
|
35
40
|
}
|
|
36
41
|
function apiPut(request, commit) {
|
|
37
|
-
return apiCall(
|
|
42
|
+
return apiCall(
|
|
43
|
+
{
|
|
44
|
+
...request,
|
|
45
|
+
method: ActionApiMethod.PUT
|
|
46
|
+
},
|
|
47
|
+
commit
|
|
48
|
+
);
|
|
38
49
|
}
|
|
39
50
|
function apiPatch(request, commit) {
|
|
40
|
-
return apiCall(
|
|
51
|
+
return apiCall(
|
|
52
|
+
{
|
|
53
|
+
...request,
|
|
54
|
+
method: ActionApiMethod.PATCH
|
|
55
|
+
},
|
|
56
|
+
commit
|
|
57
|
+
);
|
|
41
58
|
}
|
|
42
59
|
function apiDelete(request, commit) {
|
|
43
|
-
return apiCall(
|
|
60
|
+
return apiCall(
|
|
61
|
+
{
|
|
62
|
+
...request,
|
|
63
|
+
method: ActionApiMethod.DELETE
|
|
64
|
+
},
|
|
65
|
+
commit
|
|
66
|
+
);
|
|
44
67
|
}
|
|
45
68
|
const api = Object.assign(apiCall, {
|
|
46
69
|
get: apiGet,
|
|
@@ -50,18 +73,15 @@ export function createActionFactory(config, logger) {
|
|
|
50
73
|
patch: apiPatch,
|
|
51
74
|
delete: apiDelete
|
|
52
75
|
});
|
|
53
|
-
function handler(callback) {
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
get key() {
|
|
57
|
-
return key;
|
|
58
|
-
},
|
|
59
|
-
setKey(value) {
|
|
60
|
-
key = value;
|
|
61
|
-
},
|
|
76
|
+
function handler(callback, options) {
|
|
77
|
+
return wrapBaseDefinition({
|
|
62
78
|
callback,
|
|
79
|
+
options: {
|
|
80
|
+
concurrent: config?.concurrent,
|
|
81
|
+
...options
|
|
82
|
+
},
|
|
63
83
|
logger
|
|
64
|
-
};
|
|
84
|
+
});
|
|
65
85
|
}
|
|
66
86
|
return {
|
|
67
87
|
api,
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
+
import { wrapBaseDefinition } from "../utils/base.js";
|
|
1
2
|
import {
|
|
2
3
|
ModelKind
|
|
3
4
|
} from "../types/model.js";
|
|
4
5
|
export function createModelFactory(config, logger) {
|
|
5
6
|
function one(shape, options) {
|
|
6
|
-
|
|
7
|
-
return {
|
|
8
|
-
get key() {
|
|
9
|
-
return key;
|
|
10
|
-
},
|
|
11
|
-
setKey(value) {
|
|
12
|
-
key = value;
|
|
13
|
-
},
|
|
7
|
+
return wrapBaseDefinition({
|
|
14
8
|
shape,
|
|
15
9
|
kind: ModelKind.OBJECT,
|
|
16
10
|
options: {
|
|
@@ -18,17 +12,10 @@ export function createModelFactory(config, logger) {
|
|
|
18
12
|
...options
|
|
19
13
|
},
|
|
20
14
|
logger
|
|
21
|
-
};
|
|
15
|
+
});
|
|
22
16
|
}
|
|
23
17
|
function many(shape, options) {
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
get key() {
|
|
27
|
-
return key;
|
|
28
|
-
},
|
|
29
|
-
setKey(value) {
|
|
30
|
-
key = value;
|
|
31
|
-
},
|
|
18
|
+
return wrapBaseDefinition({
|
|
32
19
|
shape,
|
|
33
20
|
kind: ModelKind.ARRAY,
|
|
34
21
|
options: {
|
|
@@ -36,7 +23,7 @@ export function createModelFactory(config, logger) {
|
|
|
36
23
|
...options
|
|
37
24
|
},
|
|
38
25
|
logger
|
|
39
|
-
};
|
|
26
|
+
});
|
|
40
27
|
}
|
|
41
28
|
return {
|
|
42
29
|
one,
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
+
import { wrapBaseDefinition } from "../utils/base.js";
|
|
1
2
|
export function createViewFactory(config, logger) {
|
|
2
3
|
function from(model, resolver, options) {
|
|
3
|
-
|
|
4
|
-
const definition = {
|
|
5
|
-
get key() {
|
|
6
|
-
return key;
|
|
7
|
-
},
|
|
8
|
-
setKey(value) {
|
|
9
|
-
key = value;
|
|
10
|
-
},
|
|
4
|
+
return wrapBaseDefinition({
|
|
11
5
|
model: [model],
|
|
12
6
|
resolver,
|
|
13
7
|
options: {
|
|
@@ -15,18 +9,10 @@ export function createViewFactory(config, logger) {
|
|
|
15
9
|
...options
|
|
16
10
|
},
|
|
17
11
|
logger
|
|
18
|
-
};
|
|
19
|
-
return definition;
|
|
12
|
+
});
|
|
20
13
|
}
|
|
21
14
|
function merge(models, resolver, options) {
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
get key() {
|
|
25
|
-
return key;
|
|
26
|
-
},
|
|
27
|
-
setKey(value) {
|
|
28
|
-
key = value;
|
|
29
|
-
},
|
|
15
|
+
return wrapBaseDefinition({
|
|
30
16
|
models,
|
|
31
17
|
resolver,
|
|
32
18
|
options: {
|
|
@@ -34,7 +20,7 @@ export function createViewFactory(config, logger) {
|
|
|
34
20
|
...options
|
|
35
21
|
},
|
|
36
22
|
logger
|
|
37
|
-
};
|
|
23
|
+
});
|
|
38
24
|
}
|
|
39
25
|
return {
|
|
40
26
|
from,
|
|
@@ -52,18 +52,21 @@ export interface ActionApiDefinition<MD extends ModelDefinitions, VD extends Vie
|
|
|
52
52
|
request: ActionApiRequest<MD, VD>;
|
|
53
53
|
commit?: ActionApiCommit<MD>;
|
|
54
54
|
}
|
|
55
|
+
export interface ActionHandlerOptions {
|
|
56
|
+
payload?: unknown;
|
|
57
|
+
concurrent?: ActionConcurrent;
|
|
58
|
+
}
|
|
55
59
|
export type ActionHandlerCallback<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>, R = void> = (context: {
|
|
56
60
|
model: StoreModel<MD>;
|
|
57
61
|
view: StoreView<MD, VD>;
|
|
62
|
+
payload: unknown;
|
|
58
63
|
}) => Promise<R>;
|
|
59
64
|
export interface ActionHandlerDefinition<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>, R = void> extends BaseDefinition {
|
|
60
65
|
callback: ActionHandlerCallback<MD, VD, R>;
|
|
66
|
+
options?: ActionHandlerOptions;
|
|
61
67
|
}
|
|
62
68
|
export type ActionDefinition<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>> = ActionApiDefinition<MD, VD> | ActionHandlerDefinition<MD, VD, unknown>;
|
|
63
69
|
export type ActionDefinitions<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>> = Record<string, ActionDefinition<MD, VD>>;
|
|
64
|
-
export type StoreAction<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>, AD extends ActionDefinitions<MD, VD>> = {
|
|
65
|
-
[K in keyof AD]: ActionCall;
|
|
66
|
-
};
|
|
67
70
|
export interface ActionApiFactory<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>> {
|
|
68
71
|
(request: ActionApiRequest<MD, VD>, commit?: ActionApiCommit<MD>): ActionApiDefinition<MD, VD>;
|
|
69
72
|
get(request: ActionApiRequestShortcut<MD, VD>, commit?: ActionApiCommit<MD>): ActionApiDefinition<MD, VD>;
|
|
@@ -74,7 +77,7 @@ export interface ActionApiFactory<MD extends ModelDefinitions, VD extends ViewDe
|
|
|
74
77
|
delete(request: ActionApiRequestShortcut<MD, VD>, commit?: ActionApiCommit<MD>): ActionApiDefinition<MD, VD>;
|
|
75
78
|
}
|
|
76
79
|
export interface ActionHandlerFactory<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>> {
|
|
77
|
-
<R>(callback: ActionHandlerCallback<MD, VD, R
|
|
80
|
+
<R>(callback: ActionHandlerCallback<MD, VD, R>, options?: ActionHandlerOptions): ActionHandlerDefinition<MD, VD, R>;
|
|
78
81
|
}
|
|
79
82
|
export interface ActionFactory<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>> {
|
|
80
83
|
api: ActionApiFactory<MD, VD>;
|
|
@@ -84,8 +87,9 @@ export interface ActionCallBindOptions {
|
|
|
84
87
|
status?: Ref<ActionStatus>;
|
|
85
88
|
error?: Ref<Error | null>;
|
|
86
89
|
}
|
|
87
|
-
export interface
|
|
88
|
-
|
|
90
|
+
export interface ActionCallBaseOptions {
|
|
91
|
+
concurrent?: ActionConcurrent;
|
|
92
|
+
bind?: ActionCallBindOptions;
|
|
89
93
|
}
|
|
90
94
|
export interface ActionResolvedApi {
|
|
91
95
|
url: string;
|
|
@@ -100,7 +104,10 @@ export interface ActionCallTransformerOptions {
|
|
|
100
104
|
request?: (api: ActionResolvedApi) => ActionResolvedApi;
|
|
101
105
|
response?: (data: unknown) => unknown;
|
|
102
106
|
}
|
|
103
|
-
export interface
|
|
107
|
+
export interface ActionCallCommitOptions {
|
|
108
|
+
mode?: ModelOneMode | ModelManyMode;
|
|
109
|
+
}
|
|
110
|
+
export interface ActionApiCallOptions extends ActionCallBaseOptions {
|
|
104
111
|
params?: Record<string, string>;
|
|
105
112
|
headers?: Record<string, string>;
|
|
106
113
|
query?: Record<string, unknown>;
|
|
@@ -108,15 +115,30 @@ export interface ActionCallOptions {
|
|
|
108
115
|
timeout?: number;
|
|
109
116
|
signal?: AbortSignal;
|
|
110
117
|
transformer?: ActionCallTransformerOptions;
|
|
111
|
-
concurrent?: ActionConcurrent;
|
|
112
|
-
bind?: ActionCallBindOptions;
|
|
113
118
|
commit?: ActionCallCommitOptions;
|
|
114
119
|
}
|
|
115
|
-
export interface
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
export interface ActionResolvedHandler<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>> {
|
|
121
|
+
model: StoreModel<MD>;
|
|
122
|
+
view: StoreView<MD, VD>;
|
|
123
|
+
payload: unknown;
|
|
124
|
+
}
|
|
125
|
+
export interface ActionHandlerCallOptions extends ActionCallBaseOptions {
|
|
126
|
+
payload?: unknown;
|
|
127
|
+
}
|
|
128
|
+
export type ActionCallOptions = ActionApiCallOptions | ActionHandlerCallOptions;
|
|
129
|
+
export interface ActionCallBase {
|
|
119
130
|
readonly error: Readonly<Ref<Error | null>>;
|
|
120
|
-
readonly
|
|
131
|
+
readonly status: Readonly<Ref<ActionStatus>>;
|
|
132
|
+
readonly loading: ComputedRef<boolean>;
|
|
121
133
|
reset: () => void;
|
|
122
134
|
}
|
|
135
|
+
export interface ActionApiCall<T = void> extends ActionCallBase {
|
|
136
|
+
(options?: ActionApiCallOptions): Promise<T>;
|
|
137
|
+
}
|
|
138
|
+
export interface ActionHandlerCall<T = void> extends ActionCallBase {
|
|
139
|
+
(options?: ActionHandlerCallOptions): Promise<T>;
|
|
140
|
+
}
|
|
141
|
+
export type ActionCall<T = void> = ActionApiCall<T> | ActionHandlerCall<T>;
|
|
142
|
+
export type StoreAction<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>, AD extends ActionDefinitions<MD, VD>> = {
|
|
143
|
+
[K in keyof AD]: AD[K] extends ActionApiDefinition<MD, VD> ? ActionApiCall : AD[K] extends ActionHandlerDefinition<MD, VD, infer R> ? ActionHandlerCall<R> : never;
|
|
144
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ModelDefinitions, ModelFactory, StoreModel } from "./model.js";
|
|
2
2
|
import type { ViewDefinitions, ViewFactory, StoreView } from "./view.js";
|
|
3
|
-
import type {
|
|
4
|
-
export interface StoreConfig<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>,
|
|
3
|
+
import type { ActionDefinitions, ActionFactory, StoreAction } from "./action.js";
|
|
4
|
+
export interface StoreConfig<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>, AD extends ActionDefinitions<MD, VD>> {
|
|
5
5
|
name: string;
|
|
6
6
|
model: (factory: ModelFactory) => MD;
|
|
7
7
|
view: (factory: ViewFactory<MD>) => VD;
|
|
8
|
-
action: (factory: ActionFactory<MD, VD>) =>
|
|
8
|
+
action: (factory: ActionFactory<MD, VD>) => AD;
|
|
9
9
|
}
|
|
10
10
|
export interface Store<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>, AD extends ActionDefinitions<MD, VD>> {
|
|
11
11
|
model: StoreModel<MD>;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { ComputedRef } from "vue";
|
|
2
2
|
import type { BaseDefinition } from "./base.js";
|
|
3
3
|
import type { ModelDefinitions, ModelDefinitionInfer, ModelDefinitionInferTuple } from "./model.js";
|
|
4
|
+
export interface RuntimeViewConfig {
|
|
5
|
+
clone?: ViewClone;
|
|
6
|
+
}
|
|
4
7
|
export declare enum ViewClone {
|
|
5
8
|
SHALLOW = "shallow",
|
|
6
9
|
DEEP = "deep"
|
|
7
10
|
}
|
|
8
|
-
export interface RuntimeViewConfig {
|
|
9
|
-
clone?: ViewClone;
|
|
10
|
-
}
|
|
11
11
|
export interface ViewDefinitionOptions {
|
|
12
12
|
clone?: ViewClone;
|
|
13
13
|
}
|
|
@@ -77,13 +77,22 @@ function resolveApiSignal(options, abortController) {
|
|
|
77
77
|
}
|
|
78
78
|
return abortController.signal;
|
|
79
79
|
}
|
|
80
|
-
function
|
|
80
|
+
function resolveHandlerPayload(definition, options) {
|
|
81
|
+
if (options?.payload !== void 0) {
|
|
82
|
+
return options.payload;
|
|
83
|
+
}
|
|
84
|
+
if (definition.options?.payload !== void 0) {
|
|
85
|
+
return definition.options.payload;
|
|
86
|
+
}
|
|
87
|
+
return void 0;
|
|
88
|
+
}
|
|
89
|
+
function resolveApiCommitTarget(commit, model) {
|
|
81
90
|
if (commit) {
|
|
82
91
|
return model[commit.model];
|
|
83
92
|
}
|
|
84
93
|
return void 0;
|
|
85
94
|
}
|
|
86
|
-
function
|
|
95
|
+
function resolveApiCommitMode(commit, options) {
|
|
87
96
|
if (commit) {
|
|
88
97
|
if (options?.commit?.mode) {
|
|
89
98
|
return options.commit.mode;
|
|
@@ -92,14 +101,17 @@ function resolveCommitMode(commit, options) {
|
|
|
92
101
|
}
|
|
93
102
|
return void 0;
|
|
94
103
|
}
|
|
95
|
-
function
|
|
104
|
+
function resolveApiCommitValue(commit, data) {
|
|
96
105
|
if (typeof commit.value === "function") {
|
|
97
106
|
return commit.value(data);
|
|
98
107
|
}
|
|
99
108
|
return data;
|
|
100
109
|
}
|
|
101
110
|
function isApiDefinition(definition) {
|
|
102
|
-
return "
|
|
111
|
+
return !("callback" in definition);
|
|
112
|
+
}
|
|
113
|
+
function isHandlerDefinition(definition) {
|
|
114
|
+
return "callback" in definition;
|
|
103
115
|
}
|
|
104
116
|
function resolveConcurrent(definition, options) {
|
|
105
117
|
if (options?.concurrent) {
|
|
@@ -108,6 +120,9 @@ function resolveConcurrent(definition, options) {
|
|
|
108
120
|
if (isApiDefinition(definition) && definition.request.concurrent) {
|
|
109
121
|
return definition.request.concurrent;
|
|
110
122
|
}
|
|
123
|
+
if (isHandlerDefinition(definition) && definition.options?.concurrent) {
|
|
124
|
+
return definition.options.concurrent;
|
|
125
|
+
}
|
|
111
126
|
return ActionConcurrent.BLOCK;
|
|
112
127
|
}
|
|
113
128
|
async function executeApi(definition, api, options) {
|
|
@@ -147,15 +162,13 @@ async function executeApi(definition, api, options) {
|
|
|
147
162
|
throw fetchError;
|
|
148
163
|
}
|
|
149
164
|
}
|
|
150
|
-
async function executeHandler(definition,
|
|
165
|
+
async function executeHandler(definition, handler) {
|
|
151
166
|
try {
|
|
152
167
|
definition.logger?.debug("Action handler phase", {
|
|
153
168
|
action: definition.key
|
|
154
169
|
});
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
view
|
|
158
|
-
});
|
|
170
|
+
const data = await definition.callback(handler);
|
|
171
|
+
return data;
|
|
159
172
|
} catch (error) {
|
|
160
173
|
if (isError(error, ActionApiError, ActionHandlerError)) {
|
|
161
174
|
throw error;
|
|
@@ -186,7 +199,7 @@ function executeCommit(definition, target, mode, data) {
|
|
|
186
199
|
if (!isEmptyRecord(target.aliases())) {
|
|
187
200
|
data = resolveAliasInbound(data, target.aliases());
|
|
188
201
|
}
|
|
189
|
-
const value =
|
|
202
|
+
const value = resolveApiCommitValue(definition.commit, data);
|
|
190
203
|
target.commit(mode, value, definition.commit.options);
|
|
191
204
|
} catch (error) {
|
|
192
205
|
const commitError = toError(error, ActionCommitError);
|
|
@@ -204,7 +217,6 @@ export function createAction(definition, model, view) {
|
|
|
204
217
|
});
|
|
205
218
|
let currentController = null;
|
|
206
219
|
let abortController = null;
|
|
207
|
-
let globalData = null;
|
|
208
220
|
const globalError = ref(null);
|
|
209
221
|
const globalStatus = ref(ActionStatus.IDLE);
|
|
210
222
|
const loading = computed(() => {
|
|
@@ -242,10 +254,10 @@ export function createAction(definition, model, view) {
|
|
|
242
254
|
activeError.value = null;
|
|
243
255
|
currentController = (async () => {
|
|
244
256
|
try {
|
|
245
|
-
let data;
|
|
257
|
+
let data = void 0;
|
|
246
258
|
if (isApiDefinition(definition)) {
|
|
247
|
-
const target =
|
|
248
|
-
const mode =
|
|
259
|
+
const target = resolveApiCommitTarget(definition.commit, model);
|
|
260
|
+
const mode = resolveApiCommitMode(definition.commit, options);
|
|
249
261
|
const url = resolveApiUrl(definition, view, options);
|
|
250
262
|
const method = resolveApiMethod(definition, view);
|
|
251
263
|
const headers = resolveApiHeaders(definition, view, options);
|
|
@@ -267,10 +279,14 @@ export function createAction(definition, model, view) {
|
|
|
267
279
|
options
|
|
268
280
|
);
|
|
269
281
|
executeCommit(definition, target, mode, data);
|
|
270
|
-
} else {
|
|
271
|
-
|
|
282
|
+
} else if (isHandlerDefinition(definition)) {
|
|
283
|
+
const payload = resolveHandlerPayload(definition, options);
|
|
284
|
+
data = await executeHandler(definition, {
|
|
285
|
+
model,
|
|
286
|
+
view,
|
|
287
|
+
payload
|
|
288
|
+
});
|
|
272
289
|
}
|
|
273
|
-
globalData = data;
|
|
274
290
|
activeStatus.value = ActionStatus.SUCCESS;
|
|
275
291
|
definition.logger?.debug("Action success", {
|
|
276
292
|
action: definition.key
|
|
@@ -288,22 +304,18 @@ export function createAction(definition, model, view) {
|
|
|
288
304
|
return currentController;
|
|
289
305
|
}
|
|
290
306
|
const action = Object.assign(execute, {
|
|
291
|
-
get loading() {
|
|
292
|
-
return loading;
|
|
293
|
-
},
|
|
294
307
|
get error() {
|
|
295
308
|
return readonly(globalError);
|
|
296
309
|
},
|
|
297
310
|
get status() {
|
|
298
311
|
return readonly(globalStatus);
|
|
299
312
|
},
|
|
300
|
-
get
|
|
301
|
-
return
|
|
313
|
+
get loading() {
|
|
314
|
+
return loading;
|
|
302
315
|
},
|
|
303
316
|
reset() {
|
|
304
317
|
globalError.value = null;
|
|
305
318
|
globalStatus.value = ActionStatus.IDLE;
|
|
306
|
-
globalData = null;
|
|
307
319
|
}
|
|
308
320
|
});
|
|
309
321
|
return action;
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
+
import type { BaseDefinition } from "../types/base.js";
|
|
2
|
+
export declare function wrapBaseDefinition<T extends Omit<BaseDefinition, "key" | "setKey">>(definition: T): T & BaseDefinition;
|
|
1
3
|
export declare function trimStart(value: string, char: string): string;
|
|
2
4
|
export declare function trimEnd(value: string, char: string): string;
|
|
5
|
+
export declare function isObject(value: unknown): value is object;
|
|
3
6
|
export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
4
7
|
export declare function isEmptyRecord(record: Record<string, unknown> | undefined): record is undefined;
|
|
8
|
+
type ReferenceProxy<T> = {
|
|
9
|
+
value: T;
|
|
10
|
+
} & Record<string | symbol, unknown>;
|
|
11
|
+
export declare function toReactiveProxy<T>(reference: {
|
|
12
|
+
value: T;
|
|
13
|
+
}): ReferenceProxy<T>;
|
|
14
|
+
export declare function debounce<T extends (...args: any[]) => any>(callback: T, delay: number): T;
|
|
15
|
+
export declare function throttle<T extends (...args: any[]) => any>(callback: T, delay: number): T;
|
|
16
|
+
export {};
|
|
@@ -1,11 +1,33 @@
|
|
|
1
|
+
export function wrapBaseDefinition(definition) {
|
|
2
|
+
let key = "";
|
|
3
|
+
return Object.defineProperties(definition, {
|
|
4
|
+
key: {
|
|
5
|
+
get() {
|
|
6
|
+
return key;
|
|
7
|
+
},
|
|
8
|
+
enumerable: true,
|
|
9
|
+
configurable: true
|
|
10
|
+
},
|
|
11
|
+
setKey: {
|
|
12
|
+
value(value) {
|
|
13
|
+
key = value;
|
|
14
|
+
},
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
1
20
|
export function trimStart(value, char) {
|
|
2
21
|
return value.replace(new RegExp(`^${char}+`), "");
|
|
3
22
|
}
|
|
4
23
|
export function trimEnd(value, char) {
|
|
5
24
|
return value.replace(new RegExp(`${char}+$`), "");
|
|
6
25
|
}
|
|
26
|
+
export function isObject(value) {
|
|
27
|
+
return value != null && typeof value === "object";
|
|
28
|
+
}
|
|
7
29
|
export function isPlainObject(value) {
|
|
8
|
-
if (!value
|
|
30
|
+
if (!isObject(value)) {
|
|
9
31
|
return false;
|
|
10
32
|
}
|
|
11
33
|
if (Array.isArray(value)) {
|
|
@@ -22,3 +44,85 @@ export function isEmptyRecord(record) {
|
|
|
22
44
|
}
|
|
23
45
|
return false;
|
|
24
46
|
}
|
|
47
|
+
export function toReactiveProxy(reference) {
|
|
48
|
+
function get(_target, prop) {
|
|
49
|
+
if (prop === "value") {
|
|
50
|
+
return reference.value;
|
|
51
|
+
}
|
|
52
|
+
if (!isObject(reference.value)) {
|
|
53
|
+
return void 0;
|
|
54
|
+
}
|
|
55
|
+
return reference.value[prop];
|
|
56
|
+
}
|
|
57
|
+
function has(_target, prop) {
|
|
58
|
+
if (prop === "value") {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
if (!isObject(reference.value)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
return prop in reference.value;
|
|
65
|
+
}
|
|
66
|
+
function ownKeys() {
|
|
67
|
+
if (!isObject(reference.value)) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
return Reflect.ownKeys(reference.value);
|
|
71
|
+
}
|
|
72
|
+
function getOwnPropertyDescriptor(_target, prop) {
|
|
73
|
+
if (!isObject(reference.value) || !(prop in reference.value)) {
|
|
74
|
+
return void 0;
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
configurable: true,
|
|
78
|
+
enumerable: true,
|
|
79
|
+
value: reference.value[prop]
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return new Proxy(
|
|
83
|
+
{},
|
|
84
|
+
{
|
|
85
|
+
get,
|
|
86
|
+
has,
|
|
87
|
+
ownKeys,
|
|
88
|
+
getOwnPropertyDescriptor
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
export function debounce(callback, delay) {
|
|
93
|
+
let timer = null;
|
|
94
|
+
return (...args) => {
|
|
95
|
+
if (timer) {
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
}
|
|
98
|
+
timer = setTimeout(() => {
|
|
99
|
+
timer = null;
|
|
100
|
+
callback(...args);
|
|
101
|
+
}, delay);
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export function throttle(callback, delay) {
|
|
105
|
+
let lastCall = 0;
|
|
106
|
+
let timer = null;
|
|
107
|
+
return (...args) => {
|
|
108
|
+
const now = Date.now();
|
|
109
|
+
const remaining = delay - (now - lastCall);
|
|
110
|
+
if (remaining <= 0) {
|
|
111
|
+
if (timer) {
|
|
112
|
+
clearTimeout(timer);
|
|
113
|
+
timer = null;
|
|
114
|
+
}
|
|
115
|
+
lastCall = now;
|
|
116
|
+
callback(...args);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (timer) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
timer = setTimeout(() => {
|
|
123
|
+
lastCall = Date.now();
|
|
124
|
+
timer = null;
|
|
125
|
+
callback(...args);
|
|
126
|
+
}, remaining);
|
|
127
|
+
};
|
|
128
|
+
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -7,7 +7,12 @@ 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, ActionApiMethod } from "./core/types/action.js";
|
|
10
|
-
export type { ActionCall, ActionCallOptions, ActionCallTransformerOptions, ActionCallBindOptions, ActionCallCommitOptions, ActionResolvedApi, } from "./core/types/action.js";
|
|
10
|
+
export type { ActionCall, ActionApiCall, ActionHandlerCall, ActionCallOptions, ActionCallBaseOptions, ActionApiCallOptions, ActionHandlerCallOptions, ActionCallTransformerOptions, ActionCallBindOptions, ActionCallCommitOptions, ActionHandlerOptions, ActionResolvedApi, } from "./core/types/action.js";
|
|
11
11
|
export { ActionApiError, ActionHandlerError, ActionCommitError, ActionConcurrentError } from "./core/utils/error.js";
|
|
12
|
-
export { useIsolatedActionStatus, useIsolatedActionError } from "./composables/action.js";
|
|
12
|
+
export { useIsolatedActionStatus, useIsolatedActionError, useStoreAction } from "./composables/action.js";
|
|
13
|
+
export type { UseStoreActionOptions, UseStoreAction } from "./composables/action.js";
|
|
14
|
+
export { useStoreModel } from "./composables/model.js";
|
|
15
|
+
export type { UseStoreModelOptions, UseStoreModel } from "./composables/model.js";
|
|
16
|
+
export { useStoreView } from "./composables/view.js";
|
|
17
|
+
export type { UseStoreViewOptions, UseStoreViewProxy, UseStoreViewComputed, UseStoreViewData, UseStoreViewTrackOptions, } from "./composables/view.js";
|
|
13
18
|
export type { RuntimeConfig } from "./config.js";
|
package/dist/runtime/index.js
CHANGED
|
@@ -4,4 +4,6 @@ export { ModelKind, ModelOneMode, ModelManyMode } from "./core/types/model.js";
|
|
|
4
4
|
export { ViewClone } from "./core/types/view.js";
|
|
5
5
|
export { ActionStatus, ActionConcurrent, ActionApiMethod } from "./core/types/action.js";
|
|
6
6
|
export { ActionApiError, ActionHandlerError, ActionCommitError, ActionConcurrentError } from "./core/utils/error.js";
|
|
7
|
-
export { useIsolatedActionStatus, useIsolatedActionError } from "./composables/action.js";
|
|
7
|
+
export { useIsolatedActionStatus, useIsolatedActionError, useStoreAction } from "./composables/action.js";
|
|
8
|
+
export { useStoreModel } from "./composables/model.js";
|
|
9
|
+
export { useStoreView } from "./composables/view.js";
|