@diphyx/harlemify 3.0.0 → 4.0.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.
Files changed (59) hide show
  1. package/README.md +51 -32
  2. package/dist/module.d.mts +24 -13
  3. package/dist/module.d.ts +24 -13
  4. package/dist/module.json +1 -1
  5. package/dist/module.mjs +8 -10
  6. package/dist/runtime/composables/action.d.ts +4 -0
  7. package/dist/runtime/composables/action.js +8 -0
  8. package/dist/runtime/config.d.ts +10 -0
  9. package/dist/runtime/config.js +7 -0
  10. package/dist/runtime/core/layers/action.d.ts +4 -0
  11. package/dist/runtime/core/layers/action.js +102 -0
  12. package/dist/runtime/core/layers/model.d.ts +3 -0
  13. package/dist/runtime/core/layers/model.js +31 -0
  14. package/dist/runtime/core/layers/shape.d.ts +45 -0
  15. package/dist/runtime/core/layers/shape.js +56 -0
  16. package/dist/runtime/core/layers/view.d.ts +4 -0
  17. package/dist/runtime/core/layers/view.js +21 -0
  18. package/dist/runtime/core/store.d.ts +20 -66
  19. package/dist/runtime/core/store.js +46 -574
  20. package/dist/runtime/core/types/action.d.ts +163 -0
  21. package/dist/runtime/core/types/action.js +39 -0
  22. package/dist/runtime/core/types/model.d.ts +70 -0
  23. package/dist/runtime/core/types/model.js +5 -0
  24. package/dist/runtime/core/types/shape.d.ts +46 -0
  25. package/dist/runtime/core/types/shape.js +0 -0
  26. package/dist/runtime/core/types/view.d.ts +29 -0
  27. package/dist/runtime/core/types/view.js +0 -0
  28. package/dist/runtime/core/utils/action.d.ts +4 -0
  29. package/dist/runtime/core/utils/action.js +294 -0
  30. package/dist/runtime/core/utils/model.d.ts +12 -0
  31. package/dist/runtime/core/utils/model.js +227 -0
  32. package/dist/runtime/core/utils/shape.d.ts +3 -0
  33. package/dist/runtime/core/utils/shape.js +29 -0
  34. package/dist/runtime/core/utils/view.d.ts +5 -0
  35. package/dist/runtime/core/utils/view.js +19 -0
  36. package/dist/runtime/index.d.ts +8 -16
  37. package/dist/runtime/index.js +11 -7
  38. package/dist/runtime/plugin.js +2 -5
  39. package/package.json +2 -1
  40. package/dist/runtime/composables/use.d.ts +0 -22
  41. package/dist/runtime/composables/use.js +0 -14
  42. package/dist/runtime/core/api.d.ts +0 -37
  43. package/dist/runtime/core/api.js +0 -56
  44. package/dist/runtime/shared.d.ts +0 -9
  45. package/dist/runtime/shared.js +0 -3
  46. package/dist/runtime/utils/adapter.d.ts +0 -24
  47. package/dist/runtime/utils/adapter.js +0 -35
  48. package/dist/runtime/utils/cache.d.ts +0 -10
  49. package/dist/runtime/utils/cache.js +0 -26
  50. package/dist/runtime/utils/endpoint.d.ts +0 -38
  51. package/dist/runtime/utils/endpoint.js +0 -56
  52. package/dist/runtime/utils/errors.d.ts +0 -22
  53. package/dist/runtime/utils/errors.js +0 -33
  54. package/dist/runtime/utils/memory.d.ts +0 -40
  55. package/dist/runtime/utils/memory.js +0 -87
  56. package/dist/runtime/utils/schema.d.ts +0 -23
  57. package/dist/runtime/utils/schema.js +0 -58
  58. package/dist/runtime/utils/transform.d.ts +0 -6
  59. package/dist/runtime/utils/transform.js +0 -22
@@ -0,0 +1,163 @@
1
+ import type { ConsolaInstance } from "consola";
2
+ import type { ComputedRef, DeepReadonly, MaybeRefOrGetter, Ref } from "vue";
3
+ import type { Model, ModelShape, MutationsOneOptions, MutationsManyOptions } from "./model.js";
4
+ export interface RuntimeActionConfig {
5
+ endpoint?: string;
6
+ headers?: Record<string, string>;
7
+ query?: Record<string, unknown>;
8
+ timeout?: number;
9
+ concurrent?: ActionConcurrent;
10
+ }
11
+ export declare const DEFINITION: unique symbol;
12
+ export declare const AUTO: unique symbol;
13
+ export declare enum ActionOneMode {
14
+ SET = "set",
15
+ RESET = "reset",
16
+ PATCH = "patch"
17
+ }
18
+ export declare enum ActionManyMode {
19
+ SET = "set",
20
+ RESET = "reset",
21
+ PATCH = "patch",
22
+ REMOVE = "remove",
23
+ ADD = "add"
24
+ }
25
+ export declare enum ActionStatus {
26
+ IDLE = "idle",
27
+ PENDING = "pending",
28
+ SUCCESS = "success",
29
+ ERROR = "error"
30
+ }
31
+ export declare enum ActionConcurrent {
32
+ BLOCK = "block",
33
+ SKIP = "skip",
34
+ CANCEL = "cancel",
35
+ ALLOW = "allow"
36
+ }
37
+ export declare enum ActionApiMethod {
38
+ GET = "GET",
39
+ HEAD = "HEAD",
40
+ POST = "POST",
41
+ PUT = "PUT",
42
+ PATCH = "PATCH",
43
+ DELETE = "DELETE"
44
+ }
45
+ export interface ActionApiError extends Error {
46
+ name: "ActionApiError";
47
+ status?: number;
48
+ statusText?: string;
49
+ data?: unknown;
50
+ }
51
+ export interface ActionHandleError extends Error {
52
+ name: "ActionHandleError";
53
+ cause: Error;
54
+ }
55
+ export interface ActionCommitError extends Error {
56
+ name: "ActionCommitError";
57
+ cause: Error;
58
+ }
59
+ export interface ActionConcurrentError extends Error {
60
+ name: "ActionConcurrentError";
61
+ }
62
+ export type ActionError = ActionApiError | ActionHandleError | ActionCommitError | ActionConcurrentError;
63
+ export type ActionApiValue<V, T> = MaybeRefOrGetter<T> | ((view: DeepReadonly<V>) => T);
64
+ export interface ActionApiDefinition<V> {
65
+ endpoint?: string;
66
+ url: ActionApiValue<V, string>;
67
+ method: ActionApiMethod;
68
+ headers?: ActionApiValue<V, Record<string, string>>;
69
+ query?: ActionApiValue<V, Record<string, unknown>>;
70
+ body?: ActionApiValue<V, unknown>;
71
+ timeout?: number;
72
+ concurrent?: ActionConcurrent;
73
+ }
74
+ export type DeepPartial<T> = T extends object ? {
75
+ [K in keyof T]?: DeepPartial<T[K]>;
76
+ } : T;
77
+ export type ActionCommitValue<M extends Model, K extends keyof M, Mode> = Mode extends ActionOneMode.SET ? ModelShape<M, K> : Mode extends ActionOneMode.PATCH ? DeepPartial<ModelShape<M, K>> : Mode extends ActionOneMode.RESET ? never : Mode extends ActionManyMode.SET ? ModelShape<M, K>[] : Mode extends ActionManyMode.PATCH ? DeepPartial<ModelShape<M, K>> | DeepPartial<ModelShape<M, K>>[] : Mode extends ActionManyMode.REMOVE ? ModelShape<M, K> | ModelShape<M, K>[] : Mode extends ActionManyMode.ADD ? ModelShape<M, K> | ModelShape<M, K>[] : Mode extends ActionManyMode.RESET ? never : never;
78
+ export type ActionCommitter<M extends Model> = {
79
+ <K extends keyof M, Mode extends ActionOneMode>(model: K, mode: Mode, ...args: Mode extends ActionOneMode.RESET ? [] : [value: ActionCommitValue<M, K, Mode>, options?: MutationsOneOptions]): void;
80
+ <K extends keyof M, Mode extends ActionManyMode>(model: K, mode: Mode, ...args: Mode extends ActionManyMode.RESET ? [] : [value: ActionCommitValue<M, K, Mode>, options?: MutationsManyOptions]): void;
81
+ };
82
+ export interface ActionHandleContext<M extends Model, V, ApiResponse = unknown> {
83
+ api: <T = ApiResponse>() => Promise<T>;
84
+ view: DeepReadonly<V>;
85
+ commit: ActionCommitter<M>;
86
+ }
87
+ export interface ActionHandleContextNoApi<M extends Model, V> {
88
+ view: DeepReadonly<V>;
89
+ commit: ActionCommitter<M>;
90
+ }
91
+ export type ActionHandleCallback<M extends Model, V, R = void, ApiResponse = unknown> = (context: ActionHandleContext<M, V, ApiResponse>) => Promise<R>;
92
+ export type ActionHandleCallbackNoApi<M extends Model, V, R = void> = (context: ActionHandleContextNoApi<M, V>) => Promise<R>;
93
+ export type ActionHandleResolver<R = void> = (...args: unknown[]) => Promise<R>;
94
+ export interface ActionDefinition<M extends Model, V, R = void> {
95
+ api?: ActionApiDefinition<V>;
96
+ handle?: ActionHandleCallback<M, V, R, unknown> | ActionHandleCallbackNoApi<M, V, R>;
97
+ commit?: {
98
+ model: keyof M;
99
+ mode: ActionOneMode | ActionManyMode;
100
+ value?: unknown;
101
+ options?: MutationsOneOptions | MutationsManyOptions;
102
+ };
103
+ logger?: ConsolaInstance;
104
+ }
105
+ export type ActionDefinitions<M extends Model, V> = Record<string, ActionDefinition<M, V, unknown>>;
106
+ export interface ActionCommitMethod<M extends Model, V, R> {
107
+ <K extends keyof M, Mode extends ActionOneMode>(model: K, mode: Mode, ...args: Mode extends ActionOneMode.RESET ? [] : [value?: ActionCommitValue<M, K, Mode> | typeof AUTO, options?: MutationsOneOptions]): ActionCommitChain<M, V, R>;
108
+ <K extends keyof M, Mode extends ActionManyMode>(model: K, mode: Mode, ...args: Mode extends ActionManyMode.RESET ? [] : [value?: ActionCommitValue<M, K, Mode> | typeof AUTO, options?: MutationsManyOptions]): ActionCommitChain<M, V, R>;
109
+ }
110
+ export interface ActionApiChain<M extends Model, V, ApiResponse> {
111
+ handle<R>(callback: ActionHandleCallback<M, V, R, ApiResponse>): ActionHandleChain<M, V, R>;
112
+ commit: ActionCommitMethod<M, V, ApiResponse>;
113
+ readonly [DEFINITION]: ActionDefinition<M, V, ApiResponse>;
114
+ }
115
+ export interface ActionHandleChain<M extends Model, V, R> {
116
+ commit: ActionCommitMethod<M, V, R>;
117
+ readonly [DEFINITION]: ActionDefinition<M, V, R>;
118
+ }
119
+ export interface ActionCommitChain<M extends Model, V, R> {
120
+ readonly [DEFINITION]: ActionDefinition<M, V, R>;
121
+ }
122
+ export type ActionApiShortcutDefinition<V> = Omit<ActionApiDefinition<V>, "method">;
123
+ export interface ActionApiFactory<M extends Model, V> {
124
+ <A>(definition: ActionApiDefinition<V>): ActionApiChain<M, V, A>;
125
+ get<A>(definition: ActionApiShortcutDefinition<V>): ActionApiChain<M, V, A>;
126
+ head<A>(definition: ActionApiShortcutDefinition<V>): ActionApiChain<M, V, A>;
127
+ post<A>(definition: ActionApiShortcutDefinition<V>): ActionApiChain<M, V, A>;
128
+ put<A>(definition: ActionApiShortcutDefinition<V>): ActionApiChain<M, V, A>;
129
+ patch<A>(definition: ActionApiShortcutDefinition<V>): ActionApiChain<M, V, A>;
130
+ delete<A>(definition: ActionApiShortcutDefinition<V>): ActionApiChain<M, V, A>;
131
+ }
132
+ export interface ActionFactory<M extends Model, V> {
133
+ api: ActionApiFactory<M, V>;
134
+ handle<R>(callback: ActionHandleCallbackNoApi<M, V, R>): ActionHandleChain<M, V, R>;
135
+ commit: ActionCommitMethod<M, V, void>;
136
+ }
137
+ export interface ActionCallBind {
138
+ status?: Ref<ActionStatus>;
139
+ error?: Ref<ActionError | null>;
140
+ }
141
+ export interface ActionCallCommit {
142
+ mode?: ActionOneMode | ActionManyMode;
143
+ }
144
+ export interface ActionCallPayload<V, T = unknown, R = T> {
145
+ headers?: Record<string, string> | ((view: DeepReadonly<V>) => Record<string, string>);
146
+ query?: Record<string, unknown> | ((view: DeepReadonly<V>) => Record<string, unknown>);
147
+ body?: unknown | ((view: DeepReadonly<V>) => unknown);
148
+ timeout?: number;
149
+ signal?: AbortSignal;
150
+ transformer?: (response: T) => R;
151
+ concurrent?: ActionConcurrent;
152
+ bind?: ActionCallBind;
153
+ commit?: ActionCallCommit;
154
+ }
155
+ export interface Action<V, T = void> {
156
+ (payload?: ActionCallPayload<V, T>): Promise<T>;
157
+ <R>(payload: ActionCallPayload<V, T, R>): Promise<R>;
158
+ readonly loading: ComputedRef<boolean>;
159
+ readonly status: Readonly<Ref<ActionStatus>>;
160
+ readonly error: Readonly<Ref<ActionError | null>>;
161
+ readonly data: DeepReadonly<T> | null;
162
+ reset: () => void;
163
+ }
@@ -0,0 +1,39 @@
1
+ export const DEFINITION = Symbol("definition");
2
+ export const AUTO = Symbol("auto");
3
+ export var ActionOneMode = /* @__PURE__ */ ((ActionOneMode2) => {
4
+ ActionOneMode2["SET"] = "set";
5
+ ActionOneMode2["RESET"] = "reset";
6
+ ActionOneMode2["PATCH"] = "patch";
7
+ return ActionOneMode2;
8
+ })(ActionOneMode || {});
9
+ export var ActionManyMode = /* @__PURE__ */ ((ActionManyMode2) => {
10
+ ActionManyMode2["SET"] = "set";
11
+ ActionManyMode2["RESET"] = "reset";
12
+ ActionManyMode2["PATCH"] = "patch";
13
+ ActionManyMode2["REMOVE"] = "remove";
14
+ ActionManyMode2["ADD"] = "add";
15
+ return ActionManyMode2;
16
+ })(ActionManyMode || {});
17
+ export var ActionStatus = /* @__PURE__ */ ((ActionStatus2) => {
18
+ ActionStatus2["IDLE"] = "idle";
19
+ ActionStatus2["PENDING"] = "pending";
20
+ ActionStatus2["SUCCESS"] = "success";
21
+ ActionStatus2["ERROR"] = "error";
22
+ return ActionStatus2;
23
+ })(ActionStatus || {});
24
+ export var ActionConcurrent = /* @__PURE__ */ ((ActionConcurrent2) => {
25
+ ActionConcurrent2["BLOCK"] = "block";
26
+ ActionConcurrent2["SKIP"] = "skip";
27
+ ActionConcurrent2["CANCEL"] = "cancel";
28
+ ActionConcurrent2["ALLOW"] = "allow";
29
+ return ActionConcurrent2;
30
+ })(ActionConcurrent || {});
31
+ export var ActionApiMethod = /* @__PURE__ */ ((ActionApiMethod2) => {
32
+ ActionApiMethod2["GET"] = "GET";
33
+ ActionApiMethod2["HEAD"] = "HEAD";
34
+ ActionApiMethod2["POST"] = "POST";
35
+ ActionApiMethod2["PUT"] = "PUT";
36
+ ActionApiMethod2["PATCH"] = "PATCH";
37
+ ActionApiMethod2["DELETE"] = "DELETE";
38
+ return ActionApiMethod2;
39
+ })(ActionApiMethod || {});
@@ -0,0 +1,70 @@
1
+ import type { ConsolaInstance } from "consola";
2
+ import type { Shape, ShapeType } from "./shape.js";
3
+ export interface RuntimeModelConfig {
4
+ identifier?: string;
5
+ }
6
+ export declare enum ModelKind {
7
+ OBJECT = "object",
8
+ ARRAY = "array"
9
+ }
10
+ export interface ModelOneOptions<S extends Shape> {
11
+ identifier?: keyof S;
12
+ default?: S;
13
+ }
14
+ export interface ModelManyOptions<S extends Shape> {
15
+ identifier?: keyof S;
16
+ default?: S[];
17
+ }
18
+ export interface ModelOneDefinition<S extends Shape> {
19
+ shape: ShapeType<S>;
20
+ kind: ModelKind.OBJECT;
21
+ options?: ModelOneOptions<S>;
22
+ logger?: ConsolaInstance;
23
+ }
24
+ export interface ModelManyDefinition<S extends Shape> {
25
+ shape: ShapeType<S>;
26
+ kind: ModelKind.ARRAY;
27
+ options?: ModelManyOptions<S>;
28
+ logger?: ConsolaInstance;
29
+ }
30
+ export type ModelDefinition<S extends Shape> = ModelOneDefinition<S> | ModelManyDefinition<S>;
31
+ export type Model = Record<string, ModelDefinition<any>>;
32
+ export type ModelInstance<M extends Model, K extends keyof M> = M[K] extends ModelOneDefinition<infer S> ? S | null : M[K] extends ModelManyDefinition<infer S> ? S[] : never;
33
+ export type ModelShape<M extends Model, K extends keyof M> = M[K] extends ModelDefinition<infer S> ? S : never;
34
+ export type ModelOneKey<M extends Model> = {
35
+ [K in keyof M]: M[K] extends ModelOneDefinition<infer _S> ? K : never;
36
+ }[keyof M];
37
+ export type ModelManyKey<M extends Model> = {
38
+ [K in keyof M]: M[K] extends ModelManyDefinition<infer _S> ? K : never;
39
+ }[keyof M];
40
+ export type ModelStateOf<M extends Model> = {
41
+ [K in keyof M]: ModelInstance<M, K>;
42
+ };
43
+ export interface ModelFactory {
44
+ one<S extends Shape>(shape: ShapeType<S>, options?: ModelOneOptions<S>): ModelOneDefinition<S>;
45
+ many<S extends Shape>(shape: ShapeType<S>, options?: ModelManyOptions<S>): ModelManyDefinition<S>;
46
+ }
47
+ export interface MutationsOneOptions {
48
+ deep?: boolean;
49
+ }
50
+ export interface MutationsManyOptions {
51
+ by?: string;
52
+ prepend?: boolean;
53
+ unique?: boolean;
54
+ deep?: boolean;
55
+ }
56
+ export interface MutationsOne<S extends Shape> {
57
+ set: (value: S) => void;
58
+ reset: () => void;
59
+ patch: (value: Partial<S>, options?: MutationsOneOptions) => void;
60
+ }
61
+ export interface MutationsMany<S extends Shape> {
62
+ set: (value: S[]) => void;
63
+ reset: () => void;
64
+ patch: (value: Partial<S> | Partial<S>[], options?: MutationsManyOptions) => void;
65
+ remove: (value: S | S[], options?: MutationsManyOptions) => void;
66
+ add: (value: S | S[], options?: MutationsManyOptions) => void;
67
+ }
68
+ export type Mutations<M extends Model> = {
69
+ [K in keyof M]: M[K] extends ModelOneDefinition<infer S> ? MutationsOne<S> : M[K] extends ModelManyDefinition<infer S> ? MutationsMany<S> : never;
70
+ };
@@ -0,0 +1,5 @@
1
+ export var ModelKind = /* @__PURE__ */ ((ModelKind2) => {
2
+ ModelKind2["OBJECT"] = "object";
3
+ ModelKind2["ARRAY"] = "array";
4
+ return ModelKind2;
5
+ })(ModelKind || {});
@@ -0,0 +1,46 @@
1
+ import type { z } from "zod";
2
+ export type ShapeDefinition = z.ZodObject<z.ZodRawShape>;
3
+ export type ShapeType<S> = z.ZodType<S>;
4
+ export type ShapeInfer<T extends z.ZodType<any>> = z.infer<T>;
5
+ export type Shape = Record<string, unknown>;
6
+ export interface ShapeMeta {
7
+ identifier?: string;
8
+ defaults: Record<string, unknown>;
9
+ fields: string[];
10
+ }
11
+ export interface ShapeFactory {
12
+ string: typeof z.string;
13
+ number: typeof z.number;
14
+ boolean: typeof z.boolean;
15
+ bigint: typeof z.bigint;
16
+ date: typeof z.date;
17
+ object: typeof z.object;
18
+ array: typeof z.array;
19
+ tuple: typeof z.tuple;
20
+ record: typeof z.record;
21
+ map: typeof z.map;
22
+ set: typeof z.set;
23
+ enum: typeof z.enum;
24
+ union: typeof z.union;
25
+ literal: typeof z.literal;
26
+ email: typeof z.email;
27
+ url: typeof z.url;
28
+ uuid: typeof z.uuid;
29
+ cuid: typeof z.cuid;
30
+ cuid2: typeof z.cuid2;
31
+ ulid: typeof z.ulid;
32
+ nanoid: typeof z.nanoid;
33
+ jwt: typeof z.jwt;
34
+ emoji: typeof z.emoji;
35
+ ipv4: typeof z.ipv4;
36
+ ipv6: typeof z.ipv6;
37
+ mac: typeof z.mac;
38
+ base64: typeof z.base64;
39
+ base64url: typeof z.base64url;
40
+ hex: typeof z.hex;
41
+ any: typeof z.any;
42
+ unknown: typeof z.unknown;
43
+ never: typeof z.never;
44
+ nullable: typeof z.nullable;
45
+ optional: typeof z.optional;
46
+ }
File without changes
@@ -0,0 +1,29 @@
1
+ import type { ConsolaInstance } from "consola";
2
+ import type { Model, ModelInstance } from "./model.js";
3
+ export interface RuntimeViewConfig {
4
+ }
5
+ export type ViewFromResolver<M extends Model, K extends keyof M, R> = (model: ModelInstance<M, K>) => R;
6
+ export type ModelInstanceTuple<M extends Model, K extends readonly (keyof M)[]> = {
7
+ [I in keyof K]: K[I] extends keyof M ? ModelInstance<M, K[I]> : never;
8
+ };
9
+ export type ViewMergeResolver<M extends Model, K extends readonly (keyof M)[], R> = (...values: [...ModelInstanceTuple<M, K>]) => R;
10
+ export interface ViewFromDefinition<M extends Model, K extends keyof M, R = ModelInstance<M, K>> {
11
+ sources: readonly [K];
12
+ resolver?: ViewFromResolver<M, K, R>;
13
+ logger?: ConsolaInstance;
14
+ }
15
+ export interface ViewMergeDefinition<M extends Model, K extends readonly (keyof M)[], R> {
16
+ sources: K;
17
+ resolver: ViewMergeResolver<M, K, R>;
18
+ logger?: ConsolaInstance;
19
+ }
20
+ export type ViewDefinition<M extends Model> = ViewFromDefinition<M, keyof M, unknown> | ViewMergeDefinition<M, readonly (keyof M)[], unknown>;
21
+ export type ViewDefinitions<M extends Model> = Record<string, ViewDefinition<M>>;
22
+ export type ViewResult<M extends Model, VD extends ViewDefinition<M>> = VD extends ViewFromDefinition<M, infer _K, infer R> ? R : VD extends ViewMergeDefinition<M, infer _K, infer R> ? R : never;
23
+ export interface ViewFactory<M extends Model> {
24
+ from<K extends keyof M>(source: K): ViewFromDefinition<M, K, ModelInstance<M, K>>;
25
+ from<K extends keyof M, R>(source: K, resolver: ViewFromResolver<M, K, R>): ViewFromDefinition<M, K, R>;
26
+ merge<K1 extends keyof M, K2 extends keyof M, R>(sources: readonly [K1, K2], resolver: (v1: ModelInstance<M, K1>, v2: ModelInstance<M, K2>) => R): ViewMergeDefinition<M, readonly [K1, K2], R>;
27
+ merge<K1 extends keyof M, K2 extends keyof M, K3 extends keyof M, R>(sources: readonly [K1, K2, K3], resolver: (v1: ModelInstance<M, K1>, v2: ModelInstance<M, K2>, v3: ModelInstance<M, K3>) => R): ViewMergeDefinition<M, readonly [K1, K2, K3], R>;
28
+ merge<K extends readonly (keyof M)[], R>(sources: K, resolver: ViewMergeResolver<M, K, R>): ViewMergeDefinition<M, K, R>;
29
+ }
File without changes
@@ -0,0 +1,4 @@
1
+ import { type Action, type ActionCommitMethod, type ActionDefinition } from "../types/action.js";
2
+ import type { Model, Mutations } from "../types/model.js";
3
+ export declare function buildCommitMethod<M extends Model, V, R>(definition: ActionDefinition<M, V, R>): ActionCommitMethod<M, V, R>;
4
+ export declare function createAction<M extends Model, V, R>(definition: ActionDefinition<M, V, R>, mutations: Mutations<M>, view: V, key: string): Action<V, R>;
@@ -0,0 +1,294 @@
1
+ import { defu } from "defu";
2
+ import { ref, computed, readonly, toValue, nextTick } from "vue";
3
+ import {
4
+ ActionApiMethod,
5
+ ActionStatus,
6
+ ActionConcurrent,
7
+ DEFINITION
8
+ } from "../types/action.js";
9
+ import { createCommitter, executeCommit } from "./model.js";
10
+ class ApiError extends Error {
11
+ name = "ActionApiError";
12
+ constructor(message, options) {
13
+ super(message);
14
+ this.status = options?.status;
15
+ this.statusText = options?.statusText;
16
+ this.data = options?.data;
17
+ }
18
+ }
19
+ class HandleError extends Error {
20
+ name = "ActionHandleError";
21
+ constructor(cause) {
22
+ super(cause.message);
23
+ this.cause = cause;
24
+ }
25
+ }
26
+ class CommitError extends Error {
27
+ name = "ActionCommitError";
28
+ constructor(cause) {
29
+ super(cause.message);
30
+ this.cause = cause;
31
+ }
32
+ }
33
+ class ConcurrentError extends Error {
34
+ name = "ActionConcurrentError";
35
+ constructor() {
36
+ super("Action is already pending");
37
+ }
38
+ }
39
+ function createApiError(message, options) {
40
+ return new ApiError(message, options);
41
+ }
42
+ function createHandleError(cause) {
43
+ return new HandleError(cause);
44
+ }
45
+ function createCommitError(cause) {
46
+ return new CommitError(cause);
47
+ }
48
+ function createConcurrentError() {
49
+ return new ConcurrentError();
50
+ }
51
+ export function buildCommitMethod(definition) {
52
+ function commit(model, mode, value, options) {
53
+ return {
54
+ [DEFINITION]: {
55
+ ...definition,
56
+ commit: {
57
+ model,
58
+ mode,
59
+ value,
60
+ options
61
+ }
62
+ }
63
+ };
64
+ }
65
+ return commit;
66
+ }
67
+ function resolveApiValue(value, view, fallback) {
68
+ if (typeof value === "function") {
69
+ const handler = value;
70
+ return handler(view) || fallback;
71
+ }
72
+ return toValue(value) || fallback;
73
+ }
74
+ function resolveApiUrl(definition, view) {
75
+ const endpoint = (definition.endpoint ?? "").replace(/\/+$/, "");
76
+ const path = resolveApiValue(definition.url, view);
77
+ if (endpoint) {
78
+ return `${endpoint}/${path.replace(/^\/+/, "")}`;
79
+ }
80
+ return path;
81
+ }
82
+ function resolveApiHeaders(definition, view, payload) {
83
+ const initial = resolveApiValue(definition.headers, view, {});
84
+ const custom = resolveApiValue(payload?.headers, view, {});
85
+ return defu(custom, initial);
86
+ }
87
+ function resolveApiQuery(definition, view, payload) {
88
+ const initial = resolveApiValue(definition.query, view, {});
89
+ const custom = resolveApiValue(payload?.query, view, {});
90
+ return defu(custom, initial);
91
+ }
92
+ function resolveApiBody(definition, view, payload) {
93
+ if (definition.method === ActionApiMethod.GET || definition.method === ActionApiMethod.HEAD) {
94
+ return void 0;
95
+ }
96
+ const initial = resolveApiValue(definition.body, view, {});
97
+ const custom = resolveApiValue(payload?.body, view, {});
98
+ return defu(custom, initial);
99
+ }
100
+ export function createAction(definition, mutations, view, key) {
101
+ const globalError = ref(null);
102
+ const globalStatus = ref(ActionStatus.IDLE);
103
+ const loading = computed(() => {
104
+ return globalStatus.value === ActionStatus.PENDING;
105
+ });
106
+ let data = null;
107
+ let currentController = null;
108
+ let abortController = null;
109
+ async function execute(payload) {
110
+ await nextTick();
111
+ if (loading.value) {
112
+ const concurrent = payload?.concurrent ?? definition.api?.concurrent ?? ActionConcurrent.BLOCK;
113
+ switch (concurrent) {
114
+ case ActionConcurrent.BLOCK: {
115
+ definition.logger?.error("Action blocked by concurrent guard", {
116
+ action: key
117
+ });
118
+ throw createConcurrentError();
119
+ }
120
+ case ActionConcurrent.SKIP: {
121
+ definition.logger?.warn("Action skipped by concurrent guard", {
122
+ action: key
123
+ });
124
+ return currentController;
125
+ }
126
+ case ActionConcurrent.CANCEL: {
127
+ definition.logger?.warn("Action cancelling previous execution", {
128
+ action: key
129
+ });
130
+ abortController?.abort();
131
+ }
132
+ }
133
+ }
134
+ abortController = new AbortController();
135
+ const activeStatus = payload?.bind?.status ?? globalStatus;
136
+ const activeError = payload?.bind?.error ?? globalError;
137
+ activeStatus.value = ActionStatus.PENDING;
138
+ activeError.value = null;
139
+ currentController = (async () => {
140
+ try {
141
+ let result;
142
+ const committer = createCommitter(mutations);
143
+ if (definition.api) {
144
+ let response;
145
+ try {
146
+ const apiPayload = {
147
+ ...payload,
148
+ signal: payload?.signal ?? abortController.signal
149
+ };
150
+ const url = resolveApiUrl(definition.api, view);
151
+ definition.logger?.debug("Action API request", {
152
+ action: key,
153
+ method: definition.api.method,
154
+ url
155
+ });
156
+ response = await $fetch(url, {
157
+ method: definition.api.method,
158
+ headers: resolveApiHeaders(definition.api, view, apiPayload),
159
+ query: resolveApiQuery(definition.api, view, apiPayload),
160
+ body: resolveApiBody(definition.api, view, apiPayload),
161
+ timeout: apiPayload?.timeout ?? definition.api.timeout,
162
+ signal: apiPayload?.signal
163
+ });
164
+ definition.logger?.debug("Action API response received", {
165
+ action: key,
166
+ method: definition.api.method,
167
+ url
168
+ });
169
+ } catch (error) {
170
+ const errorMessage = error?.message ?? "API request failed";
171
+ const errorOptions = {
172
+ status: error?.status ?? error?.response?.status,
173
+ statusText: error?.statusText ?? error?.response?.statusText,
174
+ data: error?.data ?? error?.response?._data
175
+ };
176
+ definition.logger?.error("Action API error", {
177
+ action: key,
178
+ error: errorMessage
179
+ });
180
+ throw createApiError(errorMessage, errorOptions);
181
+ }
182
+ if (definition.handle) {
183
+ const handler = definition.handle;
184
+ try {
185
+ definition.logger?.debug("Action handle phase", {
186
+ action: key
187
+ });
188
+ result = await handler({
189
+ view,
190
+ commit: committer,
191
+ async api() {
192
+ return response;
193
+ }
194
+ });
195
+ } catch (handleError) {
196
+ if (handleError instanceof ApiError || handleError instanceof HandleError) {
197
+ throw handleError;
198
+ }
199
+ definition.logger?.error("Action handle error", {
200
+ action: key,
201
+ error: handleError?.message
202
+ });
203
+ throw createHandleError(handleError);
204
+ }
205
+ } else {
206
+ result = response;
207
+ }
208
+ } else if (definition.handle) {
209
+ const handler = definition.handle;
210
+ try {
211
+ definition.logger?.debug("Action handle phase", {
212
+ action: key
213
+ });
214
+ result = await handler({
215
+ view,
216
+ commit: committer
217
+ });
218
+ } catch (handleError) {
219
+ if (handleError instanceof HandleError) {
220
+ throw handleError;
221
+ }
222
+ definition.logger?.error("Action handle error", {
223
+ action: key,
224
+ error: handleError?.message
225
+ });
226
+ throw createHandleError(handleError);
227
+ }
228
+ } else {
229
+ result = void 0;
230
+ }
231
+ if (payload?.transformer) {
232
+ result = payload.transformer(result);
233
+ }
234
+ if (definition.commit) {
235
+ try {
236
+ definition.logger?.debug("Action commit phase", {
237
+ action: key,
238
+ model: definition.commit.model,
239
+ mode: definition.commit.mode
240
+ });
241
+ executeCommit(
242
+ {
243
+ ...definition.commit,
244
+ mode: payload?.commit?.mode ?? definition.commit.mode
245
+ },
246
+ mutations,
247
+ result
248
+ );
249
+ } catch (commitError) {
250
+ definition.logger?.error("Action commit error", {
251
+ action: key,
252
+ error: commitError?.message
253
+ });
254
+ throw createCommitError(commitError);
255
+ }
256
+ }
257
+ data = result;
258
+ activeStatus.value = ActionStatus.SUCCESS;
259
+ definition.logger?.debug("Action success", {
260
+ action: key
261
+ });
262
+ return result;
263
+ } catch (actionError) {
264
+ activeError.value = actionError;
265
+ activeStatus.value = ActionStatus.ERROR;
266
+ throw actionError;
267
+ } finally {
268
+ currentController = null;
269
+ abortController = null;
270
+ }
271
+ })();
272
+ return currentController;
273
+ }
274
+ const action = Object.assign(execute, {
275
+ get loading() {
276
+ return loading;
277
+ },
278
+ get error() {
279
+ return readonly(globalError);
280
+ },
281
+ get status() {
282
+ return readonly(globalStatus);
283
+ },
284
+ get data() {
285
+ return data;
286
+ },
287
+ reset() {
288
+ globalError.value = null;
289
+ globalStatus.value = ActionStatus.IDLE;
290
+ data = null;
291
+ }
292
+ });
293
+ return action;
294
+ }
@@ -0,0 +1,12 @@
1
+ import type { Store as SourceStore, BaseState } from "@harlem/core";
2
+ import { type Model, type ModelStateOf, type MutationsOneOptions, type MutationsManyOptions, type Mutations } from "../types/model.js";
3
+ import { type ActionCommitter, ActionOneMode, ActionManyMode } from "../types/action.js";
4
+ export declare function initializeState<M extends Model>(model: M): ModelStateOf<M>;
5
+ export declare function createMutations<M extends Model>(source: SourceStore<BaseState>, model: M): Mutations<M>;
6
+ export declare function executeCommit<M extends Model>(definition: {
7
+ model: keyof M;
8
+ mode: ActionOneMode | ActionManyMode;
9
+ value?: unknown;
10
+ options?: MutationsOneOptions | MutationsManyOptions;
11
+ }, mutations: Mutations<M>, result?: unknown): void;
12
+ export declare function createCommitter<M extends Model>(mutations: Mutations<M>): ActionCommitter<M>;