@neta-art/cohub 5.3.2 → 5.4.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.
- package/dist/board/codec.d.ts +2 -0
- package/dist/board/codec.js +18 -13
- package/dist/board/core/arrow-geometry.d.ts +23 -0
- package/dist/board/core/arrow-geometry.js +109 -0
- package/dist/board/core/connections.d.ts +83 -0
- package/dist/board/core/connections.js +399 -0
- package/dist/board/core/export-plan.d.ts +15 -4
- package/dist/board/core/export-plan.js +49 -16
- package/dist/board/core/shape-definition.js +1 -1
- package/dist/board/core/shape-types.d.ts +8 -2
- package/dist/board/core/shape-types.js +1 -1
- package/dist/board/core/tool-styles.d.ts +9 -3
- package/dist/board/core/tool-styles.js +10 -6
- package/dist/board/export/index.js +1 -0
- package/dist/board/export/scene.d.ts +3 -0
- package/dist/board/export/scene.js +18 -1
- package/dist/board/index.d.ts +8 -5
- package/dist/board/index.js +8 -5
- package/dist/board/render/connection-layer.d.ts +48 -0
- package/dist/board/render/connection-layer.js +223 -0
- package/dist/board/render/index.d.ts +2 -1
- package/dist/board/render/index.js +3 -2
- package/dist/board/render/renderers/arrow-card-renderer.js +35 -48
- package/dist/chunks/http.d.ts +53 -1
- package/dist/chunks/http.js +287 -1
- package/dist/chunks/websocket.d.ts +296 -57
- package/dist/http.d.ts +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/index.js +22 -58
- package/dist/protocol/dist/board-connection.d.ts +310 -0
- package/dist/protocol/dist/board-connection.js +215 -0
- package/dist/protocol/dist/board-constants.d.ts +11 -1
- package/dist/protocol/dist/board-constants.js +15 -1
- package/dist/protocol/dist/board-document.d.ts +106 -60
- package/dist/protocol/dist/board-document.js +57 -17
- package/dist/protocol/dist/board.d.ts +1 -0
- package/dist/protocol/dist/board.js +3 -0
- package/dist/protocol/dist/index.d.ts +2 -1
- package/dist/protocol/dist/index.js +2 -1
- package/dist/protocol/dist/realtime/board-awareness.js +15 -15
- package/docs/work-runtime-guide.md +1 -1
- package/package.json +1 -1
- package/dist/board/core/bindings.d.ts +0 -45
- package/dist/board/core/bindings.js +0 -162
package/dist/chunks/http.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { D as getRealtimeSpaceRoom, E as getRealtimeBoardRoom, n as HttpTransport, t as HttpError } from "./transport.js";
|
|
2
2
|
import { a as resolveApiBaseUrl } from "./environment.js";
|
|
3
|
+
import { z } from "zod";
|
|
3
4
|
//#region src/apis/channels.ts
|
|
4
5
|
var ChannelsApi = class {
|
|
5
6
|
transport;
|
|
@@ -439,6 +440,199 @@ var SessionAccessApi = class {
|
|
|
439
440
|
}
|
|
440
441
|
};
|
|
441
442
|
//#endregion
|
|
443
|
+
//#region ../protocol/dist/board-constants.js
|
|
444
|
+
const DEFAULT_BOARD_RENDER_LIMITS = {
|
|
445
|
+
particles: 2e4,
|
|
446
|
+
vertices: 5e5,
|
|
447
|
+
dynamicVertices: 15e4,
|
|
448
|
+
drawCalls: 400,
|
|
449
|
+
filterPasses: 24,
|
|
450
|
+
renderTexturePixels: 16777216,
|
|
451
|
+
textureBytes: 512 * 1024 * 1024,
|
|
452
|
+
bufferBytes: 256 * 1024 * 1024,
|
|
453
|
+
simulationSteps: 1e5
|
|
454
|
+
};
|
|
455
|
+
const BOARD_BUILTIN_CLIP_KINDS = [
|
|
456
|
+
"motion.keyframes",
|
|
457
|
+
"motion.path",
|
|
458
|
+
"draw.reveal",
|
|
459
|
+
"draw.handwrite",
|
|
460
|
+
"text.reveal",
|
|
461
|
+
"effects.particles",
|
|
462
|
+
"effects.trail",
|
|
463
|
+
"effects.impact",
|
|
464
|
+
"effects.flash",
|
|
465
|
+
"effects.color",
|
|
466
|
+
"camera.pan",
|
|
467
|
+
"camera.zoom",
|
|
468
|
+
"camera.shake"
|
|
469
|
+
];
|
|
470
|
+
const BOARD_BUILTIN_EFFECT_KINDS = ["effects.pulse", "effects.float"];
|
|
471
|
+
const BOARD_ARROW_STROKE_SIZE = 2.5;
|
|
472
|
+
const BOARD_CONNECTION_STROKE_SIZE = 2.5;
|
|
473
|
+
function clampBoardStrokeSize(size) {
|
|
474
|
+
if (!Number.isFinite(size)) return BOARD_CONNECTION_STROKE_SIZE;
|
|
475
|
+
return Math.min(64, Math.max(1, size));
|
|
476
|
+
}
|
|
477
|
+
const BOARD_BUILTIN_CAPABILITIES = [...BOARD_BUILTIN_CLIP_KINDS.map((id) => ({
|
|
478
|
+
kind: "clip",
|
|
479
|
+
id,
|
|
480
|
+
version: 1,
|
|
481
|
+
renderers: ["webgpu", "webgl"]
|
|
482
|
+
})), ...BOARD_BUILTIN_EFFECT_KINDS.map((id) => ({
|
|
483
|
+
kind: "effect",
|
|
484
|
+
id,
|
|
485
|
+
version: 1,
|
|
486
|
+
renderers: ["webgpu", "webgl"]
|
|
487
|
+
}))];
|
|
488
|
+
/**
|
|
489
|
+
* Where a connection meets its node.
|
|
490
|
+
*
|
|
491
|
+
* - `auto` — the side is chosen from the live geometry of both endpoints, so the
|
|
492
|
+
* connection stays sensible through any move or resize. This is the default and
|
|
493
|
+
* what almost every connection should use.
|
|
494
|
+
* - `side` — the user pinned a side; `offset` (0..1) positions it along that edge.
|
|
495
|
+
* - `fixed` — the user pinned an exact normalized point on the frame.
|
|
496
|
+
*
|
|
497
|
+
* `auto` is a *declaration of intent*, not a computed value: the resolved side is
|
|
498
|
+
* never written back, so the connection keeps adapting instead of freezing the
|
|
499
|
+
* first layout it happened to have.
|
|
500
|
+
*/
|
|
501
|
+
const BoardConnectionAnchorSchema = z.union([
|
|
502
|
+
z.object({ kind: z.literal("auto") }),
|
|
503
|
+
z.object({
|
|
504
|
+
kind: z.literal("side"),
|
|
505
|
+
side: z.enum([
|
|
506
|
+
"top",
|
|
507
|
+
"right",
|
|
508
|
+
"bottom",
|
|
509
|
+
"left"
|
|
510
|
+
]),
|
|
511
|
+
offset: z.number().finite().min(0).max(1).default(.5)
|
|
512
|
+
}),
|
|
513
|
+
z.object({
|
|
514
|
+
kind: z.literal("fixed"),
|
|
515
|
+
nx: z.number().finite().min(0).max(1),
|
|
516
|
+
ny: z.number().finite().min(0).max(1)
|
|
517
|
+
})
|
|
518
|
+
]);
|
|
519
|
+
const AUTO_BOARD_CONNECTION_ANCHOR = { kind: "auto" };
|
|
520
|
+
const BoardConnectionEndpointSchema = z.object({
|
|
521
|
+
nodeId: z.string().min(1).max(160),
|
|
522
|
+
anchor: BoardConnectionAnchorSchema.default(AUTO_BOARD_CONNECTION_ANCHOR)
|
|
523
|
+
});
|
|
524
|
+
/**
|
|
525
|
+
* Which ends carry an arrowhead.
|
|
526
|
+
*
|
|
527
|
+
* This is the *semantic* direction, not a style flag: `forward` means the
|
|
528
|
+
* relation reads source → target, `backward` means target → source, and `none`
|
|
529
|
+
* means the relation is symmetric. Renderers derive arrowheads from it, so the
|
|
530
|
+
* drawing can never disagree with the meaning.
|
|
531
|
+
*/
|
|
532
|
+
const BOARD_CONNECTION_DIRECTIONS = [
|
|
533
|
+
"none",
|
|
534
|
+
"forward",
|
|
535
|
+
"backward",
|
|
536
|
+
"both"
|
|
537
|
+
];
|
|
538
|
+
/** How the line travels between its two resolved endpoints. */
|
|
539
|
+
const BOARD_CONNECTION_ROUTINGS = [
|
|
540
|
+
"straight",
|
|
541
|
+
"curve",
|
|
542
|
+
"orthogonal"
|
|
543
|
+
];
|
|
544
|
+
const BOARD_CONNECTION_LINES = ["solid", "dashed"];
|
|
545
|
+
/**
|
|
546
|
+
* Relation kind — a free-form slug, not an enum.
|
|
547
|
+
*
|
|
548
|
+
* Boards are used for domains we do not control, so a closed vocabulary would
|
|
549
|
+
* force unrelated meanings into the wrong bucket. The format is constrained
|
|
550
|
+
* (lowercase, dash/dot separated) so relations stay comparable and queryable
|
|
551
|
+
* across clients instead of accumulating near-duplicate spellings.
|
|
552
|
+
*/
|
|
553
|
+
const BoardRelationSchema = z.string().min(1).max(64).regex(/^[a-z0-9]+(?:[.-][a-z0-9]+)*$/, "relation must be a lowercase slug").default("related");
|
|
554
|
+
/**
|
|
555
|
+
* Waypoints a user dragged the line through, in world space.
|
|
556
|
+
*
|
|
557
|
+
* Stored because they are *input*, not output: the resolved path is recomputed
|
|
558
|
+
* from them on every read, but the intent behind a hand-routed line cannot be
|
|
559
|
+
* recovered once discarded.
|
|
560
|
+
*/
|
|
561
|
+
const BoardConnectionWaypointSchema = z.object({
|
|
562
|
+
x: z.number().finite(),
|
|
563
|
+
y: z.number().finite()
|
|
564
|
+
});
|
|
565
|
+
const BoardConnectionRoutingSchema = z.object({
|
|
566
|
+
kind: z.enum(BOARD_CONNECTION_ROUTINGS).default("curve"),
|
|
567
|
+
/** Curve bow as a fraction of endpoint distance (-0.85..0.85). */
|
|
568
|
+
bend: z.number().finite().min(-.85).max(.85).default(0),
|
|
569
|
+
waypoints: z.array(BoardConnectionWaypointSchema).max(64).default([])
|
|
570
|
+
});
|
|
571
|
+
const BoardConnectionStyleSchema = z.object({
|
|
572
|
+
/** Palette color id, resolved to a theme token at render time. */
|
|
573
|
+
color: z.string().min(1).max(40).default("brand"),
|
|
574
|
+
size: z.number().finite().positive().default(BOARD_CONNECTION_STROKE_SIZE),
|
|
575
|
+
line: z.enum(BOARD_CONNECTION_LINES).default("solid")
|
|
576
|
+
});
|
|
577
|
+
const DEFAULT_BOARD_CONNECTION_ROUTING = {
|
|
578
|
+
kind: "curve",
|
|
579
|
+
bend: 0,
|
|
580
|
+
waypoints: []
|
|
581
|
+
};
|
|
582
|
+
const DEFAULT_BOARD_CONNECTION_STYLE = {
|
|
583
|
+
color: "brand",
|
|
584
|
+
size: BOARD_CONNECTION_STROKE_SIZE,
|
|
585
|
+
line: "solid"
|
|
586
|
+
};
|
|
587
|
+
const BoardConnectionSchema = z.object({
|
|
588
|
+
id: z.string().min(1).max(160),
|
|
589
|
+
source: BoardConnectionEndpointSchema,
|
|
590
|
+
target: BoardConnectionEndpointSchema,
|
|
591
|
+
relation: BoardRelationSchema,
|
|
592
|
+
direction: z.enum(BOARD_CONNECTION_DIRECTIONS).default("forward"),
|
|
593
|
+
label: z.string().max(280).default(""),
|
|
594
|
+
routing: BoardConnectionRoutingSchema.default(DEFAULT_BOARD_CONNECTION_ROUTING),
|
|
595
|
+
style: BoardConnectionStyleSchema.default(DEFAULT_BOARD_CONNECTION_STYLE),
|
|
596
|
+
metadata: z.record(z.string(), z.unknown()).default({})
|
|
597
|
+
});
|
|
598
|
+
BoardConnectionSchema.omit({ id: true }).partial();
|
|
599
|
+
function normalizeBoardConnectionStyle(style) {
|
|
600
|
+
return {
|
|
601
|
+
color: style?.color?.trim() || DEFAULT_BOARD_CONNECTION_STYLE.color,
|
|
602
|
+
size: clampBoardStrokeSize(typeof style?.size === "number" && Number.isFinite(style.size) ? style.size : DEFAULT_BOARD_CONNECTION_STYLE.size),
|
|
603
|
+
line: style?.line ?? DEFAULT_BOARD_CONNECTION_STYLE.line
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Build a connection with every default filled in.
|
|
608
|
+
*
|
|
609
|
+
* Callers only state what they mean (which nodes, and optionally the relation),
|
|
610
|
+
* so a connection created by the editor, an agent or the CLI is byte-identical
|
|
611
|
+
* for the same intent.
|
|
612
|
+
*/
|
|
613
|
+
function createBoardConnection(input) {
|
|
614
|
+
return {
|
|
615
|
+
id: input.id,
|
|
616
|
+
source: {
|
|
617
|
+
nodeId: input.sourceNodeId,
|
|
618
|
+
anchor: input.sourceAnchor ?? AUTO_BOARD_CONNECTION_ANCHOR
|
|
619
|
+
},
|
|
620
|
+
target: {
|
|
621
|
+
nodeId: input.targetNodeId,
|
|
622
|
+
anchor: input.targetAnchor ?? AUTO_BOARD_CONNECTION_ANCHOR
|
|
623
|
+
},
|
|
624
|
+
relation: input.relation ?? "related",
|
|
625
|
+
direction: input.direction ?? "forward",
|
|
626
|
+
label: input.label ?? "",
|
|
627
|
+
routing: {
|
|
628
|
+
...DEFAULT_BOARD_CONNECTION_ROUTING,
|
|
629
|
+
...input.routing
|
|
630
|
+
},
|
|
631
|
+
style: normalizeBoardConnectionStyle(input.style),
|
|
632
|
+
metadata: input.metadata ?? {}
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
//#endregion
|
|
442
636
|
//#region src/realtime.ts
|
|
443
637
|
function ensureRealtimeConnected(websocketClient) {
|
|
444
638
|
if (websocketClient.state === "open" || websocketClient.state === "connecting" || websocketClient.state === "reconnecting") return;
|
|
@@ -1476,6 +1670,18 @@ var BoardTransactionError = class extends Error {
|
|
|
1476
1670
|
return this.code === "VERSION_CONFLICT";
|
|
1477
1671
|
}
|
|
1478
1672
|
};
|
|
1673
|
+
/**
|
|
1674
|
+
* Identifier for a client-authored Board entity (connection id, transaction id).
|
|
1675
|
+
*
|
|
1676
|
+
* `crypto.randomUUID` is used where available and falls back to a random string
|
|
1677
|
+
* otherwise, so the SDK works in a plain browser, a worker and Node without
|
|
1678
|
+
* pulling in a polyfill.
|
|
1679
|
+
*/
|
|
1680
|
+
function randomBoardId() {
|
|
1681
|
+
const cryptoRef = globalThis.crypto;
|
|
1682
|
+
if (cryptoRef && typeof cryptoRef.randomUUID === "function") return cryptoRef.randomUUID();
|
|
1683
|
+
return `c-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1684
|
+
}
|
|
1479
1685
|
const toSessionEventName = (type) => {
|
|
1480
1686
|
switch (type) {
|
|
1481
1687
|
case "session.created": return "created";
|
|
@@ -2405,6 +2611,86 @@ var BoardClient = class {
|
|
|
2405
2611
|
playback(command) {
|
|
2406
2612
|
return this.boards.playback(this.id, command);
|
|
2407
2613
|
}
|
|
2614
|
+
/**
|
|
2615
|
+
* Read the Board's relations.
|
|
2616
|
+
*
|
|
2617
|
+
* A dedicated read rather than a filter over `inspect()`: a caller that wants
|
|
2618
|
+
* the graph should not have to fetch every node's geometry to get it.
|
|
2619
|
+
*/
|
|
2620
|
+
async connections(customFetch) {
|
|
2621
|
+
return (await this.boards.inspect(this.id, { include: ["connections"] }, customFetch)).connections;
|
|
2622
|
+
}
|
|
2623
|
+
/**
|
|
2624
|
+
* Connections touching a node, in either direction.
|
|
2625
|
+
*
|
|
2626
|
+
* Filtered client-side from the Board's relation set, which is a single read and
|
|
2627
|
+
* bounded by the Board rather than by the node's degree.
|
|
2628
|
+
*/
|
|
2629
|
+
async connectionsForNode(nodeId, customFetch) {
|
|
2630
|
+
return (await this.connections(customFetch)).filter((connection) => connection.source.nodeId === nodeId || connection.target.nodeId === nodeId);
|
|
2631
|
+
}
|
|
2632
|
+
/**
|
|
2633
|
+
* Connect two nodes.
|
|
2634
|
+
*
|
|
2635
|
+
* Wraps the transaction so the common case is one call: the caller supplies the
|
|
2636
|
+
* two nodes and, optionally, the relation. `baseVersion` still has to be the
|
|
2637
|
+
* version the caller last read, because a relation is only meaningful against
|
|
2638
|
+
* the node set it was authored on.
|
|
2639
|
+
*/
|
|
2640
|
+
connect(input) {
|
|
2641
|
+
const connection = createBoardConnection({
|
|
2642
|
+
id: input.id ?? randomBoardId(),
|
|
2643
|
+
sourceNodeId: input.sourceNodeId,
|
|
2644
|
+
targetNodeId: input.targetNodeId,
|
|
2645
|
+
...input.relation === void 0 ? {} : { relation: input.relation },
|
|
2646
|
+
...input.direction === void 0 ? {} : { direction: input.direction },
|
|
2647
|
+
...input.label === void 0 ? {} : { label: input.label }
|
|
2648
|
+
});
|
|
2649
|
+
return this.apply({
|
|
2650
|
+
txId: input.txId ?? randomBoardId(),
|
|
2651
|
+
baseVersion: input.baseVersion,
|
|
2652
|
+
operations: [{
|
|
2653
|
+
type: "connection.create",
|
|
2654
|
+
payload: { connection }
|
|
2655
|
+
}]
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
/** Remove a connection. The nodes it joined are untouched. */
|
|
2659
|
+
disconnect(input) {
|
|
2660
|
+
return this.apply({
|
|
2661
|
+
txId: input.txId ?? randomBoardId(),
|
|
2662
|
+
baseVersion: input.baseVersion,
|
|
2663
|
+
operations: [{
|
|
2664
|
+
type: "connection.delete",
|
|
2665
|
+
payload: { connectionId: input.connectionId }
|
|
2666
|
+
}]
|
|
2667
|
+
});
|
|
2668
|
+
}
|
|
2669
|
+
/**
|
|
2670
|
+
* Delete a node together with every relation that names it.
|
|
2671
|
+
*
|
|
2672
|
+
* The server refuses to orphan a relation, so the cascade is explicit and lands
|
|
2673
|
+
* in one transaction: one undo step restores the node and its edges together.
|
|
2674
|
+
* `connections` is the relation set the caller already read, so this stays a
|
|
2675
|
+
* single round-trip.
|
|
2676
|
+
*/
|
|
2677
|
+
deleteNodeWithConnections(input) {
|
|
2678
|
+
const incident = input.connections.filter((connection) => connection.source.nodeId === input.nodeId || connection.target.nodeId === input.nodeId);
|
|
2679
|
+
return this.apply({
|
|
2680
|
+
txId: input.txId ?? randomBoardId(),
|
|
2681
|
+
baseVersion: input.baseVersion,
|
|
2682
|
+
operations: [...incident.map((connection) => ({
|
|
2683
|
+
type: "connection.delete",
|
|
2684
|
+
payload: {
|
|
2685
|
+
connectionId: connection.id,
|
|
2686
|
+
reason: "node-cascade"
|
|
2687
|
+
}
|
|
2688
|
+
})), {
|
|
2689
|
+
type: "node.delete",
|
|
2690
|
+
payload: { nodeId: input.nodeId }
|
|
2691
|
+
}]
|
|
2692
|
+
});
|
|
2693
|
+
}
|
|
2408
2694
|
play(command) {
|
|
2409
2695
|
return this.boards.play(this.id, command);
|
|
2410
2696
|
}
|
|
@@ -3360,4 +3646,4 @@ var CohubHttpClient = class {
|
|
|
3360
3646
|
};
|
|
3361
3647
|
const createHttpClient = (options) => new CohubHttpClient(options);
|
|
3362
3648
|
//#endregion
|
|
3363
|
-
export { parseAssistantMessageCommit as A,
|
|
3649
|
+
export { parseAssistantMessageCommit as A, ReferencesApi as B, SpaceClient as C, buildSpacePath as D, buildSpaceInvitePath as E, BOARD_ARROW_STROKE_SIZE as F, ModelsApi as G, PublicAssetsApi as H, BOARD_BUILTIN_CAPABILITIES as I, ChannelsApi as J, GenerationsApi as K, BOARD_CONNECTION_STROKE_SIZE as L, createSessionPatchReducer as M, ensureRealtimeConnected as N, SessionGenerationStreamClient as O, BoardConnectionSchema as P, DEFAULT_BOARD_RENDER_LIMITS as R, BoardTransactionError as S, PublicInviteApi as T, SkillsApi as U, SearchApi as V, PromptsApi as W, isUiSurfaceMethod as _, ReferralsApi as a, TasksApi as b, UiCommandsApi as c, UI_COMMAND_PAYLOAD_MAX_BYTES as d, UI_COMMAND_PENDING_TTL_SECONDS as f, isTerminalUiCommandStatus as g, UI_COMMAND_VERSION as h, WorksApi as i, SessionPatchReducer as j, createSessionGenerationStreamClient as k, UI_COMMAND_DEFAULT_TIMEOUT_MS as l, UI_COMMAND_TERMINAL_TTL_SECONDS as m, createHttpClient as n, UsersApi as o, UI_COMMAND_SETTLEMENT_GRACE_SECONDS as p, CronJobsApi as q, WorkCommerceApi as r, UserApi as s, CohubHttpClient as t, UI_COMMAND_MAX_TIMEOUT_MS as u, parseUiCommand as v, SpacesApi as w, BoardClient as x, parseUiCommandId as y, SessionAccessApi as z };
|