@sequent-org/moodboard 1.4.9 → 1.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sequent-org/moodboard",
3
- "version": "1.4.9",
3
+ "version": "1.4.11",
4
4
  "type": "module",
5
5
  "description": "Interactive moodboard",
6
6
  "main": "./src/index.js",
@@ -67,11 +67,17 @@ export class ApiClient {
67
67
  const objects = Array.isArray(cleanedData?.objects) ? cleanedData.objects : [];
68
68
  const imageObjects = objects.filter((obj) => obj?.type === 'image');
69
69
  const imageObjectsWithSrc = imageObjects.filter((obj) => typeof obj?.src === 'string' && obj.src.trim().length > 0);
70
+ const imageObjectsWithoutSrc = imageObjects
71
+ .filter((obj) => !(typeof obj?.src === 'string' && obj.src.trim().length > 0))
72
+ .map((obj) => obj?.id || 'unknown');
70
73
  console.log('history/save payload stats:', {
71
74
  totalObjects: objects.length,
72
75
  imageObjects: imageObjects.length,
73
76
  imageObjectsWithSrc: imageObjectsWithSrc.length
74
77
  });
78
+ if (imageObjectsWithoutSrc.length > 0) {
79
+ console.warn('history/save warning: image objects without src (kept as broken placeholders):', imageObjectsWithoutSrc);
80
+ }
75
81
 
76
82
  const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
77
83
 
@@ -157,7 +163,7 @@ export class ApiClient {
157
163
  const normalizedSrc = topSrcRaw.trim() || propSrcRaw.trim();
158
164
 
159
165
  if (!normalizedSrc) {
160
- throw new Error(`Image object "${obj.id || 'unknown'}" has no src. Save is blocked.`);
166
+ return obj;
161
167
  }
162
168
  if (/^data:/i.test(normalizedSrc) || /^blob:/i.test(normalizedSrc)) {
163
169
  throw new Error(`Image object "${obj.id || 'unknown'}" contains forbidden data/blob src. Save is blocked.`);
@@ -174,9 +180,6 @@ export class ApiClient {
174
180
  cleanedObj.properties = { ...cleanedObj.properties };
175
181
  delete cleanedObj.properties.src;
176
182
  }
177
- if ('imageId' in cleanedObj) {
178
- delete cleanedObj.imageId;
179
- }
180
183
  return cleanedObj;
181
184
  }
182
185
 
@@ -236,9 +239,6 @@ export class ApiClient {
236
239
  restoredObj.properties = { ...restoredObj.properties };
237
240
  delete restoredObj.properties.src;
238
241
  }
239
- if ('imageId' in restoredObj) {
240
- delete restoredObj.imageId;
241
- }
242
242
  return restoredObj;
243
243
  }
244
244
 
@@ -104,9 +104,9 @@ export class SaveManager {
104
104
  });
105
105
  }
106
106
 
107
- // Жесткий контракт для сохранения картинок:
108
- // - каждый image обязан иметь src
107
+ // Контракт сохранения картинок:
109
108
  // - data:/blob: URL в image запрещены
109
+ // - image без src допускаются (legacy broken state), но логируются
110
110
  this._assertImageSaveContract(saveData);
111
111
 
112
112
  // Проверяем, изменились ли данные с последнего сохранения
@@ -240,7 +240,8 @@ export class SaveManager {
240
240
  const effectiveSrc = topSrc.trim() || propSrc.trim();
241
241
 
242
242
  if (!effectiveSrc) {
243
- throw new Error(`Image object "${obj.id || 'unknown'}" has no src. Save is blocked.`);
243
+ console.warn(`Image object "${obj.id || 'unknown'}" has no src. Saving continues for legacy compatibility.`);
244
+ continue;
244
245
  }
245
246
  if (/^data:/i.test(topSrc) || /^blob:/i.test(topSrc) || /^data:/i.test(propSrc) || /^blob:/i.test(propSrc)) {
246
247
  throw new Error(`Image object "${obj.id || 'unknown'}" contains forbidden data/blob src. Save is blocked.`);
package/src/core/index.js CHANGED
@@ -535,9 +535,6 @@ export class CoreMoodBoard {
535
535
  objectData.properties = { ...objectData.properties };
536
536
  delete objectData.properties.src;
537
537
  }
538
- if ('imageId' in objectData) {
539
- delete objectData.imageId;
540
- }
541
538
  }
542
539
  if (objectData.type === 'mindmap') {
543
540
  logMindmapCompoundDebug('core:load-object', {
@@ -11,6 +11,8 @@ export class ActionHandler {
11
11
  * Обрабатывает действия тулбара
12
12
  */
13
13
  handleToolbarAction(action) {
14
+ this._assertImageActionContract(action);
15
+
14
16
  switch (action.type) {
15
17
  case 'frame':
16
18
  case 'simple-text':
@@ -112,4 +114,19 @@ export class ActionHandler {
112
114
  exportBoard() {
113
115
  return this.handleExportBoard();
114
116
  }
117
+
118
+ _assertImageActionContract(action) {
119
+ if (!action || (action.type !== 'image' && action.type !== 'revit-screenshot-img')) return;
120
+ const src = typeof action?.properties?.src === 'string' ? action.properties.src.trim() : '';
121
+ if (src) return;
122
+
123
+ const reason = 'в цепочке создания отсутствует обязательное поле properties.src';
124
+ const message = `Загрузить картинку не получилось: ${reason}. Попробуйте еще раз.`;
125
+ if (this.workspaceManager?.showNotification) {
126
+ this.workspaceManager.showNotification(message);
127
+ } else if (typeof alert === 'function') {
128
+ alert(message);
129
+ }
130
+ throw new Error(`Image action contract violated: ${reason}`);
131
+ }
115
132
  }