Skip to content

Releases: darecstowell/LembicKit

0.5.0: every format agrees, faster range changes, safer contacts

Choose a tag to compare

@darecstowell darecstowell released this 15 Oct 02:50
be6e483

LembicKit 0.5.0 makes every export format agree, makes scope changes fast, and closes a contacts gap in Release builds. It has no breaking API changes.

Highlights

PDF, DOCX, CSV, and XLSX now match the .txt. With a scrubber on, the prepared-record APIs can take the group roster, so Member N numbers and anonymize aliases are the same in every format of one export. Before, a group member who never wrote could shift the numbers.

Fast scope changes. The new Export.ScopeRenderer holds one conversation and renders any date range with the same output as Export.render(records:...). It runs the detectors and scrubbers once, not on each change. cancel() stops a pass in progress.

Release builds read only the real Contacts. A Release app no longer reads a bundled DemoData/contacts.vcf or the LEMBIC_CONTACTS variable, so a stray file cannot replace the user's names. Debug builds and the CLI still honor LEMBIC_CONTACTS.

Correct dates, counts, and order. A seconds-era date too large to convert is now an unknown date, not a wrong one. A 1:1 chat with more than one handle row no longer counts each message twice. Conversations with the same last date keep a stable order.

Upgrading from 0.4.0

  1. No code change is required. All old signatures still work.
  2. Recommended, if you render groups to PDF, DOCX, CSV, or XLSX: call preparedRedactedRecords(_:conversation:labels:scope:redactions:) or unredactedPreparedRecords(_:conversation:labels:scope:). These add the roster and Export.knownNames(for:labels:) for you, as render(_:) does. The group: overloads take the roster alone.
  3. If you re-render as the user changes a range: use Export.ScopeRenderer in place of repeated Export.render(records:...) calls.
  4. If you script the CLI: lembic-cli export now renders through Export.render, so note-to-self echoes drop and groups get speaker labels and a header. --sample --contacts now reads Contacts, so a TCC prompt can show.

Also fixed

  • The email ReDoS test no longer fails on a busy machine. It still catches the old slow regex.
  • Internal: one module for body splices, one rule table for detectors, and one schema read per extraction. Output is byte-for-byte the same.

Every change, with details: CHANGELOG.md

0.4.0: real anonymization, stable IDs, nothing dropped silently

Choose a tag to compare

@darecstowell darecstowell released this 15 Oct 01:02
ef8e94e

LembicKit 0.4.0 makes exports safer to share and harder to get wrong. Anonymize now hides real names, saved data survives renames, and no message is dropped or shown wrong without a trace. It is also much faster.

This is a pre-1.0 minor release with breaking changes. Read Upgrading from 0.3.1 before you update.

Highlights

Anonymize hides names everywhere, not only in labels. Contact, owner, and member names, and each part of them, are replaced in message text too. Enabled scrubbers also reach the header, group name, roster, labels, and event lines, so a phone number used as a group name is not left behind.

Saved data stays attached. Conversation.id is now stable (chat: plus the smallest chat.guid). A contact rename, a group rename, a member change, or a Contacts grant no longer moves it, so per-conversation settings and redactions stay with the right chat.

Redactions follow the message. A RedactionAnchor saves a keyed fingerprint of the hidden text. If the message changes, you can move the redaction or hide the whole message. A redaction that no longer fits hides the whole message: it fails closed.

Nothing leaks, nothing vanishes. Unsent text never appears. Failed sends and pending Send Later messages no longer read as sent. A damaged message is tagged [message may be incomplete], never shown as normal. Skipped rows are reported with a reason, not dropped.

More secrets flagged. New categories for ID numbers (passports, licenses, national and health IDs), recovery keys and backup codes, and Invisible Ink messages. Password and private key flags now cover the whole value.

macOS 14 works again. The schema check fails only on the core columns. A missing optional column turns off one feature, not the whole export.

Faster, same output. Secret detection is about 15 times faster on a 22,000-message thread (666 ms to 42 ms). On a 200,000-message thread, extraction drops from 4.5 s to 1.7 s and the text transcript from 1.8 s to 1.15 s.

Upgrading from 0.3.1

  1. Saved data keyed by Conversation.id: look up old keys in the new Conversation.legacyIDs and move the data to the new id once.
  2. Exhaustive switch on SecretCategory: add idNumber, recoveryKey, and invisibleInk.
  3. Renamed APIs: Export.records, Export.preparedRecords, and Rendered.records are now unredactedRecords, unredactedPreparedRecords, and Rendered.unredactedRecords. The old names still compile, with a deprecation warning.
  4. If you parse the output: the header now says "Messages transcript" (SMS and RCS export too), the header names its time zone, and JSONL "d" carries the UTC offset (2026-11-01T01:10:00-06:00).
  5. If you call the static prepared-record APIs with anonymize on: pass Export.knownNames(for:labels:) in scope.knownNames, as render(_:) does. Otherwise names in message text are not hidden.

Also fixed

  • Old rows stored in seconds show their real date (2016, not 2000-12-31). DST fall-back hours read correctly.
  • Group rosters are complete. Different groups no longer merge, and one group no longer splits when a member uses a second handle. Group events no longer tell a false story.
  • Stickers, Genmoji, voice-note transcriptions, Apple Pay, polls, and other app messages render. Placeholders sit where they belong.
  • Reactions on different parts of one message are counted apart.
  • Non-US contacts resolve to names. Business chats keep their real id. A note to self shows each note once.
  • Fewer false flags and missed secrets in the detectors and the code, email, and phone scrubbers.

Every change, with details: CHANGELOG.md

0.3.1

Choose a tag to compare

@darecstowell darecstowell released this 28 Jun 00:48
2758f3f

Patch release bundling six merged bug fixes (#5–#9, #11).

Security

  • Exclude unsent/retracted (Undo Send) messages from exports (#11)
  • Merge overlapping/nested redaction spans so no source text can leak (#8)
  • Harden the opt-in email scrubber regex against catastrophic backtracking / ReDoS (#7)
  • Stop the password and standing-code detectors from firing on ordinary prose (#5)

Fixed

  • Gate the space-separated SSN form on a nearby ssn/social security keyword (#6)
  • Region-aware phone normalization so non-US contacts resolve and union correctly (#9)

Full notes: CHANGELOG.md

0.3.0

Choose a tag to compare

@darecstowell darecstowell released this 19 Jun 19:28
7d58be8

Changed

  • Removed unsafeFlags from the package manifest so LembicKit can be consumed as a normal versioned SwiftPM dependency (.package(url:, from:)). The lembic-cli target no longer embeds an Info.plist; its --contacts against the system Contacts store now falls back to plain numbers, while the LEMBIC_CONTACTS vCard path and the Lembic app are unaffected.

Added

  • SECURITY.md, CONTRIBUTING.md, CHANGELOG.md, GitHub issue forms, and a pull-request template.

Fixed

  • Removed two stray tags at the end of the README.