/** * OPC (Open Packaging Conventions, ECMA-376 Part 2) layer. * * An {@link OpcPackage} sits over a zip archive and exposes parts, * content-type resolution ([Content_Types].xml Defaults + Overrides), and * package-level plus part-level relationships as live models (lenses over * their .rels XML DOMs). * * Preservation contract (L3): `save()` reserializes only dirty parts; * every untouched part is copied byte-for-byte from the source zip via the * raw-copy path. See CONTRACTS.md §opc and PRESERVATION.md §2. * * Lens invariant: [Content_Types].xml and every .rels part are parsed once * at open into live DOMs; all mutations (addPart, removePart, * RelationshipSet.add/remove) write through to those DOMs immediately and * flag exactly the affected infrastructure part dirty. Unknown attributes * and elements inside those DOMs are preserved automatically. */ import { XmlDocument } from '../xml/index.js'; /** Namespace of [Content_Types].xml. */ export declare const CONTENT_TYPES_NAMESPACE = "http://schemas.openxmlformats.org/package/2006/content-types"; /** Namespace of relationship (.rels) parts. */ export declare const RELATIONSHIPS_NAMESPACE = "http://schemas.openxmlformats.org/package/2006/relationships"; /** Content type of relationship parts. */ export declare const RELATIONSHIPS_CONTENT_TYPE = "application/vnd.openxmlformats-package.relationships+xml"; /** * Media-type equality (RFC 2045 / RFC 6838): the type/subtype portion — * everything before the first ';' — compares ASCII case-insensitively, * while any parameter portion compares verbatim (parameter values may be * case-sensitive, and OPC producers do not normalize them). Stored * content-type values are never rewritten — this is a comparison, not a * normalization (conformance case opc-ct-008: values return verbatim). */ export declare function mediaTypeEquals(a: string, b: string): boolean; /** * Validate the part-name grammar we enforce (ECMA-376 Part 2 §9.1.1, * pragmatic subset per CONTRACTS.md §3.3): must start with '/', must not * end with '/', no empty segments, no '.'/'..' segments, no segment ending * with '.', no backslashes. Throws on violation. */ export declare function validatePartName(name: string): void; /** * Resolve a relationship target against its source part to an absolute * part name. `sourcePartName === null` means the package root (package- * level relationships resolve against '/'). Normalizes `./` and `../` * segments ('..' never climbs above the root; dot segments are processed * on the RAW target, before percent-decoding, per RFC 3986), then * percent-decodes each remaining segment (see {@link decodeTargetSegment}) * — producers routinely write `%20` etc. for part names containing spaces * or non-ASCII. **Internal targets only**: External URIs must not be * passed here (callers gate on `targetMode`). * * Example: resolveRelationshipTarget('/word/document.xml', 'styles.xml') * → '/word/styles.xml'; * resolveRelationshipTarget('/word/document.xml', 'media/image%20(1).png') * → '/word/media/image (1).png'. */ export declare function resolveRelationshipTarget(sourcePartName: string | null, target: string): string; /** One relationship, immutable. Change by remove + add on its set. */ export interface Relationship { /** Unique-in-set identifier, e.g. 'rId1'. */ readonly id: string; /** Relationship type URI. */ readonly type: string; /** Target: part URI (relative to source) or external URI. */ readonly target: string; /** Default 'Internal'. */ readonly targetMode: 'Internal' | 'External'; } /** Input for {@link RelationshipSet.add}. */ export interface RelationshipInput { type: string; target: string; /** Default 'Internal'. */ targetMode?: 'Internal' | 'External'; /** Explicit id; when omitted the next free 'rIdN' is allocated. */ id?: string; } /** * Internal state of one relationships part. The DOM (`doc`) is the single * source of truth; {@link RelationshipSet} is a lens over it. * @internal */ interface RelsState { /** Absolute rels part name, e.g. '/word/_rels/document.xml.rels'. */ partName: string; /** Source part name (stored case) or null for the package level. */ sourceName: string | null; /** Live DOM of the rels XML. */ doc: XmlDocument; /** Zip entry name when backed by the source archive, else null. */ sourceEntryName: string | null; /** True when the part exists in the package (source-backed or materialized). */ exists: boolean; /** True when the DOM must be reserialized at save. */ dirty: boolean; /** Lazily-created lens. */ set: RelationshipSet | null; } /** * Live model of one .rels part (or the package-level /_rels/.rels). * * Lens invariant: mutations write through to the backing rels XML DOM * immediately and mark that part dirty, so save() reserializes it. Unknown * attributes/content in the rels XML are preserved. */ export declare class RelationshipSet { #private; /** @internal Construct via OpcPackage/OpcPart `relationships()` only. */ constructor(pkg: OpcPackage, state: object); /** All relationships in document order. */ all(): readonly Relationship[]; /** Look up by id. */ byId(id: string): Relationship | undefined; /** All relationships of the given type, in document order. */ byType(type: string): readonly Relationship[]; /** * Add a relationship (auto-allocating the smallest free 'rIdN' when no * id is given). Mutates the backing DOM immediately and marks the rels * part dirty; a set that has no backing part yet materializes it. Throws * when an explicit id already exists in the set. */ add(input: RelationshipInput): Relationship; /** Remove by id; true when one was removed. */ remove(id: string): boolean; } /** * One package part. Content is read lazily from the zip; writes replace * the content in memory and mark the part dirty. */ export declare class OpcPart { #private; /** Zip entry name in the source archive, or null for added parts. @internal */ readonly _sourceEntryName: string | null; /** * Bumped on every `write()`. The document layer compares this against * the value captured when it parsed the part's DOM, so a raw-bytes write * evicts stale cached DOMs (CONTRACTS.md §6.3). * @internal */ _writeVersion: number; /** @internal Construct via OpcPackage factories only. */ constructor(pkg: OpcPackage, name: string, sourceEntryName: string | null, data: Uint8Array | null, dirty: boolean); /** Absolute part name beginning with '/', stored-case preserved. */ get name(): string; /** * Resolved content type (Override first, else Default by extension). * Empty string when the package's [Content_Types].xml resolves nothing * for this part (possible only for parts read from foreign packages). */ get contentType(): string; /** * The part's bytes. Lazy: decompressed from the source zip on first * access (and cached); returns the written bytes after `write()`. */ read(): Promise; /** Replace the part's content and mark it dirty. */ write(data: Uint8Array): void; /** True when this part must be reserialized on save (not raw-copied). */ get dirty(): boolean; /** Force the dirty flag (used by higher layers after DOM mutation). */ markDirty(): void; /** * This part's relationships (from `/_rels/.rels`), an * empty live set when the part has none yet. Relationship parts are * parsed eagerly at package open, so this is synchronous. */ relationships(): RelationshipSet; } /** * A package over a zip archive. * * Opening eagerly parses [Content_Types].xml and every .rels part (all * small); all other part content stays lazy. Relationship parts and * [Content_Types].xml are never enumerated as parts. */ export declare class OpcPackage { #private; /** @internal Construct via {@link OpcPackage.open} / {@link OpcPackage.create}. */ constructor(internal?: symbol); /** * Open a package from zip bytes. Throws `Error` when the archive has no * [Content_Types].xml or when it (or any .rels part) fails to parse. */ static open(bytes: Uint8Array): Promise; /** * Create an empty package: [Content_Types].xml with Defaults for 'rels' * and 'xml', an empty package relationship set, no parts. */ static create(): OpcPackage; /** * Resolve the content type a part name would have under the current * [Content_Types].xml: an Override for the part name (case-insensitive) * wins, else the Default for its extension (case-insensitive), else * undefined. */ contentTypeOf(partName: string): string | undefined; /** All parts (excluding .rels and [Content_Types].xml), zip order. */ parts(): readonly OpcPart[]; /** * Look up a part by name. Comparison is ASCII case-insensitive per * ECMA-376 Part 2 part-name equivalence; a leading '/' is required * (throws otherwise). */ getPart(name: string): OpcPart | undefined; /** * All parts whose resolved content type equals `contentType` under * media-type equality ({@link mediaTypeEquals}: type/subtype compares * ASCII case-insensitively, parameters verbatim). The parts still report * their stored content-type values verbatim. */ getPartsByContentType(contentType: string): readonly OpcPart[]; /** * Parts targeted by package-level relationships of the given type * (Internal targets only), in relationship document order. */ getPartsByRelationshipType(relationshipType: string): readonly OpcPart[]; /** * Add a new part with the given content. Registers an Override in * [Content_Types].xml unless an existing Default already yields exactly * `contentType` for the part's extension. The new part is dirty. Throws * when a part with an equivalent name exists, when the name violates the * part-name grammar, or when the name belongs to package infrastructure. */ addPart(name: string, contentType: string, data: Uint8Array): OpcPart; /** * Remove a part, its .rels part (if any), and its Override entry (if * any). Does NOT touch relationships elsewhere that point at the part — * callers own referential integrity. True when the part existed. */ removePart(name: string): boolean; /** The package-level relationship set (/_rels/.rels), a live model. */ relationships(): RelationshipSet; /** @internal Relationship set for a part (used by OpcPart.relationships). */ _relationshipsFor(sourcePartName: string): RelationshipSet; /** @internal First `add` on a set with no backing part creates the part. */ _materializeRels(state: RelsState): void; /** * Resolve a relationship (by id) from `source` (null = package level) to * the part it targets. Undefined for external targets, unknown ids, and * missing parts. */ relatedPart(source: OpcPart | null, relationshipId: string): OpcPart | undefined; /** @internal Lazy source-zip read for OpcPart. */ _readSourceEntry(entryName: string | null, partName: string): Promise; /** * Serialize the package to zip bytes. * * L3 contract: parts that are not dirty are copied from the source zip * byte-for-byte (raw compressed stream, via the zip raw-copy path). * Dirty parts, [Content_Types].xml (when changed), and mutated .rels * parts are reserialized and deflated. Entry order: original zip order * for surviving entries, new parts appended in creation order. Created * packages write [Content_Types].xml first, then /_rels/.rels (Office * convention). */ save(): Promise; } export {}; //# sourceMappingURL=index.d.ts.map