@botiverse/porthole 0.1.5 → 0.1.7
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/config/schema.d.ts +26 -3
- package/dist/config/validate.js +29 -4
- package/dist/conformance/index.d.ts +2 -0
- package/dist/conformance/kit.d.ts +2 -1
- package/dist/conformance/limits.d.ts +10 -0
- package/dist/conformance/limits.js +508 -0
- package/dist/conformance/probes.js +2 -0
- package/dist/conformance/served.js +74 -12
- package/dist/guide/guide.js +34 -37
- package/dist/guide/limits.d.ts +24 -0
- package/dist/guide/limits.js +152 -0
- package/dist/host/create-host.js +9 -3
- package/dist/presets/presets.d.ts +3 -1
- package/dist/presets/presets.js +4 -0
- package/dist/react/frame.js +6 -2
- package/dist/shell/plan.d.ts +1 -1
- package/dist/shell/runtime.js +1 -1
- package/package.json +1 -1
- package/src/config/schema.ts +26 -3
- package/src/config/validate.ts +44 -4
- package/src/conformance/index.ts +2 -0
- package/src/conformance/kit.ts +2 -1
- package/src/conformance/limits.ts +560 -0
- package/src/conformance/probes.ts +2 -0
- package/src/conformance/served.ts +93 -23
- package/src/guide/guide.ts +40 -45
- package/src/guide/limits.ts +224 -0
- package/src/host/create-host.ts +9 -3
- package/src/presets/presets.ts +7 -1
- package/src/react/frame.tsx +6 -2
- package/src/shell/plan.ts +1 -1
- package/src/shell/runtime.ts +1 -1
package/src/config/schema.ts
CHANGED
|
@@ -86,9 +86,11 @@ export interface ThemeConfig {
|
|
|
86
86
|
* Whether a whole document (an artifact page) takes the person's light or dark scheme:
|
|
87
87
|
* `declared` (default): only a page that declares it supports both
|
|
88
88
|
* (`<meta name="color-scheme" content="light dark">`); any other page shows as its author
|
|
89
|
-
* styled it, in light. `always`: every page.
|
|
89
|
+
* styled it, in light. `always`: every page. `never` (pages only, P065): the host has no
|
|
90
|
+
* theme for it: it always gets the light values, its frame says light, and no theme change
|
|
91
|
+
* reaches it. The variables are there in every case.
|
|
90
92
|
*/
|
|
91
|
-
readonly documents?: "declared" | "always";
|
|
93
|
+
readonly documents?: "declared" | "always" | "never";
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
export interface Limits {
|
|
@@ -143,6 +145,13 @@ export interface LayoutConfig {
|
|
|
143
145
|
readonly narrowWidthPx: number;
|
|
144
146
|
/** The widest the frame is (a desktop column). */
|
|
145
147
|
readonly wideWidthPx: number;
|
|
148
|
+
/**
|
|
149
|
+
* How the frame sits in the host (P065). `flow` (default): a card in a column, as tall as its
|
|
150
|
+
* content (up to `maxHeightPx`). `fill`: it fills the viewer (the page itself): as tall as its
|
|
151
|
+
* container, the content scrolling itself, `position: fixed` and `sticky` working. Every mount
|
|
152
|
+
* then fills (`MountOptions.fill`), and the manual says so.
|
|
153
|
+
*/
|
|
154
|
+
readonly kind?: "flow" | "fill";
|
|
146
155
|
}
|
|
147
156
|
|
|
148
157
|
export interface GuideConfig {
|
|
@@ -193,9 +202,23 @@ export interface PortholeConfig {
|
|
|
193
202
|
* "conversation" }`), so the manual says storage is shared across it and keys need a prefix.
|
|
194
203
|
*/
|
|
195
204
|
readonly storage?: StorageConfig;
|
|
205
|
+
/**
|
|
206
|
+
* Where the content's own errors go, for the manual (P065): `agent`, back to the agent that
|
|
207
|
+
* wrote it; `host`, to the app only (the agent never sees them); `none`, nowhere (the config
|
|
208
|
+
* declares no `reportError`). Absent: the manual says they are reported to the app.
|
|
209
|
+
*/
|
|
210
|
+
readonly errors?: "agent" | "host" | "none";
|
|
196
211
|
}
|
|
197
212
|
|
|
198
213
|
export interface StorageConfig {
|
|
199
|
-
/**
|
|
214
|
+
/**
|
|
215
|
+
* What the displays sharing one origin at once have in common, as a noun ("conversation"):
|
|
216
|
+
* the manual tells authors to prefix their keys.
|
|
217
|
+
*/
|
|
200
218
|
readonly shared?: string;
|
|
219
|
+
/**
|
|
220
|
+
* What one display's storage is kept for, when only one display uses its origin at a time, in
|
|
221
|
+
* words ("this artifact, across its versions", P065): the manual says so, with no prefix advice.
|
|
222
|
+
*/
|
|
223
|
+
readonly scope?: string;
|
|
201
224
|
}
|
package/src/config/validate.ts
CHANGED
|
@@ -292,6 +292,7 @@ export function validateConfig(input: unknown): PortholeConfig {
|
|
|
292
292
|
"sandbox",
|
|
293
293
|
"permissions",
|
|
294
294
|
"storage",
|
|
295
|
+
"errors",
|
|
295
296
|
],
|
|
296
297
|
"config",
|
|
297
298
|
);
|
|
@@ -360,9 +361,16 @@ export function validateConfig(input: unknown): PortholeConfig {
|
|
|
360
361
|
if (
|
|
361
362
|
theme.documents !== undefined &&
|
|
362
363
|
theme.documents !== "declared" &&
|
|
363
|
-
theme.documents !== "always"
|
|
364
|
+
theme.documents !== "always" &&
|
|
365
|
+
theme.documents !== "never"
|
|
364
366
|
) {
|
|
365
|
-
fail("config.theme.documents", 'must be "declared" or "
|
|
367
|
+
fail("config.theme.documents", 'must be "declared", "always" or "never"');
|
|
368
|
+
}
|
|
369
|
+
if (theme.documents === "never" && config.mode !== "artifact") {
|
|
370
|
+
fail(
|
|
371
|
+
"config.theme.documents",
|
|
372
|
+
'"never" is for whole pages: a fragment takes the theme it is drawn in',
|
|
373
|
+
);
|
|
366
374
|
}
|
|
367
375
|
const variables = object(theme.variables, "config.theme.variables");
|
|
368
376
|
for (const [name, value] of Object.entries(variables)) {
|
|
@@ -414,7 +422,10 @@ export function validateConfig(input: unknown): PortholeConfig {
|
|
|
414
422
|
}
|
|
415
423
|
|
|
416
424
|
const layout = object(config.layout, "config.layout");
|
|
417
|
-
only(layout, ["minWidthPx", "narrowWidthPx", "wideWidthPx"], "config.layout");
|
|
425
|
+
only(layout, ["minWidthPx", "narrowWidthPx", "wideWidthPx", "kind"], "config.layout");
|
|
426
|
+
if (layout.kind !== undefined && layout.kind !== "flow" && layout.kind !== "fill") {
|
|
427
|
+
fail("config.layout.kind", 'must be "flow" or "fill"');
|
|
428
|
+
}
|
|
418
429
|
for (const name of ["minWidthPx", "narrowWidthPx", "wideWidthPx"]) {
|
|
419
430
|
positive(layout[name], `config.layout.${name}`, 10_000);
|
|
420
431
|
}
|
|
@@ -494,7 +505,22 @@ export function validateConfig(input: unknown): PortholeConfig {
|
|
|
494
505
|
|
|
495
506
|
if (config.storage !== undefined) {
|
|
496
507
|
const storage = object(config.storage, "config.storage");
|
|
497
|
-
only(storage, ["shared"], "config.storage");
|
|
508
|
+
only(storage, ["shared", "scope"], "config.storage");
|
|
509
|
+
if (storage.shared !== undefined && storage.scope !== undefined) {
|
|
510
|
+
fail(
|
|
511
|
+
"config.storage",
|
|
512
|
+
"shared (several displays at once) or scope (one at a time), not both",
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
if (
|
|
516
|
+
storage.scope !== undefined &&
|
|
517
|
+
(typeof storage.scope !== "string" || !/^[a-z][a-z ,'-]{0,59}$/u.test(storage.scope))
|
|
518
|
+
) {
|
|
519
|
+
fail(
|
|
520
|
+
"config.storage.scope",
|
|
521
|
+
'must be short lowercase words ("this artifact, across its versions")',
|
|
522
|
+
);
|
|
523
|
+
}
|
|
498
524
|
if (config.isolation !== "domain") {
|
|
499
525
|
fail("config.storage", "only domain isolation keeps storage across displays");
|
|
500
526
|
}
|
|
@@ -506,6 +532,20 @@ export function validateConfig(input: unknown): PortholeConfig {
|
|
|
506
532
|
}
|
|
507
533
|
}
|
|
508
534
|
|
|
535
|
+
if (config.errors !== undefined) {
|
|
536
|
+
if (config.errors !== "agent" && config.errors !== "host" && config.errors !== "none") {
|
|
537
|
+
fail("config.errors", 'must be "agent", "host" or "none"');
|
|
538
|
+
}
|
|
539
|
+
if ((config.errors === "none") !== (capabilities.reportError === undefined)) {
|
|
540
|
+
fail(
|
|
541
|
+
"config.errors",
|
|
542
|
+
config.errors === "none"
|
|
543
|
+
? '"none" means no reportError: drop the capability'
|
|
544
|
+
: `${JSON.stringify(config.errors)} needs the reportError capability, which carries them`,
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
509
549
|
if (config.permissions !== undefined) {
|
|
510
550
|
if (config.mode !== "url") {
|
|
511
551
|
fail("config.permissions", "only url mode may be delegated features");
|
package/src/conformance/index.ts
CHANGED
|
@@ -40,6 +40,8 @@ export interface LaunchSpec {
|
|
|
40
40
|
readonly scheme?: ColorScheme;
|
|
41
41
|
/** The frame's width, px. */
|
|
42
42
|
readonly widthPx?: number;
|
|
43
|
+
/** The height of the box the frame sits in, px: for a layout that fills it (`layout.kind`). */
|
|
44
|
+
readonly heightPx?: number;
|
|
43
45
|
/** The host's live values for theme variables, per scheme (as `HostOptions.theme` answers). */
|
|
44
46
|
readonly hostTheme?: {
|
|
45
47
|
readonly light?: Readonly<Record<string, string>>;
|
package/src/conformance/kit.ts
CHANGED
|
@@ -34,7 +34,8 @@ export interface Probe {
|
|
|
34
34
|
readonly id: string;
|
|
35
35
|
/**
|
|
36
36
|
* The DESIGN.md egress-table item it proves; 0 for the shell's own wiring and interop, 11 for
|
|
37
|
-
* behavior (streaming, sizing, theming), 12 for host-function gates, 13 for the clipboard
|
|
37
|
+
* behavior (streaming, sizing, theming), 12 for host-function gates, 13 for the clipboard, 14
|
|
38
|
+
* for the manual's claims about the sandbox (`LIMIT_CHECKS`).
|
|
38
39
|
*/
|
|
39
40
|
readonly item: number;
|
|
40
41
|
readonly title: string;
|