@leemour/cli-messaging 0.66.0 → 0.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli/messenger/processes.d.ts +6 -0
- package/dist/cli/messenger/processes.d.ts.map +1 -1
- package/dist/cli/messenger/processes.js +42 -1
- package/dist/cli/messenger/processes.js.map +1 -1
- package/dist/cli/messenger/store-maintenance-command.d.ts.map +1 -1
- package/dist/cli/messenger/store-maintenance-command.js +140 -4
- package/dist/cli/messenger/store-maintenance-command.js.map +1 -1
- package/dist/store/sqlite/accounts.d.ts +6 -0
- package/dist/store/sqlite/accounts.d.ts.map +1 -0
- package/dist/store/sqlite/accounts.js +18 -0
- package/dist/store/sqlite/accounts.js.map +1 -0
- package/dist/store/sqlite/chats.d.ts +17 -0
- package/dist/store/sqlite/chats.d.ts.map +1 -0
- package/dist/store/sqlite/chats.js +105 -0
- package/dist/store/sqlite/chats.js.map +1 -0
- package/dist/store/sqlite/drizzle/bun.js +1 -1
- package/dist/store/sqlite/drizzle/core.d.ts +1 -1
- package/dist/store/sqlite/drizzle/core.d.ts.map +1 -1
- package/dist/store/sqlite/drizzle/core.js +11 -1
- package/dist/store/sqlite/drizzle/node.js +1 -1
- package/dist/store/sqlite/drizzle/{shared-ZF3LACGD.js → shared-I773JEFB.js} +6 -1
- package/dist/store/sqlite/identities.d.ts +23 -0
- package/dist/store/sqlite/identities.d.ts.map +1 -0
- package/dist/store/sqlite/identities.js +169 -0
- package/dist/store/sqlite/identities.js.map +1 -0
- package/dist/store/sqlite/values.d.ts +8 -0
- package/dist/store/sqlite/values.d.ts.map +1 -0
- package/dist/store/sqlite/values.js +11 -0
- package/dist/store/sqlite/values.js.map +1 -0
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +29 -200
- package/dist/store/store.js.map +1 -1
- package/package.json +1 -1
- /package/dist/store/sqlite/drizzle/{shared-ZF3LACGD.js.map → shared-I773JEFB.js.map} +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Contact, Id, Page, Provider } from "../../domain/models.js";
|
|
2
|
+
import type { PeopleLookup } from "../../resolve.js";
|
|
3
|
+
import type { AccountKey, PersonFacts } from "../store.js";
|
|
4
|
+
import type { StoreContext } from "./open.js";
|
|
5
|
+
type Facts = Omit<PersonFacts, "id" | "name">;
|
|
6
|
+
/** Every new identity gets its own person; linking two is a later, recorded act. */
|
|
7
|
+
export declare const identityOf: ({ orm, now }: StoreContext, provider: Provider, nativeId: Id, name: string | null, facts?: Facts) => number;
|
|
8
|
+
/** An identity as `accountKey` saw it — recorded as seen by that account, so reads stay per account. */
|
|
9
|
+
export declare const identityPk: (context: StoreContext, accountKey: number, provider: Provider, nativeId: Id, name: string | null, facts?: Facts) => number;
|
|
10
|
+
export declare const people: ({ orm }: StoreContext, provider: Provider, { account, accounts: native }: {
|
|
11
|
+
account?: Id;
|
|
12
|
+
accounts?: Id[];
|
|
13
|
+
}) => PeopleLookup;
|
|
14
|
+
export declare const contacts: ({ orm }: StoreContext, accountKey: number, key: AccountKey, { order, query, limit, offset }: {
|
|
15
|
+
order: "recent" | "name";
|
|
16
|
+
query?: string;
|
|
17
|
+
limit: number;
|
|
18
|
+
offset?: number;
|
|
19
|
+
}) => Page<Contact>;
|
|
20
|
+
export declare const countContacts: ({ orm }: StoreContext, accountKey: number, key: AccountKey, query: string | undefined) => number;
|
|
21
|
+
export declare const refreshRecency: ({ orm }: StoreContext, accountKey: number) => void;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=identities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identities.d.ts","sourceRoot":"","sources":["../../../src/store/sqlite/identities.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG1D,OAAO,KAAK,EAAO,YAAY,EAAE,MAAM,WAAW,CAAA;AAalD,KAAK,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,CAAA;AAqC7C,oFAAoF;AACpF,eAAO,MAAM,UAAU,iBACP,YAAY,YAChB,QAAQ,YACR,EAAE,QACN,MAAM,GAAG,IAAI,UACZ,KAAK,KACX,MAgEF,CAAA;AAED,wGAAwG;AACxG,eAAO,MAAM,UAAU,YACZ,YAAY,cACT,MAAM,YACR,QAAQ,YACR,EAAE,QACN,MAAM,GAAG,IAAI,UACZ,KAAK,KACX,MAIF,CAAA;AAED,eAAO,MAAM,MAAM,YACR,YAAY,YACX,QAAQ,iCACa;IAAE,OAAO,CAAC,EAAE,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAA;CAAE,KAC/D,YAiBF,CAAA;AAmBD,eAAO,MAAM,QAAQ,YACV,YAAY,cACT,MAAM,OACb,UAAU,mCACsB;IAAE,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAChH,IAAI,CAAC,OAAO,CAqBd,CAAA;AAED,eAAO,MAAM,aAAa,YACf,YAAY,cACT,MAAM,OACb,UAAU,SACR,MAAM,GAAG,SAAS,KACxB,MAQA,CAAA;AAEH,eAAO,MAAM,cAAc,YAAa,YAAY,cAAc,MAAM,KAAG,IAU1E,CAAA"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { CliError } from "@leemour/cli-core";
|
|
2
|
+
import { ulid } from "../ulid.js";
|
|
3
|
+
import { and, eq, inArray, ne, sql } from "./drizzle/core.js";
|
|
4
|
+
import { accountIdentities, accounts, chatMembers, chats, identities, identityLinkEvents, identityLinks, persons, } from "./schema.js";
|
|
5
|
+
import { toIso } from "./values.js";
|
|
6
|
+
const flag = (value) => (value === undefined || value === null ? null : Number(value));
|
|
7
|
+
const prepare = (orm) => ({
|
|
8
|
+
find: orm
|
|
9
|
+
.select({
|
|
10
|
+
pk: identities.pk,
|
|
11
|
+
name: identities.name,
|
|
12
|
+
username: identities.username,
|
|
13
|
+
isBot: identities.isBot,
|
|
14
|
+
description: identities.description,
|
|
15
|
+
})
|
|
16
|
+
.from(identities)
|
|
17
|
+
.where(and(eq(identities.provider, sql.placeholder("provider")), eq(identities.nativeId, sql.placeholder("nativeId"))))
|
|
18
|
+
.prepare(),
|
|
19
|
+
seen: orm
|
|
20
|
+
.insert(accountIdentities)
|
|
21
|
+
.values({
|
|
22
|
+
accountPk: sql.placeholder("accountPk"),
|
|
23
|
+
identityPk: sql.placeholder("identityPk"),
|
|
24
|
+
firstSeenAt: sql.placeholder("firstSeenAt"),
|
|
25
|
+
})
|
|
26
|
+
.onConflictDoNothing()
|
|
27
|
+
.prepare(),
|
|
28
|
+
});
|
|
29
|
+
// Built once per store: both run for every message saved, and building a Drizzle query costs more than running it.
|
|
30
|
+
const prepared = new WeakMap();
|
|
31
|
+
const statementsOf = (orm) => {
|
|
32
|
+
const statements = prepared.get(orm) ?? prepare(orm);
|
|
33
|
+
prepared.set(orm, statements);
|
|
34
|
+
return statements;
|
|
35
|
+
};
|
|
36
|
+
/** Every new identity gets its own person; linking two is a later, recorded act. */
|
|
37
|
+
export const identityOf = ({ orm, now }, provider, nativeId, name, facts = {}) => {
|
|
38
|
+
const found = statementsOf(orm).find.get({ provider, nativeId });
|
|
39
|
+
if (found) {
|
|
40
|
+
const changed = {
|
|
41
|
+
name: name ?? found.name,
|
|
42
|
+
username: facts.username ?? found.username,
|
|
43
|
+
isBot: flag(facts.isBot) ?? found.isBot,
|
|
44
|
+
description: facts.description ?? found.description,
|
|
45
|
+
};
|
|
46
|
+
// Only on a real change: the search trigger rewrites the index row on every update of `name`.
|
|
47
|
+
if (changed.name !== found.name ||
|
|
48
|
+
changed.username !== found.username ||
|
|
49
|
+
changed.isBot !== found.isBot ||
|
|
50
|
+
changed.description !== found.description) {
|
|
51
|
+
orm
|
|
52
|
+
.update(identities)
|
|
53
|
+
.set({ ...changed, updatedAt: now() })
|
|
54
|
+
.where(eq(identities.pk, found.pk))
|
|
55
|
+
.run();
|
|
56
|
+
}
|
|
57
|
+
return found.pk;
|
|
58
|
+
}
|
|
59
|
+
const at = now();
|
|
60
|
+
const identity = Number(orm
|
|
61
|
+
.insert(identities)
|
|
62
|
+
.values({
|
|
63
|
+
provider,
|
|
64
|
+
nativeId,
|
|
65
|
+
name,
|
|
66
|
+
username: facts.username ?? null,
|
|
67
|
+
isBot: flag(facts.isBot),
|
|
68
|
+
description: facts.description ?? null,
|
|
69
|
+
firstSeenAt: at,
|
|
70
|
+
updatedAt: at,
|
|
71
|
+
})
|
|
72
|
+
.returning({ pk: identities.pk })
|
|
73
|
+
.get()?.pk);
|
|
74
|
+
const person = Number(orm
|
|
75
|
+
.insert(persons)
|
|
76
|
+
.values({ uid: ulid(at), name, createdAt: at, updatedAt: at })
|
|
77
|
+
.returning({ pk: persons.pk })
|
|
78
|
+
.get()?.pk);
|
|
79
|
+
orm
|
|
80
|
+
.insert(identityLinks)
|
|
81
|
+
.values({
|
|
82
|
+
identityPk: identity,
|
|
83
|
+
personPk: person,
|
|
84
|
+
method: "initial",
|
|
85
|
+
confidence: 1,
|
|
86
|
+
linkedAt: at,
|
|
87
|
+
linkedBy: "ingest",
|
|
88
|
+
})
|
|
89
|
+
.run();
|
|
90
|
+
orm
|
|
91
|
+
.insert(identityLinkEvents)
|
|
92
|
+
.values({ identityPk: identity, fromPersonPk: null, toPersonPk: person, method: "initial", at, by: "ingest" })
|
|
93
|
+
.run();
|
|
94
|
+
return identity;
|
|
95
|
+
};
|
|
96
|
+
/** An identity as `accountKey` saw it — recorded as seen by that account, so reads stay per account. */
|
|
97
|
+
export const identityPk = (context, accountKey, provider, nativeId, name, facts = {}) => {
|
|
98
|
+
const identity = identityOf(context, provider, nativeId, name, facts);
|
|
99
|
+
statementsOf(context.orm).seen.run({ accountPk: accountKey, identityPk: identity, firstSeenAt: context.now() });
|
|
100
|
+
return identity;
|
|
101
|
+
};
|
|
102
|
+
export const people = ({ orm }, provider, { account, accounts: native }) => {
|
|
103
|
+
const within = native ?? (account === undefined ? undefined : [account]);
|
|
104
|
+
const seenBy = within &&
|
|
105
|
+
orm
|
|
106
|
+
.select({ pk: accountIdentities.identityPk })
|
|
107
|
+
.from(accountIdentities)
|
|
108
|
+
.innerJoin(accounts, eq(accounts.pk, accountIdentities.accountPk))
|
|
109
|
+
.where(and(eq(accounts.provider, provider), inArray(accounts.nativeId, within)));
|
|
110
|
+
const everyone = orm
|
|
111
|
+
.select({ id: identities.nativeId, name: identities.name, username: identities.username })
|
|
112
|
+
.from(identities)
|
|
113
|
+
.where(and(eq(identities.provider, provider), seenBy ? inArray(identities.pk, seenBy) : undefined))
|
|
114
|
+
.all()
|
|
115
|
+
.map((row) => ({ ...row, description: null, lastMessagedAt: null }));
|
|
116
|
+
const byId = new Map(everyone.map((person) => [person.id, person]));
|
|
117
|
+
return { get: (id) => byId.get(id), all: () => everyone };
|
|
118
|
+
};
|
|
119
|
+
/** A contact: someone other than the account itself, in one of its one-to-one chats. */
|
|
120
|
+
const contactsWhere = (accountKey, key, query) => {
|
|
121
|
+
if (query !== undefined && query.trim().length < 3) {
|
|
122
|
+
throw new CliError("validation_error", `a contact search takes at least 3 characters, got "${query}"`);
|
|
123
|
+
}
|
|
124
|
+
return and(eq(accountIdentities.accountPk, accountKey), ne(identities.nativeId, key.account), sql `EXISTS (SELECT 1 FROM ${chatMembers} JOIN ${chats} ON ${chats.pk} = ${chatMembers.chatPk}
|
|
125
|
+
WHERE ${chatMembers.identityPk} = ${identities.pk} AND ${chats.accountPk} = ${accountIdentities.accountPk}
|
|
126
|
+
AND ${chats.kind} = 'dialog')`, query === undefined
|
|
127
|
+
? undefined
|
|
128
|
+
: sql `${identities.pk} IN (SELECT rowid FROM identities_fts WHERE identities_fts MATCH ${`"${query.trim().replaceAll('"', '""')}"`})`);
|
|
129
|
+
};
|
|
130
|
+
export const contacts = ({ orm }, accountKey, key, { order, query, limit, offset = 0 }) => {
|
|
131
|
+
const byName = [sql `${identities.name} IS NULL`, identities.name, identities.nativeId];
|
|
132
|
+
const rows = orm
|
|
133
|
+
.select({
|
|
134
|
+
id: identities.nativeId,
|
|
135
|
+
name: identities.name,
|
|
136
|
+
username: identities.username,
|
|
137
|
+
description: identities.description,
|
|
138
|
+
lastMessagedAt: accountIdentities.lastMessagedAt,
|
|
139
|
+
})
|
|
140
|
+
.from(accountIdentities)
|
|
141
|
+
.innerJoin(identities, eq(identities.pk, accountIdentities.identityPk))
|
|
142
|
+
.where(contactsWhere(accountKey, key, query))
|
|
143
|
+
.orderBy(...(order === "recent" ? [sql `${accountIdentities.lastMessagedAt} DESC NULLS LAST`] : []), ...byName)
|
|
144
|
+
.limit(limit + 1)
|
|
145
|
+
.offset(offset)
|
|
146
|
+
.all();
|
|
147
|
+
return {
|
|
148
|
+
items: rows.slice(0, limit).map((row) => ({ ...row, lastMessagedAt: toIso(row.lastMessagedAt) })),
|
|
149
|
+
hasMore: rows.length > limit,
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
export const countContacts = ({ orm }, accountKey, key, query) => Number(orm
|
|
153
|
+
.select({ n: sql `count(*)` })
|
|
154
|
+
.from(accountIdentities)
|
|
155
|
+
.innerJoin(identities, eq(identities.pk, accountIdentities.identityPk))
|
|
156
|
+
.where(contactsWhere(accountKey, key, query))
|
|
157
|
+
.get()?.n);
|
|
158
|
+
export const refreshRecency = ({ orm }, accountKey) => {
|
|
159
|
+
orm
|
|
160
|
+
.update(accountIdentities)
|
|
161
|
+
.set({
|
|
162
|
+
lastMessagedAt: sql `(SELECT max(${chats.lastMessageAt}) FROM ${chatMembers} JOIN ${chats} ON ${chats.pk} = ${chatMembers.chatPk}
|
|
163
|
+
WHERE ${chatMembers.identityPk} = ${accountIdentities.identityPk} AND ${chats.accountPk} = ${accountIdentities.accountPk}
|
|
164
|
+
AND ${chats.kind} = 'dialog')`,
|
|
165
|
+
})
|
|
166
|
+
.where(eq(accountIdentities.accountPk, accountKey))
|
|
167
|
+
.run();
|
|
168
|
+
};
|
|
169
|
+
//# sourceMappingURL=identities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identities.js","sourceRoot":"","sources":["../../../src/store/sqlite/identities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const toMs: (iso: string | null | undefined) => number | null;
|
|
2
|
+
export declare const toIso: (ms: unknown) => string | null;
|
|
3
|
+
export declare const json: (value: unknown) => string | null;
|
|
4
|
+
export declare const parsed: <T>(text: unknown) => T | undefined;
|
|
5
|
+
export declare const present: <T extends Record<string, unknown>>(entries: T) => {
|
|
6
|
+
[k: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=values.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../../../src/store/sqlite/values.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,QAAS,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,MAAM,GAAG,IAI9D,CAAA;AAED,eAAO,MAAM,KAAK,OAAQ,OAAO,KAAG,MAAM,GAAG,IAAoE,CAAA;AAEjH,eAAO,MAAM,IAAI,UAAW,OAAO,KAAG,MAAM,GAAG,IAA4D,CAAA;AAE3G,eAAO,MAAM,MAAM,GAAI,CAAC,QAAQ,OAAO,KAAG,CAAC,GAAG,SACkB,CAAA;AAEhE,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC;;CACqC,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const toMs = (iso) => {
|
|
2
|
+
if (iso === null || iso === undefined)
|
|
3
|
+
return null;
|
|
4
|
+
const ms = Date.parse(iso);
|
|
5
|
+
return Number.isNaN(ms) ? null : ms;
|
|
6
|
+
};
|
|
7
|
+
export const toIso = (ms) => (typeof ms === "number" ? new Date(ms).toISOString() : null);
|
|
8
|
+
export const json = (value) => (value === undefined ? null : JSON.stringify(value));
|
|
9
|
+
export const parsed = (text) => typeof text === "string" ? JSON.parse(text) : undefined;
|
|
10
|
+
export const present = (entries) => Object.fromEntries(Object.entries(entries).filter(([, value]) => value !== null && value !== undefined));
|
|
11
|
+
//# sourceMappingURL=values.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values.js","sourceRoot":"","sources":["../../../src/store/sqlite/values.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,GAA8B,EAAiB,EAAE;IACpE,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IAClD,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC1B,OAAO,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;AACrC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAW,EAAiB,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;AAEjH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,KAAc,EAAiB,EAAE,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;AAE3G,MAAM,CAAC,MAAM,MAAM,GAAG,CAAI,IAAa,EAAiB,EAAE,CACxD,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAO,CAAC,CAAC,CAAC,SAAS,CAAA;AAEhE,MAAM,CAAC,MAAM,OAAO,GAAG,CAAoC,OAAU,EAAE,EAAE,CACvE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store/store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,IAAI,EACJ,OAAO,EACP,EAAE,EACF,MAAM,EACN,OAAO,EACP,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,eAAe,EAChB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store/store.ts"],"names":[],"mappings":"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"}
|
package/dist/store/store.js
CHANGED
|
@@ -5,9 +5,12 @@ import { formatLocator } from "../domain/locator.js";
|
|
|
5
5
|
import { migrate } from "./migrations.js";
|
|
6
6
|
import { NORMALIZER_VERSION, normalize } from "./normalize.js";
|
|
7
7
|
import { storePath } from "./path.js";
|
|
8
|
+
import * as accounts from "./sqlite/accounts.js";
|
|
8
9
|
import { backfillNormalized, pendingNormalization } from "./sqlite/backfill.js";
|
|
10
|
+
import * as chatQueries from "./sqlite/chats.js";
|
|
11
|
+
import * as identities from "./sqlite/identities.js";
|
|
9
12
|
import { openSqlite } from "./sqlite/open.js";
|
|
10
|
-
import {
|
|
13
|
+
import { json, parsed, present, toIso, toMs } from "./sqlite/values.js";
|
|
11
14
|
/** About 40 ms of the first open (129k rows/s measured at 1M, 2026-09-30); Tab opens the store too. */
|
|
12
15
|
export const BACKFILL_ON_OPEN = 5_000;
|
|
13
16
|
export const openStore = async ({ path, env, now = Date.now } = {}) => {
|
|
@@ -31,7 +34,8 @@ export const openStore = async ({ path, env, now = Date.now } = {}) => {
|
|
|
31
34
|
};
|
|
32
35
|
/** Telegram's chat types that number their messages themselves, not per account. */
|
|
33
36
|
const OWN_NUMBERING = "('channel', 'supergroup', 'gigagroup', 'monoforum')";
|
|
34
|
-
const storeOver = (
|
|
37
|
+
const storeOver = (context) => {
|
|
38
|
+
const { database, now } = context;
|
|
35
39
|
const one = (sql, ...parameters) => database.prepare(sql).get(...parameters);
|
|
36
40
|
const all = (sql, ...parameters) => database.prepare(sql).all(...parameters);
|
|
37
41
|
const run = (sql, ...parameters) => database.prepare(sql).run(...parameters);
|
|
@@ -46,64 +50,11 @@ const storeOver = ({ database, now }) => {
|
|
|
46
50
|
throw error;
|
|
47
51
|
}
|
|
48
52
|
};
|
|
49
|
-
const accountPk = (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
return row ? Number(row.pk) : undefined;
|
|
55
|
-
};
|
|
56
|
-
const findChatPk = (accountKey, chatId) => {
|
|
57
|
-
const row = one("SELECT pk FROM chats WHERE account_pk = ? AND native_id = ?", accountKey, chatId);
|
|
58
|
-
return row ? Number(row.pk) : undefined;
|
|
59
|
-
};
|
|
60
|
-
const upsertChat = (accountKey, chat) => {
|
|
61
|
-
run(`INSERT INTO chats (account_pk, native_id, kind, title, unread_count, last_message_at, participants_count,
|
|
62
|
-
provider_metadata, membership_state, updated_at)
|
|
63
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
64
|
-
ON CONFLICT (account_pk, native_id) DO UPDATE SET
|
|
65
|
-
kind = excluded.kind, title = excluded.title, unread_count = excluded.unread_count,
|
|
66
|
-
last_message_at = excluded.last_message_at, participants_count = excluded.participants_count,
|
|
67
|
-
provider_metadata = excluded.provider_metadata,
|
|
68
|
-
membership_state = coalesce(excluded.membership_state, chats.membership_state),
|
|
69
|
-
updated_at = excluded.updated_at`, accountKey, chat.id, chat.kind, chat.title, chat.unreadCount, toMs(chat.lastMessageAt), chat.participantsCount, json(chat.providerMetadata), chat.membershipState ?? null, now());
|
|
70
|
-
};
|
|
71
|
-
/** A chat known only from its messages, until the chat list names it. */
|
|
72
|
-
const chatPkFor = (accountKey, chatId) => findChatPk(accountKey, chatId) ??
|
|
73
|
-
Number(one("INSERT INTO chats (account_pk, native_id, kind, updated_at) VALUES (?, ?, 'unknown', ?) RETURNING pk", accountKey, chatId, now())?.pk);
|
|
74
|
-
/** An identity as `accountKey` saw it — recorded as seen by that account, so reads stay per account. */
|
|
75
|
-
const identityPk = (accountKey, provider, nativeId, name, facts = {}) => {
|
|
76
|
-
const identity = identityOf(provider, nativeId, name, facts);
|
|
77
|
-
run("INSERT OR IGNORE INTO account_identities (account_pk, identity_pk, first_seen_at) VALUES (?, ?, ?)", accountKey, identity, now());
|
|
78
|
-
return identity;
|
|
79
|
-
};
|
|
80
|
-
/** Every new identity gets its own person; linking two is a later, recorded act. */
|
|
81
|
-
const identityOf = (provider, nativeId, name, facts = {}) => {
|
|
82
|
-
const found = one("SELECT pk, name, username, is_bot, description FROM identities WHERE provider = ? AND native_id = ?", provider, nativeId);
|
|
83
|
-
if (found) {
|
|
84
|
-
const username = facts.username ?? found.username ?? null;
|
|
85
|
-
const isBot = facts.isBot === undefined || facts.isBot === null ? (found.is_bot ?? null) : Number(facts.isBot);
|
|
86
|
-
const newName = name ?? found.name ?? null;
|
|
87
|
-
const description = facts.description ?? found.description ?? null;
|
|
88
|
-
// Only on a real change: the search trigger rewrites the index row on every update of `name`.
|
|
89
|
-
if (newName !== found.name ||
|
|
90
|
-
username !== found.username ||
|
|
91
|
-
isBot !== found.is_bot ||
|
|
92
|
-
description !== found.description) {
|
|
93
|
-
run("UPDATE identities SET name = ?, username = ?, is_bot = ?, description = ?, updated_at = ? WHERE pk = ?", newName, username, isBot, description, now(), Number(found.pk));
|
|
94
|
-
}
|
|
95
|
-
return Number(found.pk);
|
|
96
|
-
}
|
|
97
|
-
const at = now();
|
|
98
|
-
const identity = Number(one(`INSERT INTO identities (provider, native_id, name, username, is_bot, description, first_seen_at, updated_at)
|
|
99
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING pk`, provider, nativeId, name, facts.username ?? null, facts.isBot === undefined || facts.isBot === null ? null : Number(facts.isBot), facts.description ?? null, at, at)?.pk);
|
|
100
|
-
const person = Number(one("INSERT INTO persons (uid, name, created_at, updated_at) VALUES (?, ?, ?, ?) RETURNING pk", ulid(at), name, at, at)?.pk);
|
|
101
|
-
run(`INSERT INTO identity_links (identity_pk, person_pk, method, confidence, linked_at, linked_by)
|
|
102
|
-
VALUES (?, ?, 'initial', 1, ?, 'ingest')`, identity, person, at);
|
|
103
|
-
run(`INSERT INTO identity_link_events (identity_pk, from_person_pk, to_person_pk, method, at, by)
|
|
104
|
-
VALUES (?, NULL, ?, 'initial', ?, 'ingest')`, identity, person, at);
|
|
105
|
-
return identity;
|
|
106
|
-
};
|
|
53
|
+
const accountPk = (key, name = null) => accounts.accountPk(context, key, name);
|
|
54
|
+
const findAccountPk = (key) => accounts.findAccountPk(context, key);
|
|
55
|
+
const findChatPk = (accountKey, chatId) => chatQueries.findChatPk(context, accountKey, chatId);
|
|
56
|
+
const chatPkFor = (accountKey, chatId) => chatQueries.chatPkFor(context, accountKey, chatId);
|
|
57
|
+
const identityPk = (accountKey, provider, nativeId, name, facts) => identities.identityPk(context, accountKey, provider, nativeId, name, facts);
|
|
107
58
|
const upsertMessage = (key, accountKey, chatKey, message, via, seenAt) => {
|
|
108
59
|
const sender = message.senderId === null || message.senderIsChat
|
|
109
60
|
? null
|
|
@@ -274,13 +225,7 @@ const storeOver = ({ database, now }) => {
|
|
|
274
225
|
}
|
|
275
226
|
return found;
|
|
276
227
|
};
|
|
277
|
-
const writeMembers = (key, accountKey, chatId, memberIds) =>
|
|
278
|
-
const chatKey = chatPkFor(accountKey, chatId);
|
|
279
|
-
run("DELETE FROM chat_members WHERE chat_pk = ?", chatKey);
|
|
280
|
-
for (const id of new Set(memberIds)) {
|
|
281
|
-
run("INSERT INTO chat_members (chat_pk, identity_pk) VALUES (?, ?)", chatKey, identityPk(accountKey, key.provider, id, null));
|
|
282
|
-
}
|
|
283
|
-
};
|
|
228
|
+
const writeMembers = (key, accountKey, chatId, memberIds) => chatQueries.writeMembers(context, key, accountKey, chatId, memberIds);
|
|
284
229
|
const writeState = (accountKey, name, value) => {
|
|
285
230
|
run(`INSERT INTO sync_state (account_pk, key, value, at) VALUES (?, ?, ?, ?)
|
|
286
231
|
ON CONFLICT (account_pk, key) DO UPDATE SET value = excluded.value, at = excluded.at`, accountKey, name, value, now());
|
|
@@ -298,54 +243,16 @@ const storeOver = ({ database, now }) => {
|
|
|
298
243
|
run("DELETE FROM transcripts WHERE chat_pk = ? AND message_native_id = ?", Number(row.chat_pk), String(row.native_id));
|
|
299
244
|
return 1;
|
|
300
245
|
};
|
|
301
|
-
const chatsWhere = (accountKey, { query, kind, unread }) => {
|
|
302
|
-
const conditions = ["account_pk = ?"];
|
|
303
|
-
const parameters = [accountKey];
|
|
304
|
-
if (query !== undefined) {
|
|
305
|
-
if (query.trim().length < 3) {
|
|
306
|
-
throw new CliError("validation_error", `a chat search takes at least 3 characters, got "${query}"`);
|
|
307
|
-
}
|
|
308
|
-
conditions.push("pk IN (SELECT rowid FROM chats_fts WHERE chats_fts MATCH ?)");
|
|
309
|
-
parameters.push(`"${query.trim().replaceAll('"', '""')}"`);
|
|
310
|
-
}
|
|
311
|
-
if (kind !== undefined) {
|
|
312
|
-
conditions.push("kind = ?");
|
|
313
|
-
parameters.push(kind);
|
|
314
|
-
}
|
|
315
|
-
if (unread)
|
|
316
|
-
conditions.push("unread_count > 0");
|
|
317
|
-
return { sql: `WHERE ${conditions.join(" AND ")}`, parameters };
|
|
318
|
-
};
|
|
319
|
-
/** A contact: someone other than the account itself, in one of its one-to-one chats. */
|
|
320
|
-
const contactsWhere = (accountKey, key, query) => {
|
|
321
|
-
const parameters = [accountKey, key.account];
|
|
322
|
-
let match = "";
|
|
323
|
-
if (query !== undefined) {
|
|
324
|
-
if (query.trim().length < 3) {
|
|
325
|
-
throw new CliError("validation_error", `a contact search takes at least 3 characters, got "${query}"`);
|
|
326
|
-
}
|
|
327
|
-
match = "AND i.pk IN (SELECT rowid FROM identities_fts WHERE identities_fts MATCH ?)";
|
|
328
|
-
parameters.push(`"${query.trim().replaceAll('"', '""')}"`);
|
|
329
|
-
}
|
|
330
|
-
return {
|
|
331
|
-
sql: `FROM account_identities ai JOIN identities i ON i.pk = ai.identity_pk
|
|
332
|
-
WHERE ai.account_pk = ? AND i.native_id != ?
|
|
333
|
-
AND EXISTS (SELECT 1 FROM chat_members cm JOIN chats c ON c.pk = cm.chat_pk
|
|
334
|
-
WHERE cm.identity_pk = i.pk AND c.account_pk = ai.account_pk AND c.kind = 'dialog')
|
|
335
|
-
${match}`,
|
|
336
|
-
parameters,
|
|
337
|
-
};
|
|
338
|
-
};
|
|
339
246
|
const MESSAGE_COLUMNS = `m.*, c.native_id AS chat_native_id, i.native_id AS sender_native_id`;
|
|
340
247
|
const MESSAGE_JOINS = `JOIN chats c ON c.pk = m.chat_pk LEFT JOIN identities i ON i.pk = m.sender_identity_pk`;
|
|
341
248
|
return {
|
|
342
249
|
saveAccount: async (key, { name }) => {
|
|
343
250
|
accountPk(key, name);
|
|
344
251
|
},
|
|
345
|
-
saveChats: async (key,
|
|
252
|
+
saveChats: async (key, list) => inTransaction(() => {
|
|
346
253
|
const accountKey = accountPk(key);
|
|
347
|
-
for (const chat of
|
|
348
|
-
upsertChat(accountKey, chat);
|
|
254
|
+
for (const chat of list)
|
|
255
|
+
chatQueries.upsertChat(context, accountKey, chat);
|
|
349
256
|
}),
|
|
350
257
|
saveMessages: async (key, chatId, messages, { via, seenAt }) => inTransaction(() => {
|
|
351
258
|
const accountKey = accountPk(key);
|
|
@@ -359,24 +266,11 @@ const storeOver = ({ database, now }) => {
|
|
|
359
266
|
members: async (key, chatId) => {
|
|
360
267
|
const accountKey = findAccountPk(key);
|
|
361
268
|
const chatKey = accountKey === undefined ? undefined : findChatPk(accountKey, chatId);
|
|
362
|
-
|
|
363
|
-
return [];
|
|
364
|
-
return all(`SELECT i.native_id, i.name, i.username FROM chat_members cm JOIN identities i ON i.pk = cm.identity_pk
|
|
365
|
-
WHERE cm.chat_pk = ? ORDER BY i.name IS NULL, i.name, i.native_id`, chatKey).map((row) => ({
|
|
366
|
-
id: String(row.native_id),
|
|
367
|
-
name: row.name ?? null,
|
|
368
|
-
username: row.username ?? null,
|
|
369
|
-
}));
|
|
269
|
+
return chatKey === undefined ? [] : chatQueries.members(context, chatKey);
|
|
370
270
|
},
|
|
371
271
|
chatsWith: async (key, memberId) => {
|
|
372
272
|
const accountKey = findAccountPk(key);
|
|
373
|
-
|
|
374
|
-
return [];
|
|
375
|
-
return all(`SELECT c.* FROM chat_members cm
|
|
376
|
-
JOIN chats c ON c.pk = cm.chat_pk
|
|
377
|
-
JOIN identities i ON i.pk = cm.identity_pk
|
|
378
|
-
WHERE c.account_pk = ? AND i.provider = ? AND i.native_id = ?
|
|
379
|
-
ORDER BY c.last_message_at DESC NULLS LAST, c.pk`, accountKey, key.provider, memberId).map(toChat);
|
|
273
|
+
return accountKey === undefined ? [] : chatQueries.chatsWith(context, accountKey, key, memberId);
|
|
380
274
|
},
|
|
381
275
|
syncState: async (key, name) => {
|
|
382
276
|
const accountKey = findAccountPk(key);
|
|
@@ -389,7 +283,7 @@ const storeOver = ({ database, now }) => {
|
|
|
389
283
|
applyDelta: async (key, { chats = [], people = [], members = new Map(), state = {} }) => inTransaction(() => {
|
|
390
284
|
const accountKey = accountPk(key);
|
|
391
285
|
for (const chat of chats)
|
|
392
|
-
upsertChat(accountKey, chat);
|
|
286
|
+
chatQueries.upsertChat(context, accountKey, chat);
|
|
393
287
|
for (const person of people)
|
|
394
288
|
identityPk(accountKey, key.provider, person.id, person.name, person);
|
|
395
289
|
for (const [chatId, ids] of members)
|
|
@@ -437,21 +331,15 @@ const storeOver = ({ database, now }) => {
|
|
|
437
331
|
text = excluded.text, source = excluded.source, heard_at = excluded.heard_at`, chatPkFor(accountPk(key), chatId), messageId, text, source, now());
|
|
438
332
|
});
|
|
439
333
|
},
|
|
440
|
-
chats: async (key,
|
|
334
|
+
chats: async (key, window) => {
|
|
441
335
|
const accountKey = findAccountPk(key);
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const rows = all(`SELECT * FROM chats ${where.sql} ORDER BY last_message_at DESC NULLS LAST, pk LIMIT ? OFFSET ?`, ...where.parameters, limit === undefined ? -1 : limit + 1, offset);
|
|
446
|
-
const hasMore = limit !== undefined && rows.length > limit;
|
|
447
|
-
return { items: rows.slice(0, limit).map(toChat), hasMore };
|
|
336
|
+
return accountKey === undefined
|
|
337
|
+
? { items: [], hasMore: false }
|
|
338
|
+
: chatQueries.listChats(context, accountKey, window);
|
|
448
339
|
},
|
|
449
340
|
countChats: async (key, filter = {}) => {
|
|
450
341
|
const accountKey = findAccountPk(key);
|
|
451
|
-
|
|
452
|
-
return 0;
|
|
453
|
-
const where = chatsWhere(accountKey, filter);
|
|
454
|
-
return Number(one(`SELECT count(*) AS n FROM chats ${where.sql}`, ...where.parameters)?.n);
|
|
342
|
+
return accountKey === undefined ? 0 : chatQueries.countChats(context, accountKey, filter);
|
|
455
343
|
},
|
|
456
344
|
countMessages: async (key, chatId, { since } = {}) => {
|
|
457
345
|
const accountKey = findAccountPk(key);
|
|
@@ -577,60 +465,27 @@ const storeOver = ({ database, now }) => {
|
|
|
577
465
|
},
|
|
578
466
|
search: async (query, { limit, account }) => find({ text: query, limit, ...(account ? { account } : {}) }),
|
|
579
467
|
find: async (filter) => find(filter),
|
|
580
|
-
contacts: async (key,
|
|
468
|
+
contacts: async (key, options) => {
|
|
581
469
|
const accountKey = findAccountPk(key);
|
|
582
470
|
if (accountKey === undefined)
|
|
583
471
|
return { items: [], hasMore: false };
|
|
584
|
-
|
|
585
|
-
const rows = all(`SELECT i.native_id, i.name, i.username, i.description, ai.last_messaged_at ${where.sql}
|
|
586
|
-
ORDER BY ${order === "recent" ? "ai.last_messaged_at DESC NULLS LAST, " : ""}i.name IS NULL, i.name, i.native_id
|
|
587
|
-
LIMIT ? OFFSET ?`, ...where.parameters, limit + 1, offset);
|
|
588
|
-
return {
|
|
589
|
-
items: rows.slice(0, limit).map((row) => ({
|
|
590
|
-
id: String(row.native_id),
|
|
591
|
-
name: row.name ?? null,
|
|
592
|
-
username: row.username ?? null,
|
|
593
|
-
description: row.description ?? null,
|
|
594
|
-
lastMessagedAt: toIso(row.last_messaged_at),
|
|
595
|
-
})),
|
|
596
|
-
hasMore: rows.length > limit,
|
|
597
|
-
};
|
|
472
|
+
return identities.contacts(context, accountKey, key, options);
|
|
598
473
|
},
|
|
599
474
|
countContacts: async (key, { query } = {}) => {
|
|
600
475
|
const accountKey = findAccountPk(key);
|
|
601
|
-
|
|
602
|
-
return 0;
|
|
603
|
-
const where = contactsWhere(accountKey, key, query);
|
|
604
|
-
return Number(one(`SELECT count(*) AS n ${where.sql}`, ...where.parameters)?.n);
|
|
476
|
+
return accountKey === undefined ? 0 : identities.countContacts(context, accountKey, key, query);
|
|
605
477
|
},
|
|
606
478
|
refreshRecency: async (key) => {
|
|
607
479
|
const accountKey = findAccountPk(key);
|
|
608
|
-
if (accountKey
|
|
609
|
-
|
|
610
|
-
inTransaction(() => {
|
|
611
|
-
run(`UPDATE account_identities SET last_messaged_at = (
|
|
612
|
-
SELECT max(c.last_message_at) FROM chat_members cm JOIN chats c ON c.pk = cm.chat_pk
|
|
613
|
-
WHERE cm.identity_pk = account_identities.identity_pk AND c.account_pk = account_identities.account_pk
|
|
614
|
-
AND c.kind = 'dialog')
|
|
615
|
-
WHERE account_pk = ?`, accountKey);
|
|
616
|
-
});
|
|
480
|
+
if (accountKey !== undefined)
|
|
481
|
+
identities.refreshRecency(context, accountKey);
|
|
617
482
|
},
|
|
618
483
|
savePeople: async (key, people) => inTransaction(() => {
|
|
619
484
|
const accountKey = accountPk(key);
|
|
620
485
|
for (const person of people)
|
|
621
486
|
identityPk(accountKey, key.provider, person.id, person.name, person);
|
|
622
487
|
}),
|
|
623
|
-
people: async (provider,
|
|
624
|
-
const within = accounts ?? (account === undefined ? undefined : [account]);
|
|
625
|
-
const scope = within
|
|
626
|
-
? `AND pk IN (SELECT ai.identity_pk FROM account_identities ai JOIN accounts a ON a.pk = ai.account_pk
|
|
627
|
-
WHERE a.provider = ? AND a.native_id IN (${within.map(() => "?").join(", ") || "NULL"}))`
|
|
628
|
-
: "";
|
|
629
|
-
const rows = all(`SELECT native_id, name, username FROM identities WHERE provider = ? ${scope}`, provider, ...(within ? [provider, ...within] : []));
|
|
630
|
-
const everyone = rows.map(toContact);
|
|
631
|
-
const byId = new Map(everyone.map((person) => [person.id, person]));
|
|
632
|
-
return { get: (id) => byId.get(id), all: () => everyone };
|
|
633
|
-
},
|
|
488
|
+
people: async (provider, options = {}) => identities.people(context, provider, options),
|
|
634
489
|
saveReactions: async (key, chatId, messageId, reactions) => {
|
|
635
490
|
const accountKey = findAccountPk(key);
|
|
636
491
|
const chatKey = accountKey === undefined ? undefined : findChatPk(accountKey, chatId);
|
|
@@ -682,32 +537,6 @@ const storeOver = ({ database, now }) => {
|
|
|
682
537
|
};
|
|
683
538
|
};
|
|
684
539
|
const searchable = (text) => ({ normalized_text: normalize(text), normalizer_version: NORMALIZER_VERSION });
|
|
685
|
-
const toMs = (iso) => {
|
|
686
|
-
if (iso === null || iso === undefined)
|
|
687
|
-
return null;
|
|
688
|
-
const ms = Date.parse(iso);
|
|
689
|
-
return Number.isNaN(ms) ? null : ms;
|
|
690
|
-
};
|
|
691
|
-
const toIso = (ms) => (typeof ms === "number" ? new Date(ms).toISOString() : null);
|
|
692
|
-
const json = (value) => (value === undefined ? null : JSON.stringify(value));
|
|
693
|
-
const parsed = (text) => (typeof text === "string" ? JSON.parse(text) : undefined);
|
|
694
|
-
const present = (entries) => Object.fromEntries(Object.entries(entries).filter(([, value]) => value !== null && value !== undefined));
|
|
695
|
-
const toContact = (row) => ({
|
|
696
|
-
id: String(row.native_id),
|
|
697
|
-
name: row.name ?? null,
|
|
698
|
-
username: row.username ?? null,
|
|
699
|
-
description: null,
|
|
700
|
-
lastMessagedAt: null,
|
|
701
|
-
});
|
|
702
|
-
const toChat = (row) => ({
|
|
703
|
-
id: String(row.native_id),
|
|
704
|
-
title: row.title ?? null,
|
|
705
|
-
kind: row.kind,
|
|
706
|
-
unreadCount: row.unread_count ?? null,
|
|
707
|
-
lastMessageAt: toIso(row.last_message_at),
|
|
708
|
-
participantsCount: row.participants_count ?? null,
|
|
709
|
-
...present({ membershipState: row.membership_state, providerMetadata: parsed(row.provider_metadata) }),
|
|
710
|
-
});
|
|
711
540
|
const toAttachment = (row) => ({
|
|
712
541
|
kind: String(row.kind),
|
|
713
542
|
...present({
|