@diphyx/harlemify 5.4.0 → 5.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 CHANGED
@@ -2,66 +2,40 @@
2
2
 
3
3
  > Factory-driven state management for Nuxt powered by [Harlem](https://harlemjs.com/)
4
4
 
5
- ![Version](https://img.shields.io/badge/version-5.3.0-42b883)
6
- ![License](https://img.shields.io/badge/license-MIT-blue)
7
-
8
5
  Define your data **shape** once with Zod — get typed **models**, computed **views**, and async **actions** with a single `createStore` call.
9
6
 
10
- Built on top of [Harlem](https://harlemjs.com/), a powerful and extensible state management library for Vue 3.
11
-
12
- ---
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
13
15
 
14
- ## The Problem
16
+ ## Install
15
17
 
16
- Every Nuxt app has the same boilerplate for every API resource:
18
+ ```bash
19
+ npm install @diphyx/harlemify
20
+ ```
17
21
 
18
22
  ```typescript
19
- // Without Harlemify — this gets written for EVERY resource
20
-
21
- // 1. Define types manually
22
- interface User {
23
- id: number;
24
- name: string;
25
- email: string;
26
- }
27
-
28
- // 2. Define state
29
- const users = ref<User[]>([]);
30
- const currentUser = ref<User | null>(null);
31
- const loading = ref(false);
32
- const error = ref<Error | null>(null);
33
-
34
- // 3. Write fetch logic
35
- async function fetchUsers() {
36
- loading.value = true;
37
- error.value = null;
38
- try {
39
- users.value = await $fetch("/api/users");
40
- } catch (e) {
41
- error.value = e as Error;
42
- } finally {
43
- loading.value = false;
44
- }
45
- }
46
-
47
- // 4. Repeat for create, update, delete...
48
- // 5. Repeat for every resource in your app...
23
+ // nuxt.config.ts
24
+ export default defineNuxtConfig({
25
+ modules: ["@diphyx/harlemify"],
26
+ });
49
27
  ```
50
28
 
51
- ## The Solution
52
-
53
- With Harlemify, define a data shape once and get everything else for free:
29
+ ## Usage
54
30
 
55
31
  ```typescript
56
- const userShape = shape((factory) => {
57
- return {
58
- id: factory.number().meta({
59
- identifier: true,
60
- }),
61
- name: factory.string(),
62
- email: factory.email(),
63
- };
64
- });
32
+ const userShape = shape((factory) => ({
33
+ id: factory.number().meta({
34
+ identifier: true,
35
+ }),
36
+ name: factory.string(),
37
+ email: factory.email(),
38
+ }));
65
39
 
66
40
  export const userStore = createStore({
67
41
  name: "users",
@@ -83,49 +57,27 @@ export const userStore = createStore({
83
57
  {
84
58
  url: "/users",
85
59
  },
86
- { model: "list", mode: ModelManyMode.SET },
87
- ),
88
- get: api.get(
89
- {
90
- url(view) {
91
- return `/users/${view.user.value?.id}`;
92
- },
93
- },
94
- { model: "current", mode: ModelOneMode.SET },
95
- ),
96
- create: api.post(
97
- {
98
- url: "/users",
99
- },
100
- { model: "list", mode: ModelManyMode.ADD },
101
- ),
102
- delete: api.delete(
103
60
  {
104
- url(view) {
105
- return `/users/${view.user.value?.id}`;
106
- },
61
+ model: "list",
62
+ mode: ModelManyMode.SET,
107
63
  },
108
- { model: "list", mode: ModelManyMode.REMOVE },
109
64
  ),
110
65
  };
111
66
  },
112
67
  });
113
68
  ```
114
69
 
115
- Use it in any component with built-in composables:
116
-
117
70
  ```vue
118
71
  <script setup>
119
- const { execute, loading, error } = useStoreAction(userStore, "list");
120
- const { data: users } = useStoreView(userStore, "users");
72
+ const { execute, loading } = useStoreAction(userStore, "list");
73
+ const { data } = useStoreView(userStore, "users");
121
74
 
122
75
  await execute();
123
76
  </script>
124
77
 
125
78
  <template>
126
- <p v-if="error">{{ error.message }}</p>
127
- <ul v-else-if="!loading">
128
- <li v-for="user in users" :key="user.id">{{ user.name }}</li>
79
+ <ul v-if="!loading">
80
+ <li v-for="user in data" :key="user.id">{{ user.name }}</li>
129
81
  </ul>
130
82
  </template>
131
83
  ```
@@ -142,14 +94,8 @@ await execute();
142
94
 
143
95
  ## Documentation
144
96
 
145
- Full docs with guides, API reference, and examples:
146
-
147
97
  [https://diphyx.github.io/harlemify/](https://diphyx.github.io/harlemify/)
148
98
 
149
- ## Contributing
150
-
151
- Contributions are welcome! Please open an issue first to discuss what you'd like to change.
152
-
153
99
  ## License
154
100
 
155
- [MIT](LICENSE)
101
+ MIT
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.14.0 || ^4.0.0"
6
6
  },
7
- "version": "5.4.0",
7
+ "version": "5.4.1",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "unknown"
@@ -6,27 +6,10 @@ export interface UseStoreViewTrackOptions {
6
6
  debounce?: number;
7
7
  throttle?: number;
8
8
  }
9
- export interface UseStoreViewOptions {
10
- proxy?: boolean;
11
- }
12
- export type UseStoreViewData<T> = {
13
- value: T;
14
- } & (T extends Record<string, unknown> ? {
15
- [K in keyof T]: T[K];
16
- } : Record<string, unknown>);
17
- export type UseStoreViewProxy<T> = {
18
- data: UseStoreViewData<T>;
19
- track: (handler: (value: T) => void, options?: UseStoreViewTrackOptions) => WatchStopHandle;
20
- };
21
- export type UseStoreViewComputed<T> = {
9
+ export type UseStoreView<T> = {
22
10
  data: ComputedRef<T>;
23
11
  track: (handler: (value: T) => void, options?: UseStoreViewTrackOptions) => WatchStopHandle;
24
12
  };
25
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: {
26
14
  view: V;
27
- }, key: K, options: UseStoreViewOptions & {
28
- proxy: false;
29
- }): UseStoreViewComputed<T>;
30
- export declare function useStoreView<V extends Record<string, ViewCall>, K extends keyof V & string, T = V[K] extends ComputedRef<infer R> ? R : unknown>(store: {
31
- view: V;
32
- }, key: K, options?: UseStoreViewOptions): UseStoreViewProxy<T>;
15
+ }, key: K): UseStoreView<T>;
@@ -1,17 +1,11 @@
1
1
  import { watch } from "vue";
2
- import { debounce, throttle, toReactiveProxy } from "../core/utils/base.js";
3
- function resolveData(source, proxy) {
4
- if (proxy !== false) {
5
- return toReactiveProxy(source);
6
- }
7
- return source;
8
- }
9
- export function useStoreView(store, key, options) {
2
+ import { debounce, throttle } from "../core/utils/base.js";
3
+ export function useStoreView(store, key) {
10
4
  if (!store.view[key]) {
11
5
  throw new Error(`View "${key}" not found in store`);
12
6
  }
13
7
  const source = store.view[key];
14
- const data = resolveData(source, options?.proxy);
8
+ const data = source;
15
9
  function resolveCallback(callback, callbackOptions) {
16
10
  if (callbackOptions?.debounce) {
17
11
  return debounce(callback, callbackOptions.debounce);
@@ -6,12 +6,5 @@ export declare function ensureArray<T>(value: T | T[]): T[];
6
6
  export declare function isObject(value: unknown): value is object;
7
7
  export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
8
8
  export declare function isEmptyRecord(record: Record<string, unknown> | undefined): record is undefined;
9
- type ReferenceProxy<T> = {
10
- value: T;
11
- } & Record<string | symbol, unknown>;
12
- export declare function toReactiveProxy<T>(reference: {
13
- value: T;
14
- }): ReferenceProxy<T>;
15
9
  export declare function debounce<T extends (...args: any[]) => any>(callback: T, delay: number): T;
16
10
  export declare function throttle<T extends (...args: any[]) => any>(callback: T, delay: number): T;
17
- export {};
@@ -43,51 +43,6 @@ export function isEmptyRecord(record) {
43
43
  }
44
44
  return false;
45
45
  }
46
- export function toReactiveProxy(reference) {
47
- function get(_target, prop) {
48
- if (prop === "value") {
49
- return reference.value;
50
- }
51
- if (!isObject(reference.value)) {
52
- return void 0;
53
- }
54
- return reference.value[prop];
55
- }
56
- function has(_target, prop) {
57
- if (prop === "value") {
58
- return true;
59
- }
60
- if (!isObject(reference.value)) {
61
- return false;
62
- }
63
- return prop in reference.value;
64
- }
65
- function ownKeys() {
66
- if (!isObject(reference.value)) {
67
- return [];
68
- }
69
- return Reflect.ownKeys(reference.value);
70
- }
71
- function getOwnPropertyDescriptor(_target, prop) {
72
- if (!isObject(reference.value) || !(prop in reference.value)) {
73
- return void 0;
74
- }
75
- return {
76
- configurable: true,
77
- enumerable: true,
78
- value: reference.value[prop]
79
- };
80
- }
81
- return new Proxy(
82
- {},
83
- {
84
- get,
85
- has,
86
- ownKeys,
87
- getOwnPropertyDescriptor
88
- }
89
- );
90
- }
91
46
  export function debounce(callback, delay) {
92
47
  let timer = null;
93
48
  return (...args) => {
@@ -17,5 +17,5 @@ export type { UseStoreActionOptions, UseStoreAction } from "./composables/action
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";
20
- export type { UseStoreViewOptions, UseStoreViewProxy, UseStoreViewComputed, UseStoreViewData, UseStoreViewTrackOptions, } from "./composables/view.js";
20
+ export type { UseStoreView, UseStoreViewTrackOptions } from "./composables/view.js";
21
21
  export type { RuntimeConfig } from "./config.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diphyx/harlemify",
3
- "version": "5.4.0",
3
+ "version": "5.4.1",
4
4
  "description": "API state management for Nuxt powered by Harlem",
5
5
  "keywords": [
6
6
  "nuxt",