@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/electron.cjs CHANGED
@@ -54682,7 +54682,7 @@ var require_event_target = __commonJS({
54682
54682
  var kTarget = Symbol("kTarget");
54683
54683
  var kType = Symbol("kType");
54684
54684
  var kWasClean = Symbol("kWasClean");
54685
- var Event = class {
54685
+ var Event2 = class {
54686
54686
  /**
54687
54687
  * Create a new `Event`.
54688
54688
  *
@@ -54706,9 +54706,9 @@ var require_event_target = __commonJS({
54706
54706
  return this[kType];
54707
54707
  }
54708
54708
  };
54709
- Object.defineProperty(Event.prototype, "target", { enumerable: true });
54710
- Object.defineProperty(Event.prototype, "type", { enumerable: true });
54711
- var CloseEvent = class extends Event {
54709
+ Object.defineProperty(Event2.prototype, "target", { enumerable: true });
54710
+ Object.defineProperty(Event2.prototype, "type", { enumerable: true });
54711
+ var CloseEvent = class extends Event2 {
54712
54712
  /**
54713
54713
  * Create a new `CloseEvent`.
54714
54714
  *
@@ -54750,7 +54750,7 @@ var require_event_target = __commonJS({
54750
54750
  Object.defineProperty(CloseEvent.prototype, "code", { enumerable: true });
54751
54751
  Object.defineProperty(CloseEvent.prototype, "reason", { enumerable: true });
54752
54752
  Object.defineProperty(CloseEvent.prototype, "wasClean", { enumerable: true });
54753
- var ErrorEvent = class extends Event {
54753
+ var ErrorEvent = class extends Event2 {
54754
54754
  /**
54755
54755
  * Create a new `ErrorEvent`.
54756
54756
  *
@@ -54780,7 +54780,7 @@ var require_event_target = __commonJS({
54780
54780
  };
54781
54781
  Object.defineProperty(ErrorEvent.prototype, "error", { enumerable: true });
54782
54782
  Object.defineProperty(ErrorEvent.prototype, "message", { enumerable: true });
54783
- var MessageEvent = class extends Event {
54783
+ var MessageEvent = class extends Event2 {
54784
54784
  /**
54785
54785
  * Create a new `MessageEvent`.
54786
54786
  *
@@ -54801,7 +54801,7 @@ var require_event_target = __commonJS({
54801
54801
  }
54802
54802
  };
54803
54803
  Object.defineProperty(MessageEvent.prototype, "data", { enumerable: true });
54804
- var EventTarget = {
54804
+ var EventTarget2 = {
54805
54805
  /**
54806
54806
  * Register an event listener.
54807
54807
  *
@@ -54850,7 +54850,7 @@ var require_event_target = __commonJS({
54850
54850
  };
54851
54851
  } else if (type === "open") {
54852
54852
  wrapper = function onOpen() {
54853
- const event = new Event("open");
54853
+ const event = new Event2("open");
54854
54854
  event[kTarget] = this;
54855
54855
  callListener(handler, this, event);
54856
54856
  };
@@ -54884,8 +54884,8 @@ var require_event_target = __commonJS({
54884
54884
  module2.exports = {
54885
54885
  CloseEvent,
54886
54886
  ErrorEvent,
54887
- Event,
54888
- EventTarget,
54887
+ Event: Event2,
54888
+ EventTarget: EventTarget2,
54889
54889
  MessageEvent
54890
54890
  };
54891
54891
  function callListener(listener, thisArg, event) {
@@ -73479,18 +73479,26 @@ var Server2 = class {
73479
73479
  this.handleClientMessage(socket, data.toString());
73480
73480
  });
73481
73481
  });
73482
- this.store.on("mutation", (event) => {
73483
- this.broadcast(event);
73482
+ this.store.addEventListener("store-change", (event) => {
73483
+ this.broadcast(event.message);
73484
73484
  });
73485
73485
  }
73486
73486
  start() {
73487
- return new Promise((resolve) => {
73488
- this.httpServer.listen(this.port, this.host, () => {
73487
+ return new Promise((resolve, reject) => {
73488
+ const handleError = (error2) => {
73489
+ this.httpServer.off("listening", handleListening);
73490
+ reject(error2);
73491
+ };
73492
+ const handleListening = () => {
73493
+ this.httpServer.off("error", handleError);
73489
73494
  const address = this.httpServer.address();
73490
73495
  const resolvedPort = typeof address === "object" && address ? address.port : this.port;
73491
73496
  this.baseURL = buildServerURL(this.host ?? DEFAULT_SERVER_HOST, resolvedPort);
73492
73497
  resolve(this.httpServer);
73493
- });
73498
+ };
73499
+ this.httpServer.once("error", handleError);
73500
+ this.httpServer.once("listening", handleListening);
73501
+ this.httpServer.listen(this.port, this.host);
73494
73502
  });
73495
73503
  }
73496
73504
  getBaseURL() {
@@ -73641,114 +73649,415 @@ function isClientMessage(value) {
73641
73649
  case "create-workspace":
73642
73650
  return typeof message.id === "string" && typeof message.name === "string";
73643
73651
  case "update-workspace":
73644
- 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(
73645
- (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"
73646
- ));
73652
+ 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));
73647
73653
  case "delete-workspace":
73648
73654
  return typeof message.workspaceID === "string";
73649
73655
  default:
73650
73656
  return false;
73651
73657
  }
73652
73658
  }
73653
-
73654
- // node_modules/mitt/dist/mitt.mjs
73655
- function mitt_default(n) {
73656
- return { all: n = n || /* @__PURE__ */ new Map(), on: function(t, e) {
73657
- var i = n.get(t);
73658
- i ? i.push(e) : n.set(t, [e]);
73659
- }, off: function(t, e) {
73660
- var i = n.get(t);
73661
- i && (e ? i.splice(i.indexOf(e) >>> 0, 1) : n.set(t, []));
73662
- }, emit: function(t, e) {
73663
- var i = n.get(t);
73664
- i && i.slice().map(function(n2) {
73665
- n2(e);
73666
- }), (i = n.get("*")) && i.slice().map(function(n2) {
73667
- n2(t, e);
73668
- });
73669
- } };
73659
+ function isLayoutNode(value) {
73660
+ if (typeof value !== "object" || value === null || !("type" in value)) {
73661
+ return false;
73662
+ }
73663
+ const node = value;
73664
+ switch (node.type) {
73665
+ case "card":
73666
+ return typeof node.id === "string" && typeof node.artifactID === "string" && (typeof node.width === "number" || node.width === "auto") && (typeof node.height === "number" || node.height === "auto");
73667
+ case "row":
73668
+ return typeof node.id === "string" && (typeof node.height === "number" || node.height === "auto") && Array.isArray(node.children) && node.children.every(isLayoutNode);
73669
+ case "stack":
73670
+ return typeof node.id === "string" && Array.isArray(node.children) && node.children.every(isLayoutNode);
73671
+ default:
73672
+ return false;
73673
+ }
73670
73674
  }
73671
73675
 
73672
- // node_modules/@rupertsworld/emitter/dist/index.js
73673
- var Emitter = class {
73674
- emitter = mitt_default();
73675
- on(type, handler) {
73676
- this.emitter.on(type, handler);
73677
- return { dispose: () => this.emitter.off(type, handler) };
73676
+ // node_modules/@rupertsworld/event-target/dist/index.js
73677
+ var RESERVED_EVENT_KEYS = /* @__PURE__ */ new Set([
73678
+ "target",
73679
+ "currentTarget",
73680
+ "eventPhase",
73681
+ "defaultPrevented",
73682
+ "isTrusted",
73683
+ "timeStamp",
73684
+ "srcElement",
73685
+ "returnValue",
73686
+ "cancelBubble",
73687
+ "NONE",
73688
+ "CAPTURING_PHASE",
73689
+ "AT_TARGET",
73690
+ "BUBBLING_PHASE",
73691
+ "composedPath",
73692
+ "stopPropagation",
73693
+ "stopImmediatePropagation",
73694
+ "preventDefault",
73695
+ "initEvent"
73696
+ ]);
73697
+ function assertNoReservedPayloadKeys(props) {
73698
+ for (const key of Object.keys(props)) {
73699
+ if (RESERVED_EVENT_KEYS.has(key)) {
73700
+ throw new Error(`Event payload key "${key}" is reserved; choose a different property name`);
73701
+ }
73678
73702
  }
73679
- once(type, handler) {
73680
- const wrappedHandler = (...args) => {
73681
- handler(...args);
73682
- this.emitter.off(type, wrappedHandler);
73683
- };
73684
- this.emitter.on(type, wrappedHandler);
73685
- return { dispose: () => this.emitter.off(type, wrappedHandler) };
73703
+ }
73704
+ function assignPayload(target, props) {
73705
+ assertNoReservedPayloadKeys(props);
73706
+ for (const key of Object.keys(props)) {
73707
+ Object.defineProperty(target, key, {
73708
+ value: props[key],
73709
+ writable: true,
73710
+ enumerable: true,
73711
+ configurable: true
73712
+ });
73686
73713
  }
73687
- /**
73688
- * Unsubscribe from an event
73689
- */
73690
- off = this.emitter.off;
73691
- /**
73692
- * Emit an event
73693
- */
73694
- emit(type, ...[event]) {
73695
- this.emitter.emit(type, event);
73714
+ }
73715
+ function defineEvent() {
73716
+ class DefinedEvent extends Event {
73717
+ constructor(type, init) {
73718
+ const { type: initType, bubbles, cancelable, composed, ...payload } = init ?? {};
73719
+ if (initType !== void 0) {
73720
+ throw new Error(`Do not pass "type" in init; use the constructor argument instead`);
73721
+ }
73722
+ super(type, { bubbles, cancelable, composed });
73723
+ assignPayload(this, payload);
73724
+ }
73696
73725
  }
73726
+ return DefinedEvent;
73727
+ }
73728
+ var EventTarget = class extends globalThis.EventTarget {
73697
73729
  };
73698
73730
 
73731
+ // src/events.ts
73732
+ var ChangeEvent = defineEvent();
73733
+ var ServerMessageEvent = defineEvent();
73734
+ var LayoutMutationEvent = defineEvent();
73735
+ var LayoutScrollEvent = defineEvent();
73736
+ var StoreChangeEvent = defineEvent();
73737
+
73699
73738
  // src/server/server-store.ts
73700
73739
  var import_node_crypto2 = require("node:crypto");
73701
73740
  var import_node_fs2 = require("node:fs");
73702
73741
  var import_node_path3 = __toESM(require("node:path"), 1);
73703
73742
 
73743
+ // src/constants.ts
73744
+ var LAYOUT_FULL_WIDTH_UNITS = 4;
73745
+ var LAYOUT_FULL_HEIGHT_UNITS = 6;
73746
+ var MIN_LAYOUT_CARD_WIDTH_UNITS = 2;
73747
+ var MAX_LAYOUT_CARD_WIDTH_UNITS = LAYOUT_FULL_WIDTH_UNITS;
73748
+ var DEFAULT_LAYOUT_CARD_WIDTH = "auto";
73749
+ var DEFAULT_LAYOUT_CARD_HEIGHT = "auto";
73750
+ var DEFAULT_LAYOUT_UNIT = 120;
73751
+ var CARD_GAP = 16;
73752
+ var CARD_WIDTH = DEFAULT_LAYOUT_UNIT * LAYOUT_FULL_WIDTH_UNITS + CARD_GAP * (LAYOUT_FULL_WIDTH_UNITS - 1);
73753
+ var CARD_HEIGHT = DEFAULT_LAYOUT_UNIT * LAYOUT_FULL_HEIGHT_UNITS + CARD_GAP * (LAYOUT_FULL_HEIGHT_UNITS - 1);
73754
+
73704
73755
  // src/types.ts
73705
- var DEFAULT_LAYOUT_CARD_COLS = 2;
73706
- var DEFAULT_LAYOUT_CARD_ROWS = 6;
73707
- var LAYOUT_COLS_NARROW = 1;
73708
- var LAYOUT_ROW_SHORT = 2;
73709
- var LAYOUT_ROW_MID = 3;
73710
- var LAYOUT_ROW_TALL = 4;
73711
- var ALLOWED_COLS = [LAYOUT_COLS_NARROW, DEFAULT_LAYOUT_CARD_COLS];
73712
- var ALLOWED_ROWS = [
73713
- LAYOUT_ROW_SHORT,
73714
- LAYOUT_ROW_MID,
73715
- LAYOUT_ROW_TALL,
73716
- DEFAULT_LAYOUT_CARD_ROWS
73717
- ];
73718
- function clampLayoutCols(cols) {
73719
- const n = Math.round(cols);
73720
- return ALLOWED_COLS.includes(n) ? n : DEFAULT_LAYOUT_CARD_COLS;
73721
- }
73722
- function clampLayoutRows(rows) {
73723
- const n = Math.round(rows);
73724
- return ALLOWED_ROWS.includes(n) ? n : DEFAULT_LAYOUT_CARD_ROWS;
73725
- }
73726
- function createLayoutCardRecord(artifactID) {
73756
+ function createCardNode(artifactID, overrides = {}) {
73727
73757
  return {
73728
- type: "artifact",
73758
+ id: overrides.id ?? ulid3(),
73759
+ type: "card",
73729
73760
  artifactID,
73730
- cols: DEFAULT_LAYOUT_CARD_COLS,
73731
- rows: DEFAULT_LAYOUT_CARD_ROWS
73761
+ width: overrides.width ?? DEFAULT_LAYOUT_CARD_WIDTH,
73762
+ height: overrides.height ?? DEFAULT_LAYOUT_CARD_HEIGHT
73732
73763
  };
73733
73764
  }
73734
- function sanitizeLayoutCard(card) {
73765
+ function layoutContainsArtifactID(layout, artifactID) {
73766
+ return layout.some((node) => nodeContainsArtifactID(node, artifactID));
73767
+ }
73768
+ function nodeContainsArtifactID(node, artifactID) {
73769
+ switch (node.type) {
73770
+ case "card":
73771
+ return node.artifactID === artifactID;
73772
+ case "row":
73773
+ return node.children.some((child) => child.artifactID === artifactID);
73774
+ case "stack":
73775
+ return node.children.some((child) => nodeContainsArtifactID(child, artifactID));
73776
+ }
73777
+ }
73778
+ function getWorkspaceArtifactIDs(workspace) {
73779
+ return workspace.layout.flatMap(collectArtifactIDs);
73780
+ }
73781
+ function collectArtifactIDs(node) {
73782
+ switch (node.type) {
73783
+ case "card":
73784
+ return [node.artifactID];
73785
+ case "row":
73786
+ return node.children.map((child) => child.artifactID);
73787
+ case "stack":
73788
+ return node.children.flatMap(collectArtifactIDs);
73789
+ }
73790
+ }
73791
+
73792
+ // src/browser/ui/layout.ts
73793
+ var LEGACY_BAND_HEIGHT_ROWS = 6;
73794
+ var LEGACY_NARROW_COLS = 1;
73795
+ var LEGACY_FULL_COLS = 2;
73796
+ var LEGACY_ROW_SHORT = 2;
73797
+ var LEGACY_ROW_MID = 3;
73798
+ var LEGACY_ROW_TALL = 4;
73799
+ var LEGACY_ROW_FULL = 6;
73800
+ var LEGACY_ALLOWED_ROWS = [LEGACY_ROW_SHORT, LEGACY_ROW_MID, LEGACY_ROW_TALL, LEGACY_ROW_FULL];
73801
+ var LEGACY_LEFT_X = 0;
73802
+ var LEGACY_RIGHT_X = 1;
73803
+ function removeArtifactFromLayout(layout, artifactID) {
73804
+ return normalizeRootNodes(layout.flatMap((node) => removeArtifactFromNode(node, artifactID)));
73805
+ }
73806
+ function migrateLegacyLayout(cards) {
73807
+ const normalized = cards.map((card) => ({
73808
+ artifactID: card.artifactID,
73809
+ width: normalizeLegacyCols(card.width),
73810
+ height: normalizeLegacyRows(card.height)
73811
+ }));
73812
+ const bands = deriveLegacyBands(normalized);
73813
+ return normalizeRootNodes(bands.flatMap(buildNodesForLegacyBand));
73814
+ }
73815
+ function normalizeRootNodes(layout) {
73816
+ const normalized = [];
73817
+ for (const node of layout) {
73818
+ const entries = normalizeNode(node);
73819
+ for (const entry of entries) {
73820
+ if (entry.type === "row") {
73821
+ normalized.push(...entry.children.map(cloneCard));
73822
+ continue;
73823
+ }
73824
+ normalized.push(entry);
73825
+ }
73826
+ }
73827
+ return normalized;
73828
+ }
73829
+ function normalizeNode(node) {
73830
+ switch (node.type) {
73831
+ case "card":
73832
+ return [cloneCard(node)];
73833
+ case "row": {
73834
+ const children = node.children.map(cloneCard);
73835
+ if (children.length === 0) {
73836
+ return [];
73837
+ }
73838
+ if (children.length === 1) {
73839
+ return [children[0]];
73840
+ }
73841
+ return [{ ...node, children }];
73842
+ }
73843
+ case "stack": {
73844
+ const children = [];
73845
+ for (const child of node.children) {
73846
+ const normalizedChildren = normalizeNode(child);
73847
+ for (const normalizedChild of normalizedChildren) {
73848
+ if (normalizedChild.type === "stack") {
73849
+ children.push(...normalizedChild.children.map(cloneStackChild));
73850
+ continue;
73851
+ }
73852
+ if (normalizedChild.type === "row") {
73853
+ children.push({
73854
+ ...normalizedChild,
73855
+ children: normalizedChild.children.map(cloneCard)
73856
+ });
73857
+ continue;
73858
+ }
73859
+ children.push(cloneCard(normalizedChild));
73860
+ }
73861
+ }
73862
+ if (children.length === 0) {
73863
+ return [];
73864
+ }
73865
+ if (children.length === 1) {
73866
+ return [cloneStackChild(children[0])];
73867
+ }
73868
+ return [{ ...node, children }];
73869
+ }
73870
+ }
73871
+ }
73872
+ function removeArtifactFromNode(node, artifactID) {
73873
+ switch (node.type) {
73874
+ case "card":
73875
+ return node.artifactID === artifactID ? [] : [cloneCard(node)];
73876
+ case "row": {
73877
+ const children = node.children.filter((child) => child.artifactID !== artifactID).map(cloneCard);
73878
+ if (children.length === 0) {
73879
+ return [];
73880
+ }
73881
+ if (children.length === 1) {
73882
+ return [children[0]];
73883
+ }
73884
+ return [{ ...node, children }];
73885
+ }
73886
+ case "stack": {
73887
+ const children = node.children.flatMap((child) => {
73888
+ const removed = removeArtifactFromNode(child, artifactID);
73889
+ return removed.filter((entry) => entry.type !== "stack");
73890
+ });
73891
+ if (children.length === 0) {
73892
+ return [];
73893
+ }
73894
+ if (children.length === 1) {
73895
+ return [cloneStackChild(children[0])];
73896
+ }
73897
+ return [{ ...node, children }];
73898
+ }
73899
+ }
73900
+ }
73901
+ function normalizeLegacyCols(width) {
73902
+ return Math.round(width) === LEGACY_NARROW_COLS ? LEGACY_NARROW_COLS : LEGACY_FULL_COLS;
73903
+ }
73904
+ function normalizeLegacyRows(height) {
73905
+ const rounded = Math.round(height);
73906
+ return LEGACY_ALLOWED_ROWS.includes(rounded) ? rounded : LEGACY_BAND_HEIGHT_ROWS;
73907
+ }
73908
+ function deriveLegacyBands(cards) {
73909
+ const bands = [];
73910
+ let current = null;
73911
+ for (const card of cards) {
73912
+ if (!current) {
73913
+ const placements = packLegacyBand([card], card.width);
73914
+ if (!placements) {
73915
+ continue;
73916
+ }
73917
+ current = {
73918
+ width: card.width,
73919
+ placements
73920
+ };
73921
+ continue;
73922
+ }
73923
+ const nextCards = current.placements.map((placement) => ({
73924
+ artifactID: placement.artifactID,
73925
+ width: placement.width,
73926
+ height: placement.height
73927
+ })).concat(card);
73928
+ let nextWidth = current.width;
73929
+ let packed = packLegacyBand(nextCards, nextWidth);
73930
+ if (!packed && current.width < LEGACY_FULL_COLS && card.width > current.width) {
73931
+ nextWidth = LEGACY_FULL_COLS;
73932
+ packed = packLegacyBand(nextCards, nextWidth);
73933
+ }
73934
+ if (packed) {
73935
+ current = {
73936
+ width: nextWidth,
73937
+ placements: packed
73938
+ };
73939
+ continue;
73940
+ }
73941
+ bands.push(current);
73942
+ const newPlacements = packLegacyBand([card], card.width);
73943
+ if (!newPlacements) {
73944
+ current = null;
73945
+ continue;
73946
+ }
73947
+ current = {
73948
+ width: card.width,
73949
+ placements: newPlacements
73950
+ };
73951
+ }
73952
+ if (current) {
73953
+ bands.push(current);
73954
+ }
73955
+ return bands;
73956
+ }
73957
+ function packLegacyBand(cards, width) {
73958
+ const occupied = Array.from(
73959
+ { length: LEGACY_BAND_HEIGHT_ROWS },
73960
+ () => Array.from({ length: width }, () => false)
73961
+ );
73962
+ const placements = [];
73963
+ for (const card of cards) {
73964
+ const position = firstLegacyFit(occupied, width, card);
73965
+ if (!position) {
73966
+ return null;
73967
+ }
73968
+ const placement = {
73969
+ artifactID: card.artifactID,
73970
+ width: card.width,
73971
+ height: card.height,
73972
+ x: position.x,
73973
+ y: position.y
73974
+ };
73975
+ placeLegacyCard(occupied, placement);
73976
+ placements.push(placement);
73977
+ }
73978
+ return placements;
73979
+ }
73980
+ function firstLegacyFit(occupied, width, card) {
73981
+ if (card.width > width || card.height > LEGACY_BAND_HEIGHT_ROWS) {
73982
+ return null;
73983
+ }
73984
+ for (let y2 = 0; y2 <= LEGACY_BAND_HEIGHT_ROWS - card.height; y2 += 1) {
73985
+ for (let x2 = 0; x2 <= width - card.width; x2 += 1) {
73986
+ let fits = true;
73987
+ for (let yy = y2; yy < y2 + card.height && fits; yy += 1) {
73988
+ for (let xx = x2; xx < x2 + card.width; xx += 1) {
73989
+ if (occupied[yy]?.[xx]) {
73990
+ fits = false;
73991
+ break;
73992
+ }
73993
+ }
73994
+ }
73995
+ if (fits) {
73996
+ return { x: x2, y: y2 };
73997
+ }
73998
+ }
73999
+ }
74000
+ return null;
74001
+ }
74002
+ function placeLegacyCard(occupied, placement) {
74003
+ for (let yy = placement.y; yy < placement.y + placement.height; yy += 1) {
74004
+ for (let xx = placement.x; xx < placement.x + placement.width; xx += 1) {
74005
+ occupied[yy][xx] = true;
74006
+ }
74007
+ }
74008
+ }
74009
+ function buildNodesForLegacyBand(band) {
74010
+ const placements = [...band.placements].sort((a, b2) => a.y - b2.y || a.x - b2.x);
74011
+ const children = [];
74012
+ for (let index = 0; index < placements.length; index += 1) {
74013
+ const current = placements[index];
74014
+ const next = placements[index + 1];
74015
+ 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) {
74016
+ children.push({
74017
+ id: ulid3(),
74018
+ type: "row",
74019
+ height: current.height,
74020
+ children: [migrateLegacyCard(current), migrateLegacyCard(next)]
74021
+ });
74022
+ index += 1;
74023
+ continue;
74024
+ }
74025
+ children.push(migrateLegacyCard(current));
74026
+ }
74027
+ if (children.length === 0) {
74028
+ return [];
74029
+ }
74030
+ if (children.length === 1) {
74031
+ const child = children[0];
74032
+ return child.type === "row" ? child.children.map(cloneCard) : [cloneCard(child)];
74033
+ }
74034
+ return [
74035
+ {
74036
+ id: ulid3(),
74037
+ type: "stack",
74038
+ children
74039
+ }
74040
+ ];
74041
+ }
74042
+ function migrateLegacyCard(card) {
73735
74043
  return {
73736
- type: "artifact",
74044
+ id: ulid3(),
74045
+ type: "card",
73737
74046
  artifactID: card.artifactID,
73738
- cols: clampLayoutCols(card.cols ?? DEFAULT_LAYOUT_CARD_COLS),
73739
- rows: clampLayoutRows(card.rows ?? DEFAULT_LAYOUT_CARD_ROWS)
74047
+ width: card.width === LEGACY_NARROW_COLS ? MIN_LAYOUT_CARD_WIDTH_UNITS : MAX_LAYOUT_CARD_WIDTH_UNITS,
74048
+ height: card.height
73740
74049
  };
73741
74050
  }
73742
- function migrateWorkspaceData(workspace) {
73743
- const layout = Array.isArray(workspace.layout) ? workspace.layout.map((card) => sanitizeLayoutCard(card)) : [];
74051
+ function cloneCard(node) {
73744
74052
  return {
73745
- id: workspace.id,
73746
- name: workspace.name,
73747
- layout
74053
+ ...node
73748
74054
  };
73749
74055
  }
73750
- function getWorkspaceArtifactIDs(workspace) {
73751
- return workspace.layout.map((card) => card.artifactID);
74056
+ function cloneStackChild(node) {
74057
+ return node.type === "card" ? cloneCard(node) : {
74058
+ ...node,
74059
+ children: node.children.map(cloneCard)
74060
+ };
73752
74061
  }
73753
74062
 
73754
74063
  // src/server/server-store.ts
@@ -73768,27 +74077,52 @@ function validateHTMLFragment(content) {
73768
74077
  }
73769
74078
  }
73770
74079
  function migrateWorkspaceJson(raw) {
73771
- if ("layout" in raw && Array.isArray(raw.layout) && raw.layout.length > 0) {
73772
- return false;
73773
- }
73774
74080
  if ("artifacts" in raw && Array.isArray(raw.artifacts)) {
73775
74081
  raw.layout = raw.artifacts;
73776
74082
  delete raw.artifacts;
73777
74083
  return true;
73778
74084
  }
73779
74085
  if ("artifactIDs" in raw && Array.isArray(raw.artifactIDs)) {
73780
- raw.layout = raw.artifactIDs.map((id) => ({
73781
- type: "artifact",
73782
- artifactID: id,
73783
- cols: DEFAULT_COLS,
73784
- rows: DEFAULT_ROWS
73785
- }));
74086
+ raw.layout = raw.artifactIDs.map((id) => ({ artifactID: id, width: DEFAULT_COLS, height: DEFAULT_ROWS }));
73786
74087
  delete raw.artifactIDs;
73787
74088
  return true;
73788
74089
  }
73789
74090
  return false;
73790
74091
  }
73791
- var ServerStore = class extends Emitter {
74092
+ function deserializeWorkspaceData(workspace) {
74093
+ const rawLayout = workspace.layout;
74094
+ if (!Array.isArray(rawLayout)) {
74095
+ return {
74096
+ migrated: false,
74097
+ workspace: {
74098
+ id: workspace.id,
74099
+ name: workspace.name,
74100
+ layout: []
74101
+ }
74102
+ };
74103
+ }
74104
+ if (rawLayout.every(
74105
+ (node) => typeof node === "object" && node !== null && "type" in node && (node.type === "card" || node.type === "stack")
74106
+ )) {
74107
+ return {
74108
+ migrated: false,
74109
+ workspace: {
74110
+ id: workspace.id,
74111
+ name: workspace.name,
74112
+ layout: rawLayout
74113
+ }
74114
+ };
74115
+ }
74116
+ return {
74117
+ migrated: true,
74118
+ workspace: {
74119
+ id: workspace.id,
74120
+ name: workspace.name,
74121
+ layout: migrateLegacyLayout(rawLayout)
74122
+ }
74123
+ };
74124
+ }
74125
+ var ServerStore = class extends EventTarget {
73792
74126
  dataDir;
73793
74127
  workspaces = /* @__PURE__ */ new Map();
73794
74128
  artifacts = /* @__PURE__ */ new Map();
@@ -73821,7 +74155,7 @@ var ServerStore = class extends Emitter {
73821
74155
  }
73822
74156
  findArtifactWorkspaces(artifactID) {
73823
74157
  return [...this.workspaces.values()].filter(
73824
- (workspace) => workspace.layout.some((card) => card.artifactID === artifactID)
74158
+ (workspace) => layoutContainsArtifactID(workspace.layout, artifactID)
73825
74159
  );
73826
74160
  }
73827
74161
  createArtifact(input) {
@@ -73839,14 +74173,18 @@ var ServerStore = class extends Emitter {
73839
74173
  content: input.content
73840
74174
  });
73841
74175
  this.artifacts.set(artifact.id, artifact);
73842
- workspace.layout.push(createLayoutCardRecord(artifact.id));
74176
+ workspace.layout = [...workspace.layout, createCardNode(artifact.id)];
73843
74177
  this.persistArtifact(artifact);
73844
74178
  this.persistWorkspace(workspace);
73845
- this.emit("mutation", {
73846
- type: "artifact-created",
73847
- workspaceID: workspace.id,
73848
- artifact
73849
- });
74179
+ this.dispatchEvent(
74180
+ new StoreChangeEvent("store-change", {
74181
+ message: {
74182
+ type: "artifact-created",
74183
+ workspaceID: workspace.id,
74184
+ artifact
74185
+ }
74186
+ })
74187
+ );
73850
74188
  return artifact;
73851
74189
  }
73852
74190
  updateArtifact(input) {
@@ -73856,11 +74194,15 @@ var ServerStore = class extends Emitter {
73856
74194
  }
73857
74195
  Object.assign(artifact, input.fields);
73858
74196
  this.persistArtifact(artifact);
73859
- this.emit("mutation", {
73860
- type: "artifact-updated",
73861
- artifactID: input.artifactID,
73862
- fields: input.fields
73863
- });
74197
+ this.dispatchEvent(
74198
+ new StoreChangeEvent("store-change", {
74199
+ message: {
74200
+ type: "artifact-updated",
74201
+ artifactID: input.artifactID,
74202
+ fields: input.fields
74203
+ }
74204
+ })
74205
+ );
73864
74206
  return artifact;
73865
74207
  }
73866
74208
  removeArtifact(input) {
@@ -73872,18 +74214,22 @@ var ServerStore = class extends Emitter {
73872
74214
  throw new Error(`Artifact not found: ${input.artifactID}`);
73873
74215
  }
73874
74216
  const workspace = this.requireWorkspace(input.workspaceID);
73875
- if (!workspace.layout.some((card) => card.artifactID === input.artifactID)) {
74217
+ if (!layoutContainsArtifactID(workspace.layout, input.artifactID)) {
73876
74218
  throw new Error(`Artifact not linked to workspace: ${input.artifactID}`);
73877
74219
  }
73878
74220
  this.artifacts.delete(input.artifactID);
73879
- workspace.layout = workspace.layout.filter((card) => card.artifactID !== input.artifactID);
74221
+ workspace.layout = removeArtifactFromLayout(workspace.layout, input.artifactID);
73880
74222
  this.persistWorkspace(workspace);
73881
74223
  this.deleteArtifactFile(input.artifactID);
73882
- this.emit("mutation", {
73883
- type: "artifact-removed",
73884
- artifactID: input.artifactID,
73885
- workspaceID: workspace.id
73886
- });
74224
+ this.dispatchEvent(
74225
+ new StoreChangeEvent("store-change", {
74226
+ message: {
74227
+ type: "artifact-removed",
74228
+ artifactID: input.artifactID,
74229
+ workspaceID: workspace.id
74230
+ }
74231
+ })
74232
+ );
73887
74233
  }
73888
74234
  createWorkspace(input) {
73889
74235
  const workspace = {
@@ -73893,10 +74239,14 @@ var ServerStore = class extends Emitter {
73893
74239
  };
73894
74240
  this.workspaces.set(workspace.id, workspace);
73895
74241
  this.persistWorkspace(workspace);
73896
- this.emit("mutation", {
73897
- type: "workspace-created",
73898
- workspace
73899
- });
74242
+ this.dispatchEvent(
74243
+ new StoreChangeEvent("store-change", {
74244
+ message: {
74245
+ type: "workspace-created",
74246
+ workspace
74247
+ }
74248
+ })
74249
+ );
73900
74250
  return workspace;
73901
74251
  }
73902
74252
  updateWorkspace(input) {
@@ -73907,15 +74257,19 @@ var ServerStore = class extends Emitter {
73907
74257
  nextFields.name = input.fields.name;
73908
74258
  }
73909
74259
  if (Array.isArray(input.fields.layout)) {
73910
- workspace.layout = input.fields.layout.map((card) => sanitizeLayoutCard(card));
74260
+ workspace.layout = input.fields.layout.map((node) => structuredClone(node));
73911
74261
  nextFields.layout = workspace.layout;
73912
74262
  }
73913
74263
  this.persistWorkspace(workspace);
73914
- this.emit("mutation", {
73915
- type: "workspace-updated",
73916
- workspaceID: input.workspaceID,
73917
- fields: nextFields
73918
- });
74264
+ this.dispatchEvent(
74265
+ new StoreChangeEvent("store-change", {
74266
+ message: {
74267
+ type: "workspace-updated",
74268
+ workspaceID: input.workspaceID,
74269
+ fields: nextFields
74270
+ }
74271
+ })
74272
+ );
73919
74273
  }
73920
74274
  removeWorkspace(input) {
73921
74275
  const workspace = this.requireWorkspace(input.workspaceID);
@@ -73928,10 +74282,14 @@ var ServerStore = class extends Emitter {
73928
74282
  this.deleteArtifactFile(artifactID);
73929
74283
  }
73930
74284
  this.deleteWorkspaceFile(workspace.id);
73931
- this.emit("mutation", {
73932
- type: "workspace-removed",
73933
- workspaceID: workspace.id
73934
- });
74285
+ this.dispatchEvent(
74286
+ new StoreChangeEvent("store-change", {
74287
+ message: {
74288
+ type: "workspace-removed",
74289
+ workspaceID: workspace.id
74290
+ }
74291
+ })
74292
+ );
73935
74293
  }
73936
74294
  requireWorkspace(workspaceID) {
73937
74295
  const workspace = this.workspaces.get(workspaceID);
@@ -73945,10 +74303,10 @@ var ServerStore = class extends Emitter {
73945
74303
  const filePath = import_node_path3.default.join(this.workspacesDir, file2);
73946
74304
  const raw = this.readJsonFile(filePath);
73947
74305
  if (!raw || typeof raw !== "object") continue;
73948
- const migrated = migrateWorkspaceJson(raw);
73949
- const workspace = migrateWorkspaceData(raw);
74306
+ const renamedLegacyFields = migrateWorkspaceJson(raw);
74307
+ const { workspace, migrated } = deserializeWorkspaceData(raw);
73950
74308
  this.workspaces.set(workspace.id, workspace);
73951
- if (migrated) {
74309
+ if (renamedLegacyFields || migrated) {
73952
74310
  this.persistWorkspace(workspace);
73953
74311
  }
73954
74312
  }