@fungi.computer/nacre 0.1.4 → 0.2.0

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.
@@ -0,0 +1,102 @@
1
+ /**
2
+ * What a host's owner settings read about a website chat channel: the web
3
+ * origin grammar both the Oyster and Hub enforce and the Settings form checks,
4
+ * and the wire shapes of a website, its conversations and a transcript.
5
+ */
6
+ import { z } from "zod";
7
+ /** One refused-origin reason, keyed for callers that name it to a person. */
8
+ export type WebOriginProblem = "tooLong" | "notUrl" | "insecure" | "credentials" | "path" | "notAllowed";
9
+ /** The reason a refused origin's first issue names. */
10
+ export declare function webOriginProblem(error: z.ZodError): WebOriginProblem;
11
+ /**
12
+ * Parse one allowed embed origin: exact `https://host[:port]`, one leading
13
+ * `*.` subdomain level, or `http` only on loopback for development. Paths,
14
+ * credentials, queries and bare wildcards are rejected. The Hub stores and
15
+ * enforces these; Settings runs the same schema before it sends one.
16
+ */
17
+ export declare const webOriginSchema: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
18
+ /** How a website is found and where it may appear. */
19
+ export type WebsiteSelector = {
20
+ /** Websites are the web provider's bindings. */
21
+ provider: "web";
22
+ /** The public key in the pasted snippet. */
23
+ siteKey: string;
24
+ /** The origins allowed to embed the chat. */
25
+ origins: string[];
26
+ /** The owner's accent colour, `#rrggbb`. */
27
+ accent?: string | undefined;
28
+ /** Visitors must pass Cloudflare Turnstile before they can chat. */
29
+ turnstile?: boolean | undefined;
30
+ };
31
+ /** One website as an owner's Settings read it. */
32
+ export type WebsiteSite = {
33
+ /** The binding's identity on its host. */
34
+ bindingId: string;
35
+ /** The Agent visitors chat with, named by its id in the host's directory. */
36
+ agentId: string;
37
+ /** How the embed finds the website and where it may appear. */
38
+ selector: WebsiteSelector;
39
+ /** Whether visitors can chat now. */
40
+ lifecycle: "active" | "suspended";
41
+ /** The version an edit must name; it advances on every edit. */
42
+ authorityVersion: number;
43
+ /** The owner's brief for this website; visitors never see it. */
44
+ persona: string;
45
+ };
46
+ /** One website as an owner's Settings read it. */
47
+ export declare const websiteSiteSchema: z.ZodType<WebsiteSite>;
48
+ /** One conversation of a website, newest first. */
49
+ export type WebsiteConversation = {
50
+ /** The conversation's Session on the website's Agent. */
51
+ sessionId: string;
52
+ /** A short label for the visitor. */
53
+ label: string;
54
+ /** When the visitor or the Agent last wrote, in epoch milliseconds. */
55
+ lastEventAt: number;
56
+ };
57
+ /** One conversation of a website. */
58
+ export declare const websiteConversationSchema: z.ZodType<WebsiteConversation>;
59
+ /** One line of a website conversation as its owner reads it. */
60
+ export type TranscriptLine = {
61
+ /** Who wrote the line. */
62
+ role: "visitor" | "agent";
63
+ /** What was written. */
64
+ text: string;
65
+ };
66
+ /** An owner's read of one website conversation. */
67
+ export type WebsiteTranscript = {
68
+ /** The conversation's Session on the website's Agent. */
69
+ sessionId: string;
70
+ /** A short label for the visitor. */
71
+ label: string;
72
+ /** What visitor and Agent said, oldest first. */
73
+ lines: TranscriptLine[];
74
+ };
75
+ /** An owner's read of one website conversation. */
76
+ export declare const websiteTranscriptSchema: z.ZodType<WebsiteTranscript>;
77
+ /** One content part of a message; only text parts are read. */
78
+ export type TranscriptPart = {
79
+ /** The part's kind; `text` parts carry the words. */
80
+ type: string;
81
+ /** The words of a text part. */
82
+ text?: string | undefined;
83
+ };
84
+ /**
85
+ * The part of a Session message a transcript reads: who said it and what the
86
+ * content holds. A Shiitake message satisfies it without this package knowing
87
+ * Shiitake.
88
+ */
89
+ export type TranscriptMessage = {
90
+ /** The model message. */
91
+ value: {
92
+ /** `user` for a visitor's prompt, `assistant` for the Agent's reply. */
93
+ role: string;
94
+ /** Plain text, or content parts of which only text parts are read. */
95
+ content: string | readonly TranscriptPart[];
96
+ };
97
+ };
98
+ /**
99
+ * The visible line of one message: a visitor's prompt or the Agent's reply.
100
+ * Tool traffic and empty turns are not conversation, so they have no line.
101
+ */
102
+ export declare function transcriptLine(message: TranscriptMessage): TranscriptLine | null;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * What a host's owner settings read about a website chat channel: the web
3
+ * origin grammar both the Oyster and Hub enforce and the Settings form checks,
4
+ * and the wire shapes of a website, its conversations and a transcript.
5
+ */
6
+ import { z } from "zod";
7
+ const loopbackHosts = new Set(["localhost", "127.0.0.1", "[::1]"]);
8
+ const webOriginProblems = {
9
+ tooLong: "Origin is too long",
10
+ notUrl: "Origin is not a URL",
11
+ insecure: "Origin must use https",
12
+ credentials: "Origin must not carry credentials",
13
+ path: "Origin must not carry a path, query or fragment",
14
+ notAllowed: "Origin is not allowed",
15
+ };
16
+ const webOriginProblemNames = [
17
+ "tooLong",
18
+ "notUrl",
19
+ "insecure",
20
+ "credentials",
21
+ "path",
22
+ "notAllowed",
23
+ ];
24
+ /** The reason a refused origin's first issue names. */
25
+ export function webOriginProblem(error) {
26
+ const message = error.issues[0]?.message;
27
+ return (webOriginProblemNames.find((problem) => webOriginProblems[problem] === message) ?? "notAllowed");
28
+ }
29
+ /**
30
+ * Parse one allowed embed origin: exact `https://host[:port]`, one leading
31
+ * `*.` subdomain level, or `http` only on loopback for development. Paths,
32
+ * credentials, queries and bare wildcards are rejected. The Hub stores and
33
+ * enforces these; Settings runs the same schema before it sends one.
34
+ */
35
+ export const webOriginSchema = z
36
+ .string()
37
+ .max(253, webOriginProblems.tooLong)
38
+ .transform((value, context) => {
39
+ const refuse = (problem) => {
40
+ context.addIssue({ code: "custom", message: webOriginProblems[problem] });
41
+ return z.NEVER;
42
+ };
43
+ const wildcard = value.startsWith("https://*.");
44
+ const candidate = wildcard ? value.replace("*.", "") : value;
45
+ let url;
46
+ try {
47
+ url = new URL(candidate);
48
+ }
49
+ catch {
50
+ return refuse("notUrl");
51
+ }
52
+ const secure = url.protocol === "https:" ||
53
+ (url.protocol === "http:" &&
54
+ !wildcard &&
55
+ loopbackHosts.has(url.hostname));
56
+ if (!secure)
57
+ return refuse("insecure");
58
+ if (url.username !== "" || url.password !== "")
59
+ return refuse("credentials");
60
+ if (url.pathname !== "/" || url.search !== "" || url.hash !== "")
61
+ return refuse("path");
62
+ if (url.origin !== candidate.toLowerCase() ||
63
+ url.hostname.includes("*") ||
64
+ (wildcard && url.hostname.split(".").length < 2))
65
+ return refuse("notAllowed");
66
+ return wildcard ? `https://*.${url.host}` : url.origin;
67
+ });
68
+ const identity = z.string().min(1).max(256);
69
+ /** One website as an owner's Settings read it. */
70
+ export const websiteSiteSchema = z.object({
71
+ bindingId: identity,
72
+ agentId: identity,
73
+ selector: z.object({
74
+ provider: z.literal("web"),
75
+ siteKey: identity,
76
+ origins: z.array(z.string()).min(1).max(16),
77
+ accent: z.string().optional(),
78
+ turnstile: z.boolean().optional(),
79
+ }),
80
+ lifecycle: z.enum(["active", "suspended"]),
81
+ authorityVersion: z.number().int().positive(),
82
+ persona: z.string().max(4_000),
83
+ });
84
+ /** One conversation of a website. */
85
+ export const websiteConversationSchema = z.object({
86
+ sessionId: identity,
87
+ label: z.string(),
88
+ lastEventAt: z.number().int().nonnegative(),
89
+ });
90
+ /** An owner's read of one website conversation. */
91
+ export const websiteTranscriptSchema = z.strictObject({
92
+ sessionId: identity,
93
+ label: z.string(),
94
+ lines: z.array(z.strictObject({
95
+ role: z.enum(["visitor", "agent"]),
96
+ text: z.string(),
97
+ })),
98
+ });
99
+ /**
100
+ * The visible line of one message: a visitor's prompt or the Agent's reply.
101
+ * Tool traffic and empty turns are not conversation, so they have no line.
102
+ */
103
+ export function transcriptLine(message) {
104
+ const { role, content } = message.value;
105
+ if (role !== "user" && role !== "assistant")
106
+ return null;
107
+ const text = hasParts(content)
108
+ ? content
109
+ .flatMap((part) => (part.type === "text" ? [part.text ?? ""] : []))
110
+ .join("")
111
+ : content;
112
+ if (text.trim() === "")
113
+ return null;
114
+ return { role: role === "user" ? "visitor" : "agent", text };
115
+ }
116
+ /** `Array.isArray` does not narrow a readonly array out of the union. */
117
+ function hasParts(content) {
118
+ return Array.isArray(content);
119
+ }
@@ -16,6 +16,7 @@
16
16
  | [index](index.md) | - |
17
17
  | [keys](keys.md) | - |
18
18
  | [shell-module](shell-module.md) | - |
19
+ | [website-channels](website-channels.md) | - |
19
20
  | [window-manager](window-manager.md) | - |
20
21
  | [workbench-directory](workbench-directory.md) | - |
21
22
  | [workbench](workbench.md) | - |
@@ -80,6 +80,19 @@ grammar stays with its owner, which hands rows of this shape.
80
80
 
81
81
  ---
82
82
 
83
+ ### AppCommandTarget
84
+
85
+ ```ts
86
+ type AppCommandTarget = Readonly<{
87
+ surfaceId: string;
88
+ commandId: string;
89
+ }>;
90
+ ```
91
+
92
+ One App command, named by its surface and its declared command id.
93
+
94
+ ---
95
+
83
96
  ### AppSurfaceCommandMount
84
97
 
85
98
  ```ts
@@ -98,8 +111,8 @@ The command side of one mounted App's host handlers.
98
111
 
99
112
  ```ts
100
113
  type PaneCommands = Readonly<{
101
- commandId: (id) => string;
102
- contribute: (commands) => WhistleContributionLease;
114
+ command: (id, group?) => WhistleCommandKey;
115
+ contribute: (commands, group?) => WhistleContributionLease;
103
116
  execute: WhistleRuntime["execute"];
104
117
  snapshot: WhistleRuntime["snapshot"];
105
118
  subscribe: WhistleRuntime["subscribe"];
@@ -133,9 +146,10 @@ type AppSurfaceCommandHost = Readonly<{
133
146
  focus: (mountId) => void;
134
147
  registerShellCommands: (commands) => () => void;
135
148
  registerDirectoryCommands: (commands, run) => () => void;
149
+ appCommand: (row) => AppCommandTarget | undefined;
136
150
  menu: () => readonly WhistleMenuProjection[];
137
151
  active: () => WhistleSnapshot;
138
- execute: (commandId, input) => Promise<WhistleExecutionOutcome>;
152
+ execute: (command, input) => Promise<WhistleExecutionOutcome>;
139
153
  snapshot: () => WhistleSnapshot;
140
154
  subscribe: (listener) => () => void;
141
155
  dispose: () => void;
@@ -198,6 +212,29 @@ Select the shell command-palette chord from the embedding browser user agent.
198
212
 
199
213
  ---
200
214
 
215
+ ### appSurfaceCommandKey()
216
+
217
+ ```ts
218
+ function appSurfaceCommandKey(target): WhistleCommandKey;
219
+ ```
220
+
221
+ The typed Whistle identity of a command a mounted App surface contributed: each
222
+ mounted surface owns the Whistle namespace named by its surface id.
223
+
224
+ #### Parameters
225
+
226
+ | Parameter | Type | Description |
227
+ | --------- | --------------------------------------- | -------------------------------------------- |
228
+ | `target` | [`AppCommandTarget`](#appcommandtarget) | The App surface and its declared command id. |
229
+
230
+ #### Returns
231
+
232
+ `WhistleCommandKey`
233
+
234
+ The key every snapshot row of that command carries as `command`.
235
+
236
+ ---
237
+
201
238
  ### createAppSurfaceCommandHost()
202
239
 
203
240
  ```ts
package/docs/api/index.md CHANGED
@@ -418,7 +418,8 @@ The shell unmounted: stop notifying its callbacks.
418
418
  mount(
419
419
  container,
420
420
  input,
421
- events
421
+ events,
422
+ signal
422
423
  ): Promise<WorkbenchChildHandle>;
423
424
  ```
424
425
 
@@ -433,6 +434,7 @@ slot in that App's window. The host never moves the child: the shell keeps
433
434
  | `container` | `HTMLElement` |
434
435
  | `input` | [`WorkbenchChildLaunch`](#workbenchchildlaunch) |
435
436
  | `events` | [`TeamWorkbenchChildEvents`](#teamworkbenchchildevents) |
437
+ | `signal` | `AbortSignal` |
436
438
 
437
439
  ###### Returns
438
440
 
@@ -476,6 +478,7 @@ TeamWorkbenchHostHandle.reportAgentSessionSelection;
476
478
  ```ts
477
479
  type TeamWorkbenchChildEvents = WorkbenchChildEvents &
478
480
  Readonly<{
481
+ onDeliveryPending?: () => void;
479
482
  onAgentSessionSelection: (selection) => Promise<void>;
480
483
  }>;
481
484
  ```
@@ -662,7 +665,8 @@ while covered.
662
665
  mount(
663
666
  container,
664
667
  input,
665
- events
668
+ events,
669
+ signal
666
670
  ): Promise<WorkbenchChildHandle>;
667
671
  ```
668
672
 
@@ -677,6 +681,7 @@ slot in that App's window. The host never moves the child: the shell keeps
677
681
  | `container` | `HTMLElement` |
678
682
  | `input` | [`WorkbenchChildLaunch`](#workbenchchildlaunch) |
679
683
  | `events` | [`TeamWorkbenchChildEvents`](#teamworkbenchchildevents) |
684
+ | `signal` | `AbortSignal` |
680
685
 
681
686
  ###### Returns
682
687
 
@@ -1606,6 +1611,18 @@ Re-exports
1606
1611
 
1607
1612
  ---
1608
1613
 
1614
+ ### AppCommandTarget
1615
+
1616
+ Re-exports [AppCommandTarget](command-host.md#appcommandtarget)
1617
+
1618
+ ---
1619
+
1620
+ ### appSurfaceCommandKey
1621
+
1622
+ Re-exports [appSurfaceCommandKey](command-host.md#appsurfacecommandkey)
1623
+
1624
+ ---
1625
+
1609
1626
  ### appDirectorySourceId
1610
1627
 
1611
1628
  Re-exports [appDirectorySourceId](command-host.md#appdirectorysourceid)
@@ -1795,6 +1812,20 @@ Re-exports [installShellKeys](keys.md#installshellkeys)
1795
1812
 
1796
1813
  ---
1797
1814
 
1815
+ ### APP\_SURFACE\_DOCUMENT\_TIMEOUT\_MS
1816
+
1817
+ Re-exports
1818
+ [APP_SURFACE_DOCUMENT_TIMEOUT_MS](window-manager.md#app_surface_document_timeout_ms)
1819
+
1820
+ ---
1821
+
1822
+ ### prepareWithDeliveryRetry
1823
+
1824
+ Re-exports
1825
+ [prepareWithDeliveryRetry](window-manager.md#preparewithdeliveryretry)
1826
+
1827
+ ---
1828
+
1798
1829
  ### WindowLaunch
1799
1830
 
1800
1831
  Re-exports [WindowLaunch](window-manager.md#windowlaunch)
package/docs/api/keys.md CHANGED
@@ -58,7 +58,7 @@ One key offered after the leader chord, with the command it runs.
58
58
  type ShellKeyHost = Readonly<{
59
59
  active: () => WhistleSnapshot;
60
60
  subscribe: (listener) => () => void;
61
- execute: (commandId, input) => Promise<WhistleExecutionOutcome>;
61
+ execute: (command, input) => Promise<WhistleExecutionOutcome>;
62
62
  }>;
63
63
  ```
64
64
 
@@ -81,6 +81,67 @@ Always ShellModuleError.
81
81
  Error.name;
82
82
  ```
83
83
 
84
+ ---
85
+
86
+ ### ShellModuleUnavailable
87
+
88
+ The picked shell's module could not be fetched or evaluated. A browser keeps a
89
+ failed module fetch for the life of the document, so only loading the page again
90
+ can recover it.
91
+
92
+ #### Extends
93
+
94
+ - `Error`
95
+
96
+ #### Constructors
97
+
98
+ ##### Constructor
99
+
100
+ ```ts
101
+ new ShellModuleUnavailable(moduleUrl, options): ShellModuleUnavailable;
102
+ ```
103
+
104
+ ###### Parameters
105
+
106
+ | Parameter | Type | Description |
107
+ | ----------- | -------------- | ----------------------------------- |
108
+ | `moduleUrl` | `string` | The module URL that could not load. |
109
+ | `options` | `ErrorOptions` | - |
110
+
111
+ ###### Returns
112
+
113
+ [`ShellModuleUnavailable`](#shellmoduleunavailable)
114
+
115
+ ###### Overrides
116
+
117
+ ```ts
118
+ Error.constructor;
119
+ ```
120
+
121
+ #### Properties
122
+
123
+ ##### name
124
+
125
+ ```ts
126
+ readonly name: "ShellModuleUnavailable" = "ShellModuleUnavailable";
127
+ ```
128
+
129
+ Always ShellModuleUnavailable.
130
+
131
+ ###### Overrides
132
+
133
+ ```ts
134
+ Error.name;
135
+ ```
136
+
137
+ ##### moduleUrl
138
+
139
+ ```ts
140
+ readonly moduleUrl: string;
141
+ ```
142
+
143
+ The module URL that could not load.
144
+
84
145
  ## Type Aliases
85
146
 
86
147
  ### ShellMountInput
@@ -0,0 +1,382 @@
1
+ <!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
2
+
3
+ [**@fungi.computer/nacre**](README.md)
4
+
5
+ ---
6
+
7
+ [@fungi.computer/nacre](README.md) / website-channels
8
+
9
+ # website-channels
10
+
11
+ ## Type Aliases
12
+
13
+ ### WebOriginProblem
14
+
15
+ ```ts
16
+ type WebOriginProblem =
17
+ "tooLong" | "notUrl" | "insecure" | "credentials" | "path" | "notAllowed";
18
+ ```
19
+
20
+ One refused-origin reason, keyed for callers that name it to a person.
21
+
22
+ ---
23
+
24
+ ### WebsiteSelector
25
+
26
+ ```ts
27
+ type WebsiteSelector = object;
28
+ ```
29
+
30
+ How a website is found and where it may appear.
31
+
32
+ #### Properties
33
+
34
+ ##### provider
35
+
36
+ ```ts
37
+ provider: "web";
38
+ ```
39
+
40
+ Websites are the web provider's bindings.
41
+
42
+ ##### siteKey
43
+
44
+ ```ts
45
+ siteKey: string;
46
+ ```
47
+
48
+ The public key in the pasted snippet.
49
+
50
+ ##### origins
51
+
52
+ ```ts
53
+ origins: string[];
54
+ ```
55
+
56
+ The origins allowed to embed the chat.
57
+
58
+ ##### accent?
59
+
60
+ ```ts
61
+ optional accent?: string;
62
+ ```
63
+
64
+ The owner's accent colour, `#rrggbb`.
65
+
66
+ ##### turnstile?
67
+
68
+ ```ts
69
+ optional turnstile?: boolean;
70
+ ```
71
+
72
+ Visitors must pass Cloudflare Turnstile before they can chat.
73
+
74
+ ---
75
+
76
+ ### WebsiteSite
77
+
78
+ ```ts
79
+ type WebsiteSite = object;
80
+ ```
81
+
82
+ One website as an owner's Settings read it.
83
+
84
+ #### Properties
85
+
86
+ ##### bindingId
87
+
88
+ ```ts
89
+ bindingId: string;
90
+ ```
91
+
92
+ The binding's identity on its host.
93
+
94
+ ##### agentId
95
+
96
+ ```ts
97
+ agentId: string;
98
+ ```
99
+
100
+ The Agent visitors chat with, named by its id in the host's directory.
101
+
102
+ ##### selector
103
+
104
+ ```ts
105
+ selector: WebsiteSelector;
106
+ ```
107
+
108
+ How the embed finds the website and where it may appear.
109
+
110
+ ##### lifecycle
111
+
112
+ ```ts
113
+ lifecycle: "active" | "suspended";
114
+ ```
115
+
116
+ Whether visitors can chat now.
117
+
118
+ ##### authorityVersion
119
+
120
+ ```ts
121
+ authorityVersion: number;
122
+ ```
123
+
124
+ The version an edit must name; it advances on every edit.
125
+
126
+ ##### persona
127
+
128
+ ```ts
129
+ persona: string;
130
+ ```
131
+
132
+ The owner's brief for this website; visitors never see it.
133
+
134
+ ---
135
+
136
+ ### WebsiteConversation
137
+
138
+ ```ts
139
+ type WebsiteConversation = object;
140
+ ```
141
+
142
+ One conversation of a website, newest first.
143
+
144
+ #### Properties
145
+
146
+ ##### sessionId
147
+
148
+ ```ts
149
+ sessionId: string;
150
+ ```
151
+
152
+ The conversation's Session on the website's Agent.
153
+
154
+ ##### label
155
+
156
+ ```ts
157
+ label: string;
158
+ ```
159
+
160
+ A short label for the visitor.
161
+
162
+ ##### lastEventAt
163
+
164
+ ```ts
165
+ lastEventAt: number;
166
+ ```
167
+
168
+ When the visitor or the Agent last wrote, in epoch milliseconds.
169
+
170
+ ---
171
+
172
+ ### TranscriptLine
173
+
174
+ ```ts
175
+ type TranscriptLine = object;
176
+ ```
177
+
178
+ One line of a website conversation as its owner reads it.
179
+
180
+ #### Properties
181
+
182
+ ##### role
183
+
184
+ ```ts
185
+ role: "visitor" | "agent";
186
+ ```
187
+
188
+ Who wrote the line.
189
+
190
+ ##### text
191
+
192
+ ```ts
193
+ text: string;
194
+ ```
195
+
196
+ What was written.
197
+
198
+ ---
199
+
200
+ ### WebsiteTranscript
201
+
202
+ ```ts
203
+ type WebsiteTranscript = object;
204
+ ```
205
+
206
+ An owner's read of one website conversation.
207
+
208
+ #### Properties
209
+
210
+ ##### sessionId
211
+
212
+ ```ts
213
+ sessionId: string;
214
+ ```
215
+
216
+ The conversation's Session on the website's Agent.
217
+
218
+ ##### label
219
+
220
+ ```ts
221
+ label: string;
222
+ ```
223
+
224
+ A short label for the visitor.
225
+
226
+ ##### lines
227
+
228
+ ```ts
229
+ lines: TranscriptLine[];
230
+ ```
231
+
232
+ What visitor and Agent said, oldest first.
233
+
234
+ ---
235
+
236
+ ### TranscriptPart
237
+
238
+ ```ts
239
+ type TranscriptPart = object;
240
+ ```
241
+
242
+ One content part of a message; only text parts are read.
243
+
244
+ #### Properties
245
+
246
+ ##### type
247
+
248
+ ```ts
249
+ type: string;
250
+ ```
251
+
252
+ The part's kind; `text` parts carry the words.
253
+
254
+ ##### text?
255
+
256
+ ```ts
257
+ optional text?: string;
258
+ ```
259
+
260
+ The words of a text part.
261
+
262
+ ---
263
+
264
+ ### TranscriptMessage
265
+
266
+ ```ts
267
+ type TranscriptMessage = object;
268
+ ```
269
+
270
+ The part of a Session message a transcript reads: who said it and what the
271
+ content holds. A Shiitake message satisfies it without this package knowing
272
+ Shiitake.
273
+
274
+ #### Properties
275
+
276
+ ##### value
277
+
278
+ ```ts
279
+ value: object;
280
+ ```
281
+
282
+ The model message.
283
+
284
+ ###### role
285
+
286
+ ```ts
287
+ role: string;
288
+ ```
289
+
290
+ `user` for a visitor's prompt, `assistant` for the Agent's reply.
291
+
292
+ ###### content
293
+
294
+ ```ts
295
+ content: string | readonly TranscriptPart[];
296
+ ```
297
+
298
+ Plain text, or content parts of which only text parts are read.
299
+
300
+ ## Variables
301
+
302
+ ### webOriginSchema
303
+
304
+ ```ts
305
+ const webOriginSchema: ZodPipe<ZodString, ZodTransform<string, string>>;
306
+ ```
307
+
308
+ Parse one allowed embed origin: exact `https://host[:port]`, one leading `*.`
309
+ subdomain level, or `http` only on loopback for development. Paths, credentials,
310
+ queries and bare wildcards are rejected. The Hub stores and enforces these;
311
+ Settings runs the same schema before it sends one.
312
+
313
+ ---
314
+
315
+ ### websiteSiteSchema
316
+
317
+ ```ts
318
+ const websiteSiteSchema: z.ZodType<WebsiteSite>;
319
+ ```
320
+
321
+ One website as an owner's Settings read it.
322
+
323
+ ---
324
+
325
+ ### websiteConversationSchema
326
+
327
+ ```ts
328
+ const websiteConversationSchema: z.ZodType<WebsiteConversation>;
329
+ ```
330
+
331
+ One conversation of a website.
332
+
333
+ ---
334
+
335
+ ### websiteTranscriptSchema
336
+
337
+ ```ts
338
+ const websiteTranscriptSchema: z.ZodType<WebsiteTranscript>;
339
+ ```
340
+
341
+ An owner's read of one website conversation.
342
+
343
+ ## Functions
344
+
345
+ ### webOriginProblem()
346
+
347
+ ```ts
348
+ function webOriginProblem(error): WebOriginProblem;
349
+ ```
350
+
351
+ The reason a refused origin's first issue names.
352
+
353
+ #### Parameters
354
+
355
+ | Parameter | Type |
356
+ | --------- | ---------- |
357
+ | `error` | `ZodError` |
358
+
359
+ #### Returns
360
+
361
+ [`WebOriginProblem`](#weboriginproblem)
362
+
363
+ ---
364
+
365
+ ### transcriptLine()
366
+
367
+ ```ts
368
+ function transcriptLine(message): TranscriptLine | null;
369
+ ```
370
+
371
+ The visible line of one message: a visitor's prompt or the Agent's reply. Tool
372
+ traffic and empty turns are not conversation, so they have no line.
373
+
374
+ #### Parameters
375
+
376
+ | Parameter | Type |
377
+ | --------- | ----------------------------------------- |
378
+ | `message` | [`TranscriptMessage`](#transcriptmessage) |
379
+
380
+ #### Returns
381
+
382
+ [`TranscriptLine`](#transcriptline) \| `null`
@@ -25,7 +25,8 @@ Minimum identity required to own a window across mount generations.
25
25
  ### WindowStatus
26
26
 
27
27
  ```ts
28
- type WindowStatus = "loading" | "ready" | "minimized" | "error";
28
+ type WindowStatus =
29
+ "loading" | "getting-ready" | "ready" | "minimized" | "error";
29
30
  ```
30
31
 
31
32
  Current presentation state of a managed window.
@@ -61,6 +62,7 @@ with it.
61
62
 
62
63
  ```ts
63
64
  type WindowEvents = Readonly<{
65
+ onDeliveryPending?: () => void;
64
66
  onComputerChoice: () => Promise<void>;
65
67
  onNavigationState: (state) => void;
66
68
  onStatusItems: (items) => void;
@@ -211,8 +213,49 @@ Host adapters used to create, attach and validate window mounts.
211
213
  | `Launch` _extends_ [`WindowLaunch`](#windowlaunch) |
212
214
  | `Container` |
213
215
 
216
+ ## Variables
217
+
218
+ ### APP\_SURFACE\_DOCUMENT\_TIMEOUT\_MS
219
+
220
+ ```ts
221
+ const APP_SURFACE_DOCUMENT_TIMEOUT_MS: 30000 = 30_000;
222
+ ```
223
+
224
+ Existing cold-document bound, also used as one total preparation budget.
225
+
214
226
  ## Functions
215
227
 
228
+ ### prepareWithDeliveryRetry()
229
+
230
+ ```ts
231
+ function prepareWithDeliveryRetry<A>(prepare, signal, onPending): Promise<A>;
232
+ ```
233
+
234
+ Shell-only preparation retry. No document, connection or mounted operation
235
+ belongs inside `prepare`. Each fetch receives the interruptible attempt's
236
+ signal; the absolute budget covers both requests and backoff, never resets, and
237
+ is released as soon as preparation succeeds.
238
+
239
+ #### Type Parameters
240
+
241
+ | Type Parameter |
242
+ | -------------- |
243
+ | `A` |
244
+
245
+ #### Parameters
246
+
247
+ | Parameter | Type |
248
+ | ----------- | ------------------------------ |
249
+ | `prepare` | (`signal`) => `Promise`\<`A`\> |
250
+ | `signal` | `AbortSignal` |
251
+ | `onPending` | () => `void` |
252
+
253
+ #### Returns
254
+
255
+ `Promise`\<`A`\>
256
+
257
+ ---
258
+
216
259
  ### hasVisibleWindows()
217
260
 
218
261
  ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fungi.computer/nacre",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "author": "Levi <levi@technomancy.dev>",
5
5
  "description": "The shell client for hosting Apps: workbench, command host, keys, commands, window manager and App directory rows",
6
6
  "type": "module",
@@ -43,6 +43,10 @@
43
43
  "./workbench-directory": {
44
44
  "types": "./dist/workbench-directory.d.ts",
45
45
  "import": "./dist/workbench-directory.js"
46
+ },
47
+ "./website-channels": {
48
+ "types": "./dist/website-channels.d.ts",
49
+ "import": "./dist/website-channels.js"
46
50
  }
47
51
  },
48
52
  "files": [