@panneau/data 4.1.0 → 5.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -0
- package/dist/adapter.d.ts +84 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/errors.d.ts +51 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +78 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +4 -456
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -1794
- package/dist/laravel/index.d.ts +17 -0
- package/dist/laravel/index.d.ts.map +1 -0
- package/dist/laravel/index.js +37 -0
- package/dist/laravel/index.js.map +1 -0
- package/dist/query/context.d.ts +15 -0
- package/dist/query/context.d.ts.map +1 -0
- package/dist/query/context.js +34 -0
- package/dist/query/context.js.map +1 -0
- package/dist/query/hooks.d.ts +52 -0
- package/dist/query/hooks.d.ts.map +1 -0
- package/dist/query/hooks.js +299 -0
- package/dist/query/hooks.js.map +1 -0
- package/dist/query/index.d.ts +6 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +6 -0
- package/dist/query/keys.d.ts +17 -0
- package/dist/query/keys.d.ts.map +1 -0
- package/dist/query/keys.js +55 -0
- package/dist/query/keys.js.map +1 -0
- package/dist/query/options.d.ts +18 -0
- package/dist/query/options.d.ts.map +1 -0
- package/dist/query/options.js +30 -0
- package/dist/query/options.js.map +1 -0
- package/dist/query/refresh.d.ts +12 -0
- package/dist/query/refresh.d.ts.map +1 -0
- package/dist/query/refresh.js +24 -0
- package/dist/query/refresh.js.map +1 -0
- package/dist/rest.d.ts +25 -0
- package/dist/rest.d.ts.map +1 -0
- package/dist/rest.js +243 -0
- package/dist/rest.js.map +1 -0
- package/package.json +40 -55
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { queryKeys } from "./keys.js";
|
|
2
|
+
import { keepPreviousData, queryOptions } from "@tanstack/react-query";
|
|
3
|
+
//#region src/query/options.ts
|
|
4
|
+
/** Query options of the definition, for `useQuery()`, prefetching or route loaders. */
|
|
5
|
+
function definitionQueryOptions(adapter) {
|
|
6
|
+
return queryOptions({
|
|
7
|
+
queryKey: queryKeys.definition(),
|
|
8
|
+
queryFn: ({ signal }) => adapter.getDefinition({ signal }),
|
|
9
|
+
staleTime: Infinity
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
/** Query options of a page of items. The previous page stays shown while the next one loads. */
|
|
13
|
+
function resourceListQueryOptions(adapter, resource, query = {}) {
|
|
14
|
+
return queryOptions({
|
|
15
|
+
queryKey: queryKeys.list(resource, query),
|
|
16
|
+
queryFn: ({ signal }) => adapter.list(resource, query, { signal }),
|
|
17
|
+
placeholderData: keepPreviousData
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/** Query options of one item. */
|
|
21
|
+
function resourceItemQueryOptions(adapter, resource, id) {
|
|
22
|
+
return queryOptions({
|
|
23
|
+
queryKey: queryKeys.item(resource, id),
|
|
24
|
+
queryFn: ({ signal }) => adapter.get(resource, id, { signal })
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { definitionQueryOptions, resourceItemQueryOptions, resourceListQueryOptions };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","names":[],"sources":["../../src/query/options.ts"],"sourcesContent":["import {\n type DataTag,\n type QueryKey,\n type UseQueryOptions,\n keepPreviousData,\n queryOptions,\n} from '@tanstack/react-query';\n\nimport type { Definition, Item, ListQuery, ListResponse } from '@panneau/protocol';\n\nimport type { DataAdapter } from '../adapter';\nimport { queryKeys } from './keys';\n\n/**\n * Query options made by the `*QueryOptions()` functions. Their key is tagged with the type of the\n * data, so `queryClient.getQueryData(options.queryKey)` is typed.\n */\nexport type DataQueryOptions<TData, TKey extends QueryKey> = UseQueryOptions<\n TData,\n Error,\n TData,\n TKey\n> & { queryKey: DataTag<TKey, TData, Error> };\n\n/** Query options of the definition, for `useQuery()`, prefetching or route loaders. */\nexport function definitionQueryOptions(\n adapter: DataAdapter,\n): DataQueryOptions<Definition, ReturnType<typeof queryKeys.definition>> {\n return queryOptions({\n queryKey: queryKeys.definition(),\n queryFn: ({ signal }) => adapter.getDefinition({ signal }),\n // The definition only changes with the user or the deployment.\n staleTime: Infinity,\n });\n}\n\n/** Query options of a page of items. The previous page stays shown while the next one loads. */\nexport function resourceListQueryOptions(\n adapter: DataAdapter,\n resource: string,\n query: ListQuery = {},\n): DataQueryOptions<ListResponse, ReturnType<typeof queryKeys.list>> {\n return queryOptions({\n queryKey: queryKeys.list(resource, query),\n queryFn: ({ signal }) => adapter.list(resource, query, { signal }),\n placeholderData: keepPreviousData,\n });\n}\n\n/** Query options of one item. */\nexport function resourceItemQueryOptions(\n adapter: DataAdapter,\n resource: string,\n id: string,\n): DataQueryOptions<Item, ReturnType<typeof queryKeys.item>> {\n return queryOptions({\n queryKey: queryKeys.item(resource, id),\n queryFn: ({ signal }) => adapter.get(resource, id, { signal }),\n });\n}\n"],"mappings":";;;;AAyBA,SAAgB,uBACZ,SACqE;CACrE,OAAO,aAAa;EAChB,UAAU,UAAU,WAAW;EAC/B,UAAU,EAAE,aAAa,QAAQ,cAAc,EAAE,OAAO,CAAC;EAEzD,WAAW;CACf,CAAC;AACL;;AAGA,SAAgB,yBACZ,SACA,UACA,QAAmB,CAAC,GAC6C;CACjE,OAAO,aAAa;EAChB,UAAU,UAAU,KAAK,UAAU,KAAK;EACxC,UAAU,EAAE,aAAa,QAAQ,KAAK,UAAU,OAAO,EAAE,OAAO,CAAC;EACjE,iBAAiB;CACrB,CAAC;AACL;;AAGA,SAAgB,yBACZ,SACA,UACA,IACyD;CACzD,OAAO,aAAa;EAChB,UAAU,UAAU,KAAK,UAAU,EAAE;EACrC,UAAU,EAAE,aAAa,QAAQ,IAAI,UAAU,IAAI,EAAE,OAAO,CAAC;CACjE,CAAC;AACL"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { QueryClient } from '@tanstack/react-query';
|
|
2
|
+
import type { ActionResult, Selection } from '@panneau/protocol';
|
|
3
|
+
/**
|
|
4
|
+
* Invalidates the cached data that an action result asks to refresh:
|
|
5
|
+
*
|
|
6
|
+
* - `none`: nothing;
|
|
7
|
+
* - `items`: the affected items (every item of the resource for a query selection), and the
|
|
8
|
+
* lists, which show them;
|
|
9
|
+
* - `list` (the default): every list and item of the resource.
|
|
10
|
+
*/
|
|
11
|
+
export declare function invalidateActionResult(client: QueryClient, resource: string, result: ActionResult, selection?: Selection): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=refresh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../src/query/refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAIjE;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CACxC,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,EACpB,SAAS,CAAC,EAAE,SAAS,GACtB,OAAO,CAAC,IAAI,CAAC,CAkBf"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { queryKeys } from "./keys.js";
|
|
2
|
+
//#region src/query/refresh.ts
|
|
3
|
+
/**
|
|
4
|
+
* Invalidates the cached data that an action result asks to refresh:
|
|
5
|
+
*
|
|
6
|
+
* - `none`: nothing;
|
|
7
|
+
* - `items`: the affected items (every item of the resource for a query selection), and the
|
|
8
|
+
* lists, which show them;
|
|
9
|
+
* - `list` (the default): every list and item of the resource.
|
|
10
|
+
*/
|
|
11
|
+
async function invalidateActionResult(client, resource, result, selection) {
|
|
12
|
+
const refresh = result.refresh ?? "list";
|
|
13
|
+
if (refresh === "none") return;
|
|
14
|
+
if (refresh === "list") {
|
|
15
|
+
await client.invalidateQueries({ queryKey: queryKeys.resource(resource) });
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const ids = selection !== void 0 && "ids" in selection ? selection.ids : null;
|
|
19
|
+
await Promise.all([client.invalidateQueries({ queryKey: queryKeys.lists(resource) }), ...ids === null ? [client.invalidateQueries({ queryKey: queryKeys.items(resource) })] : ids.map((id) => client.invalidateQueries({ queryKey: queryKeys.item(resource, id) }))]);
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { invalidateActionResult };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=refresh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh.js","names":[],"sources":["../../src/query/refresh.ts"],"sourcesContent":["import type { QueryClient } from '@tanstack/react-query';\n\nimport type { ActionResult, Selection } from '@panneau/protocol';\n\nimport { queryKeys } from './keys';\n\n/**\n * Invalidates the cached data that an action result asks to refresh:\n *\n * - `none`: nothing;\n * - `items`: the affected items (every item of the resource for a query selection), and the\n * lists, which show them;\n * - `list` (the default): every list and item of the resource.\n */\nexport async function invalidateActionResult(\n client: QueryClient,\n resource: string,\n result: ActionResult,\n selection?: Selection,\n): Promise<void> {\n const refresh = result.refresh ?? 'list';\n if (refresh === 'none') {\n return;\n }\n if (refresh === 'list') {\n await client.invalidateQueries({ queryKey: queryKeys.resource(resource) });\n return;\n }\n const ids = selection !== undefined && 'ids' in selection ? (selection.ids as string[]) : null;\n await Promise.all([\n client.invalidateQueries({ queryKey: queryKeys.lists(resource) }),\n ...(ids === null\n ? [client.invalidateQueries({ queryKey: queryKeys.items(resource) })]\n : ids.map((id) =>\n client.invalidateQueries({ queryKey: queryKeys.item(resource, id) }),\n )),\n ]);\n}\n"],"mappings":";;;;;;;;;;AAcA,eAAsB,uBAClB,QACA,UACA,QACA,WACa;CACb,MAAM,UAAU,OAAO,WAAW;CAClC,IAAI,YAAY,QACZ;CAEJ,IAAI,YAAY,QAAQ;EACpB,MAAM,OAAO,kBAAkB,EAAE,UAAU,UAAU,SAAS,QAAQ,EAAE,CAAC;EACzE;CACJ;CACA,MAAM,MAAM,cAAc,KAAA,KAAa,SAAS,YAAa,UAAU,MAAmB;CAC1F,MAAM,QAAQ,IAAI,CACd,OAAO,kBAAkB,EAAE,UAAU,UAAU,MAAM,QAAQ,EAAE,CAAC,GAChE,GAAI,QAAQ,OACN,CAAC,OAAO,kBAAkB,EAAE,UAAU,UAAU,MAAM,QAAQ,EAAE,CAAC,CAAC,IAClE,IAAI,KAAK,OACL,OAAO,kBAAkB,EAAE,UAAU,UAAU,KAAK,UAAU,EAAE,EAAE,CAAC,CACvE,CAAE,CACX;AACL"}
|
package/dist/rest.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Problem } from '@panneau/protocol';
|
|
2
|
+
import type { DataAdapter } from './adapter';
|
|
3
|
+
import { type ApiError } from './errors';
|
|
4
|
+
export interface RestAdapterOptions {
|
|
5
|
+
/** URL of the API, as `api.baseUrl` in the definition (`/panneau/api`). */
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
/** The `fetch` function to use. Defaults to the global one. */
|
|
8
|
+
fetch?: (input: string, init: RequestInit) => Promise<Response>;
|
|
9
|
+
/** Headers added to every request, or a function that returns them for each request. */
|
|
10
|
+
headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);
|
|
11
|
+
/** Whether requests send cookies (`fetch`'s `credentials`). */
|
|
12
|
+
credentials?: RequestCredentials;
|
|
13
|
+
/**
|
|
14
|
+
* Creates the error of a failed response. Return `undefined` to use the default mapping from
|
|
15
|
+
* the status (`createApiError()`). The Laravel preset uses it for `419`.
|
|
16
|
+
*/
|
|
17
|
+
createError?: (problem: Problem, response: Response) => ApiError | undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A `DataAdapter` over the HTTP API of the protocol. Errors (`application/problem+json`) reject
|
|
21
|
+
* with typed errors, updates send `If-Match` from the item version, and list queries use the
|
|
22
|
+
* protocol's query string format.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createRestAdapter(options: RestAdapterOptions): DataAdapter;
|
|
25
|
+
//# sourceMappingURL=rest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"AAAA,OAAO,EAMH,KAAK,OAAO,EAIf,MAAM,mBAAmB,CAAC;AAU3B,OAAO,KAAK,EAAkB,WAAW,EAAU,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,KAAK,QAAQ,EAAwC,MAAM,UAAU,CAAC;AAE/E,MAAM,WAAW,kBAAkB;IAC/B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,wFAAwF;IACxF,OAAO,CAAC,EAAE,WAAW,GAAG,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IACnE,+DAA+D;IAC/D,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,KAAK,QAAQ,GAAG,SAAS,CAAC;CAChF;AAuFD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CAiM1E"}
|
package/dist/rest.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { InvalidResponseError, createApiError } from "./errors.js";
|
|
2
|
+
import { ActionResult, ActionRun, Definition, PROBLEM_CONTENT_TYPE, isProblem, toSearchParams, validate } from "@panneau/protocol";
|
|
3
|
+
//#region src/rest.ts
|
|
4
|
+
var ACCEPT = `application/json, ${PROBLEM_CONTENT_TYPE}`;
|
|
5
|
+
function isBlob(value) {
|
|
6
|
+
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
7
|
+
}
|
|
8
|
+
function hasBlob(value) {
|
|
9
|
+
if (isBlob(value)) return true;
|
|
10
|
+
if (Array.isArray(value)) return value.some(hasBlob);
|
|
11
|
+
if (value !== null && typeof value === "object") return Object.values(value).some(hasBlob);
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
/** Appends a value to form data with bracket keys: `values[tags][]`, `selection[ids][]`. */
|
|
15
|
+
function appendFormData(data, key, value) {
|
|
16
|
+
if (value === void 0) return;
|
|
17
|
+
if (isBlob(value)) data.append(key, value);
|
|
18
|
+
else if (Array.isArray(value)) value.forEach((item) => appendFormData(data, `${key}[]`, item));
|
|
19
|
+
else if (value !== null && typeof value === "object") Object.entries(value).forEach(([name, item]) => appendFormData(data, key === "" ? name : `${key}[${name}]`, item));
|
|
20
|
+
else if (typeof value === "boolean") data.append(key, value ? "1" : "0");
|
|
21
|
+
else data.append(key, value === null ? "" : String(value));
|
|
22
|
+
}
|
|
23
|
+
function encode(path) {
|
|
24
|
+
return encodeURIComponent(path);
|
|
25
|
+
}
|
|
26
|
+
/** Builds the problem of a failed response, from its body when it is one. */
|
|
27
|
+
async function readProblem(response) {
|
|
28
|
+
const body = await response.clone().json().catch(() => null);
|
|
29
|
+
if (isProblem(body)) return body;
|
|
30
|
+
const record = body !== null && typeof body === "object" ? body : {};
|
|
31
|
+
const problem = {
|
|
32
|
+
type: "about:blank",
|
|
33
|
+
title: typeof record.title === "string" ? record.title : typeof record.message === "string" ? record.message : response.statusText || `HTTP ${response.status}`,
|
|
34
|
+
status: response.status
|
|
35
|
+
};
|
|
36
|
+
const errors = record.errors;
|
|
37
|
+
if (errors !== null && typeof errors === "object" && !Array.isArray(errors)) problem.errors = Object.fromEntries(Object.entries(errors).map(([path, messages]) => [path, (Array.isArray(messages) ? messages : [messages]).map(String)]));
|
|
38
|
+
return problem;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A `DataAdapter` over the HTTP API of the protocol. Errors (`application/problem+json`) reject
|
|
42
|
+
* with typed errors, updates send `If-Match` from the item version, and list queries use the
|
|
43
|
+
* protocol's query string format.
|
|
44
|
+
*/
|
|
45
|
+
function createRestAdapter(options) {
|
|
46
|
+
const baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
47
|
+
const fetcher = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
48
|
+
const send = async ({ method = "GET", path, query, body, headers: requestHeaders, signal }) => {
|
|
49
|
+
const headers = new Headers(typeof options.headers === "function" ? await options.headers() : options.headers);
|
|
50
|
+
headers.set("Accept", ACCEPT);
|
|
51
|
+
new Headers(requestHeaders).forEach((value, name) => headers.set(name, value));
|
|
52
|
+
let payload;
|
|
53
|
+
if (body !== void 0) {
|
|
54
|
+
if (hasBlob(body)) {
|
|
55
|
+
const data = new FormData();
|
|
56
|
+
appendFormData(data, "", body);
|
|
57
|
+
payload = data;
|
|
58
|
+
} else {
|
|
59
|
+
headers.set("Content-Type", "application/json");
|
|
60
|
+
payload = JSON.stringify(body);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const search = query?.toString() ?? "";
|
|
64
|
+
const init = {
|
|
65
|
+
method,
|
|
66
|
+
headers
|
|
67
|
+
};
|
|
68
|
+
if (payload !== void 0) init.body = payload;
|
|
69
|
+
if (options.credentials !== void 0) init.credentials = options.credentials;
|
|
70
|
+
if (signal !== void 0) init.signal = signal;
|
|
71
|
+
const response = await fetcher(`${baseUrl}${path}${search !== "" ? `?${search}` : ""}`, init);
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
const problem = await readProblem(response);
|
|
74
|
+
throw options.createError?.(problem, response) ?? createApiError(problem);
|
|
75
|
+
}
|
|
76
|
+
return response;
|
|
77
|
+
};
|
|
78
|
+
const json = async (request) => {
|
|
79
|
+
return await (await send(request)).json();
|
|
80
|
+
};
|
|
81
|
+
const data = async (request) => (await json(request)).data;
|
|
82
|
+
return {
|
|
83
|
+
async getDefinition({ signal } = {}) {
|
|
84
|
+
const body = await json({
|
|
85
|
+
path: "/definition",
|
|
86
|
+
signal
|
|
87
|
+
});
|
|
88
|
+
const result = validate(Definition, body);
|
|
89
|
+
if (!result.success) throw new InvalidResponseError("The definition is invalid.", result.issues);
|
|
90
|
+
return result.data;
|
|
91
|
+
},
|
|
92
|
+
list(resource, query = {}, { signal } = {}) {
|
|
93
|
+
return json({
|
|
94
|
+
path: `/resources/${encode(resource)}`,
|
|
95
|
+
query: toSearchParams(query),
|
|
96
|
+
signal
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
get(resource, id, { signal } = {}) {
|
|
100
|
+
return data({
|
|
101
|
+
path: `/resources/${encode(resource)}/${encode(id)}`,
|
|
102
|
+
signal
|
|
103
|
+
});
|
|
104
|
+
},
|
|
105
|
+
create(resource, values, { signal } = {}) {
|
|
106
|
+
return data({
|
|
107
|
+
method: "POST",
|
|
108
|
+
path: `/resources/${encode(resource)}`,
|
|
109
|
+
body: values,
|
|
110
|
+
signal
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
update(resource, id, values, { version, signal } = {}) {
|
|
114
|
+
return data({
|
|
115
|
+
method: "PATCH",
|
|
116
|
+
path: `/resources/${encode(resource)}/${encode(id)}`,
|
|
117
|
+
body: values,
|
|
118
|
+
headers: version !== void 0 && version !== null ? { "If-Match": `"${version}"` } : {},
|
|
119
|
+
signal
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
async delete(resource, id, { signal } = {}) {
|
|
123
|
+
await send({
|
|
124
|
+
method: "DELETE",
|
|
125
|
+
path: `/resources/${encode(resource)}/${encode(id)}`,
|
|
126
|
+
signal
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
async runAction(resource, action, request, { signal } = {}) {
|
|
130
|
+
const response = await send({
|
|
131
|
+
method: "POST",
|
|
132
|
+
path: `/resources/${encode(resource)}/actions/${encode(action)}`,
|
|
133
|
+
body: request,
|
|
134
|
+
signal
|
|
135
|
+
});
|
|
136
|
+
const body = response.status === 204 ? {} : await response.json();
|
|
137
|
+
if (response.status === 202) {
|
|
138
|
+
const run = validate(ActionRun, body.run);
|
|
139
|
+
if (!run.success) throw new InvalidResponseError("The action run is invalid.", run.issues);
|
|
140
|
+
return { run: run.data };
|
|
141
|
+
}
|
|
142
|
+
const result = validate(ActionResult, body);
|
|
143
|
+
if (!result.success) throw new InvalidResponseError("The action result is invalid.", result.issues);
|
|
144
|
+
return { result: result.data };
|
|
145
|
+
},
|
|
146
|
+
async getActionRun(id, { signal } = {}) {
|
|
147
|
+
return (await json({
|
|
148
|
+
path: `/actions/runs/${encode(id)}`,
|
|
149
|
+
signal
|
|
150
|
+
})).run;
|
|
151
|
+
},
|
|
152
|
+
listActionRuns({ signal } = {}) {
|
|
153
|
+
return data({
|
|
154
|
+
path: "/actions/runs",
|
|
155
|
+
signal
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
async cancelActionRun(id, { signal } = {}) {
|
|
159
|
+
await send({
|
|
160
|
+
method: "DELETE",
|
|
161
|
+
path: `/actions/runs/${encode(id)}`,
|
|
162
|
+
signal
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
listMedia(query = {}, { signal } = {}) {
|
|
166
|
+
return json({
|
|
167
|
+
path: "/media",
|
|
168
|
+
query: toSearchParams(query),
|
|
169
|
+
signal
|
|
170
|
+
});
|
|
171
|
+
},
|
|
172
|
+
getMedia(id, { signal } = {}) {
|
|
173
|
+
return data({
|
|
174
|
+
path: `/media/${encode(id)}`,
|
|
175
|
+
signal
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
uploadMedia(file, values = {}, { signal } = {}) {
|
|
179
|
+
return data({
|
|
180
|
+
method: "POST",
|
|
181
|
+
path: "/media",
|
|
182
|
+
body: {
|
|
183
|
+
...values,
|
|
184
|
+
file
|
|
185
|
+
},
|
|
186
|
+
signal
|
|
187
|
+
});
|
|
188
|
+
},
|
|
189
|
+
updateMedia(id, values, { signal } = {}) {
|
|
190
|
+
return data({
|
|
191
|
+
method: "PATCH",
|
|
192
|
+
path: `/media/${encode(id)}`,
|
|
193
|
+
body: values,
|
|
194
|
+
signal
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
async deleteMedia(id, { signal } = {}) {
|
|
198
|
+
await send({
|
|
199
|
+
method: "DELETE",
|
|
200
|
+
path: `/media/${encode(id)}`,
|
|
201
|
+
signal
|
|
202
|
+
});
|
|
203
|
+
},
|
|
204
|
+
getSession({ signal } = {}) {
|
|
205
|
+
return json({
|
|
206
|
+
path: "/auth/session",
|
|
207
|
+
signal
|
|
208
|
+
});
|
|
209
|
+
},
|
|
210
|
+
login(credentials, { signal } = {}) {
|
|
211
|
+
return json({
|
|
212
|
+
method: "POST",
|
|
213
|
+
path: "/auth/login",
|
|
214
|
+
body: credentials,
|
|
215
|
+
signal
|
|
216
|
+
});
|
|
217
|
+
},
|
|
218
|
+
async logout({ signal } = {}) {
|
|
219
|
+
await send({
|
|
220
|
+
method: "POST",
|
|
221
|
+
path: "/auth/logout",
|
|
222
|
+
signal
|
|
223
|
+
});
|
|
224
|
+
},
|
|
225
|
+
search(q, { signal } = {}) {
|
|
226
|
+
return json({
|
|
227
|
+
path: "/search",
|
|
228
|
+
query: new URLSearchParams({ q }),
|
|
229
|
+
signal
|
|
230
|
+
});
|
|
231
|
+
},
|
|
232
|
+
getWidgetData(widget, { signal } = {}) {
|
|
233
|
+
return json({
|
|
234
|
+
path: `/dashboard/widgets/${encode(widget)}`,
|
|
235
|
+
signal
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
export { createRestAdapter };
|
|
242
|
+
|
|
243
|
+
//# sourceMappingURL=rest.js.map
|
package/dist/rest.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.js","names":[],"sources":["../src/rest.ts"],"sourcesContent":["import {\n ActionResult,\n ActionRun,\n Definition,\n type ListQuery,\n PROBLEM_CONTENT_TYPE,\n type Problem,\n isProblem,\n toSearchParams,\n validate,\n} from '@panneau/protocol';\nimport type {\n Item,\n ListResponse,\n Media,\n MediaListResponse,\n SearchResponse,\n Session,\n} from '@panneau/protocol';\n\nimport type { ActionResponse, DataAdapter, Values } from './adapter';\nimport { type ApiError, InvalidResponseError, createApiError } from './errors';\n\nexport interface RestAdapterOptions {\n /** URL of the API, as `api.baseUrl` in the definition (`/panneau/api`). */\n baseUrl: string;\n /** The `fetch` function to use. Defaults to the global one. */\n fetch?: (input: string, init: RequestInit) => Promise<Response>;\n /** Headers added to every request, or a function that returns them for each request. */\n headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);\n /** Whether requests send cookies (`fetch`'s `credentials`). */\n credentials?: RequestCredentials;\n /**\n * Creates the error of a failed response. Return `undefined` to use the default mapping from\n * the status (`createApiError()`). The Laravel preset uses it for `419`.\n */\n createError?: (problem: Problem, response: Response) => ApiError | undefined;\n}\n\ninterface Request {\n method?: string;\n path: string;\n query?: URLSearchParams;\n body?: unknown;\n headers?: HeadersInit;\n signal?: AbortSignal | undefined;\n}\n\nconst ACCEPT = `application/json, ${PROBLEM_CONTENT_TYPE}`;\n\nfunction isBlob(value: unknown): value is Blob {\n return typeof Blob !== 'undefined' && value instanceof Blob;\n}\n\nfunction hasBlob(value: unknown): boolean {\n if (isBlob(value)) {\n return true;\n }\n if (Array.isArray(value)) {\n return value.some(hasBlob);\n }\n if (value !== null && typeof value === 'object') {\n return Object.values(value).some(hasBlob);\n }\n return false;\n}\n\n/** Appends a value to form data with bracket keys: `values[tags][]`, `selection[ids][]`. */\nfunction appendFormData(data: FormData, key: string, value: unknown) {\n if (value === undefined) {\n return;\n }\n if (isBlob(value)) {\n data.append(key, value);\n } else if (Array.isArray(value)) {\n value.forEach((item) => appendFormData(data, `${key}[]`, item));\n } else if (value !== null && typeof value === 'object') {\n Object.entries(value).forEach(([name, item]) =>\n appendFormData(data, key === '' ? name : `${key}[${name}]`, item),\n );\n } else if (typeof value === 'boolean') {\n data.append(key, value ? '1' : '0');\n } else {\n data.append(key, value === null ? '' : String(value));\n }\n}\n\nfunction encode(path: string): string {\n return encodeURIComponent(path);\n}\n\n/** Builds the problem of a failed response, from its body when it is one. */\nasync function readProblem(response: Response): Promise<Problem> {\n const body: unknown = await response\n .clone()\n .json()\n .catch(() => null);\n if (isProblem(body)) {\n return body;\n }\n const record =\n body !== null && typeof body === 'object' ? (body as Record<string, unknown>) : {};\n const problem: Problem = {\n type: 'about:blank',\n title:\n typeof record.title === 'string'\n ? record.title\n : typeof record.message === 'string'\n ? record.message\n : response.statusText || `HTTP ${response.status}`,\n status: response.status,\n };\n const errors = record.errors;\n if (errors !== null && typeof errors === 'object' && !Array.isArray(errors)) {\n problem.errors = Object.fromEntries(\n Object.entries(errors).map(([path, messages]) => [\n path,\n (Array.isArray(messages) ? messages : [messages]).map(String),\n ]),\n );\n }\n return problem;\n}\n\n/**\n * A `DataAdapter` over the HTTP API of the protocol. Errors (`application/problem+json`) reject\n * with typed errors, updates send `If-Match` from the item version, and list queries use the\n * protocol's query string format.\n */\nexport function createRestAdapter(options: RestAdapterOptions): DataAdapter {\n const baseUrl = options.baseUrl.replace(/\\/+$/, '');\n const fetcher = options.fetch ?? ((input, init) => globalThis.fetch(input, init));\n\n const send = async ({\n method = 'GET',\n path,\n query,\n body,\n headers: requestHeaders,\n signal,\n }: Request): Promise<Response> => {\n const headers = new Headers(\n typeof options.headers === 'function' ? await options.headers() : options.headers,\n );\n headers.set('Accept', ACCEPT);\n new Headers(requestHeaders).forEach((value, name) => headers.set(name, value));\n\n let payload: BodyInit | undefined;\n if (body !== undefined) {\n if (hasBlob(body)) {\n const data = new FormData();\n appendFormData(data, '', body);\n payload = data;\n } else {\n headers.set('Content-Type', 'application/json');\n payload = JSON.stringify(body);\n }\n }\n\n const search = query?.toString() ?? '';\n const init: RequestInit = { method, headers };\n if (payload !== undefined) {\n init.body = payload;\n }\n if (options.credentials !== undefined) {\n init.credentials = options.credentials;\n }\n if (signal !== undefined) {\n init.signal = signal;\n }\n const response = await fetcher(\n `${baseUrl}${path}${search !== '' ? `?${search}` : ''}`,\n init,\n );\n if (!response.ok) {\n const problem = await readProblem(response);\n throw options.createError?.(problem, response) ?? createApiError(problem);\n }\n return response;\n };\n\n const json = async <T>(request: Request): Promise<T> => {\n const response = await send(request);\n return (await response.json()) as T;\n };\n\n const data = async <T>(request: Request): Promise<T> => (await json<{ data: T }>(request)).data;\n\n return {\n async getDefinition({ signal } = {}) {\n const body = await json<unknown>({ path: '/definition', signal });\n const result = validate(Definition, body);\n if (!result.success) {\n throw new InvalidResponseError('The definition is invalid.', result.issues);\n }\n return result.data;\n },\n\n list(resource, query: ListQuery = {}, { signal } = {}) {\n return json<ListResponse>({\n path: `/resources/${encode(resource)}`,\n query: toSearchParams(query),\n signal,\n });\n },\n get(resource, id, { signal } = {}) {\n return data<Item>({ path: `/resources/${encode(resource)}/${encode(id)}`, signal });\n },\n create(resource, values, { signal } = {}) {\n return data<Item>({\n method: 'POST',\n path: `/resources/${encode(resource)}`,\n body: values,\n signal,\n });\n },\n update(resource, id, values, { version, signal } = {}) {\n return data<Item>({\n method: 'PATCH',\n path: `/resources/${encode(resource)}/${encode(id)}`,\n body: values,\n headers:\n version !== undefined && version !== null ? { 'If-Match': `\"${version}\"` } : {},\n signal,\n });\n },\n async delete(resource, id, { signal } = {}) {\n await send({\n method: 'DELETE',\n path: `/resources/${encode(resource)}/${encode(id)}`,\n signal,\n });\n },\n\n async runAction(resource, action, request, { signal } = {}) {\n const response = await send({\n method: 'POST',\n path: `/resources/${encode(resource)}/actions/${encode(action)}`,\n body: request,\n signal,\n });\n const body: unknown = response.status === 204 ? {} : await response.json();\n if (response.status === 202) {\n const run = validate(ActionRun, (body as { run?: unknown }).run);\n if (!run.success) {\n throw new InvalidResponseError('The action run is invalid.', run.issues);\n }\n return { run: run.data } satisfies ActionResponse;\n }\n const result = validate(ActionResult, body);\n if (!result.success) {\n throw new InvalidResponseError('The action result is invalid.', result.issues);\n }\n return { result: result.data } satisfies ActionResponse;\n },\n async getActionRun(id, { signal } = {}) {\n return (await json<{ run: ActionRun }>({ path: `/actions/runs/${encode(id)}`, signal }))\n .run;\n },\n listActionRuns({ signal } = {}) {\n return data<ActionRun[]>({ path: '/actions/runs', signal });\n },\n async cancelActionRun(id, { signal } = {}) {\n await send({ method: 'DELETE', path: `/actions/runs/${encode(id)}`, signal });\n },\n\n listMedia(query: ListQuery = {}, { signal } = {}) {\n return json<MediaListResponse>({\n path: '/media',\n query: toSearchParams(query),\n signal,\n });\n },\n getMedia(id, { signal } = {}) {\n return data<Media>({ path: `/media/${encode(id)}`, signal });\n },\n uploadMedia(file, values: Values = {}, { signal } = {}) {\n return data<Media>({\n method: 'POST',\n path: '/media',\n body: { ...values, file },\n signal,\n });\n },\n updateMedia(id, values, { signal } = {}) {\n return data<Media>({\n method: 'PATCH',\n path: `/media/${encode(id)}`,\n body: values,\n signal,\n });\n },\n async deleteMedia(id, { signal } = {}) {\n await send({ method: 'DELETE', path: `/media/${encode(id)}`, signal });\n },\n\n getSession({ signal } = {}) {\n return json<Session>({ path: '/auth/session', signal });\n },\n login(credentials, { signal } = {}) {\n return json<Session>({\n method: 'POST',\n path: '/auth/login',\n body: credentials,\n signal,\n });\n },\n async logout({ signal } = {}) {\n await send({ method: 'POST', path: '/auth/logout', signal });\n },\n\n search(q, { signal } = {}) {\n return json<SearchResponse>({\n path: '/search',\n query: new URLSearchParams({ q }),\n signal,\n });\n },\n getWidgetData(widget, { signal } = {}) {\n return json<unknown>({ path: `/dashboard/widgets/${encode(widget)}`, signal });\n },\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,75 +1,60 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panneau/data",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
],
|
|
8
|
-
"homepage": "https://github.com/folkloreinc/panneau-js",
|
|
3
|
+
"version": "5.0.0-alpha.0",
|
|
4
|
+
"description": "The data layer of Panneau: the DataAdapter interface, the REST adapter of the protocol, its Laravel preset and TanStack Query hooks.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
9
7
|
"repository": {
|
|
10
8
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/folkloreinc/panneau-js.git"
|
|
9
|
+
"url": "git+https://github.com/folkloreinc/panneau-js.git",
|
|
10
|
+
"directory": "packages/data"
|
|
12
11
|
},
|
|
13
|
-
"license": "ISC",
|
|
14
|
-
"author": {
|
|
15
|
-
"name": "Folklore",
|
|
16
|
-
"email": "info@folklore.email"
|
|
17
|
-
},
|
|
18
|
-
"contributors": [
|
|
19
|
-
{
|
|
20
|
-
"name": "David Mongeau-Petitpas",
|
|
21
|
-
"email": "dmp@folklore.email"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"name": "Nicolas Roy-Bourdages",
|
|
25
|
-
"email": "nrb@folklore.email"
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"name": "Julien Carignan",
|
|
29
|
-
"email": "jc@folklore.email"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"name": "Théo Gjini",
|
|
33
|
-
"email": "tg@folklore.email"
|
|
34
|
-
}
|
|
35
|
-
],
|
|
36
12
|
"sideEffects": false,
|
|
37
|
-
"type": "module",
|
|
38
13
|
"exports": {
|
|
39
14
|
".": {
|
|
15
|
+
"@panneau/source": "./src/index.ts",
|
|
40
16
|
"types": "./dist/index.d.ts",
|
|
41
17
|
"default": "./dist/index.js"
|
|
42
|
-
}
|
|
18
|
+
},
|
|
19
|
+
"./laravel": {
|
|
20
|
+
"@panneau/source": "./src/laravel/index.ts",
|
|
21
|
+
"types": "./dist/laravel/index.d.ts",
|
|
22
|
+
"default": "./dist/laravel/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./query": {
|
|
25
|
+
"@panneau/source": "./src/query/index.ts",
|
|
26
|
+
"types": "./dist/query/index.d.ts",
|
|
27
|
+
"default": "./dist/query/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./package.json": "./package.json"
|
|
43
30
|
},
|
|
44
|
-
"module": "dist/index.js",
|
|
45
|
-
"types": "dist/index.d.ts",
|
|
46
31
|
"files": [
|
|
47
|
-
"dist"
|
|
48
|
-
"assets"
|
|
32
|
+
"dist"
|
|
49
33
|
],
|
|
50
34
|
"scripts": {
|
|
51
|
-
"build": "
|
|
52
|
-
"
|
|
35
|
+
"build": "vite build && tsc -p tsconfig.build.json",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"api": "tsc -p tsconfig.build.json && node ../../scripts/api-report.js"
|
|
53
38
|
},
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"@folklore/fetch": "^0.1.21",
|
|
57
|
-
"@folklore/routes": "^0.4.11",
|
|
58
|
-
"@panneau/core": "^4.1.0",
|
|
59
|
-
"@tanstack/react-query": "^5.100.9",
|
|
60
|
-
"lodash-es": "^4.17.21",
|
|
61
|
-
"query-string": "^9.0.0"
|
|
62
|
-
},
|
|
63
|
-
"devDependencies": {
|
|
64
|
-
"react": "^19.2.0",
|
|
65
|
-
"react-dom": "^19.0.0"
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
66
41
|
},
|
|
67
42
|
"peerDependencies": {
|
|
68
|
-
"react": "^
|
|
69
|
-
"react
|
|
43
|
+
"@tanstack/react-query": "^5.0.0",
|
|
44
|
+
"react": "^19.2.0"
|
|
70
45
|
},
|
|
71
|
-
"
|
|
72
|
-
"
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@panneau/protocol": "5.0.0-alpha.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"@tanstack/react-query": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"react": {
|
|
54
|
+
"optional": true
|
|
55
|
+
}
|
|
73
56
|
},
|
|
74
|
-
"
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@panneau/core": "5.0.0-alpha.0"
|
|
59
|
+
}
|
|
75
60
|
}
|