@diphyx/harlemify 4.0.0 → 5.0.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 +15 -19
- package/dist/module.d.mts +5 -0
- package/dist/module.d.ts +5 -0
- package/dist/module.json +1 -1
- package/dist/runtime/composables/action.d.ts +2 -2
- package/dist/runtime/core/layers/action.d.ts +3 -2
- package/dist/runtime/core/layers/action.js +37 -69
- package/dist/runtime/core/layers/model.js +14 -0
- package/dist/runtime/core/layers/shape.d.ts +2 -2
- package/dist/runtime/core/layers/shape.js +3 -2
- package/dist/runtime/core/layers/view.d.ts +2 -2
- package/dist/runtime/core/layers/view.js +27 -5
- package/dist/runtime/core/store.d.ts +5 -23
- package/dist/runtime/core/store.js +8 -28
- package/dist/runtime/core/types/action.d.ts +78 -118
- package/dist/runtime/core/types/action.js +0 -15
- package/dist/runtime/core/types/base.d.ts +6 -0
- package/dist/runtime/core/types/base.js +0 -0
- package/dist/runtime/core/types/model.d.ts +47 -32
- package/dist/runtime/core/types/model.js +14 -0
- package/dist/runtime/core/types/shape.d.ts +30 -5
- package/dist/runtime/core/types/store.d.ts +14 -0
- package/dist/runtime/core/types/store.js +0 -0
- package/dist/runtime/core/types/view.d.ts +35 -24
- package/dist/runtime/core/types/view.js +5 -0
- package/dist/runtime/core/utils/action.d.ts +4 -4
- package/dist/runtime/core/utils/action.js +219 -203
- package/dist/runtime/core/utils/base.d.ts +4 -0
- package/dist/runtime/core/utils/base.js +24 -0
- package/dist/runtime/core/utils/error.d.ts +21 -0
- package/dist/runtime/core/utils/error.js +36 -0
- package/dist/runtime/core/utils/model.d.ts +3 -11
- package/dist/runtime/core/utils/model.js +104 -107
- package/dist/runtime/core/utils/shape.d.ts +6 -3
- package/dist/runtime/core/utils/shape.js +218 -14
- package/dist/runtime/core/utils/store.d.ts +8 -0
- package/dist/runtime/core/utils/store.js +35 -0
- package/dist/runtime/core/utils/view.d.ts +3 -4
- package/dist/runtime/core/utils/view.js +35 -14
- package/dist/runtime/index.d.ts +8 -4
- package/dist/runtime/index.js +4 -2
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
7
|
+
- **Single Factory** - Define shape, model, view, and action in one `createStore` call — fully typed end to end
|
|
8
|
+
- **Zod Shapes** - Schema-first design with built-in validation, type inference, and identifier metadata
|
|
9
|
+
- **Reactive Models** - `one()` and `many()` state containers with `set`, `patch`, `add`, `remove`, `reset` mutations
|
|
10
|
+
- **Computed Views** - Derive read-only state from models with `from()` and `merge()` — auto-tracked by Vue
|
|
11
|
+
- **API & Handler Actions** - Declarative HTTP actions with auto-commit, or custom handlers with full model/view access
|
|
12
|
+
- **Action Metadata** - Every action exposes `loading`, `status`, `error`, `data`, and `reset()` out of the box
|
|
13
|
+
- **Concurrency Control** - Block, skip, cancel, or allow parallel calls per action
|
|
14
|
+
- **SSR Ready** - Server-side rendering with automatic state hydration
|
|
13
15
|
|
|
14
16
|
## Install
|
|
15
17
|
|
|
@@ -35,7 +37,7 @@ export default defineNuxtConfig({
|
|
|
35
37
|
|
|
36
38
|
```typescript
|
|
37
39
|
// stores/user.ts
|
|
38
|
-
import { createStore, shape,
|
|
40
|
+
import { createStore, shape, ModelManyMode, type ShapeInfer } from "@diphyx/harlemify";
|
|
39
41
|
|
|
40
42
|
const userShape = shape((factory) => {
|
|
41
43
|
return {
|
|
@@ -63,19 +65,13 @@ export const userStore = createStore({
|
|
|
63
65
|
users: from("list"),
|
|
64
66
|
};
|
|
65
67
|
},
|
|
66
|
-
action({ api,
|
|
68
|
+
action({ api, handler }) {
|
|
67
69
|
return {
|
|
68
|
-
list: api
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
create: api
|
|
74
|
-
.post({
|
|
75
|
-
url: "/users",
|
|
76
|
-
})
|
|
77
|
-
.commit("list", ActionManyMode.ADD),
|
|
78
|
-
clear: commit("list", ActionManyMode.RESET),
|
|
70
|
+
list: api.get({ url: "/users" }, { model: "list", mode: ModelManyMode.SET }),
|
|
71
|
+
create: api.post({ url: "/users" }, { model: "list", mode: ModelManyMode.ADD }),
|
|
72
|
+
clear: handler(async ({ model }) => {
|
|
73
|
+
model.list.reset();
|
|
74
|
+
}),
|
|
79
75
|
};
|
|
80
76
|
},
|
|
81
77
|
});
|
package/dist/module.d.mts
CHANGED
package/dist/module.d.ts
CHANGED
package/dist/module.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type Ref } from "vue";
|
|
2
|
-
import {
|
|
2
|
+
import { ActionStatus } from "../core/types/action.js";
|
|
3
3
|
export declare function useIsolatedActionStatus(): Ref<ActionStatus>;
|
|
4
|
-
export declare function useIsolatedActionError(): Ref<
|
|
4
|
+
export declare function useIsolatedActionError(): Ref<Error | null>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ConsolaInstance } from "consola";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ModelDefinitions } from "../types/model.js";
|
|
3
|
+
import type { ViewDefinitions } from "../types/view.js";
|
|
3
4
|
import { type RuntimeActionConfig, type ActionFactory } from "../types/action.js";
|
|
4
|
-
export declare function createActionFactory<
|
|
5
|
+
export declare function createActionFactory<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>>(config?: RuntimeActionConfig, logger?: ConsolaInstance): ActionFactory<MD, VD>;
|
|
@@ -1,77 +1,46 @@
|
|
|
1
|
-
import { buildCommitMethod } from "../utils/action.js";
|
|
2
1
|
import {
|
|
3
|
-
ActionApiMethod
|
|
4
|
-
DEFINITION
|
|
2
|
+
ActionApiMethod
|
|
5
3
|
} from "../types/action.js";
|
|
6
|
-
export function createActionFactory(config, logger
|
|
7
|
-
function apiCall(
|
|
8
|
-
|
|
4
|
+
export function createActionFactory(config, logger) {
|
|
5
|
+
function apiCall(request, commit) {
|
|
6
|
+
const mergedRequest = {
|
|
9
7
|
endpoint: config?.endpoint,
|
|
10
8
|
headers: config?.headers,
|
|
11
9
|
query: config?.query,
|
|
12
10
|
timeout: config?.timeout,
|
|
13
11
|
concurrent: config?.concurrent,
|
|
14
|
-
...
|
|
15
|
-
};
|
|
16
|
-
const actionDefinition = {
|
|
17
|
-
api: apiDefinition,
|
|
18
|
-
logger
|
|
12
|
+
...request
|
|
19
13
|
};
|
|
14
|
+
let key = "";
|
|
20
15
|
return {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
27
|
-
return {
|
|
28
|
-
commit: buildCommitMethod(handleDefinition),
|
|
29
|
-
get [DEFINITION]() {
|
|
30
|
-
return handleDefinition;
|
|
31
|
-
}
|
|
32
|
-
};
|
|
16
|
+
get key() {
|
|
17
|
+
return key;
|
|
18
|
+
},
|
|
19
|
+
setKey(value) {
|
|
20
|
+
key = value;
|
|
33
21
|
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
22
|
+
request: mergedRequest,
|
|
23
|
+
commit,
|
|
24
|
+
logger
|
|
38
25
|
};
|
|
39
26
|
}
|
|
40
|
-
function apiGet(
|
|
41
|
-
return apiCall({
|
|
42
|
-
...definition,
|
|
43
|
-
method: ActionApiMethod.GET
|
|
44
|
-
});
|
|
27
|
+
function apiGet(request, commit) {
|
|
28
|
+
return apiCall({ ...request, method: ActionApiMethod.GET }, commit);
|
|
45
29
|
}
|
|
46
|
-
function apiHead(
|
|
47
|
-
return apiCall({
|
|
48
|
-
...definition,
|
|
49
|
-
method: ActionApiMethod.HEAD
|
|
50
|
-
});
|
|
30
|
+
function apiHead(request, commit) {
|
|
31
|
+
return apiCall({ ...request, method: ActionApiMethod.HEAD }, commit);
|
|
51
32
|
}
|
|
52
|
-
function apiPost(
|
|
53
|
-
return apiCall({
|
|
54
|
-
...definition,
|
|
55
|
-
method: ActionApiMethod.POST
|
|
56
|
-
});
|
|
33
|
+
function apiPost(request, commit) {
|
|
34
|
+
return apiCall({ ...request, method: ActionApiMethod.POST }, commit);
|
|
57
35
|
}
|
|
58
|
-
function apiPut(
|
|
59
|
-
return apiCall({
|
|
60
|
-
...definition,
|
|
61
|
-
method: ActionApiMethod.PUT
|
|
62
|
-
});
|
|
36
|
+
function apiPut(request, commit) {
|
|
37
|
+
return apiCall({ ...request, method: ActionApiMethod.PUT }, commit);
|
|
63
38
|
}
|
|
64
|
-
function apiPatch(
|
|
65
|
-
return apiCall({
|
|
66
|
-
...definition,
|
|
67
|
-
method: ActionApiMethod.PATCH
|
|
68
|
-
});
|
|
39
|
+
function apiPatch(request, commit) {
|
|
40
|
+
return apiCall({ ...request, method: ActionApiMethod.PATCH }, commit);
|
|
69
41
|
}
|
|
70
|
-
function apiDelete(
|
|
71
|
-
return apiCall({
|
|
72
|
-
...definition,
|
|
73
|
-
method: ActionApiMethod.DELETE
|
|
74
|
-
});
|
|
42
|
+
function apiDelete(request, commit) {
|
|
43
|
+
return apiCall({ ...request, method: ActionApiMethod.DELETE }, commit);
|
|
75
44
|
}
|
|
76
45
|
const api = Object.assign(apiCall, {
|
|
77
46
|
get: apiGet,
|
|
@@ -81,22 +50,21 @@ export function createActionFactory(config, logger, _model, _view) {
|
|
|
81
50
|
patch: apiPatch,
|
|
82
51
|
delete: apiDelete
|
|
83
52
|
});
|
|
84
|
-
function
|
|
85
|
-
|
|
86
|
-
handle: callback,
|
|
87
|
-
logger
|
|
88
|
-
};
|
|
53
|
+
function handler(callback) {
|
|
54
|
+
let key = "";
|
|
89
55
|
return {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
56
|
+
get key() {
|
|
57
|
+
return key;
|
|
58
|
+
},
|
|
59
|
+
setKey(value) {
|
|
60
|
+
key = value;
|
|
61
|
+
},
|
|
62
|
+
callback,
|
|
63
|
+
logger
|
|
94
64
|
};
|
|
95
65
|
}
|
|
96
|
-
const commit = buildCommitMethod({ logger });
|
|
97
66
|
return {
|
|
98
67
|
api,
|
|
99
|
-
|
|
100
|
-
commit
|
|
68
|
+
handler
|
|
101
69
|
};
|
|
102
70
|
}
|
|
@@ -3,7 +3,14 @@ import {
|
|
|
3
3
|
} from "../types/model.js";
|
|
4
4
|
export function createModelFactory(config, logger) {
|
|
5
5
|
function one(shape, options) {
|
|
6
|
+
let key = "";
|
|
6
7
|
return {
|
|
8
|
+
get key() {
|
|
9
|
+
return key;
|
|
10
|
+
},
|
|
11
|
+
setKey(value) {
|
|
12
|
+
key = value;
|
|
13
|
+
},
|
|
7
14
|
shape,
|
|
8
15
|
kind: ModelKind.OBJECT,
|
|
9
16
|
options: {
|
|
@@ -14,7 +21,14 @@ export function createModelFactory(config, logger) {
|
|
|
14
21
|
};
|
|
15
22
|
}
|
|
16
23
|
function many(shape, options) {
|
|
24
|
+
let key = "";
|
|
17
25
|
return {
|
|
26
|
+
get key() {
|
|
27
|
+
return key;
|
|
28
|
+
},
|
|
29
|
+
setKey(value) {
|
|
30
|
+
key = value;
|
|
31
|
+
},
|
|
18
32
|
shape,
|
|
19
33
|
kind: ModelKind.ARRAY,
|
|
20
34
|
options: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import type { ShapeFactory } from "../types/shape.js";
|
|
2
|
+
import type { ShapeFactory, ShapeRawDefinition } from "../types/shape.js";
|
|
3
3
|
export declare const primitiveField: {
|
|
4
4
|
string: typeof z.string;
|
|
5
5
|
number: typeof z.number;
|
|
@@ -42,4 +42,4 @@ export declare const specialField: {
|
|
|
42
42
|
nullable: typeof z.nullable;
|
|
43
43
|
optional: typeof z.optional;
|
|
44
44
|
};
|
|
45
|
-
export declare function shape<T extends
|
|
45
|
+
export declare function shape<T extends ShapeRawDefinition>(definition: T | ((factory: ShapeFactory) => T)): import("../types/shape").ShapeCall<T>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { createShape } from "../utils/shape.js";
|
|
2
3
|
export const primitiveField = {
|
|
3
4
|
string: z.string,
|
|
4
5
|
number: z.number,
|
|
@@ -43,7 +44,7 @@ export const specialField = {
|
|
|
43
44
|
};
|
|
44
45
|
export function shape(definition) {
|
|
45
46
|
if (typeof definition === "function") {
|
|
46
|
-
return
|
|
47
|
+
return createShape(
|
|
47
48
|
definition({
|
|
48
49
|
...primitiveField,
|
|
49
50
|
...structureField,
|
|
@@ -52,5 +53,5 @@ export function shape(definition) {
|
|
|
52
53
|
})
|
|
53
54
|
);
|
|
54
55
|
}
|
|
55
|
-
return
|
|
56
|
+
return createShape(definition);
|
|
56
57
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ConsolaInstance } from "consola";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ModelDefinitions } from "../types/model.js";
|
|
3
3
|
import type { RuntimeViewConfig, ViewFactory } from "../types/view.js";
|
|
4
|
-
export declare function createViewFactory<
|
|
4
|
+
export declare function createViewFactory<MD extends ModelDefinitions>(config?: RuntimeViewConfig, logger?: ConsolaInstance): ViewFactory<MD>;
|
|
@@ -1,16 +1,38 @@
|
|
|
1
|
-
export function createViewFactory(config, logger
|
|
2
|
-
function from(
|
|
1
|
+
export function createViewFactory(config, logger) {
|
|
2
|
+
function from(model, resolver, options) {
|
|
3
|
+
let key = "";
|
|
3
4
|
const definition = {
|
|
4
|
-
|
|
5
|
+
get key() {
|
|
6
|
+
return key;
|
|
7
|
+
},
|
|
8
|
+
setKey(value) {
|
|
9
|
+
key = value;
|
|
10
|
+
},
|
|
11
|
+
model: [model],
|
|
5
12
|
resolver,
|
|
13
|
+
options: {
|
|
14
|
+
clone: config?.clone,
|
|
15
|
+
...options
|
|
16
|
+
},
|
|
6
17
|
logger
|
|
7
18
|
};
|
|
8
19
|
return definition;
|
|
9
20
|
}
|
|
10
|
-
function merge(
|
|
21
|
+
function merge(models, resolver, options) {
|
|
22
|
+
let key = "";
|
|
11
23
|
return {
|
|
12
|
-
|
|
24
|
+
get key() {
|
|
25
|
+
return key;
|
|
26
|
+
},
|
|
27
|
+
setKey(value) {
|
|
28
|
+
key = value;
|
|
29
|
+
},
|
|
30
|
+
models,
|
|
13
31
|
resolver,
|
|
32
|
+
options: {
|
|
33
|
+
clone: config?.clone,
|
|
34
|
+
...options
|
|
35
|
+
},
|
|
14
36
|
logger
|
|
15
37
|
};
|
|
16
38
|
}
|
|
@@ -1,23 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import
|
|
5
|
-
export
|
|
6
|
-
export type StoreView<M extends Model, VD extends ViewDefinitions<M>> = {
|
|
7
|
-
readonly [K in keyof VD]: ComputedRef<ViewResult<M, VD[K]>>;
|
|
8
|
-
};
|
|
9
|
-
export type StoreAction<M extends Model, V, AD extends Record<string, ActionDefinition<M, V, unknown>>> = {
|
|
10
|
-
[K in keyof AD]: Action<V>;
|
|
11
|
-
};
|
|
12
|
-
export interface StoreConfig<M extends Model, VD extends ViewDefinitions<M>, _AD extends ActionDefinitions<M, StoreView<M, VD>>> {
|
|
13
|
-
name: string;
|
|
14
|
-
model: (factory: ModelFactory) => M;
|
|
15
|
-
view: (factory: ViewFactory<M>) => VD;
|
|
16
|
-
action: (factory: ActionFactory<M, StoreView<M, VD>>) => Record<string, ActionApiChain<M, StoreView<M, VD>, unknown> | ActionHandleChain<M, StoreView<M, VD>, unknown> | ActionCommitChain<M, StoreView<M, VD>, unknown>>;
|
|
17
|
-
}
|
|
18
|
-
export interface Store<M extends Model, VD extends ViewDefinitions<M>, AD extends ActionDefinitions<M, StoreView<M, VD>>> {
|
|
19
|
-
model: StoreModel<M>;
|
|
20
|
-
view: StoreView<M, VD>;
|
|
21
|
-
action: StoreAction<M, StoreView<M, VD>, AD>;
|
|
22
|
-
}
|
|
23
|
-
export declare function createStore<M extends Model, VD extends ViewDefinitions<M>, AD extends ActionDefinitions<M, StoreView<M, VD>>>(config: StoreConfig<M, VD, AD>): Store<M, VD, AD>;
|
|
1
|
+
import type { ModelDefinitions } from "./types/model.js";
|
|
2
|
+
import type { ViewDefinitions } from "./types/view.js";
|
|
3
|
+
import type { ActionDefinitions } from "./types/action.js";
|
|
4
|
+
import type { Store, StoreConfig } from "./types/store.js";
|
|
5
|
+
export declare function createStore<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>, AD extends ActionDefinitions<MD, VD>>(config: StoreConfig<MD, VD, AD>): Store<MD, VD, AD>;
|
|
@@ -1,28 +1,10 @@
|
|
|
1
1
|
import { createConsola } from "consola";
|
|
2
|
-
import { createStore as
|
|
2
|
+
import { createStore as createStoreSource } from "@harlem/core";
|
|
3
3
|
import { runtimeConfig } from "../config.js";
|
|
4
4
|
import { createModelFactory } from "./layers/model.js";
|
|
5
5
|
import { createViewFactory } from "./layers/view.js";
|
|
6
6
|
import { createActionFactory } from "./layers/action.js";
|
|
7
|
-
import {
|
|
8
|
-
import { createView } from "./utils/view.js";
|
|
9
|
-
import { createAction } from "./utils/action.js";
|
|
10
|
-
import {
|
|
11
|
-
DEFINITION
|
|
12
|
-
} from "./types/action.js";
|
|
13
|
-
function createStoreModel(mutations) {
|
|
14
|
-
return createCommitter(mutations);
|
|
15
|
-
}
|
|
16
|
-
function createStoreView(source, viewDefinitions) {
|
|
17
|
-
return createView(source, viewDefinitions);
|
|
18
|
-
}
|
|
19
|
-
function createStoreAction(actionDefinitions, view, mutations) {
|
|
20
|
-
const actions = {};
|
|
21
|
-
for (const [key, chain] of Object.entries(actionDefinitions)) {
|
|
22
|
-
actions[key] = createAction(chain[DEFINITION], mutations, view, key);
|
|
23
|
-
}
|
|
24
|
-
return actions;
|
|
25
|
-
}
|
|
7
|
+
import { createStoreState, createStoreModel, createStoreView, createStoreAction } from "./utils/store.js";
|
|
26
8
|
export function createStore(config) {
|
|
27
9
|
const logger = createConsola({
|
|
28
10
|
level: runtimeConfig.logger,
|
|
@@ -30,20 +12,18 @@ export function createStore(config) {
|
|
|
30
12
|
tag: `harlemify:${config.name}`
|
|
31
13
|
}
|
|
32
14
|
});
|
|
15
|
+
logger.info("Creating store");
|
|
33
16
|
const modelFactory = createModelFactory(runtimeConfig.model, logger);
|
|
34
17
|
const viewFactory = createViewFactory(runtimeConfig.view, logger);
|
|
35
18
|
const actionFactory = createActionFactory(runtimeConfig.action, logger);
|
|
36
|
-
logger.info("Creating store");
|
|
37
19
|
const modelDefinitions = config.model(modelFactory);
|
|
38
20
|
const viewDefinitions = config.view(viewFactory);
|
|
39
21
|
const actionDefinitions = config.action(actionFactory);
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const view = createStoreView(source, viewDefinitions);
|
|
46
|
-
const action = createStoreAction(actionDefinitions, view, mutations);
|
|
22
|
+
const state = createStoreState(modelDefinitions);
|
|
23
|
+
const source = createStoreSource(config.name, state);
|
|
24
|
+
const model = createStoreModel(modelDefinitions, source);
|
|
25
|
+
const view = createStoreView(viewDefinitions, source);
|
|
26
|
+
const action = createStoreAction(actionDefinitions, model, view);
|
|
47
27
|
logger.info("Store created");
|
|
48
28
|
return {
|
|
49
29
|
model,
|