Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
bd0381c
-
KishanBagaria May 3, 2026
4b40af3
-
KishanBagaria May 3, 2026
6233fad
-
KishanBagaria May 3, 2026
47265ff
-
KishanBagaria May 3, 2026
3bac14d
Update todos.md
KishanBagaria May 3, 2026
af9ad51
-
KishanBagaria May 3, 2026
41bc82f
Update IMDatabase+MappedMessages.swift
KishanBagaria May 3, 2026
192df7f
Update IMDatabase+MappedMessages.swift
KishanBagaria May 3, 2026
a1e7ed4
-
KishanBagaria May 3, 2026
a5e85a8
Update PlatformAPI+Hashing.swift
KishanBagaria May 3, 2026
aa0faa2
Update ServerEvent.swift
KishanBagaria May 3, 2026
52aa114
-
KishanBagaria May 3, 2026
b7b47a5
-
KishanBagaria May 3, 2026
93a2135
-
KishanBagaria May 3, 2026
903d194
remove chatref
KishanBagaria May 3, 2026
e22dc17
Update EventWatcher+Updates.swift
KishanBagaria May 3, 2026
99ed2a9
Update EventWatcher+Updates.swift
KishanBagaria May 3, 2026
7f1a86d
Update EventWatcher+Updates.swift
KishanBagaria May 4, 2026
bfce1f5
Update EventWatcher+Updates.swift
KishanBagaria May 4, 2026
664ffd9
Update ServerEvent.swift
KishanBagaria May 4, 2026
1b2dcad
-
KishanBagaria May 4, 2026
abf401e
Update EventWatcher+Updates.swift
KishanBagaria May 4, 2026
74ce7f4
dedup message GUID lookups
pmanot May 4, 2026
32023d8
use OrderedSet
pmanot May 4, 2026
6577b22
dedup rowIDs
pmanot May 4, 2026
6518f39
optimize date_read and date_edited lookup
pmanot May 4, 2026
f8fd1de
unify imCoreDate helper
pmanot May 4, 2026
97a2b53
refactor
pmanot May 4, 2026
472fcd0
wip
pmanot May 5, 2026
c0591b6
use GRDB
pmanot May 6, 2026
6adc1de
Add live IMDatabase SQL tests
pmanot May 6, 2026
8b5a13d
update gitignore
pmanot May 6, 2026
8ac9d0c
update tests
pmanot May 6, 2026
4f82ac9
add SQL performance benchmark
pmanot May 7, 2026
b72f5b7
optimize GRDB mapped SQL hot paths
pmanot May 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ DerivedData/
.*.history.json
.claude
.build
.swiftpm
50 changes: 36 additions & 14 deletions .parity/check-swift-mapper-parity.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { app } from 'electron'
import * as fs from 'node:fs/promises'
import * as path from 'node:path'
import { fileURLToPath } from 'node:url'

Expand Down Expand Up @@ -31,7 +32,7 @@ const {
const args = parseArgs(process.argv.slice(2))

const referenceRoot = path.resolve(args.get('reference-root') ?? path.join(repoRoot, '.parity/platform-imessage-main'))
const defaultReferenceIMessageNodePath = path.join(referenceRoot, 'binaries', `${process.platform}-${process.arch}`, 'IMessage.node')
const defaultReferenceIMessageNodePath = path.join(referenceRoot, 'binaries', `${process.platform}-${process.arch}`, 'SwiftServer.node')
const referenceIMessageNodePath = args.get('reference-swift-server-node') ?? defaultReferenceIMessageNodePath
const referenceBinariesDirPath = args.get('reference-binaries-dir') ?? path.dirname(path.dirname(referenceIMessageNodePath))

Expand Down Expand Up @@ -229,21 +230,34 @@ function searchTermsFromMessage(message) {
}

if (childRole) {
await runAPIChild({
role: childRole,
try {
await runAPIChild({
role: childRole,
repoRoot,
referenceAPIPath: args.get('reference-api-bundle'),
referenceBinariesDirPath,
})
process.exit(process.exitCode ?? 0)
} catch (error) {
console.error(error instanceof Error ? error.stack ?? error.message : String(error))
app.exit(1)
process.exit(1)
}
}

let referenceAPIPath
try {
referenceAPIPath = await ensureReferenceAPI({
args,
repoRoot,
referenceAPIPath: args.get('reference-api-bundle'),
referenceRoot,
referenceBinariesDirPath,
})
process.exit(0)
} catch (error) {
console.error(error instanceof Error ? error.stack ?? error.message : String(error))
app.exit(1)
process.exit(1)
}

const referenceAPIPath = await ensureReferenceAPI({
args,
repoRoot,
referenceRoot,
referenceBinariesDirPath,
})
const childAPIs = [
spawnAPIChild({
role: 'current',
Expand Down Expand Up @@ -500,7 +514,7 @@ try {
byDiff[failure.details] = (byDiff[failure.details] ?? 0) + 1
}

console.log(JSON.stringify({
const summary = {
chatLimit: formatLimit(chatLimit),
skipChats,
messageLimitPerChat: formatLimit(messageLimit),
Expand All @@ -521,7 +535,15 @@ try {
byDiff,
perfDeltas: summarizePerfDeltas(),
failures,
}, null, 2))
}
const summaryJSON = JSON.stringify(summary, null, 2)
const outputJSONPath = args.get('output-json')
if (outputJSONPath) {
await fs.writeFile(outputJSONPath, `${summaryJSON}\n`)
}
if (!args.has('no-stdout-json')) {
console.log(summaryJSON)
}

process.exitCode = failures.length === 0 ? 0 : 1
} finally {
Expand Down
7 changes: 7 additions & 0 deletions .parity/parity-child-processes.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ export async function runAPIChild(options) {
writeIPC({ id: request.id, ok: false, error: serializeError(result.error), ms: result.ms })
}
}
} catch (error) {
writeIPC({ type: 'startup-error', error: serializeError(error) })
process.exitCode = 1
} finally {
await Promise.resolve(api?.dispose?.()).catch(() => {})
if (dataDirPath) await fs.rm(dataDirPath, { recursive: true, force: true }).catch(() => {})
Expand Down Expand Up @@ -177,6 +180,10 @@ export function spawnAPIChild({
readyResolve()
return
}
if (message.type === 'startup-error') {
readyReject(deserializeError(message.error))
return
}

const request = pending.get(message.id)
if (!request) return
Expand Down
41 changes: 39 additions & 2 deletions .parity/parity-utils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,43 @@ export function exec(command, commandArgs, cwd) {
execFileSync(command, commandArgs, { cwd, stdio: 'inherit' })
}

async function ensureReferenceDependencies(referenceRoot) {
if (!await pathExists(path.join(referenceRoot, 'node_modules'))) {
exec('yarn', [], referenceRoot)
}
}

async function findReferenceNativeModule(referenceBinariesDirPath) {
const archBinariesDirPath = path.join(referenceBinariesDirPath, `${process.platform}-${process.arch}`)
for (const fileName of ['IMessage.node', 'SwiftServer.node']) {
const candidate = path.join(archBinariesDirPath, fileName)
if (await pathExists(candidate)) return candidate
}
return undefined
}

async function ensureReferenceNativeModule({ args, referenceRoot, referenceBinariesDirPath }) {
if (args.get('reference-swift-server-node')) return
if (await findReferenceNativeModule(referenceBinariesDirPath)) return

if (args.has('skip-reference-rebuild') && !args.has('rebuild-reference')) {
throw new Error(
`Reference native module is missing under ${path.join(referenceBinariesDirPath, `${process.platform}-${process.arch}`)}. ` +
'Run again without --skip-reference-rebuild, or pass --reference-binaries-dir to a directory containing the reference Swift .node binary.',
)
}

await ensureReferenceDependencies(referenceRoot)
exec('bun', ['build:swift', '--standalone'], referenceRoot)

if (!await findReferenceNativeModule(referenceBinariesDirPath)) {
throw new Error(
`Reference Swift build finished, but no IMessage.node or SwiftServer.node was found under ` +
`${path.join(referenceBinariesDirPath, `${process.platform}-${process.arch}`)}.`,
)
}
}

export async function readDefaultReferenceRef(repoRoot) {
const refFile = path.join(repoRoot, '.parity/REFERENCE_REF')
try {
Expand Down Expand Up @@ -73,9 +110,9 @@ export async function ensureReferenceAPI({
didCreateReferenceRoot = true
}
if (didCreateReferenceRoot) {
exec('yarn', [], referenceRoot)
exec('bun', ['build:swift', '--standalone'], referenceRoot)
await ensureReferenceDependencies(referenceRoot)
}
await ensureReferenceNativeModule({ args, referenceRoot, referenceBinariesDirPath })
if (!args.has('skip-reference-rebuild') || args.has('rebuild-reference') || !await pathExists(bundlePath)) {
const binariesDirPathLiteral = JSON.stringify(referenceBinariesDirPath)
const buildBanner = `globalThis.texts={IS_DEV:true,isLoggingEnabled:false,log(){},error(){},constants:{USER_AGENT:'platform-imessage-parity',APP_VERSION:'1.0.0'},Sentry:{captureException(){},captureMessage(){},startTransaction(){}},async trackPlatformEvent(){},getBinariesDirPath(){return ${binariesDirPathLiteral}},fetch:globalThis.fetch,fetchStream:undefined,createHttpClient:undefined,nativeFetch:undefined,nativeFetchStream:undefined,runWorker:undefined,forkChildProcess:undefined,getOriginalObject:undefined,openBrowserWindow:undefined};`
Expand Down
9 changes: 9 additions & 0 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 21 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var products: [Product] = [
targets: ["IMessage"]
),
.executable(name: "imessage-cli", targets: ["IMessageCLI"]),
.executable(name: "IMessagePerfBench", targets: ["IMessagePerfBench"]),
]

var dependencies: [Package.Dependency] = [
Expand All @@ -24,6 +25,7 @@ var dependencies: [Package.Dependency] = [
.package(url: "https://github.com/apple/swift-collections.git", from: "1.2.0"),
.package(url: "https://github.com/apple/swift-async-algorithms", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.6.1"),
.package(url: "https://github.com/groue/GRDB.swift.git", from: "6.29.3"),
.package(url: "https://github.com/swiftlang/swift-syntax.git", exact: "603.0.0-prerelease-2025-10-30"),
]

Expand Down Expand Up @@ -76,13 +78,21 @@ var targets: [Target] = [
dependencies: ["SQLite"],
path: "src/IMessage/Sources/SQLiteTests"
),
.testTarget(
name: "IMDatabaseTests",
dependencies: [
"IMDatabase",
.product(name: "GRDB", package: "GRDB.swift"),
],
path: "src/IMessage/Sources/IMDatabaseTests"
),
.target(
name: "IMDatabase",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
.product(name: "Collections", package: "swift-collections"),
"SQLite",
.product(name: "GRDB", package: "GRDB.swift"),
"ExceptionCatcher",
"IMessageCore",
],
Expand All @@ -98,6 +108,16 @@ var targets: [Target] = [
path: "src/IMessage/Sources/IMessageCLI",
plugins: ["GenerateIMessageCLIVersionPlugin"]
),
.executableTarget(
name: "IMessagePerfBench",
dependencies: [
"IMDatabase",
"IMessage",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
],
path: "src/IMessage/Sources/IMessagePerfBench",
exclude: ["README.md"]
),
.plugin(
name: "GenerateIMessageCLIVersionPlugin",
capability: .buildTool(),
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"lint:js": "yarn eslint src --ext ts,tsx,js,jsx --cache",
"cli:js": "env NODE_OPTIONS=\"--force-node-api-uncaught-exceptions-policy=true\" electron cli.compiled.mjs",
"cli": "swift run imessage-cli",
"perf:imessage": "node scripts/imessage-perf.mjs",
"swift-mapper-parity": "yarn build:swift-mapper-parity && env NODE_OPTIONS=\"--force-node-api-uncaught-exceptions-policy=true\" electron .parity/check-swift-mapper-parity.compiled.mjs",
"build:cli:release": "sh -c 'swift build -c release --product imessage-cli >/dev/null && bin_path=$(swift build -c release --product imessage-cli --show-bin-path) && printf \"%s/imessage-cli\\n\" \"$bin_path\"'",
"build:cli:js": "bun build src/cli/index.ts --target=node --format=esm --external electron --external @textshq/platform-test-lib --outfile=cli.compiled.mjs",
Expand Down
Loading
Loading