@telepath-computer/television 0.1.8 → 0.1.10

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/cli.cjs CHANGED
@@ -58109,7 +58109,7 @@ var require_event_target = __commonJS({
58109
58109
  var kTarget = Symbol("kTarget");
58110
58110
  var kType = Symbol("kType");
58111
58111
  var kWasClean = Symbol("kWasClean");
58112
- var Event = class {
58112
+ var Event2 = class {
58113
58113
  /**
58114
58114
  * Create a new `Event`.
58115
58115
  *
@@ -58133,9 +58133,9 @@ var require_event_target = __commonJS({
58133
58133
  return this[kType];
58134
58134
  }
58135
58135
  };
58136
- Object.defineProperty(Event.prototype, "target", { enumerable: true });
58137
- Object.defineProperty(Event.prototype, "type", { enumerable: true });
58138
- var CloseEvent = class extends Event {
58136
+ Object.defineProperty(Event2.prototype, "target", { enumerable: true });
58137
+ Object.defineProperty(Event2.prototype, "type", { enumerable: true });
58138
+ var CloseEvent = class extends Event2 {
58139
58139
  /**
58140
58140
  * Create a new `CloseEvent`.
58141
58141
  *
@@ -58177,7 +58177,7 @@ var require_event_target = __commonJS({
58177
58177
  Object.defineProperty(CloseEvent.prototype, "code", { enumerable: true });
58178
58178
  Object.defineProperty(CloseEvent.prototype, "reason", { enumerable: true });
58179
58179
  Object.defineProperty(CloseEvent.prototype, "wasClean", { enumerable: true });
58180
- var ErrorEvent = class extends Event {
58180
+ var ErrorEvent = class extends Event2 {
58181
58181
  /**
58182
58182
  * Create a new `ErrorEvent`.
58183
58183
  *
@@ -58207,7 +58207,7 @@ var require_event_target = __commonJS({
58207
58207
  };
58208
58208
  Object.defineProperty(ErrorEvent.prototype, "error", { enumerable: true });
58209
58209
  Object.defineProperty(ErrorEvent.prototype, "message", { enumerable: true });
58210
- var MessageEvent = class extends Event {
58210
+ var MessageEvent = class extends Event2 {
58211
58211
  /**
58212
58212
  * Create a new `MessageEvent`.
58213
58213
  *
@@ -58228,7 +58228,7 @@ var require_event_target = __commonJS({
58228
58228
  }
58229
58229
  };
58230
58230
  Object.defineProperty(MessageEvent.prototype, "data", { enumerable: true });
58231
- var EventTarget = {
58231
+ var EventTarget2 = {
58232
58232
  /**
58233
58233
  * Register an event listener.
58234
58234
  *
@@ -58277,7 +58277,7 @@ var require_event_target = __commonJS({
58277
58277
  };
58278
58278
  } else if (type === "open") {
58279
58279
  wrapper = function onOpen() {
58280
- const event = new Event("open");
58280
+ const event = new Event2("open");
58281
58281
  event[kTarget] = this;
58282
58282
  callListener(handler, this, event);
58283
58283
  };
@@ -58311,8 +58311,8 @@ var require_event_target = __commonJS({
58311
58311
  module2.exports = {
58312
58312
  CloseEvent,
58313
58313
  ErrorEvent,
58314
- Event,
58315
- EventTarget,
58314
+ Event: Event2,
58315
+ EventTarget: EventTarget2,
58316
58316
  MessageEvent
58317
58317
  };
58318
58318
  function callListener(listener, thisArg, event) {
@@ -77191,18 +77191,26 @@ var Server2 = class {
77191
77191
  this.handleClientMessage(socket, data.toString());
77192
77192
  });
77193
77193
  });
77194
- this.store.on("mutation", (event) => {
77195
- this.broadcast(event);
77194
+ this.store.addEventListener("store-change", (event) => {
77195
+ this.broadcast(event.message);
77196
77196
  });
77197
77197
  }
77198
77198
  start() {
77199
- return new Promise((resolve) => {
77200
- this.httpServer.listen(this.port, this.host, () => {
77199
+ return new Promise((resolve, reject) => {
77200
+ const handleError = (error2) => {
77201
+ this.httpServer.off("listening", handleListening);
77202
+ reject(error2);
77203
+ };
77204
+ const handleListening = () => {
77205
+ this.httpServer.off("error", handleError);
77201
77206
  const address = this.httpServer.address();
77202
77207
  const resolvedPort = typeof address === "object" && address ? address.port : this.port;
77203
77208
  this.baseURL = buildServerURL(this.host ?? DEFAULT_SERVER_HOST, resolvedPort);
77204
77209
  resolve(this.httpServer);
77205
- });
77210
+ };
77211
+ this.httpServer.once("error", handleError);
77212
+ this.httpServer.once("listening", handleListening);
77213
+ this.httpServer.listen(this.port, this.host);
77206
77214
  });
77207
77215
  }
77208
77216
  getBaseURL() {
@@ -77353,114 +77361,415 @@ function isClientMessage(value) {
77353
77361
  case "create-workspace":
77354
77362
  return typeof message.id === "string" && typeof message.name === "string";
77355
77363
  case "update-workspace":
77356
- return typeof message.workspaceID === "string" && typeof message.fields === "object" && message.fields !== null && (!("name" in message.fields) || typeof message.fields.name === "string") && (!("layout" in message.fields) || Array.isArray(message.fields.layout) && message.fields.layout.every(
77357
- (card) => typeof card === "object" && card !== null && "type" in card && card.type === "artifact" && "artifactID" in card && typeof card.artifactID === "string" && "cols" in card && typeof card.cols === "number" && "rows" in card && typeof card.rows === "number"
77358
- ));
77364
+ return typeof message.workspaceID === "string" && typeof message.fields === "object" && message.fields !== null && (!("name" in message.fields) || typeof message.fields.name === "string") && (!("layout" in message.fields) || Array.isArray(message.fields.layout) && message.fields.layout.every(isLayoutNode));
77359
77365
  case "delete-workspace":
77360
77366
  return typeof message.workspaceID === "string";
77361
77367
  default:
77362
77368
  return false;
77363
77369
  }
77364
77370
  }
77365
-
77366
- // node_modules/mitt/dist/mitt.mjs
77367
- function mitt_default(n) {
77368
- return { all: n = n || /* @__PURE__ */ new Map(), on: function(t, e) {
77369
- var i = n.get(t);
77370
- i ? i.push(e) : n.set(t, [e]);
77371
- }, off: function(t, e) {
77372
- var i = n.get(t);
77373
- i && (e ? i.splice(i.indexOf(e) >>> 0, 1) : n.set(t, []));
77374
- }, emit: function(t, e) {
77375
- var i = n.get(t);
77376
- i && i.slice().map(function(n2) {
77377
- n2(e);
77378
- }), (i = n.get("*")) && i.slice().map(function(n2) {
77379
- n2(t, e);
77380
- });
77381
- } };
77371
+ function isLayoutNode(value) {
77372
+ if (typeof value !== "object" || value === null || !("type" in value)) {
77373
+ return false;
77374
+ }
77375
+ const node = value;
77376
+ switch (node.type) {
77377
+ case "card":
77378
+ return typeof node.id === "string" && typeof node.artifactID === "string" && (typeof node.width === "number" || node.width === "auto") && (typeof node.height === "number" || node.height === "auto");
77379
+ case "row":
77380
+ return typeof node.id === "string" && (typeof node.height === "number" || node.height === "auto") && Array.isArray(node.children) && node.children.every(isLayoutNode);
77381
+ case "stack":
77382
+ return typeof node.id === "string" && Array.isArray(node.children) && node.children.every(isLayoutNode);
77383
+ default:
77384
+ return false;
77385
+ }
77382
77386
  }
77383
77387
 
77384
- // node_modules/@rupertsworld/emitter/dist/index.js
77385
- var Emitter = class {
77386
- emitter = mitt_default();
77387
- on(type, handler) {
77388
- this.emitter.on(type, handler);
77389
- return { dispose: () => this.emitter.off(type, handler) };
77388
+ // node_modules/@rupertsworld/event-target/dist/index.js
77389
+ var RESERVED_EVENT_KEYS = /* @__PURE__ */ new Set([
77390
+ "target",
77391
+ "currentTarget",
77392
+ "eventPhase",
77393
+ "defaultPrevented",
77394
+ "isTrusted",
77395
+ "timeStamp",
77396
+ "srcElement",
77397
+ "returnValue",
77398
+ "cancelBubble",
77399
+ "NONE",
77400
+ "CAPTURING_PHASE",
77401
+ "AT_TARGET",
77402
+ "BUBBLING_PHASE",
77403
+ "composedPath",
77404
+ "stopPropagation",
77405
+ "stopImmediatePropagation",
77406
+ "preventDefault",
77407
+ "initEvent"
77408
+ ]);
77409
+ function assertNoReservedPayloadKeys(props) {
77410
+ for (const key of Object.keys(props)) {
77411
+ if (RESERVED_EVENT_KEYS.has(key)) {
77412
+ throw new Error(`Event payload key "${key}" is reserved; choose a different property name`);
77413
+ }
77390
77414
  }
77391
- once(type, handler) {
77392
- const wrappedHandler = (...args) => {
77393
- handler(...args);
77394
- this.emitter.off(type, wrappedHandler);
77395
- };
77396
- this.emitter.on(type, wrappedHandler);
77397
- return { dispose: () => this.emitter.off(type, wrappedHandler) };
77415
+ }
77416
+ function assignPayload(target, props) {
77417
+ assertNoReservedPayloadKeys(props);
77418
+ for (const key of Object.keys(props)) {
77419
+ Object.defineProperty(target, key, {
77420
+ value: props[key],
77421
+ writable: true,
77422
+ enumerable: true,
77423
+ configurable: true
77424
+ });
77398
77425
  }
77399
- /**
77400
- * Unsubscribe from an event
77401
- */
77402
- off = this.emitter.off;
77403
- /**
77404
- * Emit an event
77405
- */
77406
- emit(type, ...[event]) {
77407
- this.emitter.emit(type, event);
77426
+ }
77427
+ function defineEvent() {
77428
+ class DefinedEvent extends Event {
77429
+ constructor(type, init) {
77430
+ const { type: initType, bubbles, cancelable, composed, ...payload } = init ?? {};
77431
+ if (initType !== void 0) {
77432
+ throw new Error(`Do not pass "type" in init; use the constructor argument instead`);
77433
+ }
77434
+ super(type, { bubbles, cancelable, composed });
77435
+ assignPayload(this, payload);
77436
+ }
77408
77437
  }
77438
+ return DefinedEvent;
77439
+ }
77440
+ var EventTarget = class extends globalThis.EventTarget {
77409
77441
  };
77410
77442
 
77443
+ // src/events.ts
77444
+ var ChangeEvent = defineEvent();
77445
+ var ServerMessageEvent = defineEvent();
77446
+ var LayoutMutationEvent = defineEvent();
77447
+ var LayoutScrollEvent = defineEvent();
77448
+ var StoreChangeEvent = defineEvent();
77449
+
77411
77450
  // src/server/server-store.ts
77412
77451
  var import_node_crypto2 = require("node:crypto");
77413
77452
  var import_node_fs3 = require("node:fs");
77414
77453
  var import_node_path4 = __toESM(require("node:path"), 1);
77415
77454
 
77455
+ // src/constants.ts
77456
+ var LAYOUT_FULL_WIDTH_UNITS = 4;
77457
+ var LAYOUT_FULL_HEIGHT_UNITS = 6;
77458
+ var MIN_LAYOUT_CARD_WIDTH_UNITS = 2;
77459
+ var MAX_LAYOUT_CARD_WIDTH_UNITS = LAYOUT_FULL_WIDTH_UNITS;
77460
+ var DEFAULT_LAYOUT_CARD_WIDTH = "auto";
77461
+ var DEFAULT_LAYOUT_CARD_HEIGHT = "auto";
77462
+ var DEFAULT_LAYOUT_UNIT = 120;
77463
+ var CARD_GAP = 16;
77464
+ var CARD_WIDTH = DEFAULT_LAYOUT_UNIT * LAYOUT_FULL_WIDTH_UNITS + CARD_GAP * (LAYOUT_FULL_WIDTH_UNITS - 1);
77465
+ var CARD_HEIGHT = DEFAULT_LAYOUT_UNIT * LAYOUT_FULL_HEIGHT_UNITS + CARD_GAP * (LAYOUT_FULL_HEIGHT_UNITS - 1);
77466
+
77416
77467
  // src/types.ts
77417
- var DEFAULT_LAYOUT_CARD_COLS = 2;
77418
- var DEFAULT_LAYOUT_CARD_ROWS = 6;
77419
- var LAYOUT_COLS_NARROW = 1;
77420
- var LAYOUT_ROW_SHORT = 2;
77421
- var LAYOUT_ROW_MID = 3;
77422
- var LAYOUT_ROW_TALL = 4;
77423
- var ALLOWED_COLS = [LAYOUT_COLS_NARROW, DEFAULT_LAYOUT_CARD_COLS];
77424
- var ALLOWED_ROWS = [
77425
- LAYOUT_ROW_SHORT,
77426
- LAYOUT_ROW_MID,
77427
- LAYOUT_ROW_TALL,
77428
- DEFAULT_LAYOUT_CARD_ROWS
77429
- ];
77430
- function clampLayoutCols(cols) {
77431
- const n = Math.round(cols);
77432
- return ALLOWED_COLS.includes(n) ? n : DEFAULT_LAYOUT_CARD_COLS;
77433
- }
77434
- function clampLayoutRows(rows) {
77435
- const n = Math.round(rows);
77436
- return ALLOWED_ROWS.includes(n) ? n : DEFAULT_LAYOUT_CARD_ROWS;
77437
- }
77438
- function createLayoutCardRecord(artifactID) {
77468
+ function createCardNode(artifactID, overrides = {}) {
77439
77469
  return {
77440
- type: "artifact",
77470
+ id: overrides.id ?? ulid3(),
77471
+ type: "card",
77441
77472
  artifactID,
77442
- cols: DEFAULT_LAYOUT_CARD_COLS,
77443
- rows: DEFAULT_LAYOUT_CARD_ROWS
77473
+ width: overrides.width ?? DEFAULT_LAYOUT_CARD_WIDTH,
77474
+ height: overrides.height ?? DEFAULT_LAYOUT_CARD_HEIGHT
77444
77475
  };
77445
77476
  }
77446
- function sanitizeLayoutCard(card) {
77477
+ function layoutContainsArtifactID(layout, artifactID) {
77478
+ return layout.some((node) => nodeContainsArtifactID(node, artifactID));
77479
+ }
77480
+ function nodeContainsArtifactID(node, artifactID) {
77481
+ switch (node.type) {
77482
+ case "card":
77483
+ return node.artifactID === artifactID;
77484
+ case "row":
77485
+ return node.children.some((child) => child.artifactID === artifactID);
77486
+ case "stack":
77487
+ return node.children.some((child) => nodeContainsArtifactID(child, artifactID));
77488
+ }
77489
+ }
77490
+ function getWorkspaceArtifactIDs(workspace) {
77491
+ return workspace.layout.flatMap(collectArtifactIDs);
77492
+ }
77493
+ function collectArtifactIDs(node) {
77494
+ switch (node.type) {
77495
+ case "card":
77496
+ return [node.artifactID];
77497
+ case "row":
77498
+ return node.children.map((child) => child.artifactID);
77499
+ case "stack":
77500
+ return node.children.flatMap(collectArtifactIDs);
77501
+ }
77502
+ }
77503
+
77504
+ // src/browser/ui/layout.ts
77505
+ var LEGACY_BAND_HEIGHT_ROWS = 6;
77506
+ var LEGACY_NARROW_COLS = 1;
77507
+ var LEGACY_FULL_COLS = 2;
77508
+ var LEGACY_ROW_SHORT = 2;
77509
+ var LEGACY_ROW_MID = 3;
77510
+ var LEGACY_ROW_TALL = 4;
77511
+ var LEGACY_ROW_FULL = 6;
77512
+ var LEGACY_ALLOWED_ROWS = [LEGACY_ROW_SHORT, LEGACY_ROW_MID, LEGACY_ROW_TALL, LEGACY_ROW_FULL];
77513
+ var LEGACY_LEFT_X = 0;
77514
+ var LEGACY_RIGHT_X = 1;
77515
+ function removeArtifactFromLayout(layout, artifactID) {
77516
+ return normalizeRootNodes(layout.flatMap((node) => removeArtifactFromNode(node, artifactID)));
77517
+ }
77518
+ function migrateLegacyLayout(cards) {
77519
+ const normalized = cards.map((card) => ({
77520
+ artifactID: card.artifactID,
77521
+ width: normalizeLegacyCols(card.width),
77522
+ height: normalizeLegacyRows(card.height)
77523
+ }));
77524
+ const bands = deriveLegacyBands(normalized);
77525
+ return normalizeRootNodes(bands.flatMap(buildNodesForLegacyBand));
77526
+ }
77527
+ function normalizeRootNodes(layout) {
77528
+ const normalized = [];
77529
+ for (const node of layout) {
77530
+ const entries = normalizeNode(node);
77531
+ for (const entry of entries) {
77532
+ if (entry.type === "row") {
77533
+ normalized.push(...entry.children.map(cloneCard));
77534
+ continue;
77535
+ }
77536
+ normalized.push(entry);
77537
+ }
77538
+ }
77539
+ return normalized;
77540
+ }
77541
+ function normalizeNode(node) {
77542
+ switch (node.type) {
77543
+ case "card":
77544
+ return [cloneCard(node)];
77545
+ case "row": {
77546
+ const children = node.children.map(cloneCard);
77547
+ if (children.length === 0) {
77548
+ return [];
77549
+ }
77550
+ if (children.length === 1) {
77551
+ return [children[0]];
77552
+ }
77553
+ return [{ ...node, children }];
77554
+ }
77555
+ case "stack": {
77556
+ const children = [];
77557
+ for (const child of node.children) {
77558
+ const normalizedChildren = normalizeNode(child);
77559
+ for (const normalizedChild of normalizedChildren) {
77560
+ if (normalizedChild.type === "stack") {
77561
+ children.push(...normalizedChild.children.map(cloneStackChild));
77562
+ continue;
77563
+ }
77564
+ if (normalizedChild.type === "row") {
77565
+ children.push({
77566
+ ...normalizedChild,
77567
+ children: normalizedChild.children.map(cloneCard)
77568
+ });
77569
+ continue;
77570
+ }
77571
+ children.push(cloneCard(normalizedChild));
77572
+ }
77573
+ }
77574
+ if (children.length === 0) {
77575
+ return [];
77576
+ }
77577
+ if (children.length === 1) {
77578
+ return [cloneStackChild(children[0])];
77579
+ }
77580
+ return [{ ...node, children }];
77581
+ }
77582
+ }
77583
+ }
77584
+ function removeArtifactFromNode(node, artifactID) {
77585
+ switch (node.type) {
77586
+ case "card":
77587
+ return node.artifactID === artifactID ? [] : [cloneCard(node)];
77588
+ case "row": {
77589
+ const children = node.children.filter((child) => child.artifactID !== artifactID).map(cloneCard);
77590
+ if (children.length === 0) {
77591
+ return [];
77592
+ }
77593
+ if (children.length === 1) {
77594
+ return [children[0]];
77595
+ }
77596
+ return [{ ...node, children }];
77597
+ }
77598
+ case "stack": {
77599
+ const children = node.children.flatMap((child) => {
77600
+ const removed = removeArtifactFromNode(child, artifactID);
77601
+ return removed.filter((entry) => entry.type !== "stack");
77602
+ });
77603
+ if (children.length === 0) {
77604
+ return [];
77605
+ }
77606
+ if (children.length === 1) {
77607
+ return [cloneStackChild(children[0])];
77608
+ }
77609
+ return [{ ...node, children }];
77610
+ }
77611
+ }
77612
+ }
77613
+ function normalizeLegacyCols(width) {
77614
+ return Math.round(width) === LEGACY_NARROW_COLS ? LEGACY_NARROW_COLS : LEGACY_FULL_COLS;
77615
+ }
77616
+ function normalizeLegacyRows(height) {
77617
+ const rounded = Math.round(height);
77618
+ return LEGACY_ALLOWED_ROWS.includes(rounded) ? rounded : LEGACY_BAND_HEIGHT_ROWS;
77619
+ }
77620
+ function deriveLegacyBands(cards) {
77621
+ const bands = [];
77622
+ let current = null;
77623
+ for (const card of cards) {
77624
+ if (!current) {
77625
+ const placements = packLegacyBand([card], card.width);
77626
+ if (!placements) {
77627
+ continue;
77628
+ }
77629
+ current = {
77630
+ width: card.width,
77631
+ placements
77632
+ };
77633
+ continue;
77634
+ }
77635
+ const nextCards = current.placements.map((placement) => ({
77636
+ artifactID: placement.artifactID,
77637
+ width: placement.width,
77638
+ height: placement.height
77639
+ })).concat(card);
77640
+ let nextWidth = current.width;
77641
+ let packed = packLegacyBand(nextCards, nextWidth);
77642
+ if (!packed && current.width < LEGACY_FULL_COLS && card.width > current.width) {
77643
+ nextWidth = LEGACY_FULL_COLS;
77644
+ packed = packLegacyBand(nextCards, nextWidth);
77645
+ }
77646
+ if (packed) {
77647
+ current = {
77648
+ width: nextWidth,
77649
+ placements: packed
77650
+ };
77651
+ continue;
77652
+ }
77653
+ bands.push(current);
77654
+ const newPlacements = packLegacyBand([card], card.width);
77655
+ if (!newPlacements) {
77656
+ current = null;
77657
+ continue;
77658
+ }
77659
+ current = {
77660
+ width: card.width,
77661
+ placements: newPlacements
77662
+ };
77663
+ }
77664
+ if (current) {
77665
+ bands.push(current);
77666
+ }
77667
+ return bands;
77668
+ }
77669
+ function packLegacyBand(cards, width) {
77670
+ const occupied = Array.from(
77671
+ { length: LEGACY_BAND_HEIGHT_ROWS },
77672
+ () => Array.from({ length: width }, () => false)
77673
+ );
77674
+ const placements = [];
77675
+ for (const card of cards) {
77676
+ const position = firstLegacyFit(occupied, width, card);
77677
+ if (!position) {
77678
+ return null;
77679
+ }
77680
+ const placement = {
77681
+ artifactID: card.artifactID,
77682
+ width: card.width,
77683
+ height: card.height,
77684
+ x: position.x,
77685
+ y: position.y
77686
+ };
77687
+ placeLegacyCard(occupied, placement);
77688
+ placements.push(placement);
77689
+ }
77690
+ return placements;
77691
+ }
77692
+ function firstLegacyFit(occupied, width, card) {
77693
+ if (card.width > width || card.height > LEGACY_BAND_HEIGHT_ROWS) {
77694
+ return null;
77695
+ }
77696
+ for (let y2 = 0; y2 <= LEGACY_BAND_HEIGHT_ROWS - card.height; y2 += 1) {
77697
+ for (let x2 = 0; x2 <= width - card.width; x2 += 1) {
77698
+ let fits = true;
77699
+ for (let yy = y2; yy < y2 + card.height && fits; yy += 1) {
77700
+ for (let xx = x2; xx < x2 + card.width; xx += 1) {
77701
+ if (occupied[yy]?.[xx]) {
77702
+ fits = false;
77703
+ break;
77704
+ }
77705
+ }
77706
+ }
77707
+ if (fits) {
77708
+ return { x: x2, y: y2 };
77709
+ }
77710
+ }
77711
+ }
77712
+ return null;
77713
+ }
77714
+ function placeLegacyCard(occupied, placement) {
77715
+ for (let yy = placement.y; yy < placement.y + placement.height; yy += 1) {
77716
+ for (let xx = placement.x; xx < placement.x + placement.width; xx += 1) {
77717
+ occupied[yy][xx] = true;
77718
+ }
77719
+ }
77720
+ }
77721
+ function buildNodesForLegacyBand(band) {
77722
+ const placements = [...band.placements].sort((a, b2) => a.y - b2.y || a.x - b2.x);
77723
+ const children = [];
77724
+ for (let index = 0; index < placements.length; index += 1) {
77725
+ const current = placements[index];
77726
+ const next = placements[index + 1];
77727
+ if (current.width === LEGACY_NARROW_COLS && next && next.width === LEGACY_NARROW_COLS && next.y === current.y && next.height === current.height && current.x === LEGACY_LEFT_X && next.x === LEGACY_RIGHT_X) {
77728
+ children.push({
77729
+ id: ulid3(),
77730
+ type: "row",
77731
+ height: current.height,
77732
+ children: [migrateLegacyCard(current), migrateLegacyCard(next)]
77733
+ });
77734
+ index += 1;
77735
+ continue;
77736
+ }
77737
+ children.push(migrateLegacyCard(current));
77738
+ }
77739
+ if (children.length === 0) {
77740
+ return [];
77741
+ }
77742
+ if (children.length === 1) {
77743
+ const child = children[0];
77744
+ return child.type === "row" ? child.children.map(cloneCard) : [cloneCard(child)];
77745
+ }
77746
+ return [
77747
+ {
77748
+ id: ulid3(),
77749
+ type: "stack",
77750
+ children
77751
+ }
77752
+ ];
77753
+ }
77754
+ function migrateLegacyCard(card) {
77447
77755
  return {
77448
- type: "artifact",
77756
+ id: ulid3(),
77757
+ type: "card",
77449
77758
  artifactID: card.artifactID,
77450
- cols: clampLayoutCols(card.cols ?? DEFAULT_LAYOUT_CARD_COLS),
77451
- rows: clampLayoutRows(card.rows ?? DEFAULT_LAYOUT_CARD_ROWS)
77759
+ width: card.width === LEGACY_NARROW_COLS ? MIN_LAYOUT_CARD_WIDTH_UNITS : MAX_LAYOUT_CARD_WIDTH_UNITS,
77760
+ height: card.height
77452
77761
  };
77453
77762
  }
77454
- function migrateWorkspaceData(workspace) {
77455
- const layout = Array.isArray(workspace.layout) ? workspace.layout.map((card) => sanitizeLayoutCard(card)) : [];
77763
+ function cloneCard(node) {
77456
77764
  return {
77457
- id: workspace.id,
77458
- name: workspace.name,
77459
- layout
77765
+ ...node
77460
77766
  };
77461
77767
  }
77462
- function getWorkspaceArtifactIDs(workspace) {
77463
- return workspace.layout.map((card) => card.artifactID);
77768
+ function cloneStackChild(node) {
77769
+ return node.type === "card" ? cloneCard(node) : {
77770
+ ...node,
77771
+ children: node.children.map(cloneCard)
77772
+ };
77464
77773
  }
77465
77774
 
77466
77775
  // src/server/server-store.ts
@@ -77480,27 +77789,52 @@ function validateHTMLFragment(content) {
77480
77789
  }
77481
77790
  }
77482
77791
  function migrateWorkspaceJson(raw) {
77483
- if ("layout" in raw && Array.isArray(raw.layout) && raw.layout.length > 0) {
77484
- return false;
77485
- }
77486
77792
  if ("artifacts" in raw && Array.isArray(raw.artifacts)) {
77487
77793
  raw.layout = raw.artifacts;
77488
77794
  delete raw.artifacts;
77489
77795
  return true;
77490
77796
  }
77491
77797
  if ("artifactIDs" in raw && Array.isArray(raw.artifactIDs)) {
77492
- raw.layout = raw.artifactIDs.map((id) => ({
77493
- type: "artifact",
77494
- artifactID: id,
77495
- cols: DEFAULT_COLS,
77496
- rows: DEFAULT_ROWS
77497
- }));
77798
+ raw.layout = raw.artifactIDs.map((id) => ({ artifactID: id, width: DEFAULT_COLS, height: DEFAULT_ROWS }));
77498
77799
  delete raw.artifactIDs;
77499
77800
  return true;
77500
77801
  }
77501
77802
  return false;
77502
77803
  }
77503
- var ServerStore = class extends Emitter {
77804
+ function deserializeWorkspaceData(workspace) {
77805
+ const rawLayout = workspace.layout;
77806
+ if (!Array.isArray(rawLayout)) {
77807
+ return {
77808
+ migrated: false,
77809
+ workspace: {
77810
+ id: workspace.id,
77811
+ name: workspace.name,
77812
+ layout: []
77813
+ }
77814
+ };
77815
+ }
77816
+ if (rawLayout.every(
77817
+ (node) => typeof node === "object" && node !== null && "type" in node && (node.type === "card" || node.type === "stack")
77818
+ )) {
77819
+ return {
77820
+ migrated: false,
77821
+ workspace: {
77822
+ id: workspace.id,
77823
+ name: workspace.name,
77824
+ layout: rawLayout
77825
+ }
77826
+ };
77827
+ }
77828
+ return {
77829
+ migrated: true,
77830
+ workspace: {
77831
+ id: workspace.id,
77832
+ name: workspace.name,
77833
+ layout: migrateLegacyLayout(rawLayout)
77834
+ }
77835
+ };
77836
+ }
77837
+ var ServerStore = class extends EventTarget {
77504
77838
  dataDir;
77505
77839
  workspaces = /* @__PURE__ */ new Map();
77506
77840
  artifacts = /* @__PURE__ */ new Map();
@@ -77533,7 +77867,7 @@ var ServerStore = class extends Emitter {
77533
77867
  }
77534
77868
  findArtifactWorkspaces(artifactID) {
77535
77869
  return [...this.workspaces.values()].filter(
77536
- (workspace) => workspace.layout.some((card) => card.artifactID === artifactID)
77870
+ (workspace) => layoutContainsArtifactID(workspace.layout, artifactID)
77537
77871
  );
77538
77872
  }
77539
77873
  createArtifact(input) {
@@ -77551,14 +77885,18 @@ var ServerStore = class extends Emitter {
77551
77885
  content: input.content
77552
77886
  });
77553
77887
  this.artifacts.set(artifact.id, artifact);
77554
- workspace.layout.push(createLayoutCardRecord(artifact.id));
77888
+ workspace.layout = [...workspace.layout, createCardNode(artifact.id)];
77555
77889
  this.persistArtifact(artifact);
77556
77890
  this.persistWorkspace(workspace);
77557
- this.emit("mutation", {
77558
- type: "artifact-created",
77559
- workspaceID: workspace.id,
77560
- artifact
77561
- });
77891
+ this.dispatchEvent(
77892
+ new StoreChangeEvent("store-change", {
77893
+ message: {
77894
+ type: "artifact-created",
77895
+ workspaceID: workspace.id,
77896
+ artifact
77897
+ }
77898
+ })
77899
+ );
77562
77900
  return artifact;
77563
77901
  }
77564
77902
  updateArtifact(input) {
@@ -77568,11 +77906,15 @@ var ServerStore = class extends Emitter {
77568
77906
  }
77569
77907
  Object.assign(artifact, input.fields);
77570
77908
  this.persistArtifact(artifact);
77571
- this.emit("mutation", {
77572
- type: "artifact-updated",
77573
- artifactID: input.artifactID,
77574
- fields: input.fields
77575
- });
77909
+ this.dispatchEvent(
77910
+ new StoreChangeEvent("store-change", {
77911
+ message: {
77912
+ type: "artifact-updated",
77913
+ artifactID: input.artifactID,
77914
+ fields: input.fields
77915
+ }
77916
+ })
77917
+ );
77576
77918
  return artifact;
77577
77919
  }
77578
77920
  removeArtifact(input) {
@@ -77584,18 +77926,22 @@ var ServerStore = class extends Emitter {
77584
77926
  throw new Error(`Artifact not found: ${input.artifactID}`);
77585
77927
  }
77586
77928
  const workspace = this.requireWorkspace(input.workspaceID);
77587
- if (!workspace.layout.some((card) => card.artifactID === input.artifactID)) {
77929
+ if (!layoutContainsArtifactID(workspace.layout, input.artifactID)) {
77588
77930
  throw new Error(`Artifact not linked to workspace: ${input.artifactID}`);
77589
77931
  }
77590
77932
  this.artifacts.delete(input.artifactID);
77591
- workspace.layout = workspace.layout.filter((card) => card.artifactID !== input.artifactID);
77933
+ workspace.layout = removeArtifactFromLayout(workspace.layout, input.artifactID);
77592
77934
  this.persistWorkspace(workspace);
77593
77935
  this.deleteArtifactFile(input.artifactID);
77594
- this.emit("mutation", {
77595
- type: "artifact-removed",
77596
- artifactID: input.artifactID,
77597
- workspaceID: workspace.id
77598
- });
77936
+ this.dispatchEvent(
77937
+ new StoreChangeEvent("store-change", {
77938
+ message: {
77939
+ type: "artifact-removed",
77940
+ artifactID: input.artifactID,
77941
+ workspaceID: workspace.id
77942
+ }
77943
+ })
77944
+ );
77599
77945
  }
77600
77946
  createWorkspace(input) {
77601
77947
  const workspace = {
@@ -77605,10 +77951,14 @@ var ServerStore = class extends Emitter {
77605
77951
  };
77606
77952
  this.workspaces.set(workspace.id, workspace);
77607
77953
  this.persistWorkspace(workspace);
77608
- this.emit("mutation", {
77609
- type: "workspace-created",
77610
- workspace
77611
- });
77954
+ this.dispatchEvent(
77955
+ new StoreChangeEvent("store-change", {
77956
+ message: {
77957
+ type: "workspace-created",
77958
+ workspace
77959
+ }
77960
+ })
77961
+ );
77612
77962
  return workspace;
77613
77963
  }
77614
77964
  updateWorkspace(input) {
@@ -77619,15 +77969,19 @@ var ServerStore = class extends Emitter {
77619
77969
  nextFields.name = input.fields.name;
77620
77970
  }
77621
77971
  if (Array.isArray(input.fields.layout)) {
77622
- workspace.layout = input.fields.layout.map((card) => sanitizeLayoutCard(card));
77972
+ workspace.layout = input.fields.layout.map((node) => structuredClone(node));
77623
77973
  nextFields.layout = workspace.layout;
77624
77974
  }
77625
77975
  this.persistWorkspace(workspace);
77626
- this.emit("mutation", {
77627
- type: "workspace-updated",
77628
- workspaceID: input.workspaceID,
77629
- fields: nextFields
77630
- });
77976
+ this.dispatchEvent(
77977
+ new StoreChangeEvent("store-change", {
77978
+ message: {
77979
+ type: "workspace-updated",
77980
+ workspaceID: input.workspaceID,
77981
+ fields: nextFields
77982
+ }
77983
+ })
77984
+ );
77631
77985
  }
77632
77986
  removeWorkspace(input) {
77633
77987
  const workspace = this.requireWorkspace(input.workspaceID);
@@ -77640,10 +77994,14 @@ var ServerStore = class extends Emitter {
77640
77994
  this.deleteArtifactFile(artifactID);
77641
77995
  }
77642
77996
  this.deleteWorkspaceFile(workspace.id);
77643
- this.emit("mutation", {
77644
- type: "workspace-removed",
77645
- workspaceID: workspace.id
77646
- });
77997
+ this.dispatchEvent(
77998
+ new StoreChangeEvent("store-change", {
77999
+ message: {
78000
+ type: "workspace-removed",
78001
+ workspaceID: workspace.id
78002
+ }
78003
+ })
78004
+ );
77647
78005
  }
77648
78006
  requireWorkspace(workspaceID) {
77649
78007
  const workspace = this.workspaces.get(workspaceID);
@@ -77657,10 +78015,10 @@ var ServerStore = class extends Emitter {
77657
78015
  const filePath = import_node_path4.default.join(this.workspacesDir, file2);
77658
78016
  const raw = this.readJsonFile(filePath);
77659
78017
  if (!raw || typeof raw !== "object") continue;
77660
- const migrated = migrateWorkspaceJson(raw);
77661
- const workspace = migrateWorkspaceData(raw);
78018
+ const renamedLegacyFields = migrateWorkspaceJson(raw);
78019
+ const { workspace, migrated } = deserializeWorkspaceData(raw);
77662
78020
  this.workspaces.set(workspace.id, workspace);
77663
- if (migrated) {
78021
+ if (renamedLegacyFields || migrated) {
77664
78022
  this.persistWorkspace(workspace);
77665
78023
  }
77666
78024
  }