Follow-on to #86, scoped lean for the last hour of the window. Four actions, one of them the biggest single feature so far: craft.db runs on in-process SQLite from the Zig archive.
dbExecute / dbQuery
Runs on the vendored SQLite the desktop already uses, with the same extern-fn bindings database.zig proved (no new @cImport, per the audit gate). Bind-only — no SQL is ever built by string formatting, and page-controlled column aliases are JSON-escaped on the way out.
Reply shapes match Swift byte-for-byte: dbExecute → {"rowsAffected":n,"lastInsertId":n}; dbQuery → a bare array of row objects (.fragmentsAllowed); BLOB columns omit their key; NULL is null; the db file is <Documents>/craft.db exactly — existing app data stays readable after migration.
The review pass caught two real defects pre-merge:
- a double-free in the query loop's unknown-column-type arm (manual
deinitunder an activeerrdefer) - a safety-panic on a ≥2³¹-byte sql/param (
@intCastintoc_int) — now refused asInvalidParameter, far above SQLite's own 1e9 limit so nothing honest is refused
cancelNotification / cancelAllNotifications
Guards [NSBundle mainBundle].bundleIdentifier before touching UNUserNotificationCenter — currentNotificationCenter raises an uncatchable NSInternalInconsistencyException in an unbundled process. The guard is proven live by a test walking the real ObjC path.
Build: SQLite into the iOS archives
Compiling sqlite3.c for an iOS target needs the SDK's libc headers, which Zig's bundled headers don't cover for C translation units. build.zig resolves the SDK per target through xcrun at configure time (iphoneos / iphonesimulator); absent xcrun the C source is skipped and the archive fails loudly at app link rather than silently shipping stubs.
Verification
Eleven fixture assertions on an iPhone 17 Pro simulator — the new one round-trips a value containing a quote through in-process SQLite (CREATE, bound INSERT, SELECT back, byte-identical), the only check that proves the archive's SQLite actually links and runs inside the app process:
ok: … (previous ten)
ok: dbExecute/dbQuery round-tripped through in-process SQLite (i=12 seen 1x)
PASSPlus zig build test / test:ios / build-ios / build-ios-simulator / build-android, zig fmt --check, pickier. Ratchet at 70.