@protobase/server 0.22.4 → 0.22.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.
@@ -1,4 +1,4 @@
1
- import { isGroupChart } from "@protobase/schema/internal";
1
+ import { isGroupChart, viewOfList } from "@protobase/schema/internal";
2
2
  import { checkFilter, parseFilter } from "@protobase/schema";
3
3
  //#region src/check-view-queries.ts
4
4
  const widgetName = {
@@ -45,7 +45,8 @@ const checkViewQueries = (models, views) => {
45
45
  const byName = new Map(models.map((model) => [model.name, model]));
46
46
  const problems = views.flatMap((view) => {
47
47
  const model = byName.get(view.resource);
48
- return model ? viewQueryErrors(view, model).map((problem) => `View "${view.resource}": ${problem}`) : [];
48
+ if (!model) return [];
49
+ return [...viewQueryErrors(view, model).map((problem) => `View "${view.resource}": ${problem}`), ...(view.lists ?? []).flatMap((named) => viewQueryErrors(viewOfList(view, named.name), model).map((problem) => `View "${view.resource}" list "${named.name}": ${problem}`))];
49
50
  });
50
51
  if (problems.length > 0) throw new Error(`The views ask for what their resources do not allow:\n${problems.map((problem) => ` - ${problem}`).join("\n")}`);
51
52
  };
@@ -7,7 +7,7 @@ import { mapDisplayErrors, mapErrors } from "./view-map.js";
7
7
  import { relatedColumnErrors } from "./view-related-column.js";
8
8
  import { editableErrors } from "./view-editable.js";
9
9
  import { conditionProblems } from "@protobase/layout";
10
- import { actionInputErrors, addressErrors, addressPlaceholders, boardErrors, calendarErrors, chartFields, displayFields, fieldRefsIn, hrefField, hrefPlaceholders, layoutItems, linkActionError, promptError, promptFields, updateSetErrors } from "@protobase/schema/internal";
10
+ import { actionInputErrors, addressErrors, addressPlaceholders, boardErrors, calendarErrors, chartFields, displayFields, fieldRefsIn, hrefField, hrefPlaceholders, layoutItems, linkActionError, promptError, promptFields, updateSetErrors, viewOfList } from "@protobase/schema/internal";
11
11
  import { isRecordCondition } from "@protobase/schema";
12
12
  //#region src/check-views.ts
13
13
  const linkFields = (run) => run?.kind !== "link" ? [] : "to" in run ? addressPlaceholders(run.to) : hrefPlaceholders(run.href);
@@ -151,9 +151,7 @@ const listOfErrors = (model, name, models) => {
151
151
  const checkViews = (registry, views, pages = [], fieldTypes = {}) => {
152
152
  const models = Object.fromEntries(registry.entries.map((entry) => [entry.name, entry.model]));
153
153
  const pageNames = new Set(pages);
154
- const problems = views.flatMap((view) => {
155
- const model = models[view.resource];
156
- if (!model) return [];
154
+ const viewProblems = (view, model) => {
157
155
  const related = [...layoutItems(view.layout).flatMap((item) => item.kind === "related" ? relatedErrors(item, view.resource, models).map((error) => `related "${item.title}": ${error}`) : []), ...relatedColumnsErrors(view, model, models)];
158
156
  const photos = [
159
157
  ...(view.list?.displays ?? []).flatMap((display) => display.kind === "cards" && display.photos ? cardPhotosErrors(display.photos, view.resource, models).map((error) => `display "${display.name}" photos: ${error}`) : []),
@@ -193,7 +191,16 @@ const checkViews = (registry, views, pages = [], fieldTypes = {}) => {
193
191
  ...aiActionErrors(view, model),
194
192
  ...inputErrors(view, models),
195
193
  ...createErrors(view, pageNames)
196
- ].map((problem) => `View "${view.resource}": ${problem}`);
194
+ ];
195
+ };
196
+ const problems = views.flatMap((view) => {
197
+ const model = models[view.resource];
198
+ if (!model) return [];
199
+ return [...viewProblems(view, model).map((problem) => `View "${view.resource}": ${problem}`), ...(view.lists ?? []).flatMap((named) => viewProblems({
200
+ ...viewOfList(view, named.name),
201
+ layout: [],
202
+ actions: []
203
+ }, model).map((problem) => `View "${view.resource}" list "${named.name}": ${problem}`))];
197
204
  });
198
205
  if (problems.length > 0) throw new Error(`The views do not match the resources:\n${problems.map((problem) => ` - ${problem}`).join("\n")}`);
199
206
  };
@@ -137,26 +137,31 @@ const widgetShape = shapes.oneOf({
137
137
  range: shapes.object({
138
138
  kind: shapes.data,
139
139
  field: shapes.field,
140
- histogram: shapes.data
140
+ histogram: shapes.data,
141
+ secondary: shapes.data
141
142
  }, { requires: ["field"] }),
142
143
  facets: shapes.object({
143
144
  kind: shapes.data,
144
145
  field: shapes.field,
145
- search: shapes.data
146
+ search: shapes.data,
147
+ secondary: shapes.data
146
148
  }, { requires: ["field"] }),
147
149
  dateRange: shapes.object({
148
150
  kind: shapes.data,
149
151
  field: shapes.field,
150
- presets: shapes.data
152
+ presets: shapes.data,
153
+ secondary: shapes.data
151
154
  }, { requires: ["field"] }),
152
155
  toggle: shapes.object({
153
156
  kind: shapes.data,
154
- field: shapes.field
157
+ field: shapes.field,
158
+ secondary: shapes.data
155
159
  }, { requires: ["field"] }),
156
160
  flags: shapes.object({
157
161
  kind: shapes.data,
158
162
  fields: shapes.list(shapes.field, { nonEmpty: true }),
159
- label: shapes.data
163
+ label: shapes.data,
164
+ secondary: shapes.data
160
165
  }, { requires: ["fields"] })
161
166
  });
162
167
  const layoutShape = (resource, model, models) => {
@@ -250,41 +255,54 @@ const actionShape = (model, models) => shapes.object({
250
255
  }),
251
256
  inputs: inputsShape(models)
252
257
  }, { requires: ["run", "inputs"] });
253
- const viewShape = (resource, model, models, prompted) => shapes.object({
254
- resource: shapes.data,
255
- roles: shapes.data,
256
- title: shapes.field,
257
- searchResult: shapes.object({
258
- title: shapes.list(shapes.field, { nonEmpty: true }),
259
- subtitle: shapes.field
260
- }),
261
- nav: shapes.object({
258
+ const viewShape = (resource, model, models, prompted) => {
259
+ const nav = shapes.object({
262
260
  hidden: shapes.data,
263
261
  group: shapes.data,
264
262
  order: shapes.data,
265
263
  recent: shapes.map((recent) => navRecentErrors(recent, model).length === 0 ? recent : void 0)
266
- }),
267
- names: shapes.data,
268
- icon: shapes.data,
269
- help: shapes.data,
270
- fields: shapes.keys(),
271
- list: listShape(resource, model, models, prompted),
272
- filters: shapes.list(widgetShape),
273
- layout: shapes.list(layoutShape(resource, model, models)),
274
- chart: shapes.map((chart) => chartFields(chart).every((name) => Object.hasOwn(model.fields, name)) ? chart : void 0),
275
- recordMode: shapes.data,
276
- helpWhen: shapes.data,
277
- saveFeedback: shapes.data,
278
- actions: shapes.list(actionShape(model, models)),
279
- listOf: shapes.field,
280
- signIn: shapes.data,
281
- saveSearch: shapes.map((search) => prompted.has(search.resource) || models[search.resource] ? search : void 0),
282
- searchesOf: shapes.map((searches) => searchesOfFor(searches, resource, models)),
283
- import: shapes.data,
284
- export: shapes.data,
285
- create: shapes.data,
286
- forms: shapes.map(() => void 0)
287
- });
264
+ });
265
+ const chart = shapes.map((chart) => chartFields(chart).every((name) => Object.hasOwn(model.fields, name)) ? chart : void 0);
266
+ return shapes.object({
267
+ resource: shapes.data,
268
+ roles: shapes.data,
269
+ title: shapes.field,
270
+ searchResult: shapes.object({
271
+ title: shapes.list(shapes.field, { nonEmpty: true }),
272
+ subtitle: shapes.field
273
+ }),
274
+ nav,
275
+ names: shapes.data,
276
+ icon: shapes.data,
277
+ help: shapes.data,
278
+ fields: shapes.keys(),
279
+ list: listShape(resource, model, models, prompted),
280
+ filters: shapes.list(widgetShape),
281
+ layout: shapes.list(layoutShape(resource, model, models)),
282
+ chart,
283
+ recordMode: shapes.data,
284
+ helpWhen: shapes.data,
285
+ saveFeedback: shapes.data,
286
+ actions: shapes.list(actionShape(model, models)),
287
+ listOf: shapes.field,
288
+ signIn: shapes.data,
289
+ saveSearch: shapes.map((search) => prompted.has(search.resource) || models[search.resource] ? search : void 0),
290
+ searchesOf: shapes.map((searches) => searchesOfFor(searches, resource, models)),
291
+ import: shapes.data,
292
+ export: shapes.data,
293
+ create: shapes.data,
294
+ forms: shapes.map(() => void 0),
295
+ lists: shapes.list(shapes.object({
296
+ name: shapes.data,
297
+ names: shapes.data,
298
+ nav,
299
+ help: shapes.data,
300
+ list: listShape(resource, model, models, prompted),
301
+ filters: shapes.list(widgetShape),
302
+ chart
303
+ }))
304
+ });
305
+ };
288
306
  /**
289
307
  * The view with every reference to a field the caller cannot read removed: list columns, sort, search and displays,
290
308
  * field hints, filter widgets, record sections, maps, galleries and custom components' props, the chart, title and search result, the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/server",
3
- "version": "0.22.4",
3
+ "version": "0.22.6",
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.4",
35
- "@protobase/query": "0.22.4",
36
- "@protobase/schema": "0.22.4",
34
+ "@protobase/layout": "0.22.6",
35
+ "@protobase/query": "0.22.6",
36
+ "@protobase/schema": "0.22.6",
37
37
  "@react-email/render": "^2.1.0",
38
38
  "@scalar/hono-api-reference": "^0.12.10",
39
39
  "@sentry/core": "^11.7.0",