@wp-typia/rest 0.3.5 → 0.3.6
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 +5 -0
- package/dist/client.d.ts +3 -1
- package/dist/client.js +18 -3
- package/dist/index.d.ts +1 -1
- package/dist/react.d.ts +11 -11
- package/dist/react.js +50 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -37,6 +37,11 @@ const endpoint = createEndpoint<MyRequest, MyResponse>({
|
|
|
37
37
|
const result = await callEndpoint(endpoint, { title: "Hello" });
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
`callEndpoint(...)` returns `EndpointValidationResult<Req, Res>`. If request
|
|
41
|
+
validation fails before transport execution, the result keeps
|
|
42
|
+
`validationTarget: "request"`. Response validation runs after transport and uses
|
|
43
|
+
`validationTarget: "response"`.
|
|
44
|
+
|
|
40
45
|
If you need a canonical REST URL for a route path, use:
|
|
41
46
|
|
|
42
47
|
```ts
|
package/dist/client.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { APIFetchOptions, ApiFetch } from "@wordpress/api-fetch";
|
|
2
|
+
import type { EndpointValidationResult } from "@wp-typia/api-client";
|
|
2
3
|
import { type ValidationLike, type ValidationResult } from "./internal/runtime-primitives.js";
|
|
3
4
|
export type { ValidationError, ValidationLike, ValidationResult } from "./internal/runtime-primitives.js";
|
|
4
5
|
export { isValidationResult, normalizeValidationError, toValidationResult } from "./internal/runtime-primitives.js";
|
|
6
|
+
export type { EndpointRequestValidationResult, EndpointResponseValidationResult, EndpointValidationResult, EndpointValidationTarget, } from "@wp-typia/api-client";
|
|
5
7
|
export interface ValidatedFetch<T> {
|
|
6
8
|
assertFetch(options: APIFetchOptions): Promise<T>;
|
|
7
9
|
fetch(options: APIFetchOptions): Promise<ValidationResult<T>>;
|
|
@@ -25,4 +27,4 @@ export interface EndpointCallOptions {
|
|
|
25
27
|
export declare function resolveRestRouteUrl(routePath: string, root?: string): string;
|
|
26
28
|
export declare function createValidatedFetch<T>(validator: (input: unknown) => ValidationLike<T>, fetchFn?: ApiFetch): ValidatedFetch<T>;
|
|
27
29
|
export declare function createEndpoint<Req, Res>(config: ApiEndpoint<Req, Res>): ApiEndpoint<Req, Res>;
|
|
28
|
-
export declare function callEndpoint<Req, Res>(endpoint: ApiEndpoint<Req, Res>, request: Req, { fetchFn, requestOptions }?: EndpointCallOptions): Promise<
|
|
30
|
+
export declare function callEndpoint<Req, Res>(endpoint: ApiEndpoint<Req, Res>, request: Req, { fetchFn, requestOptions }?: EndpointCallOptions): Promise<EndpointValidationResult<Req, Res>>;
|
package/dist/client.js
CHANGED
|
@@ -169,11 +169,26 @@ export function createValidatedFetch(validator, fetchFn = defaultFetch) {
|
|
|
169
169
|
export function createEndpoint(config) {
|
|
170
170
|
return config;
|
|
171
171
|
}
|
|
172
|
+
function isInvalidValidationResult(validation) {
|
|
173
|
+
return validation.isValid === false;
|
|
174
|
+
}
|
|
175
|
+
function toEndpointRequestValidationResult(validation) {
|
|
176
|
+
return {
|
|
177
|
+
...validation,
|
|
178
|
+
validationTarget: "request",
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function toEndpointResponseValidationResult(validation) {
|
|
182
|
+
return {
|
|
183
|
+
...validation,
|
|
184
|
+
validationTarget: "response",
|
|
185
|
+
};
|
|
186
|
+
}
|
|
172
187
|
export async function callEndpoint(endpoint, request, { fetchFn = defaultFetch, requestOptions } = {}) {
|
|
173
188
|
const requestValidation = endpoint.validateRequest(request);
|
|
174
|
-
if (
|
|
175
|
-
return requestValidation;
|
|
189
|
+
if (isInvalidValidationResult(requestValidation)) {
|
|
190
|
+
return toEndpointRequestValidationResult(requestValidation);
|
|
176
191
|
}
|
|
177
192
|
const payload = await fetchFn(mergeFetchOptions(buildEndpointFetchOptions(endpoint, request), requestOptions));
|
|
178
|
-
return endpoint.validateResponse(payload);
|
|
193
|
+
return toEndpointResponseValidationResult(endpoint.validateResponse(payload));
|
|
179
194
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { createEndpoint, createValidatedFetch, callEndpoint, isValidationResult, normalizeValidationError, resolveRestRouteUrl, toValidationResult, type ApiEndpoint, type EndpointCallOptions, type ValidatedFetch, type ValidationResult, type ValidationError, type ValidationLike, } from "./client.js";
|
|
1
|
+
export { createEndpoint, createValidatedFetch, callEndpoint, isValidationResult, normalizeValidationError, resolveRestRouteUrl, toValidationResult, type ApiEndpoint, type EndpointCallOptions, type EndpointRequestValidationResult, type EndpointResponseValidationResult, type EndpointValidationResult, type EndpointValidationTarget, type ValidatedFetch, type ValidationResult, type ValidationError, type ValidationLike, } from "./client.js";
|
|
2
2
|
export { createHeadersDecoder, createParameterDecoder, createQueryDecoder, } from "./http.js";
|
package/dist/react.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createElement } from "@wordpress/element";
|
|
2
2
|
import type { ApiFetch } from "@wordpress/api-fetch";
|
|
3
|
-
import { type ApiEndpoint, type EndpointCallOptions, type
|
|
3
|
+
import { type ApiEndpoint, type EndpointCallOptions, type EndpointResponseValidationResult, type EndpointValidationResult } from "./client.js";
|
|
4
4
|
type EndpointDataUpdater<T> = T | ((current: T | undefined) => T | undefined);
|
|
5
5
|
export interface EndpointDataClient {
|
|
6
6
|
invalidate<Req, Res>(endpoint: ApiEndpoint<Req, Res>, request?: Req): void;
|
|
@@ -19,31 +19,31 @@ export interface UseEndpointQueryOptions<_Req, Res, Selected = Res> {
|
|
|
19
19
|
fetchFn?: ApiFetch;
|
|
20
20
|
initialData?: Res;
|
|
21
21
|
onError?: (error: unknown) => void | Promise<void>;
|
|
22
|
-
onSuccess?: (data: Selected, validation:
|
|
22
|
+
onSuccess?: (data: Selected, validation: EndpointResponseValidationResult<Res>) => void | Promise<void>;
|
|
23
23
|
resolveCallOptions?: () => EndpointCallOptions | undefined;
|
|
24
24
|
select?: (data: Res) => Selected;
|
|
25
25
|
staleTime?: number;
|
|
26
26
|
}
|
|
27
|
-
export interface UseEndpointQueryResult<Res, Selected = Res> {
|
|
27
|
+
export interface UseEndpointQueryResult<Res, Selected = Res, Req = unknown> {
|
|
28
28
|
data: Selected | undefined;
|
|
29
29
|
error: unknown;
|
|
30
30
|
isFetching: boolean;
|
|
31
31
|
isLoading: boolean;
|
|
32
|
-
refetch: () => Promise<
|
|
33
|
-
validation:
|
|
32
|
+
refetch: () => Promise<EndpointValidationResult<Req, Res>>;
|
|
33
|
+
validation: EndpointValidationResult<Req, Res> | null;
|
|
34
34
|
}
|
|
35
35
|
export interface UseEndpointMutationOptions<Req, Res, Context = unknown> {
|
|
36
36
|
client?: EndpointDataClient;
|
|
37
37
|
fetchFn?: ApiFetch;
|
|
38
|
-
invalidate?: EndpointInvalidateTargets | ((data: Res | undefined, variables: Req, validation:
|
|
38
|
+
invalidate?: EndpointInvalidateTargets | ((data: Res | undefined, variables: Req, validation: EndpointValidationResult<Req, Res>) => EndpointInvalidateTargets);
|
|
39
39
|
onError?: (error: unknown, variables: Req, client: EndpointDataClient, context: Context | undefined) => void | Promise<void>;
|
|
40
40
|
onMutate?: (variables: Req, client: EndpointDataClient) => Context | Promise<Context>;
|
|
41
41
|
onSettled?: (result: {
|
|
42
42
|
data: Res | undefined;
|
|
43
43
|
error: unknown;
|
|
44
|
-
validation:
|
|
44
|
+
validation: EndpointValidationResult<Req, Res> | null;
|
|
45
45
|
}, variables: Req, client: EndpointDataClient, context: Context | undefined) => void | Promise<void>;
|
|
46
|
-
onSuccess?: (data: Res | undefined, variables: Req, validation:
|
|
46
|
+
onSuccess?: (data: Res | undefined, variables: Req, validation: EndpointResponseValidationResult<Res>, client: EndpointDataClient, context: Context | undefined) => void | Promise<void>;
|
|
47
47
|
resolveCallOptions?: (variables: Req) => EndpointCallOptions | undefined;
|
|
48
48
|
}
|
|
49
49
|
export interface UseEndpointMutationResult<Req, Res> {
|
|
@@ -51,9 +51,9 @@ export interface UseEndpointMutationResult<Req, Res> {
|
|
|
51
51
|
error: unknown;
|
|
52
52
|
isPending: boolean;
|
|
53
53
|
mutate: (variables: Req) => void;
|
|
54
|
-
mutateAsync: (variables: Req) => Promise<
|
|
54
|
+
mutateAsync: (variables: Req) => Promise<EndpointValidationResult<Req, Res>>;
|
|
55
55
|
reset: () => void;
|
|
56
|
-
validation:
|
|
56
|
+
validation: EndpointValidationResult<Req, Res> | null;
|
|
57
57
|
}
|
|
58
58
|
export interface EndpointDataProviderProps {
|
|
59
59
|
children?: unknown;
|
|
@@ -62,6 +62,6 @@ export interface EndpointDataProviderProps {
|
|
|
62
62
|
export declare function createEndpointDataClient(): EndpointDataClient;
|
|
63
63
|
export declare function EndpointDataProvider({ children, client, }: EndpointDataProviderProps): ReturnType<typeof createElement>;
|
|
64
64
|
export declare function useEndpointDataClient(): EndpointDataClient;
|
|
65
|
-
export declare function useEndpointQuery<Req, Res, Selected = Res>(endpoint: ApiEndpoint<Req, Res>, request: Req, options?: UseEndpointQueryOptions<Req, Res, Selected>): UseEndpointQueryResult<Res, Selected>;
|
|
65
|
+
export declare function useEndpointQuery<Req, Res, Selected = Res>(endpoint: ApiEndpoint<Req, Res>, request: Req, options?: UseEndpointQueryOptions<Req, Res, Selected>): UseEndpointQueryResult<Res, Selected, Req>;
|
|
66
66
|
export declare function useEndpointMutation<Req, Res, Context = unknown>(endpoint: ApiEndpoint<Req, Res>, options?: UseEndpointMutationOptions<Req, Res, Context>): UseEndpointMutationResult<Req, Res>;
|
|
67
67
|
export {};
|
package/dist/react.js
CHANGED
|
@@ -10,6 +10,18 @@ const EMPTY_SNAPSHOT = {
|
|
|
10
10
|
validation: null,
|
|
11
11
|
};
|
|
12
12
|
const EndpointDataClientContext = createContext(null);
|
|
13
|
+
const endpointIdentityIds = new WeakMap();
|
|
14
|
+
let nextEndpointIdentityId = 0;
|
|
15
|
+
function getStableEndpointIdentity(value) {
|
|
16
|
+
const existing = endpointIdentityIds.get(value);
|
|
17
|
+
if (existing !== undefined) {
|
|
18
|
+
return existing;
|
|
19
|
+
}
|
|
20
|
+
const created = nextEndpointIdentityId;
|
|
21
|
+
nextEndpointIdentityId += 1;
|
|
22
|
+
endpointIdentityIds.set(value, created);
|
|
23
|
+
return created;
|
|
24
|
+
}
|
|
13
25
|
function normalizeCacheValue(value) {
|
|
14
26
|
if (value === undefined) {
|
|
15
27
|
return undefined;
|
|
@@ -45,7 +57,18 @@ function normalizeCacheValue(value) {
|
|
|
45
57
|
return String(value);
|
|
46
58
|
}
|
|
47
59
|
function createEndpointPrefix(endpoint) {
|
|
48
|
-
|
|
60
|
+
const requestValidatorId = getStableEndpointIdentity(endpoint.validateRequest);
|
|
61
|
+
const responseValidatorId = getStableEndpointIdentity(endpoint.validateResponse);
|
|
62
|
+
const requestBuilderId = endpoint.buildRequestOptions !== undefined
|
|
63
|
+
? getStableEndpointIdentity(endpoint.buildRequestOptions)
|
|
64
|
+
: -1;
|
|
65
|
+
return [
|
|
66
|
+
endpoint.method,
|
|
67
|
+
endpoint.path,
|
|
68
|
+
`request:${requestValidatorId}`,
|
|
69
|
+
`response:${responseValidatorId}`,
|
|
70
|
+
`builder:${requestBuilderId}`,
|
|
71
|
+
].join(" ");
|
|
49
72
|
}
|
|
50
73
|
function createCacheKey(endpoint, request) {
|
|
51
74
|
const requestValidation = endpoint.validateRequest(request);
|
|
@@ -103,6 +126,21 @@ function isEntryStale(entry, staleTime) {
|
|
|
103
126
|
function asInternalClient(client) {
|
|
104
127
|
return client;
|
|
105
128
|
}
|
|
129
|
+
function isInvalidValidationResult(validation) {
|
|
130
|
+
return validation.isValid === false;
|
|
131
|
+
}
|
|
132
|
+
function toEndpointRequestValidationResult(validation) {
|
|
133
|
+
return {
|
|
134
|
+
...validation,
|
|
135
|
+
validationTarget: "request",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function toEndpointResponseValidationResult(validation) {
|
|
139
|
+
return {
|
|
140
|
+
...validation,
|
|
141
|
+
validationTarget: "response",
|
|
142
|
+
};
|
|
143
|
+
}
|
|
106
144
|
export function createEndpointDataClient() {
|
|
107
145
|
const entries = new Map();
|
|
108
146
|
function notify(cacheKey) {
|
|
@@ -171,11 +209,11 @@ export function createEndpointDataClient() {
|
|
|
171
209
|
entry.data = resolvedNext;
|
|
172
210
|
entry.error = null;
|
|
173
211
|
entry.updatedAt = Date.now();
|
|
174
|
-
entry.validation = {
|
|
212
|
+
entry.validation = toEndpointResponseValidationResult({
|
|
175
213
|
data: resolvedNext,
|
|
176
214
|
errors: [],
|
|
177
215
|
isValid: true,
|
|
178
|
-
};
|
|
216
|
+
});
|
|
179
217
|
syncSnapshot(entry);
|
|
180
218
|
notify(cacheKey);
|
|
181
219
|
},
|
|
@@ -194,6 +232,9 @@ export function createEndpointDataClient() {
|
|
|
194
232
|
if (validation.isValid) {
|
|
195
233
|
entry.data = validation.data;
|
|
196
234
|
}
|
|
235
|
+
else if (validation.validationTarget === "request") {
|
|
236
|
+
entry.data = undefined;
|
|
237
|
+
}
|
|
197
238
|
syncSnapshot(entry);
|
|
198
239
|
notify(cacheKey);
|
|
199
240
|
},
|
|
@@ -257,11 +298,11 @@ export function createEndpointDataClient() {
|
|
|
257
298
|
entry.data = data;
|
|
258
299
|
entry.error = null;
|
|
259
300
|
entry.updatedAt = Date.now();
|
|
260
|
-
entry.validation = {
|
|
301
|
+
entry.validation = toEndpointResponseValidationResult({
|
|
261
302
|
data,
|
|
262
303
|
errors: [],
|
|
263
304
|
isValid: true,
|
|
264
|
-
};
|
|
305
|
+
});
|
|
265
306
|
syncSnapshot(entry);
|
|
266
307
|
notify(cacheKey);
|
|
267
308
|
},
|
|
@@ -328,8 +369,8 @@ export function useEndpointQuery(endpoint, request, options = {}) {
|
|
|
328
369
|
if (!executeQueryRef.current) {
|
|
329
370
|
executeQueryRef.current = async (force) => {
|
|
330
371
|
const latest = latestRef.current;
|
|
331
|
-
if (
|
|
332
|
-
const invalidValidation = latest.requestValidation;
|
|
372
|
+
if (isInvalidValidationResult(latest.requestValidation)) {
|
|
373
|
+
const invalidValidation = toEndpointRequestValidationResult(latest.requestValidation);
|
|
333
374
|
latest.client.__publishValidation(latest.cacheKey, invalidValidation);
|
|
334
375
|
return invalidValidation;
|
|
335
376
|
}
|
|
@@ -371,11 +412,11 @@ export function useEndpointQuery(endpoint, request, options = {}) {
|
|
|
371
412
|
if (!enabled) {
|
|
372
413
|
return;
|
|
373
414
|
}
|
|
374
|
-
if (
|
|
415
|
+
if (isInvalidValidationResult(prepared.requestValidation)) {
|
|
375
416
|
if (snapshot.validation?.isValid === false) {
|
|
376
417
|
return;
|
|
377
418
|
}
|
|
378
|
-
client.__publishValidation(prepared.cacheKey, prepared.requestValidation);
|
|
419
|
+
client.__publishValidation(prepared.cacheKey, toEndpointRequestValidationResult(prepared.requestValidation));
|
|
379
420
|
return;
|
|
380
421
|
}
|
|
381
422
|
if (snapshot.isFetching) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wp-typia/rest",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "Typed WordPress REST helpers powered by Typia validation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"bun": ">=1.3.11"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@wp-typia/api-client": "^0.4.
|
|
65
|
+
"@wp-typia/api-client": "^0.4.3",
|
|
66
66
|
"@typia/interface": "^12.0.1",
|
|
67
67
|
"@wordpress/api-fetch": "^7.42.0"
|
|
68
68
|
},
|