indesign-cli 0.2.0__py3-none-any.whl

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 (72) hide show
  1. cli_anything/indesign/README.md +32 -0
  2. cli_anything/indesign/__init__.py +1 -0
  3. cli_anything/indesign/__main__.py +5 -0
  4. cli_anything/indesign/core/artifacts.py +57 -0
  5. cli_anything/indesign/core/catalog.py +405 -0
  6. cli_anything/indesign/core/domains.py +178 -0
  7. cli_anything/indesign/core/envelope.py +65 -0
  8. cli_anything/indesign/core/errors.py +30 -0
  9. cli_anything/indesign/core/health.py +46 -0
  10. cli_anything/indesign/core/hidden_backend.py +116 -0
  11. cli_anything/indesign/core/hidden_handler_schemas.py +223 -0
  12. cli_anything/indesign/core/mcp_backend.py +152 -0
  13. cli_anything/indesign/core/node_setup.py +35 -0
  14. cli_anything/indesign/core/paths.py +41 -0
  15. cli_anything/indesign/core/plugins/__init__.py +2 -0
  16. cli_anything/indesign/core/plugins/backend.py +90 -0
  17. cli_anything/indesign/core/plugins/discovery.py +69 -0
  18. cli_anything/indesign/core/plugins/host_actions.py +76 -0
  19. cli_anything/indesign/core/plugins/install.py +38 -0
  20. cli_anything/indesign/core/plugins/manifest.py +279 -0
  21. cli_anything/indesign/core/plugins/validate.py +181 -0
  22. cli_anything/indesign/core/router.py +217 -0
  23. cli_anything/indesign/core/runtime.py +59 -0
  24. cli_anything/indesign/core/scripts.py +44 -0
  25. cli_anything/indesign/core/session.py +68 -0
  26. cli_anything/indesign/indesign_cli.py +320 -0
  27. cli_anything/indesign/node/hidden_handler_bridge.mjs +111 -0
  28. cli_anything/indesign/server/package-lock.json +168 -0
  29. cli_anything/indesign/server/package.json +45 -0
  30. cli_anything/indesign/server/src/advanced/index.js +76 -0
  31. cli_anything/indesign/server/src/core/InDesignMCPServer.js +273 -0
  32. cli_anything/indesign/server/src/core/scriptExecutor.js +271 -0
  33. cli_anything/indesign/server/src/core/sessionManager.js +545 -0
  34. cli_anything/indesign/server/src/handlers/advancedTemplateHandlers.js +1072 -0
  35. cli_anything/indesign/server/src/handlers/bookHandlers.js +490 -0
  36. cli_anything/indesign/server/src/handlers/documentHandlers.js +1472 -0
  37. cli_anything/indesign/server/src/handlers/exportHandlers.js +208 -0
  38. cli_anything/indesign/server/src/handlers/graphicsHandlers.js +605 -0
  39. cli_anything/indesign/server/src/handlers/groupHandlers.js +358 -0
  40. cli_anything/indesign/server/src/handlers/helpHandlers.js +347 -0
  41. cli_anything/indesign/server/src/handlers/index.js +77 -0
  42. cli_anything/indesign/server/src/handlers/layerHandlers.js +75 -0
  43. cli_anything/indesign/server/src/handlers/masterSpreadHandlers.js +451 -0
  44. cli_anything/indesign/server/src/handlers/pageHandlers.js +698 -0
  45. cli_anything/indesign/server/src/handlers/pageItemHandlers.js +704 -0
  46. cli_anything/indesign/server/src/handlers/presentationHandlers.js +220 -0
  47. cli_anything/indesign/server/src/handlers/spreadHandlers.js +348 -0
  48. cli_anything/indesign/server/src/handlers/styleHandlers.js +458 -0
  49. cli_anything/indesign/server/src/handlers/textHandlers.js +431 -0
  50. cli_anything/indesign/server/src/handlers/utilityHandlers.js +83 -0
  51. cli_anything/indesign/server/src/index.js +17 -0
  52. cli_anything/indesign/server/src/types/index.js +106 -0
  53. cli_anything/indesign/server/src/types/toolDefinitionsAdvancedTemplates.js +144 -0
  54. cli_anything/indesign/server/src/types/toolDefinitionsBook.js +224 -0
  55. cli_anything/indesign/server/src/types/toolDefinitionsContent.js +353 -0
  56. cli_anything/indesign/server/src/types/toolDefinitionsDocument.js +409 -0
  57. cli_anything/indesign/server/src/types/toolDefinitionsExport.js +65 -0
  58. cli_anything/indesign/server/src/types/toolDefinitionsLayer.js +40 -0
  59. cli_anything/indesign/server/src/types/toolDefinitionsMasterSpread.js +160 -0
  60. cli_anything/indesign/server/src/types/toolDefinitionsPage.js +271 -0
  61. cli_anything/indesign/server/src/types/toolDefinitionsPageItemGroup.js +437 -0
  62. cli_anything/indesign/server/src/types/toolDefinitionsPresentation.js +83 -0
  63. cli_anything/indesign/server/src/types/toolDefinitionsSpread.js +158 -0
  64. cli_anything/indesign/server/src/types/toolDefinitionsUtility.js +40 -0
  65. cli_anything/indesign/server/src/utils/stringUtils.js +107 -0
  66. cli_anything/indesign/skills/SKILL.md +198 -0
  67. indesign_cli-0.2.0.dist-info/METADATA +267 -0
  68. indesign_cli-0.2.0.dist-info/RECORD +72 -0
  69. indesign_cli-0.2.0.dist-info/WHEEL +5 -0
  70. indesign_cli-0.2.0.dist-info/entry_points.txt +3 -0
  71. indesign_cli-0.2.0.dist-info/licenses/LICENSE +21 -0
  72. indesign_cli-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,545 @@
1
+ /**
2
+ * Enhanced Session management for InDesign MCP Server
3
+ * Stores page dimensions and other session-specific data with improved validation and error handling
4
+ */
5
+ if (typeof globalThis.CustomEvent !== 'function') {
6
+ const BaseEvent = typeof globalThis.Event === 'function' ? globalThis.Event : null;
7
+ if (BaseEvent) {
8
+ class NodeCustomEvent extends BaseEvent {
9
+ constructor(type, params = {}) {
10
+ super(type, params);
11
+ this.detail = params?.detail ?? null;
12
+ }
13
+ }
14
+ globalThis.CustomEvent = NodeCustomEvent;
15
+ } else {
16
+ class MinimalCustomEvent {
17
+ constructor(type, params = {}) {
18
+ this.type = type;
19
+ this.detail = params?.detail ?? null;
20
+ this.bubbles = Boolean(params?.bubbles);
21
+ this.cancelable = Boolean(params?.cancelable);
22
+ }
23
+ }
24
+ globalThis.CustomEvent = MinimalCustomEvent;
25
+ }
26
+ }
27
+
28
+ export class SessionManager extends EventTarget {
29
+ constructor(config = {}) {
30
+ super();
31
+
32
+ this.config = {
33
+ defaultMargin: config.defaultMargin || 20,
34
+ minMargin: config.minMargin || 5,
35
+ minDimension: config.minDimension || 10,
36
+ maxDimension: config.maxDimension || 10000,
37
+ precision: config.precision || 2,
38
+ ...config
39
+ };
40
+
41
+ this.sessionData = {
42
+ pageDimensions: null,
43
+ activeDocument: null,
44
+ activePage: null,
45
+ lastCreatedItem: null,
46
+ createdAt: new Date().toISOString(),
47
+ lastModified: null
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Set page dimensions for the current session
53
+ * @param {Object} dimensions - Page dimensions object
54
+ * @param {number} dimensions.width - Page width in mm
55
+ * @param {number} dimensions.height - Page height in mm
56
+ */
57
+ setPageDimensions(dimensions) {
58
+ this._validateDimensions(dimensions);
59
+
60
+ const old = this.sessionData.pageDimensions;
61
+ this.sessionData.pageDimensions = { ...dimensions };
62
+ this._updateLastModified();
63
+
64
+ this.dispatchEvent(new CustomEvent('dimensionsChanged', {
65
+ detail: { old, new: dimensions }
66
+ }));
67
+ }
68
+
69
+ /**
70
+ * Get page dimensions for the current session (returns copy to prevent mutations)
71
+ */
72
+ getPageDimensions() {
73
+ return this.sessionData.pageDimensions ? { ...this.sessionData.pageDimensions } : null;
74
+ }
75
+
76
+ /**
77
+ * Set active document info
78
+ */
79
+ setActiveDocument(documentInfo) {
80
+ this._validateDocumentInfo(documentInfo);
81
+
82
+ const old = this.sessionData.activeDocument;
83
+ this.sessionData.activeDocument = documentInfo ? { ...documentInfo } : null;
84
+ this._updateLastModified();
85
+
86
+ this.dispatchEvent(new CustomEvent('documentChanged', {
87
+ detail: { old, new: documentInfo }
88
+ }));
89
+ }
90
+
91
+ /**
92
+ * Get active document info (returns copy)
93
+ */
94
+ getActiveDocument() {
95
+ return this.sessionData.activeDocument ? { ...this.sessionData.activeDocument } : null;
96
+ }
97
+
98
+ /**
99
+ * Set active page info
100
+ */
101
+ setActivePage(pageInfo) {
102
+ this._validatePageInfo(pageInfo);
103
+
104
+ const old = this.sessionData.activePage;
105
+ this.sessionData.activePage = pageInfo ? { ...pageInfo } : null;
106
+ this._updateLastModified();
107
+
108
+ this.dispatchEvent(new CustomEvent('pageChanged', {
109
+ detail: { old, new: pageInfo }
110
+ }));
111
+ }
112
+
113
+ /**
114
+ * Get active page info (returns copy)
115
+ */
116
+ getActivePage() {
117
+ return this.sessionData.activePage ? { ...this.sessionData.activePage } : null;
118
+ }
119
+
120
+ /**
121
+ * Set last created item info
122
+ */
123
+ setLastCreatedItem(itemInfo) {
124
+ this.sessionData.lastCreatedItem = itemInfo ? { ...itemInfo, createdAt: new Date().toISOString() } : null;
125
+ this._updateLastModified();
126
+ }
127
+
128
+ /**
129
+ * Get last created item info (returns copy)
130
+ */
131
+ getLastCreatedItem() {
132
+ return this.sessionData.lastCreatedItem ? { ...this.sessionData.lastCreatedItem } : null;
133
+ }
134
+
135
+ /**
136
+ * Get calculated positioning based on page dimensions with enhanced bounds checking
137
+ */
138
+ getCalculatedPositioning(options = {}) {
139
+ const dimensions = this.getPageDimensions();
140
+ if (!dimensions) {
141
+ return this._getDefaultPositioning(options);
142
+ }
143
+
144
+ const config = this._getPositioningConfig(options);
145
+ const bounds = this._calculateBounds(dimensions, config);
146
+ const position = this._adjustPositionToBounds(options, bounds, config);
147
+
148
+ return this._roundPositioning(position, bounds);
149
+ }
150
+
151
+ /**
152
+ * Enhanced validation with detailed feedback
153
+ */
154
+ validatePositioning(x, y, width, height) {
155
+ // Input validation
156
+ const inputValidation = this._validatePositioningInputs(x, y, width, height);
157
+ if (!inputValidation.valid) return inputValidation;
158
+
159
+ const dimensions = this.getPageDimensions();
160
+ if (!dimensions) {
161
+ return {
162
+ valid: true,
163
+ reason: 'No page dimensions available for validation',
164
+ warning: 'Consider setting page dimensions for better validation'
165
+ };
166
+ }
167
+
168
+ return this._validateAgainstPageBounds(x, y, width, height, dimensions);
169
+ }
170
+
171
+ /**
172
+ * Get available space at given position
173
+ */
174
+ getAvailableSpace(x, y) {
175
+ const bounds = this.getPageBounds();
176
+ if (!bounds) return null;
177
+
178
+ return {
179
+ width: Math.max(0, bounds.pageWidth - x - bounds.minMargin),
180
+ height: Math.max(0, bounds.pageHeight - y - bounds.minMargin),
181
+ maxWidth: bounds.pageWidth - bounds.minMargin * 2,
182
+ maxHeight: bounds.pageHeight - bounds.minMargin * 2
183
+ };
184
+ }
185
+
186
+ /**
187
+ * Find optimal position for given dimensions
188
+ */
189
+ findOptimalPosition(width, height, preferences = {}) {
190
+ const bounds = this.getPageBounds();
191
+ if (!bounds) return null;
192
+
193
+ const { align = 'top-left', margin = this.config.defaultMargin } = preferences;
194
+
195
+ const positions = {
196
+ 'top-left': { x: margin, y: margin },
197
+ 'top-center': { x: (bounds.pageWidth - width) / 2, y: margin },
198
+ 'top-right': { x: bounds.pageWidth - width - margin, y: margin },
199
+ 'center-left': { x: margin, y: (bounds.pageHeight - height) / 2 },
200
+ 'center': { x: (bounds.pageWidth - width) / 2, y: (bounds.pageHeight - height) / 2 },
201
+ 'center-right': { x: bounds.pageWidth - width - margin, y: (bounds.pageHeight - height) / 2 },
202
+ 'bottom-left': { x: margin, y: bounds.pageHeight - height - margin },
203
+ 'bottom-center': { x: (bounds.pageWidth - width) / 2, y: bounds.pageHeight - height - margin },
204
+ 'bottom-right': { x: bounds.pageWidth - width - margin, y: bounds.pageHeight - height - margin }
205
+ };
206
+
207
+ const position = positions[align] || positions['top-left'];
208
+ const validation = this.validatePositioning(position.x, position.y, width, height);
209
+
210
+ return {
211
+ ...position,
212
+ validation,
213
+ align
214
+ };
215
+ }
216
+
217
+ /**
218
+ * Get enhanced page bounds information
219
+ */
220
+ getPageBounds() {
221
+ const dimensions = this.getPageDimensions();
222
+ if (!dimensions) return null;
223
+
224
+ const { width: pageWidth, height: pageHeight } = dimensions;
225
+ const margin = this.config.defaultMargin;
226
+ const minMargin = this.config.minMargin;
227
+
228
+ return {
229
+ pageWidth,
230
+ pageHeight,
231
+ margin,
232
+ minMargin,
233
+ safeArea: {
234
+ x: margin,
235
+ y: margin,
236
+ width: Math.max(0, pageWidth - (margin * 2)),
237
+ height: Math.max(0, pageHeight - (margin * 2))
238
+ },
239
+ absoluteBounds: {
240
+ x: minMargin,
241
+ y: minMargin,
242
+ width: Math.max(0, pageWidth - (minMargin * 2)),
243
+ height: Math.max(0, pageHeight - (minMargin * 2))
244
+ },
245
+ center: {
246
+ x: pageWidth / 2,
247
+ y: pageHeight / 2
248
+ }
249
+ };
250
+ }
251
+
252
+ /**
253
+ * Clear session data with optional preservation
254
+ */
255
+ clearSession(preserve = []) {
256
+ const preserveSet = new Set(preserve);
257
+ const oldData = { ...this.sessionData };
258
+
259
+ this.sessionData = {
260
+ pageDimensions: preserveSet.has('pageDimensions') ? this.sessionData.pageDimensions : null,
261
+ activeDocument: preserveSet.has('activeDocument') ? this.sessionData.activeDocument : null,
262
+ activePage: preserveSet.has('activePage') ? this.sessionData.activePage : null,
263
+ lastCreatedItem: preserveSet.has('lastCreatedItem') ? this.sessionData.lastCreatedItem : null,
264
+ createdAt: new Date().toISOString(),
265
+ lastModified: null
266
+ };
267
+
268
+ this.dispatchEvent(new CustomEvent('sessionCleared', {
269
+ detail: { old: oldData, preserved: preserve }
270
+ }));
271
+ }
272
+
273
+ /**
274
+ * Get comprehensive session summary
275
+ */
276
+ getSessionSummary() {
277
+ const bounds = this.getPageBounds();
278
+
279
+ return {
280
+ hasPageDimensions: !!this.sessionData.pageDimensions,
281
+ hasActiveDocument: !!this.sessionData.activeDocument,
282
+ hasActivePage: !!this.sessionData.activePage,
283
+ hasLastCreatedItem: !!this.sessionData.lastCreatedItem,
284
+ pageDimensions: this.getPageDimensions(),
285
+ activeDocument: this.getActiveDocument(),
286
+ activePage: this.getActivePage(),
287
+ lastCreatedItem: this.getLastCreatedItem(),
288
+ bounds: bounds,
289
+ timestamps: {
290
+ createdAt: this.sessionData.createdAt,
291
+ lastModified: this.sessionData.lastModified
292
+ },
293
+ config: { ...this.config }
294
+ };
295
+ }
296
+
297
+ /**
298
+ * Export session data for persistence
299
+ */
300
+ exportSession() {
301
+ return JSON.stringify({
302
+ sessionData: this.sessionData,
303
+ config: this.config,
304
+ version: '2.0'
305
+ });
306
+ }
307
+
308
+ /**
309
+ * Import session data from persistence
310
+ */
311
+ importSession(sessionString) {
312
+ try {
313
+ const imported = JSON.parse(sessionString);
314
+ if (imported.version && imported.sessionData) {
315
+ this.sessionData = { ...imported.sessionData };
316
+ if (imported.config) {
317
+ this.config = { ...this.config, ...imported.config };
318
+ }
319
+ this.dispatchEvent(new CustomEvent('sessionImported', {
320
+ detail: { version: imported.version }
321
+ }));
322
+ return true;
323
+ }
324
+ } catch (error) {
325
+ console.error('Failed to import session:', error);
326
+ }
327
+ return false;
328
+ }
329
+
330
+ // Private helper methods
331
+ _validateDimensions(dimensions) {
332
+ if (!dimensions || typeof dimensions !== 'object') {
333
+ throw new Error('Dimensions must be an object');
334
+ }
335
+
336
+ const { width, height } = dimensions;
337
+ if (typeof width !== 'number' || typeof height !== 'number') {
338
+ throw new Error('Width and height must be numbers');
339
+ }
340
+
341
+ if (width <= 0 || height <= 0) {
342
+ throw new Error('Width and height must be positive');
343
+ }
344
+
345
+ if (width > this.config.maxDimension || height > this.config.maxDimension) {
346
+ throw new Error(`Dimensions exceed maximum allowed size of ${this.config.maxDimension}mm`);
347
+ }
348
+ }
349
+
350
+ _validateDocumentInfo(documentInfo) {
351
+ if (documentInfo && typeof documentInfo !== 'object') {
352
+ throw new Error('Document info must be an object');
353
+ }
354
+ }
355
+
356
+ _validatePageInfo(pageInfo) {
357
+ if (pageInfo && typeof pageInfo !== 'object') {
358
+ throw new Error('Page info must be an object');
359
+ }
360
+ }
361
+
362
+ _validatePositioningInputs(x, y, width, height) {
363
+ const inputs = { x, y, width, height };
364
+
365
+ for (const [key, value] of Object.entries(inputs)) {
366
+ if (typeof value !== 'number' || isNaN(value)) {
367
+ return {
368
+ valid: false,
369
+ reason: `${key} must be a valid number`,
370
+ input: key
371
+ };
372
+ }
373
+ }
374
+
375
+ if (width <= 0 || height <= 0) {
376
+ return {
377
+ valid: false,
378
+ reason: 'Width and height must be positive',
379
+ suggested: {
380
+ width: Math.max(width, this.config.minDimension),
381
+ height: Math.max(height, this.config.minDimension)
382
+ }
383
+ };
384
+ }
385
+
386
+ return { valid: true };
387
+ }
388
+
389
+ _validateAgainstPageBounds(x, y, width, height, dimensions) {
390
+ const { width: pageWidth, height: pageHeight } = dimensions;
391
+ const minMargin = this.config.minMargin;
392
+
393
+ if (x < minMargin) {
394
+ return {
395
+ valid: false,
396
+ reason: `X position (${x}mm) is too close to left edge`,
397
+ suggested: { x: minMargin },
398
+ bounds: { minX: minMargin }
399
+ };
400
+ }
401
+
402
+ if (y < minMargin) {
403
+ return {
404
+ valid: false,
405
+ reason: `Y position (${y}mm) is too close to top edge`,
406
+ suggested: { y: minMargin },
407
+ bounds: { minY: minMargin }
408
+ };
409
+ }
410
+
411
+ if (x + width > pageWidth - minMargin) {
412
+ return {
413
+ valid: false,
414
+ reason: `Content extends beyond right edge (${x + width}mm > ${pageWidth - minMargin}mm)`,
415
+ suggested: {
416
+ width: Math.max(pageWidth - x - minMargin, this.config.minDimension),
417
+ x: Math.max(pageWidth - width - minMargin, minMargin)
418
+ },
419
+ bounds: { maxX: pageWidth - minMargin }
420
+ };
421
+ }
422
+
423
+ if (y + height > pageHeight - minMargin) {
424
+ return {
425
+ valid: false,
426
+ reason: `Content extends beyond bottom edge (${y + height}mm > ${pageHeight - minMargin}mm)`,
427
+ suggested: {
428
+ height: Math.max(pageHeight - y - minMargin, this.config.minDimension),
429
+ y: Math.max(pageHeight - height - minMargin, minMargin)
430
+ },
431
+ bounds: { maxY: pageHeight - minMargin }
432
+ };
433
+ }
434
+
435
+ return {
436
+ valid: true,
437
+ reason: 'Positioning is within page bounds'
438
+ };
439
+ }
440
+
441
+ _getDefaultPositioning(options) {
442
+ return {
443
+ x: options.x || 10,
444
+ y: options.y || 10,
445
+ width: options.width || 100,
446
+ height: options.height || 50,
447
+ note: 'No page dimensions available - using default positioning'
448
+ };
449
+ }
450
+
451
+ _getPositioningConfig(options) {
452
+ return {
453
+ margin: options.margin ?? this.config.defaultMargin,
454
+ minMargin: this.config.minMargin,
455
+ minDimension: this.config.minDimension
456
+ };
457
+ }
458
+
459
+ _calculateBounds(dimensions, config) {
460
+ const { width: pageWidth, height: pageHeight } = dimensions;
461
+
462
+ return {
463
+ pageWidth,
464
+ pageHeight,
465
+ safeWidth: pageWidth - (config.margin * 2),
466
+ safeHeight: pageHeight - (config.margin * 2),
467
+ margin: config.margin,
468
+ minMargin: config.minMargin
469
+ };
470
+ }
471
+
472
+ _adjustPositionToBounds(options, bounds, config) {
473
+ let x = options.x !== undefined ? options.x : bounds.margin;
474
+ let y = options.y !== undefined ? options.y : bounds.margin;
475
+ let width = options.width !== undefined ? options.width : Math.min(bounds.safeWidth, 100);
476
+ let height = options.height !== undefined ? options.height : Math.min(bounds.safeHeight, 50);
477
+
478
+ // Ensure content stays within page bounds
479
+ if (x + width > bounds.pageWidth - config.minMargin) {
480
+ if (options.x !== undefined) {
481
+ width = Math.max(bounds.pageWidth - x - config.minMargin, config.minDimension);
482
+ } else {
483
+ x = Math.max(bounds.pageWidth - width - config.minMargin, bounds.margin);
484
+ }
485
+ }
486
+
487
+ if (y + height > bounds.pageHeight - config.minMargin) {
488
+ if (options.y !== undefined) {
489
+ height = Math.max(bounds.pageHeight - y - config.minMargin, config.minDimension);
490
+ } else {
491
+ y = Math.max(bounds.pageHeight - height - config.minMargin, bounds.margin);
492
+ }
493
+ }
494
+
495
+ // Ensure minimum dimensions and positions
496
+ width = Math.max(width, config.minDimension);
497
+ height = Math.max(height, config.minDimension);
498
+ x = Math.max(x, config.minMargin);
499
+ y = Math.max(y, config.minMargin);
500
+
501
+ return { x, y, width, height };
502
+ }
503
+
504
+ _roundPositioning(position, bounds = null) {
505
+ const precision = this.config.precision;
506
+ const factor = Math.pow(10, precision);
507
+
508
+ const result = {
509
+ x: Math.round(position.x * factor) / factor,
510
+ y: Math.round(position.y * factor) / factor,
511
+ width: Math.round(position.width * factor) / factor,
512
+ height: Math.round(position.height * factor) / factor
513
+ };
514
+
515
+ if (bounds) {
516
+ result.pageWidth = bounds.pageWidth;
517
+ result.pageHeight = bounds.pageHeight;
518
+ result.safeArea = {
519
+ width: bounds.safeWidth,
520
+ height: bounds.safeHeight,
521
+ margin: bounds.margin
522
+ };
523
+ }
524
+
525
+ return result;
526
+ }
527
+
528
+ _updateLastModified() {
529
+ this.sessionData.lastModified = new Date().toISOString();
530
+ }
531
+
532
+ // Alias for compatibility
533
+ getSessionInfo() {
534
+ return this.getSessionSummary();
535
+ }
536
+ }
537
+
538
+ // Create a singleton instance with default configuration
539
+ export const sessionManager = new SessionManager({
540
+ defaultMargin: 20,
541
+ minMargin: 5,
542
+ minDimension: 10,
543
+ maxDimension: 10000,
544
+ precision: 2
545
+ });