@diphyx/harlemify 0.0.3 → 1.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Amir Reza Dalir
3
+ Copyright (c) 2026 DiPhyx
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,19 +1,18 @@
1
1
  # Harlemify
2
2
 
3
- API state management for Nuxt powered by [Harlem](https://harlemjs.com/)
3
+ > Schema-driven state management for Nuxt powered by [Harlem](https://harlemjs.com/)
4
4
 
5
5
  ![Harlemify](https://raw.githubusercontent.com/diphyx/harlemify/main/docs/_media/icon.svg)
6
6
 
7
+ Define your data schema once with Zod, and Harlemify handles the rest: type-safe API calls, reactive state, request monitoring, and automatic memory management. Your schema becomes the single source of truth for types, validation, and API payloads.
8
+
7
9
  ## Features
8
10
 
9
- - Zod schema validation with field metadata
10
- - Automatic API client with runtime config
11
- - CRUD operations with endpoint status tracking
12
- - Type-safe endpoint URL parameters
13
- - SSR support via Harlem SSR plugin
14
- - Configurable primary key indicator
15
- - Lifecycle hooks (before/after) for API operations
16
- - Abort controller support for request cancellation
11
+ - **Schema-Driven** - Zod schema defines types, validation, and API payloads
12
+ - **Automatic API Client** - Built-in HTTP client with runtime configuration
13
+ - **Reactive Memory** - Unit and collection caching with Vue reactivity
14
+ - **Request Monitoring** - Track pending, success, and failed states
15
+ - **SSR Support** - Server-side rendering via Harlem SSR plugin
17
16
 
18
17
  ## Installation
19
18
 
@@ -37,58 +36,35 @@ export default defineNuxtConfig({
37
36
 
38
37
  ```typescript
39
38
  // stores/user.ts
40
- import { z, createStore, Endpoint, ApiAction } from "@diphyx/harlemify";
39
+ import { z } from "zod";
40
+ import { createStore, Endpoint, EndpointMethod } from "@diphyx/harlemify";
41
41
 
42
42
  const UserSchema = z.object({
43
- id: z.number().meta({
44
- indicator: true,
45
- }),
43
+ id: z.number().meta({ indicator: true }),
46
44
  name: z.string().meta({
47
- actions: [ApiAction.POST, ApiAction.PATCH],
45
+ methods: [EndpointMethod.POST, EndpointMethod.PATCH],
48
46
  }),
49
47
  });
50
48
 
51
49
  export type User = z.infer<typeof UserSchema>;
52
50
 
53
- export const userStore = createStore(
54
- "user",
55
- UserSchema,
56
- {
57
- [Endpoint.GET_UNITS]: {
58
- action: ApiAction.GET,
59
- url: "/users",
60
- },
61
- [Endpoint.POST_UNITS]: {
62
- action: ApiAction.POST,
63
- url: "/users",
64
- },
65
- [Endpoint.PATCH_UNITS]: {
66
- action: ApiAction.PATCH,
67
- url: (params) => `/users/${params.id}`,
68
- },
69
- [Endpoint.DELETE_UNITS]: {
70
- action: ApiAction.DELETE,
71
- url: (params) => `/users/${params.id}`,
72
- },
73
- },
74
- {
75
- indicator: "id",
76
- hooks: {
77
- before() {
78
- console.log("Request starting...");
79
- },
80
- after(error) {
81
- if (error) {
82
- console.error("Request failed:", error);
83
- } else {
84
- console.log("Request completed");
85
- }
86
- },
87
- },
88
- },
89
- );
51
+ export const userStore = createStore("user", UserSchema, {
52
+ [Endpoint.GET_UNITS]: { method: EndpointMethod.GET, url: "/users" },
53
+ [Endpoint.POST_UNITS]: { method: EndpointMethod.POST, url: "/users" },
54
+ [Endpoint.PATCH_UNITS]: { method: EndpointMethod.PATCH, url: (p) => `/users/${p.id}` },
55
+ [Endpoint.DELETE_UNITS]: { method: EndpointMethod.DELETE, url: (p) => `/users/${p.id}` },
56
+ });
90
57
  ```
91
58
 
59
+ ## Why Harlemify?
60
+
61
+ | | |
62
+ | --------------- | ------------------------------------------------- |
63
+ | **Type-Safe** | Full TypeScript support with Zod schema inference |
64
+ | **Declarative** | Define schema once, derive everything else |
65
+ | **Reactive** | Powered by Vue's reactivity through Harlem |
66
+ | **Simple** | Minimal boilerplate, maximum productivity |
67
+
92
68
  ## Documentation
93
69
 
94
70
  Full documentation available at [https://diphyx.github.io/harlemify/](https://diphyx.github.io/harlemify/)
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.0.0 || >=4.0.0"
6
6
  },
7
- "version": "0.0.3",
7
+ "version": "1.0.0",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -15,6 +15,8 @@ const module = defineNuxtModule({
15
15
  const { resolve } = createResolver(import.meta.url);
16
16
  addPlugin(resolve("./runtime", "plugin"));
17
17
  addImportsDir(resolve("./runtime", "core"));
18
+ addImportsDir(resolve("./runtime", "composables"));
19
+ addImportsDir(resolve("./runtime", "utils"));
18
20
  updateRuntimeConfig({
19
21
  public: {
20
22
  harlemify: options
@@ -0,0 +1,30 @@
1
+ import type { ComputedRef } from "vue";
2
+ import { EndpointMethod } from "../utils/endpoint.js";
3
+ import type { Store } from "../core/store.js";
4
+ import type { Pluralize, Capitalize } from "../utils/transform.js";
5
+ import type { EndpointStatusFlag } from "../utils/endpoint.js";
6
+ type Indicator<T, I extends keyof T> = Required<Pick<T, I>>;
7
+ type PartialWithIndicator<T, I extends keyof T> = Indicator<T, I> & Partial<T>;
8
+ type MemoryState<E extends string, T> = {
9
+ [P in E]: ComputedRef<T | null>;
10
+ } & {
11
+ [P in Pluralize<E>]: ComputedRef<T[]>;
12
+ };
13
+ type MemoryAction<A extends string, E extends string, U> = {
14
+ [K in `${A}${Capitalize<E>}`]: (unit: U) => void;
15
+ } & {
16
+ [K in `${A}${Capitalize<Pluralize<E>>}`]: (units: U[]) => void;
17
+ };
18
+ type EndpointAction<E extends string, T> = {
19
+ [M in EndpointMethod as `${M}${Capitalize<E>}`]: (unit?: Partial<T>) => Promise<T>;
20
+ } & {
21
+ [M in EndpointMethod as `${M}${Capitalize<Pluralize<E>>}`]: (units?: Partial<T>[]) => Promise<T[]>;
22
+ };
23
+ type EndpointMonitor<E extends string> = {
24
+ [M in EndpointMethod as `${M}${Capitalize<E>}${EndpointStatusFlag}`]: ComputedRef<boolean>;
25
+ } & {
26
+ [M in EndpointMethod as `${M}${Capitalize<Pluralize<E>>}${EndpointStatusFlag}`]: ComputedRef<boolean>;
27
+ };
28
+ type StoreAlias<E extends string, T, I extends keyof T = keyof T> = MemoryState<E, T> & MemoryAction<"set", E, T | null> & MemoryAction<"edit", E, PartialWithIndicator<T, I>> & MemoryAction<"drop", E, PartialWithIndicator<T, I>> & EndpointAction<E, T> & EndpointMonitor<E>;
29
+ export declare function useStoreAlias<E extends string, T, I extends keyof T = keyof T>(store: Store<E, T, I>): StoreAlias<E, T, I>;
30
+ export {};
@@ -0,0 +1,25 @@
1
+ import { capitalize } from "../utils/transform.js";
2
+ import { EndpointMethod, EndpointStatus, makeEndpointStatusFlag } from "../utils/endpoint.js";
3
+ import { StoreMemoryAction } from "../core/store.js";
4
+ export function useStoreAlias(store) {
5
+ const capitalizedUnit = capitalize(store.alias.unit);
6
+ const capitalizedUnits = capitalize(store.alias.units);
7
+ const output = {
8
+ [store.alias.unit]: store.unit,
9
+ [store.alias.units]: store.units
10
+ };
11
+ for (const action of Object.values(StoreMemoryAction)) {
12
+ output[`${action}${capitalizedUnit}`] = store.memory[`${action}Unit`];
13
+ output[`${action}${capitalizedUnits}`] = store.memory[`${action}Units`];
14
+ }
15
+ for (const method of Object.values(EndpointMethod)) {
16
+ output[`${method}${capitalizedUnit}`] = store.endpoint[`${method}Unit`];
17
+ output[`${method}${capitalizedUnits}`] = store.endpoint[`${method}Units`];
18
+ for (const status of Object.values(EndpointStatus)) {
19
+ const statusFlag = makeEndpointStatusFlag(status);
20
+ output[`${method}${capitalizedUnit}${statusFlag}`] = store.monitor[`${method}Unit${statusFlag}`];
21
+ output[`${method}${capitalizedUnits}${statusFlag}`] = store.monitor[`${method}Units${statusFlag}`];
22
+ }
23
+ }
24
+ return output;
25
+ }
@@ -1,11 +1,5 @@
1
- import { type MaybeRefOrGetter } from "vue";
2
- export declare enum ApiAction {
3
- GET = "get",
4
- POST = "post",
5
- PUT = "put",
6
- PATCH = "patch",
7
- DELETE = "delete"
8
- }
1
+ import type { MaybeRefOrGetter } from "vue";
2
+ import { EndpointMethod } from "../utils/endpoint.js";
9
3
  export declare enum ApiResponseType {
10
4
  JSON = "json",
11
5
  TEXT = "text",
@@ -19,7 +13,7 @@ export declare enum ApiErrorSource {
19
13
  export type ApiRequestHeader = MaybeRefOrGetter<Record<string, unknown>>;
20
14
  export type ApiRequestQuery = MaybeRefOrGetter<Record<string, unknown>>;
21
15
  export type ApiRequestBody = MaybeRefOrGetter<string | number | ArrayBuffer | FormData | Blob | Record<string, any>>;
22
- export interface ApiRequestOptions<A extends ApiAction = ApiAction, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery, B extends ApiRequestBody = ApiRequestBody> {
16
+ export interface ApiRequestOptions<A extends EndpointMethod = EndpointMethod, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery, B extends ApiRequestBody = ApiRequestBody> {
23
17
  action?: A;
24
18
  headers?: H;
25
19
  query?: Q;
@@ -37,7 +31,7 @@ export interface ApiOptions {
37
31
  query?: ApiRequestQuery;
38
32
  timeout?: number;
39
33
  }
40
- export type ApiActionOptions<A extends ApiAction, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery, B extends ApiRequestBody = ApiRequestBody> = Omit<ApiRequestOptions<A, H, Q, B>, "action">;
34
+ export type EndpointMethodOptions<A extends EndpointMethod, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery, B extends ApiRequestBody = ApiRequestBody> = Omit<ApiRequestOptions<A, H, Q, B>, "action">;
41
35
  export interface ApiErrorOptions {
42
36
  source: ApiErrorSource;
43
37
  method: string;
@@ -56,10 +50,11 @@ export declare class ApiRequestError extends ApiError {
56
50
  export declare class ApiResponseError extends ApiError {
57
51
  constructor(options: Omit<ApiErrorOptions, "source">);
58
52
  }
59
- export declare function createApi(options?: ApiOptions): {
60
- get: <T, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery>(url: string, options?: ApiActionOptions<ApiAction.GET, H, Q, never>) => Promise<T>;
61
- post: <T, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery, B extends ApiRequestBody = ApiRequestBody>(url: string, options?: ApiActionOptions<ApiAction.POST, H, Q, B>) => Promise<T>;
62
- put: <T, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery, B extends ApiRequestBody = ApiRequestBody>(url: string, options?: ApiActionOptions<ApiAction.PUT, H, Q, B>) => Promise<T>;
63
- patch: <T, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery, B extends ApiRequestBody = ApiRequestBody>(url: string, options?: ApiActionOptions<ApiAction.PATCH, H, Q, B>) => Promise<T>;
64
- del: <T, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery>(url: string, options?: ApiActionOptions<ApiAction.DELETE, H, Q, never>) => Promise<T>;
65
- };
53
+ export interface Api {
54
+ get: <T, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery>(url: string, options?: EndpointMethodOptions<EndpointMethod.GET, H, Q, never>) => Promise<T>;
55
+ post: <T, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery, B extends ApiRequestBody = ApiRequestBody>(url: string, options?: EndpointMethodOptions<EndpointMethod.POST, H, Q, B>) => Promise<T>;
56
+ put: <T, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery, B extends ApiRequestBody = ApiRequestBody>(url: string, options?: EndpointMethodOptions<EndpointMethod.PUT, H, Q, B>) => Promise<T>;
57
+ patch: <T, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery, B extends ApiRequestBody = ApiRequestBody>(url: string, options?: EndpointMethodOptions<EndpointMethod.PATCH, H, Q, B>) => Promise<T>;
58
+ del: <T, H extends ApiRequestHeader = ApiRequestHeader, Q extends ApiRequestQuery = ApiRequestQuery>(url: string, options?: EndpointMethodOptions<EndpointMethod.DELETE, H, Q, never>) => Promise<T>;
59
+ }
60
+ export declare function createApi(options?: ApiOptions): Api;
@@ -1,12 +1,5 @@
1
1
  import { toValue } from "vue";
2
- export var ApiAction = /* @__PURE__ */ ((ApiAction2) => {
3
- ApiAction2["GET"] = "get";
4
- ApiAction2["POST"] = "post";
5
- ApiAction2["PUT"] = "put";
6
- ApiAction2["PATCH"] = "patch";
7
- ApiAction2["DELETE"] = "delete";
8
- return ApiAction2;
9
- })(ApiAction || {});
2
+ import { EndpointMethod } from "../utils/endpoint.js";
10
3
  export var ApiResponseType = /* @__PURE__ */ ((ApiResponseType2) => {
11
4
  ApiResponseType2["JSON"] = "json";
12
5
  ApiResponseType2["TEXT"] = "text";
@@ -24,7 +17,7 @@ export class ApiError extends Error {
24
17
  method;
25
18
  url;
26
19
  constructor(options) {
27
- super(options.message || "Unknown error");
20
+ super(options.message ?? "Unknown error");
28
21
  this.name = "ApiError";
29
22
  this.source = options.source;
30
23
  this.method = options.method;
@@ -51,7 +44,7 @@ export function createApi(options) {
51
44
  async function request(url, requestOptions) {
52
45
  return $fetch(url, {
53
46
  baseURL: options?.url,
54
- method: requestOptions?.action ?? "get" /* GET */,
47
+ method: requestOptions?.action ?? EndpointMethod.GET,
55
48
  headers: {
56
49
  ...toValue(options?.headers),
57
50
  ...toValue(requestOptions?.headers)
@@ -86,31 +79,31 @@ export function createApi(options) {
86
79
  async function get(url, options2) {
87
80
  return request(url, {
88
81
  ...options2,
89
- action: "get" /* GET */
82
+ action: EndpointMethod.GET
90
83
  });
91
84
  }
92
85
  async function post(url, options2) {
93
86
  return request(url, {
94
87
  ...options2,
95
- action: "post" /* POST */
88
+ action: EndpointMethod.POST
96
89
  });
97
90
  }
98
91
  async function put(url, options2) {
99
92
  return request(url, {
100
93
  ...options2,
101
- action: "put" /* PUT */
94
+ action: EndpointMethod.PUT
102
95
  });
103
96
  }
104
97
  async function patch(url, options2) {
105
98
  return request(url, {
106
99
  ...options2,
107
- action: "patch" /* PATCH */
100
+ action: EndpointMethod.PATCH
108
101
  });
109
102
  }
110
103
  async function del(url, options2) {
111
104
  return request(url, {
112
105
  ...options2,
113
- action: "delete" /* DELETE */
106
+ action: EndpointMethod.DELETE
114
107
  });
115
108
  }
116
109
  return {
@@ -1,14 +1,19 @@
1
- import { z } from "zod";
2
- import { type Extension, type BaseState } from "@harlem/core";
3
- import { Endpoint, type EndpointDefinition, type EndpointMemory } from "../utils/endpoint.js";
1
+ import type { z } from "zod";
2
+ import type { ComputedRef } from "vue";
3
+ import type { Extension, BaseState } from "@harlem/core";
4
+ import { Endpoint, EndpointStatus } from "../utils/endpoint.js";
5
+ import type { EndpointMethodOptions, ApiOptions } from "./api.js";
6
+ import type { EndpointDefinition, EndpointStatusName } from "../utils/endpoint.js";
7
+ import type { Pluralize } from "../utils/transform.js";
8
+ export declare enum StoreMemoryAction {
9
+ SET = "set",
10
+ EDIT = "edit",
11
+ DROP = "drop"
12
+ }
4
13
  export declare enum StoreMemoryPosition {
5
14
  FIRST = "first",
6
15
  LAST = "last"
7
16
  }
8
- import { ApiAction, type ApiActionOptions, type ApiOptions } from "./api.js";
9
- export declare class StoreConfigurationError extends Error {
10
- constructor(message: string);
11
- }
12
17
  export interface StoreHooks {
13
18
  before?: () => Promise<void> | void;
14
19
  after?: (error?: Error) => Promise<void> | void;
@@ -19,57 +24,51 @@ export interface StoreOptions {
19
24
  hooks?: StoreHooks;
20
25
  extensions?: Extension<BaseState>[];
21
26
  }
22
- export declare function createStore<T extends z.ZodRawShape, K extends keyof z.infer<z.ZodObject<T>> = "id" & keyof z.infer<z.ZodObject<T>>>(name: string, schema: z.ZodObject<T>, endpoints?: Partial<Record<Endpoint, EndpointDefinition<Partial<z.infer<z.ZodObject<T>>>>>>, options?: StoreOptions): {
23
- api: () => {
24
- get: <T_1, H extends import("./api").ApiRequestHeader = import("./api").ApiRequestHeader, Q extends import("./api").ApiRequestQuery = import("./api").ApiRequestQuery>(url: string, options?: ApiActionOptions<ApiAction.GET, H, Q, never>) => Promise<T_1>;
25
- post: <T_1, H extends import("./api").ApiRequestHeader = import("./api").ApiRequestHeader, Q extends import("./api").ApiRequestQuery = import("./api").ApiRequestQuery, B extends import("./api").ApiRequestBody = import("./api").ApiRequestBody>(url: string, options?: ApiActionOptions<ApiAction.POST, H, Q, B>) => Promise<T_1>;
26
- put: <T_1, H extends import("./api").ApiRequestHeader = import("./api").ApiRequestHeader, Q extends import("./api").ApiRequestQuery = import("./api").ApiRequestQuery, B extends import("./api").ApiRequestBody = import("./api").ApiRequestBody>(url: string, options?: ApiActionOptions<ApiAction.PUT, H, Q, B>) => Promise<T_1>;
27
- patch: <T_1, H extends import("./api").ApiRequestHeader = import("./api").ApiRequestHeader, Q extends import("./api").ApiRequestQuery = import("./api").ApiRequestQuery, B extends import("./api").ApiRequestBody = import("./api").ApiRequestBody>(url: string, options?: ApiActionOptions<ApiAction.PATCH, H, Q, B>) => Promise<T_1>;
28
- del: <T_1, H extends import("./api").ApiRequestHeader = import("./api").ApiRequestHeader, Q extends import("./api").ApiRequestQuery = import("./api").ApiRequestQuery>(url: string, options?: ApiActionOptions<ApiAction.DELETE, H, Q, never>) => Promise<T_1>;
27
+ type Indicator<T, I extends keyof T> = Required<Pick<T, I>>;
28
+ type WithIndicator<T, I extends keyof T> = Indicator<T, I> & T;
29
+ type PartialWithIndicator<T, I extends keyof T> = Indicator<T, I> & Partial<T>;
30
+ type StoreEndpointReadOptions = Omit<EndpointMethodOptions<any>, "body">;
31
+ type StoreEndpointWriteOptions = EndpointMethodOptions<any> & {
32
+ validate?: boolean;
33
+ };
34
+ type StoreEndpointWriteMultipleOptions = StoreEndpointWriteOptions & {
35
+ position?: StoreMemoryPosition;
36
+ };
37
+ type StoreMemory<T = unknown, I extends keyof T = keyof T> = {
38
+ setUnit: (unit: T | null) => void;
39
+ setUnits: (units: T[]) => void;
40
+ editUnit: (unit: PartialWithIndicator<T, I>) => void;
41
+ editUnits: (units: PartialWithIndicator<T, I>[]) => void;
42
+ dropUnit: (unit: PartialWithIndicator<T, I>) => void;
43
+ dropUnits: (units: PartialWithIndicator<T, I>[]) => void;
44
+ };
45
+ type StoreEndpoint<T = unknown, I extends keyof T = keyof T> = {
46
+ getUnit: (unit?: PartialWithIndicator<T, I>, options?: StoreEndpointReadOptions) => Promise<T>;
47
+ getUnits: (options?: StoreEndpointReadOptions) => Promise<T[]>;
48
+ postUnit: (unit: WithIndicator<T, I>, options?: StoreEndpointWriteOptions) => Promise<T>;
49
+ postUnits: (units: WithIndicator<T, I>[], options?: StoreEndpointWriteMultipleOptions) => Promise<T[]>;
50
+ putUnit: (unit: WithIndicator<T, I>, options?: StoreEndpointWriteOptions) => Promise<T>;
51
+ putUnits: (units: WithIndicator<T, I>[], options?: StoreEndpointWriteOptions) => Promise<T[]>;
52
+ patchUnit: (unit: PartialWithIndicator<T, I>, options?: StoreEndpointWriteOptions) => Promise<Partial<T>>;
53
+ patchUnits: (units: PartialWithIndicator<T, I>[], options?: StoreEndpointWriteOptions) => Promise<Partial<T>[]>;
54
+ deleteUnit: (unit: PartialWithIndicator<T, I>, options?: StoreEndpointReadOptions) => Promise<boolean>;
55
+ deleteUnits: (units: PartialWithIndicator<T, I>[], options?: StoreEndpointReadOptions) => Promise<boolean>;
56
+ };
57
+ type StoreMonitor = {
58
+ [K in Endpoint as EndpointStatusName<K, EndpointStatus>]: ComputedRef<boolean>;
59
+ };
60
+ export type Store<E extends string = string, T = unknown, I extends keyof T = keyof T> = {
61
+ store: any;
62
+ alias: {
63
+ unit: E;
64
+ units: Pluralize<E>;
29
65
  };
30
- store: Omit<import("@harlem/core").Store<{
31
- memory: {
32
- unit: z.core.$InferObjectOutput<T, {}> | null;
33
- units: z.core.$InferObjectOutput<T, {}>[];
34
- };
35
- endpoints: Record<Endpoint, EndpointMemory>;
36
- }>, never>;
37
- memorizedUnit: import("vue").ComputedRef<import("vue").DeepReadonly<z.core.$InferObjectOutput<T, {}>> | null>;
38
- memorizedUnits: import("vue").ComputedRef<readonly import("vue").DeepReadonly<z.core.$InferObjectOutput<T, {}>>[]>;
39
- hasMemorizedUnits: (...units: (Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>)[]) => Record<string | number, boolean>;
40
- endpointsStatus: import("../utils/endpoint").EndpointsStatusMap<import("vue").ComputedRef<boolean>>;
41
- setMemorizedUnit: import("@harlem/core").Mutation<z.core.$InferObjectOutput<T, {}> | null, void>;
42
- setMemorizedUnits: (payload: z.core.$InferObjectOutput<T, {}>[]) => void;
43
- editMemorizedUnit: import("@harlem/core").Mutation<Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>, void>;
44
- editMemorizedUnits: (payload: (Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>)[]) => void;
45
- dropMemorizedUnit: import("@harlem/core").Mutation<Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>, void>;
46
- dropMemorizedUnits: (payload: (Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>)[]) => void;
47
- patchEndpointMemory: (payload: {
48
- key: Endpoint;
49
- memory: EndpointMemory;
50
- }) => void;
51
- purgeEndpointMemory: (payload?: unknown) => void;
52
- getUnit: (unit?: Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>, options?: Omit<ApiActionOptions<ApiAction.GET>, "body">) => Promise<z.core.$InferObjectOutput<T, {}>>;
53
- getUnits: (options?: Omit<ApiActionOptions<ApiAction.GET>, "body">) => Promise<z.core.$InferObjectOutput<T, {}>[]>;
54
- postUnit: (unit: Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>, actionOptions?: ApiActionOptions<ApiAction.POST> & {
55
- validate?: boolean;
56
- }) => Promise<Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>>;
57
- postUnits: (units: (Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>)[], options?: ApiActionOptions<ApiAction.POST> & {
58
- validate?: boolean;
59
- position?: StoreMemoryPosition;
60
- }) => Promise<(Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>)[]>;
61
- putUnit: (unit: Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>, options?: ApiActionOptions<ApiAction.PUT> & {
62
- validate?: boolean;
63
- }) => Promise<Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>>;
64
- putUnits: (units: (Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>)[], options?: ApiActionOptions<ApiAction.PUT> & {
65
- validate?: boolean;
66
- }) => Promise<(Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>)[]>;
67
- patchUnit: (unit: Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>, options?: ApiActionOptions<ApiAction.PATCH> & {
68
- validate?: boolean;
69
- }) => Promise<Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>>;
70
- patchUnits: (units: (Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>)[], options?: ApiActionOptions<ApiAction.PATCH> & {
71
- validate?: boolean;
72
- }) => Promise<(Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>)[]>;
73
- deleteUnit: (unit: Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>, options?: Omit<ApiActionOptions<ApiAction.DELETE>, "body">) => Promise<boolean>;
74
- deleteUnits: (units: (Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>)[], options?: Omit<ApiActionOptions<ApiAction.DELETE>, "body">) => Promise<boolean>;
66
+ indicator: I;
67
+ unit: ComputedRef<T | null>;
68
+ units: ComputedRef<T[]>;
69
+ memory: StoreMemory<T, I>;
70
+ endpoint: StoreEndpoint<T, I>;
71
+ monitor: StoreMonitor;
75
72
  };
73
+ export declare function createStore<E extends string, T extends z.ZodRawShape, S extends z.infer<z.ZodObject<T>> = z.infer<z.ZodObject<T>>, I extends keyof S = "id" & keyof S>(entity: E, schema: z.ZodObject<T>, endpoints?: Partial<Record<Endpoint, EndpointDefinition<Partial<S>>>>, options?: StoreOptions): Store<E, S, I>;
74
+ export {};
@@ -1,277 +1,181 @@
1
1
  import { defu } from "defu";
2
- import {
3
- createStore as createHarlemStore
4
- } from "@harlem/core";
2
+ import { createStore as createHarlemStore } from "@harlem/core";
3
+ import { createApi } from "./api.js";
5
4
  import { resolveSchema } from "../utils/schema.js";
6
- import {
7
- makeEndpointStatusKey,
8
- getEndpoint,
9
- resolveEndpointUrl,
10
- makeEndpointsStatus,
11
- Endpoint,
12
- EndpointStatus
13
- } from "../utils/endpoint.js";
5
+ import { pluralize } from "../utils/transform.js";
6
+ import { Endpoint, EndpointStatus, getEndpoint, makeEndpointStatusName, resolveEndpointUrl } from "../utils/endpoint.js";
7
+ export var StoreMemoryAction = /* @__PURE__ */ ((StoreMemoryAction2) => {
8
+ StoreMemoryAction2["SET"] = "set";
9
+ StoreMemoryAction2["EDIT"] = "edit";
10
+ StoreMemoryAction2["DROP"] = "drop";
11
+ return StoreMemoryAction2;
12
+ })(StoreMemoryAction || {});
14
13
  export var StoreMemoryPosition = /* @__PURE__ */ ((StoreMemoryPosition2) => {
15
14
  StoreMemoryPosition2["FIRST"] = "first";
16
15
  StoreMemoryPosition2["LAST"] = "last";
17
16
  return StoreMemoryPosition2;
18
17
  })(StoreMemoryPosition || {});
19
- import {
20
- createApi
21
- } from "./api.js";
22
- export class StoreConfigurationError extends Error {
23
- constructor(message) {
24
- super(message);
25
- this.name = "StoreConfigurationError";
26
- }
27
- }
28
- export function createStore(name, schema, endpoints, options) {
18
+ export function createStore(entity, schema, endpoints, options) {
29
19
  const { indicator } = resolveSchema(schema, {
30
20
  indicator: options?.indicator
31
21
  });
32
- const hooks = options?.hooks;
33
22
  let apiClient;
34
- let apiInitError = null;
35
23
  function api() {
36
- if (apiInitError) {
37
- throw apiInitError;
38
- }
39
24
  if (!apiClient) {
40
- try {
41
- const config = useRuntimeConfig();
42
- if (!config) {
43
- throw new StoreConfigurationError(
44
- `Runtime config is not available. Ensure the store "${name}" is used within a Nuxt context.`
45
- );
46
- }
47
- apiClient = createApi({
48
- ...config.public.harlemify?.api,
49
- ...options?.api
50
- });
51
- } catch (error) {
52
- apiInitError = error instanceof Error ? error : new StoreConfigurationError(
53
- `Failed to initialize API client for store "${name}": ${String(error)}`
54
- );
55
- throw apiInitError;
56
- }
25
+ const config = useRuntimeConfig();
26
+ apiClient = createApi({
27
+ ...config.public.harlemify?.api ?? {},
28
+ ...options?.api
29
+ });
57
30
  }
58
31
  return apiClient;
59
32
  }
60
- const store = createHarlemStore(
61
- name,
62
- {
63
- memory: {
64
- unit: null,
65
- units: []
66
- },
67
- endpoints: {}
33
+ const state = {
34
+ memory: {
35
+ unit: null,
36
+ units: []
68
37
  },
69
- {
70
- extensions: options?.extensions ?? []
71
- }
72
- );
73
- const memorizedUnit = store.getter("memorizedUnit", (state) => {
74
- return state.memory.unit;
38
+ endpoints: {}
39
+ };
40
+ const store = createHarlemStore(entity, state, {
41
+ extensions: options?.extensions ?? []
42
+ });
43
+ const alias = {
44
+ unit: entity,
45
+ units: pluralize(entity)
46
+ };
47
+ const memorizedUnit = store.getter("memorizedUnit", (state2) => {
48
+ return state2.memory.unit;
49
+ });
50
+ const memorizedUnits = store.getter("memorizedUnits", (state2) => {
51
+ return state2.memory.units;
75
52
  });
76
- const memorizedUnits = store.getter("memorizedUnits", (state) => {
77
- return state.memory.units;
53
+ const setMemorizedUnit = store.mutation("setMemorizedUnit", (state2, unit = null) => {
54
+ state2.memory.unit = unit;
78
55
  });
79
- function hasMemorizedUnits(...units) {
80
- const output = {};
56
+ const setMemorizedUnits = store.mutation("setMemorizedUnits", (state2, units = []) => {
57
+ state2.memory.units = units;
58
+ });
59
+ const editMemorizedUnit = store.mutation("editMemorizedUnit", (state2, unit) => {
60
+ if (state2.memory.unit?.[indicator] === unit[indicator]) {
61
+ state2.memory.unit = defu(unit, state2.memory.unit);
62
+ }
63
+ });
64
+ const editMemorizedUnits = store.mutation("editMemorizedUnits", (state2, units) => {
81
65
  for (const unit of units) {
82
- const exists = memorizedUnits.value.some((memorizedUnit2) => {
66
+ const index = state2.memory.units.findIndex((memorizedUnit2) => {
83
67
  return memorizedUnit2[indicator] === unit[indicator];
84
68
  });
85
- output[unit[indicator]] = exists;
86
- }
87
- return output;
88
- }
89
- const setMemorizedUnit = store.mutation(
90
- "setMemorizedUnit",
91
- (state, unit = null) => {
92
- state.memory.unit = unit;
93
- }
94
- );
95
- const setMemorizedUnits = store.mutation(
96
- "setMemorizedUnits",
97
- (state, units = []) => {
98
- state.memory.units = units;
99
- }
100
- );
101
- const editMemorizedUnit = store.mutation(
102
- "editMemorizedUnit",
103
- (state, unit) => {
104
- if (state.memory.unit?.[indicator] === unit[indicator]) {
105
- state.memory.unit = defu(unit, state.memory.unit);
69
+ if (index !== -1) {
70
+ state2.memory.units[index] = defu(unit, state2.memory.units[index]);
106
71
  }
107
72
  }
108
- );
109
- const editMemorizedUnits = store.mutation(
110
- "editMemorizedUnits",
111
- (state, units) => {
73
+ });
74
+ const dropMemorizedUnit = store.mutation("dropMemorizedUnit", (state2, unit) => {
75
+ if (state2.memory.unit?.[indicator] === unit[indicator]) {
76
+ state2.memory.unit = null;
77
+ }
78
+ });
79
+ const dropMemorizedUnits = store.mutation("dropMemorizedUnits", (state2, units) => {
80
+ state2.memory.units = state2.memory.units.filter((memorizedUnit2) => {
112
81
  for (const unit of units) {
113
- const index = state.memory.units.findIndex((memorizedUnit2) => {
114
- return memorizedUnit2[indicator] === unit[indicator];
115
- });
116
- if (index !== -1) {
117
- state.memory.units[index] = defu(
118
- unit,
119
- state.memory.units[index]
120
- );
82
+ if (memorizedUnit2[indicator] === unit[indicator]) {
83
+ return false;
121
84
  }
122
85
  }
123
- }
124
- );
125
- const dropMemorizedUnit = store.mutation(
126
- "dropMemorizedUnit",
127
- (state, unit) => {
128
- if (state.memory.unit?.[indicator] === unit[indicator]) {
129
- state.memory.unit = null;
130
- }
131
- }
132
- );
133
- const dropMemorizedUnits = store.mutation(
134
- "dropMemorizedUnits",
135
- (state, units) => {
136
- state.memory.units = state.memory.units.filter((memorizedUnit2) => {
137
- for (const unit of units) {
138
- if (memorizedUnit2[indicator] === unit[indicator]) {
139
- return false;
140
- }
141
- }
142
- return true;
86
+ return true;
87
+ });
88
+ });
89
+ const monitor = {};
90
+ for (const endpoint of Object.values(Endpoint)) {
91
+ for (const endpointStatus of Object.values(EndpointStatus)) {
92
+ const statusKey = makeEndpointStatusName(endpoint, endpointStatus);
93
+ monitor[statusKey] = store.getter(statusKey, (state2) => {
94
+ return state2.endpoints[endpoint] === endpointStatus;
143
95
  });
144
96
  }
145
- );
146
- const endpointsStatus = makeEndpointsStatus(store.getter);
147
- const patchEndpointMemory = store.mutation(
148
- "patchEndpointMemory",
149
- (state, {
150
- key,
151
- memory
152
- }) => {
153
- state.endpoints[key] = memory;
154
- }
155
- );
156
- const purgeEndpointMemory = store.mutation(
157
- "purgeEndpointMemory",
158
- (state) => {
159
- state.endpoints = {};
97
+ }
98
+ const patchMonitor = store.mutation(
99
+ "patchMonitor",
100
+ (state2, payload) => {
101
+ state2.endpoints[payload.endpoint] = payload.status;
160
102
  }
161
103
  );
162
- function patchEndpointMemoryTo(key, memory) {
163
- if (memory.status === EndpointStatus.PENDING) {
164
- const statusKey = makeEndpointStatusKey(
165
- key,
166
- EndpointStatus.PENDING
167
- );
168
- if (endpointsStatus[statusKey].value) {
169
- throw new Error(`Endpoint "${key}" is already pending`);
104
+ function patchMonitorTo(endpoint, status) {
105
+ if (status === EndpointStatus.PENDING) {
106
+ const statusKey = makeEndpointStatusName(endpoint, EndpointStatus.PENDING);
107
+ if (monitor[statusKey].value) {
108
+ throw new Error(`Endpoint "${endpoint}" is already pending`);
170
109
  }
171
110
  }
172
- patchEndpointMemory({
173
- key,
174
- memory
111
+ patchMonitor({
112
+ endpoint,
113
+ status
175
114
  });
176
115
  }
177
- async function withEndpointStatus(key, operation) {
178
- await hooks?.before?.();
179
- patchEndpointMemoryTo(key, {
180
- status: EndpointStatus.PENDING
181
- });
116
+ async function withStatus(key, operation) {
117
+ await options?.hooks?.before?.();
118
+ patchMonitorTo(key, EndpointStatus.PENDING);
182
119
  try {
183
120
  const result = await operation();
184
- patchEndpointMemoryTo(key, {
185
- status: EndpointStatus.SUCCESS
186
- });
187
- await hooks?.after?.();
121
+ patchMonitorTo(key, EndpointStatus.SUCCESS);
122
+ await options?.hooks?.after?.();
188
123
  return result;
189
124
  } catch (error) {
190
- patchEndpointMemoryTo(key, {
191
- status: EndpointStatus.FAILED
192
- });
193
- await hooks?.after?.(error);
125
+ patchMonitorTo(key, EndpointStatus.FAILED);
126
+ await options?.hooks?.after?.(error);
194
127
  throw error;
195
128
  }
196
129
  }
197
- async function getUnit(unit, options2) {
130
+ async function getUnitEndpoint(unit, options2) {
198
131
  const endpoint = getEndpoint(endpoints, Endpoint.GET_UNIT);
199
- return withEndpointStatus(Endpoint.GET_UNIT, async () => {
200
- const response = await api().get(
201
- resolveEndpointUrl(endpoint, unit),
202
- options2
203
- );
132
+ return withStatus(Endpoint.GET_UNIT, async () => {
133
+ const response = await api().get(resolveEndpointUrl(endpoint, unit), options2);
204
134
  setMemorizedUnit(response);
205
135
  return response;
206
136
  });
207
137
  }
208
- async function getUnits(options2) {
138
+ async function getUnitsEndpoint(options2) {
209
139
  const endpoint = getEndpoint(endpoints, Endpoint.GET_UNITS);
210
- return withEndpointStatus(Endpoint.GET_UNITS, async () => {
211
- const response = await api().get(
212
- resolveEndpointUrl(endpoint),
213
- options2
214
- );
140
+ return withStatus(Endpoint.GET_UNITS, async () => {
141
+ const response = await api().get(resolveEndpointUrl(endpoint), options2);
215
142
  setMemorizedUnits(response);
216
143
  return response;
217
144
  });
218
145
  }
219
- async function postUnit(unit, actionOptions) {
146
+ async function postUnitEndpoint(unit, actionOptions) {
220
147
  const endpoint = getEndpoint(endpoints, Endpoint.POST_UNIT);
221
- const resolvedSchema = resolveSchema(schema, {
222
- indicator,
223
- endpoint,
224
- unit
225
- });
148
+ const resolvedSchema = resolveSchema(schema, { indicator, endpoint, unit });
226
149
  if (actionOptions?.validate) {
227
150
  schema.pick(resolvedSchema.keys).parse(unit);
228
151
  }
229
- return withEndpointStatus(Endpoint.POST_UNIT, async () => {
230
- const response = await api().post(
231
- resolveEndpointUrl(endpoint, unit),
232
- {
233
- ...actionOptions,
234
- body: actionOptions?.body ?? resolvedSchema.values
235
- }
236
- );
237
- setMemorizedUnit({
238
- ...unit,
239
- ...response
152
+ return withStatus(Endpoint.POST_UNIT, async () => {
153
+ const response = await api().post(resolveEndpointUrl(endpoint, unit), {
154
+ ...actionOptions,
155
+ body: actionOptions?.body ?? resolvedSchema.values
240
156
  });
157
+ setMemorizedUnit({ ...unit, ...response });
241
158
  return response;
242
159
  });
243
160
  }
244
- async function postUnits(units, options2) {
161
+ async function postUnitsEndpoint(units, options2) {
245
162
  const endpoint = getEndpoint(endpoints, Endpoint.POST_UNITS);
246
- return withEndpointStatus(Endpoint.POST_UNITS, async () => {
163
+ return withStatus(Endpoint.POST_UNITS, async () => {
247
164
  const responses = [];
248
165
  for (const unit of units) {
249
- const resolvedSchema = resolveSchema(schema, {
250
- indicator,
251
- endpoint,
252
- unit
253
- });
166
+ const resolvedSchema = resolveSchema(schema, { indicator, endpoint, unit });
254
167
  if (options2?.validate) {
255
168
  schema.pick(resolvedSchema.keys).parse(unit);
256
169
  }
257
- const response = await api().post(
258
- resolveEndpointUrl(endpoint, unit),
259
- {
260
- ...options2,
261
- body: options2?.body ?? resolvedSchema.values
262
- }
263
- );
170
+ const response = await api().post(resolveEndpointUrl(endpoint, unit), {
171
+ ...options2,
172
+ body: options2?.body ?? resolvedSchema.values
173
+ });
264
174
  const clonedUnits = [...memorizedUnits.value];
265
175
  if (options2?.position === "last" /* LAST */) {
266
- clonedUnits.push({
267
- ...unit,
268
- ...response
269
- });
176
+ clonedUnits.push({ ...unit, ...response });
270
177
  } else {
271
- clonedUnits.unshift({
272
- ...unit,
273
- ...response
274
- });
178
+ clonedUnits.unshift({ ...unit, ...response });
275
179
  }
276
180
  setMemorizedUnits(clonedUnits);
277
181
  responses.push(response);
@@ -279,94 +183,61 @@ export function createStore(name, schema, endpoints, options) {
279
183
  return responses;
280
184
  });
281
185
  }
282
- async function putUnit(unit, options2) {
186
+ async function putUnitEndpoint(unit, options2) {
283
187
  const endpoint = getEndpoint(endpoints, Endpoint.PUT_UNIT);
284
- const resolvedSchema = resolveSchema(schema, {
285
- indicator,
286
- endpoint,
287
- unit
288
- });
188
+ const resolvedSchema = resolveSchema(schema, { indicator, endpoint, unit });
289
189
  if (options2?.validate) {
290
190
  schema.pick(resolvedSchema.keys).parse(unit);
291
191
  }
292
- return withEndpointStatus(Endpoint.PUT_UNIT, async () => {
293
- const response = await api().put(
294
- resolveEndpointUrl(endpoint, unit),
295
- {
296
- ...options2,
297
- body: options2?.body ?? resolvedSchema.values
298
- }
299
- );
300
- setMemorizedUnit({
301
- ...unit,
302
- ...response
192
+ return withStatus(Endpoint.PUT_UNIT, async () => {
193
+ const response = await api().put(resolveEndpointUrl(endpoint, unit), {
194
+ ...options2,
195
+ body: options2?.body ?? resolvedSchema.values
303
196
  });
197
+ setMemorizedUnit({ ...unit, ...response });
304
198
  return response;
305
199
  });
306
200
  }
307
- async function putUnits(units, options2) {
201
+ async function putUnitsEndpoint(units, options2) {
308
202
  const endpoint = getEndpoint(endpoints, Endpoint.PUT_UNITS);
309
- return withEndpointStatus(Endpoint.PUT_UNITS, async () => {
203
+ return withStatus(Endpoint.PUT_UNITS, async () => {
310
204
  const responses = [];
311
205
  for (const unit of units) {
312
- const resolvedSchema = resolveSchema(schema, {
313
- indicator,
314
- endpoint,
315
- unit
316
- });
206
+ const resolvedSchema = resolveSchema(schema, { indicator, endpoint, unit });
317
207
  if (options2?.validate) {
318
208
  schema.pick(resolvedSchema.keys).parse(unit);
319
209
  }
320
- const response = await api().put(
321
- resolveEndpointUrl(endpoint, unit),
322
- {
323
- ...options2,
324
- body: options2?.body ?? resolvedSchema.values
325
- }
326
- );
327
- editMemorizedUnits([
328
- {
329
- ...unit,
330
- ...response
331
- }
332
- ]);
210
+ const response = await api().put(resolveEndpointUrl(endpoint, unit), {
211
+ ...options2,
212
+ body: options2?.body ?? resolvedSchema.values
213
+ });
214
+ editMemorizedUnits([{ ...unit, ...response }]);
333
215
  responses.push(response);
334
216
  }
335
217
  return responses;
336
218
  });
337
219
  }
338
- async function patchUnit(unit, options2) {
220
+ async function patchUnitEndpoint(unit, options2) {
339
221
  const endpoint = getEndpoint(endpoints, Endpoint.PATCH_UNIT);
340
- const resolvedSchema = resolveSchema(schema, {
341
- indicator,
342
- endpoint,
343
- unit
344
- });
222
+ const resolvedSchema = resolveSchema(schema, { indicator, endpoint, unit });
345
223
  if (options2?.validate) {
346
224
  schema.pick(resolvedSchema.keys).partial().parse(unit);
347
225
  }
348
- return withEndpointStatus(Endpoint.PATCH_UNIT, async () => {
226
+ return withStatus(Endpoint.PATCH_UNIT, async () => {
349
227
  const response = await api().patch(resolveEndpointUrl(endpoint, unit), {
350
228
  ...options2,
351
229
  body: options2?.body ?? resolvedSchema.values
352
230
  });
353
- editMemorizedUnit({
354
- ...unit,
355
- ...response
356
- });
231
+ editMemorizedUnit({ ...unit, ...response });
357
232
  return response;
358
233
  });
359
234
  }
360
- async function patchUnits(units, options2) {
235
+ async function patchUnitsEndpoint(units, options2) {
361
236
  const endpoint = getEndpoint(endpoints, Endpoint.PATCH_UNITS);
362
- return withEndpointStatus(Endpoint.PATCH_UNITS, async () => {
237
+ return withStatus(Endpoint.PATCH_UNITS, async () => {
363
238
  const responses = [];
364
239
  for (const unit of units) {
365
- const resolvedSchema = resolveSchema(schema, {
366
- indicator,
367
- endpoint,
368
- unit
369
- });
240
+ const resolvedSchema = resolveSchema(schema, { indicator, endpoint, unit });
370
241
  if (options2?.validate) {
371
242
  schema.pick(resolvedSchema.keys).partial().parse(unit);
372
243
  }
@@ -374,65 +245,56 @@ export function createStore(name, schema, endpoints, options) {
374
245
  ...options2,
375
246
  body: options2?.body ?? resolvedSchema.values
376
247
  });
377
- editMemorizedUnits([
378
- {
379
- ...unit,
380
- ...response
381
- }
382
- ]);
248
+ editMemorizedUnits([{ ...unit, ...response }]);
383
249
  responses.push(response);
384
250
  }
385
251
  return responses;
386
252
  });
387
253
  }
388
- async function deleteUnit(unit, options2) {
254
+ async function deleteUnitEndpoint(unit, options2) {
389
255
  const endpoint = getEndpoint(endpoints, Endpoint.DELETE_UNIT);
390
- return withEndpointStatus(Endpoint.DELETE_UNIT, async () => {
391
- await api().del(
392
- resolveEndpointUrl(endpoint, unit),
393
- options2
394
- );
256
+ return withStatus(Endpoint.DELETE_UNIT, async () => {
257
+ await api().del(resolveEndpointUrl(endpoint, unit), options2);
395
258
  dropMemorizedUnit(unit);
396
259
  return true;
397
260
  });
398
261
  }
399
- async function deleteUnits(units, options2) {
262
+ async function deleteUnitsEndpoint(units, options2) {
400
263
  const endpoint = getEndpoint(endpoints, Endpoint.DELETE_UNITS);
401
- return withEndpointStatus(Endpoint.DELETE_UNITS, async () => {
264
+ return withStatus(Endpoint.DELETE_UNITS, async () => {
402
265
  for (const unit of units) {
403
- await api().del(
404
- resolveEndpointUrl(endpoint, unit),
405
- options2
406
- );
266
+ await api().del(resolveEndpointUrl(endpoint, unit), options2);
407
267
  dropMemorizedUnits([unit]);
408
268
  }
409
269
  return true;
410
270
  });
411
271
  }
412
272
  return {
413
- api,
414
273
  store,
415
- memorizedUnit,
416
- memorizedUnits,
417
- hasMemorizedUnits,
418
- endpointsStatus,
419
- setMemorizedUnit,
420
- setMemorizedUnits,
421
- editMemorizedUnit,
422
- editMemorizedUnits,
423
- dropMemorizedUnit,
424
- dropMemorizedUnits,
425
- patchEndpointMemory,
426
- purgeEndpointMemory,
427
- getUnit,
428
- getUnits,
429
- postUnit,
430
- postUnits,
431
- putUnit,
432
- putUnits,
433
- patchUnit,
434
- patchUnits,
435
- deleteUnit,
436
- deleteUnits
274
+ alias,
275
+ indicator,
276
+ unit: memorizedUnit,
277
+ units: memorizedUnits,
278
+ memory: {
279
+ setUnit: setMemorizedUnit,
280
+ setUnits: setMemorizedUnits,
281
+ editUnit: editMemorizedUnit,
282
+ editUnits: editMemorizedUnits,
283
+ dropUnit: dropMemorizedUnit,
284
+ dropUnits: dropMemorizedUnits
285
+ },
286
+ endpoint: {
287
+ getUnit: getUnitEndpoint,
288
+ getUnits: getUnitsEndpoint,
289
+ postUnit: postUnitEndpoint,
290
+ postUnits: postUnitsEndpoint,
291
+ putUnit: putUnitEndpoint,
292
+ putUnits: putUnitsEndpoint,
293
+ patchUnit: patchUnitEndpoint,
294
+ patchUnits: patchUnitsEndpoint,
295
+ deleteUnit: deleteUnitEndpoint,
296
+ deleteUnits: deleteUnitsEndpoint
297
+ },
298
+ monitor
437
299
  };
438
300
  }
@@ -1,5 +1,8 @@
1
- export { z } from "zod";
2
- export { ApiAction, ApiResponseType, ApiErrorSource, type ApiRequestHeader, type ApiRequestQuery, type ApiRequestBody, type ApiRequestOptions, type ApiOptions, type ApiActionOptions, type ApiErrorOptions, createApi, ApiError, ApiRequestError, ApiResponseError, } from "./core/api.js";
3
- export { Endpoint, EndpointStatus, type EndpointDefinition, type EndpointMemory, } from "./utils/endpoint.js";
4
- export { type SchemaMeta, getMeta, resolveSchema } from "./utils/schema.js";
1
+ export { EndpointMethod, Endpoint, EndpointStatus } from "./utils/endpoint.js";
2
+ export { getMeta, resolveSchema } from "./utils/schema.js";
3
+ export { createApi, ApiResponseType, ApiErrorSource, ApiError, ApiRequestError, ApiResponseError } from "./core/api.js";
5
4
  export { createStore, StoreMemoryPosition } from "./core/store.js";
5
+ export { useStoreAlias } from "./composables/use.js";
6
+ export type { EndpointDefinition } from "./utils/endpoint.js";
7
+ export type { SchemaMeta } from "./utils/schema.js";
8
+ export type { ApiRequestHeader, ApiRequestQuery, ApiRequestBody, ApiRequestOptions, ApiOptions, EndpointMethodOptions, ApiErrorOptions, } from "./core/api.js";
@@ -1,16 +1,5 @@
1
- export { z } from "zod";
2
- export {
3
- ApiAction,
4
- ApiResponseType,
5
- ApiErrorSource,
6
- createApi,
7
- ApiError,
8
- ApiRequestError,
9
- ApiResponseError
10
- } from "./core/api.js";
11
- export {
12
- Endpoint,
13
- EndpointStatus
14
- } from "./utils/endpoint.js";
1
+ export { EndpointMethod, Endpoint, EndpointStatus } from "./utils/endpoint.js";
15
2
  export { getMeta, resolveSchema } from "./utils/schema.js";
3
+ export { createApi, ApiResponseType, ApiErrorSource, ApiError, ApiRequestError, ApiResponseError } from "./core/api.js";
16
4
  export { createStore, StoreMemoryPosition } from "./core/store.js";
5
+ export { useStoreAlias } from "./composables/use.js";
@@ -1,9 +1,5 @@
1
1
  import { createVuePlugin } from "@harlem/core";
2
- import {
3
- createServerSSRPlugin,
4
- createClientSSRPlugin,
5
- getBridgingScript
6
- } from "@harlem/plugin-ssr";
2
+ import { createServerSSRPlugin, createClientSSRPlugin, getBridgingScript } from "@harlem/plugin-ssr";
7
3
  export default defineNuxtPlugin((nuxtApp) => {
8
4
  const plugins = [];
9
5
  if (import.meta.server) {
@@ -1,5 +1,11 @@
1
- import type { BaseState } from "@harlem/core";
2
- import type { ApiAction } from "../core/api.js";
1
+ import type { Capitalize } from "./transform.js";
2
+ export declare enum EndpointMethod {
3
+ GET = "get",
4
+ POST = "post",
5
+ PUT = "put",
6
+ PATCH = "patch",
7
+ DELETE = "delete"
8
+ }
3
9
  export declare enum Endpoint {
4
10
  GET_UNIT = "getUnit",
5
11
  GET_UNITS = "getUnits",
@@ -19,21 +25,14 @@ export declare enum EndpointStatus {
19
25
  FAILED = "failed"
20
26
  }
21
27
  export interface EndpointDefinition<T = Record<string, unknown>> {
22
- action: ApiAction;
28
+ method: EndpointMethod;
23
29
  url: string | ((params: T) => string);
24
30
  }
25
- export interface EndpointMemory {
26
- status: EndpointStatus;
27
- }
28
- type CapitalizeString<S extends string> = S extends `${infer F}${infer R}` ? `${Uppercase<F>}${R}` : S;
29
- export type EndpointStatusKey<K extends Endpoint = Endpoint, S extends EndpointStatus = EndpointStatus> = `${K}Is${CapitalizeString<S>}`;
30
- export declare function makeEndpointStatusKey<K extends Endpoint, S extends EndpointStatus>(key: K, status: S): EndpointStatusKey<K, S>;
31
- export declare function getEndpoint<T = Record<string, unknown>>(endpoints: Partial<Record<Endpoint, EndpointDefinition<T>>> | undefined, key: Endpoint): EndpointDefinition<T>;
31
+ export type EndpointStatusFlag<S extends EndpointStatus = EndpointStatus> = `Is${Capitalize<S>}`;
32
+ export type EndpointStatusName<K extends Endpoint = Endpoint, S extends EndpointStatus = EndpointStatus> = `${K}${EndpointStatusFlag<S>}`;
33
+ export declare function makeEndpointStatusFlag<S extends EndpointStatus>(status: S): EndpointStatusFlag<S>;
34
+ export declare function makeEndpointStatusName<K extends Endpoint, S extends EndpointStatus>(key: K, status: S): EndpointStatusName<K, S>;
35
+ export declare function getEndpoint<T = Record<string, unknown>>(endpoints: Partial<Record<Endpoint, EndpointDefinition<T>>> | undefined, endpoint: Endpoint): EndpointDefinition<T>;
32
36
  export declare function resolveEndpointUrl<T>(endpoint: EndpointDefinition<T>, params?: {
33
37
  [key: string]: unknown;
34
38
  }): string;
35
- export type EndpointsStatusMap<T> = {
36
- [K in Endpoint as EndpointStatusKey<K, EndpointStatus>]: T;
37
- };
38
- export declare function makeEndpointsStatus<T>(getter: (name: string, fn: (state: BaseState) => boolean) => T): EndpointsStatusMap<T>;
39
- export {};
@@ -1,3 +1,12 @@
1
+ import { capitalize } from "./transform.js";
2
+ export var EndpointMethod = /* @__PURE__ */ ((EndpointMethod2) => {
3
+ EndpointMethod2["GET"] = "get";
4
+ EndpointMethod2["POST"] = "post";
5
+ EndpointMethod2["PUT"] = "put";
6
+ EndpointMethod2["PATCH"] = "patch";
7
+ EndpointMethod2["DELETE"] = "delete";
8
+ return EndpointMethod2;
9
+ })(EndpointMethod || {});
1
10
  export var Endpoint = /* @__PURE__ */ ((Endpoint2) => {
2
11
  Endpoint2["GET_UNIT"] = "getUnit";
3
12
  Endpoint2["GET_UNITS"] = "getUnits";
@@ -18,16 +27,17 @@ export var EndpointStatus = /* @__PURE__ */ ((EndpointStatus2) => {
18
27
  EndpointStatus2["FAILED"] = "failed";
19
28
  return EndpointStatus2;
20
29
  })(EndpointStatus || {});
21
- export function makeEndpointStatusKey(key, status) {
22
- const capitalizedStatus = status.charAt(0).toUpperCase() + status.slice(1);
23
- return `${key}Is${capitalizedStatus}`;
30
+ export function makeEndpointStatusFlag(status) {
31
+ return `Is${capitalize(status)}`;
24
32
  }
25
- export function getEndpoint(endpoints, key) {
26
- const endpoint = endpoints?.[key];
27
- if (!endpoint) {
28
- throw new Error(`Endpoint "${key}" is not configured`);
33
+ export function makeEndpointStatusName(key, status) {
34
+ return `${key}${makeEndpointStatusFlag(status)}`;
35
+ }
36
+ export function getEndpoint(endpoints, endpoint) {
37
+ if (!endpoints || !(endpoint in endpoints)) {
38
+ throw new Error(`Endpoint "${endpoint}" is not configured`);
29
39
  }
30
- return endpoint;
40
+ return endpoints[endpoint];
31
41
  }
32
42
  export function resolveEndpointUrl(endpoint, params) {
33
43
  if (typeof endpoint.url === "function") {
@@ -35,15 +45,3 @@ export function resolveEndpointUrl(endpoint, params) {
35
45
  }
36
46
  return endpoint.url;
37
47
  }
38
- export function makeEndpointsStatus(getter) {
39
- const output = {};
40
- for (const key of Object.values(Endpoint)) {
41
- for (const status of Object.values(EndpointStatus)) {
42
- const statusKey = makeEndpointStatusKey(key, status);
43
- output[statusKey] = getter(statusKey, (state) => {
44
- return state.endpoints[key]?.status === status;
45
- });
46
- }
47
- }
48
- return output;
49
- }
@@ -1,9 +1,8 @@
1
- import { z } from "zod";
2
- import type { ApiAction } from "../core/api.js";
3
- import type { EndpointDefinition } from "./endpoint.js";
1
+ import type { z } from "zod";
2
+ import type { EndpointDefinition, EndpointMethod } from "./endpoint.js";
4
3
  export interface SchemaMeta {
5
4
  indicator?: boolean;
6
- actions?: ApiAction[];
5
+ methods?: EndpointMethod[];
7
6
  }
8
7
  export declare function getMeta(field: any): SchemaMeta | undefined;
9
8
  export interface ResolveSchemaOptions<S> {
@@ -12,10 +12,10 @@ export function resolveSchema(schema, options) {
12
12
  if (meta?.indicator) {
13
13
  output.indicator = key;
14
14
  }
15
- if (!options?.endpoint?.action || !meta?.actions) {
15
+ if (!options?.endpoint?.method || !meta?.methods) {
16
16
  continue;
17
17
  }
18
- if (meta?.actions.includes(options.endpoint.action)) {
18
+ if (meta?.methods.includes(options.endpoint.method)) {
19
19
  output.keys[key] = true;
20
20
  if (options?.unit && key in options.unit) {
21
21
  output.values[key] = options.unit[key];
@@ -0,0 +1,6 @@
1
+ type IsVowel<C extends string> = C extends "a" | "e" | "i" | "o" | "u" ? true : false;
2
+ export type Pluralize<S extends string> = S extends `${infer Base}y` ? Base extends `${infer _Rest}${infer Last}` ? IsVowel<Last> extends true ? `${S}s` : `${Base}ies` : `${S}s` : S extends `${string}${"s" | "x" | "z"}` ? `${S}es` : S extends `${string}${"ch" | "sh"}` ? `${S}es` : `${S}s`;
3
+ export declare function pluralize<S extends string>(word: S): Pluralize<S>;
4
+ export type Capitalize<S extends string> = S extends `${infer F}${infer R}` ? `${Uppercase<F>}${R}` : S;
5
+ export declare function capitalize<S extends string>(str: S): Capitalize<S>;
6
+ export {};
@@ -0,0 +1,20 @@
1
+ export function pluralize(word) {
2
+ if (!word) return word;
3
+ const vowels = ["a", "e", "i", "o", "u"];
4
+ const lastChar = word.slice(-1).toLowerCase();
5
+ const lastTwo = word.slice(-2).toLowerCase();
6
+ const beforeLast = word.slice(-2, -1).toLowerCase();
7
+ if (lastChar === "y" && !vowels.includes(beforeLast)) {
8
+ return word.slice(0, -1) + "ies";
9
+ }
10
+ if (["s", "x", "z"].includes(lastChar)) {
11
+ return word + "es";
12
+ }
13
+ if (["ch", "sh"].includes(lastTwo)) {
14
+ return word + "es";
15
+ }
16
+ return word + "s";
17
+ }
18
+ export function capitalize(str) {
19
+ return str.charAt(0).toUpperCase() + str.slice(1);
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diphyx/harlemify",
3
- "version": "0.0.3",
3
+ "version": "1.0.0",
4
4
  "description": "API state management for Nuxt powered by Harlem",
5
5
  "keywords": [
6
6
  "nuxt",