@protobase/schema 0.23.3 → 0.23.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.
@@ -7,11 +7,13 @@ export type AddressCheck = {
7
7
  pages?: ReadonlySet<string>;
8
8
  /** The resource of the record the link sits on, whose fields its `{field}` placeholders name. */
9
9
  source?: ResourceModel;
10
+ /** The resources whose view opens a create page of the app's own, which reads a create address's values whatever their names. */
11
+ createPages?: ReadonlySet<string>;
10
12
  };
11
13
  /**
12
14
  * What is wrong with a link's address against these models: an unknown resource or page, a `{field}` the record it sits
13
15
  * on does not have, a filter or order naming fields the resource does not have, or create values for fields it does not
14
- * have. Empty when it can be followed.
16
+ * have, unless its view opens a create page, which reads them. Empty when it can be followed.
15
17
  */
16
- export declare const addressErrors: (to: AppAddress, { models, pages, source }: AddressCheck) => string[];
18
+ export declare const addressErrors: (to: AppAddress, { models, pages, source, createPages }: AddressCheck) => string[];
17
19
  //#endregion
@@ -32,9 +32,9 @@ const orderErrors = (model, orderBy) => {
32
32
  /**
33
33
  * What is wrong with a link's address against these models: an unknown resource or page, a `{field}` the record it sits
34
34
  * on does not have, a filter or order naming fields the resource does not have, or create values for fields it does not
35
- * have. Empty when it can be followed.
35
+ * have, unless its view opens a create page, which reads them. Empty when it can be followed.
36
36
  */
37
- const addressErrors = (to, { models, pages, source }) => {
37
+ const addressErrors = (to, { models, pages, source, createPages }) => {
38
38
  const placeholders = addressPlaceholders(to).flatMap((name) => {
39
39
  if (!source) return [`"{${name}}" takes a value from the record, but the link sits on none`];
40
40
  return Object.hasOwn(source.fields, name) ? [] : [`"{${name}}" is not a field of ${source.name}`];
@@ -46,6 +46,7 @@ const addressErrors = (to, { models, pages, source }) => {
46
46
  case "create": {
47
47
  const target = Object.hasOwn(models, to.resource) ? models[to.resource] : void 0;
48
48
  if (!target) return [`unknown resource "${to.resource}"`];
49
+ if (to.kind === "create" && createPages?.has(to.resource)) return placeholders;
49
50
  if (to.kind === "create") return [...placeholders, ...Object.keys(to.values ?? {}).filter((name) => !Object.hasOwn(target.fields, name)).map((name) => `values: unknown field "${name}" on ${to.resource}`)];
50
51
  if (to.kind !== "list") return placeholders;
51
52
  return [
@@ -20,4 +20,5 @@ import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-even
20
20
  import { readEventStream } from "./assistant/event-stream.js";
21
21
  import { layoutItems } from "./layout-items.js";
22
22
  import { viewOfList } from "./named-list.js";
23
- export { type AddressCheck, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, calendarErrors, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, layoutItems, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
23
+ import { Locale, isLocale, locales, pickLocale } from "./locale.js";
24
+ export { type AddressCheck, type Locale, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, calendarErrors, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, isLocale, layoutItems, leavesApp, linkActionError, locales, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pickLocale, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
package/dist/internal.js CHANGED
@@ -20,4 +20,5 @@ import { redactSecrets } from "./redact-secrets.js";
20
20
  import { addressErrors } from "./address-errors.js";
21
21
  import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-event.js";
22
22
  import { readEventStream } from "./assistant/event-stream.js";
23
- export { actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, calendarErrors, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, layoutItems, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
23
+ import { isLocale, locales, pickLocale } from "./locale.js";
24
+ export { actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, calendarErrors, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, isLocale, layoutItems, leavesApp, linkActionError, locales, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pickLocale, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
@@ -0,0 +1,11 @@
1
+ //#region src/locale.d.ts
2
+ /** The languages Protobase's built-in screens come in. */
3
+ export declare const locales: readonly ["en", "nl"];
4
+ export type Locale = (typeof locales)[number];
5
+ export declare const isLocale: (value: unknown) => value is Locale;
6
+ /**
7
+ * The first of `preferred`, language tags such as the browser's `nl-BE` or `en`, whose language the screens come in;
8
+ * English when none is.
9
+ */
10
+ export declare const pickLocale: (preferred: readonly string[]) => Locale;
11
+ //#endregion
package/dist/locale.js ADDED
@@ -0,0 +1,13 @@
1
+ //#region src/locale.ts
2
+ /** The languages Protobase's built-in screens come in. */
3
+ const locales = ["en", "nl"];
4
+ const isLocale = (value) => locales.includes(value);
5
+ /**
6
+ * The first of `preferred`, language tags such as the browser's `nl-BE` or `en`, whose language the screens come in;
7
+ * English when none is.
8
+ */
9
+ const pickLocale = (preferred) => {
10
+ return preferred.map((tag) => tag.split("-")[0].toLowerCase()).find(isLocale) ?? "en";
11
+ };
12
+ //#endregion
13
+ export { isLocale, locales, pickLocale };
package/dist/model.d.ts CHANGED
@@ -112,6 +112,8 @@ export type ResourceModel = {
112
112
  history?: true;
113
113
  /** Whether people who may read its records comment on them (`.comments()`). */
114
114
  comments?: true;
115
+ /** Whether open pages refresh as soon as its records change (`.live()`). */
116
+ live?: true;
115
117
  };
116
118
  /** What happened to a record: `delete` and `undelete` include setting and clearing a soft delete field. */
117
119
  export type EventOperation = 'create' | 'update' | 'delete' | 'undelete';
@@ -19,5 +19,6 @@ export type ResourceState = {
19
19
  events?: EventSpec[];
20
20
  history?: boolean;
21
21
  comments?: boolean;
22
+ live?: boolean;
22
23
  };
23
24
  //#endregion
@@ -62,6 +62,7 @@ const assembleModel = (state) => {
62
62
  ...state.owner && { owner: state.owner },
63
63
  ...state.history && { history: true },
64
64
  ...state.comments && { comments: true },
65
+ ...state.live && { live: true },
65
66
  ...state.position && { position: { ...state.position } }
66
67
  };
67
68
  };
@@ -109,6 +109,12 @@ export declare class ResourceBuilder<F extends FieldsInput = {}, K = never> {
109
109
  * [Record comments](website/src/content/docs/reference/comments.mdx).
110
110
  */
111
111
  comments(): ResourceBuilder<F, K>;
112
+ /**
113
+ * Refreshes the pages open on its records and lists as soon as they change, from the API or elsewhere: the server
114
+ * tells each open app which records changed, never their values, and the app reads them again as its user. See
115
+ * [Live updates](website/src/content/docs/reference/live.mdx).
116
+ */
117
+ live(): ResourceBuilder<F, K>;
112
118
  /** The code predicates (`match`) of its events, by event name. */
113
119
  eventMatches(): Record<string, EventMatch<any>>;
114
120
  /**
package/dist/resource.js CHANGED
@@ -128,6 +128,14 @@ var ResourceBuilder = class ResourceBuilder {
128
128
  comments() {
129
129
  return this.next({ comments: true });
130
130
  }
131
+ /**
132
+ * Refreshes the pages open on its records and lists as soon as they change, from the API or elsewhere: the server
133
+ * tells each open app which records changed, never their values, and the app reads them again as its user. See
134
+ * [Live updates](website/src/content/docs/reference/live.mdx).
135
+ */
136
+ live() {
137
+ return this.next({ live: true });
138
+ }
131
139
  /** The code predicates (`match`) of its events, by event name. */
132
140
  eventMatches() {
133
141
  return eventMatches(this.toModel(), this.state.events ?? []);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/schema",
3
- "version": "0.23.3",
3
+ "version": "0.23.5",
4
4
  "description": "Resource, field, view and access definitions for Protobase configs.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {