Skip to content

A native Interchange mailbox, and nothing else - #20

Merged
TheGreatAxios merged 17 commits into
mainfrom
native-mailbox-store
Sep 17, 2026
Merged

TheGreatAxios merged 17 commits into
mainfrom
native-mailbox-store

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Contributor

Summary

Owner ruling: @corbits/mailbox exists ONLY to give human principals a
native Interchange mailbox (createPrincipalMailboxStore /
NativeMailboxStore over mailbox.principal_mail + mailbox.mailbox_state,
vendored @intx/mailbox on top). Everything else — triage
(priority/classification/status/assignee), delegation/assign, this
package's own threading/search, /me/threads*, the pre-native
read/write model — is deleted.

Four commits, in order:

  1. Delete tests of the pre-native mailbox model — every test
    file/describe exercising triage columns, readAt/archivedAt/trashedAt,
    this library's own threading/search, /me/threads*, and the mount
    routes/features tied to them.
  2. Routes over the native store — mount.ts is now a thin wrapper:
    GET /me/inbox (vendored executeSearch over open(folder), keyset
    by uid, envelope+raw fetched per ref), POST /me/inbox/:uid/read| unread (addFlags/removeFlags \Seen), archive|trash|restore
    (moveNativeMailboxMessage), GET /me/inbox/events (SSE, unchanged).
    read.ts, thread.ts, mutations.ts, vocabulary.ts are deleted.
    write.ts (writeMailboxMessage, deliverInboxItems) and
    persist.ts (the transport dual-write seam) now land every write
    through NativeMailboxStore.append.
  3. Drop the pre-native columns — migration 0005_drop_pre_native_ columns drops mailbox.mailbox (the read_at/archived_at/trashed_at/
    priority/classification/status/assignee management table — nothing
    reads it anymore) and sets principal_mail.uid/modseq NOT NULL.
    schema.ts, schema-check.ts, and the DDL parity test follow.
  4. Docs — README rewritten to the one-job statement and the
    surviving routes/write paths; package.json bumped to 1.0.0 for
    the breaking cut.

Line counts

  • origin/main (pre-vendoring, full pre-native model): 15,632 lines in src/
  • Branch base (54f657f, native store added, old model still present): 16,288 lines
  • This PR's src/ after Slice B: 6,355 lines — a 60% cut from the branch base

Vendored ledger

Unchanged by this slice — VENDORED.md still lists vendor/intx-mailbox,
vendor/intx-mime, vendor/intx-types at the same pinned commit, kill
condition still "first npm publish of @intx/mailbox". Note for whoever
picks this up next: publish @intx/mailbox (and a matching
@intx/mime/@intx/types npm refresh) to retire all three vendored rows.

Remaining public API

  • mountMailbox (routes above), MAX_MAILBOX_PAGE_LIMIT, MAX_PENDING_SSE_EVENTS
  • runMailboxMigrations, MigrationChecksumError
  • assertExpectedColumnTypes, expectedColumnTypes, SchemaTypeMismatchError
  • createMailboxDb
  • createPrincipalMailboxStore, openNativeMailboxStore, moveNativeMailboxMessage
  • principalMail, mailboxPgSchema (schema/table exports)
  • assertMailboxScope, assertMailboxTenantId, MAX_MAILBOX_FRAME_BYTES, assertMailboxFrameBytes
  • purgeTenantMailbox, purgePrincipalMailbox
  • createInMemoryMailboxEventBus, MailboxEventSchema, MAILBOX_EVENT_OPS (now 6 ops, no enrich/assign)
  • writeMailboxMessage, deliverInboxItems
  • buildMailFrame, generateMailboxMessageId, MESSAGE_ID_FALLBACK_DOMAIN
  • createMailboxPersist, MAX_MAILBOX_RECIPIENTS
  • parseAddressList, resolveMailboxRecipients

Deleted from the public API: writeMailboxMessages, mailboxKey,
MAX_MAILBOX_REFS/refs support, all of read.ts's exports (list/
filter/sort/enrichment/sender-display), all of thread.ts's exports,
all of mutations.ts's exports (enrich/assign/bulk), all of
vocabulary.ts's exports — mountMailbox no longer takes a
vocabulary or resolveSenderDisplays option.

Test plan

  • bun run typecheck green (pre-existing, unrelated errors only in
    examples/reference-host, not touched by this PR)
  • bun test src green — 156 pass, 2 pre-existing/unrelated fails in
    recipients.test.ts (isRunAddress from intx-types-compat.ts
    not recognizing ins_ addresses — present before this PR's first
    commit, untouched by any of these changes)
  • CI

The library now does exactly one thing: a native Interchange mailbox
for human principals. README documents the surviving routes and write
paths; package.json bumps to 1.0.0 for the breaking API cut.
The published tarball listed @intx/mailbox, @intx/mime, and @intx/types
as workspace:* devDependencies only, so a plain npm/node consumer had
no way to resolve them at runtime (CI's node consumer smoke test caught
this: `Cannot find package '@intx/mailbox'`). @intx/mailbox has never
been published, so there is nothing on npm to depend on instead.

scripts/build.mjs now bundles the three vendored packages straight into
dist/index.js via `bun build` (everything else stays external), and
compiles their declarations separately into dist/vendor/<name>/,
rewriting the bare specifiers in every emitted .d.ts to relative paths
so a consumer's own tsc can resolve them too. @intx/mime and
@intx/types drop out of peerDependencies; @intx/crypto (a real,
byte-identical npm dependency the vendored code imports at runtime)
moves from devDependencies to dependencies.
package.json's sideEffects: false is metadata for a CONSUMER's bundler.
On Linux, bun build read that same field for this package's own build
and collapsed src/index.ts's re-export-only module to a bare
'export { ... }' stub with every import deleted, leaving the export
list referencing nothing — every named export threw "X is not
declared in this file" at import time. --ignore-dce-annotations makes
bun bundle its own build honestly regardless of that field.
The bun bundler's own tree-shaking (even with --ignore-dce-annotations,
per the previous commit) still produced a dist/index.js under bun on
Linux where named exports were declared but not defined, failing the
reference-host acceptance job. Bundling is gone: tsc now emits our own
src/ and the three vendored @intX packages as plain module-for-module
JS + d.ts, and every bare @intx/* import plus every vendored package's
own extensionless relative import is rewritten to a relative dist/
path afterward.

mountMailbox gains a POST /me/inbox/send route: builds an RFC 5322
message via the vendored frame builder, appends it to the caller's
Sent folder through the native store, and hands it to a new required
deliver mount dep — this package still owns no transport of its own.
@TheGreatAxios
TheGreatAxios merged commit e85b81e into main Sep 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant