@diphyx/harlemify 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -16
- package/dist/module.json +1 -1
- package/dist/runtime/core/api.d.ts +2 -0
- package/dist/runtime/core/api.js +1 -0
- package/dist/runtime/core/store.d.ts +16 -47
- package/dist/runtime/core/store.js +100 -153
- package/dist/runtime/utils/endpoint.d.ts +7 -42
- package/dist/runtime/utils/endpoint.js +2 -1
- package/dist/runtime/utils/schema.d.ts +7 -1
- package/dist/runtime/utils/schema.js +6 -6
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -11,6 +11,9 @@ API state management for Nuxt powered by [Harlem](https://harlemjs.com/)
|
|
|
11
11
|
- CRUD operations with endpoint status tracking
|
|
12
12
|
- Type-safe endpoint URL parameters
|
|
13
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
|
|
14
17
|
|
|
15
18
|
## Installation
|
|
16
19
|
|
|
@@ -47,24 +50,43 @@ const UserSchema = z.object({
|
|
|
47
50
|
|
|
48
51
|
export type User = z.infer<typeof UserSchema>;
|
|
49
52
|
|
|
50
|
-
export const userStore = createStore(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
+
},
|
|
62
73
|
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
+
},
|
|
66
88
|
},
|
|
67
|
-
|
|
89
|
+
);
|
|
68
90
|
```
|
|
69
91
|
|
|
70
92
|
## Documentation
|
package/dist/module.json
CHANGED
|
@@ -24,10 +24,12 @@ export interface ApiRequestOptions<A extends ApiAction = ApiAction, H extends Ap
|
|
|
24
24
|
headers?: H;
|
|
25
25
|
query?: Q;
|
|
26
26
|
body?: B;
|
|
27
|
+
timeout?: number;
|
|
27
28
|
responseType?: ApiResponseType;
|
|
28
29
|
retry?: number | false;
|
|
29
30
|
retryDelay?: number;
|
|
30
31
|
retryStatusCodes?: number[];
|
|
32
|
+
signal?: AbortSignal;
|
|
31
33
|
}
|
|
32
34
|
export interface ApiOptions {
|
|
33
35
|
url?: string;
|
package/dist/runtime/core/api.js
CHANGED
|
@@ -66,6 +66,7 @@ export function createApi(options) {
|
|
|
66
66
|
retry: requestOptions?.retry,
|
|
67
67
|
retryDelay: requestOptions?.retryDelay,
|
|
68
68
|
retryStatusCodes: requestOptions?.retryStatusCodes,
|
|
69
|
+
signal: requestOptions?.signal,
|
|
69
70
|
onRequestError({ request: request2, options: options2, error }) {
|
|
70
71
|
throw new ApiRequestError({
|
|
71
72
|
method: options2.method,
|
|
@@ -6,10 +6,20 @@ export declare enum StoreMemoryPosition {
|
|
|
6
6
|
LAST = "last"
|
|
7
7
|
}
|
|
8
8
|
import { ApiAction, type ApiActionOptions, type ApiOptions } from "./api.js";
|
|
9
|
-
export declare
|
|
9
|
+
export declare class StoreConfigurationError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
export interface StoreHooks {
|
|
13
|
+
before?: () => Promise<void> | void;
|
|
14
|
+
after?: (error?: Error) => Promise<void> | void;
|
|
15
|
+
}
|
|
16
|
+
export interface StoreOptions {
|
|
10
17
|
api?: ApiOptions;
|
|
18
|
+
indicator?: string;
|
|
19
|
+
hooks?: StoreHooks;
|
|
11
20
|
extensions?: Extension<BaseState>[];
|
|
12
|
-
}
|
|
21
|
+
}
|
|
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): {
|
|
13
23
|
api: () => {
|
|
14
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>;
|
|
15
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>;
|
|
@@ -24,51 +34,10 @@ export declare function createStore<T extends z.ZodRawShape, K extends keyof z.i
|
|
|
24
34
|
};
|
|
25
35
|
endpoints: Record<Endpoint, EndpointMemory>;
|
|
26
36
|
}>, never>;
|
|
27
|
-
memorizedUnit: import("
|
|
28
|
-
memorizedUnits: import("
|
|
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, {}>>[]>;
|
|
29
39
|
hasMemorizedUnits: (...units: (Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>)[]) => Record<string | number, boolean>;
|
|
30
|
-
endpointsStatus:
|
|
31
|
-
getUnitIsIdle: import("@vue/reactivity").ComputedRef<boolean>;
|
|
32
|
-
getUnitIsPending: import("@vue/reactivity").ComputedRef<boolean>;
|
|
33
|
-
getUnitIsSuccess: import("@vue/reactivity").ComputedRef<boolean>;
|
|
34
|
-
getUnitIsFailed: import("@vue/reactivity").ComputedRef<boolean>;
|
|
35
|
-
getUnitsIsIdle: import("@vue/reactivity").ComputedRef<boolean>;
|
|
36
|
-
getUnitsIsPending: import("@vue/reactivity").ComputedRef<boolean>;
|
|
37
|
-
getUnitsIsSuccess: import("@vue/reactivity").ComputedRef<boolean>;
|
|
38
|
-
getUnitsIsFailed: import("@vue/reactivity").ComputedRef<boolean>;
|
|
39
|
-
postUnitIsIdle: import("@vue/reactivity").ComputedRef<boolean>;
|
|
40
|
-
postUnitIsPending: import("@vue/reactivity").ComputedRef<boolean>;
|
|
41
|
-
postUnitIsSuccess: import("@vue/reactivity").ComputedRef<boolean>;
|
|
42
|
-
postUnitIsFailed: import("@vue/reactivity").ComputedRef<boolean>;
|
|
43
|
-
postUnitsIsIdle: import("@vue/reactivity").ComputedRef<boolean>;
|
|
44
|
-
postUnitsIsPending: import("@vue/reactivity").ComputedRef<boolean>;
|
|
45
|
-
postUnitsIsSuccess: import("@vue/reactivity").ComputedRef<boolean>;
|
|
46
|
-
postUnitsIsFailed: import("@vue/reactivity").ComputedRef<boolean>;
|
|
47
|
-
putUnitIsIdle: import("@vue/reactivity").ComputedRef<boolean>;
|
|
48
|
-
putUnitIsPending: import("@vue/reactivity").ComputedRef<boolean>;
|
|
49
|
-
putUnitIsSuccess: import("@vue/reactivity").ComputedRef<boolean>;
|
|
50
|
-
putUnitIsFailed: import("@vue/reactivity").ComputedRef<boolean>;
|
|
51
|
-
putUnitsIsIdle: import("@vue/reactivity").ComputedRef<boolean>;
|
|
52
|
-
putUnitsIsPending: import("@vue/reactivity").ComputedRef<boolean>;
|
|
53
|
-
putUnitsIsSuccess: import("@vue/reactivity").ComputedRef<boolean>;
|
|
54
|
-
putUnitsIsFailed: import("@vue/reactivity").ComputedRef<boolean>;
|
|
55
|
-
patchUnitIsIdle: import("@vue/reactivity").ComputedRef<boolean>;
|
|
56
|
-
patchUnitIsPending: import("@vue/reactivity").ComputedRef<boolean>;
|
|
57
|
-
patchUnitIsSuccess: import("@vue/reactivity").ComputedRef<boolean>;
|
|
58
|
-
patchUnitIsFailed: import("@vue/reactivity").ComputedRef<boolean>;
|
|
59
|
-
patchUnitsIsIdle: import("@vue/reactivity").ComputedRef<boolean>;
|
|
60
|
-
patchUnitsIsPending: import("@vue/reactivity").ComputedRef<boolean>;
|
|
61
|
-
patchUnitsIsSuccess: import("@vue/reactivity").ComputedRef<boolean>;
|
|
62
|
-
patchUnitsIsFailed: import("@vue/reactivity").ComputedRef<boolean>;
|
|
63
|
-
deleteUnitIsIdle: import("@vue/reactivity").ComputedRef<boolean>;
|
|
64
|
-
deleteUnitIsPending: import("@vue/reactivity").ComputedRef<boolean>;
|
|
65
|
-
deleteUnitIsSuccess: import("@vue/reactivity").ComputedRef<boolean>;
|
|
66
|
-
deleteUnitIsFailed: import("@vue/reactivity").ComputedRef<boolean>;
|
|
67
|
-
deleteUnitsIsIdle: import("@vue/reactivity").ComputedRef<boolean>;
|
|
68
|
-
deleteUnitsIsPending: import("@vue/reactivity").ComputedRef<boolean>;
|
|
69
|
-
deleteUnitsIsSuccess: import("@vue/reactivity").ComputedRef<boolean>;
|
|
70
|
-
deleteUnitsIsFailed: import("@vue/reactivity").ComputedRef<boolean>;
|
|
71
|
-
};
|
|
40
|
+
endpointsStatus: import("../utils/endpoint").EndpointsStatusMap<import("vue").ComputedRef<boolean>>;
|
|
72
41
|
setMemorizedUnit: import("@harlem/core").Mutation<z.core.$InferObjectOutput<T, {}> | null, void>;
|
|
73
42
|
setMemorizedUnits: (payload: z.core.$InferObjectOutput<T, {}>[]) => void;
|
|
74
43
|
editMemorizedUnit: import("@harlem/core").Mutation<Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & Partial<z.core.$InferObjectOutput<T, {}>>, void>;
|
|
@@ -82,7 +51,7 @@ export declare function createStore<T extends z.ZodRawShape, K extends keyof z.i
|
|
|
82
51
|
purgeEndpointMemory: (payload?: unknown) => void;
|
|
83
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, {}>>;
|
|
84
53
|
getUnits: (options?: Omit<ApiActionOptions<ApiAction.GET>, "body">) => Promise<z.core.$InferObjectOutput<T, {}>[]>;
|
|
85
|
-
postUnit: (unit: Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>,
|
|
54
|
+
postUnit: (unit: Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>, actionOptions?: ApiActionOptions<ApiAction.POST> & {
|
|
86
55
|
validate?: boolean;
|
|
87
56
|
}) => Promise<Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>>;
|
|
88
57
|
postUnits: (units: (Required<Pick<z.core.$InferObjectOutput<T, {}>, K>> & z.core.$InferObjectOutput<T, {}>)[], options?: ApiActionOptions<ApiAction.POST> & {
|
|
@@ -19,16 +19,41 @@ export var StoreMemoryPosition = /* @__PURE__ */ ((StoreMemoryPosition2) => {
|
|
|
19
19
|
import {
|
|
20
20
|
createApi
|
|
21
21
|
} from "./api.js";
|
|
22
|
+
export class StoreConfigurationError extends Error {
|
|
23
|
+
constructor(message) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "StoreConfigurationError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
22
28
|
export function createStore(name, schema, endpoints, options) {
|
|
23
|
-
const { indicator } = resolveSchema(schema
|
|
29
|
+
const { indicator } = resolveSchema(schema, {
|
|
30
|
+
indicator: options?.indicator
|
|
31
|
+
});
|
|
32
|
+
const hooks = options?.hooks;
|
|
24
33
|
let apiClient;
|
|
34
|
+
let apiInitError = null;
|
|
25
35
|
function api() {
|
|
36
|
+
if (apiInitError) {
|
|
37
|
+
throw apiInitError;
|
|
38
|
+
}
|
|
26
39
|
if (!apiClient) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
+
}
|
|
32
57
|
}
|
|
33
58
|
return apiClient;
|
|
34
59
|
}
|
|
@@ -149,95 +174,83 @@ export function createStore(name, schema, endpoints, options) {
|
|
|
149
174
|
memory
|
|
150
175
|
});
|
|
151
176
|
}
|
|
152
|
-
async function
|
|
153
|
-
|
|
154
|
-
patchEndpointMemoryTo(
|
|
177
|
+
async function withEndpointStatus(key, operation) {
|
|
178
|
+
await hooks?.before?.();
|
|
179
|
+
patchEndpointMemoryTo(key, {
|
|
155
180
|
status: EndpointStatus.PENDING
|
|
156
181
|
});
|
|
157
182
|
try {
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
options2
|
|
161
|
-
);
|
|
162
|
-
setMemorizedUnit(response);
|
|
163
|
-
patchEndpointMemoryTo(Endpoint.GET_UNIT, {
|
|
183
|
+
const result = await operation();
|
|
184
|
+
patchEndpointMemoryTo(key, {
|
|
164
185
|
status: EndpointStatus.SUCCESS
|
|
165
186
|
});
|
|
166
|
-
|
|
187
|
+
await hooks?.after?.();
|
|
188
|
+
return result;
|
|
167
189
|
} catch (error) {
|
|
168
|
-
patchEndpointMemoryTo(
|
|
190
|
+
patchEndpointMemoryTo(key, {
|
|
169
191
|
status: EndpointStatus.FAILED
|
|
170
192
|
});
|
|
193
|
+
await hooks?.after?.(error);
|
|
171
194
|
throw error;
|
|
172
195
|
}
|
|
173
196
|
}
|
|
197
|
+
async function getUnit(unit, options2) {
|
|
198
|
+
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
|
+
);
|
|
204
|
+
setMemorizedUnit(response);
|
|
205
|
+
return response;
|
|
206
|
+
});
|
|
207
|
+
}
|
|
174
208
|
async function getUnits(options2) {
|
|
175
209
|
const endpoint = getEndpoint(endpoints, Endpoint.GET_UNITS);
|
|
176
|
-
|
|
177
|
-
status: EndpointStatus.PENDING
|
|
178
|
-
});
|
|
179
|
-
try {
|
|
210
|
+
return withEndpointStatus(Endpoint.GET_UNITS, async () => {
|
|
180
211
|
const response = await api().get(
|
|
181
212
|
resolveEndpointUrl(endpoint),
|
|
182
213
|
options2
|
|
183
214
|
);
|
|
184
215
|
setMemorizedUnits(response);
|
|
185
|
-
patchEndpointMemoryTo(Endpoint.GET_UNITS, {
|
|
186
|
-
status: EndpointStatus.SUCCESS
|
|
187
|
-
});
|
|
188
216
|
return response;
|
|
189
|
-
}
|
|
190
|
-
patchEndpointMemoryTo(Endpoint.GET_UNITS, {
|
|
191
|
-
status: EndpointStatus.FAILED
|
|
192
|
-
});
|
|
193
|
-
throw error;
|
|
194
|
-
}
|
|
217
|
+
});
|
|
195
218
|
}
|
|
196
|
-
async function postUnit(unit,
|
|
219
|
+
async function postUnit(unit, actionOptions) {
|
|
197
220
|
const endpoint = getEndpoint(endpoints, Endpoint.POST_UNIT);
|
|
198
|
-
const resolvedSchema = resolveSchema(schema,
|
|
199
|
-
|
|
221
|
+
const resolvedSchema = resolveSchema(schema, {
|
|
222
|
+
indicator,
|
|
223
|
+
endpoint,
|
|
224
|
+
unit
|
|
225
|
+
});
|
|
226
|
+
if (actionOptions?.validate) {
|
|
200
227
|
schema.pick(resolvedSchema.keys).parse(unit);
|
|
201
228
|
}
|
|
202
|
-
|
|
203
|
-
status: EndpointStatus.PENDING
|
|
204
|
-
});
|
|
205
|
-
try {
|
|
229
|
+
return withEndpointStatus(Endpoint.POST_UNIT, async () => {
|
|
206
230
|
const response = await api().post(
|
|
207
231
|
resolveEndpointUrl(endpoint, unit),
|
|
208
232
|
{
|
|
209
|
-
...
|
|
210
|
-
body:
|
|
233
|
+
...actionOptions,
|
|
234
|
+
body: actionOptions?.body ?? resolvedSchema.values
|
|
211
235
|
}
|
|
212
236
|
);
|
|
213
237
|
setMemorizedUnit({
|
|
214
238
|
...unit,
|
|
215
239
|
...response
|
|
216
240
|
});
|
|
217
|
-
patchEndpointMemoryTo(Endpoint.POST_UNIT, {
|
|
218
|
-
status: EndpointStatus.SUCCESS
|
|
219
|
-
});
|
|
220
241
|
return response;
|
|
221
|
-
}
|
|
222
|
-
patchEndpointMemoryTo(Endpoint.POST_UNIT, {
|
|
223
|
-
status: EndpointStatus.FAILED
|
|
224
|
-
});
|
|
225
|
-
throw error;
|
|
226
|
-
}
|
|
242
|
+
});
|
|
227
243
|
}
|
|
228
244
|
async function postUnits(units, options2) {
|
|
229
245
|
const endpoint = getEndpoint(endpoints, Endpoint.POST_UNITS);
|
|
230
|
-
|
|
231
|
-
status: EndpointStatus.PENDING
|
|
232
|
-
});
|
|
233
|
-
try {
|
|
246
|
+
return withEndpointStatus(Endpoint.POST_UNITS, async () => {
|
|
234
247
|
const responses = [];
|
|
235
248
|
for (const unit of units) {
|
|
236
|
-
const resolvedSchema = resolveSchema(
|
|
237
|
-
|
|
238
|
-
endpoint
|
|
249
|
+
const resolvedSchema = resolveSchema(schema, {
|
|
250
|
+
indicator,
|
|
251
|
+
endpoint,
|
|
239
252
|
unit
|
|
240
|
-
);
|
|
253
|
+
});
|
|
241
254
|
if (options2?.validate) {
|
|
242
255
|
schema.pick(resolvedSchema.keys).parse(unit);
|
|
243
256
|
}
|
|
@@ -263,27 +276,20 @@ export function createStore(name, schema, endpoints, options) {
|
|
|
263
276
|
setMemorizedUnits(clonedUnits);
|
|
264
277
|
responses.push(response);
|
|
265
278
|
}
|
|
266
|
-
patchEndpointMemoryTo(Endpoint.POST_UNITS, {
|
|
267
|
-
status: EndpointStatus.SUCCESS
|
|
268
|
-
});
|
|
269
279
|
return responses;
|
|
270
|
-
}
|
|
271
|
-
patchEndpointMemoryTo(Endpoint.POST_UNITS, {
|
|
272
|
-
status: EndpointStatus.FAILED
|
|
273
|
-
});
|
|
274
|
-
throw error;
|
|
275
|
-
}
|
|
280
|
+
});
|
|
276
281
|
}
|
|
277
282
|
async function putUnit(unit, options2) {
|
|
278
283
|
const endpoint = getEndpoint(endpoints, Endpoint.PUT_UNIT);
|
|
279
|
-
const resolvedSchema = resolveSchema(schema,
|
|
284
|
+
const resolvedSchema = resolveSchema(schema, {
|
|
285
|
+
indicator,
|
|
286
|
+
endpoint,
|
|
287
|
+
unit
|
|
288
|
+
});
|
|
280
289
|
if (options2?.validate) {
|
|
281
290
|
schema.pick(resolvedSchema.keys).parse(unit);
|
|
282
291
|
}
|
|
283
|
-
|
|
284
|
-
status: EndpointStatus.PENDING
|
|
285
|
-
});
|
|
286
|
-
try {
|
|
292
|
+
return withEndpointStatus(Endpoint.PUT_UNIT, async () => {
|
|
287
293
|
const response = await api().put(
|
|
288
294
|
resolveEndpointUrl(endpoint, unit),
|
|
289
295
|
{
|
|
@@ -295,30 +301,19 @@ export function createStore(name, schema, endpoints, options) {
|
|
|
295
301
|
...unit,
|
|
296
302
|
...response
|
|
297
303
|
});
|
|
298
|
-
patchEndpointMemoryTo(Endpoint.PUT_UNIT, {
|
|
299
|
-
status: EndpointStatus.SUCCESS
|
|
300
|
-
});
|
|
301
304
|
return response;
|
|
302
|
-
}
|
|
303
|
-
patchEndpointMemoryTo(Endpoint.PUT_UNIT, {
|
|
304
|
-
status: EndpointStatus.FAILED
|
|
305
|
-
});
|
|
306
|
-
throw error;
|
|
307
|
-
}
|
|
305
|
+
});
|
|
308
306
|
}
|
|
309
307
|
async function putUnits(units, options2) {
|
|
310
308
|
const endpoint = getEndpoint(endpoints, Endpoint.PUT_UNITS);
|
|
311
|
-
|
|
312
|
-
status: EndpointStatus.PENDING
|
|
313
|
-
});
|
|
314
|
-
try {
|
|
309
|
+
return withEndpointStatus(Endpoint.PUT_UNITS, async () => {
|
|
315
310
|
const responses = [];
|
|
316
311
|
for (const unit of units) {
|
|
317
|
-
const resolvedSchema = resolveSchema(
|
|
318
|
-
|
|
319
|
-
endpoint
|
|
312
|
+
const resolvedSchema = resolveSchema(schema, {
|
|
313
|
+
indicator,
|
|
314
|
+
endpoint,
|
|
320
315
|
unit
|
|
321
|
-
);
|
|
316
|
+
});
|
|
322
317
|
if (options2?.validate) {
|
|
323
318
|
schema.pick(resolvedSchema.keys).parse(unit);
|
|
324
319
|
}
|
|
@@ -337,27 +332,20 @@ export function createStore(name, schema, endpoints, options) {
|
|
|
337
332
|
]);
|
|
338
333
|
responses.push(response);
|
|
339
334
|
}
|
|
340
|
-
patchEndpointMemoryTo(Endpoint.PUT_UNITS, {
|
|
341
|
-
status: EndpointStatus.SUCCESS
|
|
342
|
-
});
|
|
343
335
|
return responses;
|
|
344
|
-
}
|
|
345
|
-
patchEndpointMemoryTo(Endpoint.PUT_UNITS, {
|
|
346
|
-
status: EndpointStatus.FAILED
|
|
347
|
-
});
|
|
348
|
-
throw error;
|
|
349
|
-
}
|
|
336
|
+
});
|
|
350
337
|
}
|
|
351
338
|
async function patchUnit(unit, options2) {
|
|
352
339
|
const endpoint = getEndpoint(endpoints, Endpoint.PATCH_UNIT);
|
|
353
|
-
const resolvedSchema = resolveSchema(schema,
|
|
340
|
+
const resolvedSchema = resolveSchema(schema, {
|
|
341
|
+
indicator,
|
|
342
|
+
endpoint,
|
|
343
|
+
unit
|
|
344
|
+
});
|
|
354
345
|
if (options2?.validate) {
|
|
355
346
|
schema.pick(resolvedSchema.keys).partial().parse(unit);
|
|
356
347
|
}
|
|
357
|
-
|
|
358
|
-
status: EndpointStatus.PENDING
|
|
359
|
-
});
|
|
360
|
-
try {
|
|
348
|
+
return withEndpointStatus(Endpoint.PATCH_UNIT, async () => {
|
|
361
349
|
const response = await api().patch(resolveEndpointUrl(endpoint, unit), {
|
|
362
350
|
...options2,
|
|
363
351
|
body: options2?.body ?? resolvedSchema.values
|
|
@@ -366,30 +354,19 @@ export function createStore(name, schema, endpoints, options) {
|
|
|
366
354
|
...unit,
|
|
367
355
|
...response
|
|
368
356
|
});
|
|
369
|
-
patchEndpointMemoryTo(Endpoint.PATCH_UNIT, {
|
|
370
|
-
status: EndpointStatus.SUCCESS
|
|
371
|
-
});
|
|
372
357
|
return response;
|
|
373
|
-
}
|
|
374
|
-
patchEndpointMemoryTo(Endpoint.PATCH_UNIT, {
|
|
375
|
-
status: EndpointStatus.FAILED
|
|
376
|
-
});
|
|
377
|
-
throw error;
|
|
378
|
-
}
|
|
358
|
+
});
|
|
379
359
|
}
|
|
380
360
|
async function patchUnits(units, options2) {
|
|
381
361
|
const endpoint = getEndpoint(endpoints, Endpoint.PATCH_UNITS);
|
|
382
|
-
|
|
383
|
-
status: EndpointStatus.PENDING
|
|
384
|
-
});
|
|
385
|
-
try {
|
|
362
|
+
return withEndpointStatus(Endpoint.PATCH_UNITS, async () => {
|
|
386
363
|
const responses = [];
|
|
387
364
|
for (const unit of units) {
|
|
388
|
-
const resolvedSchema = resolveSchema(
|
|
389
|
-
|
|
390
|
-
endpoint
|
|
365
|
+
const resolvedSchema = resolveSchema(schema, {
|
|
366
|
+
indicator,
|
|
367
|
+
endpoint,
|
|
391
368
|
unit
|
|
392
|
-
);
|
|
369
|
+
});
|
|
393
370
|
if (options2?.validate) {
|
|
394
371
|
schema.pick(resolvedSchema.keys).partial().parse(unit);
|
|
395
372
|
}
|
|
@@ -405,45 +382,23 @@ export function createStore(name, schema, endpoints, options) {
|
|
|
405
382
|
]);
|
|
406
383
|
responses.push(response);
|
|
407
384
|
}
|
|
408
|
-
patchEndpointMemoryTo(Endpoint.PATCH_UNITS, {
|
|
409
|
-
status: EndpointStatus.SUCCESS
|
|
410
|
-
});
|
|
411
385
|
return responses;
|
|
412
|
-
}
|
|
413
|
-
patchEndpointMemoryTo(Endpoint.PATCH_UNITS, {
|
|
414
|
-
status: EndpointStatus.FAILED
|
|
415
|
-
});
|
|
416
|
-
throw error;
|
|
417
|
-
}
|
|
386
|
+
});
|
|
418
387
|
}
|
|
419
388
|
async function deleteUnit(unit, options2) {
|
|
420
389
|
const endpoint = getEndpoint(endpoints, Endpoint.DELETE_UNIT);
|
|
421
|
-
|
|
422
|
-
status: EndpointStatus.PENDING
|
|
423
|
-
});
|
|
424
|
-
try {
|
|
390
|
+
return withEndpointStatus(Endpoint.DELETE_UNIT, async () => {
|
|
425
391
|
await api().del(
|
|
426
392
|
resolveEndpointUrl(endpoint, unit),
|
|
427
393
|
options2
|
|
428
394
|
);
|
|
429
395
|
dropMemorizedUnit(unit);
|
|
430
|
-
patchEndpointMemoryTo(Endpoint.DELETE_UNIT, {
|
|
431
|
-
status: EndpointStatus.SUCCESS
|
|
432
|
-
});
|
|
433
396
|
return true;
|
|
434
|
-
}
|
|
435
|
-
patchEndpointMemoryTo(Endpoint.DELETE_UNIT, {
|
|
436
|
-
status: EndpointStatus.FAILED
|
|
437
|
-
});
|
|
438
|
-
throw error;
|
|
439
|
-
}
|
|
397
|
+
});
|
|
440
398
|
}
|
|
441
399
|
async function deleteUnits(units, options2) {
|
|
442
400
|
const endpoint = getEndpoint(endpoints, Endpoint.DELETE_UNITS);
|
|
443
|
-
|
|
444
|
-
status: EndpointStatus.PENDING
|
|
445
|
-
});
|
|
446
|
-
try {
|
|
401
|
+
return withEndpointStatus(Endpoint.DELETE_UNITS, async () => {
|
|
447
402
|
for (const unit of units) {
|
|
448
403
|
await api().del(
|
|
449
404
|
resolveEndpointUrl(endpoint, unit),
|
|
@@ -451,16 +406,8 @@ export function createStore(name, schema, endpoints, options) {
|
|
|
451
406
|
);
|
|
452
407
|
dropMemorizedUnits([unit]);
|
|
453
408
|
}
|
|
454
|
-
patchEndpointMemoryTo(Endpoint.DELETE_UNITS, {
|
|
455
|
-
status: EndpointStatus.SUCCESS
|
|
456
|
-
});
|
|
457
409
|
return true;
|
|
458
|
-
}
|
|
459
|
-
patchEndpointMemoryTo(Endpoint.DELETE_UNITS, {
|
|
460
|
-
status: EndpointStatus.FAILED
|
|
461
|
-
});
|
|
462
|
-
throw error;
|
|
463
|
-
}
|
|
410
|
+
});
|
|
464
411
|
}
|
|
465
412
|
return {
|
|
466
413
|
api,
|
|
@@ -25,50 +25,15 @@ export interface EndpointDefinition<T = Record<string, unknown>> {
|
|
|
25
25
|
export interface EndpointMemory {
|
|
26
26
|
status: EndpointStatus;
|
|
27
27
|
}
|
|
28
|
-
|
|
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>;
|
|
29
31
|
export declare function getEndpoint<T = Record<string, unknown>>(endpoints: Partial<Record<Endpoint, EndpointDefinition<T>>> | undefined, key: Endpoint): EndpointDefinition<T>;
|
|
30
32
|
export declare function resolveEndpointUrl<T>(endpoint: EndpointDefinition<T>, params?: {
|
|
31
33
|
[key: string]: unknown;
|
|
32
34
|
}): string;
|
|
33
|
-
export
|
|
34
|
-
|
|
35
|
-
getUnitIsPending: T;
|
|
36
|
-
getUnitIsSuccess: T;
|
|
37
|
-
getUnitIsFailed: T;
|
|
38
|
-
getUnitsIsIdle: T;
|
|
39
|
-
getUnitsIsPending: T;
|
|
40
|
-
getUnitsIsSuccess: T;
|
|
41
|
-
getUnitsIsFailed: T;
|
|
42
|
-
postUnitIsIdle: T;
|
|
43
|
-
postUnitIsPending: T;
|
|
44
|
-
postUnitIsSuccess: T;
|
|
45
|
-
postUnitIsFailed: T;
|
|
46
|
-
postUnitsIsIdle: T;
|
|
47
|
-
postUnitsIsPending: T;
|
|
48
|
-
postUnitsIsSuccess: T;
|
|
49
|
-
postUnitsIsFailed: T;
|
|
50
|
-
putUnitIsIdle: T;
|
|
51
|
-
putUnitIsPending: T;
|
|
52
|
-
putUnitIsSuccess: T;
|
|
53
|
-
putUnitIsFailed: T;
|
|
54
|
-
putUnitsIsIdle: T;
|
|
55
|
-
putUnitsIsPending: T;
|
|
56
|
-
putUnitsIsSuccess: T;
|
|
57
|
-
putUnitsIsFailed: T;
|
|
58
|
-
patchUnitIsIdle: T;
|
|
59
|
-
patchUnitIsPending: T;
|
|
60
|
-
patchUnitIsSuccess: T;
|
|
61
|
-
patchUnitIsFailed: T;
|
|
62
|
-
patchUnitsIsIdle: T;
|
|
63
|
-
patchUnitsIsPending: T;
|
|
64
|
-
patchUnitsIsSuccess: T;
|
|
65
|
-
patchUnitsIsFailed: T;
|
|
66
|
-
deleteUnitIsIdle: T;
|
|
67
|
-
deleteUnitIsPending: T;
|
|
68
|
-
deleteUnitIsSuccess: T;
|
|
69
|
-
deleteUnitIsFailed: T;
|
|
70
|
-
deleteUnitsIsIdle: T;
|
|
71
|
-
deleteUnitsIsPending: T;
|
|
72
|
-
deleteUnitsIsSuccess: T;
|
|
73
|
-
deleteUnitsIsFailed: T;
|
|
35
|
+
export type EndpointsStatusMap<T> = {
|
|
36
|
+
[K in Endpoint as EndpointStatusKey<K, EndpointStatus>]: T;
|
|
74
37
|
};
|
|
38
|
+
export declare function makeEndpointsStatus<T>(getter: (name: string, fn: (state: BaseState) => boolean) => T): EndpointsStatusMap<T>;
|
|
39
|
+
export {};
|
|
@@ -19,7 +19,8 @@ export var EndpointStatus = /* @__PURE__ */ ((EndpointStatus2) => {
|
|
|
19
19
|
return EndpointStatus2;
|
|
20
20
|
})(EndpointStatus || {});
|
|
21
21
|
export function makeEndpointStatusKey(key, status) {
|
|
22
|
-
|
|
22
|
+
const capitalizedStatus = status.charAt(0).toUpperCase() + status.slice(1);
|
|
23
|
+
return `${key}Is${capitalizedStatus}`;
|
|
23
24
|
}
|
|
24
25
|
export function getEndpoint(endpoints, key) {
|
|
25
26
|
const endpoint = endpoints?.[key];
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { ApiAction } from "../core/api.js";
|
|
3
|
+
import type { EndpointDefinition } from "./endpoint.js";
|
|
3
4
|
export interface SchemaMeta {
|
|
4
5
|
indicator?: boolean;
|
|
5
6
|
actions?: ApiAction[];
|
|
6
7
|
}
|
|
7
8
|
export declare function getMeta(field: any): SchemaMeta | undefined;
|
|
8
|
-
export
|
|
9
|
+
export interface ResolveSchemaOptions<S> {
|
|
10
|
+
indicator?: keyof S;
|
|
11
|
+
endpoint?: EndpointDefinition<Partial<S>>;
|
|
12
|
+
unit?: Partial<S>;
|
|
13
|
+
}
|
|
14
|
+
export declare function resolveSchema<T extends z.ZodRawShape, S extends z.infer<z.ZodObject<T>>>(schema: z.ZodObject<T>, options?: ResolveSchemaOptions<S>): {
|
|
9
15
|
indicator: keyof S;
|
|
10
16
|
keys: Record<keyof S, true>;
|
|
11
17
|
values: Partial<S>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export function getMeta(field) {
|
|
2
2
|
return field.meta();
|
|
3
3
|
}
|
|
4
|
-
export function resolveSchema(schema,
|
|
4
|
+
export function resolveSchema(schema, options) {
|
|
5
5
|
const output = {
|
|
6
|
-
indicator: "id",
|
|
6
|
+
indicator: options?.indicator ?? "id",
|
|
7
7
|
keys: {},
|
|
8
8
|
values: {}
|
|
9
9
|
};
|
|
@@ -12,13 +12,13 @@ export function resolveSchema(schema, action, input) {
|
|
|
12
12
|
if (meta?.indicator) {
|
|
13
13
|
output.indicator = key;
|
|
14
14
|
}
|
|
15
|
-
if (!action || !meta?.actions) {
|
|
15
|
+
if (!options?.endpoint?.action || !meta?.actions) {
|
|
16
16
|
continue;
|
|
17
17
|
}
|
|
18
|
-
if (meta?.actions.includes(action)) {
|
|
18
|
+
if (meta?.actions.includes(options.endpoint.action)) {
|
|
19
19
|
output.keys[key] = true;
|
|
20
|
-
if (
|
|
21
|
-
output.values[key] =
|
|
20
|
+
if (options?.unit && key in options.unit) {
|
|
21
|
+
output.values[key] = options.unit[key];
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diphyx/harlemify",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "API state management for Nuxt powered by Harlem",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nuxt",
|
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
"eslint": "^9.0.0",
|
|
53
53
|
"nuxt": "^3.14.0",
|
|
54
54
|
"typescript": "^5.6.0",
|
|
55
|
-
"vitest": "^2.0.0"
|
|
55
|
+
"vitest": "^2.0.0",
|
|
56
|
+
"vue": "^3.5.26"
|
|
56
57
|
},
|
|
57
58
|
"scripts": {
|
|
58
59
|
"cleanup": "pnpm nuxt cleanup && pnpm nuxt cleanup playground",
|