@diphyx/harlemify 4.0.1 → 5.1.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.
Files changed (47) hide show
  1. package/README.md +30 -44
  2. package/dist/module.d.mts +5 -0
  3. package/dist/module.d.ts +5 -0
  4. package/dist/module.json +1 -1
  5. package/dist/runtime/composables/action.d.ts +16 -3
  6. package/dist/runtime/composables/action.js +47 -3
  7. package/dist/runtime/composables/model.d.ts +22 -0
  8. package/dist/runtime/composables/model.js +32 -0
  9. package/dist/runtime/composables/view.d.ts +33 -0
  10. package/dist/runtime/composables/view.js +54 -0
  11. package/dist/runtime/core/layers/action.d.ts +3 -2
  12. package/dist/runtime/core/layers/action.js +37 -69
  13. package/dist/runtime/core/layers/model.js +14 -0
  14. package/dist/runtime/core/layers/shape.d.ts +2 -2
  15. package/dist/runtime/core/layers/shape.js +3 -2
  16. package/dist/runtime/core/layers/view.d.ts +2 -2
  17. package/dist/runtime/core/layers/view.js +27 -5
  18. package/dist/runtime/core/store.d.ts +5 -23
  19. package/dist/runtime/core/store.js +8 -28
  20. package/dist/runtime/core/types/action.d.ts +79 -121
  21. package/dist/runtime/core/types/action.js +0 -16
  22. package/dist/runtime/core/types/base.d.ts +6 -0
  23. package/dist/runtime/core/types/base.js +0 -0
  24. package/dist/runtime/core/types/model.d.ts +47 -32
  25. package/dist/runtime/core/types/model.js +14 -0
  26. package/dist/runtime/core/types/shape.d.ts +30 -5
  27. package/dist/runtime/core/types/store.d.ts +14 -0
  28. package/dist/runtime/core/types/store.js +0 -0
  29. package/dist/runtime/core/types/view.d.ts +35 -24
  30. package/dist/runtime/core/types/view.js +5 -0
  31. package/dist/runtime/core/utils/action.d.ts +4 -4
  32. package/dist/runtime/core/utils/action.js +217 -207
  33. package/dist/runtime/core/utils/base.d.ts +14 -0
  34. package/dist/runtime/core/utils/base.js +109 -0
  35. package/dist/runtime/core/utils/error.d.ts +21 -0
  36. package/dist/runtime/core/utils/error.js +36 -0
  37. package/dist/runtime/core/utils/model.d.ts +3 -11
  38. package/dist/runtime/core/utils/model.js +104 -110
  39. package/dist/runtime/core/utils/shape.d.ts +6 -3
  40. package/dist/runtime/core/utils/shape.js +218 -14
  41. package/dist/runtime/core/utils/store.d.ts +8 -0
  42. package/dist/runtime/core/utils/store.js +35 -0
  43. package/dist/runtime/core/utils/view.d.ts +3 -4
  44. package/dist/runtime/core/utils/view.js +35 -14
  45. package/dist/runtime/index.d.ts +14 -5
  46. package/dist/runtime/index.js +7 -10
  47. package/package.json +2 -1
@@ -1,4 +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>;
1
+ import { type StoreModel, type ModelDefinitions } from "../types/model.js";
2
+ import type { StoreView, ViewDefinitions } from "../types/view.js";
3
+ import { type ActionCall, type ActionDefinition } from "../types/action.js";
4
+ export declare function createAction<MD extends ModelDefinitions, VD extends ViewDefinitions<MD>, R>(definition: ActionDefinition<MD, VD>, model: StoreModel<MD>, view: StoreView<MD, VD>): ActionCall<R>;
@@ -3,263 +3,277 @@ import { ref, computed, readonly, toValue, nextTick } from "vue";
3
3
  import {
4
4
  ActionApiMethod,
5
5
  ActionStatus,
6
- ActionConcurrent,
7
- DEFINITION
6
+ ActionConcurrent
8
7
  } 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;
8
+ import { trimStart, trimEnd, isEmptyRecord, isPlainObject } from "./base.js";
9
+ import {
10
+ ActionApiError,
11
+ ActionHandlerError,
12
+ ActionCommitError,
13
+ ActionConcurrentError,
14
+ isError,
15
+ toError
16
+ } from "./error.js";
17
+ import { resolveAliasInbound, resolveAliasOutbound } from "./shape.js";
18
+ function resolveValue(value, view, fallback) {
19
+ if (typeof value === "function") {
20
+ return value(view) || fallback;
17
21
  }
22
+ return toValue(value) || fallback;
18
23
  }
19
- class HandleError extends Error {
20
- name = "ActionHandleError";
21
- constructor(cause) {
22
- super(cause.message);
23
- this.cause = cause;
24
+ function resolveApiUrl(definition, view, options) {
25
+ const endpoint = trimEnd(definition.request.endpoint ?? "", "/");
26
+ let path = resolveValue(definition.request.url, view);
27
+ if (options?.params) {
28
+ for (const [key, value] of Object.entries(options.params)) {
29
+ path = path.replace(`:${key}`, encodeURIComponent(value));
30
+ }
24
31
  }
25
- }
26
- class CommitError extends Error {
27
- name = "ActionCommitError";
28
- constructor(cause) {
29
- super(cause.message);
30
- this.cause = cause;
32
+ if (endpoint) {
33
+ return `${endpoint}/${trimStart(path, "/")}`;
31
34
  }
35
+ return path;
32
36
  }
33
- class ConcurrentError extends Error {
34
- name = "ActionConcurrentError";
35
- constructor() {
36
- super("Action is already pending");
37
+ function resolveApiHeaders(definition, view, options) {
38
+ const initial = resolveValue(definition.request.headers, view, {});
39
+ const custom = options?.headers ?? {};
40
+ return defu(custom, initial);
41
+ }
42
+ function resolveApiQuery(definition, view, options) {
43
+ const initial = resolveValue(definition.request.query, view, {});
44
+ const custom = options?.query ?? {};
45
+ return defu(custom, initial);
46
+ }
47
+ function resolveApiBody(definition, view, target, options) {
48
+ if (definition.request.method === ActionApiMethod.GET || definition.request.method === ActionApiMethod.HEAD) {
49
+ return void 0;
50
+ }
51
+ const initial = resolveValue(definition.request.body, view, {});
52
+ const custom = options?.body ?? {};
53
+ const body = defu(custom, initial);
54
+ if (!isPlainObject(body)) {
55
+ return body;
37
56
  }
57
+ if (!isEmptyRecord(target?.aliases())) {
58
+ return resolveAliasOutbound(body, target.aliases());
59
+ }
60
+ return body;
38
61
  }
39
- function createApiError(message, options) {
40
- return new ApiError(message, options);
62
+ function resolveApiMethod(definition, view) {
63
+ return resolveValue(definition.request.method, view, ActionApiMethod.GET);
41
64
  }
42
- function createHandleError(cause) {
43
- return new HandleError(cause);
65
+ function resolveApiTimeout(definition, view, options) {
66
+ if (options?.timeout) {
67
+ return options.timeout;
68
+ }
69
+ if (definition.request.timeout) {
70
+ return resolveValue(definition.request.timeout, view);
71
+ }
72
+ return void 0;
44
73
  }
45
- function createCommitError(cause) {
46
- return new CommitError(cause);
74
+ function resolveApiSignal(options, abortController) {
75
+ if (options?.signal) {
76
+ return options.signal;
77
+ }
78
+ return abortController.signal;
47
79
  }
48
- function createConcurrentError() {
49
- return new ConcurrentError();
80
+ function resolveCommitTarget(commit, model) {
81
+ if (commit) {
82
+ return model[commit.model];
83
+ }
84
+ return void 0;
50
85
  }
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
- };
86
+ function resolveCommitMode(commit, options) {
87
+ if (commit) {
88
+ if (options?.commit?.mode) {
89
+ return options.commit.mode;
90
+ }
91
+ return commit.mode;
64
92
  }
65
- return commit;
93
+ return void 0;
66
94
  }
67
- function resolveApiValue(value, view, fallback) {
68
- if (typeof value === "function") {
69
- const handler = value;
70
- return handler(view) || fallback;
95
+ function resolveCommitValue(commit, data) {
96
+ if (typeof commit.value === "function") {
97
+ return commit.value(data);
71
98
  }
72
- return toValue(value) || fallback;
99
+ return data;
73
100
  }
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(/^\/+/, "")}`;
101
+ function isApiDefinition(definition) {
102
+ return "request" in definition;
103
+ }
104
+ function resolveConcurrent(definition, options) {
105
+ if (options?.concurrent) {
106
+ return options.concurrent;
79
107
  }
80
- return path;
108
+ if (isApiDefinition(definition) && definition.request.concurrent) {
109
+ return definition.request.concurrent;
110
+ }
111
+ return ActionConcurrent.BLOCK;
81
112
  }
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);
113
+ async function executeApi(definition, api, options) {
114
+ try {
115
+ definition.logger?.debug("Action API request", {
116
+ action: definition.key,
117
+ method: api.method,
118
+ url: api.url
119
+ });
120
+ if (options?.transformer?.request) {
121
+ api = options.transformer.request(api);
122
+ }
123
+ const response = await $fetch(api.url, {
124
+ method: api.method,
125
+ headers: api.headers,
126
+ query: api.query,
127
+ body: api.body,
128
+ timeout: api.timeout,
129
+ signal: api.signal,
130
+ responseType: "json"
131
+ });
132
+ definition.logger?.debug("Action API response received", {
133
+ action: definition.key,
134
+ method: api.method,
135
+ url: api.url
136
+ });
137
+ if (options?.transformer?.response) {
138
+ return options.transformer.response(response);
139
+ }
140
+ return response;
141
+ } catch (error) {
142
+ const fetchError = toError(error, ActionApiError);
143
+ definition.logger?.error("Action API error", {
144
+ action: definition.key,
145
+ error: fetchError.message
146
+ });
147
+ throw fetchError;
148
+ }
86
149
  }
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);
150
+ async function executeHandler(definition, model, view) {
151
+ try {
152
+ definition.logger?.debug("Action handler phase", {
153
+ action: definition.key
154
+ });
155
+ return await definition.callback({
156
+ model,
157
+ view
158
+ });
159
+ } catch (error) {
160
+ if (isError(error, ActionApiError, ActionHandlerError)) {
161
+ throw error;
162
+ }
163
+ const handlerError = toError(error, ActionHandlerError);
164
+ definition.logger?.error("Action handler error", {
165
+ action: definition.key,
166
+ error: handlerError.message
167
+ });
168
+ throw handlerError;
169
+ }
91
170
  }
92
- function resolveApiBody(definition, view, payload) {
93
- if (definition.method === ActionApiMethod.GET || definition.method === ActionApiMethod.HEAD) {
94
- return void 0;
171
+ function executeCommit(definition, target, mode, data) {
172
+ if (!definition.commit) {
173
+ return;
174
+ }
175
+ if (!target || !mode) {
176
+ throw new ActionCommitError({
177
+ message: `Model "${definition.commit.model}" is not defined`
178
+ });
179
+ }
180
+ try {
181
+ definition.logger?.debug("Action commit phase", {
182
+ action: definition.key,
183
+ target,
184
+ mode
185
+ });
186
+ if (!isEmptyRecord(target.aliases())) {
187
+ data = resolveAliasInbound(data, target.aliases());
188
+ }
189
+ const value = resolveCommitValue(definition.commit, data);
190
+ target.commit(mode, value, definition.commit.options);
191
+ } catch (error) {
192
+ const commitError = toError(error, ActionCommitError);
193
+ definition.logger?.error("Action commit error", {
194
+ action: definition.key,
195
+ error: commitError.message
196
+ });
197
+ throw commitError;
95
198
  }
96
- const initial = resolveApiValue(definition.body, view, {});
97
- const custom = resolveApiValue(payload?.body, view, {});
98
- return defu(custom, initial);
99
199
  }
100
- export function createAction(definition, mutations, view, key) {
200
+ export function createAction(definition, model, view) {
201
+ definition.logger?.debug("Registering action", {
202
+ action: definition.key,
203
+ type: isApiDefinition(definition) ? "api" : "handler"
204
+ });
205
+ let currentController = null;
206
+ let abortController = null;
101
207
  const globalError = ref(null);
102
208
  const globalStatus = ref(ActionStatus.IDLE);
103
209
  const loading = computed(() => {
104
210
  return globalStatus.value === ActionStatus.PENDING;
105
211
  });
106
- let data = null;
107
- let currentController = null;
108
- let abortController = null;
109
- async function execute(payload) {
212
+ async function execute(options) {
110
213
  await nextTick();
214
+ const concurrent = resolveConcurrent(definition, options);
111
215
  if (loading.value) {
112
- const concurrent = payload?.concurrent ?? definition.api?.concurrent ?? ActionConcurrent.BLOCK;
113
216
  switch (concurrent) {
114
217
  case ActionConcurrent.BLOCK: {
115
218
  definition.logger?.error("Action blocked by concurrent guard", {
116
- action: key
219
+ action: definition.key
117
220
  });
118
- throw createConcurrentError();
221
+ throw new ActionConcurrentError();
119
222
  }
120
223
  case ActionConcurrent.SKIP: {
121
224
  definition.logger?.warn("Action skipped by concurrent guard", {
122
- action: key
225
+ action: definition.key
123
226
  });
124
227
  return currentController;
125
228
  }
126
229
  case ActionConcurrent.CANCEL: {
127
230
  definition.logger?.warn("Action cancelling previous execution", {
128
- action: key
231
+ action: definition.key
129
232
  });
130
233
  abortController?.abort();
131
234
  }
132
235
  }
133
236
  }
134
237
  abortController = new AbortController();
135
- const activeStatus = payload?.bind?.status ?? globalStatus;
136
- const activeError = payload?.bind?.error ?? globalError;
238
+ const activeStatus = options?.bind?.status ?? globalStatus;
239
+ const activeError = options?.bind?.error ?? globalError;
137
240
  activeStatus.value = ActionStatus.PENDING;
138
241
  activeError.value = null;
139
242
  currentController = (async () => {
140
243
  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
- }
244
+ let data;
245
+ if (isApiDefinition(definition)) {
246
+ const target = resolveCommitTarget(definition.commit, model);
247
+ const mode = resolveCommitMode(definition.commit, options);
248
+ const url = resolveApiUrl(definition, view, options);
249
+ const method = resolveApiMethod(definition, view);
250
+ const headers = resolveApiHeaders(definition, view, options);
251
+ const query = resolveApiQuery(definition, view, options);
252
+ const body = resolveApiBody(definition, view, target, options);
253
+ const timeout = resolveApiTimeout(definition, view, options);
254
+ const signal = resolveApiSignal(options, abortController);
255
+ data = await executeApi(
256
+ definition,
257
+ {
258
+ url,
259
+ method,
260
+ headers,
261
+ query,
262
+ body,
263
+ timeout,
264
+ signal
265
+ },
266
+ options
267
+ );
268
+ executeCommit(definition, target, mode, data);
228
269
  } else {
229
- result = void 0;
230
- }
231
- if (payload?.transformer) {
232
- result = payload.transformer(result);
270
+ data = await executeHandler(definition, model, view);
233
271
  }
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
272
  activeStatus.value = ActionStatus.SUCCESS;
259
273
  definition.logger?.debug("Action success", {
260
- action: key
274
+ action: definition.key
261
275
  });
262
- return result;
276
+ return data;
263
277
  } catch (actionError) {
264
278
  activeError.value = actionError;
265
279
  activeStatus.value = ActionStatus.ERROR;
@@ -272,22 +286,18 @@ export function createAction(definition, mutations, view, key) {
272
286
  return currentController;
273
287
  }
274
288
  const action = Object.assign(execute, {
275
- get loading() {
276
- return loading;
277
- },
278
289
  get error() {
279
290
  return readonly(globalError);
280
291
  },
281
292
  get status() {
282
293
  return readonly(globalStatus);
283
294
  },
284
- get data() {
285
- return data;
295
+ get loading() {
296
+ return loading;
286
297
  },
287
298
  reset() {
288
299
  globalError.value = null;
289
300
  globalStatus.value = ActionStatus.IDLE;
290
- data = null;
291
301
  }
292
302
  });
293
303
  return action;
@@ -0,0 +1,14 @@
1
+ export declare function trimStart(value: string, char: string): string;
2
+ export declare function trimEnd(value: string, char: string): string;
3
+ export declare function isObject(value: unknown): value is object;
4
+ export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
5
+ export declare function isEmptyRecord(record: Record<string, unknown> | undefined): record is undefined;
6
+ type ReferenceProxy<T> = {
7
+ value: T;
8
+ } & Record<string | symbol, unknown>;
9
+ export declare function toReactiveProxy<T>(reference: {
10
+ value: T;
11
+ }): ReferenceProxy<T>;
12
+ export declare function debounce<T extends (...args: any[]) => any>(callback: T, delay: number): T;
13
+ export declare function throttle<T extends (...args: any[]) => any>(callback: T, delay: number): T;
14
+ export {};
@@ -0,0 +1,109 @@
1
+ export function trimStart(value, char) {
2
+ return value.replace(new RegExp(`^${char}+`), "");
3
+ }
4
+ export function trimEnd(value, char) {
5
+ return value.replace(new RegExp(`${char}+$`), "");
6
+ }
7
+ export function isObject(value) {
8
+ return value != null && typeof value === "object";
9
+ }
10
+ export function isPlainObject(value) {
11
+ if (!isObject(value)) {
12
+ return false;
13
+ }
14
+ if (Array.isArray(value)) {
15
+ return false;
16
+ }
17
+ return true;
18
+ }
19
+ export function isEmptyRecord(record) {
20
+ if (!record) {
21
+ return true;
22
+ }
23
+ if (Object.keys(record).length === 0) {
24
+ return true;
25
+ }
26
+ return false;
27
+ }
28
+ export function toReactiveProxy(reference) {
29
+ function get(_target, prop) {
30
+ if (prop === "value") {
31
+ return reference.value;
32
+ }
33
+ if (!isObject(reference.value)) {
34
+ return void 0;
35
+ }
36
+ return reference.value[prop];
37
+ }
38
+ function has(_target, prop) {
39
+ if (prop === "value") {
40
+ return true;
41
+ }
42
+ if (!isObject(reference.value)) {
43
+ return false;
44
+ }
45
+ return prop in reference.value;
46
+ }
47
+ function ownKeys() {
48
+ if (!isObject(reference.value)) {
49
+ return [];
50
+ }
51
+ return Reflect.ownKeys(reference.value);
52
+ }
53
+ function getOwnPropertyDescriptor(_target, prop) {
54
+ if (!isObject(reference.value) || !(prop in reference.value)) {
55
+ return void 0;
56
+ }
57
+ return {
58
+ configurable: true,
59
+ enumerable: true,
60
+ value: reference.value[prop]
61
+ };
62
+ }
63
+ return new Proxy(
64
+ {},
65
+ {
66
+ get,
67
+ has,
68
+ ownKeys,
69
+ getOwnPropertyDescriptor
70
+ }
71
+ );
72
+ }
73
+ export function debounce(callback, delay) {
74
+ let timer = null;
75
+ return (...args) => {
76
+ if (timer) {
77
+ clearTimeout(timer);
78
+ }
79
+ timer = setTimeout(() => {
80
+ timer = null;
81
+ callback(...args);
82
+ }, delay);
83
+ };
84
+ }
85
+ export function throttle(callback, delay) {
86
+ let lastCall = 0;
87
+ let timer = null;
88
+ return (...args) => {
89
+ const now = Date.now();
90
+ const remaining = delay - (now - lastCall);
91
+ if (remaining <= 0) {
92
+ if (timer) {
93
+ clearTimeout(timer);
94
+ timer = null;
95
+ }
96
+ lastCall = now;
97
+ callback(...args);
98
+ return;
99
+ }
100
+ if (timer) {
101
+ return;
102
+ }
103
+ timer = setTimeout(() => {
104
+ lastCall = Date.now();
105
+ timer = null;
106
+ callback(...args);
107
+ }, remaining);
108
+ };
109
+ }
@@ -0,0 +1,21 @@
1
+ export declare class ActionApiError extends Error {
2
+ name: "ActionApiError";
3
+ status: number;
4
+ statusText: string;
5
+ data: unknown;
6
+ constructor(source: any);
7
+ }
8
+ export declare class ActionHandlerError extends Error {
9
+ name: "ActionHandlerError";
10
+ constructor(source: any);
11
+ }
12
+ export declare class ActionCommitError extends Error {
13
+ name: "ActionCommitError";
14
+ constructor(source: any);
15
+ }
16
+ export declare class ActionConcurrentError extends Error {
17
+ name: "ActionConcurrentError";
18
+ constructor();
19
+ }
20
+ export declare function isError(error: unknown, ...types: (abstract new (...args: never[]) => Error)[]): error is Error;
21
+ export declare function toError<T extends Error = Error>(error: unknown, ErrorType?: new (source: unknown) => T): T;