@protobase/server 0.22.3 → 0.22.5
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/dist/check-view-queries.js +12 -1
- package/dist/view-access.js +11 -5
- package/package.json +4 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isGroupChart } from "@protobase/schema/internal";
|
|
2
|
+
import { checkFilter, parseFilter } from "@protobase/schema";
|
|
2
3
|
//#region src/check-view-queries.ts
|
|
3
4
|
const widgetName = {
|
|
4
5
|
facets: "facets filter",
|
|
@@ -17,16 +18,26 @@ const listSortErrors = (model, view) => (view.list?.sort ?? []).flatMap(([name])
|
|
|
17
18
|
if (!field) return [`the list sorts by "${name}", which is not a field of ${model.name}`];
|
|
18
19
|
return field.sortable ? [] : [`the list sorts by "${name}", which is not sortable, so the API refuses it: mark "${name}" .sortable()`];
|
|
19
20
|
});
|
|
21
|
+
const listFilterErrors = (model, view) => {
|
|
22
|
+
const source = view.list?.filter;
|
|
23
|
+
if (source === void 0) return [];
|
|
24
|
+
const parsed = parseFilter(source);
|
|
25
|
+
if (!parsed.ok) return parsed.errors.map((error) => `the list's filter: ${error.message}`);
|
|
26
|
+
if (!parsed.ast) return [];
|
|
27
|
+
const checked = checkFilter(model, parsed.ast);
|
|
28
|
+
return checked.ok ? [] : checked.errors.map((error) => `the list's filter: ${error.message}`);
|
|
29
|
+
};
|
|
20
30
|
const searchErrors = (model, view) => (view.list?.search ?? []).filter((name) => !(model.search ?? []).includes(name)).map((name) => `the list searches "${name}", which ${model.name} does not search: add it to the resource's .search(...)`);
|
|
21
31
|
/**
|
|
22
32
|
* What a view asks the API for that its resource does not allow, which the API refuses only once a page asks: a filter
|
|
23
|
-
* widget or the chart on a field that is not `.filterable()`, a list sorted by one that is not `.sortable()`, and a list
|
|
33
|
+
* widget or the chart on a field that is not `.filterable()`, a list sorted by one that is not `.sortable()`, a list filter that does not parse or check, and a list
|
|
24
34
|
* search on a field the resource does not search. The server's startup checks the rest of a view.
|
|
25
35
|
*/
|
|
26
36
|
const viewQueryErrors = (view, model) => [
|
|
27
37
|
...view.filters.flatMap((widget) => filterableErrors(model, widget.kind === "flags" ? widget.fields : [widget.field], `the ${widgetName[widget.kind]}`)),
|
|
28
38
|
...view.chart ? filterableErrors(model, [isGroupChart(view.chart) ? view.chart.groupBy : view.chart.field], "the chart") : [],
|
|
29
39
|
...listSortErrors(model, view),
|
|
40
|
+
...listFilterErrors(model, view),
|
|
30
41
|
...searchErrors(model, view)
|
|
31
42
|
];
|
|
32
43
|
/** Throws one error listing what every view asks for that its resource does not allow; views of unknown resources are left to the other checks. */
|
package/dist/view-access.js
CHANGED
|
@@ -130,32 +130,38 @@ const listShape = (resource, model, models, prompted) => shapes.object({
|
|
|
130
130
|
props: shapes.refs
|
|
131
131
|
}, { requires: ["props"] })
|
|
132
132
|
})),
|
|
133
|
+
filter: shapes.data,
|
|
133
134
|
default: shapes.data
|
|
134
135
|
}, { after: tidyList(model) });
|
|
135
136
|
const widgetShape = shapes.oneOf({
|
|
136
137
|
range: shapes.object({
|
|
137
138
|
kind: shapes.data,
|
|
138
139
|
field: shapes.field,
|
|
139
|
-
histogram: shapes.data
|
|
140
|
+
histogram: shapes.data,
|
|
141
|
+
secondary: shapes.data
|
|
140
142
|
}, { requires: ["field"] }),
|
|
141
143
|
facets: shapes.object({
|
|
142
144
|
kind: shapes.data,
|
|
143
145
|
field: shapes.field,
|
|
144
|
-
search: shapes.data
|
|
146
|
+
search: shapes.data,
|
|
147
|
+
secondary: shapes.data
|
|
145
148
|
}, { requires: ["field"] }),
|
|
146
149
|
dateRange: shapes.object({
|
|
147
150
|
kind: shapes.data,
|
|
148
151
|
field: shapes.field,
|
|
149
|
-
presets: shapes.data
|
|
152
|
+
presets: shapes.data,
|
|
153
|
+
secondary: shapes.data
|
|
150
154
|
}, { requires: ["field"] }),
|
|
151
155
|
toggle: shapes.object({
|
|
152
156
|
kind: shapes.data,
|
|
153
|
-
field: shapes.field
|
|
157
|
+
field: shapes.field,
|
|
158
|
+
secondary: shapes.data
|
|
154
159
|
}, { requires: ["field"] }),
|
|
155
160
|
flags: shapes.object({
|
|
156
161
|
kind: shapes.data,
|
|
157
162
|
fields: shapes.list(shapes.field, { nonEmpty: true }),
|
|
158
|
-
label: shapes.data
|
|
163
|
+
label: shapes.data,
|
|
164
|
+
secondary: shapes.data
|
|
159
165
|
}, { requires: ["fields"] })
|
|
160
166
|
});
|
|
161
167
|
const layoutShape = (resource, model, models) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/server",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.5",
|
|
4
4
|
"description": "The Protobase REST API as a Hono app, with Better Auth sign-in.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@better-auth/passkey": "^1.7.7",
|
|
33
33
|
"@better-auth/sso": "^1.7.7",
|
|
34
|
-
"@protobase/layout": "0.22.
|
|
35
|
-
"@protobase/query": "0.22.
|
|
36
|
-
"@protobase/schema": "0.22.
|
|
34
|
+
"@protobase/layout": "0.22.5",
|
|
35
|
+
"@protobase/query": "0.22.5",
|
|
36
|
+
"@protobase/schema": "0.22.5",
|
|
37
37
|
"@react-email/render": "^2.1.0",
|
|
38
38
|
"@scalar/hono-api-reference": "^0.12.10",
|
|
39
39
|
"@sentry/core": "^11.7.0",
|