Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
# `createChatDbFixture`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Builds a real `chat.db`-shaped SQLite database on a temp path using
the structural `SqliteReader` seam. This is the foundation of the
test strategy: every watcher / adapter test runs against a real
`bun:sqlite` database whose schema mirrors Apple's Messages app,
populated via the helpers returned by this factory. There are no
mocks anywhere in the call chain — the SQL the watcher executes in
production runs unchanged against the fixture.
## Features
- DDL covers the six tables the watcher reads:
`message`, `handle`, `chat`, `chat_message_join`, `attachment`,
`message_attachment_join` — with the exact column names + types
Apple's chat.db uses.
- Helpers return the inserted ROWID via a `SELECT ROWID ORDER BY
ROWID DESC LIMIT 1` so tests can wire foreign-key joins
deterministically without depending on `last_insert_rowid()`
semantics across reader implementations.
- `insertMessage(row, chatId)` writes both the message and its
`chat_message_join` row so the watcher's `JOIN cmj` query finds
the chat without extra wiring.
- `insertAttachment(row, messageId)` writes both the attachment and
its `message_attachment_join` row.
- `close()` closes the handle so the temp file can be deleted by the
caller's `afterEach`.
## Usage: Basic
```ts
import { tmpdir } from "node:os";
import { join } from "node:path";
import {
createBunSqliteReader,
createChatDbFixture,
} from "@suaveplan/imessage-adapter";
const reader = createBunSqliteReader();
const fixture = createChatDbFixture(reader, join(tmpdir(), "chat.db"));
const chatId = fixture.insertChat({
guid: "iMessage;+;+15551234567",
chat_identifier: "+15551234567",
display_name: null,
group_id: null,
service_name: "iMessage",
is_archived: 0,
});
fixture.close();
```
## Usage: Advanced
```ts
const handleId = fixture.insertHandle({
id: "+15551234567",
country: "us",
service: "iMessage",
uncanonicalized_id: null,
});
const messageId = fixture.insertMessage({
guid: "m-1",
text: "Hello",
handle_id: handleId,
service: "iMessage",
date: 700_000_000,
date_read: 0,
date_delivered: 0,
is_from_me: 0,
is_read: 1,
is_delivered: 1,
is_sent: 0,
cache_has_attachments: 1,
associated_message_guid: null,
associated_message_type: 0,
balloon_bundle_id: null,
group_title: null,
}, chatId);
fixture.insertAttachment({
guid: "a-1",
filename: "/tmp/photo.jpg",
mime_type: "image/jpeg",
total_bytes: 1024,
transfer_name: "photo.jpg",
}, messageId);
```
## API Reference
- `createChatDbFixture(reader, path): ChatDbFixture` — DDLs the schema
and returns the helpers.
- `ChatDbFixture.handle: SqliteHandle` — exposed for advanced custom
inserts.
- `insertHandle(row): number` — returns the new ROWID.
- `insertChat(row): number` — returns the new ROWID.
- `insertMessage(row, chatId?): number` — wires the
`chat_message_join` row when `chatId` is supplied.
- `insertAttachment(row, messageId): number` — wires the
`message_attachment_join` row.
- `close(): void` — closes the handle.
## Implementation Notes
The factory is server-tier-only because it requires a real SQLite
implementation, but it accepts any `SqliteReader` so a future
in-process SQLite-WASM reader could also drive the fixture. The
schema uses `AUTOINCREMENT` so insertion order maps to monotonically
increasing ROWIDs, which the watcher's `ROWID > lastRowId` cursor
relies on for incremental polling.