@leemour/max-cli 0.1.0 → 0.2.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.
Files changed (78) hide show
  1. package/README.md +25 -9
  2. package/dist/cache/schema.d.ts +10 -1
  3. package/dist/cache/schema.d.ts.map +1 -1
  4. package/dist/cache/schema.js +71 -7
  5. package/dist/cache/schema.js.map +1 -1
  6. package/dist/cache/store.d.ts +84 -3
  7. package/dist/cache/store.d.ts.map +1 -1
  8. package/dist/cache/store.js +155 -25
  9. package/dist/cache/store.js.map +1 -1
  10. package/dist/client.d.ts +68 -9
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +286 -31
  13. package/dist/client.js.map +1 -1
  14. package/dist/commands/chats.d.ts.map +1 -1
  15. package/dist/commands/chats.js +5 -9
  16. package/dist/commands/chats.js.map +1 -1
  17. package/dist/commands/contacts.d.ts.map +1 -1
  18. package/dist/commands/contacts.js +46 -5
  19. package/dist/commands/contacts.js.map +1 -1
  20. package/dist/commands/login.d.ts +15 -0
  21. package/dist/commands/login.d.ts.map +1 -0
  22. package/dist/commands/login.js +43 -0
  23. package/dist/commands/login.js.map +1 -0
  24. package/dist/commands/logout.d.ts +10 -0
  25. package/dist/commands/logout.d.ts.map +1 -0
  26. package/dist/commands/logout.js +22 -0
  27. package/dist/commands/logout.js.map +1 -0
  28. package/dist/commands/me.d.ts +3 -0
  29. package/dist/commands/me.d.ts.map +1 -0
  30. package/dist/commands/me.js +18 -0
  31. package/dist/commands/me.js.map +1 -0
  32. package/dist/commands/messages.d.ts.map +1 -1
  33. package/dist/commands/messages.js +18 -3
  34. package/dist/commands/messages.js.map +1 -1
  35. package/dist/commands/paging.d.ts +38 -0
  36. package/dist/commands/paging.d.ts.map +1 -0
  37. package/dist/commands/paging.js +43 -0
  38. package/dist/commands/paging.js.map +1 -0
  39. package/dist/commands/send.d.ts +10 -0
  40. package/dist/commands/send.d.ts.map +1 -0
  41. package/dist/commands/send.js +30 -0
  42. package/dist/commands/send.js.map +1 -0
  43. package/dist/commands/session.d.ts.map +1 -1
  44. package/dist/commands/session.js +3 -3
  45. package/dist/commands/session.js.map +1 -1
  46. package/dist/config.d.ts +6 -0
  47. package/dist/config.d.ts.map +1 -1
  48. package/dist/config.js +10 -0
  49. package/dist/config.js.map +1 -1
  50. package/dist/domain/map.d.ts +1 -0
  51. package/dist/domain/map.d.ts.map +1 -1
  52. package/dist/domain/map.js +2 -0
  53. package/dist/domain/map.js.map +1 -1
  54. package/dist/domain/models.d.ts +18 -0
  55. package/dist/domain/models.d.ts.map +1 -1
  56. package/dist/generated/operations.generated.d.ts +1 -0
  57. package/dist/generated/operations.generated.d.ts.map +1 -1
  58. package/dist/protocol/session.d.ts +54 -0
  59. package/dist/protocol/session.d.ts.map +1 -0
  60. package/dist/protocol/session.js +57 -0
  61. package/dist/protocol/session.js.map +1 -0
  62. package/dist/session/adopt.d.ts +22 -0
  63. package/dist/session/adopt.d.ts.map +1 -0
  64. package/dist/session/adopt.js +29 -0
  65. package/dist/session/adopt.js.map +1 -0
  66. package/dist/session/handshake.d.ts +14 -1
  67. package/dist/session/handshake.d.ts.map +1 -1
  68. package/dist/session/handshake.js +5 -5
  69. package/dist/session/handshake.js.map +1 -1
  70. package/dist/spec/operations/auth.d.ts +42 -0
  71. package/dist/spec/operations/auth.d.ts.map +1 -0
  72. package/dist/spec/operations/session.d.ts +16 -0
  73. package/dist/spec/operations/session.d.ts.map +1 -1
  74. package/dist/spec/operations/session.js +21 -1
  75. package/dist/spec/operations/session.js.map +1 -1
  76. package/dist/version.d.ts +1 -1
  77. package/dist/version.js +1 -1
  78. package/package.json +4 -3
package/README.md CHANGED
@@ -14,9 +14,6 @@ max chats list --limit 5
14
14
  max messages list "Иван Петров"
15
15
  ```
16
16
 
17
- > ⚠ **Версия `0.1.0` ещё не опубликована.** Под именем `@leemour/max-cli` на npm пока нет ничего.
18
- > Пока — [установка из исходников](docs/installation.md).
19
-
20
17
  ## Что это даёт
21
18
 
22
19
  - **Один запуск — одна операция.** Соединиться, сделать, напечатать, отключиться. Ничего не висит
@@ -39,6 +36,9 @@ max messages list "Иван Петров"
39
36
  хэшем.
40
37
  - **По умолчанию не записывается ничего.** Мессенджер, который сам собирает каталог с историей
41
38
  того, кого вы читали, — это чужая жизнь в чужом логе; запись включается флагом.
39
+ - **Каждый вход спрашивает только то, что изменилось.** Метка времени прошлого входа уходит
40
+ обратно, и MAX присылает дельту, а не весь список заново — так что контакты остаются свежими,
41
+ не стоя ничего.
42
42
  - **Два рантайма, и это проверяется.** Node 22+ и Bun; под обоими в CI выполняется собранная
43
43
  команда, а не только проверка типов.
44
44
  - **Мы выглядим как официальный клиент.** На проводе нет ни нашего имени, ни своего user-agent:
@@ -59,11 +59,16 @@ max messages list "Иван Петров"
59
59
  Пакет — **`@leemour/max-cli`**, команда, которую он ставит, — **`max`**. Имя без области занято
60
60
  чужим пакетом с 2018 года.
61
61
 
62
- Пока `0.1.0` не опубликован, ставится из исходников:
62
+ Запустить, ничего не устанавливая:
63
+
64
+ ```sh
65
+ npx @leemour/max-cli --help
66
+ ```
67
+
68
+ Поставить насовсем:
63
69
 
64
70
  ```sh
65
- git clone git@github.com:leemour/max-cli.git
66
- cd max-cli && pnpm install && pnpm build && pnpm link --global
71
+ npm install -g @leemour/max-cli
67
72
  max --version # 0.1.0
68
73
  ```
69
74
 
@@ -93,12 +98,20 @@ export MAX_PROFILE=personal # или на всю сессию оболочки
93
98
 
94
99
  ```sh
95
100
  max chats list --limit 5
96
- max contacts list
101
+ max contacts list # люди, с кем есть личный чат
97
102
  max messages list 0 --limit 50 # по id чата
98
103
  max messages list "Иван Петров" # или по части названия
99
104
  max messages send 0 "текст"
100
105
  ```
101
106
 
107
+ Списки листаются одинаково везде, а история — по времени, потому что она к нему и привязана:
108
+
109
+ ```sh
110
+ max contacts list --limit 5 --page 2 # шестой по десятый
111
+ max contacts list --all --order name # всё, по алфавиту
112
+ max messages list 0 --before 2026-09-20T01:00:00Z
113
+ ```
114
+
102
115
  Что делала команда:
103
116
 
104
117
  ```sh
@@ -126,8 +139,11 @@ max chats list --json
126
139
  ```
127
140
 
128
141
  `--json` — это **ровно одно значение JSON на stdout и больше ничего**: ни спиннера, ни галочки, ни
129
- предупреждения. То же самое включается само, когда stdout не терминал. Ошибка уходит на stderr, а
130
- stdout остаётся пустым, поэтому отказ невозможно принять за результат:
142
+ предупреждения. То же самое включается само, когда stdout не терминал. Любой список отвечает одним
143
+ объектом — `{ "items": […], "page": 1, "limit": 20, "hasMore": true }` — и `--all` с `--offline`
144
+ отвечают **тем же**, чтобы разбирающему ответ не приходилось ветвиться на две формы.
145
+
146
+ Ошибка уходит на stderr, а stdout остаётся пустым, поэтому отказ невозможно принять за результат:
131
147
 
132
148
  ```json
133
149
  {"error":{"code":"authentication_error","message":"no session for profile \"default\" — run `max session start`"}}
@@ -3,12 +3,21 @@ import type { CacheDatabase } from "./driver.js";
3
3
  * **Raise this on every change to the statements below.** The second schema change is the one that
4
4
  * corrupts somebody's file, because the first is always made while the only copy is your own.
5
5
  */
6
- export declare const SCHEMA_VERSION = 1;
6
+ export declare const SCHEMA_VERSION = 2;
7
7
  /**
8
8
  * Brings a file up to date, and **refuses a file from the future** rather than writing to it.
9
9
  *
10
10
  * A newer `max` may have added a column this one does not know about. Reading it is survivable;
11
11
  * writing to it is how one version quietly destroys what another stored.
12
+ *
13
+ * **An older file is rebuilt, not altered.** Everything in here comes back from MAX, so a
14
+ * column-by-column migration would be code that runs once, is tested never, and is how the second
15
+ * schema change corrupts somebody's file. What a rebuild costs is one full login — which is what
16
+ * every command did before the delta sync existed.
17
+ *
18
+ * ⚠ **This stops being the right answer the day the database holds something MAX cannot re-send.**
19
+ * Contacts that are in no chat would be exactly that (`RES-7`), and the day they arrive this
20
+ * becomes `ALTER TABLE … ADD COLUMN` and this paragraph gets rewritten.
12
21
  */
13
22
  export declare const migrate: (database: CacheDatabase) => void;
14
23
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/cache/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD;;;GAGG;AACH,eAAO,MAAM,cAAc,IAAI,CAAA;AAiF/B;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,UAAU,aAAa,KAAG,IAcjD,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/cache/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD;;;GAGG;AACH,eAAO,MAAM,cAAc,IAAI,CAAA;AAyH/B;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,OAAO,GAAI,UAAU,aAAa,KAAG,IAgBjD,CAAA"}
@@ -2,7 +2,7 @@
2
2
  * **Raise this on every change to the statements below.** The second schema change is the one that
3
3
  * corrupts somebody's file, because the first is always made while the only copy is your own.
4
4
  */
5
- export const SCHEMA_VERSION = 1;
5
+ export const SCHEMA_VERSION = 2;
6
6
  /**
7
7
  * Everything the cache holds, and the indexes are part of it rather than an afterthought — each
8
8
  * one exists for a query that is actually made.
@@ -25,12 +25,48 @@ const STATEMENTS = [
25
25
  fetched_at INTEGER NOT NULL
26
26
  )`,
27
27
  `CREATE INDEX IF NOT EXISTS chats_by_recency ON chats (last_message_at DESC)`,
28
- `CREATE TABLE IF NOT EXISTS contacts (
29
- id TEXT PRIMARY KEY,
30
- name TEXT,
31
- username TEXT,
32
- description TEXT,
33
- fetched_at INTEGER NOT NULL
28
+ /**
29
+ * **Everyone MAX has named for us, whatever the reason** — not an address book and not a contact
30
+ * list. A group member gets a row here because their name has to live somewhere; whether they
31
+ * are a *contact* is a question the query answers (a dialog with them exists), never a flag
32
+ * somebody has to maintain (`NEED-105`).
33
+ *
34
+ * `last_messaged_at` is stored rather than derived because it is the default order: recomputing
35
+ * `MAX(chats.last_message_at)` per person on every listing is the work this table exists to
36
+ * avoid. `source` records how we met them and is diagnostic — it is not what the filter reads.
37
+ */
38
+ `CREATE TABLE IF NOT EXISTS people (
39
+ id TEXT PRIMARY KEY,
40
+ name TEXT,
41
+ username TEXT,
42
+ description TEXT,
43
+ last_messaged_at INTEGER,
44
+ source TEXT NOT NULL,
45
+ fetched_at INTEGER NOT NULL
46
+ )`,
47
+ `CREATE INDEX IF NOT EXISTS people_by_recency ON people (last_messaged_at DESC)`,
48
+ /**
49
+ * Who is in what. It is what the client used to work out in memory and throw away, and it is how
50
+ * "which groups do I share with this person" becomes one indexed lookup — every chat in this
51
+ * database is one the owner is in, so the chats of a person *are* the shared set.
52
+ */
53
+ `CREATE TABLE IF NOT EXISTS chat_members (
54
+ chat_id TEXT NOT NULL,
55
+ person_id TEXT NOT NULL,
56
+ PRIMARY KEY (chat_id, person_id)
57
+ )`,
58
+ `CREATE INDEX IF NOT EXISTS members_by_person ON chat_members (person_id)`,
59
+ /**
60
+ * Where the last login's `time` is kept, so the next one can ask for the delta instead of the
61
+ * whole collection. One row, and the `CHECK` is what keeps it that way.
62
+ *
63
+ * It lives here rather than in the profile's state file because a marker that outlives the rows
64
+ * it describes is a promise this database cannot keep: `max cache clear` has to forget both in
65
+ * the same breath, and a marker in another file would survive it.
66
+ */
67
+ `CREATE TABLE IF NOT EXISTS sync_marker (
68
+ id INTEGER PRIMARY KEY CHECK (id = 1),
69
+ marker INTEGER NOT NULL
34
70
  )`,
35
71
  `CREATE TABLE IF NOT EXISTS messages (
36
72
  chat_id TEXT NOT NULL,
@@ -47,6 +83,8 @@ const STATEMENTS = [
47
83
  )`,
48
84
  `CREATE INDEX IF NOT EXISTS messages_by_time ON messages (chat_id, time DESC)`,
49
85
  `CREATE INDEX IF NOT EXISTS messages_by_update ON messages (chat_id, update_time)`,
86
+ /** `messages list --before <id>` resolves an id to its `time`, without knowing which chat. */
87
+ `CREATE INDEX IF NOT EXISTS messages_by_id ON messages (id)`,
50
88
  /**
51
89
  * The windows we claim to hold **completely**, which is what makes "absent means deleted" safe
52
90
  * to believe. A message outside every range is a message we have never looked for; a message
@@ -81,6 +119,15 @@ const STATEMENTS = [
81
119
  *
82
120
  * A newer `max` may have added a column this one does not know about. Reading it is survivable;
83
121
  * writing to it is how one version quietly destroys what another stored.
122
+ *
123
+ * **An older file is rebuilt, not altered.** Everything in here comes back from MAX, so a
124
+ * column-by-column migration would be code that runs once, is tested never, and is how the second
125
+ * schema change corrupts somebody's file. What a rebuild costs is one full login — which is what
126
+ * every command did before the delta sync existed.
127
+ *
128
+ * ⚠ **This stops being the right answer the day the database holds something MAX cannot re-send.**
129
+ * Contacts that are in no chat would be exactly that (`RES-7`), and the day they arrive this
130
+ * becomes `ALTER TABLE … ADD COLUMN` and this paragraph gets rewritten.
84
131
  */
85
132
  export const migrate = (database) => {
86
133
  const current = Number(database.prepare("PRAGMA user_version").get()?.user_version ?? 0);
@@ -88,8 +135,25 @@ export const migrate = (database) => {
88
135
  throw new Error(`this cache was written by a newer max (schema ${current}, this one speaks ${SCHEMA_VERSION}) — ` +
89
136
  "run `max cache clear`, or use the newer version");
90
137
  }
138
+ if (current > 0 && current < SCHEMA_VERSION)
139
+ rebuild(database);
91
140
  for (const statement of STATEMENTS)
92
141
  database.exec(statement);
93
142
  database.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);
94
143
  };
144
+ /**
145
+ * Drops what is there by asking the file rather than by listing what we think a previous version
146
+ * wrote. A version that added a table we have since forgotten would otherwise survive the rebuild
147
+ * and collide with a later name.
148
+ *
149
+ * The `fetched` table goes with the rest on purpose: it records that a collection was complete,
150
+ * and keeping it would claim a sweep whose rows have just been thrown away.
151
+ */
152
+ const rebuild = (database) => {
153
+ const tables = database
154
+ .prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'")
155
+ .all();
156
+ for (const { name } of tables)
157
+ database.exec(`DROP TABLE IF EXISTS "${String(name)}"`);
158
+ };
95
159
  //# sourceMappingURL=schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/cache/schema.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAA;AAE/B;;;;;;;;;GASG;AACH,MAAM,UAAU,GAAG;IACjB;;;;;;;;;KASG;IACH,6EAA6E;IAE7E;;;;;;KAMG;IAEH;;;;;;;;;;;;KAYG;IACH,8EAA8E;IAC9E,kFAAkF;IAElF;;;;OAIG;IACH;;;;;KAKG;IACH,0EAA0E;IAE1E;;;;OAIG;IACH;;;KAGG;IAEH;;;;;;KAMG;CACJ,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,QAAuB,EAAQ,EAAE;IACvD,MAAM,OAAO,GAAG,MAAM,CACnB,QAAQ,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,GAAG,EAAgC,EAAE,YAAY,IAAI,CAAC,CAChG,CAAA;IAED,IAAI,OAAO,GAAG,cAAc,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,iDAAiD,OAAO,qBAAqB,cAAc,MAAM;YAC/F,iDAAiD,CACpD,CAAA;IACH,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,UAAU;QAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC5D,QAAQ,CAAC,IAAI,CAAC,yBAAyB,cAAc,EAAE,CAAC,CAAA;AAC1D,CAAC,CAAA"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/cache/schema.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAA;AAE/B;;;;;;;;;GASG;AACH,MAAM,UAAU,GAAG;IACjB;;;;;;;;;KASG;IACH,6EAA6E;IAE7E;;;;;;;;;OASG;IACH;;;;;;;;KAQG;IACH,gFAAgF;IAEhF;;;;OAIG;IACH;;;;KAIG;IACH,0EAA0E;IAE1E;;;;;;;OAOG;IACH;;;KAGG;IAEH;;;;;;;;;;;;KAYG;IACH,8EAA8E;IAC9E,kFAAkF;IAClF,8FAA8F;IAC9F,4DAA4D;IAE5D;;;;OAIG;IACH;;;;;KAKG;IACH,0EAA0E;IAE1E;;;;OAIG;IACH;;;KAGG;IAEH;;;;;;KAMG;CACJ,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,QAAuB,EAAQ,EAAE;IACvD,MAAM,OAAO,GAAG,MAAM,CACnB,QAAQ,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,GAAG,EAAgC,EAAE,YAAY,IAAI,CAAC,CAChG,CAAA;IAED,IAAI,OAAO,GAAG,cAAc,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,iDAAiD,OAAO,qBAAqB,cAAc,MAAM;YAC/F,iDAAiD,CACpD,CAAA;IACH,CAAC;IAED,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,cAAc;QAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IAE9D,KAAK,MAAM,SAAS,IAAI,UAAU;QAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC5D,QAAQ,CAAC,IAAI,CAAC,yBAAyB,cAAc,EAAE,CAAC,CAAA;AAC1D,CAAC,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,GAAG,CAAC,QAAuB,EAAQ,EAAE;IAChD,MAAM,MAAM,GAAG,QAAQ;SACpB,OAAO,CAAC,kFAAkF,CAAC;SAC3F,GAAG,EAAE,CAAA;IAER,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,MAAM;QAAE,QAAQ,CAAC,IAAI,CAAC,yBAAyB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACxF,CAAC,CAAA"}
@@ -1,5 +1,41 @@
1
1
  import type { Chat, Contact, Id, Message } from "../domain/models.js";
2
2
  import type { CacheDatabase } from "./driver.js";
3
+ /** How we came to know a person. Diagnostic — what makes somebody a *contact* is the query. */
4
+ export type PersonSource = "login" | "info" | "participant" | "sync";
5
+ export type PersonOrder = "recent" | "name";
6
+ export interface PageOptions {
7
+ order: PersonOrder;
8
+ limit: number;
9
+ offset: number;
10
+ }
11
+ /**
12
+ * One login's worth of change: the chats that moved, the people that changed, who is in which
13
+ * chat, and the `time` MAX answered with.
14
+ *
15
+ * `members` is keyed by chat id and holds that chat's **whole** membership minus ourselves, so a
16
+ * chat named here has its rows replaced rather than added to. A chat absent from the map keeps
17
+ * the members it already had.
18
+ */
19
+ /**
20
+ * What a merge did, in counts and **nothing else** — no name, no username, no description. It is
21
+ * what `max contacts sync` prints, and a summary that named anybody would be the one place the
22
+ * sixth constraint leaks.
23
+ *
24
+ * `changed` is "already known and sent again". A delta carries only what moved, so for an ordinary
25
+ * login that is exactly what it sounds like; for a full re-take, where MAX resends everything, it
26
+ * reads as "re-sent" instead — which is what `full` in the command's output is there to say.
27
+ */
28
+ export interface SyncSummary {
29
+ known: number;
30
+ added: number;
31
+ changed: number;
32
+ }
33
+ export interface SyncDelta {
34
+ chats: Chat[];
35
+ people: Contact[];
36
+ members: Map<Id, Id[]>;
37
+ marker: number;
38
+ }
3
39
  export interface CacheOptions {
4
40
  database: CacheDatabase;
5
41
  /** Injected so a freshness test costs nothing and does not wait. */
@@ -10,17 +46,62 @@ export interface CacheStore {
10
46
  chats: {
11
47
  read(freshForMs: number): Chat[] | undefined;
12
48
  write(chats: Chat[]): void;
49
+ /** One page, newest first, in SQL rather than by building the whole list and slicing it. */
50
+ page(options: {
51
+ limit: number;
52
+ offset: number;
53
+ }): Chat[];
54
+ count(): number;
13
55
  };
14
- contacts: {
15
- read(freshForMs: number): Contact[] | undefined;
16
- write(contacts: Contact[]): void;
56
+ people: {
57
+ /**
58
+ * One page of **contacts** — the people a one-to-one chat exists with. `recent` is
59
+ * `last_messaged_at` newest first, the never-messaged last, then by name.
60
+ *
61
+ * A group member is not in this answer, and nothing marks them as excluded: they are simply
62
+ * not in the set the query asks for (`NEED-105`).
63
+ */
64
+ contacts(options: PageOptions): Contact[];
65
+ /** How many that query would return, so a page can say whether another one exists. */
66
+ countContacts(): number;
67
+ /** Everyone we can put a name to, contact or not. */
68
+ page(options: PageOptions): Contact[];
69
+ /** Everyone, counted — what `max contacts sync` reports as known. */
70
+ count(): number;
71
+ /** Carries how we met them. Never deletes: absence from a delta means unchanged. */
72
+ upsert(people: Contact[], source: PersonSource): void;
73
+ /** The chats this person is in — which, every chat here being one we are in, is the shared set. */
74
+ chatsWith(personId: Id): Id[];
75
+ /**
76
+ * Recomputes `last_messaged_at` from the dialogs we hold.
77
+ *
78
+ * ⚠ **Call it after any write that adds people.** A person's recency cannot be set while
79
+ * writing the chats, because most people are not known yet at that moment: the login names a
80
+ * handful and the rest arrive from a `CONTACT_INFO` that has not been sent. Measured on the
81
+ * real account 2026-09-21: 6 of 22 people had a recency and the other 16 sorted as
82
+ * never-messaged, which is every dialog partner the login did not name.
83
+ */
84
+ refreshRecency(): void;
17
85
  };
86
+ /** The `time` the last login answered with, or `undefined` for a store that has never synced. */
87
+ syncMarker(): number | undefined;
88
+ /** Rows, memberships, recency and the marker — **in one transaction**. */
89
+ mergeDelta(delta: SyncDelta): SyncSummary;
90
+ /** Makes the next login ask for everything again. */
91
+ forgetSyncMarker(): void;
18
92
  messages: {
19
93
  /** The newest `limit` messages, but only if the window we hold is both fresh and contiguous. */
20
94
  read(chatId: Id, limit: number, freshForMs: number): Message[] | undefined;
21
95
  write(chatId: Id, messages: Message[]): void;
22
96
  /** After a send, what we hold for that chat is missing the message we just added. */
23
97
  invalidate(chatId: Id): void;
98
+ /**
99
+ * When a message was sent, for `messages list --before <id>`.
100
+ *
101
+ * `undefined` for an id we have never stored — which is exactly what a deleted message looks
102
+ * like, since it is no longer in the history MAX returns either.
103
+ */
104
+ timeOf(id: Id): number | undefined;
24
105
  };
25
106
  /** True when this process may go to MAX for that window; false when somebody else already is. */
26
107
  claim(chatId: Id, anchor: string, holder: string, forMs: number): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/cache/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,aAAa,CAAA;IACvB,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED,sFAAsF;AACtF,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE;QACL,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,SAAS,CAAA;QAC5C,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAA;KAC3B,CAAA;IACD,QAAQ,EAAE;QACR,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE,GAAG,SAAS,CAAA;QAC/C,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;KACjC,CAAA;IACD,QAAQ,EAAE;QACR,gGAAgG;QAChG,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE,GAAG,SAAS,CAAA;QAC1E,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;QAC5C,qFAAqF;QACrF,UAAU,CAAC,MAAM,EAAE,EAAE,GAAG,IAAI,CAAA;KAC7B,CAAA;IACD,iGAAiG;IACjG,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;IACzE,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACzC,KAAK,IAAI,IAAI,CAAA;IACb,KAAK,IAAI,IAAI,CAAA;CACd;AAED,eAAO,MAAM,SAAS,GAAI,mBAAsC,YAAY,KAAG,UA8L9E,CAAA"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/cache/store.ts"],"names":[],"mappings":"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"}
@@ -14,11 +14,86 @@ export const openStore = ({ database, now = () => Date.now() }) => {
14
14
  title = excluded.title, kind = excluded.kind, unread_count = excluded.unread_count,
15
15
  last_message_at = excluded.last_message_at, participants_count = excluded.participants_count,
16
16
  fetched_at = excluded.fetched_at, generation = chats.generation + 1`);
17
- const putContact = database.prepare(`
18
- INSERT INTO contacts (id, name, username, description, fetched_at) VALUES (?, ?, ?, ?, ?)
17
+ /**
18
+ * **`COALESCE`, not assignment, for the three names.** The same person arrives from several
19
+ * places — the login, `CONTACT_INFO`, a group's participant list — and not all of them carry a
20
+ * description or a username. Overwriting with what the latest one happened to omit would blank
21
+ * a name we already had, which is the one thing this table exists to prevent.
22
+ */
23
+ const putPerson = database.prepare(`
24
+ INSERT INTO people (id, name, username, description, last_messaged_at, source, fetched_at)
25
+ VALUES (?, ?, ?, ?, NULL, ?, ?)
19
26
  ON CONFLICT(id) DO UPDATE SET
20
- name = excluded.name, username = excluded.username,
21
- description = excluded.description, fetched_at = excluded.fetched_at`);
27
+ name = coalesce(excluded.name, people.name),
28
+ username = coalesce(excluded.username, people.username),
29
+ description = coalesce(excluded.description, people.description),
30
+ source = excluded.source, fetched_at = excluded.fetched_at`);
31
+ const toContact = (row) => ({
32
+ id: String(row.id),
33
+ name: row.name === null ? null : String(row.name),
34
+ username: row.username === null ? null : String(row.username),
35
+ description: row.description === null ? null : String(row.description),
36
+ lastMessagedAt: row.last_messaged_at === null ? null : new Date(Number(row.last_messaged_at)).toISOString(),
37
+ });
38
+ /**
39
+ * `NULLS LAST` spelled out as a sort key rather than as syntax: it arrived in SQLite 3.30 and
40
+ * this runs on whatever `node:sqlite` and `bun:sqlite` were built against.
41
+ */
42
+ const ORDER = {
43
+ recent: "p.last_messaged_at IS NULL, p.last_messaged_at DESC, p.name IS NULL, p.name",
44
+ name: "p.name IS NULL, p.name",
45
+ };
46
+ /** People a *dialog* exists with. The join is the definition of "contact" (`NEED-105`). */
47
+ const CONTACTS_FROM = `
48
+ FROM people p
49
+ JOIN chat_members m ON m.person_id = p.id
50
+ JOIN chats c ON c.id = m.chat_id AND c.kind = 'dialog'`;
51
+ /**
52
+ * The default order, derived from the dialogs rather than accumulated as they arrive.
53
+ *
54
+ * It has to be a recompute rather than "raise it as each chat lands": a person's row often does
55
+ * not exist yet when their chat does, because the login names six people and the other sixteen
56
+ * come back from a request sent afterwards. An `UPDATE` at that moment reaches nobody.
57
+ *
58
+ * Derived from what we hold, so it is correct however the writes interleave, and cheap — one
59
+ * indexed join over the people who are in a dialog, once per write rather than per listing.
60
+ */
61
+ const refreshRecency = () => {
62
+ database.exec(`
63
+ UPDATE people SET last_messaged_at = (
64
+ SELECT MAX(c.last_message_at) FROM chat_members m
65
+ JOIN chats c ON c.id = m.chat_id AND c.kind = 'dialog'
66
+ WHERE m.person_id = people.id
67
+ )
68
+ WHERE id IN (
69
+ SELECT m.person_id FROM chat_members m
70
+ JOIN chats c ON c.id = m.chat_id AND c.kind = 'dialog'
71
+ )`);
72
+ };
73
+ const upsertPeople = (people, source, at) => {
74
+ for (const person of people) {
75
+ if (!person.id)
76
+ continue;
77
+ putPerson.run(person.id, person.name, person.username, person.description, source, at);
78
+ }
79
+ };
80
+ /**
81
+ * SQLite has no nested transactions and this is the only writer that needs one, so a plain
82
+ * `BEGIN` is enough. The rollback is what item 4 of the plan turns on: a marker saved over rows
83
+ * that were never written makes the next login ask for changes since data we do not have, and
84
+ * nothing downstream ever notices.
85
+ */
86
+ const inTransaction = (body) => {
87
+ database.exec("BEGIN");
88
+ try {
89
+ body();
90
+ database.exec("COMMIT");
91
+ }
92
+ catch (error) {
93
+ database.exec("ROLLBACK");
94
+ throw error;
95
+ }
96
+ };
22
97
  /**
23
98
  * **Compares MAX's clock, never ours.** `update_time` is what MAX sets on an edit and is `NULL`
24
99
  * on a message nobody has changed (measured 2026-09-20).
@@ -66,6 +141,11 @@ export const openStore = ({ database, now = () => Date.now() }) => {
66
141
  return undefined;
67
142
  return database.prepare("SELECT * FROM chats ORDER BY last_message_at DESC").all().map(toChat);
68
143
  },
144
+ page: ({ limit, offset }) => database
145
+ .prepare("SELECT * FROM chats ORDER BY last_message_at DESC LIMIT ? OFFSET ?")
146
+ .all(limit, offset)
147
+ .map(toChat),
148
+ count: () => Number(database.prepare("SELECT COUNT(*) AS n FROM chats").get()?.n ?? 0),
69
149
  write: (chats) => {
70
150
  const at = now();
71
151
  for (const chat of chats) {
@@ -74,27 +154,64 @@ export const openStore = ({ database, now = () => Date.now() }) => {
74
154
  markFetched.run("chats", at);
75
155
  },
76
156
  },
77
- contacts: {
78
- read: (freshForMs) => {
79
- if (!isFresh("contacts", freshForMs))
80
- return undefined;
81
- return database
82
- .prepare("SELECT * FROM contacts ORDER BY name")
83
- .all()
84
- .map((row) => ({
85
- id: String(row.id),
86
- name: row.name === null ? null : String(row.name),
87
- username: row.username === null ? null : String(row.username),
88
- description: row.description === null ? null : String(row.description),
89
- }));
90
- },
91
- write: (contacts) => {
92
- const at = now();
93
- for (const contact of contacts) {
94
- putContact.run(contact.id, contact.name, contact.username, contact.description, at);
157
+ people: {
158
+ contacts: ({ order, limit, offset }) => database
159
+ .prepare(`SELECT DISTINCT p.* ${CONTACTS_FROM} ORDER BY ${ORDER[order]} LIMIT ? OFFSET ?`)
160
+ .all(limit, offset)
161
+ .map(toContact),
162
+ countContacts: () => Number(database.prepare(`SELECT COUNT(DISTINCT p.id) AS n ${CONTACTS_FROM}`).get()?.n ?? 0),
163
+ page: ({ order, limit, offset }) => database
164
+ .prepare(`SELECT p.* FROM people p ORDER BY ${ORDER[order]} LIMIT ? OFFSET ?`)
165
+ .all(limit, offset)
166
+ .map(toContact),
167
+ upsert: (people, source) => upsertPeople(people, source, now()),
168
+ refreshRecency,
169
+ count: () => Number(database.prepare("SELECT COUNT(*) AS n FROM people").get()?.n ?? 0),
170
+ chatsWith: (personId) => database
171
+ .prepare("SELECT chat_id FROM chat_members WHERE person_id = ?")
172
+ .all(personId)
173
+ .map((row) => String(row.chat_id)),
174
+ },
175
+ syncMarker: () => database.prepare("SELECT marker FROM sync_marker WHERE id = 1").get()
176
+ ?.marker,
177
+ mergeDelta: ({ chats, people, members, marker }) => {
178
+ const at = now();
179
+ const summary = { known: 0, added: 0, changed: 0 };
180
+ inTransaction(() => {
181
+ const known = database.prepare("SELECT 1 FROM people WHERE id = ?");
182
+ for (const person of people) {
183
+ if (!person.id)
184
+ continue;
185
+ if (known.get(person.id))
186
+ summary.changed += 1;
187
+ else
188
+ summary.added += 1;
95
189
  }
96
- markFetched.run("contacts", at);
97
- },
190
+ for (const chat of chats) {
191
+ putChat.run(chat.id, chat.title, chat.kind, chat.unreadCount, epoch(chat.lastMessageAt), chat.participantsCount, at);
192
+ }
193
+ upsertPeople(people, "login", at);
194
+ // Replaced per chat, never globally: MAX restates a chat's whole membership whenever it
195
+ // sends that chat, so a member missing from it has left — while a *person* missing from a
196
+ // delta is merely unchanged, which after the first login is every person we know.
197
+ for (const [chatId, personIds] of members) {
198
+ database.prepare("DELETE FROM chat_members WHERE chat_id = ?").run(chatId);
199
+ for (const personId of personIds) {
200
+ database
201
+ .prepare("INSERT OR IGNORE INTO chat_members (chat_id, person_id) VALUES (?, ?)")
202
+ .run(chatId, personId);
203
+ }
204
+ }
205
+ refreshRecency();
206
+ database
207
+ .prepare("INSERT INTO sync_marker (id, marker) VALUES (1, ?) ON CONFLICT(id) DO UPDATE SET marker = excluded.marker")
208
+ .run(marker);
209
+ summary.known = Number(database.prepare("SELECT COUNT(*) AS n FROM people").get()?.n ?? 0);
210
+ });
211
+ return summary;
212
+ },
213
+ forgetSyncMarker: () => {
214
+ database.exec("DELETE FROM sync_marker");
98
215
  },
99
216
  messages: {
100
217
  read: (chatId, limit, freshForMs) => {
@@ -129,6 +246,10 @@ export const openStore = ({ database, now = () => Date.now() }) => {
129
246
  invalidate: (chatId) => {
130
247
  database.prepare("DELETE FROM fetched WHERE kind = ?").run(`messages:${chatId}`);
131
248
  },
249
+ timeOf: (id) => {
250
+ const row = database.prepare("SELECT time FROM messages WHERE id = ? LIMIT 1").get(id);
251
+ return row?.time === undefined ? undefined : Number(row.time);
252
+ },
132
253
  },
133
254
  claim: (chatId, anchor, holder, forMs) => {
134
255
  const at = now();
@@ -143,7 +264,16 @@ export const openStore = ({ database, now = () => Date.now() }) => {
143
264
  database.prepare("DELETE FROM fetch_lease WHERE chat_id = ? AND anchor = ?").run(chatId, anchor);
144
265
  },
145
266
  clear: () => {
146
- for (const table of ["messages", "chats", "contacts", "ranges", "fetched", "fetch_lease"]) {
267
+ for (const table of [
268
+ "messages",
269
+ "chats",
270
+ "people",
271
+ "chat_members",
272
+ "sync_marker",
273
+ "ranges",
274
+ "fetched",
275
+ "fetch_lease",
276
+ ]) {
147
277
  database.exec(`DELETE FROM ${table}`);
148
278
  }
149
279
  },
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/cache/store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAgCrC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,EAAE,QAAQ,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAAgB,EAAc,EAAE;IAC1F,OAAO,CAAC,QAAQ,CAAC,CAAA;IAEjB,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAClC,+FAA+F,CAChG,CAAA;IACD,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAA;IAE3E,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,UAAkB,EAAW,EAAE;QAC5D,MAAM,EAAE,GAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAiC,EAAE,EAAE,CAAA;QACnE,OAAO,EAAE,KAAK,SAAS,IAAI,GAAG,EAAE,GAAG,EAAE,IAAI,UAAU,CAAA;IACrD,CAAC,CAAA;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;;;;;;0EAMuC,CAAC,CAAA;IAEzE,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC;;;;2EAIqC,CAAC,CAAA;IAE1E;;;;;;;;;;;;OAYG;IACH,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC;;;;;;iFAM2C,CAAC,CAAA;IAEhF,MAAM,MAAM,GAAG,CAAC,GAA4B,EAAQ,EAAE,CAAC,CAAC;QACtD,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QAClB,KAAK,EAAE,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;QACpD,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAiB;QACtC,WAAW,EAAE,GAAG,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;QACxE,aAAa,EAAE,GAAG,CAAC,eAAe,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,WAAW,EAAE;QACxG,iBAAiB,EAAE,GAAG,CAAC,kBAAkB,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC;KAC3F,CAAC,CAAA;IAEF,MAAM,SAAS,GAAG,CAAC,GAA4B,EAAW,EAAE,CAAC,CAAC;QAC5D,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;QAC3B,QAAQ,EAAE,GAAG,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC;QAC/D,UAAU,EAAE,GAAG,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;QACrE,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE;QACnD,QAAQ,EAAE,GAAG,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE;QAC3F,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;QACtB,QAAQ,EAAE,GAAG,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC;QAC3D,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAA2B;KAC3E,CAAC,CAAA;IAEF,MAAM,KAAK,GAAG,CAAC,GAAkB,EAAiB,EAAE,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAA;IAEpG,OAAO;QACL,KAAK,EAAE;YACL,IAAI,EAAE,CAAC,UAAU,EAAE,EAAE;gBACnB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC;oBAAE,OAAO,SAAS,CAAA;gBACnD,OAAO,QAAQ,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YAChG,CAAC;YACD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;gBACf,MAAM,EAAE,GAAG,GAAG,EAAE,CAAA;gBAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,WAAW,EAChB,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,EACzB,IAAI,CAAC,iBAAiB,EACtB,EAAE,CACH,CAAA;gBACH,CAAC;gBACD,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;YAC9B,CAAC;SACF;QAED,QAAQ,EAAE;YACR,IAAI,EAAE,CAAC,UAAU,EAAE,EAAE;gBACnB,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC;oBAAE,OAAO,SAAS,CAAA;gBACtD,OAAO,QAAQ;qBACZ,OAAO,CAAC,sCAAsC,CAAC;qBAC/C,GAAG,EAAE;qBACL,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBACb,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;oBAClB,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;oBACjD,QAAQ,EAAE,GAAG,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;oBAC7D,WAAW,EAAE,GAAG,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;iBACvE,CAAC,CAAC,CAAA;YACP,CAAC;YACD,KAAK,EAAE,CAAC,QAAQ,EAAE,EAAE;gBAClB,MAAM,EAAE,GAAG,GAAG,EAAE,CAAA;gBAChB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAC/B,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;gBACrF,CAAC;gBACD,WAAW,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;YACjC,CAAC;SACF;QAED,QAAQ,EAAE;YACR,IAAI,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE;gBAClC,IAAI,CAAC,OAAO,CAAC,YAAY,MAAM,EAAE,EAAE,UAAU,CAAC;oBAAE,OAAO,SAAS,CAAA;gBAChE,MAAM,IAAI,GAAG,QAAQ;qBAClB,OAAO,CAAC,qEAAqE,CAAC;qBAC9E,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;gBAErB,0FAA0F;gBAC1F,2EAA2E;gBAC3E,MAAM,KAAK,GAAG,QAAQ;qBACnB,OAAO,CAAC,4EAA4E,CAAC;qBACrF,GAAG,CAAC,MAAM,CAAC,CAAA;gBACd,IAAI,CAAC,KAAK;oBAAE,OAAO,SAAS,CAAA;gBAE5B,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAA;YACtC,CAAC;YACD,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE;gBAC1B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAM;gBACjC,MAAM,EAAE,GAAG,GAAG,EAAE,CAAA;gBAChB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAC/B,UAAU,CAAC,GAAG,CACZ,MAAM,EACN,OAAO,CAAC,EAAE,EACV,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,UAAU,EAClB,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,EAC7B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EACvB,OAAO,CAAC,IAAI,EACZ,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAC3D,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EACnC,EAAE,CACH,CAAA;gBACH,CAAC;gBAED,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;gBACtE,QAAQ;qBACL,OAAO,CACN;2GAC+F,CAChG;qBACA,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAA;gBACtD,WAAW,CAAC,GAAG,CAAC,YAAY,MAAM,EAAE,EAAE,EAAE,CAAC,CAAA;YAC3C,CAAC;YACD,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE;gBACrB,QAAQ,CAAC,OAAO,CAAC,oCAAoC,CAAC,CAAC,GAAG,CAAC,YAAY,MAAM,EAAE,CAAC,CAAA;YAClF,CAAC;SACF;QAED,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;YACvC,MAAM,EAAE,GAAG,GAAG,EAAE,CAAA;YAChB,OAAO,CACL,QAAQ;iBACL,OAAO,CACN;;;iDAGqC,CACtC;iBACA,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,KAAK,CAAC,CAC7D,CAAA;QACH,CAAC;QAED,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE;YAC1B,QAAQ,CAAC,OAAO,CAAC,0DAA0D,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAClG,CAAC;QAED,KAAK,EAAE,GAAG,EAAE;YACV,KAAK,MAAM,KAAK,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE,CAAC;gBAC1F,QAAQ,CAAC,IAAI,CAAC,eAAe,KAAK,EAAE,CAAC,CAAA;YACvC,CAAC;QACH,CAAC;QAED,KAAK,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE;KAC9B,CAAA;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/cache/store.ts"],"names":[],"mappings":"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"}