aibroker 0.8.3 → 0.8.4
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/dist/adapters/pailot/message-queue.d.ts.map +1 -1
- package/dist/adapters/pailot/message-queue.js +9 -1
- package/dist/adapters/pailot/message-queue.js.map +1 -1
- package/dist/apns/client.d.ts.map +1 -1
- package/dist/apns/client.js +26 -19
- package/dist/apns/client.js.map +1 -1
- package/dist/core/json-store.d.ts +82 -0
- package/dist/core/json-store.d.ts.map +1 -0
- package/dist/core/json-store.js +149 -0
- package/dist/core/json-store.js.map +1 -0
- package/dist/core/persistence.d.ts +2 -0
- package/dist/core/persistence.d.ts.map +1 -1
- package/dist/core/persistence.js +28 -9
- package/dist/core/persistence.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-queue.d.ts","sourceRoot":"","sources":["../../../src/adapters/pailot/message-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"message-queue.d.ts","sourceRoot":"","sources":["../../../src/adapters/pailot/message-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAeH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,EAAE,EAAE,MAAM,CAAC;CACZ;AAiBD,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CA0BpD;AA0BD,yDAAyD;AACzD,wBAAgB,UAAU,IAAI,IAAI,CAYjC;AAID;;;GAGG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAqBjG;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CAM9E;AAED,4DAA4D;AAC5D,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,gDAAgD;AAChD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD"}
|
|
@@ -12,6 +12,7 @@ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
import { homedir } from "node:os";
|
|
14
14
|
import { log } from "../../core/log.js";
|
|
15
|
+
import { saveJson } from "../../core/json-store.js";
|
|
15
16
|
const QUEUE_DIR = join(homedir(), ".aibroker");
|
|
16
17
|
const QUEUE_FILE = join(QUEUE_DIR, "pailot-queue.json");
|
|
17
18
|
const DEFAULT_MAX_SIZE = 500;
|
|
@@ -64,7 +65,14 @@ function scheduleSave() {
|
|
|
64
65
|
dirty = false;
|
|
65
66
|
try {
|
|
66
67
|
const state = { nextSeq, messages };
|
|
67
|
-
|
|
68
|
+
// Atomic, so a crash mid-write cannot truncate the queue into the corrupt
|
|
69
|
+
// state that makes the next load discard it. No .bak: this saves on a
|
|
70
|
+
// 500ms debounce and copying the whole buffer each time would cost more
|
|
71
|
+
// than the backup is worth. Unlike the name and token stores, refusing to
|
|
72
|
+
// save on a corrupt read would be wrong here — undelivered messages are
|
|
73
|
+
// not recoverable from a broken file, so starting fresh IS the correct
|
|
74
|
+
// recovery and blocking writes would disable the queue permanently.
|
|
75
|
+
saveJson(QUEUE_FILE, state, { backup: false });
|
|
68
76
|
}
|
|
69
77
|
catch (err) {
|
|
70
78
|
log(`[MQ] save error: ${err instanceof Error ? err.message : err}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-queue.js","sourceRoot":"","sources":["../../../src/adapters/pailot/message-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"message-queue.js","sourceRoot":"","sources":["../../../src/adapters/pailot/message-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;AACxD,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B,qDAAqD;AACrD,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAe1D,uBAAuB;AAEvB,IAAI,OAAO,GAAG,CAAC,CAAC;AAChB,IAAI,QAAQ,GAAoB,EAAE,CAAC;AACnC,IAAI,OAAO,GAAG,gBAAgB,CAAC;AAC/B,IAAI,KAAK,GAAG,KAAK,CAAC;AAClB,IAAI,UAAU,GAAyC,IAAI,CAAC;AAE5D,sBAAsB;AAEtB,6DAA6D;AAC7D,MAAM,UAAU,SAAS,CAAC,WAAoB;IAC5C,IAAI,WAAW;QAAE,OAAO,GAAG,WAAW,CAAC;IAEvC,IAAI,CAAC;QACH,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAe,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE1C,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;YAC3D,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC1B,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClC,8DAA8D;YAC9D,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;QAC5C,CAAC;QAED,GAAG,CAAC,eAAe,QAAQ,CAAC,MAAM,sBAAsB,OAAO,EAAE,CAAC,CAAC;IACrE,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,GAAG,CAAC,8CAA8C,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,8BAA8B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QAChF,CAAC;QACD,OAAO,GAAG,CAAC,CAAC;QACZ,QAAQ,GAAG,EAAE,CAAC;IAChB,CAAC;AACH,CAAC;AAED,gEAAgE;AAChE,SAAS,YAAY;IACnB,KAAK,GAAG,IAAI,CAAC;IACb,IAAI,UAAU;QAAE,OAAO;IACvB,UAAU,GAAG,UAAU,CAAC,GAAG,EAAE;QAC3B,UAAU,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,KAAK,GAAG,KAAK,CAAC;QACd,IAAI,CAAC;YACH,MAAM,KAAK,GAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;YAChD,0EAA0E;YAC1E,sEAAsE;YACtE,wEAAwE;YACxE,0EAA0E;YAC1E,wEAAwE;YACxE,uEAAuE;YACvE,oEAAoE;YACpE,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,oBAAoB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,qEAAqE;AAChF,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,UAAU;IACxB,IAAI,UAAU,EAAE,CAAC;QACf,YAAY,CAAC,UAAU,CAAC,CAAC;QACzB,UAAU,GAAG,IAAI,CAAC;IACpB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,KAAK,GAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;QAChD,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QAC1D,GAAG,CAAC,gBAAgB,QAAQ,CAAC,MAAM,mBAAmB,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,qBAAqB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED,oBAAoB;AAEpB;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,SAAiB,EAAE,IAAY,EAAE,OAAgC;IACvF,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAEvC,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,MAAM,KAAK,GAAkB;QAC3B,GAAG;QACH,SAAS;QACT,IAAI;QACJ,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE;QAC5B,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;KACf,CAAC;IAEF,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAErB,uBAAuB;IACvB,IAAI,QAAQ,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;QAC9B,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,YAAY,EAAE,CAAC;IACf,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAgB,EAAE,SAAkB;IAC3D,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;QACzB,IAAI,CAAC,CAAC,GAAG,IAAI,QAAQ;YAAE,OAAO,KAAK,CAAC;QACpC,IAAI,SAAS,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,GAAG,CAAC,CAAC;AACrB,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/apns/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/apns/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAkGH;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAQjD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI/C;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,MAAM,EAAE,CAEpC;AAOD,iEAAiE;AACjE,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAID,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CA8B3F;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAepD"}
|
package/dist/apns/client.js
CHANGED
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
* APNS_TEAM_ID — 10-character Apple Team ID (e.g., 7KU642K5ZL)
|
|
11
11
|
* APNS_PRODUCTION — set to "1" or "true" to use production APNs host
|
|
12
12
|
*/
|
|
13
|
-
import { readFileSync,
|
|
13
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
14
14
|
import { join } from "node:path";
|
|
15
15
|
import { homedir } from "node:os";
|
|
16
16
|
import { createRequire } from "node:module";
|
|
17
17
|
import { log } from "../core/log.js";
|
|
18
|
+
import { GuardedStore } from "../core/json-store.js";
|
|
18
19
|
const require = createRequire(import.meta.url);
|
|
19
20
|
const APNS_BUNDLE_ID = "com.tekmidian.pailot";
|
|
20
21
|
const TOKENS_FILE = join(homedir(), ".aibroker", "apns-tokens.json");
|
|
@@ -61,27 +62,33 @@ function getApnsClient() {
|
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
// --- Token storage ---
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Registered device tokens.
|
|
67
|
+
*
|
|
68
|
+
* Guarded because the read-then-write cycle here silently deletes devices: an
|
|
69
|
+
* unreadable token file used to read as `[]`, the newly registering device was
|
|
70
|
+
* appended to nothing, and the save persisted a one-element list. Every other
|
|
71
|
+
* device stops receiving push, with no error at any point — and a notification
|
|
72
|
+
* that never arrives is not something anyone notices for days.
|
|
73
|
+
*/
|
|
74
|
+
let _tokenStore = null;
|
|
75
|
+
function tokenStore() {
|
|
76
|
+
if (_tokenStore === null) {
|
|
77
|
+
_tokenStore = new GuardedStore(TOKENS_FILE, () => [], "[APNs]");
|
|
74
78
|
}
|
|
79
|
+
return _tokenStore;
|
|
80
|
+
}
|
|
81
|
+
function loadTokens() {
|
|
82
|
+
const raw = tokenStore().load();
|
|
83
|
+
// Tolerate a hand-edited file that parsed but isn't the expected shape.
|
|
84
|
+
return Array.isArray(raw) ? raw.filter((t) => typeof t === "string") : [];
|
|
75
85
|
}
|
|
76
86
|
function saveTokens(tokens) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
catch (err) {
|
|
83
|
-
log(`[APNs] failed to save tokens: ${err instanceof Error ? err.message : String(err)}`);
|
|
84
|
-
}
|
|
87
|
+
const store = tokenStore();
|
|
88
|
+
const cache = store.load();
|
|
89
|
+
cache.length = 0;
|
|
90
|
+
cache.push(...tokens);
|
|
91
|
+
store.save();
|
|
85
92
|
}
|
|
86
93
|
/**
|
|
87
94
|
* Register a device token. Silently ignores duplicates.
|
package/dist/apns/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/apns/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/apns/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/json-store.ts — durable JSON state files.
|
|
3
|
+
*
|
|
4
|
+
* Every persisted store here follows the same shape: read it, modify it, write
|
|
5
|
+
* it back. That shape has one catastrophic failure mode, and it is silent:
|
|
6
|
+
*
|
|
7
|
+
* read fails -> caller substitutes an empty default -> write makes it permanent
|
|
8
|
+
*
|
|
9
|
+
* A file that is briefly unreadable, or corrupt from a half-finished write,
|
|
10
|
+
* becomes an empty object. The next ordinary update — registering a device,
|
|
11
|
+
* renaming a session — then persists that emptiness over real data and reports
|
|
12
|
+
* success. Nothing errors, nothing logs, and the loss is only noticed later
|
|
13
|
+
* when a push never arrives or every session has lost its name.
|
|
14
|
+
*
|
|
15
|
+
* The fix is to make "I could not read it" a THIRD outcome that callers cannot
|
|
16
|
+
* accidentally treat as "it was empty":
|
|
17
|
+
*
|
|
18
|
+
* missing — legitimately absent, start fresh, writing is safe
|
|
19
|
+
* ok — parsed, writing is safe
|
|
20
|
+
* unreadable — exists but could not be parsed. NEVER overwrite: the bytes on
|
|
21
|
+
* disk are the only copy of whatever is in there.
|
|
22
|
+
*
|
|
23
|
+
* Writes are atomic (temp + rename) so a crash mid-write cannot truncate a good
|
|
24
|
+
* file into a corrupt one, and the previous contents are kept as `.bak` so even
|
|
25
|
+
* a logic error upstream is recoverable.
|
|
26
|
+
*/
|
|
27
|
+
export type LoadResult<T> = {
|
|
28
|
+
status: "ok";
|
|
29
|
+
data: T;
|
|
30
|
+
} | {
|
|
31
|
+
status: "missing";
|
|
32
|
+
} | {
|
|
33
|
+
status: "unreadable";
|
|
34
|
+
error: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Read a JSON store, distinguishing absent from unreadable.
|
|
38
|
+
*
|
|
39
|
+
* Deliberately returns a result rather than `T | null`: a nullable return is
|
|
40
|
+
* what lets `?? {}` quietly turn corruption into an empty store.
|
|
41
|
+
*/
|
|
42
|
+
export declare function loadJson<T>(path: string): LoadResult<T>;
|
|
43
|
+
/**
|
|
44
|
+
* Write a JSON store atomically, keeping the previous contents as `.bak`.
|
|
45
|
+
*
|
|
46
|
+
* temp + rename means a reader never sees a partial file and a crash cannot
|
|
47
|
+
* leave a truncated one, which is the usual way these files become corrupt in
|
|
48
|
+
* the first place.
|
|
49
|
+
*/
|
|
50
|
+
export declare function saveJson(path: string, data: unknown, opts?: {
|
|
51
|
+
backup?: boolean;
|
|
52
|
+
}): void;
|
|
53
|
+
/**
|
|
54
|
+
* A store that refuses to save once its file has been found unreadable.
|
|
55
|
+
*
|
|
56
|
+
* Holding the flag matters as much as the initial check: these stores cache
|
|
57
|
+
* their contents, so a single transient read failure at startup would
|
|
58
|
+
* otherwise poison every later write for the lifetime of the process, long
|
|
59
|
+
* after the file itself is readable again.
|
|
60
|
+
*/
|
|
61
|
+
export declare class GuardedStore<T> {
|
|
62
|
+
private readonly path;
|
|
63
|
+
private readonly empty;
|
|
64
|
+
private readonly label;
|
|
65
|
+
private cache;
|
|
66
|
+
private blocked;
|
|
67
|
+
private blockedReason;
|
|
68
|
+
constructor(path: string, empty: () => T, label: string);
|
|
69
|
+
/** Contents, or an empty value when missing/unreadable. Never throws. */
|
|
70
|
+
load(): T;
|
|
71
|
+
/** True when the backing file could not be read and must not be overwritten. */
|
|
72
|
+
isBlocked(): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Persist the cache. A no-op — loudly — when the file was unreadable, because
|
|
75
|
+
* writing would replace data we were never able to see with the empty value
|
|
76
|
+
* we substituted for it.
|
|
77
|
+
*/
|
|
78
|
+
save(): boolean;
|
|
79
|
+
/** Drop the in-memory copy (and any block) so the next load re-reads disk. */
|
|
80
|
+
reset(): void;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=json-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-store.d.ts","sourceRoot":"","sources":["../../src/core/json-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,MAAM,MAAM,UAAU,CAAC,CAAC,IACpB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GACzB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5C;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAUvD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,IAAI,CAkB3F;AAED;;;;;;;GAOG;AACH,qBAAa,YAAY,CAAC,CAAC;IAMvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAPxB,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAM;gBAGR,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,EACd,KAAK,EAAE,MAAM;IAGhC,yEAAyE;IACzE,IAAI,IAAI,CAAC;IAeT,gFAAgF;IAChF,SAAS,IAAI,OAAO;IAEpB;;;;OAIG;IACH,IAAI,IAAI,OAAO;IAgBf,8EAA8E;IAC9E,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/json-store.ts — durable JSON state files.
|
|
3
|
+
*
|
|
4
|
+
* Every persisted store here follows the same shape: read it, modify it, write
|
|
5
|
+
* it back. That shape has one catastrophic failure mode, and it is silent:
|
|
6
|
+
*
|
|
7
|
+
* read fails -> caller substitutes an empty default -> write makes it permanent
|
|
8
|
+
*
|
|
9
|
+
* A file that is briefly unreadable, or corrupt from a half-finished write,
|
|
10
|
+
* becomes an empty object. The next ordinary update — registering a device,
|
|
11
|
+
* renaming a session — then persists that emptiness over real data and reports
|
|
12
|
+
* success. Nothing errors, nothing logs, and the loss is only noticed later
|
|
13
|
+
* when a push never arrives or every session has lost its name.
|
|
14
|
+
*
|
|
15
|
+
* The fix is to make "I could not read it" a THIRD outcome that callers cannot
|
|
16
|
+
* accidentally treat as "it was empty":
|
|
17
|
+
*
|
|
18
|
+
* missing — legitimately absent, start fresh, writing is safe
|
|
19
|
+
* ok — parsed, writing is safe
|
|
20
|
+
* unreadable — exists but could not be parsed. NEVER overwrite: the bytes on
|
|
21
|
+
* disk are the only copy of whatever is in there.
|
|
22
|
+
*
|
|
23
|
+
* Writes are atomic (temp + rename) so a crash mid-write cannot truncate a good
|
|
24
|
+
* file into a corrupt one, and the previous contents are kept as `.bak` so even
|
|
25
|
+
* a logic error upstream is recoverable.
|
|
26
|
+
*/
|
|
27
|
+
import { readFileSync, writeFileSync, existsSync, renameSync, copyFileSync, unlinkSync, mkdirSync } from "node:fs";
|
|
28
|
+
import { dirname } from "node:path";
|
|
29
|
+
import { log } from "./log.js";
|
|
30
|
+
/**
|
|
31
|
+
* Read a JSON store, distinguishing absent from unreadable.
|
|
32
|
+
*
|
|
33
|
+
* Deliberately returns a result rather than `T | null`: a nullable return is
|
|
34
|
+
* what lets `?? {}` quietly turn corruption into an empty store.
|
|
35
|
+
*/
|
|
36
|
+
export function loadJson(path) {
|
|
37
|
+
if (!existsSync(path))
|
|
38
|
+
return { status: "missing" };
|
|
39
|
+
try {
|
|
40
|
+
return { status: "ok", data: JSON.parse(readFileSync(path, "utf-8")) };
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
44
|
+
log(`json-store: ${path} exists but could not be read (${error}). ` +
|
|
45
|
+
`Refusing to treat it as empty — writes to this store are now blocked to avoid overwriting it.`);
|
|
46
|
+
return { status: "unreadable", error };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Write a JSON store atomically, keeping the previous contents as `.bak`.
|
|
51
|
+
*
|
|
52
|
+
* temp + rename means a reader never sees a partial file and a crash cannot
|
|
53
|
+
* leave a truncated one, which is the usual way these files become corrupt in
|
|
54
|
+
* the first place.
|
|
55
|
+
*/
|
|
56
|
+
export function saveJson(path, data, opts = {}) {
|
|
57
|
+
const { backup = true } = opts;
|
|
58
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
59
|
+
// Skipped for high-churn stores where a copy on every write costs more than
|
|
60
|
+
// the backup is worth; the atomic rename below is the part that matters.
|
|
61
|
+
if (backup && existsSync(path)) {
|
|
62
|
+
try {
|
|
63
|
+
copyFileSync(path, `${path}.bak`);
|
|
64
|
+
}
|
|
65
|
+
catch { /* best effort */ }
|
|
66
|
+
}
|
|
67
|
+
const tmp = `${path}.tmp`;
|
|
68
|
+
try {
|
|
69
|
+
writeFileSync(tmp, JSON.stringify(data, null, 2), "utf-8");
|
|
70
|
+
renameSync(tmp, path);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
try {
|
|
74
|
+
if (existsSync(tmp))
|
|
75
|
+
unlinkSync(tmp);
|
|
76
|
+
}
|
|
77
|
+
catch { /* best effort */ }
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A store that refuses to save once its file has been found unreadable.
|
|
83
|
+
*
|
|
84
|
+
* Holding the flag matters as much as the initial check: these stores cache
|
|
85
|
+
* their contents, so a single transient read failure at startup would
|
|
86
|
+
* otherwise poison every later write for the lifetime of the process, long
|
|
87
|
+
* after the file itself is readable again.
|
|
88
|
+
*/
|
|
89
|
+
export class GuardedStore {
|
|
90
|
+
path;
|
|
91
|
+
empty;
|
|
92
|
+
label;
|
|
93
|
+
cache = null;
|
|
94
|
+
blocked = false;
|
|
95
|
+
blockedReason = "";
|
|
96
|
+
constructor(path, empty, label) {
|
|
97
|
+
this.path = path;
|
|
98
|
+
this.empty = empty;
|
|
99
|
+
this.label = label;
|
|
100
|
+
}
|
|
101
|
+
/** Contents, or an empty value when missing/unreadable. Never throws. */
|
|
102
|
+
load() {
|
|
103
|
+
if (this.cache !== null)
|
|
104
|
+
return this.cache;
|
|
105
|
+
const res = loadJson(this.path);
|
|
106
|
+
if (res.status === "ok") {
|
|
107
|
+
this.cache = res.data;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
if (res.status === "unreadable") {
|
|
111
|
+
this.blocked = true;
|
|
112
|
+
this.blockedReason = res.error;
|
|
113
|
+
}
|
|
114
|
+
this.cache = this.empty();
|
|
115
|
+
}
|
|
116
|
+
return this.cache;
|
|
117
|
+
}
|
|
118
|
+
/** True when the backing file could not be read and must not be overwritten. */
|
|
119
|
+
isBlocked() { return this.blocked; }
|
|
120
|
+
/**
|
|
121
|
+
* Persist the cache. A no-op — loudly — when the file was unreadable, because
|
|
122
|
+
* writing would replace data we were never able to see with the empty value
|
|
123
|
+
* we substituted for it.
|
|
124
|
+
*/
|
|
125
|
+
save() {
|
|
126
|
+
if (this.blocked) {
|
|
127
|
+
log(`${this.label}: NOT saving — ${this.path} was unreadable at load (${this.blockedReason}). ` +
|
|
128
|
+
`The file is untouched; fix or remove it and restart to resume persistence.`);
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
if (this.cache === null)
|
|
132
|
+
return false;
|
|
133
|
+
try {
|
|
134
|
+
saveJson(this.path, this.cache);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
log(`${this.label}: failed to save ${this.path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** Drop the in-memory copy (and any block) so the next load re-reads disk. */
|
|
143
|
+
reset() {
|
|
144
|
+
this.cache = null;
|
|
145
|
+
this.blocked = false;
|
|
146
|
+
this.blockedReason = "";
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=json-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-store.js","sourceRoot":"","sources":["../../src/core/json-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACnH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAO/B;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAI,IAAY;IACtC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACpD,IAAI,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAM,EAAE,CAAC;IAC9E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC/D,GAAG,CAAC,eAAe,IAAI,kCAAkC,KAAK,KAAK;YAC/D,+FAA+F,CAAC,CAAC;QACrG,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IACzC,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,IAAa,EAAE,OAA6B,EAAE;IACnF,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAC/B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE9C,4EAA4E;IAC5E,yEAAyE;IACzE,IAAI,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,IAAI,CAAC;YAAC,YAAY,CAAC,IAAI,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,IAAI,MAAM,CAAC;IAC1B,IAAI,CAAC;QACH,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC3D,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YAAC,IAAI,UAAU,CAAC,GAAG,CAAC;gBAAE,UAAU,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;QACzE,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,YAAY;IAMJ;IACA;IACA;IAPX,KAAK,GAAa,IAAI,CAAC;IACvB,OAAO,GAAG,KAAK,CAAC;IAChB,aAAa,GAAG,EAAE,CAAC;IAE3B,YACmB,IAAY,EACZ,KAAc,EACd,KAAa;QAFb,SAAI,GAAJ,IAAI,CAAQ;QACZ,UAAK,GAAL,KAAK,CAAS;QACd,UAAK,GAAL,KAAK,CAAQ;IAC7B,CAAC;IAEJ,yEAAyE;IACzE,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;QAC3C,MAAM,GAAG,GAAG,QAAQ,CAAI,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;gBAChC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;gBACpB,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,KAAK,CAAC;YACjC,CAAC;YACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,gFAAgF;IAChF,SAAS,KAAc,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAE7C;;;;OAIG;IACH,IAAI;QACF,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,kBAAkB,IAAI,CAAC,IAAI,4BAA4B,IAAI,CAAC,aAAa,KAAK;gBAC3F,4EAA4E,CAAC,CAAC;YAClF,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACtC,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAChC,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,oBAAoB,IAAI,CAAC,IAAI,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACvG,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -18,6 +18,8 @@ export declare function saveVoiceConfig(config?: VoiceConfig): void;
|
|
|
18
18
|
export declare function loadSessionRegistry(): void;
|
|
19
19
|
export declare function saveSessionRegistry(): void;
|
|
20
20
|
type SessionNamesStore = Record<string, string>;
|
|
21
|
+
/** Drop the cached name store (used when the app dir changes, and by tests). */
|
|
22
|
+
export declare function resetSessionNamesCache(): void;
|
|
21
23
|
/**
|
|
22
24
|
* Persist a user-chosen name for an iTerm2 session.
|
|
23
25
|
* @param itermSessionId - the raw iTerm2 session UUID (e.g. "942A4044-...")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../src/core/persistence.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../src/core/persistence.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH,OAAO,KAAK,EAAE,WAAW,EAAuB,MAAM,mBAAmB,CAAC;AAM1E;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAK3C;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAuBD,eAAO,MAAM,oBAAoB,EAAE,WAUlC,CAAC;AAEF,wBAAgB,eAAe,IAAI,WAAW,CAS7C;AAED,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,CAE1D;AAID,wBAAgB,mBAAmB,IAAI,IAAI,CAgC1C;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAU1C;AASD,KAAK,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAkChD,gFAAgF;AAChF,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAInF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEnF;AAED;;GAEG;AACH,wBAAgB,4BAA4B,IAAI,iBAAiB,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,iBAAiB,EACxB,EAAE,EAAE,MAAM,EACV,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,MAAM,GAAG,IAAI,CAGf;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAIxE"}
|
package/dist/core/persistence.js
CHANGED
|
@@ -9,6 +9,7 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
import { log } from "./log.js";
|
|
12
|
+
import { GuardedStore } from "./json-store.js";
|
|
12
13
|
import { sessionRegistry, clientQueues, activeItermSessionId, setActiveItermSessionId, voiceConfig, setVoiceConfig, } from "./state.js";
|
|
13
14
|
// ── Configuration ──
|
|
14
15
|
let _appDir = join(homedir(), ".aibroker");
|
|
@@ -18,6 +19,9 @@ let _appDir = join(homedir(), ".aibroker");
|
|
|
18
19
|
*/
|
|
19
20
|
export function setAppDir(dir) {
|
|
20
21
|
_appDir = dir;
|
|
22
|
+
// The name store binds its path at construction, so a later dir change must
|
|
23
|
+
// invalidate it or it would keep reading (and writing) the previous location.
|
|
24
|
+
resetSessionNamesCache();
|
|
21
25
|
}
|
|
22
26
|
export function getAppDir() {
|
|
23
27
|
return _appDir;
|
|
@@ -110,18 +114,33 @@ export function saveSessionRegistry() {
|
|
|
110
114
|
// Survives daemon restarts. Used to re-assert tab titles after Claude Code
|
|
111
115
|
// overwrites them with its auto-generated ai-title.
|
|
112
116
|
const SESSION_NAMES_FILE = "session-names.json";
|
|
113
|
-
/**
|
|
114
|
-
|
|
117
|
+
/**
|
|
118
|
+
* The persistent name store.
|
|
119
|
+
*
|
|
120
|
+
* Guarded rather than a plain `?? {}`: this file maps every session id to its
|
|
121
|
+
* PAI name, and those names are what dispatch and name-targeted sends resolve
|
|
122
|
+
* against. Reading it as empty and then saving one rename over the top would
|
|
123
|
+
* discard the lot, silently, on an operation that reports success — and the
|
|
124
|
+
* result is cached, so a single unreadable read at startup would keep
|
|
125
|
+
* truncating the file for the rest of the daemon's life.
|
|
126
|
+
*/
|
|
127
|
+
let _sessionNames = null;
|
|
128
|
+
function sessionNames() {
|
|
129
|
+
// Built lazily: _appDir is configurable and may be set after module load.
|
|
130
|
+
if (_sessionNames === null) {
|
|
131
|
+
_sessionNames = new GuardedStore(join(_appDir, SESSION_NAMES_FILE), () => ({}), "session-names");
|
|
132
|
+
}
|
|
133
|
+
return _sessionNames;
|
|
134
|
+
}
|
|
115
135
|
function loadSessionNames() {
|
|
116
|
-
|
|
117
|
-
return _sessionNamesCache;
|
|
118
|
-
_sessionNamesCache = safeReadJson(SESSION_NAMES_FILE) ?? {};
|
|
119
|
-
return _sessionNamesCache;
|
|
136
|
+
return sessionNames().load();
|
|
120
137
|
}
|
|
121
138
|
function saveSessionNames() {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
139
|
+
sessionNames().save();
|
|
140
|
+
}
|
|
141
|
+
/** Drop the cached name store (used when the app dir changes, and by tests). */
|
|
142
|
+
export function resetSessionNamesCache() {
|
|
143
|
+
_sessionNames = null;
|
|
125
144
|
}
|
|
126
145
|
/**
|
|
127
146
|
* Persist a user-chosen name for an iTerm2 session.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence.js","sourceRoot":"","sources":["../../src/core/persistence.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EACL,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,uBAAuB,EACvB,WAAW,EACX,cAAc,GACf,MAAM,YAAY,CAAC;AAGpB,sBAAsB;AAEtB,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AAE3C;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,GAAG,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"persistence.js","sourceRoot":"","sources":["../../src/core/persistence.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,uBAAuB,EACvB,WAAW,EACX,cAAc,GACf,MAAM,YAAY,CAAC;AAGpB,sBAAsB;AAEtB,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AAE3C;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,GAAG,GAAG,CAAC;IACd,4EAA4E;IAC5E,8EAA8E;IAC9E,sBAAsB,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,SAAS;IAChB,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,YAAY,CAAI,QAAgB;IACvC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB,EAAE,IAAa;IACpD,SAAS,EAAE,CAAC;IACZ,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACjF,CAAC;AAED,qBAAqB;AAErB,MAAM,CAAC,MAAM,oBAAoB,GAAgB;IAC/C,YAAY,EAAE,UAAU;IACxB,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,KAAK;IAChB,QAAQ,EAAE;QACR,MAAM,EAAE,WAAW;QACnB,MAAM,EAAE,WAAW;QACnB,MAAM,EAAE,WAAW;QACnB,KAAK,EAAE,UAAU;KAClB;CACF,CAAC;AAEF,MAAM,UAAU,eAAe;IAC7B,MAAM,IAAI,GAAG,YAAY,CAAc,mBAAmB,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAgB;QAC1B,GAAG,oBAAoB;QACvB,GAAG,IAAI;QACP,QAAQ,EAAE,EAAE,GAAG,oBAAoB,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC,EAAE;KAC1E,CAAC;IACF,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,aAAa,CAAC,mBAAmB,EAAE,MAAM,IAAI,WAAW,CAAC,CAAC;AAC5D,CAAC;AAED,yBAAyB;AAEzB,MAAM,UAAU,mBAAmB;IACjC,MAAM,MAAM,GAAG,YAAY,CACzB,eAAe,CAChB,CAAC;IACF,IAAI,CAAC,MAAM;QAAE,OAAO;IAEpB,qGAAqG;IACrG,MAAM,GAAG,GACP,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAE3D,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC,SAAS;YAAE,SAAS;QAC/B,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE;YACnC,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,SAAS;YAC7B,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE;SACzB,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,oBAAoB,EAAE,CAAC;QAC1D,uBAAuB,CAAC,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC;QAC7D,GAAG,CAAC,kCAAkC,MAAM,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnB,GAAG,CAAC,YAAY,GAAG,CAAC,MAAM,uBAAuB,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,MAAM,IAAI,GAAwB;QAChC,oBAAoB,EAAE,oBAAoB,IAAI,EAAE;QAChD,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzD,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,cAAc,EAAE,CAAC,CAAC,cAAc;SACjC,CAAC,CAAC;KACJ,CAAC;IACF,aAAa,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,iCAAiC;AACjC,uEAAuE;AACvE,2EAA2E;AAC3E,oDAAoD;AAEpD,MAAM,kBAAkB,GAAG,oBAAoB,CAAC;AAIhD;;;;;;;;;GASG;AACH,IAAI,aAAa,GAA2C,IAAI,CAAC;AAEjE,SAAS,YAAY;IACnB,0EAA0E;IAC1E,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAC3B,aAAa,GAAG,IAAI,YAAY,CAC9B,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,EACjC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EACV,eAAe,CAChB,CAAC;IACJ,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAS,gBAAgB;IACvB,OAAO,YAAY,EAAE,CAAC,IAAI,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,gBAAgB;IACvB,YAAY,EAAE,CAAC,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,sBAAsB;IACpC,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,cAAsB,EAAE,IAAY;IAC3E,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAC;IACjC,KAAK,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,cAAsB;IAC7D,OAAO,gBAAgB,EAAE,CAAC,cAAc,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,4BAA4B;IAC1C,OAAO,EAAE,GAAG,gBAAgB,EAAE,EAAE,CAAC;AACnC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAwB,EACxB,EAAU,EACV,SAAyB;IAEzB,IAAI,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC,SAAS,CAAC,CAAC;IAC3D,OAAO,KAAK,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,2BAA2B,CAAC,cAAsB;IAChE,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAC;IACjC,OAAO,KAAK,CAAC,cAAc,CAAC,CAAC;IAC7B,gBAAgB,EAAE,CAAC;AACrB,CAAC"}
|