Skip to content

cupertino-files / ObjectStore

Class: ObjectStore ​

Defined in: src/tsp/store.ts:134

Constructors ​

Constructor ​

new ObjectStore(container, options?): ObjectStore

Defined in: src/tsp/store.ts:156

Parameters ​

container ​

IWorkContainer

options? ​
app? ​

IWorkApp

containerParentOf? ​

ContainerParentResolver

referenceExtractors? ​

ReadonlyMap<number, ReferenceExtractor>

Returns ​

ObjectStore

Properties ​

app ​

readonly app: IWorkApp

Defined in: src/tsp/store.ts:137


components ​

readonly components: Component[] = []

Defined in: src/tsp/store.ts:136


container ​

readonly container: IWorkContainer

Defined in: src/tsp/store.ts:135


pendingFiles ​

readonly pendingFiles: Map<string, Uint8Array<ArrayBufferLike>>

Defined in: src/tsp/store.ts:328

Files to add to the package on save (e.g. "Data/photo.png").

Accessors ​

packageMetadata ​

Get Signature ​

get packageMetadata(): IwaObject

Defined in: src/tsp/store.ts:214

Returns ​

IwaObject

Methods ​

addDataFile() ​

addDataFile(data, preferredFileName): object

Defined in: src/tsp/store.ts:336

Register media bytes as a Data/ file: dedupes by SHA-1 digest against existing DataInfos, allocates a data-space identifier, appends the DataInfo to PackageMetadata and schedules the file for writing. Returns the data identifier and stored file name.

Parameters ​

data ​

Uint8Array

preferredFileName ​

string

Returns ​

object

dataId ​

dataId: bigint

fileName ​

fileName: string


allObjects() ​

allObjects(): IterableIterator<{ component: Component; obj: IwaObject; }>

Defined in: src/tsp/store.ts:208

Returns ​

IterableIterator<{ component: Component; obj: IwaObject; }>


allocateId() ​

allocateId(): bigint

Defined in: src/tsp/store.ts:228

Allocate a fresh object identifier. First allocation rounds the current maximum up to the next multiple of 1,000,000 (numbers-parser convention, keeping new IDs clear of Apple's); every allocation is recorded in PackageMetadata.last_object_identifier.

Returns ​

bigint


componentByLocator() ​

componentByLocator(locator): Component | undefined

Defined in: src/tsp/store.ts:185

Parameters ​

locator ​

string

Returns ​

Component | undefined


componentInfo() ​

componentInfo(component): RawMessage | undefined

Defined in: src/tsp/store.ts:380

ComponentInfo message inside PackageMetadata for a component, if any.

Parameters ​

component ​

Component

Returns ​

RawMessage | undefined


componentOf() ​

componentOf(id): Component | undefined

Defined in: src/tsp/store.ts:181

Parameters ​

id ​

bigint

Returns ​

Component | undefined


createComponent() ​

createComponent(locator, modeledOn): Component | undefined

Defined in: src/tsp/store.ts:472

Create an empty component and register it in the package metadata.

Measured from a Keynote-saved multi-slide deck (olekristensen-v26.3-mac-builds-effects.key): each slide lives in a component of its own whose ComponentInfo carries the slide's id as identifier, the bare kind as preferred locator ("Slide"), the full Slide-<id> as locator, the document read/write versions, an explicit is_stored_outside_object_archive: false, the save token, and the external references its content needs. modeledOn supplies everything content-dependent: versions and save token are copied from its info, and its external-reference rows are mirrored verbatim — right for a component whose objects reference the same styles and master as the donor's, which is what a slide copy does. The apps' own slide infos also carry per-object UUID map entries; a component created here has none, a difference Keynote accepted in every measured save.

Returns undefined when the package keeps no metadata (nothing to register against) or the locator lacks the Kind-<digits> shape.

Parameters ​

locator ​

string

modeledOn ​

Component

Returns ​

Component | undefined


createObject() ​

createObject(type, component, options?): IwaObject

Defined in: src/tsp/store.ts:248

Create a new object of the given type inside a component. The MessageInfo version list is copied from an existing sibling of the same type when one exists (falling back to [1, 0, 5], which is what numbers-parser writes). cloneFrom seeds the payload with a copy of another object's message.

Parameters ​

type ​

number

component ​

Component

options? ​
cloneFrom? ​

IwaObject

Returns ​

IwaObject


currentReferencesOf() ​

currentReferencesOf(obj): bigint[]

Defined in: src/tsp/store.ts:628

The references an object holds right now, computed from its message rather than read from the declarations, which refresh only at save.

The clone walk needs this: selecting from stale declarations made a copy of a just-inserted drawable share every owned child the original had — its title and caption stand-ins, and its mask had it been cropped — because none of them was declared yet. For an Apple-written object with no extractor the declarations are the truth, exactly as at save.

Parameters ​

obj ​

IwaObject

Returns ​

bigint[]


dataFileName() ​

dataFileName(dataId): string | undefined

Defined in: src/tsp/store.ts:521

File name registered for a Data/ identifier, from PackageMetadata.datas.

Parameters ​

dataId ​

bigint

Returns ​

string | undefined


declareComponentDependency() ​

declareComponentDependency(fromComponent, toComponentId): void

Defined in: src/tsp/store.ts:435

Ensure fromComponent's ComponentInfo carries a component-level external reference (no object identifier) to the component whose ComponentInfo identifier is toComponentId — the shape the apps use for whole-component dependencies, such as the document's row for each slide component.

Parameters ​

fromComponent ​

Component

toComponentId ​

bigint

Returns ​

void


declareReference() ​

declareReference(referrer, id): void

Defined in: src/tsp/store.ts:606

Declare that referrer now points at id, adding the cross-component bookkeeping if the two live apart.

retargetReference covers "this reference moved"; this covers "there is one more of them", which is what adding an entry to a list inside an existing archive needs. Both matter for the same reason: an undeclared reference into another component is how an app decides a document is damaged.

Parameters ​

referrer ​

IwaObject

id ​

bigint

Returns ​

void


findByType() ​

findByType(type): IwaObject | undefined

Defined in: src/tsp/store.ts:201

Parameters ​

type ​

number

Returns ​

IwaObject | undefined


isCreated() ​

isCreated(id): boolean

Defined in: src/tsp/store.ts:152

True for an object this library created rather than read.

Parameters ​

id ​

bigint

Returns ​

boolean


moveObjectsToComponent() ​

moveObjectsToComponent(ids, component): void

Defined in: src/tsp/store.ts:504

Move objects into component, keeping index and dirtiness straight. The objects' identities and payloads are untouched; only which IWA file they serialize into changes.

Parameters ​

ids ​

Iterable<bigint>

component ​

Component

Returns ​

void


object() ​

object(id): IwaObject | undefined

Defined in: src/tsp/store.ts:177

Parameters ​

id ​

bigint

Returns ​

IwaObject | undefined


prune() ​

prune(roots): number

Defined in: src/tsp/store.ts:288

Drop objects nothing can reach, and report how many went.

Deleting a sheet or a slide unlinks its archives but does not remove them: they sit in their component, unreferenced, and go on being written out. A document blanked from a real one is mostly this — a template with eleven tables becomes one table and ten ghosts.

Why the scan is deliberately crude ​

Reachability is computed by walking every submessage of every object and treating anything shaped like a TSP.Reference — a message whose only field is varint 1 — as a pointer, if that value names an object. No schema is consulted.

That over-approximates: a field that happens to hold an integer equal to some object's id keeps that object alive for no reason. This is the safe direction. The alternative, walking only the references this library knows how to extract, would silently drop whatever an unmodelled archive points at — and a document that loses an object it needed is unrecoverable, while one that keeps a few too many is merely larger than it could be.

Objects in components that failed to decode are never touched, and neither are the roots.

Parameters ​

roots ​

readonly bigint[]

Returns ​

number


referrers() ​

referrers(id): bigint[]

Defined in: src/tsp/store.ts:560

Objects declaring a reference to id, per MessageInfo.object_references.

The cheap, accurate way to ask "is this archive shared?" — Apple keeps the declarations current, so a style used by ten charts is named by ten objects. Answering by scanning payloads instead would mean parsing every archive in the document.

Only as good as the declarations: an object whose references this library has not recomputed reports what it reported when Apple wrote it. For deciding whether to copy-on-write, that errs toward copying, which is the safe direction.

Parameters ​

id ​

bigint

Returns ​

bigint[]


resolve() ​

resolve(ref): IwaObject | undefined

Defined in: src/tsp/store.ts:190

Resolve a TSP.Reference message (field 1 = identifier) to its object.

Parameters ​

ref ​

bigint | RawMessage | undefined

Returns ​

IwaObject | undefined


retargetReference() ​

retargetReference(referrer, oldId, newId): void

Defined in: src/tsp/store.ts:585

Note that referrer now points at newId where it pointed at oldId.

Used after copy-on-write: the payload has been repointed, and the bookkeeping has to follow. Doing it here rather than through a ReferenceExtractor is deliberate — an extractor replaces the whole declared list, so writing one for a type as broad as TSCH.ChartDrawableArchive would silently drop every reference it failed to enumerate. This changes exactly the one that moved.

oldId is dropped only when the payload no longer mentions it: one archive can be pointed at from several slots, and a shared style being privatised for series 2 may still be in use by series 4. The membership test over-approximates, so the failure mode is keeping a declaration a little too long — harmless, since the object still exists — rather than dropping a live one.

Parameters ​

referrer ​

IwaObject

oldId ​

bigint

newId ​

bigint

Returns ​

void


save() ​

save(): Uint8Array

Defined in: src/tsp/store.ts:663

Serialize the document. Recomputes reference bookkeeping for dirty objects, then rebuilds only the components that changed.

Returns ​

Uint8Array


staleCompatibilityPatches() ​

staleCompatibilityPatches(): object[]

Defined in: src/tsp/store.ts:537

Objects edited in this session that carry older-reader compatibility diffs (see IwaObject.compatibilityPatchVersions). The diffs are preserved verbatim but NOT recomputed, so an older app opening the saved document would apply a stale diff for those objects. Empty in practice unless you edit UI-state objects.

Returns ​

object[]


typeNameOf() ​

typeNameOf(object): string | undefined

Defined in: src/tsp/store.ts:197

Registry name of an object's archive type, resolved for this app.

Parameters ​

object ​

IwaObject

Returns ​

string | undefined

MIT licensed. Independently made — not by Apple in California. Not affiliated with or endorsed by Apple Inc.