@volter/world-core 3.0.9 → 3.0.11

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.
@@ -113,11 +113,41 @@ export type DerivedFetch = ((request: Request) => Promise<Response>) & {
113
113
  upgrade?: WebSocketUpgrade;
114
114
  /** The workspace screens it draws, its lanes' too (`GET /twin`'s `screens`). */
115
115
  workspaces?(): Workspace[];
116
+ /** Whether it lays out frames of the World's board (`semantics/board.ts`). */
117
+ boards?: boolean;
118
+ /** Whether a built screen of it takes a URL: a board frame it draws. */
119
+ draws?(url: string): boolean;
116
120
  };
117
121
  /** A workspace screen a pack draws, as `GET /twin` lists it: its id and path (Viewing a World). */
118
122
  export type Workspace = {
119
123
  id: string;
120
124
  path: string;
121
125
  };
126
+ /** A frame of the World's board (architecture, "The board"): one thing of the vendor's where a person sees it, as the
127
+ * vendor's pack lays out its default board (`semantics/board.ts`), the editorial choice of which views of the vendor a
128
+ * person keeps open (a Worker's site, a repository's page, a Jira board). `GET /twin/board` lists them. */
129
+ export type BoardFrame = {
130
+ /** stable within the vendor, whatever the World's ids: what a saved board names the frame by */
131
+ id: string;
132
+ /** what it is, in the vendor's own word (a site, a repository, a board) */
133
+ kind: string;
134
+ title: string;
135
+ /** the vendor's container it is grouped under (an account, an organization, a project); `aka`, the ids it was known
136
+ * by before (an account a deploy adopted), so a board that included it under one still holds it */
137
+ section: {
138
+ id: string;
139
+ title: string;
140
+ aka?: string[];
141
+ };
142
+ /** where the vendor shows it: an absolute URL on the vendor's host, or on a hostname the vendor serves for its customer */
143
+ url: string;
144
+ /** the records whose changes are this frame's changes */
145
+ covers: Array<{
146
+ type: string;
147
+ id: string;
148
+ }>;
149
+ /** set by the kernel, never the pack: whether a built screen of the vendor's (any of its lanes') draws the url */
150
+ drawn?: boolean;
151
+ };
122
152
  export declare function createDerivedFetch(options: DerivedFetchOptions): DerivedFetch;
123
153
  export {};
@@ -28,7 +28,7 @@ export type { MultipartPart } from './multipart.js';
28
28
  export declare const bindSemantics: (m: Parameters<typeof bindAny>[0], handlers: Record<string, Handler>, scope?: CoreScope) => Record<string, DerivedHandler>;
29
29
  export { createPackFetch, createVendorFetch, type LanePart, type PackFetchOptions, type PackParts, type PackScenario } from './pack-fetch.js';
30
30
  export { createDerivedFetch } from './derived.js';
31
- export type { DerivedCall, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedSurface } from './derived.js';
31
+ export type { DerivedCall, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedSurface, BoardFrame } from './derived.js';
32
32
  export { coreFor, crossCutting, derivedRequestScopes, vendorError } from './derived-core.js';
33
33
  export { answerVendorErrors, RefusedWriteError } from './head.js';
34
34
  export { GraphqlError, type GraphqlPart, type GraphqlResolver } from './graphql-wire.js';
@@ -1,5 +1,5 @@
1
1
  import { type DerivedManifest, type Handler, type HandlerContext, type VendorManifest } from './derived-core.js';
2
- import { type DerivedFetch, type DerivedOwner, type DerivedSurface, type Workspace } from './derived.js';
2
+ import { type DerivedFetch, type DerivedOwner, type DerivedSurface, type Workspace, type BoardFrame } from './derived.js';
3
3
  import { type PackScenarioAdapter } from './scenario.js';
4
4
  import { type SocketEngine } from './sockets.js';
5
5
  import { type GraphqlPart } from './graphql-wire.js';
@@ -39,6 +39,8 @@ export type PackParts = {
39
39
  };
40
40
  /** `semantics/sockets.ts`: each socket's engine, by the id the manifest's `sockets` gives it (sockets.ts). */
41
41
  sockets?: Record<string, SocketEngine<HandlerContext>>;
42
+ /** `semantics/board.ts`: the vendor's frames on the World's board, read from its state (`GET /twin/board`). */
43
+ board?: (ctx: HandlerContext) => BoardFrame[] | Promise<BoardFrame[]>;
42
44
  };
43
45
  /** A pack's scenario (`semantics/scenario.ts` exports `scenario`): the adapter the kernel's engine reads the World's
44
46
  * scenario document with, the operations it decides a turn of, and the request an operation is to it (undefined when
@@ -52,6 +54,8 @@ export type PackScenario<Req = any> = {
52
54
  export type LanePart = {
53
55
  fetch: ((request: Request) => Promise<Response>) & {
54
56
  serves?: (method: string, path: string) => boolean;
57
+ boards?: boolean;
58
+ draws?: (url: string) => boolean;
55
59
  };
56
60
  manifest: {
57
61
  doors?: ReadonlyArray<{
@@ -211,7 +211,19 @@ export function createPackFetch(parts, options = {}) {
211
211
  // the workspaces a person can be shown (Viewing a World): each built workspace screen's id and path, the pack's own
212
212
  // and its lanes'
213
213
  const workspaces = () => [...(m.screens ?? []).filter((s) => s.kind === 'workspace' && s.status === 'done' && parts.screens?.[s.id]).map((s) => ({ id: s.id, path: s.path })), ...lanesWorkspaces(parts.lanes ?? {})];
214
- // a context the kernel opens for what no surface operation names: a door, a screen, the clock
214
+ /** Whether a built screen a person views (a workspace or a flow, never content an API client reads) draws a url: its host
215
+ * one the screen names, its path the screen's or under it (a root screen draws its root alone). */
216
+ const drawsUrl = (at) => {
217
+ try {
218
+ const u = new URL(at);
219
+ const path = u.pathname.replace(/\/+$/, '') || '/';
220
+ return screens.some((s) => s.decl.kind !== 'content' && Boolean(s.host(u.hostname.toLowerCase())) && (s.decl.path.replace(/\/+$/, '') === '' ? path === '/' : Boolean(s.path(path))));
221
+ }
222
+ catch {
223
+ return false;
224
+ }
225
+ };
226
+ // a context the kernel opens for what no surface operation names: a door, a screen, the clock, the board
215
227
  const open = (request, id, method, path, params) => contextFor(m, { request, operation: { id, method, path, class: method === 'GET' ? 'retrieve' : 'action' }, params }, scope);
216
228
  const refusedReadOnly = () => vendorError(m, m.readOnly);
217
229
  const prefix = m.pathPrefix ? new RegExp(`^(?:${m.pathPrefix})(?=/)`) : undefined;
@@ -246,6 +258,15 @@ export function createPackFetch(parts, options = {}) {
246
258
  // the discovery door is the pack's own, whichever lane would take its path
247
259
  const asked = new URL(arrived.url).pathname.replace(/\/+$/, '') || '/';
248
260
  const discovery = arrived.method === 'GET' && m.discovery !== undefined && (asked === '/twin' || asked === '/twin/scenario');
261
+ // the board is read from the state as it stands, before anything else runs (the clock, a lane, the API): a read,
262
+ // whoever asks, each frame drawn when a built screen takes its url; a pack that lays out none has an empty board
263
+ if (arrived.method === 'GET' && asked === '/twin/board') {
264
+ if (!parts.board)
265
+ return Response.json({ frames: [] });
266
+ const request = withHeaders(arrived, new Headers([...arrived.headers, [READ_ONLY_REQUEST_HEADER, '1']]));
267
+ const frames = await parts.board(await open(request, 'board', 'GET', '/twin/board', {}));
268
+ return Response.json({ frames: frames.map((f) => ({ ...f, drawn: drawsUrl(f.url) })) });
269
+ }
249
270
  const toLane = discovery ? undefined : lane?.(arrived);
250
271
  if (toLane)
251
272
  return toLane(arrived);
@@ -400,7 +421,7 @@ export function createPackFetch(parts, options = {}) {
400
421
  async (asked) => engineOf()?.serve(asked)) : undefined;
401
422
  // what serves each operation: the pack's own, and each lane's
402
423
  const owners = () => ({ ...api.owners(), ...lanesOwners(parts.lanes ?? {}) });
403
- return derivedRequestScopes(m, Object.assign(served, { owners, serves, workspaces, ...(upgrade ? { upgrade } : {}) }));
424
+ return derivedRequestScopes(m, Object.assign(served, { owners, serves, workspaces, boards: Boolean(parts.board), draws: drawsUrl, ...(upgrade ? { upgrade } : {}) }));
404
425
  }
405
426
  /** The vendor's gateway over its lanes: the lane a request goes to (a door to the lane that declares it, then the first
406
427
  * route whose conditions all hold, then the default), behind the gateway's CORS; undefined when none takes it. */
@@ -456,6 +477,22 @@ export function createVendorFetch(manifest, lanes) {
456
477
  const lane = laneRouter(manifest.vendor, manifest.lanes, lanes);
457
478
  return Object.assign(async (request) => {
458
479
  const path = new URL(request.url).pathname.replace(/\/+$/, '') || '/';
480
+ // the vendor's board is the frames of the lanes that lay one out, each drawn when any lane's screen takes its url
481
+ if (request.method === 'GET' && path === '/twin/board') {
482
+ const frames = [];
483
+ for (const l of Object.values(lanes)) {
484
+ if (!l.fetch.boards)
485
+ continue;
486
+ try {
487
+ const answer = await l.fetch(new Request(request.url, { headers: request.headers }));
488
+ if (answer.ok)
489
+ frames.push(...((await answer.json()).frames ?? []));
490
+ }
491
+ catch { /* a lane whose board does not answer lays out nothing */ }
492
+ }
493
+ const draws = (url) => Object.values(lanes).some((l) => l.fetch.draws?.(url) ?? false);
494
+ return Response.json({ frames: frames.map((f) => ({ ...f, drawn: draws(f.url) })) });
495
+ }
459
496
  if (request.method === 'GET' && path === '/twin' && manifest.discovery) {
460
497
  // the vendor's screens are its lanes' (a dashboard drawn by one lane is the vendor's)
461
498
  const screens = lanesWorkspaces(lanes);
@@ -8,7 +8,7 @@ export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER, ReadOnlyRequestError, runA
8
8
  export { compileSurface, createDerivedFetch, matchOperation } from './derived.js';
9
9
  export { currentTraceparent, deliveryTraceHeaders, newTraceparent, parseTraceparent, runWithRequestTrace, runWithTraceparent, TRACEPARENT_HEADER, traceparentForDelivery, validTraceparent } from './trace-context.js';
10
10
  export type { Traceparent } from './trace-context.js';
11
- export type { DerivedCall, DerivedCoreOutcome, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface } from './derived.js';
11
+ export type { DerivedCall, DerivedCoreOutcome, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface, BoardFrame } from './derived.js';
12
12
  export { authRefusal, bindSemantics, coreFor, crossCutting, flagOf, derivedRequestScopes, observeTransitions, resourcesOfType as twinResourcesOfType, semanticsContext, stateOf, transitionFor, parseBracketForm, readParams, render as renderDerived, serveCore, sse, vendorError } from './derived-core.js';
13
13
  export { deliverEvents, fillEnvelope, signEvent, signEventAll, verifyEvent } from './events.js';
14
14
  export { equalSecrets, hmac, jwks, jwtDecode, jwtSign, jwtVerify, keyId, lettersFrom, md5, sha256, SIGNING_ALGORITHMS, uuidFrom } from './signing.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/world-core",
3
- "version": "3.0.9",
3
+ "version": "3.0.11",
4
4
  "description": "The kernel of Volter World: one log per twin, branches as pointers, checkpoints, the fold that keeps a twin current, the head that performs a write against the vendor, references, and the git plane. A twin package builds on it; the runtime serves it.",
5
5
  "keywords": [
6
6
  "twin",
package/src/derived.ts CHANGED
@@ -198,11 +198,35 @@ export type DerivedFetch = ((request: Request) => Promise<Response>) & {
198
198
  upgrade?: WebSocketUpgrade;
199
199
  /** The workspace screens it draws, its lanes' too (`GET /twin`'s `screens`). */
200
200
  workspaces?(): Workspace[];
201
+ /** Whether it lays out frames of the World's board (`semantics/board.ts`). */
202
+ boards?: boolean;
203
+ /** Whether a built screen of it takes a URL: a board frame it draws. */
204
+ draws?(url: string): boolean;
201
205
  };
202
206
 
203
207
  /** A workspace screen a pack draws, as `GET /twin` lists it: its id and path (Viewing a World). */
204
208
  export type Workspace = { id: string; path: string };
205
209
 
210
+ /** A frame of the World's board (architecture, "The board"): one thing of the vendor's where a person sees it, as the
211
+ * vendor's pack lays out its default board (`semantics/board.ts`), the editorial choice of which views of the vendor a
212
+ * person keeps open (a Worker's site, a repository's page, a Jira board). `GET /twin/board` lists them. */
213
+ export type BoardFrame = {
214
+ /** stable within the vendor, whatever the World's ids: what a saved board names the frame by */
215
+ id: string;
216
+ /** what it is, in the vendor's own word (a site, a repository, a board) */
217
+ kind: string;
218
+ title: string;
219
+ /** the vendor's container it is grouped under (an account, an organization, a project); `aka`, the ids it was known
220
+ * by before (an account a deploy adopted), so a board that included it under one still holds it */
221
+ section: { id: string; title: string; aka?: string[] };
222
+ /** where the vendor shows it: an absolute URL on the vendor's host, or on a hostname the vendor serves for its customer */
223
+ url: string;
224
+ /** the records whose changes are this frame's changes */
225
+ covers: Array<{ type: string; id: string }>;
226
+ /** set by the kernel, never the pack: whether a built screen of the vendor's (any of its lanes') draws the url */
227
+ drawn?: boolean;
228
+ };
229
+
206
230
  export function createDerivedFetch(options: DerivedFetchOptions): DerivedFetch {
207
231
  const handlers = options.handlers ?? {};
208
232
  const known = new Set(options.surface.operations.map((o) => o.id));
package/src/index.ts CHANGED
@@ -39,7 +39,7 @@ export const bindSemantics = (m: Parameters<typeof bindAny>[0], handlers: Record
39
39
  // ── the derived fetch ──────────────────────────────────────────────────────────────────────────
40
40
  export { createPackFetch, createVendorFetch, type LanePart, type PackFetchOptions, type PackParts, type PackScenario } from './pack-fetch.ts';
41
41
  export { createDerivedFetch } from './derived.ts';
42
- export type { DerivedCall, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedSurface } from './derived.ts';
42
+ export type { DerivedCall, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedSurface, BoardFrame } from './derived.ts';
43
43
  export { coreFor, crossCutting, derivedRequestScopes, vendorError } from './derived-core.ts';
44
44
  export { answerVendorErrors, RefusedWriteError } from './head.ts';
45
45
  // a GraphQL API's resolvers (`semantics/graphql.ts`), and the error one answers with the vendor's type
package/src/pack-fetch.ts CHANGED
@@ -10,7 +10,7 @@ import { TWIN_PREFIX_HEADER } from './twin-fetch.ts';
10
10
  import { PREFIX_PARAMS_HEADER } from './derived.ts';
11
11
  import { withHeaders } from './with-headers.ts';
12
12
  import { authRefusal, bindSemantics, contextFor, LANE_HEADER, SCENARIO_DECISION_HEADER, coreFor, crossCutting, derivedRequestScopes, vendorError, type CoreScope, type DerivedManifest, type ErrorSpec, type Handler, type HandlerContext, type LanesDecl, type VendorManifest } from './derived-core.ts';
13
- import { compileSurface, createDerivedFetch, matchOperation, type DerivedFetch, type DerivedOperation, type DerivedOwner, type DerivedSurface, type Workspace } from './derived.ts';
13
+ import { compileSurface, createDerivedFetch, matchOperation, type DerivedFetch, type DerivedOperation, type DerivedOwner, type DerivedSurface, type Workspace, type BoardFrame } from './derived.ts';
14
14
  import { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER, runAsVendorMove } from './request-scope.ts';
15
15
  import { parseScenarioDocument, ScenarioEngine, ScenarioError, statefulTwinManifest, twinManifest, type PackScenarioAdapter } from './scenario.ts';
16
16
  import { getActiveWorldStore } from './world-store.ts';
@@ -57,6 +57,8 @@ export type PackParts = {
57
57
  graphql?: GraphqlPart<HandlerContext> & { sdl: string };
58
58
  /** `semantics/sockets.ts`: each socket's engine, by the id the manifest's `sockets` gives it (sockets.ts). */
59
59
  sockets?: Record<string, SocketEngine<HandlerContext>>;
60
+ /** `semantics/board.ts`: the vendor's frames on the World's board, read from its state (`GET /twin/board`). */
61
+ board?: (ctx: HandlerContext) => BoardFrame[] | Promise<BoardFrame[]>;
60
62
  };
61
63
 
62
64
  /** A pack's scenario (`semantics/scenario.ts` exports `scenario`): the adapter the kernel's engine reads the World's
@@ -66,7 +68,7 @@ export type PackParts = {
66
68
  export type PackScenario<Req = any> = { adapter: PackScenarioAdapter<Req>; operations: ReadonlyArray<string>; request: (ctx: HandlerContext) => Req | undefined };
67
69
 
68
70
  /** A lane as its vendor's fetch is given it: its own pack fetch, and its manifest (the doors it declares). */
69
- export type LanePart = { fetch: ((request: Request) => Promise<Response>) & { serves?: (method: string, path: string) => boolean }; manifest: { doors?: ReadonlyArray<{ method: string; path: string }> } };
71
+ export type LanePart = { fetch: ((request: Request) => Promise<Response>) & { serves?: (method: string, path: string) => boolean; boards?: boolean; draws?: (url: string) => boolean }; manifest: { doors?: ReadonlyArray<{ method: string; path: string }> } };
70
72
 
71
73
  /** Where a pack serves: its World's root, whether it was started read-only, the World instant when a caller pins it, the
72
74
  * World's managed Postgres the runtime binds a pack declaring `managedDatabase` to (a handler's `ctx.engine`), and the
@@ -245,7 +247,15 @@ export function createPackFetch(parts: PackParts, options: PackFetchOptions = {}
245
247
  // the workspaces a person can be shown (Viewing a World): each built workspace screen's id and path, the pack's own
246
248
  // and its lanes'
247
249
  const workspaces = (): Workspace[] => [...(m.screens ?? []).filter((s) => s.kind === 'workspace' && s.status === 'done' && parts.screens?.[s.id]).map((s) => ({ id: s.id, path: s.path })), ...lanesWorkspaces(parts.lanes ?? {})];
248
- // a context the kernel opens for what no surface operation names: a door, a screen, the clock
250
+ /** Whether a built screen a person views (a workspace or a flow, never content an API client reads) draws a url: its host
251
+ * one the screen names, its path the screen's or under it (a root screen draws its root alone). */
252
+ const drawsUrl = (at: string): boolean => {
253
+ try {
254
+ const u = new URL(at); const path = u.pathname.replace(/\/+$/, '') || '/';
255
+ return screens.some((s) => s.decl.kind !== 'content' && Boolean(s.host(u.hostname.toLowerCase())) && (s.decl.path.replace(/\/+$/, '') === '' ? path === '/' : Boolean(s.path(path))));
256
+ } catch { return false; }
257
+ };
258
+ // a context the kernel opens for what no surface operation names: a door, a screen, the clock, the board
249
259
  const open = (request: Request, id: string, method: string, path: string, params: Record<string, string>): Promise<HandlerContext> =>
250
260
  contextFor(m, { request, operation: { id, method, path, class: method === 'GET' ? 'retrieve' : 'action' } as DerivedOperation, params }, scope);
251
261
  const refusedReadOnly = (): Response => vendorError(m, m.readOnly);
@@ -278,6 +288,14 @@ export function createPackFetch(parts: PackParts, options: PackFetchOptions = {}
278
288
  // the discovery door is the pack's own, whichever lane would take its path
279
289
  const asked = new URL(arrived.url).pathname.replace(/\/+$/, '') || '/';
280
290
  const discovery = arrived.method === 'GET' && m.discovery !== undefined && (asked === '/twin' || asked === '/twin/scenario');
291
+ // the board is read from the state as it stands, before anything else runs (the clock, a lane, the API): a read,
292
+ // whoever asks, each frame drawn when a built screen takes its url; a pack that lays out none has an empty board
293
+ if (arrived.method === 'GET' && asked === '/twin/board') {
294
+ if (!parts.board) return Response.json({ frames: [] });
295
+ const request = withHeaders(arrived, new Headers([...arrived.headers, [READ_ONLY_REQUEST_HEADER, '1']]));
296
+ const frames = await parts.board(await open(request, 'board', 'GET', '/twin/board', {}));
297
+ return Response.json({ frames: frames.map((f) => ({ ...f, drawn: drawsUrl(f.url) })) });
298
+ }
281
299
  const toLane = discovery ? undefined : lane?.(arrived);
282
300
  if (toLane) return toLane(arrived);
283
301
  // only the kernel names a scenario's decision, or a path prefix's parameters
@@ -407,7 +425,7 @@ export function createPackFetch(parts: PackParts, options: PackFetchOptions = {}
407
425
  async (asked) => engineOf()?.serve(asked)) : undefined;
408
426
  // what serves each operation: the pack's own, and each lane's
409
427
  const owners = (): Record<string, DerivedOwner> => ({ ...api.owners(), ...lanesOwners(parts.lanes ?? {}) });
410
- return derivedRequestScopes(m, Object.assign(served, { owners, serves, workspaces, ...(upgrade ? { upgrade } : {}) }));
428
+ return derivedRequestScopes(m, Object.assign(served, { owners, serves, workspaces, boards: Boolean(parts.board), draws: drawsUrl, ...(upgrade ? { upgrade } : {}) }));
411
429
  }
412
430
 
413
431
  /** The vendor's gateway over its lanes: the lane a request goes to (a door to the lane that declares it, then the first
@@ -468,6 +486,19 @@ export function createVendorFetch(manifest: VendorManifest, lanes: Record<string
468
486
  const lane = laneRouter(manifest.vendor, manifest.lanes, lanes);
469
487
  return Object.assign(async (request: Request): Promise<Response> => {
470
488
  const path = new URL(request.url).pathname.replace(/\/+$/, '') || '/';
489
+ // the vendor's board is the frames of the lanes that lay one out, each drawn when any lane's screen takes its url
490
+ if (request.method === 'GET' && path === '/twin/board') {
491
+ const frames: BoardFrame[] = [];
492
+ for (const l of Object.values(lanes)) {
493
+ if (!l.fetch.boards) continue;
494
+ try {
495
+ const answer = await l.fetch(new Request(request.url, { headers: request.headers }));
496
+ if (answer.ok) frames.push(...(((await answer.json()) as { frames?: BoardFrame[] }).frames ?? []));
497
+ } catch { /* a lane whose board does not answer lays out nothing */ }
498
+ }
499
+ const draws = (url: string): boolean => Object.values(lanes).some((l) => l.fetch.draws?.(url) ?? false);
500
+ return Response.json({ frames: frames.map((f) => ({ ...f, drawn: draws(f.url) })) });
501
+ }
471
502
  if (request.method === 'GET' && path === '/twin' && manifest.discovery) {
472
503
  // the vendor's screens are its lanes' (a dashboard drawn by one lane is the vendor's)
473
504
  const screens = lanesWorkspaces(lanes);
package/src/runtime.ts CHANGED
@@ -17,7 +17,7 @@ export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER, ReadOnlyRequestError, runA
17
17
  export { compileSurface, createDerivedFetch, matchOperation } from './derived.ts';
18
18
  export { currentTraceparent, deliveryTraceHeaders, newTraceparent, parseTraceparent, runWithRequestTrace, runWithTraceparent, TRACEPARENT_HEADER, traceparentForDelivery, validTraceparent } from './trace-context.ts';
19
19
  export type { Traceparent } from './trace-context.ts';
20
- export type { DerivedCall, DerivedCoreOutcome, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface } from './derived.ts';
20
+ export type { DerivedCall, DerivedCoreOutcome, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface, BoardFrame } from './derived.ts';
21
21
  export { authRefusal, bindSemantics, coreFor, crossCutting, flagOf, derivedRequestScopes, observeTransitions, resourcesOfType as twinResourcesOfType, semanticsContext, stateOf, transitionFor, parseBracketForm, readParams, render as renderDerived, serveCore, sse, vendorError } from './derived-core.ts';
22
22
  export { deliverEvents, fillEnvelope, signEvent, signEventAll, verifyEvent } from './events.ts';
23
23
  export { equalSecrets, hmac, jwks, jwtDecode, jwtSign, jwtVerify, keyId, lettersFrom, md5, sha256, SIGNING_ALGORITHMS, uuidFrom } from './signing.ts';