@neta-art/cohub 5.3.3 → 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.
Files changed (43) hide show
  1. package/dist/board/codec.d.ts +2 -0
  2. package/dist/board/codec.js +18 -13
  3. package/dist/board/core/arrow-geometry.d.ts +23 -0
  4. package/dist/board/core/arrow-geometry.js +109 -0
  5. package/dist/board/core/connections.d.ts +83 -0
  6. package/dist/board/core/connections.js +399 -0
  7. package/dist/board/core/export-plan.d.ts +15 -4
  8. package/dist/board/core/export-plan.js +49 -16
  9. package/dist/board/core/shape-definition.js +1 -1
  10. package/dist/board/core/shape-types.d.ts +8 -2
  11. package/dist/board/core/shape-types.js +1 -1
  12. package/dist/board/core/tool-styles.d.ts +9 -3
  13. package/dist/board/core/tool-styles.js +10 -6
  14. package/dist/board/export/index.js +1 -0
  15. package/dist/board/export/scene.d.ts +3 -0
  16. package/dist/board/export/scene.js +18 -1
  17. package/dist/board/index.d.ts +8 -5
  18. package/dist/board/index.js +8 -5
  19. package/dist/board/render/connection-layer.d.ts +48 -0
  20. package/dist/board/render/connection-layer.js +223 -0
  21. package/dist/board/render/index.d.ts +2 -1
  22. package/dist/board/render/index.js +3 -2
  23. package/dist/board/render/renderers/arrow-card-renderer.js +35 -48
  24. package/dist/chunks/http.d.ts +53 -1
  25. package/dist/chunks/http.js +287 -1
  26. package/dist/chunks/websocket.d.ts +296 -57
  27. package/dist/http.d.ts +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.js +17 -56
  30. package/dist/protocol/dist/board-connection.d.ts +310 -0
  31. package/dist/protocol/dist/board-connection.js +215 -0
  32. package/dist/protocol/dist/board-constants.d.ts +11 -1
  33. package/dist/protocol/dist/board-constants.js +15 -1
  34. package/dist/protocol/dist/board-document.d.ts +106 -60
  35. package/dist/protocol/dist/board-document.js +57 -17
  36. package/dist/protocol/dist/board.d.ts +1 -0
  37. package/dist/protocol/dist/board.js +3 -0
  38. package/dist/protocol/dist/index.d.ts +2 -1
  39. package/dist/protocol/dist/index.js +2 -1
  40. package/dist/protocol/dist/realtime/board-awareness.js +15 -15
  41. package/package.json +1 -1
  42. package/dist/board/core/bindings.d.ts +0 -45
  43. package/dist/board/core/bindings.js +0 -162
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as parseAssistantMessageCommit, B as ModelsApi, C as SpaceClient, D as buildSpacePath, E as buildSpaceInvitePath, F as ReferencesApi, H as CronJobsApi, I as SearchApi, L as PublicAssetsApi, M as createSessionPatchReducer, N as ensureRealtimeConnected, O as SessionGenerationStreamClient, P as SessionAccessApi, R as SkillsApi, S as BoardTransactionError, T as PublicInviteApi, U as ChannelsApi, V as GenerationsApi, _ as isUiSurfaceMethod, a as ReferralsApi, b as TasksApi, c as UiCommandsApi, d as UI_COMMAND_PAYLOAD_MAX_BYTES, f as UI_COMMAND_PENDING_TTL_SECONDS, g as isTerminalUiCommandStatus, h as UI_COMMAND_VERSION, i as WorksApi, j as SessionPatchReducer, k as createSessionGenerationStreamClient, l as UI_COMMAND_DEFAULT_TIMEOUT_MS, m as UI_COMMAND_TERMINAL_TTL_SECONDS, n as createHttpClient, o as UsersApi, p as UI_COMMAND_SETTLEMENT_GRACE_SECONDS, r as WorkCommerceApi, s as UserApi, t as CohubHttpClient, u as UI_COMMAND_MAX_TIMEOUT_MS, v as parseUiCommand, w as SpacesApi, x as BoardClient, y as parseUiCommandId, z as PromptsApi } from "./chunks/http.js";
1
+ import { A as parseAssistantMessageCommit, B as ReferencesApi, C as SpaceClient, D as buildSpacePath, E as buildSpaceInvitePath, F as BOARD_ARROW_STROKE_SIZE, G as ModelsApi, H as PublicAssetsApi, I as BOARD_BUILTIN_CAPABILITIES, J as ChannelsApi, K as GenerationsApi, L as BOARD_CONNECTION_STROKE_SIZE, M as createSessionPatchReducer, N as ensureRealtimeConnected, O as SessionGenerationStreamClient, P as BoardConnectionSchema, R as DEFAULT_BOARD_RENDER_LIMITS, S as BoardTransactionError, T as PublicInviteApi, U as SkillsApi, V as SearchApi, W as PromptsApi, _ as isUiSurfaceMethod, a as ReferralsApi, b as TasksApi, c as UiCommandsApi, d as UI_COMMAND_PAYLOAD_MAX_BYTES, f as UI_COMMAND_PENDING_TTL_SECONDS, g as isTerminalUiCommandStatus, h as UI_COMMAND_VERSION, i as WorksApi, j as SessionPatchReducer, k as createSessionGenerationStreamClient, l as UI_COMMAND_DEFAULT_TIMEOUT_MS, m as UI_COMMAND_TERMINAL_TTL_SECONDS, n as createHttpClient, o as UsersApi, p as UI_COMMAND_SETTLEMENT_GRACE_SECONDS, q as CronJobsApi, r as WorkCommerceApi, s as UserApi, t as CohubHttpClient, u as UI_COMMAND_MAX_TIMEOUT_MS, v as parseUiCommand, w as SpacesApi, x as BoardClient, y as parseUiCommandId, z as SessionAccessApi } from "./chunks/http.js";
2
2
  import { _ as requestSourceToHeaders, a as sanitizeAccessToken, b as REALTIME_ROOM_EVENT_NAME_PATTERN, c as REQUEST_SOURCE_VIA_MAX_LENGTH, d as isRequestSourceEmpty, f as isRequestSourceUuid, g as readRequestSourceFromEnv, h as parseRequestSourceFromHeaders, i as matchesUnauthorizedErrorToken, l as hasRequestSourceIdentity, m as normalizeRequestSource, n as HttpTransport, o as COHUB_SOURCE_HEADER, p as mergeRequestSourceIntoMeta, r as joinApiUrl, s as COHUB_SOURCE_HEADER_NAMES, t as HttpError, u as isRequestSourceClientId, v as resolveRequestSourceChannel, y as REALTIME_DOMAINS } from "./chunks/transport.js";
3
3
  import { a as resolveApiBaseUrl, c as resolveWebsocketUrl, i as normalizeWebsocketUrl, n as normalizeBaseUrl, o as resolveCohubEnvironment, r as normalizeVoiceInputWebsocketUrl, s as resolveVoiceInputWebsocketUrl, t as COHUB_ENVIRONMENTS } from "./chunks/environment.js";
4
4
  import { a as extractBillingPayload, c as isFeatureNotEntitledError, i as FEATURE_NOT_ENTITLED_ERROR_CODE, l as isHttpErrorCode, n as createWebsocketClient, o as isBillingAccessBlockedCode, r as BILLING_ACCESS_BLOCKED_ERROR_CODE, s as isBillingAccessBlockedError, t as WebsocketClient } from "./chunks/websocket.js";
@@ -70,47 +70,6 @@ var BillingApi = class {
70
70
  }
71
71
  };
72
72
  //#endregion
73
- //#region ../protocol/dist/board-constants.js
74
- const DEFAULT_BOARD_RENDER_LIMITS = {
75
- particles: 2e4,
76
- vertices: 5e5,
77
- dynamicVertices: 15e4,
78
- drawCalls: 400,
79
- filterPasses: 24,
80
- renderTexturePixels: 16777216,
81
- textureBytes: 512 * 1024 * 1024,
82
- bufferBytes: 256 * 1024 * 1024,
83
- simulationSteps: 1e5
84
- };
85
- const BOARD_BUILTIN_CLIP_KINDS = [
86
- "motion.keyframes",
87
- "motion.path",
88
- "draw.reveal",
89
- "draw.handwrite",
90
- "text.reveal",
91
- "effects.particles",
92
- "effects.trail",
93
- "effects.impact",
94
- "effects.flash",
95
- "effects.color",
96
- "camera.pan",
97
- "camera.zoom",
98
- "camera.shake"
99
- ];
100
- const BOARD_BUILTIN_EFFECT_KINDS = ["effects.pulse", "effects.float"];
101
- const BOARD_ARROW_STROKE_SIZE = 2.5;
102
- const BOARD_BUILTIN_CAPABILITIES = [...BOARD_BUILTIN_CLIP_KINDS.map((id) => ({
103
- kind: "clip",
104
- id,
105
- version: 1,
106
- renderers: ["webgpu", "webgl"]
107
- })), ...BOARD_BUILTIN_EFFECT_KINDS.map((id) => ({
108
- kind: "effect",
109
- id,
110
- version: 1,
111
- renderers: ["webgpu", "webgl"]
112
- }))];
113
- //#endregion
114
73
  //#region ../protocol/dist/realtime/board-awareness.js
115
74
  const idSchema$1 = z.string().min(1).max(160);
116
75
  const finiteSchema$1 = z.number().finite();
@@ -126,23 +85,13 @@ const BoardAwarenessFrameSchema = z.object({
126
85
  height: finiteSchema$1.positive(),
127
86
  rotation: finiteSchema$1
128
87
  });
129
- const arrowEndpointSchema = z.union([z.object({
130
- kind: z.literal("point"),
131
- x: finiteSchema$1,
132
- y: finiteSchema$1
133
- }), z.object({
134
- kind: z.literal("binding"),
135
- target: idSchema$1,
136
- nx: finiteSchema$1,
137
- ny: finiteSchema$1,
138
- precise: z.boolean()
139
- })]);
140
88
  const BoardAwarenessNodePreviewSchema = z.object({
141
89
  nodeId: idSchema$1,
142
90
  frame: BoardAwarenessFrameSchema,
91
+ /** Live endpoints of a free arrow being dragged. */
143
92
  arrow: z.object({
144
- start: arrowEndpointSchema,
145
- end: arrowEndpointSchema,
93
+ start: BoardAwarenessPointSchema,
94
+ end: BoardAwarenessPointSchema,
146
95
  bend: finiteSchema$1
147
96
  }).optional()
148
97
  });
@@ -191,6 +140,15 @@ const BoardAwarenessGestureSchema = z.discriminatedUnion("kind", [
191
140
  color: z.string().min(1).max(64),
192
141
  geo: z.string().min(1).max(40)
193
142
  }),
143
+ z.object({
144
+ kind: z.literal("connection"),
145
+ id: idSchema$1,
146
+ sourceNodeId: idSchema$1,
147
+ targetNodeId: idSchema$1.nullable(),
148
+ current: BoardAwarenessPointSchema,
149
+ color: z.string().min(1).max(64),
150
+ size: finiteSchema$1.positive().max(256).default(BOARD_CONNECTION_STROKE_SIZE)
151
+ }),
194
152
  z.object({
195
153
  kind: z.literal("transform"),
196
154
  id: idSchema$1,
@@ -198,7 +156,8 @@ const BoardAwarenessGestureSchema = z.discriminatedUnion("kind", [
198
156
  "translate",
199
157
  "resize",
200
158
  "rotate",
201
- "arrow"
159
+ "arrow",
160
+ "connection"
202
161
  ]),
203
162
  nodes: z.array(BoardAwarenessNodePreviewSchema).max(64),
204
163
  bounds: BoardAwarenessFrameSchema.nullable()
@@ -2572,6 +2531,7 @@ z.object({
2572
2531
  title: z.string().min(1).max(255).optional(),
2573
2532
  metadata: jsonObjectSchema.optional(),
2574
2533
  nodes: z.array(BoardNodeInputSchema).max(5e4).optional(),
2534
+ connections: z.array(BoardConnectionSchema).max(5e4).optional(),
2575
2535
  effects: z.array(BoardEffectSchema.omit({
2576
2536
  boardId: true,
2577
2537
  revision: true
@@ -2587,6 +2547,7 @@ z.object({
2587
2547
  z.object({
2588
2548
  include: z.array(z.enum([
2589
2549
  "nodes",
2550
+ "connections",
2590
2551
  "effects",
2591
2552
  "sequences",
2592
2553
  "clips",
@@ -0,0 +1,310 @@
1
+ import { z } from "zod";
2
+ //#region ../protocol/dist/board-connection.d.ts
3
+ /** Sides of a node frame a connection can attach to. */
4
+ declare const BOARD_CONNECTION_SIDES: readonly ["top", "right", "bottom", "left"];
5
+ type BoardConnectionSide = (typeof BOARD_CONNECTION_SIDES)[number];
6
+ /**
7
+ * Where a connection meets its node.
8
+ *
9
+ * - `auto` — the side is chosen from the live geometry of both endpoints, so the
10
+ * connection stays sensible through any move or resize. This is the default and
11
+ * what almost every connection should use.
12
+ * - `side` — the user pinned a side; `offset` (0..1) positions it along that edge.
13
+ * - `fixed` — the user pinned an exact normalized point on the frame.
14
+ *
15
+ * `auto` is a *declaration of intent*, not a computed value: the resolved side is
16
+ * never written back, so the connection keeps adapting instead of freezing the
17
+ * first layout it happened to have.
18
+ */
19
+ declare const BoardConnectionAnchorSchema: z.ZodUnion<readonly [z.ZodObject<{
20
+ kind: z.ZodLiteral<"auto">;
21
+ }, z.core.$strip>, z.ZodObject<{
22
+ kind: z.ZodLiteral<"side">;
23
+ side: z.ZodEnum<{
24
+ bottom: "bottom";
25
+ left: "left";
26
+ right: "right";
27
+ top: "top";
28
+ }>;
29
+ offset: z.ZodDefault<z.ZodNumber>;
30
+ }, z.core.$strip>, z.ZodObject<{
31
+ kind: z.ZodLiteral<"fixed">;
32
+ nx: z.ZodNumber;
33
+ ny: z.ZodNumber;
34
+ }, z.core.$strip>]>;
35
+ type BoardConnectionAnchor = z.infer<typeof BoardConnectionAnchorSchema>;
36
+ declare const AUTO_BOARD_CONNECTION_ANCHOR: BoardConnectionAnchor;
37
+ declare const BoardConnectionEndpointSchema: z.ZodObject<{
38
+ nodeId: z.ZodString;
39
+ anchor: z.ZodDefault<z.ZodUnion<readonly [z.ZodObject<{
40
+ kind: z.ZodLiteral<"auto">;
41
+ }, z.core.$strip>, z.ZodObject<{
42
+ kind: z.ZodLiteral<"side">;
43
+ side: z.ZodEnum<{
44
+ bottom: "bottom";
45
+ left: "left";
46
+ right: "right";
47
+ top: "top";
48
+ }>;
49
+ offset: z.ZodDefault<z.ZodNumber>;
50
+ }, z.core.$strip>, z.ZodObject<{
51
+ kind: z.ZodLiteral<"fixed">;
52
+ nx: z.ZodNumber;
53
+ ny: z.ZodNumber;
54
+ }, z.core.$strip>]>>;
55
+ }, z.core.$strip>;
56
+ type BoardConnectionEndpoint = z.infer<typeof BoardConnectionEndpointSchema>;
57
+ /**
58
+ * Which ends carry an arrowhead.
59
+ *
60
+ * This is the *semantic* direction, not a style flag: `forward` means the
61
+ * relation reads source → target, `backward` means target → source, and `none`
62
+ * means the relation is symmetric. Renderers derive arrowheads from it, so the
63
+ * drawing can never disagree with the meaning.
64
+ */
65
+ declare const BOARD_CONNECTION_DIRECTIONS: readonly ["none", "forward", "backward", "both"];
66
+ type BoardConnectionDirection = (typeof BOARD_CONNECTION_DIRECTIONS)[number];
67
+ /** How the line travels between its two resolved endpoints. */
68
+ declare const BOARD_CONNECTION_ROUTINGS: readonly ["straight", "curve", "orthogonal"];
69
+ type BoardConnectionRouting = (typeof BOARD_CONNECTION_ROUTINGS)[number];
70
+ declare const BOARD_CONNECTION_LINES: readonly ["solid", "dashed"];
71
+ type BoardConnectionLine = (typeof BOARD_CONNECTION_LINES)[number];
72
+ /**
73
+ * The default relation kind.
74
+ *
75
+ * "related" is deliberately unopinionated: drawing a line between two nodes
76
+ * states that they are connected, not *how*. A stronger claim (depends-on,
77
+ * blocks, ...) is something the user or an agent asserts explicitly.
78
+ */
79
+ declare const DEFAULT_BOARD_RELATION: "related";
80
+ /**
81
+ * Relation kind — a free-form slug, not an enum.
82
+ *
83
+ * Boards are used for domains we do not control, so a closed vocabulary would
84
+ * force unrelated meanings into the wrong bucket. The format is constrained
85
+ * (lowercase, dash/dot separated) so relations stay comparable and queryable
86
+ * across clients instead of accumulating near-duplicate spellings.
87
+ */
88
+ declare const BoardRelationSchema: z.ZodDefault<z.ZodString>;
89
+ /**
90
+ * Waypoints a user dragged the line through, in world space.
91
+ *
92
+ * Stored because they are *input*, not output: the resolved path is recomputed
93
+ * from them on every read, but the intent behind a hand-routed line cannot be
94
+ * recovered once discarded.
95
+ */
96
+ declare const BoardConnectionWaypointSchema: z.ZodObject<{
97
+ x: z.ZodNumber;
98
+ y: z.ZodNumber;
99
+ }, z.core.$strip>;
100
+ declare const BoardConnectionRoutingSchema: z.ZodObject<{
101
+ kind: z.ZodDefault<z.ZodEnum<{
102
+ curve: "curve";
103
+ orthogonal: "orthogonal";
104
+ straight: "straight";
105
+ }>>;
106
+ bend: z.ZodDefault<z.ZodNumber>;
107
+ waypoints: z.ZodDefault<z.ZodArray<z.ZodObject<{
108
+ x: z.ZodNumber;
109
+ y: z.ZodNumber;
110
+ }, z.core.$strip>>>;
111
+ }, z.core.$strip>;
112
+ type BoardConnectionRoutingConfig = z.infer<typeof BoardConnectionRoutingSchema>;
113
+ declare const BoardConnectionStyleSchema: z.ZodObject<{
114
+ color: z.ZodDefault<z.ZodString>;
115
+ size: z.ZodDefault<z.ZodNumber>;
116
+ line: z.ZodDefault<z.ZodEnum<{
117
+ dashed: "dashed";
118
+ solid: "solid";
119
+ }>>;
120
+ }, z.core.$strip>;
121
+ type BoardConnectionStyle = z.infer<typeof BoardConnectionStyleSchema>;
122
+ declare const DEFAULT_BOARD_CONNECTION_ROUTING: BoardConnectionRoutingConfig;
123
+ declare const DEFAULT_BOARD_CONNECTION_STYLE: BoardConnectionStyle;
124
+ declare const BoardConnectionSchema: z.ZodObject<{
125
+ id: z.ZodString;
126
+ source: z.ZodObject<{
127
+ nodeId: z.ZodString;
128
+ anchor: z.ZodDefault<z.ZodUnion<readonly [z.ZodObject<{
129
+ kind: z.ZodLiteral<"auto">;
130
+ }, z.core.$strip>, z.ZodObject<{
131
+ kind: z.ZodLiteral<"side">;
132
+ side: z.ZodEnum<{
133
+ bottom: "bottom";
134
+ left: "left";
135
+ right: "right";
136
+ top: "top";
137
+ }>;
138
+ offset: z.ZodDefault<z.ZodNumber>;
139
+ }, z.core.$strip>, z.ZodObject<{
140
+ kind: z.ZodLiteral<"fixed">;
141
+ nx: z.ZodNumber;
142
+ ny: z.ZodNumber;
143
+ }, z.core.$strip>]>>;
144
+ }, z.core.$strip>;
145
+ target: z.ZodObject<{
146
+ nodeId: z.ZodString;
147
+ anchor: z.ZodDefault<z.ZodUnion<readonly [z.ZodObject<{
148
+ kind: z.ZodLiteral<"auto">;
149
+ }, z.core.$strip>, z.ZodObject<{
150
+ kind: z.ZodLiteral<"side">;
151
+ side: z.ZodEnum<{
152
+ bottom: "bottom";
153
+ left: "left";
154
+ right: "right";
155
+ top: "top";
156
+ }>;
157
+ offset: z.ZodDefault<z.ZodNumber>;
158
+ }, z.core.$strip>, z.ZodObject<{
159
+ kind: z.ZodLiteral<"fixed">;
160
+ nx: z.ZodNumber;
161
+ ny: z.ZodNumber;
162
+ }, z.core.$strip>]>>;
163
+ }, z.core.$strip>;
164
+ relation: z.ZodDefault<z.ZodString>;
165
+ direction: z.ZodDefault<z.ZodEnum<{
166
+ backward: "backward";
167
+ both: "both";
168
+ forward: "forward";
169
+ none: "none";
170
+ }>>;
171
+ label: z.ZodDefault<z.ZodString>;
172
+ routing: z.ZodDefault<z.ZodObject<{
173
+ kind: z.ZodDefault<z.ZodEnum<{
174
+ curve: "curve";
175
+ orthogonal: "orthogonal";
176
+ straight: "straight";
177
+ }>>;
178
+ bend: z.ZodDefault<z.ZodNumber>;
179
+ waypoints: z.ZodDefault<z.ZodArray<z.ZodObject<{
180
+ x: z.ZodNumber;
181
+ y: z.ZodNumber;
182
+ }, z.core.$strip>>>;
183
+ }, z.core.$strip>>;
184
+ style: z.ZodDefault<z.ZodObject<{
185
+ color: z.ZodDefault<z.ZodString>;
186
+ size: z.ZodDefault<z.ZodNumber>;
187
+ line: z.ZodDefault<z.ZodEnum<{
188
+ dashed: "dashed";
189
+ solid: "solid";
190
+ }>>;
191
+ }, z.core.$strip>>;
192
+ metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
193
+ }, z.core.$strip>;
194
+ type BoardConnection = z.infer<typeof BoardConnectionSchema>;
195
+ /** Server-owned fields, mirroring how nodes carry a board id and revision. */
196
+ type BoardConnectionRecord = BoardConnection & {
197
+ boardId: string;
198
+ revision: number;
199
+ createdAt: string | null;
200
+ updatedAt: string | null;
201
+ };
202
+ /** The client-authored form of a connection (no server-owned fields). */
203
+ type BoardConnectionInput = BoardConnection;
204
+ /**
205
+ * A patch to an existing connection.
206
+ *
207
+ * `id` is excluded: a connection's identity never changes, and re-pointing both
208
+ * endpoints is an edit of the same relation, not a new one.
209
+ */
210
+ declare const BoardConnectionPatchSchema: z.ZodObject<{
211
+ source: z.ZodOptional<z.ZodObject<{
212
+ nodeId: z.ZodString;
213
+ anchor: z.ZodDefault<z.ZodUnion<readonly [z.ZodObject<{
214
+ kind: z.ZodLiteral<"auto">;
215
+ }, z.core.$strip>, z.ZodObject<{
216
+ kind: z.ZodLiteral<"side">;
217
+ side: z.ZodEnum<{
218
+ bottom: "bottom";
219
+ left: "left";
220
+ right: "right";
221
+ top: "top";
222
+ }>;
223
+ offset: z.ZodDefault<z.ZodNumber>;
224
+ }, z.core.$strip>, z.ZodObject<{
225
+ kind: z.ZodLiteral<"fixed">;
226
+ nx: z.ZodNumber;
227
+ ny: z.ZodNumber;
228
+ }, z.core.$strip>]>>;
229
+ }, z.core.$strip>>;
230
+ target: z.ZodOptional<z.ZodObject<{
231
+ nodeId: z.ZodString;
232
+ anchor: z.ZodDefault<z.ZodUnion<readonly [z.ZodObject<{
233
+ kind: z.ZodLiteral<"auto">;
234
+ }, z.core.$strip>, z.ZodObject<{
235
+ kind: z.ZodLiteral<"side">;
236
+ side: z.ZodEnum<{
237
+ bottom: "bottom";
238
+ left: "left";
239
+ right: "right";
240
+ top: "top";
241
+ }>;
242
+ offset: z.ZodDefault<z.ZodNumber>;
243
+ }, z.core.$strip>, z.ZodObject<{
244
+ kind: z.ZodLiteral<"fixed">;
245
+ nx: z.ZodNumber;
246
+ ny: z.ZodNumber;
247
+ }, z.core.$strip>]>>;
248
+ }, z.core.$strip>>;
249
+ relation: z.ZodOptional<z.ZodDefault<z.ZodString>>;
250
+ direction: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
251
+ backward: "backward";
252
+ both: "both";
253
+ forward: "forward";
254
+ none: "none";
255
+ }>>>;
256
+ label: z.ZodOptional<z.ZodDefault<z.ZodString>>;
257
+ routing: z.ZodOptional<z.ZodDefault<z.ZodObject<{
258
+ kind: z.ZodDefault<z.ZodEnum<{
259
+ curve: "curve";
260
+ orthogonal: "orthogonal";
261
+ straight: "straight";
262
+ }>>;
263
+ bend: z.ZodDefault<z.ZodNumber>;
264
+ waypoints: z.ZodDefault<z.ZodArray<z.ZodObject<{
265
+ x: z.ZodNumber;
266
+ y: z.ZodNumber;
267
+ }, z.core.$strip>>>;
268
+ }, z.core.$strip>>>;
269
+ style: z.ZodOptional<z.ZodDefault<z.ZodObject<{
270
+ color: z.ZodDefault<z.ZodString>;
271
+ size: z.ZodDefault<z.ZodNumber>;
272
+ line: z.ZodDefault<z.ZodEnum<{
273
+ dashed: "dashed";
274
+ solid: "solid";
275
+ }>>;
276
+ }, z.core.$strip>>>;
277
+ metadata: z.ZodOptional<z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
278
+ }, z.core.$strip>;
279
+ type BoardConnectionPatch = z.infer<typeof BoardConnectionPatchSchema>;
280
+ /** Both node ids a connection touches, deduped for a self-loop. */
281
+ declare function connectionNodeIds(connection: BoardConnection): string[];
282
+ /** Whether a connection touches the given node. */
283
+ declare function connectionTouchesNode(connection: BoardConnection, nodeId: string): boolean;
284
+ /** The node at the far end of a connection from `nodeId`, or null. */
285
+ declare function connectionOtherNodeId(connection: BoardConnection, nodeId: string): string | null;
286
+ declare function normalizeBoardConnectionStyle(style: Partial<BoardConnectionStyle> | undefined): BoardConnectionStyle;
287
+ /**
288
+ * Build a connection with every default filled in.
289
+ *
290
+ * Callers only state what they mean (which nodes, and optionally the relation),
291
+ * so a connection created by the editor, an agent or the CLI is byte-identical
292
+ * for the same intent.
293
+ */
294
+ declare function createBoardConnection(input: {
295
+ id: string;
296
+ sourceNodeId: string;
297
+ targetNodeId: string;
298
+ relation?: string;
299
+ direction?: BoardConnectionDirection;
300
+ label?: string;
301
+ sourceAnchor?: BoardConnectionAnchor;
302
+ targetAnchor?: BoardConnectionAnchor;
303
+ routing?: Partial<BoardConnectionRoutingConfig>;
304
+ style?: Partial<BoardConnectionStyle>;
305
+ metadata?: Record<string, unknown>;
306
+ }): BoardConnection;
307
+ /** Reverse a connection's endpoints, preserving the relation's reading order. */
308
+ declare function flipBoardConnection(connection: BoardConnection): BoardConnection;
309
+ //#endregion
310
+ export { AUTO_BOARD_CONNECTION_ANCHOR, BOARD_CONNECTION_DIRECTIONS, BOARD_CONNECTION_LINES, BOARD_CONNECTION_ROUTINGS, BOARD_CONNECTION_SIDES, BoardConnection, BoardConnectionAnchor, BoardConnectionAnchorSchema, BoardConnectionDirection, BoardConnectionEndpoint, BoardConnectionEndpointSchema, BoardConnectionInput, BoardConnectionLine, BoardConnectionPatch, BoardConnectionPatchSchema, BoardConnectionRecord, BoardConnectionRouting, BoardConnectionRoutingConfig, BoardConnectionRoutingSchema, BoardConnectionSchema, BoardConnectionSide, BoardConnectionStyle, BoardConnectionStyleSchema, BoardConnectionWaypointSchema, BoardRelationSchema, DEFAULT_BOARD_CONNECTION_ROUTING, DEFAULT_BOARD_CONNECTION_STYLE, DEFAULT_BOARD_RELATION, connectionNodeIds, connectionOtherNodeId, connectionTouchesNode, createBoardConnection, flipBoardConnection, normalizeBoardConnectionStyle };
@@ -0,0 +1,215 @@
1
+ import { BOARD_CONNECTION_STROKE_SIZE, clampBoardStrokeSize } from "./board-constants.js";
2
+ import { z } from "zod";
3
+ //#region ../protocol/dist/board-connection.js
4
+ /**
5
+ * Board connections — the first-class relation between two Board nodes.
6
+ *
7
+ * A connection is *not* a shape. It has no frame of its own: its geometry is
8
+ * derived entirely from the two nodes it joins, which is exactly why it belongs
9
+ * in its own entity rather than in the item list. Storing it as a node would
10
+ * force a bounding box to be persisted and kept in sync with both endpoints —
11
+ * a second source of truth that is stale the moment either node moves.
12
+ *
13
+ * The stored form is therefore purely semantic: which nodes, in which direction,
14
+ * anchored where, routed how. Every world coordinate is resolved at read time
15
+ * from the live node frames (see the SDK's connection geometry), so a connection
16
+ * can never drift from the nodes it describes.
17
+ *
18
+ * Agents read this model directly: `source`, `target`, `relation` and `label`
19
+ * carry the meaning, while `routing` and `style` carry only presentation. A
20
+ * reader that wants the graph never has to interpret pixels.
21
+ */
22
+ /** Sides of a node frame a connection can attach to. */
23
+ const BOARD_CONNECTION_SIDES = [
24
+ "top",
25
+ "right",
26
+ "bottom",
27
+ "left"
28
+ ];
29
+ /**
30
+ * Where a connection meets its node.
31
+ *
32
+ * - `auto` — the side is chosen from the live geometry of both endpoints, so the
33
+ * connection stays sensible through any move or resize. This is the default and
34
+ * what almost every connection should use.
35
+ * - `side` — the user pinned a side; `offset` (0..1) positions it along that edge.
36
+ * - `fixed` — the user pinned an exact normalized point on the frame.
37
+ *
38
+ * `auto` is a *declaration of intent*, not a computed value: the resolved side is
39
+ * never written back, so the connection keeps adapting instead of freezing the
40
+ * first layout it happened to have.
41
+ */
42
+ const BoardConnectionAnchorSchema = z.union([
43
+ z.object({ kind: z.literal("auto") }),
44
+ z.object({
45
+ kind: z.literal("side"),
46
+ side: z.enum(BOARD_CONNECTION_SIDES),
47
+ offset: z.number().finite().min(0).max(1).default(.5)
48
+ }),
49
+ z.object({
50
+ kind: z.literal("fixed"),
51
+ nx: z.number().finite().min(0).max(1),
52
+ ny: z.number().finite().min(0).max(1)
53
+ })
54
+ ]);
55
+ const AUTO_BOARD_CONNECTION_ANCHOR = { kind: "auto" };
56
+ const BoardConnectionEndpointSchema = z.object({
57
+ nodeId: z.string().min(1).max(160),
58
+ anchor: BoardConnectionAnchorSchema.default(AUTO_BOARD_CONNECTION_ANCHOR)
59
+ });
60
+ /**
61
+ * Which ends carry an arrowhead.
62
+ *
63
+ * This is the *semantic* direction, not a style flag: `forward` means the
64
+ * relation reads source → target, `backward` means target → source, and `none`
65
+ * means the relation is symmetric. Renderers derive arrowheads from it, so the
66
+ * drawing can never disagree with the meaning.
67
+ */
68
+ const BOARD_CONNECTION_DIRECTIONS = [
69
+ "none",
70
+ "forward",
71
+ "backward",
72
+ "both"
73
+ ];
74
+ /** How the line travels between its two resolved endpoints. */
75
+ const BOARD_CONNECTION_ROUTINGS = [
76
+ "straight",
77
+ "curve",
78
+ "orthogonal"
79
+ ];
80
+ const BOARD_CONNECTION_LINES = ["solid", "dashed"];
81
+ /**
82
+ * The default relation kind.
83
+ *
84
+ * "related" is deliberately unopinionated: drawing a line between two nodes
85
+ * states that they are connected, not *how*. A stronger claim (depends-on,
86
+ * blocks, ...) is something the user or an agent asserts explicitly.
87
+ */
88
+ const DEFAULT_BOARD_RELATION = "related";
89
+ /**
90
+ * Relation kind — a free-form slug, not an enum.
91
+ *
92
+ * Boards are used for domains we do not control, so a closed vocabulary would
93
+ * force unrelated meanings into the wrong bucket. The format is constrained
94
+ * (lowercase, dash/dot separated) so relations stay comparable and queryable
95
+ * across clients instead of accumulating near-duplicate spellings.
96
+ */
97
+ const BoardRelationSchema = z.string().min(1).max(64).regex(/^[a-z0-9]+(?:[.-][a-z0-9]+)*$/, "relation must be a lowercase slug").default(DEFAULT_BOARD_RELATION);
98
+ /**
99
+ * Waypoints a user dragged the line through, in world space.
100
+ *
101
+ * Stored because they are *input*, not output: the resolved path is recomputed
102
+ * from them on every read, but the intent behind a hand-routed line cannot be
103
+ * recovered once discarded.
104
+ */
105
+ const BoardConnectionWaypointSchema = z.object({
106
+ x: z.number().finite(),
107
+ y: z.number().finite()
108
+ });
109
+ const BoardConnectionRoutingSchema = z.object({
110
+ kind: z.enum(BOARD_CONNECTION_ROUTINGS).default("curve"),
111
+ /** Curve bow as a fraction of endpoint distance (-0.85..0.85). */
112
+ bend: z.number().finite().min(-.85).max(.85).default(0),
113
+ waypoints: z.array(BoardConnectionWaypointSchema).max(64).default([])
114
+ });
115
+ const BoardConnectionStyleSchema = z.object({
116
+ /** Palette color id, resolved to a theme token at render time. */
117
+ color: z.string().min(1).max(40).default("brand"),
118
+ size: z.number().finite().positive().default(BOARD_CONNECTION_STROKE_SIZE),
119
+ line: z.enum(BOARD_CONNECTION_LINES).default("solid")
120
+ });
121
+ const DEFAULT_BOARD_CONNECTION_ROUTING = {
122
+ kind: "curve",
123
+ bend: 0,
124
+ waypoints: []
125
+ };
126
+ const DEFAULT_BOARD_CONNECTION_STYLE = {
127
+ color: "brand",
128
+ size: BOARD_CONNECTION_STROKE_SIZE,
129
+ line: "solid"
130
+ };
131
+ const BoardConnectionSchema = z.object({
132
+ id: z.string().min(1).max(160),
133
+ source: BoardConnectionEndpointSchema,
134
+ target: BoardConnectionEndpointSchema,
135
+ relation: BoardRelationSchema,
136
+ direction: z.enum(BOARD_CONNECTION_DIRECTIONS).default("forward"),
137
+ label: z.string().max(280).default(""),
138
+ routing: BoardConnectionRoutingSchema.default(DEFAULT_BOARD_CONNECTION_ROUTING),
139
+ style: BoardConnectionStyleSchema.default(DEFAULT_BOARD_CONNECTION_STYLE),
140
+ metadata: z.record(z.string(), z.unknown()).default({})
141
+ });
142
+ /**
143
+ * A patch to an existing connection.
144
+ *
145
+ * `id` is excluded: a connection's identity never changes, and re-pointing both
146
+ * endpoints is an edit of the same relation, not a new one.
147
+ */
148
+ const BoardConnectionPatchSchema = BoardConnectionSchema.omit({ id: true }).partial();
149
+ /** Both node ids a connection touches, deduped for a self-loop. */
150
+ function connectionNodeIds(connection) {
151
+ return connection.source.nodeId === connection.target.nodeId ? [connection.source.nodeId] : [connection.source.nodeId, connection.target.nodeId];
152
+ }
153
+ /** Whether a connection touches the given node. */
154
+ function connectionTouchesNode(connection, nodeId) {
155
+ return connection.source.nodeId === nodeId || connection.target.nodeId === nodeId;
156
+ }
157
+ /** The node at the far end of a connection from `nodeId`, or null. */
158
+ function connectionOtherNodeId(connection, nodeId) {
159
+ if (connection.source.nodeId === nodeId) return connection.target.nodeId;
160
+ if (connection.target.nodeId === nodeId) return connection.source.nodeId;
161
+ return null;
162
+ }
163
+ function normalizeBoardConnectionStyle(style) {
164
+ return {
165
+ color: style?.color?.trim() || DEFAULT_BOARD_CONNECTION_STYLE.color,
166
+ size: clampBoardStrokeSize(typeof style?.size === "number" && Number.isFinite(style.size) ? style.size : DEFAULT_BOARD_CONNECTION_STYLE.size),
167
+ line: style?.line ?? DEFAULT_BOARD_CONNECTION_STYLE.line
168
+ };
169
+ }
170
+ /**
171
+ * Build a connection with every default filled in.
172
+ *
173
+ * Callers only state what they mean (which nodes, and optionally the relation),
174
+ * so a connection created by the editor, an agent or the CLI is byte-identical
175
+ * for the same intent.
176
+ */
177
+ function createBoardConnection(input) {
178
+ return {
179
+ id: input.id,
180
+ source: {
181
+ nodeId: input.sourceNodeId,
182
+ anchor: input.sourceAnchor ?? AUTO_BOARD_CONNECTION_ANCHOR
183
+ },
184
+ target: {
185
+ nodeId: input.targetNodeId,
186
+ anchor: input.targetAnchor ?? AUTO_BOARD_CONNECTION_ANCHOR
187
+ },
188
+ relation: input.relation ?? "related",
189
+ direction: input.direction ?? "forward",
190
+ label: input.label ?? "",
191
+ routing: {
192
+ ...DEFAULT_BOARD_CONNECTION_ROUTING,
193
+ ...input.routing
194
+ },
195
+ style: normalizeBoardConnectionStyle(input.style),
196
+ metadata: input.metadata ?? {}
197
+ };
198
+ }
199
+ /** Reverse a connection's endpoints, preserving the relation's reading order. */
200
+ function flipBoardConnection(connection) {
201
+ const direction = connection.direction === "forward" ? "backward" : connection.direction === "backward" ? "forward" : connection.direction;
202
+ return {
203
+ ...connection,
204
+ source: connection.target,
205
+ target: connection.source,
206
+ direction,
207
+ routing: {
208
+ ...connection.routing,
209
+ bend: -connection.routing.bend,
210
+ waypoints: [...connection.routing.waypoints].reverse()
211
+ }
212
+ };
213
+ }
214
+ //#endregion
215
+ export { AUTO_BOARD_CONNECTION_ANCHOR, BOARD_CONNECTION_DIRECTIONS, BOARD_CONNECTION_LINES, BOARD_CONNECTION_ROUTINGS, BOARD_CONNECTION_SIDES, BoardConnectionAnchorSchema, BoardConnectionEndpointSchema, BoardConnectionPatchSchema, BoardConnectionRoutingSchema, BoardConnectionSchema, BoardConnectionStyleSchema, BoardConnectionWaypointSchema, BoardRelationSchema, DEFAULT_BOARD_CONNECTION_ROUTING, DEFAULT_BOARD_CONNECTION_STYLE, DEFAULT_BOARD_RELATION, connectionNodeIds, connectionOtherNodeId, connectionTouchesNode, createBoardConnection, flipBoardConnection, normalizeBoardConnectionStyle };
@@ -19,5 +19,15 @@ type BoardCapability = {
19
19
  fallbackId?: string;
20
20
  schema?: Record<string, unknown>;
21
21
  };
22
+ /**
23
+ * Stroke width bounds, shared by every stroked board entity.
24
+ *
25
+ * Defined here (not beside the editor) because the persisted schemas clamp with
26
+ * them: a single range is what keeps a width authored by the editor, an agent or
27
+ * the CLI from being silently re-clamped to something else on read.
28
+ */
29
+ declare const BOARD_STROKE_MIN_SIZE = 1;
30
+ declare const BOARD_STROKE_MAX_SIZE = 64;
31
+ declare function clampBoardStrokeSize(size: number): number;
22
32
  //#endregion
23
- export { BoardCapability, BoardRenderCost };
33
+ export { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardCapability, BoardRenderCost, clampBoardStrokeSize };