@poe-platform/safe-bash 0.1.816 → 0.1.817

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 (48) hide show
  1. package/dist/pdf-ast/content/evaluator.d.ts +4 -0
  2. package/dist/pdf-ast/cos/value-parser.d.ts +2 -0
  3. package/dist/pdf-ast/fonts/resolve.d.ts +5 -1
  4. package/dist/pdf-ast/index.js +172 -165
  5. package/dist/safe-bash/command-chunks/biff-KLS4T7FP-UO3CXFFF.js +5581 -0
  6. package/dist/safe-bash/command-chunks/chunk-2J4OQT3F.js +153 -0
  7. package/dist/safe-bash/command-chunks/{chunk-K7VDCBXW.js → chunk-ABL2DPJI.js} +20 -20
  8. package/dist/safe-bash/command-chunks/{chunk-RINR7XPR.js → chunk-E64ZI2YB.js} +121 -4
  9. package/dist/safe-bash/command-chunks/{chunk-GEDO5V32.js → chunk-FSG6UC2N.js} +243 -105
  10. package/dist/safe-bash/command-chunks/{chunk-4QEJPP3K.js → chunk-S5X7PBO4.js} +1 -1
  11. package/dist/safe-bash/command-chunks/{chunk-IHLZ6HNQ.js → chunk-TSKJNCKD.js} +3 -2
  12. package/dist/safe-bash/command-chunks/{chunk-DBZCTL7C.js → chunk-UYZ6EFZE.js} +20 -18
  13. package/dist/safe-bash/command-chunks/{chunk-B2C3UPJS.js → chunk-W42SUPD6.js} +13 -1
  14. package/dist/safe-bash/command-chunks/chunk-ZHHALBM7.js +398 -0
  15. package/dist/safe-bash/command-chunks/{command-engine-GHE6QUHU.js → command-engine-2QXVRRH3.js} +8 -4
  16. package/dist/safe-bash/command-chunks/{engine-RG6HQCCB-FXYZS264.js → engine-T4GP6QOK-ECFKMR5V.js} +1 -1
  17. package/dist/safe-bash/command-chunks/odf-SL5TG4B3-XI3FNOTN.js +3041 -0
  18. package/dist/safe-bash/command-chunks/{xlsx-RE54MFCS-IQ6OXXKK.js → xlsx-RE54MFCS-4UZ5W3U7.js} +1 -1
  19. package/dist/safe-bash-command-apply-patch/apply.js +1 -1
  20. package/dist/safe-bash-command-apply-patch/index.js +1 -1
  21. package/dist/safe-bash-command-csvkit/index.js +1 -1
  22. package/dist/safe-bash-command-diff/diff.js +1 -1
  23. package/dist/safe-bash-command-diff/index.js +1 -1
  24. package/dist/safe-bash-command-pptx/engine.js +1 -1
  25. package/dist/safe-bash-command-ssconvert/index.js +5 -5
  26. package/dist/safe-bash-presentation-engine/index.js +1 -1
  27. package/dist/safe-bash-presentation-engine/retained-tags.d.ts +20 -0
  28. package/dist/safe-bash-presentation-engine/tags.d.ts +2 -0
  29. package/dist/safe-bash-presentation-engine/tags.js +11 -3
  30. package/dist/safe-bash-xml-engine/document.js +2 -2
  31. package/dist/safe-bash-xml-engine/index.js +2 -2
  32. package/dist/safe-bash-xml-engine/stored-document.d.ts +2 -0
  33. package/dist/safe-bash-xml-engine/stored-document.js +1 -1
  34. package/dist/safe-bash-xml-engine/stored-evaluate.js +2 -2
  35. package/dist/safe-bash-xml-engine/stored-namespaces.d.ts +21 -0
  36. package/dist/safe-bash-zip-engine/zip/safety.js +1 -1
  37. package/dist/safe-bash-zip-engine/zip/volumes.js +1 -1
  38. package/dist/spreadsheet-format-xls/biff-properties-merge.js +3 -3
  39. package/dist/spreadsheet-format-xls/biff-properties.d.ts +4 -2
  40. package/dist/spreadsheet-format-xls/biff-properties.js +141 -122
  41. package/dist/spreadsheet-format-xls/biff-property-names.d.ts +24 -0
  42. package/dist/spreadsheet-format-xls/biff-property-names.js +167 -0
  43. package/dist/xlsx-ast/comment-geometry.js +1 -1
  44. package/package.json +3 -2
  45. package/dist/safe-bash/command-chunks/biff-UBP2BZLK-JPODPKS3.js +0 -5448
  46. package/dist/safe-bash/command-chunks/chunk-O2HNOQQG.js +0 -161
  47. package/dist/safe-bash/command-chunks/chunk-ZUP5TBRG.js +0 -99
  48. package/dist/safe-bash/command-chunks/odf-3EA3EVSD-7B5GVNTC.js +0 -3097
@@ -1,6 +1,7 @@
1
1
  import {
2
+ StoredNamespaces,
2
3
  StoredXmlDocument
3
- } from "./chunk-RINR7XPR.js";
4
+ } from "./chunk-E64ZI2YB.js";
4
5
  import {
5
6
  escape
6
7
  } from "./chunk-IJE65P52.js";
@@ -139,7 +140,7 @@ function declaration(source) {
139
140
  }
140
141
  return result + "?>\n";
141
142
  }
142
- async function attributes(element, source, inherited, budget, exclusive, stored) {
143
+ async function attributes(element, source, namespaces, inherited, budget, exclusive, stored) {
143
144
  const selected = stored ? new StoredAttributes(stored.storage, budget) : [];
144
145
  for await (const attribute of source()) {
145
146
  {
@@ -151,7 +152,7 @@ async function attributes(element, source, inherited, budget, exclusive, stored)
151
152
  else await selected.append(attribute);
152
153
  }
153
154
  }
154
- for (const [prefix, uri] of element.namespaces) {
155
+ for await (const [prefix, uri] of namespaces) {
155
156
  {
156
157
  const _p = budget.tick(uri.length + prefix.length + 1);
157
158
  if (_p) await _p;
@@ -169,7 +170,7 @@ async function attributes(element, source, inherited, budget, exclusive, stored)
169
170
  }
170
171
  if (!used) continue;
171
172
  }
172
- if (uri === (inherited.get(prefix) ?? "")) continue;
173
+ if (uri === (await inherited.get(prefix) ?? "")) continue;
173
174
  const attribute = {
174
175
  name: prefix ? `xmlns:${prefix}` : "xmlns",
175
176
  namespace: xmlns,
@@ -200,7 +201,6 @@ var StoredFrames = class {
200
201
  }
201
202
  document;
202
203
  head = 0;
203
- namespaces = /* @__PURE__ */ new WeakMap();
204
204
  async store(value) {
205
205
  const bytes = new TextEncoder().encode(JSON.stringify(value));
206
206
  const header = new Uint8Array(8);
@@ -219,11 +219,8 @@ var StoredFrames = class {
219
219
  for await (const frame of source) {
220
220
  const checkpoint = this.document.budget.tick();
221
221
  if (checkpoint) await checkpoint;
222
- let namespaces = this.namespaces.get(frame.namespaces);
223
- if (namespaces === void 0) {
224
- namespaces = await this.store([...frame.namespaces]);
225
- this.namespaces.set(frame.namespaces, namespaces);
226
- }
222
+ if (!(frame.namespaces instanceof StoredNamespaces)) throw new TypeError("Stored frames require backed namespace scopes");
223
+ const namespaces = frame.namespaces.reference;
227
224
  const value = await this.store({ ...frame, namespaces });
228
225
  const link = new Uint8Array(16), view = new DataView(link.buffer);
229
226
  view.setFloat64(0, reversed, true);
@@ -247,8 +244,7 @@ var StoredFrames = class {
247
244
  const view = new DataView(link.buffer, link.byteOffset, 16);
248
245
  this.head = view.getFloat64(0, true);
249
246
  const frame = await this.load(view.getFloat64(8, true));
250
- const namespaces = new Map(await this.load(frame.namespaces));
251
- this.namespaces.set(namespaces, frame.namespaces);
247
+ const namespaces = new StoredNamespaces(this.document.storage, this.document.budget, frame.namespaces);
252
248
  return { ...frame, namespaces };
253
249
  }
254
250
  };
@@ -272,6 +268,9 @@ async function* serializeDocument(source, mode, budget, format = mode === "forma
272
268
  if (typeof reference === "number") yield* stored.attributes(reference);
273
269
  else if (reference.kind === "element") yield* reference.attributes;
274
270
  }
271
+ async function namespaceScope(reference, element) {
272
+ return typeof reference === "number" ? stored.namespaceScope(reference) : element.namespaces;
273
+ }
275
274
  const root = await load(rootReference);
276
275
  const canonical = mode !== "format";
277
276
  const documentDeclaration = options.declaration ?? root.declaration;
@@ -302,7 +301,7 @@ async function* serializeDocument(source, mode, budget, format = mode === "forma
302
301
  const p = budget.tick();
303
302
  if (p) await p;
304
303
  }
305
- for (const [prefix, uri] of element.namespaces) {
304
+ for await (const [prefix, uri] of await namespaceScope(reference, element)) {
306
305
  {
307
306
  const p = budget.tick(uri.length + prefix.length + 1);
308
307
  if (p) await p;
@@ -317,7 +316,7 @@ async function* serializeDocument(source, mode, budget, format = mode === "forma
317
316
  }
318
317
  }
319
318
  } else yield declaration(documentDeclaration);
320
- const namespaces = /* @__PURE__ */ new Map([["xml", xml]]);
319
+ const namespaces = stored ? await new StoredNamespaces(stored.storage, budget).set("xml", xml) : /* @__PURE__ */ new Map([["xml", xml]]);
321
320
  async function* siblings() {
322
321
  if (stored) yield* stored.children(stored.document);
323
322
  else {
@@ -430,7 +429,7 @@ async function* serializeDocument(source, mode, budget, format = mode === "forma
430
429
  count++;
431
430
  mixed = child.mixed;
432
431
  }
433
- const ordered = canonical ? await attributes(current, () => elementAttributes(reference), frame.namespaces, budget, mode === "exc-c14n", stored) : [];
432
+ const ordered = canonical ? await attributes(current, () => elementAttributes(reference), await namespaceScope(reference, current), frame.namespaces, budget, mode === "exc-c14n", stored) : [];
434
433
  async function* outputAttributes() {
435
434
  if (canonical) yield* ordered;
436
435
  else for (const namespace of [true, false]) for await (const attribute of elementAttributes(reference)) {
@@ -444,9 +443,12 @@ async function* serializeDocument(source, mode, budget, format = mode === "forma
444
443
  yield `<${current.name}`;
445
444
  for await (const attribute of outputAttributes()) {
446
445
  if (canonical && attribute.namespace === xmlns) {
447
- changed ??= new Map(frame.namespaces);
448
- changed.set(attribute.localName, attribute.value);
449
- childNamespaces = changed;
446
+ if (childNamespaces instanceof StoredNamespaces) childNamespaces = await childNamespaces.set(attribute.localName, attribute.value);
447
+ else {
448
+ changed ??= new Map(childNamespaces);
449
+ changed.set(attribute.localName, attribute.value);
450
+ childNamespaces = changed;
451
+ }
450
452
  }
451
453
  {
452
454
  const p = budget.tick();
@@ -18,6 +18,7 @@ import {
18
18
  // packages/safe-bash-command-apply-patch/src/apply.ts
19
19
  import { PagedStorage as PagedStorage2 } from "@poe-platform/safe-fs/storage";
20
20
  import {
21
+ collectBytes,
21
22
  createOutputOperation,
22
23
  dirname,
23
24
  readBytes,
@@ -398,7 +399,7 @@ var Invocation = class {
398
399
  for (const file of files) for (const path of [file.path, file.destination]) {
399
400
  if (!path) continue;
400
401
  const capabilities = await this.work.fs(path, async () => await this.fs.capabilitiesFor?.(path, { signal: this.context.signal }) ?? this.fs.capabilities);
401
- if (capabilities.atomicFileMutation !== true || capabilities.retainedStagingWrite !== true || capabilities.retainedStagingCleanup !== true || capabilities.atomicStagedFileMutation !== true) throw new PatchError("filesystem does not support atomic conditional patch mutations");
402
+ if (capabilities.atomicFileMutation !== true || !this.fs.writeFileConditional && (capabilities.retainedStagingWrite !== true || capabilities.retainedStagingCleanup !== true || capabilities.atomicStagedFileMutation !== true)) throw new PatchError("filesystem does not support atomic conditional patch mutations");
402
403
  let parent = dirname(path);
403
404
  while (!await this.inspect(parent, false)) {
404
405
  await this.work.charge(1);
@@ -609,6 +610,17 @@ var Invocation = class {
609
610
  async write(path, output, parent, expected) {
610
611
  let staging;
611
612
  const signal = this.context.signal;
613
+ const capabilities = await this.work.fs(path, async () => await this.fs.capabilitiesFor?.(path, { signal }) ?? this.fs.capabilities);
614
+ if (capabilities.retainedStagingWrite !== true || capabilities.retainedStagingCleanup !== true || capabilities.atomicStagedFileMutation !== true) {
615
+ const bytes = await collectBytes(output.range(0, output.size), { signal, maxBytes: this.work.limits.maxFileBytes });
616
+ await this.work.fs(path, () => this.fs.writeFileConditional(path, bytes, {
617
+ parent,
618
+ expected: expected ?? null,
619
+ signal,
620
+ ...expected ? { mode: expected.mode & 4095 } : {}
621
+ }));
622
+ return;
623
+ }
612
624
  try {
613
625
  await this.work.fs(path, async () => {
614
626
  staging = await this.fs.createStagedFile(
@@ -0,0 +1,398 @@
1
+ import {
2
+ openRetainedPresentationIndex,
3
+ stageRetainedOutput,
4
+ streamJson
5
+ } from "./chunk-FB2WPI3M.js";
6
+ import {
7
+ attr,
8
+ child,
9
+ escape,
10
+ invalid,
11
+ loadShared,
12
+ nextRel,
13
+ relPart
14
+ } from "./chunk-A5SPMSKD.js";
15
+ import {
16
+ SelectionError,
17
+ decodeSelectionToken
18
+ } from "./chunk-NCNHJRIY.js";
19
+ import {
20
+ openRetainedPresentationValidation
21
+ } from "./chunk-6W4RMBFH.js";
22
+ import {
23
+ dialects
24
+ } from "./chunk-6KJDTKE4.js";
25
+ import {
26
+ parseXmlPart
27
+ } from "./chunk-7PYDVQPB.js";
28
+ import {
29
+ relativePartReference
30
+ } from "./chunk-MOUCMZZP.js";
31
+ import {
32
+ OfficeError,
33
+ RetainedValues,
34
+ equal,
35
+ folded,
36
+ literal,
37
+ openRetainedXmlDocument,
38
+ resolveOfficeResources
39
+ } from "./chunk-KM2SMMXZ.js";
40
+
41
+ // packages/safe-bash-presentation-engine/src/retained-tags.ts
42
+ import { PagedStorage } from "@poe-platform/safe-fs/storage";
43
+ async function openRetainedTags(archive, fingerprint, options, settings) {
44
+ validateTagOptions(options);
45
+ const query = { ...options, ...options.selection ? { selection: { ...options.selection, ...options.selection.position ? { position: { ...options.selection.position } } : {} } } : {} };
46
+ const context = resolveOfficeResources(settings), working = { ...settings.workingStorage }, signal = context.signal ?? new AbortController().signal;
47
+ const index = await openRetainedPresentationIndex(archive, fingerprint, { ...context, workingStorage: working });
48
+ const pages = new PagedStorage({ fs: working.fs, cwd: working.directory, env: {}, signal }, (working.cacheBytes ?? 1024 * 1024) / 16384);
49
+ let closed = false, closing, head = 0, tail = 0;
50
+ const check = () => {
51
+ if (closed) throw new OfficeError("invalid-handle", "Tags are closed.", "index");
52
+ if (signal.aborted) throw new OfficeError("cancelled", "Operation cancelled.", "index");
53
+ };
54
+ const close = () => {
55
+ closed = true;
56
+ return closing ??= (async () => {
57
+ const outcomes = await Promise.allSettled([index.close(), pages.close()]);
58
+ for (const outcome of outcomes) if (outcome.status === "rejected") throw outcome.reason;
59
+ })();
60
+ };
61
+ const values = new RetainedValues(pages, check, signal);
62
+ const range = (row2, offset) => ({ start: row2[offset], length: row2[offset + 1] });
63
+ async function row(pointer) {
64
+ check();
65
+ const bytes = await pages.read(pointer, 7 /* Count */ * 8), view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
66
+ return Array.from({ length: 7 /* Count */ }, (_, n) => view.getFloat64(n * 8, true));
67
+ }
68
+ async function write(pointer, numbers) {
69
+ check();
70
+ const bytes = new Uint8Array(numbers.length * 8), view = new DataView(bytes.buffer);
71
+ numbers.forEach((number, n) => view.setFloat64(n * 8, number, true));
72
+ await pages.write(pointer, bytes);
73
+ }
74
+ async function bounded(value) {
75
+ const decoder = new TextDecoder();
76
+ let result = "";
77
+ for await (const bytes of values.read(value)) result += decoder.decode(bytes, { stream: true });
78
+ return result + decoder.decode();
79
+ }
80
+ const invalid2 = (message) => {
81
+ throw new OfficeError("invalid-value", message, "usage");
82
+ };
83
+ async function is(document, node, local, namespace) {
84
+ return await equal(document.raw(node.localName), literal(local)) && await equal(document.namespace(node), namespace);
85
+ }
86
+ async function child2(document, parent, local) {
87
+ let found;
88
+ for await (const node of document.children(parent)) if (node.kind === "element" && await is(document, node, local, document.namespace(parent))) {
89
+ if (found) invalid2("Ambiguous shared structure.");
90
+ found = node;
91
+ }
92
+ return found;
93
+ }
94
+ async function attribute(document, node, local, namespace = "") {
95
+ for await (const attr2 of document.attributes(node)) if (await is(document, attr2, local, literal(namespace))) return attr2;
96
+ return void 0;
97
+ }
98
+ try {
99
+ const validation = await openRetainedPresentationValidation(archive, { ...context, workingStorage: working }, { ...context.xmlLimits, ...context.relationshipLimits, maxBytes: Math.min(context.xmlLimits.maxBytes, context.relationshipLimits.maxBytes), maxEntries: context.archiveLimits.maxMembers });
100
+ const valid = validation.valid;
101
+ try {
102
+ await validation.close();
103
+ } catch (error) {
104
+ if (valid) await Promise.reject(error);
105
+ }
106
+ if (!valid) throw new OfficeError("invalid-opc", "Invalid presentation graph.", "validate-intent");
107
+ for await (const part of archive.parts()) {
108
+ const key = await values.store(folded(literal(part))), value = await values.store(literal(part));
109
+ await values.insert("parts", key, value);
110
+ }
111
+ const main = await openRetainedXmlDocument(archive.read(index.records.main), { ...context, workingStorage: working });
112
+ let dialect = dialects[0], failed = false;
113
+ try {
114
+ for (const candidate of dialects) if (await equal(main.namespace(main.root), literal(candidate.p))) dialect = candidate;
115
+ } catch (error) {
116
+ failed = true;
117
+ throw error;
118
+ } finally {
119
+ try {
120
+ await main.close();
121
+ } catch (error) {
122
+ if (!failed) await Promise.reject(error);
123
+ }
124
+ }
125
+ let token;
126
+ if (query.selection?.token) {
127
+ if (Object.keys(query.selection).some((key) => key !== "token")) throw new SelectionError("invalid-selection");
128
+ token = decodeSelectionToken(query.selection.token);
129
+ if (token.fingerprint !== fingerprint) throw new SelectionError("stale-selection");
130
+ if (token.scope !== "slides" && token.scope !== "presentation" || query.scope !== void 0 && query.scope !== token.scope) throw new SelectionError("invalid-selection");
131
+ }
132
+ async function* owners2() {
133
+ if ((token?.scope ?? query.scope) === "presentation") {
134
+ yield { part: index.records.main, slide: null };
135
+ return;
136
+ }
137
+ const selected = token ? void 0 : query.selection;
138
+ for await (const record of selected ? index.records.select({ kind: "slide", ...selected }) : index.records.records("slide")) {
139
+ if (record.kind !== "slide") throw new SelectionError("invalid-selection");
140
+ yield { part: record.part, slide: record.position };
141
+ }
142
+ }
143
+ for await (const ignoredOwner of owners2()) check();
144
+ for await (const owner of owners2()) {
145
+ const document = await openRetainedXmlDocument(archive.read(owner.part), { ...context, workingStorage: working });
146
+ let failed2 = false, reference;
147
+ try {
148
+ const base = owner.part === index.records.main ? document.root : await child2(document, document.root, "cSld");
149
+ if (!base) invalid2("Tag owner lacks common slide data.");
150
+ const list = await child2(document, base, "custDataLst"), tags2 = list ? await child2(document, list, "tags") : void 0;
151
+ if (tags2) {
152
+ const id = await attribute(document, tags2, "id", dialect.r);
153
+ let count = 0;
154
+ if (id) {
155
+ for await (const edge of index.graph.outgoing(owner.part)) if (edge.owner === owner.part && !edge.external && await equal(edge.type(), literal(`${dialect.r}/tags`)) && await equal(edge.id(), document.text(id))) {
156
+ count++;
157
+ if (edge.targetPart) reference = await values.store(edge.targetPart());
158
+ }
159
+ }
160
+ if (count !== 1 || !reference) invalid2("Invalid tag association.");
161
+ }
162
+ } catch (error) {
163
+ failed2 = true;
164
+ throw error;
165
+ } finally {
166
+ try {
167
+ await document.close();
168
+ } catch (error) {
169
+ if (!failed2) await Promise.reject(error);
170
+ }
171
+ }
172
+ if (!reference) continue;
173
+ const original = await values.find("parts", () => folded(values.read(reference)));
174
+ if (!original) throw new OfficeError("missing-binding", "Package member is absent.", "index");
175
+ const part = await bounded(reference), tags = await openRetainedXmlDocument(archive.read(await bounded(original)), { ...context, workingStorage: working });
176
+ let failedTags = false;
177
+ try {
178
+ if (!await is(tags, tags.root, "tagLst", literal(dialect.p))) invalid2("Invalid tag list.");
179
+ let childIndex = 0;
180
+ for await (const node of tags.children(tags.root)) {
181
+ if (node.kind !== "element") continue;
182
+ const position = childIndex++;
183
+ if (!await is(tags, node, "tag", literal(dialect.p))) continue;
184
+ const name = await attribute(tags, node, "name"), value = await attribute(tags, node, "val");
185
+ if (!name || !value) invalid2("Tag requires name and value attributes.");
186
+ const location = { fingerprint, scope: owner.slide === null ? "presentation" : "slides", owner: owner.part, objectId: `tag:${part}:${position}`, coordinateSystem: "identity" };
187
+ const metadata = await values.store(literal(JSON.stringify({ part, owner: owner.part, slide: owner.slide, selector: JSON.stringify(location), location })));
188
+ const key = await values.store(tags.text(name)), text = await values.store(tags.text(value));
189
+ const pointer = pages.allocate(7 /* Count */ * 8);
190
+ await write(pointer, [0, metadata.start, metadata.length, key.start, key.length, text.start, text.length]);
191
+ if (tail) await write(tail, [pointer]);
192
+ else head = pointer;
193
+ tail = pointer;
194
+ }
195
+ } catch (error) {
196
+ failedTags = true;
197
+ throw error;
198
+ } finally {
199
+ try {
200
+ await tags.close();
201
+ } catch (error) {
202
+ if (!failedTags) await Promise.reject(error);
203
+ }
204
+ }
205
+ }
206
+ await index.close();
207
+ return Object.freeze({ close, async *records() {
208
+ check();
209
+ for (let pointer = head; pointer; ) {
210
+ const data = await row(pointer);
211
+ pointer = data[0 /* Next */];
212
+ const metadata = JSON.parse(await bounded(range(data, 1 /* Metadata */)));
213
+ if (token && metadata.selector !== query.selection.token) continue;
214
+ yield { name: () => values.read(range(data, 3 /* Name */)), value: () => values.read(range(data, 5 /* Value */)), ...metadata };
215
+ }
216
+ check();
217
+ } });
218
+ } catch (error) {
219
+ await close().catch(() => {
220
+ });
221
+ throw error instanceof OfficeError ? error : new OfficeError(signal.aborted ? "cancelled" : "io-failure", "Tag storage operation failed.", "index");
222
+ }
223
+ }
224
+ async function stageRetainedTags(archive, fingerprint, query, settings, output) {
225
+ const format = { ...output };
226
+ if (!["tags.list", "tags.get"].includes(format.operation)) throw new OfficeError("invalid-value", "Invalid tag read operation.", "usage");
227
+ const tags = await openRetainedTags(archive, fingerprint, query, settings);
228
+ let staged;
229
+ try {
230
+ if (format.operation === "tags.get") {
231
+ let count = 0;
232
+ for await (const ignoredRecord of tags.records()) count++;
233
+ if (count !== 1) throw new SelectionError(count ? "ambiguous-selection" : "missing-selection");
234
+ }
235
+ async function* locations() {
236
+ for await (const tag of tags.records()) yield tag.location;
237
+ }
238
+ async function* render() {
239
+ if (format.json) {
240
+ yield* streamJson({ version: 1, operation: format.operation, ok: true, data: { tags: tags.records() }, affected: 0, warnings: [], errors: [], locations: locations() });
241
+ yield* literal("\n");
242
+ } else for await (const tag of tags.records()) {
243
+ yield* streamJson(tag.name);
244
+ yield* literal(": ");
245
+ yield* streamJson(tag.value);
246
+ yield* literal("\n");
247
+ }
248
+ }
249
+ staged = await stageRetainedOutput(render(), settings, format.maxOutputBytes);
250
+ await tags.close();
251
+ return staged;
252
+ } catch (error) {
253
+ await Promise.allSettled([tags.close(), staged?.close()]);
254
+ throw error;
255
+ }
256
+ }
257
+
258
+ // packages/safe-bash-presentation-engine/src/tags.ts
259
+ var relns = "http://schemas.openxmlformats.org/package/2006/relationships";
260
+ function validateTagOptions(options, action) {
261
+ if (!options || ![Object.prototype, null].includes(Object.getPrototypeOf(options)) || Object.keys(options).some((key) => !["scope", "selection", "name", "value", "allowEmpty"].includes(key)) || options.scope !== void 0 && !["presentation", "slides"].includes(options.scope) || options.allowEmpty !== void 0 && typeof options.allowEmpty !== "boolean") invalid("Invalid tag options.");
262
+ if (options.scope === "presentation" && options.selection && Object.keys(options.selection).some((key) => key !== "all" && key !== "token")) invalid("Presentation tags do not accept slide selectors.");
263
+ if (action === "add" && (options.name === void 0 || options.value === void 0)) invalid("New tags require name and value.");
264
+ if (action === "set" && options.name === void 0 && options.value === void 0) invalid("A tag edit requires name or value.");
265
+ for (const value of [options.name, options.value]) {
266
+ if (value === void 0) continue;
267
+ if (typeof value !== "string") invalid("Tag fields require strings.");
268
+ for (const c of value) {
269
+ const n = c.codePointAt(0);
270
+ if (n < 32 && ![9, 10, 13].includes(n) || n >= 55296 && n <= 57343 || n === 65534 || n === 65535) invalid("Tag fields require XML characters.");
271
+ }
272
+ }
273
+ if (options.name === "") invalid("Tag names cannot be empty.");
274
+ if (!action && (options.name !== void 0 || options.value !== void 0 || options.allowEmpty !== void 0)) invalid("Tag reads accept selection and scope only.");
275
+ if (action === "remove" && (options.name !== void 0 || options.value !== void 0)) invalid("Tag removal does not accept edit fields.");
276
+ }
277
+ function owners(s, options) {
278
+ if (options.scope === "presentation") return [{ part: s.main, slide: null }];
279
+ const selection = options.selection;
280
+ return (selection ? s.index.select({ kind: "slide", ...selection }) : s.index.slides).map((record) => {
281
+ if (record.kind !== "slide") throw new SelectionError("invalid-selection");
282
+ return { part: record.part, slide: record.position };
283
+ });
284
+ }
285
+ function association(s, owner) {
286
+ const doc = s.doc(owner);
287
+ const base = owner === s.main ? doc.root : child(doc.root, "cSld");
288
+ if (!base) invalid("Tag owner lacks common slide data.");
289
+ const list = child(base, "custDataLst");
290
+ const tags = list ? child(list, "tags") : void 0;
291
+ if (!tags) return void 0;
292
+ const id = tags.attributes.find((a) => a.name.namespace === s.r && a.name.localName === "id")?.value;
293
+ const edges = s.index.inventory.relationships.filter((e) => e.owner === owner && e.id === id && e.type === `${s.r}/tags` && !e.external);
294
+ if (edges.length !== 1 || !edges[0].targetPart) invalid("Invalid tag association.");
295
+ return edges[0].targetPart;
296
+ }
297
+ function records(s, options) {
298
+ let token;
299
+ if (options.selection?.token) {
300
+ if (Object.keys(options.selection).some((key) => key !== "token")) throw new SelectionError("invalid-selection");
301
+ token = decodeSelectionToken(options.selection.token);
302
+ if (token.fingerprint !== s.index.fingerprint) throw new SelectionError("stale-selection");
303
+ if (token.scope !== "slides" && token.scope !== "presentation") throw new SelectionError("invalid-selection");
304
+ if (options.scope !== void 0 && options.scope !== token.scope) throw new SelectionError("invalid-selection");
305
+ }
306
+ const selected = owners(s, token ? { scope: token.scope } : options);
307
+ const result = selected.flatMap((owner) => {
308
+ const part = association(s, owner.part);
309
+ if (!part) return [];
310
+ const doc = s.doc(part);
311
+ if (doc.root.name.namespace !== s.p || doc.root.name.localName !== "tagLst") invalid("Invalid tag list.");
312
+ return doc.root.children.flatMap((node, index) => {
313
+ if (node.name.namespace !== s.p || node.name.localName !== "tag") return [];
314
+ const name = attr(node, "name"), value = attr(node, "val");
315
+ if (name === void 0 || value === void 0) invalid("Tag requires name and value attributes.");
316
+ const location = { fingerprint: s.index.fingerprint, scope: owner.slide === null ? "presentation" : "slides", owner: owner.part, objectId: `tag:${part}:${index}`, coordinateSystem: "identity" };
317
+ return [{ name, value, part, owner: owner.part, slide: owner.slide, selector: JSON.stringify(location), location }];
318
+ });
319
+ });
320
+ return token ? result.filter((r) => r.selector === options.selection.token) : result;
321
+ }
322
+ async function readTags(input, options, context) {
323
+ validateTagOptions(options);
324
+ return records(await loadShared(input, context, false), options);
325
+ }
326
+ function createAssociation(s, owner, context) {
327
+ let n = 1;
328
+ while (s.reader.has(`/ppt/tags/tag${n}.xml`) || s.changes.has(`/ppt/tags/tag${n}.xml`)) n++;
329
+ const part = `/ppt/tags/tag${n}.xml`;
330
+ s.save(part, parseXmlPart(new TextEncoder().encode(`<p:tagLst xmlns:p="${s.p}"/>`), context.xmlLimits));
331
+ const types = s.doc("/[Content_Types].xml");
332
+ s.save("/[Content_Types].xml", types.spliceChildren(types.root, types.root.children.length, 0, [`<Override xmlns="${types.root.name.namespace}" PartName="${part}" ContentType="application/vnd.openxmlformats-officedocument.presentationml.tags+xml"/>`]));
333
+ const relName = relPart(owner);
334
+ const rels = s.reader.has(relName) ? s.doc(relName) : parseXmlPart(new TextEncoder().encode(`<Relationships xmlns="${relns}"/>`), context.xmlLimits);
335
+ const id = nextRel(rels);
336
+ s.save(relName, rels.spliceChildren(rels.root, rels.root.children.length, 0, [`<Relationship xmlns="${relns}" Id="${id}" Type="${s.r}/tags" Target="${escape(relativePartReference(part, owner.slice(0, owner.lastIndexOf("/"))))}"/>`]));
337
+ let doc = s.doc(owner);
338
+ let base = owner === s.main ? doc.root : child(doc.root, "cSld");
339
+ let list = child(base, "custDataLst");
340
+ if (!list) {
341
+ const order = owner === s.main ? ["sldMasterIdLst", "notesMasterIdLst", "handoutMasterIdLst", "sldIdLst", "sldSz", "notesSz", "smartTags", "embeddedFontLst", "custShowLst", "photoAlbum", "custDataLst", "kinsoku", "defaultTextStyle", "modifyVerifier", "extLst"] : ["bg", "spTree", "custDataLst", "controls", "extLst"];
342
+ doc = doc.merge(base, { children: { sequence: order.map((localName) => ({ namespace: s.p, localName })), upsert: [{ name: { namespace: s.p, localName: "custDataLst" }, merge: {} }] } });
343
+ base = owner === s.main ? doc.root : child(doc.root, "cSld");
344
+ list = child(base, "custDataLst");
345
+ }
346
+ s.save(owner, doc.spliceChildren(list, list.children.length, 0, [`<p:tags xmlns:p="${s.p}" xmlns:r="${s.r}" r:id="${id}"/>`]));
347
+ return part;
348
+ }
349
+ async function mutateTags(input, action, options, context) {
350
+ if (!["add", "set", "remove"].includes(action)) invalid("Invalid tag action.");
351
+ validateTagOptions(options, action);
352
+ if ((options.name?.length ?? 0) + (options.value?.length ?? 0) > context.xmlLimits.maxBytes) throw new OfficeError("resource-limit", "Tag exceeds XML limits.", "usage");
353
+ if (!options.selection && options.scope !== "presentation") throw new SelectionError("missing-selection");
354
+ const s = await loadShared(input, context);
355
+ const existing = records(s, options);
356
+ const locations = [];
357
+ if (action === "add") {
358
+ if (options.selection?.token) throw new SelectionError("invalid-selection");
359
+ const selected = owners(s, options);
360
+ if (!selected.length && !options.allowEmpty) throw new SelectionError("missing-selection");
361
+ for (const owner of selected) {
362
+ if (existing.some((r) => r.owner === owner.part && r.name === options.name)) invalid("Duplicate tag name.");
363
+ const part = association(s, owner.part) ?? createAssociation(s, owner.part, context);
364
+ if (s.index.inventory.relationships.filter((e) => e.targetPart === part).length > 1) throw new OfficeError("unsupported-edit", "Shared tag lists cannot be edited.", "validate-intent");
365
+ const doc = s.doc(part);
366
+ const location = { fingerprint: s.index.fingerprint, scope: owner.slide === null ? "presentation" : "slides", owner: owner.part, objectId: `tag:${part}:${doc.root.children.length}`, coordinateSystem: "identity" };
367
+ s.save(part, doc.spliceChildren(doc.root, doc.root.children.length, 0, [`<p:tag xmlns:p="${s.p}" name="${escape(options.name)}" val="${escape(options.value)}"/>`]));
368
+ locations.push(location);
369
+ }
370
+ } else {
371
+ if (!existing.length && !options.allowEmpty) throw new SelectionError("missing-selection");
372
+ if (existing.length > 1 && !options.selection?.all) throw new SelectionError("ambiguous-selection");
373
+ if (options.name !== void 0) {
374
+ const all = records(s, { scope: existing[0]?.location.scope });
375
+ for (const record of existing) if (all.some((r) => r.owner === record.owner && r.name === options.name && r.selector !== record.selector)) invalid("Duplicate tag name.");
376
+ if (existing.some((r, i) => existing.slice(0, i).some((v) => v.owner === r.owner))) invalid("Duplicate tag name.");
377
+ }
378
+ for (const record of [...existing].reverse()) {
379
+ if (s.index.inventory.relationships.filter((e) => e.targetPart === record.part).length > 1) throw new OfficeError("unsupported-edit", "Shared tag lists cannot be edited.", "validate-intent");
380
+ const doc = s.doc(record.part);
381
+ const index = Number(record.location.objectId.slice(record.location.objectId.lastIndexOf(":") + 1));
382
+ const node = doc.root.children[index];
383
+ if (action === "remove" && (node.children.length || node.attributes.some((a) => a.name.namespace !== "" || !["name", "val"].includes(a.name.localName)))) throw new OfficeError("unsupported-edit", "Decorated tags are preserved on removal.", "validate-intent");
384
+ s.save(record.part, action === "remove" ? doc.spliceChildren(doc.root, index, 1, []) : doc.merge(doc.root.children[index], { attributes: [...options.name === void 0 ? [] : [{ namespace: "", localName: "name", value: options.name }], ...options.value === void 0 ? [] : [{ namespace: "", localName: "val", value: options.value }]] }));
385
+ locations.push(record.location);
386
+ }
387
+ }
388
+ const result = await s.finish(s.main, []);
389
+ return { bytes: result.bytes, affected: locations.length, locations };
390
+ }
391
+
392
+ export {
393
+ openRetainedTags,
394
+ stageRetainedTags,
395
+ validateTagOptions,
396
+ readTags,
397
+ mutateTags
398
+ };
@@ -12,6 +12,7 @@ import {
12
12
  import "./chunk-65DS4IOB.js";
13
13
 
14
14
  // packages/safe-bash-command-pptx/src/command-engine.ts
15
+ import { stageRetainedTags } from "../../safe-bash-presentation-engine/tags.js";
15
16
  import { stageRetainedProperties } from "../../safe-bash-presentation-engine/properties.js";
16
17
  import { stageRetainedNotes } from "../../safe-bash-presentation-engine/notes.js";
17
18
 
@@ -12113,8 +12114,8 @@ async function executeRequest(request, options2, owned) {
12113
12114
  publication = { inputPath: args.input, outputPath: destination, bytes: staged.bytes(), originalBytes: input, inPlace: args.inPlace ?? false, force: args.force ?? false, dryRun };
12114
12115
  }
12115
12116
  result = success(operation2, null);
12116
- } else if ((args.operation === "inspect" || args.operation === "text.get" || args.operation === "fields.list" || args.operation === "fields.get" || args.operation === "text.frames.list" || args.operation === "text.frames.get" || args.operation === "notes.list" || args.operation === "notes.get" || args.operation === "properties.list" || args.operation === "properties.get" || args.operation === "xml.get") && request.streaming) {
12117
- if (args.token && args.operation !== "notes.list" && args.operation !== "notes.get") decodeSelectionToken2(args.token);
12117
+ } else if ((args.operation === "inspect" || args.operation === "text.get" || args.operation === "fields.list" || args.operation === "fields.get" || args.operation === "text.frames.list" || args.operation === "text.frames.get" || args.operation === "notes.list" || args.operation === "notes.get" || args.operation === "properties.list" || args.operation === "properties.get" || args.operation === "tags.list" || args.operation === "tags.get" || args.operation === "xml.get") && request.streaming) {
12118
+ if (args.token && args.operation !== "notes.list" && args.operation !== "notes.get" && args.operation !== "tags.list" && args.operation !== "tags.get") decodeSelectionToken2(args.token);
12118
12119
  const input = await request.streaming.openInput(args.input, Math.min(options2.context.limits.maxBytes, options2.context.archiveLimits.maxArchiveBytes));
12119
12120
  const hash = sha2564.create();
12120
12121
  for await (const bytes of input.stream()) {
@@ -12126,8 +12127,11 @@ async function executeRequest(request, options2, owned) {
12126
12127
  const archive = await openPackageArchive(input, context);
12127
12128
  let failed = false;
12128
12129
  try {
12129
- const scope = args.operation === "notes.list" || args.operation === "notes.get" ? void 0 : args.token ? decodeSelectionToken2(args.token).scope : args.scope;
12130
- stagedOutput = args.operation === "properties.list" || args.operation === "properties.get" ? await stageRetainedProperties(archive, fingerprint, args.metadataName === void 0 ? {} : { name: args.metadataName }, context, { operation: args.operation, json: args.json, maxOutputBytes: options2.maxOutputBytes }) : args.operation === "notes.list" || args.operation === "notes.get" ? await stageRetainedNotes(archive, fingerprint, { selection: {
12130
+ const scope = args.operation === "notes.list" || args.operation === "notes.get" || args.operation === "tags.list" || args.operation === "tags.get" ? void 0 : args.token ? decodeSelectionToken2(args.token).scope : args.scope;
12131
+ stagedOutput = args.operation === "tags.list" || args.operation === "tags.get" ? await stageRetainedTags(archive, fingerprint, {
12132
+ ...args.scope === void 0 ? {} : { scope: args.scope },
12133
+ ...args.token ? { selection: { token: args.token } } : args.slide === void 0 ? args.all ? { selection: { all: true } } : {} : { selection: { kind: "slide", position: { coordinateSystem: "one-based", value: args.slide }, ...args.all ? { all: true } : {} } }
12134
+ }, context, { operation: args.operation, json: args.json, maxOutputBytes: options2.maxOutputBytes }) : args.operation === "properties.list" || args.operation === "properties.get" ? await stageRetainedProperties(archive, fingerprint, args.metadataName === void 0 ? {} : { name: args.metadataName }, context, { operation: args.operation, json: args.json, maxOutputBytes: options2.maxOutputBytes }) : args.operation === "notes.list" || args.operation === "notes.get" ? await stageRetainedNotes(archive, fingerprint, { selection: {
12131
12135
  kind: "slide",
12132
12136
  ...args.token ? { token: args.token } : {},
12133
12137
  ...args.slide === void 0 ? {} : { position: { coordinateSystem: "one-based", value: args.slide } },
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Si,
3
3
  gi
4
- } from "./chunk-K7VDCBXW.js";
4
+ } from "./chunk-ABL2DPJI.js";
5
5
  import "./chunk-Z7ESJVFP.js";
6
6
  import "./chunk-WHWIZ2B7.js";
7
7
  import "./chunk-65DS4IOB.js";