@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.
@@ -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. */
@@ -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",
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.3",
35
- "@protobase/query": "0.22.3",
36
- "@protobase/schema": "0.22.3",
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",