pptx-viewer-mcp 1.1.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.
package/README.md ADDED
@@ -0,0 +1,146 @@
1
+ # pptx-viewer-mcp
2
+
3
+ Pure tool functions, Zod schemas, a Y.Doc collaboration codec, and an MCP server for PPTX manipulation — all built on top of `pptx-viewer-core`.
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ npm install pptx-viewer-mcp pptx-viewer-core
9
+ # optional — required only for the collaboration codec
10
+ npm install yjs
11
+ ```
12
+
13
+ ## Exports
14
+
15
+ | Entry point | Contents |
16
+ | ---------------------------- | ------------------------------------------------------- |
17
+ | `pptx-viewer-mcp` | 24 tool functions + provider types + execution pipeline |
18
+ | `pptx-viewer-mcp/schemas` | Zod schemas for every tool input |
19
+ | `pptx-viewer-mcp/codec` | `PptxCodec` — Y.Doc ↔ PPTX bytes codec |
20
+ | `pptx-viewer-mcp/mcp` | `createServer()` — programmatic MCP server factory |
21
+
22
+ ## Tool reference
23
+
24
+ **Slide (8):** `getSlide`, `addSlide`, `deleteSlides`, `reorderSlides`, `duplicateSlide`, `updateSlideProperties`, `setSlideTransition`, `setCanvasSize`
25
+
26
+ **Element (9):** `addElement`, `updateElement`, `deleteElements`, `arrangeElements`, `cloneElement`, `setElementAnimation`, `groupElements`, `ungroupElements`, `batchUpdateElements`
27
+
28
+ **Table (2):** `updateTableCells`, `manageTableStructure`
29
+
30
+ **Style (2):** `updateElementStyle`, `runAccessibilityCheck`
31
+
32
+ **Content (3):** `findText`, `replaceText`, `manageComments`
33
+
34
+ **Conversion (1):** `convertToMarkdown`
35
+
36
+ ---
37
+
38
+ ## Quick start
39
+
40
+ ### 1. Using tool functions directly
41
+
42
+ Every tool is a pure function — no file I/O, no framework dependencies.
43
+
44
+ ```ts
45
+ import { PptxHandler } from 'pptx-viewer-core';
46
+ import { addSlide, getSlide } from 'pptx-viewer-mcp';
47
+
48
+ // Load
49
+ const handler = new PptxHandler();
50
+ const bytes = await fs.readFile('deck.pptx');
51
+ const pptxData = await handler.load(bytes.buffer);
52
+
53
+ // Run a tool
54
+ const ctx = { pptxData };
55
+ const { pptxData: updated, dirty } = addSlide(ctx, { insertAfterIndex: 0 });
56
+
57
+ // Save when dirty
58
+ if (dirty) {
59
+ const out = await handler.save(updated.slides);
60
+ await fs.writeFile('deck.pptx', out);
61
+ }
62
+
63
+ // Inspect a slide
64
+ const { result } = getSlide(ctx, { slideIndex: 0 });
65
+ console.log(result.elements);
66
+ ```
67
+
68
+ ### 2. Using the MCP server
69
+
70
+ Add to your MCP client configuration (Claude Desktop, Cursor, etc.):
71
+
72
+ ```json
73
+ {
74
+ "mcpServers": {
75
+ "pptx": {
76
+ "command": "npx",
77
+ "args": ["pptx-viewer-mcp"]
78
+ }
79
+ }
80
+ }
81
+ ```
82
+
83
+ The binary is also available as `pptx-tools` after a global install. All 24 tools are exposed over stdio with the same names in snake_case (e.g. `add_slide`, `batch_update_elements`). Every tool accepts a `filePath` parameter — the server handles load/save internally.
84
+
85
+ ### 3. Using `executeToolWithContext` with providers
86
+
87
+ `executeToolWithContext` wraps the load → tool → save cycle and routes through a live Y.Doc collaboration room when one is available.
88
+
89
+ ```ts
90
+ import {
91
+ executeToolWithContext,
92
+ type ExecutionContext,
93
+ type FileSystemProvider,
94
+ type CollaborationProvider,
95
+ } from 'pptx-viewer-mcp';
96
+ import { replaceText } from 'pptx-viewer-mcp';
97
+ import { readFile, writeFile } from 'node:fs/promises';
98
+
99
+ // Minimal file-system-only provider
100
+ const filesystem: FileSystemProvider = {
101
+ readFile: (p) => readFile(p),
102
+ writeFile: (p, data) => writeFile(p, data),
103
+ };
104
+
105
+ const execCtx: ExecutionContext = { filesystem };
106
+
107
+ const result = await executeToolWithContext('deck.pptx', execCtx, (ctx) =>
108
+ replaceText(ctx, { find: 'Draft', replace: 'Final', caseSensitive: false }),
109
+ );
110
+
111
+ console.log(result.replacements, result.savedToDisk);
112
+ ```
113
+
114
+ When `execCtx.collaboration` is provided, `executeToolWithContext` automatically dehydrates the current Y.Doc state before running the tool and re-hydrates the room after saving, so remote peers receive the change without a file reload.
115
+
116
+ ---
117
+
118
+ ## Architecture
119
+
120
+ ```
121
+ ToolContext { pptxData }
122
+ │
123
+ ▼
124
+ tool function → ToolResult { pptxData, result, dirty }
125
+ │
126
+ ▼ (when dirty)
127
+ savePresentation()
128
+ ├─ collaboration room → hydrate Y.Doc → broadcast
129
+ └─ no room → writeFile to disk
130
+ ```
131
+
132
+ `CollaborationProvider`, `FileSystemProvider`, and `ViewerProvider` are plain interfaces — implement them for any runtime (Node, Electron, browser, edge worker).
133
+
134
+ ---
135
+
136
+ ## Development
137
+
138
+ ```sh
139
+ bun run build # tsup → dist/
140
+ bun run typecheck # tsc --noEmit
141
+ bun run test # vitest run
142
+ ```
143
+
144
+ ## License
145
+
146
+ MIT
@@ -0,0 +1,26 @@
1
+ import { Doc } from 'yjs';
2
+
3
+ declare const ORIGIN_FILE_LOAD = "file-load";
4
+ /**
5
+ * Bidirectional format codec: file bytes <-> Y.Doc shared types.
6
+ */
7
+ interface FormatCodec {
8
+ readonly formatId: string;
9
+ readonly extensions: string[];
10
+ hydrate(ydoc: Doc, bytes: Uint8Array, origin?: string): Promise<void>;
11
+ dehydrate(ydoc: Doc, dirtyPaths?: string[]): Promise<Uint8Array>;
12
+ observe(ydoc: Doc, onChange: () => void): () => void;
13
+ }
14
+ declare class PptxCodec implements FormatCodec {
15
+ readonly formatId = "pptx";
16
+ readonly extensions: string[];
17
+ hydrate(ydoc: Doc, bytes: Uint8Array, origin?: string): Promise<void>;
18
+ dehydrate(ydoc: Doc, _dirtyPaths?: string[]): Promise<Uint8Array>;
19
+ observe(ydoc: Doc, onChange: () => void): () => void;
20
+ private _slideToYMap;
21
+ private _yMapToSlide;
22
+ private _elementToYMap;
23
+ private _yMapToElement;
24
+ }
25
+
26
+ export { type FormatCodec, ORIGIN_FILE_LOAD, PptxCodec };
@@ -0,0 +1,26 @@
1
+ import { Doc } from 'yjs';
2
+
3
+ declare const ORIGIN_FILE_LOAD = "file-load";
4
+ /**
5
+ * Bidirectional format codec: file bytes <-> Y.Doc shared types.
6
+ */
7
+ interface FormatCodec {
8
+ readonly formatId: string;
9
+ readonly extensions: string[];
10
+ hydrate(ydoc: Doc, bytes: Uint8Array, origin?: string): Promise<void>;
11
+ dehydrate(ydoc: Doc, dirtyPaths?: string[]): Promise<Uint8Array>;
12
+ observe(ydoc: Doc, onChange: () => void): () => void;
13
+ }
14
+ declare class PptxCodec implements FormatCodec {
15
+ readonly formatId = "pptx";
16
+ readonly extensions: string[];
17
+ hydrate(ydoc: Doc, bytes: Uint8Array, origin?: string): Promise<void>;
18
+ dehydrate(ydoc: Doc, _dirtyPaths?: string[]): Promise<Uint8Array>;
19
+ observe(ydoc: Doc, onChange: () => void): () => void;
20
+ private _slideToYMap;
21
+ private _yMapToSlide;
22
+ private _elementToYMap;
23
+ private _yMapToElement;
24
+ }
25
+
26
+ export { type FormatCodec, ORIGIN_FILE_LOAD, PptxCodec };
@@ -0,0 +1,241 @@
1
+ 'use strict';
2
+
3
+ var pptxViewerCore = require('pptx-viewer-core');
4
+ var yjs = require('yjs');
5
+
6
+ // src/codec/pptx-codec.ts
7
+ var ORIGIN_FILE_LOAD = "file-load";
8
+ var SCALAR_ELEMENT_KEYS = /* @__PURE__ */ new Set([
9
+ "id",
10
+ "type",
11
+ "x",
12
+ "y",
13
+ "width",
14
+ "height",
15
+ "rotation",
16
+ "flipHorizontal",
17
+ "flipVertical",
18
+ "hidden",
19
+ "opacity",
20
+ "text",
21
+ "name",
22
+ "altText",
23
+ "shapeType",
24
+ "placeholder",
25
+ "imagePath",
26
+ "imageData",
27
+ "svgContent",
28
+ "inkSvg",
29
+ "sourceSlideId",
30
+ "mediaType",
31
+ "mediaPath",
32
+ "linkedTxbxId",
33
+ "linkedTxbxSeq",
34
+ "promptText"
35
+ ]);
36
+ var COMPLEX_FIELD_MAP = {
37
+ textSegments: "_textSegments",
38
+ textStyle: "_textStyle",
39
+ shapeStyle: "_shapeStyle",
40
+ shapeAdjustments: "_shapeAdjustments",
41
+ adjustmentHandles: "_adjustmentHandles",
42
+ tableData: "_tableData",
43
+ chartData: "_chartData",
44
+ smartArtData: "_smartArtData",
45
+ connectionStart: "_connectionStart",
46
+ connectionEnd: "_connectionEnd",
47
+ animations: "_animations",
48
+ nativeAnimations: "_nativeAnimations",
49
+ children: "_children",
50
+ paragraphIndents: "_paragraphIndents",
51
+ rawXml: "_rawXml",
52
+ actionClick: "_actionClick",
53
+ actionHover: "_actionHover",
54
+ locks: "_locks",
55
+ imageEffects: "_imageEffects",
56
+ cropShape: "_cropShape",
57
+ mediaBookmarks: "_mediaBookmarks",
58
+ captionTracks: "_captionTracks"
59
+ };
60
+ var REVERSE_COMPLEX_MAP = {};
61
+ for (const [original, prefixed] of Object.entries(COMPLEX_FIELD_MAP)) {
62
+ REVERSE_COMPLEX_MAP[prefixed] = original;
63
+ }
64
+ var SCALAR_SLIDE_KEYS = /* @__PURE__ */ new Set([
65
+ "id",
66
+ "rId",
67
+ "sourceSlideId",
68
+ "layoutPath",
69
+ "layoutName",
70
+ "slideNumber",
71
+ "hidden",
72
+ "sectionName",
73
+ "sectionId",
74
+ "backgroundColor",
75
+ "backgroundImage",
76
+ "backgroundGradient",
77
+ "notes",
78
+ "backgroundShowAnimation",
79
+ "showMasterShapes",
80
+ "isDirty"
81
+ ]);
82
+ var COMPLEX_SLIDE_FIELD_MAP = {
83
+ transition: "_transition",
84
+ animations: "_animations",
85
+ nativeAnimations: "_nativeAnimations",
86
+ rawTiming: "_rawTiming",
87
+ notesSegments: "_notesSegments",
88
+ comments: "_comments",
89
+ warnings: "_warnings",
90
+ rawXml: "_rawXml",
91
+ clrMapOverride: "_clrMapOverride",
92
+ guides: "_guides",
93
+ customerData: "_customerData",
94
+ activeXControls: "_activeXControls"
95
+ };
96
+ var REVERSE_COMPLEX_SLIDE_MAP = {};
97
+ for (const [original, prefixed] of Object.entries(COMPLEX_SLIDE_FIELD_MAP)) {
98
+ REVERSE_COMPLEX_SLIDE_MAP[prefixed] = original;
99
+ }
100
+ var PptxCodec = class {
101
+ formatId = "pptx";
102
+ extensions = [".pptx", ".ppt"];
103
+ async hydrate(ydoc, bytes, origin) {
104
+ const effectiveOrigin = origin ?? ORIGIN_FILE_LOAD;
105
+ const handler = new pptxViewerCore.PptxHandler();
106
+ const pptxData = await handler.load(bytes.buffer);
107
+ ydoc.transact(() => {
108
+ const meta = ydoc.getMap("pptx:meta");
109
+ meta.set("width", pptxData.width);
110
+ meta.set("height", pptxData.height);
111
+ if (pptxData.widthEmu !== void 0) {
112
+ meta.set("widthEmu", pptxData.widthEmu);
113
+ }
114
+ if (pptxData.heightEmu !== void 0) {
115
+ meta.set("heightEmu", pptxData.heightEmu);
116
+ }
117
+ const sourceBytesArr = new yjs.Array();
118
+ sourceBytesArr.insert(0, Array.from(bytes));
119
+ meta.set("sourceBytes", sourceBytesArr);
120
+ const slidesArray = ydoc.getArray("pptx:slides");
121
+ if (slidesArray.length > 0) {
122
+ slidesArray.delete(0, slidesArray.length);
123
+ }
124
+ for (const slide of pptxData.slides) {
125
+ const slideMap = this._slideToYMap(slide);
126
+ slidesArray.push([slideMap]);
127
+ }
128
+ }, effectiveOrigin);
129
+ }
130
+ async dehydrate(ydoc, _dirtyPaths) {
131
+ const meta = ydoc.getMap("pptx:meta");
132
+ const slidesArray = ydoc.getArray("pptx:slides");
133
+ const slides = [];
134
+ for (let i = 0; i < slidesArray.length; i++) {
135
+ const slideMap = slidesArray.get(i);
136
+ slides.push(this._yMapToSlide(slideMap));
137
+ }
138
+ const sourceBytesArr = meta.get("sourceBytes");
139
+ try {
140
+ if (!sourceBytesArr || sourceBytesArr.length === 0) {
141
+ throw new Error("No source bytes for PptxHandler");
142
+ }
143
+ const sourceBytes = new Uint8Array(sourceBytesArr.toArray());
144
+ const handler = new pptxViewerCore.PptxHandler();
145
+ await handler.load(sourceBytes.buffer);
146
+ return await handler.save(slides);
147
+ } catch {
148
+ if (sourceBytesArr && sourceBytesArr.length > 0) {
149
+ return new Uint8Array(sourceBytesArr.toArray());
150
+ }
151
+ throw new Error("No PPTX bytes available for dehydration");
152
+ }
153
+ }
154
+ observe(ydoc, onChange) {
155
+ const slidesArray = ydoc.getArray("pptx:slides");
156
+ const meta = ydoc.getMap("pptx:meta");
157
+ const handler = () => onChange();
158
+ slidesArray.observeDeep(handler);
159
+ meta.observeDeep(handler);
160
+ return () => {
161
+ slidesArray.unobserveDeep(handler);
162
+ meta.unobserveDeep(handler);
163
+ };
164
+ }
165
+ _slideToYMap(slide) {
166
+ const slideMap = new yjs.Map();
167
+ const slideRecord = slide;
168
+ for (const key of SCALAR_SLIDE_KEYS) {
169
+ const value = slideRecord[key];
170
+ if (value !== void 0) {
171
+ slideMap.set(key, value);
172
+ }
173
+ }
174
+ for (const [original, prefixed] of Object.entries(COMPLEX_SLIDE_FIELD_MAP)) {
175
+ const value = slideRecord[original];
176
+ if (value !== void 0) {
177
+ slideMap.set(prefixed, JSON.stringify(value));
178
+ }
179
+ }
180
+ const elementsArray = new yjs.Array();
181
+ for (const element of slide.elements) {
182
+ elementsArray.push([this._elementToYMap(element)]);
183
+ }
184
+ slideMap.set("elements", elementsArray);
185
+ return slideMap;
186
+ }
187
+ _yMapToSlide(slideMap) {
188
+ const slide = {};
189
+ for (const key of SCALAR_SLIDE_KEYS) {
190
+ const value = slideMap.get(key);
191
+ if (value !== void 0) {
192
+ slide[key] = value;
193
+ }
194
+ }
195
+ for (const [prefixed, original] of Object.entries(REVERSE_COMPLEX_SLIDE_MAP)) {
196
+ const value = slideMap.get(prefixed);
197
+ if (value !== void 0) {
198
+ slide[original] = JSON.parse(value);
199
+ }
200
+ }
201
+ const elementsArray = slideMap.get("elements");
202
+ const elements = [];
203
+ if (elementsArray) {
204
+ for (let i = 0; i < elementsArray.length; i++) {
205
+ const elemMap = elementsArray.get(i);
206
+ elements.push(this._yMapToElement(elemMap));
207
+ }
208
+ }
209
+ slide["elements"] = elements;
210
+ return slide;
211
+ }
212
+ _elementToYMap(element) {
213
+ const elemMap = new yjs.Map();
214
+ const record = element;
215
+ for (const [key, value] of Object.entries(record)) {
216
+ if (value === void 0) {
217
+ continue;
218
+ }
219
+ if (SCALAR_ELEMENT_KEYS.has(key)) {
220
+ elemMap.set(key, value);
221
+ } else if (COMPLEX_FIELD_MAP[key]) {
222
+ elemMap.set(COMPLEX_FIELD_MAP[key], JSON.stringify(value));
223
+ }
224
+ }
225
+ return elemMap;
226
+ }
227
+ _yMapToElement(elemMap) {
228
+ const element = {};
229
+ elemMap.forEach((value, key) => {
230
+ if (REVERSE_COMPLEX_MAP[key]) {
231
+ element[REVERSE_COMPLEX_MAP[key]] = JSON.parse(value);
232
+ } else {
233
+ element[key] = value;
234
+ }
235
+ });
236
+ return element;
237
+ }
238
+ };
239
+
240
+ exports.ORIGIN_FILE_LOAD = ORIGIN_FILE_LOAD;
241
+ exports.PptxCodec = PptxCodec;
@@ -0,0 +1,238 @@
1
+ import { PptxHandler } from 'pptx-viewer-core';
2
+ import { Array as Array$1, Map } from 'yjs';
3
+
4
+ // src/codec/pptx-codec.ts
5
+ var ORIGIN_FILE_LOAD = "file-load";
6
+ var SCALAR_ELEMENT_KEYS = /* @__PURE__ */ new Set([
7
+ "id",
8
+ "type",
9
+ "x",
10
+ "y",
11
+ "width",
12
+ "height",
13
+ "rotation",
14
+ "flipHorizontal",
15
+ "flipVertical",
16
+ "hidden",
17
+ "opacity",
18
+ "text",
19
+ "name",
20
+ "altText",
21
+ "shapeType",
22
+ "placeholder",
23
+ "imagePath",
24
+ "imageData",
25
+ "svgContent",
26
+ "inkSvg",
27
+ "sourceSlideId",
28
+ "mediaType",
29
+ "mediaPath",
30
+ "linkedTxbxId",
31
+ "linkedTxbxSeq",
32
+ "promptText"
33
+ ]);
34
+ var COMPLEX_FIELD_MAP = {
35
+ textSegments: "_textSegments",
36
+ textStyle: "_textStyle",
37
+ shapeStyle: "_shapeStyle",
38
+ shapeAdjustments: "_shapeAdjustments",
39
+ adjustmentHandles: "_adjustmentHandles",
40
+ tableData: "_tableData",
41
+ chartData: "_chartData",
42
+ smartArtData: "_smartArtData",
43
+ connectionStart: "_connectionStart",
44
+ connectionEnd: "_connectionEnd",
45
+ animations: "_animations",
46
+ nativeAnimations: "_nativeAnimations",
47
+ children: "_children",
48
+ paragraphIndents: "_paragraphIndents",
49
+ rawXml: "_rawXml",
50
+ actionClick: "_actionClick",
51
+ actionHover: "_actionHover",
52
+ locks: "_locks",
53
+ imageEffects: "_imageEffects",
54
+ cropShape: "_cropShape",
55
+ mediaBookmarks: "_mediaBookmarks",
56
+ captionTracks: "_captionTracks"
57
+ };
58
+ var REVERSE_COMPLEX_MAP = {};
59
+ for (const [original, prefixed] of Object.entries(COMPLEX_FIELD_MAP)) {
60
+ REVERSE_COMPLEX_MAP[prefixed] = original;
61
+ }
62
+ var SCALAR_SLIDE_KEYS = /* @__PURE__ */ new Set([
63
+ "id",
64
+ "rId",
65
+ "sourceSlideId",
66
+ "layoutPath",
67
+ "layoutName",
68
+ "slideNumber",
69
+ "hidden",
70
+ "sectionName",
71
+ "sectionId",
72
+ "backgroundColor",
73
+ "backgroundImage",
74
+ "backgroundGradient",
75
+ "notes",
76
+ "backgroundShowAnimation",
77
+ "showMasterShapes",
78
+ "isDirty"
79
+ ]);
80
+ var COMPLEX_SLIDE_FIELD_MAP = {
81
+ transition: "_transition",
82
+ animations: "_animations",
83
+ nativeAnimations: "_nativeAnimations",
84
+ rawTiming: "_rawTiming",
85
+ notesSegments: "_notesSegments",
86
+ comments: "_comments",
87
+ warnings: "_warnings",
88
+ rawXml: "_rawXml",
89
+ clrMapOverride: "_clrMapOverride",
90
+ guides: "_guides",
91
+ customerData: "_customerData",
92
+ activeXControls: "_activeXControls"
93
+ };
94
+ var REVERSE_COMPLEX_SLIDE_MAP = {};
95
+ for (const [original, prefixed] of Object.entries(COMPLEX_SLIDE_FIELD_MAP)) {
96
+ REVERSE_COMPLEX_SLIDE_MAP[prefixed] = original;
97
+ }
98
+ var PptxCodec = class {
99
+ formatId = "pptx";
100
+ extensions = [".pptx", ".ppt"];
101
+ async hydrate(ydoc, bytes, origin) {
102
+ const effectiveOrigin = origin ?? ORIGIN_FILE_LOAD;
103
+ const handler = new PptxHandler();
104
+ const pptxData = await handler.load(bytes.buffer);
105
+ ydoc.transact(() => {
106
+ const meta = ydoc.getMap("pptx:meta");
107
+ meta.set("width", pptxData.width);
108
+ meta.set("height", pptxData.height);
109
+ if (pptxData.widthEmu !== void 0) {
110
+ meta.set("widthEmu", pptxData.widthEmu);
111
+ }
112
+ if (pptxData.heightEmu !== void 0) {
113
+ meta.set("heightEmu", pptxData.heightEmu);
114
+ }
115
+ const sourceBytesArr = new Array$1();
116
+ sourceBytesArr.insert(0, Array.from(bytes));
117
+ meta.set("sourceBytes", sourceBytesArr);
118
+ const slidesArray = ydoc.getArray("pptx:slides");
119
+ if (slidesArray.length > 0) {
120
+ slidesArray.delete(0, slidesArray.length);
121
+ }
122
+ for (const slide of pptxData.slides) {
123
+ const slideMap = this._slideToYMap(slide);
124
+ slidesArray.push([slideMap]);
125
+ }
126
+ }, effectiveOrigin);
127
+ }
128
+ async dehydrate(ydoc, _dirtyPaths) {
129
+ const meta = ydoc.getMap("pptx:meta");
130
+ const slidesArray = ydoc.getArray("pptx:slides");
131
+ const slides = [];
132
+ for (let i = 0; i < slidesArray.length; i++) {
133
+ const slideMap = slidesArray.get(i);
134
+ slides.push(this._yMapToSlide(slideMap));
135
+ }
136
+ const sourceBytesArr = meta.get("sourceBytes");
137
+ try {
138
+ if (!sourceBytesArr || sourceBytesArr.length === 0) {
139
+ throw new Error("No source bytes for PptxHandler");
140
+ }
141
+ const sourceBytes = new Uint8Array(sourceBytesArr.toArray());
142
+ const handler = new PptxHandler();
143
+ await handler.load(sourceBytes.buffer);
144
+ return await handler.save(slides);
145
+ } catch {
146
+ if (sourceBytesArr && sourceBytesArr.length > 0) {
147
+ return new Uint8Array(sourceBytesArr.toArray());
148
+ }
149
+ throw new Error("No PPTX bytes available for dehydration");
150
+ }
151
+ }
152
+ observe(ydoc, onChange) {
153
+ const slidesArray = ydoc.getArray("pptx:slides");
154
+ const meta = ydoc.getMap("pptx:meta");
155
+ const handler = () => onChange();
156
+ slidesArray.observeDeep(handler);
157
+ meta.observeDeep(handler);
158
+ return () => {
159
+ slidesArray.unobserveDeep(handler);
160
+ meta.unobserveDeep(handler);
161
+ };
162
+ }
163
+ _slideToYMap(slide) {
164
+ const slideMap = new Map();
165
+ const slideRecord = slide;
166
+ for (const key of SCALAR_SLIDE_KEYS) {
167
+ const value = slideRecord[key];
168
+ if (value !== void 0) {
169
+ slideMap.set(key, value);
170
+ }
171
+ }
172
+ for (const [original, prefixed] of Object.entries(COMPLEX_SLIDE_FIELD_MAP)) {
173
+ const value = slideRecord[original];
174
+ if (value !== void 0) {
175
+ slideMap.set(prefixed, JSON.stringify(value));
176
+ }
177
+ }
178
+ const elementsArray = new Array$1();
179
+ for (const element of slide.elements) {
180
+ elementsArray.push([this._elementToYMap(element)]);
181
+ }
182
+ slideMap.set("elements", elementsArray);
183
+ return slideMap;
184
+ }
185
+ _yMapToSlide(slideMap) {
186
+ const slide = {};
187
+ for (const key of SCALAR_SLIDE_KEYS) {
188
+ const value = slideMap.get(key);
189
+ if (value !== void 0) {
190
+ slide[key] = value;
191
+ }
192
+ }
193
+ for (const [prefixed, original] of Object.entries(REVERSE_COMPLEX_SLIDE_MAP)) {
194
+ const value = slideMap.get(prefixed);
195
+ if (value !== void 0) {
196
+ slide[original] = JSON.parse(value);
197
+ }
198
+ }
199
+ const elementsArray = slideMap.get("elements");
200
+ const elements = [];
201
+ if (elementsArray) {
202
+ for (let i = 0; i < elementsArray.length; i++) {
203
+ const elemMap = elementsArray.get(i);
204
+ elements.push(this._yMapToElement(elemMap));
205
+ }
206
+ }
207
+ slide["elements"] = elements;
208
+ return slide;
209
+ }
210
+ _elementToYMap(element) {
211
+ const elemMap = new Map();
212
+ const record = element;
213
+ for (const [key, value] of Object.entries(record)) {
214
+ if (value === void 0) {
215
+ continue;
216
+ }
217
+ if (SCALAR_ELEMENT_KEYS.has(key)) {
218
+ elemMap.set(key, value);
219
+ } else if (COMPLEX_FIELD_MAP[key]) {
220
+ elemMap.set(COMPLEX_FIELD_MAP[key], JSON.stringify(value));
221
+ }
222
+ }
223
+ return elemMap;
224
+ }
225
+ _yMapToElement(elemMap) {
226
+ const element = {};
227
+ elemMap.forEach((value, key) => {
228
+ if (REVERSE_COMPLEX_MAP[key]) {
229
+ element[REVERSE_COMPLEX_MAP[key]] = JSON.parse(value);
230
+ } else {
231
+ element[key] = value;
232
+ }
233
+ });
234
+ return element;
235
+ }
236
+ };
237
+
238
+ export { ORIGIN_FILE_LOAD, PptxCodec };