@protobase/schema 0.15.1 → 0.15.3
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/address-template.d.ts +11 -0
- package/dist/address-template.js +11 -1
- package/dist/fields/file.js +4 -1
- package/dist/file-field.d.ts +6 -0
- package/dist/file-field.js +8 -0
- package/dist/files/file-options.d.ts +2 -0
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +2 -2
- package/dist/model.d.ts +8 -3
- package/dist/resource-model.js +2 -1
- package/dist/view-actions.d.ts +4 -2
- package/dist/view-actions.js +7 -5
- package/package.json +1 -1
|
@@ -13,4 +13,15 @@ export declare const fillAddress: (to: AppAddress, record?: Record<string, unkno
|
|
|
13
13
|
export declare const leavesApp: (href: string) => boolean;
|
|
14
14
|
/** Why an href cannot be a link's `href`: it points inside the app, which takes an address in `to`. */
|
|
15
15
|
export declare const appHrefError: (href: string) => string | undefined;
|
|
16
|
+
/** The field an action's href is made of alone, `{field}`: the record's value is the whole URL, as it is stored. */
|
|
17
|
+
export declare const hrefField: (href: string) => string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Why a link action cannot be built: an `href` that points inside the app (one that is a single `{field}`, the URL the
|
|
20
|
+
* record holds, is fine), or `{host}` in the label of a link that goes `to` an address in the app, which has no host.
|
|
21
|
+
*/
|
|
22
|
+
export declare const linkActionError: (label: string, run: {
|
|
23
|
+
to: AppAddress;
|
|
24
|
+
} | {
|
|
25
|
+
href: string;
|
|
26
|
+
}) => string | undefined;
|
|
16
27
|
//#endregion
|
package/dist/address-template.js
CHANGED
|
@@ -39,5 +39,15 @@ const fillAddress = (to, record = {}) => {
|
|
|
39
39
|
const leavesApp = (href) => /^([a-z][a-z0-9+.-]*:|\/\/)/i.test(href);
|
|
40
40
|
/** Why an href cannot be a link's `href`: it points inside the app, which takes an address in `to`. */
|
|
41
41
|
const appHrefError = (href) => leavesApp(href) ? void 0 : `href "${href}" points inside the app; give the link \`to\` instead, an address such as { kind: 'record', resource: 'orders', key: '{order_id}' }`;
|
|
42
|
+
/** The field an action's href is made of alone, `{field}`: the record's value is the whole URL, as it is stored. */
|
|
43
|
+
const hrefField = (href) => /^\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(href)?.[1];
|
|
44
|
+
/**
|
|
45
|
+
* Why a link action cannot be built: an `href` that points inside the app (one that is a single `{field}`, the URL the
|
|
46
|
+
* record holds, is fine), or `{host}` in the label of a link that goes `to` an address in the app, which has no host.
|
|
47
|
+
*/
|
|
48
|
+
const linkActionError = (label, run) => {
|
|
49
|
+
if ("href" in run) return hrefField(run.href) ? void 0 : appHrefError(run.href);
|
|
50
|
+
return label.includes("{host}") ? "the label names {host}, which only a link with an href has" : void 0;
|
|
51
|
+
};
|
|
42
52
|
//#endregion
|
|
43
|
-
export { addressPlaceholders, appHrefError, fillAddress, hrefPlaceholders, leavesApp };
|
|
53
|
+
export { addressPlaceholders, appHrefError, fillAddress, hrefField, hrefPlaceholders, leavesApp, linkActionError };
|
package/dist/fields/file.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
//#region src/fields/file.ts
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* A file column holds `{provider}:{path}?name=…&size=…` as text, or an https URL with `.externalUrls()`; writes send a
|
|
5
|
+
* ticket from `:upload` instead.
|
|
6
|
+
*/
|
|
4
7
|
const file = {
|
|
5
8
|
type: "file",
|
|
6
9
|
constraints: [],
|
package/dist/file-field.d.ts
CHANGED
|
@@ -27,6 +27,12 @@ export declare class FileField<V> extends Field<V> {
|
|
|
27
27
|
* format: 'webp' } }`. `{ original }` stores that image instead of the upload. Other files get none.
|
|
28
28
|
*/
|
|
29
29
|
variants(variants: Record<string, ImageVariant>, options?: ImageVariantOptions): FileField<V>;
|
|
30
|
+
/**
|
|
31
|
+
* Also takes an https URL of a file elsewhere, such as `https://images.example.com/photos/42.jpg`, stored as it is:
|
|
32
|
+
* never uploaded, without variants, and drawn from that address. See
|
|
33
|
+
* [External URLs](website/src/content/docs/reference/files.mdx#external-urls).
|
|
34
|
+
*/
|
|
35
|
+
externalUrls(): FileField<V>;
|
|
30
36
|
/** The column is nullable: the field may hold no file. */
|
|
31
37
|
optional(): FileField<V | null>;
|
|
32
38
|
/** Never written through the API. */
|
package/dist/file-field.js
CHANGED
|
@@ -49,6 +49,14 @@ var FileField = class FileField extends Field {
|
|
|
49
49
|
...options.original && { original: checkedVariant("The original", options.original) }
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Also takes an https URL of a file elsewhere, such as `https://images.example.com/photos/42.jpg`, stored as it is:
|
|
54
|
+
* never uploaded, without variants, and drawn from that address. See
|
|
55
|
+
* [External URLs](website/src/content/docs/reference/files.mdx#external-urls).
|
|
56
|
+
*/
|
|
57
|
+
externalUrls() {
|
|
58
|
+
return this.withFile({ external: true });
|
|
59
|
+
}
|
|
52
60
|
/** The column is nullable: the field may hold no file. */
|
|
53
61
|
optional() {
|
|
54
62
|
return this.with({ nullable: true });
|
|
@@ -64,6 +64,8 @@ export type FileOptions = {
|
|
|
64
64
|
variants?: Record<string, ImageVariant>;
|
|
65
65
|
/** The image stored instead of the upload (`.variants()`' `original`). */
|
|
66
66
|
original?: ImageVariant;
|
|
67
|
+
/** Whether a value may also be an https URL of a file elsewhere (`.externalUrls()`). */
|
|
68
|
+
external?: true;
|
|
67
69
|
};
|
|
68
70
|
/** Bytes from a number or text such as `10 MB` (decimal units) or `5 MiB` (binary units). */
|
|
69
71
|
export declare const parseSize: (size: number | string) => number;
|
package/dist/internal.d.ts
CHANGED
|
@@ -10,8 +10,8 @@ import { SearchTerm, matchedSearchField, matchesSearch, searchTerms, termMatches
|
|
|
10
10
|
import { defaultRecentLimit, navRecentErrors, statusTones } from "./nav-recent.js";
|
|
11
11
|
import { PluginHost, PluginRequirement, inRange, pluginProblem } from "./plugin-version.js";
|
|
12
12
|
import { redactSecrets } from "./redact-secrets.js";
|
|
13
|
-
import { addressPlaceholders, appHrefError, fillAddress, hrefPlaceholders, leavesApp } from "./address-template.js";
|
|
13
|
+
import { addressPlaceholders, appHrefError, fillAddress, hrefField, hrefPlaceholders, leavesApp, linkActionError } from "./address-template.js";
|
|
14
14
|
import { AddressCheck, addressErrors } from "./address-errors.js";
|
|
15
15
|
import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-event.js";
|
|
16
16
|
import { readEventStream } from "./assistant/event-stream.js";
|
|
17
|
-
export { type AddressCheck, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, bottomBarFor, cardPhotoLimit, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefPlaceholders, inRange, isFieldRef, leavesApp, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, pruneByShape, readEventStream, redactSecrets, searchTerms, shapes, statusTones, tableDisplay, termMatches, unmarkFieldRefs, webhookResources };
|
|
17
|
+
export { type AddressCheck, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, bottomBarFor, cardPhotoLimit, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, pruneByShape, readEventStream, redactSecrets, searchTerms, shapes, statusTones, tableDisplay, termMatches, unmarkFieldRefs, webhookResources };
|
package/dist/internal.js
CHANGED
|
@@ -2,7 +2,7 @@ import { checkedAccept, checkedProvider, parseSize } from "./files/file-options.
|
|
|
2
2
|
import { matchedSearchField, matchesSearch, searchTerms, termMatches } from "./search-match.js";
|
|
3
3
|
import { checkEventFilter } from "./events/event-models.js";
|
|
4
4
|
import { defaultRecentLimit, navRecentErrors, statusTones } from "./nav-recent.js";
|
|
5
|
-
import { addressPlaceholders, appHrefError, fillAddress, hrefPlaceholders, leavesApp } from "./address-template.js";
|
|
5
|
+
import { addressPlaceholders, appHrefError, fillAddress, hrefField, hrefPlaceholders, leavesApp, linkActionError } from "./address-template.js";
|
|
6
6
|
import { fieldRefsIn, isFieldRef, markFieldRefs, unmarkFieldRefs } from "./field-ref.js";
|
|
7
7
|
import { cardPhotoLimit, displayFields, tableDisplay } from "./view-displays.js";
|
|
8
8
|
import { bottomBarFor } from "./bottom-bar.js";
|
|
@@ -14,4 +14,4 @@ import { redactSecrets } from "./redact-secrets.js";
|
|
|
14
14
|
import { addressErrors } from "./address-errors.js";
|
|
15
15
|
import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-event.js";
|
|
16
16
|
import { readEventStream } from "./assistant/event-stream.js";
|
|
17
|
-
export { addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, bottomBarFor, cardPhotoLimit, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefPlaceholders, inRange, isFieldRef, leavesApp, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, pruneByShape, readEventStream, redactSecrets, searchTerms, shapes, statusTones, tableDisplay, termMatches, unmarkFieldRefs, webhookResources };
|
|
17
|
+
export { addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, bottomBarFor, cardPhotoLimit, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, pruneByShape, readEventStream, redactSecrets, searchTerms, shapes, statusTones, tableDisplay, termMatches, unmarkFieldRefs, webhookResources };
|
package/dist/model.d.ts
CHANGED
|
@@ -61,6 +61,8 @@ export type FileFieldModel = {
|
|
|
61
61
|
variants?: Record<string, ImageVariant>;
|
|
62
62
|
/** What is stored instead of an uploaded image, when the upload is not kept. */
|
|
63
63
|
original?: ImageVariant;
|
|
64
|
+
/** Whether a value may also be an https URL of a file elsewhere, drawn and linked as it is (`.externalUrls()`). */
|
|
65
|
+
external?: true;
|
|
64
66
|
};
|
|
65
67
|
/** `digitsEnd`: only the end of the value's digits, spaces, `+` and dashes ignored (phone numbers). */
|
|
66
68
|
export type SearchMatch = 'digitsEnd';
|
|
@@ -583,9 +585,12 @@ export type ActionRun = {
|
|
|
583
585
|
/** The address, with `{field}` replaced by the record's values. */
|
|
584
586
|
to: AppAddress;
|
|
585
587
|
} | {
|
|
586
|
-
/** Opens a link that leaves the app. */
|
|
588
|
+
/** Opens a link that leaves the app, an `https:` or `http:` one in a new tab without the referrer. */
|
|
587
589
|
kind: 'link';
|
|
588
|
-
/**
|
|
590
|
+
/**
|
|
591
|
+
* The link (`https:`, `mailto:`), with `{field}` replaced by the record's values, percent-encoded; or only `{field}`,
|
|
592
|
+
* the `https:` or `http:` URL the record holds, without which the action does not show.
|
|
593
|
+
*/
|
|
589
594
|
href: string;
|
|
590
595
|
};
|
|
591
596
|
/** A named action of a view (`.actions((a) => ...)`); see [Named actions](website/src/content/docs/reference/layouts.md#named-actions). */
|
|
@@ -594,7 +599,7 @@ export type ActionModel = {
|
|
|
594
599
|
name: string;
|
|
595
600
|
/** The button's label. */
|
|
596
601
|
label: string;
|
|
597
|
-
/** The button's icon: `bed`, `file-text`, `ruler`, `send` or `wallet`; another name shows a lightning bolt. */
|
|
602
|
+
/** The button's icon: `bed`, `bell`, `bookmark`, `external-link`, `file-text`, `heart`, `ruler`, `send` or `wallet`; another name shows a lightning bolt. */
|
|
598
603
|
icon?: string;
|
|
599
604
|
/** The question the button asks before it runs the action. */
|
|
600
605
|
confirm?: string;
|
package/dist/resource-model.js
CHANGED
|
@@ -38,7 +38,8 @@ const fieldModel = (name, field) => {
|
|
|
38
38
|
...writtenFields(meta.file).length > 0 && { derive: writtenFields(meta.file) },
|
|
39
39
|
...meta.file.placeholder !== void 0 && { placeholder: meta.file.placeholder },
|
|
40
40
|
...meta.file.variants && Object.keys(meta.file.variants).length > 0 && { variants: structuredClone(meta.file.variants) },
|
|
41
|
-
...meta.file.original && { original: { ...meta.file.original } }
|
|
41
|
+
...meta.file.original && { original: { ...meta.file.original } },
|
|
42
|
+
...meta.file.external && { external: true }
|
|
42
43
|
} }
|
|
43
44
|
};
|
|
44
45
|
};
|
package/dist/view-actions.d.ts
CHANGED
|
@@ -19,8 +19,10 @@ export declare const actions: {
|
|
|
19
19
|
remove: (name: string, o: ActionOptions) => ActionModel;
|
|
20
20
|
/**
|
|
21
21
|
* Goes `to` an address in the app, such as `{ kind: 'record', resource: 'orders', key: '{order_id}' }`, or opens an
|
|
22
|
-
* `href` that leaves it (`https:`, `mailto:`); `{field}` is replaced by the record's value.
|
|
23
|
-
*
|
|
22
|
+
* `href` that leaves it (`https:`, `mailto:`); `{field}` is replaced by the record's value. An `https:` or `http:` link
|
|
23
|
+
* opens in a new tab without the referrer. An href that is only `{field}`, such as `'{website}'`, opens the URL the
|
|
24
|
+
* record holds, and the button shows only when it is an `https:` or `http:` URL; `{host}` in the label becomes its host,
|
|
25
|
+
* as in `'View on {host}'`. A path in the app is refused as an `href`, so every address in the app is written one way.
|
|
24
26
|
*/
|
|
25
27
|
link: (name: string, o: Omit<ActionOptions, "confirm"> & ({
|
|
26
28
|
to: AppAddress;
|
package/dist/view-actions.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { linkActionError } from "./address-template.js";
|
|
2
2
|
//#region src/view-actions.ts
|
|
3
3
|
const named = (name, o) => ({
|
|
4
4
|
name,
|
|
@@ -25,10 +25,14 @@ const actions = {
|
|
|
25
25
|
}),
|
|
26
26
|
/**
|
|
27
27
|
* Goes `to` an address in the app, such as `{ kind: 'record', resource: 'orders', key: '{order_id}' }`, or opens an
|
|
28
|
-
* `href` that leaves it (`https:`, `mailto:`); `{field}` is replaced by the record's value.
|
|
29
|
-
*
|
|
28
|
+
* `href` that leaves it (`https:`, `mailto:`); `{field}` is replaced by the record's value. An `https:` or `http:` link
|
|
29
|
+
* opens in a new tab without the referrer. An href that is only `{field}`, such as `'{website}'`, opens the URL the
|
|
30
|
+
* record holds, and the button shows only when it is an `https:` or `http:` URL; `{host}` in the label becomes its host,
|
|
31
|
+
* as in `'View on {host}'`. A path in the app is refused as an `href`, so every address in the app is written one way.
|
|
30
32
|
*/
|
|
31
33
|
link: (name, o) => {
|
|
34
|
+
const error = linkActionError(o.label, o);
|
|
35
|
+
if (error) throw new Error(`Action "${name}": ${error}`);
|
|
32
36
|
if ("to" in o) return {
|
|
33
37
|
...named(name, o),
|
|
34
38
|
run: {
|
|
@@ -36,8 +40,6 @@ const actions = {
|
|
|
36
40
|
to: structuredClone(o.to)
|
|
37
41
|
}
|
|
38
42
|
};
|
|
39
|
-
const error = appHrefError(o.href);
|
|
40
|
-
if (error) throw new Error(`Action "${name}": ${error}`);
|
|
41
43
|
return {
|
|
42
44
|
...named(name, o),
|
|
43
45
|
run: {
|