@bobfrankston/mailx-settings 0.1.6 → 0.1.7

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/cloud.d.ts CHANGED
@@ -16,10 +16,35 @@
16
16
  * Dropbox (removed 2026-04-06): Never implemented — placeholder only.
17
17
  * Would need Dropbox OAuth app, token management, and Dropbox API v2 calls.
18
18
  */
19
- /** Find the settings folder on GDrive, or create a flat "mailx" folder.
20
- * Supports nested paths from config (e.g. "home/.mailx") by walking each
21
- * segment. Falls back to the folderId in config if set, so a stale ID that
22
- * points to the wrong folder gets corrected on next lookup. */
19
+ /** Verify a cached folder ID still points to an `.rmfmail`-named folder
20
+ * the user owns and isn't trashed. Returns true if the ID is good to use,
21
+ * false if mailx should drop it and re-discover via gDriveFindOrCreateFolder.
22
+ *
23
+ * Catches the cross-version-corruption case: 1.0.504 had a buggy folder
24
+ * lookup that created an empty `rmfmail` folder at My Drive root and cached
25
+ * its ID. Once 1.0.505 fixed the lookup, the cached ID still pointed at the
26
+ * buggy folder forever — mailx kept reading the 1-account stub instead of
27
+ * the user's real `home/.rmfmail/accounts.jsonc`. This validator forces a
28
+ * re-discovery whenever the cached ID is wrong. */
29
+ export declare function gDriveValidateCachedFolder(folderId: string): Promise<boolean>;
30
+ /** Find or create the rmfmail settings folder on Google Drive.
31
+ *
32
+ * Lookup order — match the Android side (`mailx-store-web/android-bootstrap.ts`):
33
+ * 1. `home/.rmfmail/` — the established convention. Bob's family-of-two
34
+ * layout has been here since the rebrand. Path scope (`'root' in
35
+ * parents` for `home`, then `<homeId> in parents` for `.rmfmail`) is
36
+ * what the Android side does, so desktop matches.
37
+ * 2. `.rmfmail/` at My Drive root — fallback for users who don't have a
38
+ * `home/` folder. Mostly hypothetical; included so a brand-new Drive
39
+ * still works.
40
+ * 3. Create `.rmfmail` at My Drive root if neither exists. Don't auto-
41
+ * create `home/` — that's a user-organization choice we shouldn't
42
+ * make for them.
43
+ *
44
+ * Previously this looked for a literal `rmfmail` (no dot) at root, which
45
+ * on clean install created a NEW empty folder alongside the real data,
46
+ * orphaning the user's accounts/contacts/etc. Switched to the dotted name
47
+ * matching the actual folder convention. */
23
48
  export declare function gDriveFindOrCreateFolder(): Promise<string | null>;
24
49
  export type CloudProvider = "gdrive" | "google" | "local";
25
50
  export interface CloudFile {
package/cloud.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["cloud.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA0JH;;;;;;;;;oDASoD;AACpD,wBAAsB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA8BnF;AAcD;;;;;;;;;;;;;;;;;6CAiB6C;AAC7C,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBvE;AA4ED,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE1D,MAAM,WAAW,SAAS;IACtB,kFAAkF;IAClF,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/C,uGAAuG;IACvG,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,8BAA8B;IAC9B,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAuBtF;AAED;;;;2DAI2D;AAC3D,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAoBvG"}
package/cloud.js CHANGED
@@ -19,7 +19,7 @@
19
19
  import fs from "node:fs";
20
20
  import path from "node:path";
21
21
  import { authenticateOAuth } from "@bobfrankston/oauthsupport";
22
- const SETTINGS_DIR = path.join(process.env.USERPROFILE || process.env.HOME || ".", ".mailx");
22
+ const SETTINGS_DIR = path.join(process.env.USERPROFILE || process.env.HOME || ".", ".rmfmail");
23
23
  // ── Credentials ──
24
24
  // Google Drive: reuse iflow's OAuth credentials (same Google Cloud project)
25
25
  function findGoogleCredentials() {
@@ -54,10 +54,6 @@ const GDRIVE_TOKEN_DIR = path.join(SETTINGS_DIR, "tokens", "gdrive");
54
54
  // The Gmail scope is already mail.google.com (full email), so this isn't a
55
55
  // bigger privacy ask. Token cache at tokens/gdrive/ will re-auth on scope change.
56
56
  const GDRIVE_SCOPES = "https://www.googleapis.com/auth/drive";
57
- /** Paths to try when no config.path is set (fresh install). Order matters:
58
- * "home/.mailx" is the user convention for shared family settings; "mailx"
59
- * is the auto-created default. First one that exists on GDrive wins. */
60
- const GDRIVE_PATH_SEARCH_ORDER = ["home/.mailx", "mailx"];
61
57
  // ── Token helpers ──
62
58
  /** Get a GDrive-capable token. Prefers the Gmail token (which now includes
63
59
  * drive scope) — avoids a second OAuth consent prompt. Falls back to the
@@ -103,7 +99,7 @@ async function getGoogleDriveToken() {
103
99
  // Strategy 2: dedicated GDrive token (legacy path or non-Gmail setups)
104
100
  const creds = findGoogleCredentials();
105
101
  if (!creds) {
106
- console.error(" [cloud] No Google credentials found (checked ~/.mailx/google-credentials.json and iflow package)");
102
+ console.error(" [cloud] No Google credentials found (checked ~/.rmfmail/google-credentials.json and iflow package)");
107
103
  return null;
108
104
  }
109
105
  const tokenPath = path.join(GDRIVE_TOKEN_DIR, "token.json");
@@ -179,19 +175,46 @@ async function walkGDrivePath(token, segments, create) {
179
175
  }
180
176
  return parentId || null;
181
177
  }
182
- /** Resolve a folder ID back to its name (for diagnostic logging). */
183
- async function gDriveGetFolderName(token, folderId) {
178
+ /** Verify a cached folder ID still points to an `.rmfmail`-named folder
179
+ * the user owns and isn't trashed. Returns true if the ID is good to use,
180
+ * false if mailx should drop it and re-discover via gDriveFindOrCreateFolder.
181
+ *
182
+ * Catches the cross-version-corruption case: 1.0.504 had a buggy folder
183
+ * lookup that created an empty `rmfmail` folder at My Drive root and cached
184
+ * its ID. Once 1.0.505 fixed the lookup, the cached ID still pointed at the
185
+ * buggy folder forever — mailx kept reading the 1-account stub instead of
186
+ * the user's real `home/.rmfmail/accounts.jsonc`. This validator forces a
187
+ * re-discovery whenever the cached ID is wrong. */
188
+ export async function gDriveValidateCachedFolder(folderId) {
189
+ const token = await getGoogleDriveToken();
190
+ if (!token)
191
+ return true; // can't verify → trust the cache (no token = nothing else to do)
184
192
  try {
185
- const res = await fetch(`https://www.googleapis.com/drive/v3/files/${folderId}?fields=name,parents`, {
186
- headers: { Authorization: `Bearer ${token}` },
187
- });
193
+ const res = await fetch(`https://www.googleapis.com/drive/v3/files/${folderId}?fields=id,name,trashed,mimeType`, { headers: { Authorization: `Bearer ${token}` } });
194
+ if (res.status === 404) {
195
+ console.log(` [cloud] cached folderId ${folderId} → 404 (folder deleted), re-discovering`);
196
+ return false;
197
+ }
188
198
  if (!res.ok)
189
- return null;
199
+ return true;
190
200
  const data = await res.json();
191
- return data.name || null;
201
+ if (data.trashed) {
202
+ console.log(` [cloud] cached folderId ${folderId} is trashed, re-discovering`);
203
+ return false;
204
+ }
205
+ if (data.mimeType !== "application/vnd.google-apps.folder") {
206
+ console.log(` [cloud] cached folderId ${folderId} is not a folder (${data.mimeType}), re-discovering`);
207
+ return false;
208
+ }
209
+ if (data.name !== ".rmfmail") {
210
+ console.log(` [cloud] cached folderId ${folderId} is named '${data.name}', not '.rmfmail' — re-discovering`);
211
+ return false;
212
+ }
213
+ return true;
192
214
  }
193
- catch {
194
- return null;
215
+ catch (e) {
216
+ console.error(` [cloud] gDriveValidateCachedFolder: ${e.message}`);
217
+ return true; // network failure → trust the cache
195
218
  }
196
219
  }
197
220
  /** Find a single folder by name, optionally inside a parent. */
@@ -209,48 +232,45 @@ async function gDriveFindFolder(token, name, parentId) {
209
232
  const data = await res.json();
210
233
  return data.files?.[0]?.id || null;
211
234
  }
212
- /** Find the settings folder on GDrive, or create a flat "mailx" folder.
213
- * Supports nested paths from config (e.g. "home/.mailx") by walking each
214
- * segment. Falls back to the folderId in config if set, so a stale ID that
215
- * points to the wrong folder gets corrected on next lookup. */
235
+ /** Find or create the rmfmail settings folder on Google Drive.
236
+ *
237
+ * Lookup order match the Android side (`mailx-store-web/android-bootstrap.ts`):
238
+ * 1. `home/.rmfmail/` the established convention. Bob's family-of-two
239
+ * layout has been here since the rebrand. Path scope (`'root' in
240
+ * parents` for `home`, then `<homeId> in parents` for `.rmfmail`) is
241
+ * what the Android side does, so desktop matches.
242
+ * 2. `.rmfmail/` at My Drive root — fallback for users who don't have a
243
+ * `home/` folder. Mostly hypothetical; included so a brand-new Drive
244
+ * still works.
245
+ * 3. Create `.rmfmail` at My Drive root if neither exists. Don't auto-
246
+ * create `home/` — that's a user-organization choice we shouldn't
247
+ * make for them.
248
+ *
249
+ * Previously this looked for a literal `rmfmail` (no dot) at root, which
250
+ * on clean install created a NEW empty folder alongside the real data,
251
+ * orphaning the user's accounts/contacts/etc. Switched to the dotted name
252
+ * matching the actual folder convention. */
216
253
  export async function gDriveFindOrCreateFolder() {
217
254
  const token = await getGoogleDriveToken();
218
255
  if (!token)
219
256
  return null;
220
- // Read path from config — supports nested like "home/.mailx"
221
- let cfgEntry = null;
222
257
  try {
223
- const cfgPath = path.join(SETTINGS_DIR, "config.jsonc");
224
- if (fs.existsSync(cfgPath)) {
225
- const raw = fs.readFileSync(cfgPath, "utf-8").replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
226
- cfgEntry = JSON.parse(raw).sharedDir;
258
+ // 1. Try home/.rmfmail (the canonical location)
259
+ const inHome = await walkGDrivePath(token, ["home", ".rmfmail"], false);
260
+ if (inHome) {
261
+ console.log(` [cloud] Found 'home/.rmfmail' folder (${inHome})`);
262
+ return inHome;
227
263
  }
228
- }
229
- catch { /* ignore */ }
230
- // Build search list: configured path first, then common conventions
231
- const configuredPath = (typeof cfgEntry === "object" && cfgEntry?.path) ? cfgEntry.path : null;
232
- const pathsToTry = configuredPath
233
- ? [configuredPath]
234
- : GDRIVE_PATH_SEARCH_ORDER;
235
- try {
236
- for (const tryPath of pathsToTry) {
237
- console.log(` [cloud] Trying GDrive path: '${tryPath}'`);
238
- const segments = tryPath.split(/[/\\]/).filter(Boolean);
239
- const folderId = await walkGDrivePath(token, segments, false);
240
- if (folderId) {
241
- // Resolve folder ID back to name for verification
242
- const name = await gDriveGetFolderName(token, folderId);
243
- console.log(` [cloud] Found existing '${tryPath}' → folder '${name || "?"}' (${folderId})`);
244
- return folderId;
245
- }
246
- console.log(` [cloud] Path '${tryPath}' not found on GDrive`);
264
+ // 2. Try .rmfmail at root
265
+ const atRoot = await walkGDrivePath(token, [".rmfmail"], false);
266
+ if (atRoot) {
267
+ console.log(` [cloud] Found '.rmfmail' folder at My Drive root (${atRoot})`);
268
+ return atRoot;
247
269
  }
248
- // None found create the last (simplest) path
249
- const createPath = configuredPath || GDRIVE_PATH_SEARCH_ORDER[GDRIVE_PATH_SEARCH_ORDER.length - 1];
250
- const segments = createPath.split(/[/\\]/).filter(Boolean);
251
- const created = await walkGDrivePath(token, segments, true);
270
+ // 3. Create .rmfmail at root (don't try to create `home/`)
271
+ const created = await walkGDrivePath(token, [".rmfmail"], true);
252
272
  if (created)
253
- console.log(` [cloud] Created '${createPath}' folder: ${created}`);
273
+ console.log(` [cloud] Created '.rmfmail' folder at My Drive root (${created})`);
254
274
  return created;
255
275
  }
256
276
  catch (e) {
package/copy-docs.js ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * copy-docs.js — pre-pack hook for mailx-settings.
4
+ *
5
+ * The reference docs live at `<workspace>/app/docs/*.md` so they're easy
6
+ * to edit and discover in the source tree. The published npm package
7
+ * needs them as a sibling of index.js so `deployDocs()` can find them at
8
+ * runtime via `__dirname/docs/`. This script copies the workspace docs
9
+ * into a local `./docs/` directory just before npm publish, then npm's
10
+ * `files` field includes them in the tarball.
11
+ *
12
+ * Idempotent — safe to run multiple times. Source path is the workspace
13
+ * root resolved upward from this package.
14
+ */
15
+ import fs from "node:fs";
16
+ import path from "node:path";
17
+
18
+ const __dirname = import.meta.dirname;
19
+ const src = path.join(__dirname, "..", "..", "docs");
20
+ const dst = path.join(__dirname, "docs");
21
+
22
+ if (!fs.existsSync(src)) {
23
+ console.log(`[mailx-settings] no source docs at ${src} — skipping copy`);
24
+ process.exit(0);
25
+ }
26
+ fs.mkdirSync(dst, { recursive: true });
27
+ const files = fs.readdirSync(src).filter(f => f.endsWith(".md"));
28
+ for (const f of files) {
29
+ fs.copyFileSync(path.join(src, f), path.join(dst, f));
30
+ }
31
+ console.log(`[mailx-settings] copied ${files.length} .md file(s) from app/docs/ → docs/`);
@@ -0,0 +1,41 @@
1
+ # accounts.jsonc
2
+
3
+ > **Owned by rmfmail. Do not edit this file — your changes will be overwritten the next time the app starts.** The canonical copy ships with each release; this file is a deployed copy for reference. To change account *settings*, edit `accounts.jsonc` (which IS user-editable). To change *documentation*, file an issue.
4
+
5
+ ## What this file documents
6
+
7
+ `accounts.jsonc` lists every email account rmfmail manages. It lives in your shared GDrive folder (`My Drive/home/.rmfmail/`) so all your devices read the same list.
8
+
9
+ ## Shape
10
+
11
+ ```jsonc
12
+ {
13
+ "name": "Bob Frankston", // optional; default name applied to every account that doesn't override
14
+ "accounts": [
15
+ {
16
+ "id": "gmail", // short tag used in folder paths and the UI
17
+ "email": "you@example.com", // primary login address
18
+ "name": "Bob Frankston", // display name (optional if file-level name is set)
19
+ "imap": { "host": "imap.example.com", "port": 993, "tls": true, "auth": "password" },
20
+ "smtp": { "host": "smtp.example.com", "port": 465, "tls": true, "auth": "password" },
21
+ "enabled": true, // false skips this account at startup
22
+ "identityDomains": ["alias.com"] // extra domains for Reply-From auto-detect
23
+ }
24
+ ]
25
+ }
26
+ ```
27
+
28
+ ## Field rules
29
+
30
+ - **id** — short identifier. Used in folder paths (e.g. `bob.ma/INBOX`) and as a stable key when accounts.jsonc is edited.
31
+ - **email** — primary login. Determines provider auto-config when `imap`/`smtp` are omitted.
32
+ - **imap / smtp** — explicit server config. Omit for known providers (Gmail / Outlook / Yahoo / iCloud / Google Workspace are detected from the email domain via MX records).
33
+ - **auth** — `"password"` for traditional IMAP/SMTP, `"oauth2"` for Gmail/Google Workspace/Outlook.
34
+ - **enabled** — set `false` to keep the account record but skip sync at startup.
35
+ - **identityDomains** — addresses you receive at on alternative domains. When you Reply, rmfmail picks the matching identity address as From instead of the account's primary.
36
+
37
+ ## Notes
38
+
39
+ - JSONC: `// line comments` and trailing commas are allowed. The parser is lenient.
40
+ - Adding/removing accounts requires a daemon restart (`rmfmail -kill && rmfmail`). A status banner reminds you when the file changes.
41
+ - For OAuth accounts (Gmail, Google Workspace), the token cache lives in `~/.rmfmail/tokens/` and is per-machine.
@@ -0,0 +1,27 @@
1
+ # allowlist.jsonc
2
+
3
+ > **Owned by rmfmail. Do not edit this file — your changes will be overwritten the next time the app starts.** This is reference documentation. To change allow-list data, edit `allowlist.jsonc` itself.
4
+
5
+ ## What this file documents
6
+
7
+ `allowlist.jsonc` controls which senders' remote content (images, etc.) loads automatically and which senders/domains are flagged with a ⚠ banner. Lives in `My Drive/home/.rmfmail/`.
8
+
9
+ ## Shape
10
+
11
+ ```jsonc
12
+ {
13
+ "senders": ["alice@example.com"], // load remote content for these senders
14
+ "domains": ["example.com"], // load remote content for any sender at these domains
15
+ "recipients": ["you@example.com"], // addresses you receive at — treated as "your inbox identity"
16
+ "flaggedSenders": ["spam@bad.com"], // viewer shows ⚠ FLAGGED banner for these senders
17
+ "flaggedDomains": ["phishing.example"] // viewer shows ⚠ FLAGGED banner for any sender at these domains
18
+ }
19
+ ```
20
+
21
+ ## Notes
22
+
23
+ - All entries are case-insensitive plain email or domain strings.
24
+ - Multi-client safe: each device's save merges with the cloud copy (set-union), so adds from any device propagate.
25
+ - Use the message viewer's "allow remote content" button to add a sender/domain to `senders`/`domains` interactively.
26
+ - Use the right-click menu in the viewer to flag a sender/domain — adds to `flaggedSenders`/`flaggedDomains`.
27
+ - JSONC: `// line comments` and trailing commas are allowed.
@@ -0,0 +1,24 @@
1
+ # clients.jsonc
2
+
3
+ > **Owned by rmfmail. Do not edit this file — your changes will be overwritten the next time the app starts.** This is reference documentation.
4
+
5
+ ## What this file documents
6
+
7
+ `clients.jsonc` is the registry of devices running rmfmail under your account. It's auto-managed: each device adds itself on first launch and refreshes its `lastSeen` timestamp on every startup. You don't normally need to look at it.
8
+
9
+ ## Shape
10
+
11
+ ```jsonc
12
+ {
13
+ "devices": [
14
+ { "id": "abc-uuid", "name": "Pixel 9 Pro Fold", "lastSeen": 1746381600000, "accounts": ["gmail", "bobma"] },
15
+ { "id": "def-uuid", "name": "rmf39 desktop", "lastSeen": 1746399999000, "accounts": ["gmail", "bobma"] }
16
+ ]
17
+ }
18
+ ```
19
+
20
+ ## Notes
21
+
22
+ - `id` is a stable UUID generated on first launch and stored locally (`localStorage` on Android, config dir on desktop).
23
+ - `accounts` is the list of account ids this device is currently configured for.
24
+ - Removing a device from this file forces it to re-register on next launch — harmless but pointless.
package/docs/config.md ADDED
@@ -0,0 +1,32 @@
1
+ # config.jsonc
2
+
3
+ > **Owned by rmfmail. Do not edit this DOCUMENTATION file — changes will be overwritten.** Note: the **actual** `config.jsonc` IS user-editable; this `.md` file is just the reference for it.
4
+
5
+ ## What this file documents
6
+
7
+ `config.jsonc` is your *local, per-machine* config. It is **NOT** synced to GDrive — every machine has its own. It points at the shared GDrive folder and overrides machine-specific paths.
8
+
9
+ Lives at `~/.rmfmail/config.jsonc` on the local filesystem.
10
+
11
+ ## Shape
12
+
13
+ ```jsonc
14
+ {
15
+ "sharedDir": {
16
+ "provider": "gdrive",
17
+ "path": ".rmfmail", // folder name in My Drive (currently My Drive/home/.rmfmail)
18
+ "folderId": "1AbCdEf...XYZ" // resolved Drive folderId, cached after first lookup
19
+ },
20
+ "storePath": "C:/Users/Bob/.rmfmail/mailxstore", // local directory for .eml message bodies
21
+ "historyDays": 30 // how far back to sync; overrides the shared default
22
+ }
23
+ ```
24
+
25
+ ## Notes
26
+
27
+ - `sharedDir.provider`: `"gdrive"` is the only currently-supported value (OneDrive/Dropbox were removed).
28
+ - `sharedDir.folderId` is resolved at startup if missing; caching it avoids a Drive query on every launch.
29
+ - `storePath` is where `.eml` bodies are stored locally. Defaults to `~/.rmfmail/mailxstore` on desktop. Android uses app-private sandbox storage and ignores this field.
30
+ - `historyDays` is a per-machine override for the cloud-synced default in `preferences.jsonc`.
31
+ - Because this file is local, edits don't propagate to other devices. Use `accounts.jsonc` / `preferences.jsonc` for shared settings.
32
+ - JSONC: `// line comments` and trailing commas are allowed.
@@ -0,0 +1,40 @@
1
+ # contact-rules.jsonc
2
+
3
+ > **Owned by rmfmail. Do not edit this file — your changes will be overwritten the next time the app starts.** This is reference documentation. The actual rules ship with the app and update on every release.
4
+
5
+ ## What this file documents
6
+
7
+ `contact-rules.jsonc` defines the **global** junk-contact filter patterns (noreply, mailer-daemon, gateway domains, one-off-shape locals, etc.). It is *NOT* user-editable — it's part of the app, deployed alongside your data so you can see what's being filtered.
8
+
9
+ User-specific filters live in `contacts.jsonc` (`denylist` exact match; `denylistPatterns` regex array — TODO).
10
+
11
+ ## Shape
12
+
13
+ ```jsonc
14
+ {
15
+ "rulesVersion": "v3-domain-oneoff", // bump when patterns tighten — triggers one-shot purge
16
+ "junk": {
17
+ "localExact": "^(no-?reply|do-?not-?reply|noreply|mailer-daemon|...)$",
18
+ "localSuffix": "(-bounces|\\+bounces|-noreply|-no-reply|...)$",
19
+ "localPrefix": "^(no-?reply|noreply|notifications?|alerts?|bounces?|mailer)[-_+]",
20
+ "localOneoff": "^[0-9a-f]{4,}\\.[0-9a-f]{4,}(\\.[0-9a-z]{6,})?$",
21
+ "domain": "^(txt\\.voice\\.google\\.com|reply\\.facebook\\.com|reply\\.linkedin\\.com)$"
22
+ }
23
+ }
24
+ ```
25
+
26
+ ## How rules apply
27
+
28
+ Each newly-harvested address is checked against ALL rule patterns; any match drops it. Each rule is a single regex, case-insensitive:
29
+
30
+ - **localExact** — whole-string match against the local part (before `@`).
31
+ - **localSuffix** — local part ends with the pattern.
32
+ - **localPrefix** — local part begins with the pattern + a `-` / `_` / `+` separator. Catches `noreply-<random>` style.
33
+ - **localOneoff** — full-shape match for per-message gateway addresses (Google Voice SMS uses three dot-separated alphanumeric segments).
34
+ - **domain** — whole-string match against the domain (after `@`).
35
+
36
+ ## When rules update
37
+
38
+ Each rmfmail release ships an updated `contact-rules.jsonc`. On startup, the app compares the bundled `rulesVersion` to the value stored locally. If they differ, the app sweeps the contacts table once and removes rows the new rules now reject — then records the new version so the sweep doesn't repeat.
39
+
40
+ To add a rule: file an issue, or fork+PR. (Eventually `rules.jsonc` per-user will allow personal additions without forking.)
@@ -0,0 +1,48 @@
1
+ # contacts.jsonc
2
+
3
+ > **Owned by rmfmail. Do not edit this file — your changes will be overwritten the next time the app starts.** This is reference documentation. To change contact data, edit `contacts.jsonc` itself.
4
+
5
+ ## What this file documents
6
+
7
+ `contacts.jsonc` is your address book. It's split into three tiers and lives in `My Drive/home/.rmfmail/`.
8
+
9
+ ## Shape
10
+
11
+ ```jsonc
12
+ {
13
+ "preferred": [
14
+ { "name": "David Reed", "email": "dpreed@example.com", "organization": "Deep Plum" }
15
+ ],
16
+ "denylist": [
17
+ "spammer@example.com"
18
+ ],
19
+ "discovered": [
20
+ { "name": "Bob", "email": "bob@example.com", "useCount": 715, "lastUsed": 1777921829000 }
21
+ ]
22
+ }
23
+ ```
24
+
25
+ ## Tiers
26
+
27
+ - **preferred** — manually-curated, top-ranked in autocomplete. Add people you actually want to reach quickly.
28
+ - **denylist** — addresses (lowercased) excluded from autocomplete entirely.
29
+ - **discovered** — auto-collected from sent/received mail. `useCount` × recency drives autocomplete ranking. Junk patterns (see below) are dropped at insertion.
30
+
31
+ ## Global junk filter
32
+
33
+ Addresses matching any of these are dropped at insertion AND swept on startup:
34
+
35
+ - Whole local part: `noreply`, `no-reply`, `do-not-reply`, `mailer-daemon`, `postmaster`, `bounces`, etc.
36
+ - Local-part prefix: `noreply-<random>`, `notifications-<id>`, `alerts-<x>`, `bounces-<x>`, `mailer-<x>`
37
+ - Local-part suffix: `*-bounces`, `*+bounces`, `*-noreply`, `*-notifications`
38
+ - Multi-segment one-off shape: `16179691997.15082868100.nfblcbll1x` (per-message gateway addresses)
39
+ - Domains: `txt.voice.google.com` (Google Voice SMS gateway), `reply.facebook.com`, `reply.linkedin.com`
40
+
41
+ The full pattern set lives in `contact-rules.jsonc` (shipped with the app). Bumping `rulesVersion` in that file triggers a one-shot purge of historical rows the new rules now reject.
42
+
43
+ ## Notes
44
+
45
+ - JSONC: `// line comments` and trailing commas are allowed.
46
+ - `useCount` and `lastUsed` are auto-managed; manually editing them only changes ranking briefly until the next sync.
47
+ - Removing a `preferred` entry doesn't add it to `denylist` — it just demotes back to `discovered` (or drops if not seen in mail).
48
+ - Each device contributes its observed addresses to `discovered`. The file accumulates the union across devices.
package/docs/editor.md ADDED
@@ -0,0 +1,92 @@
1
+ # Compose editor — formatting and shortcuts
2
+
3
+ mailx ships with two rich-text editors: **Quill** (default) and **tiptap**.
4
+ Most things work the same in both. Differences are called out below.
5
+
6
+ Switch editors via **Settings → Editor → Quill | tiptap**.
7
+
8
+ ## Universal — works in both editors
9
+
10
+ | Action | Shortcut | Where |
11
+ |---|---|---|
12
+ | **Send** | Ctrl+Enter | toolbar Send button |
13
+ | Bold / Italic / Underline | Ctrl+B / Ctrl+I / Ctrl+U | toolbar B / I / U |
14
+ | Strikethrough | Ctrl+Shift+X | toolbar S |
15
+ | Bulleted list | Ctrl+Shift+8 | toolbar • |
16
+ | Ordered list | Ctrl+Shift+7 | toolbar 1. |
17
+ | Insert / edit link | Ctrl+K | toolbar 🔗 |
18
+ | Remove link | Ctrl+Shift+K | (no toolbar button — use Ctrl+Shift+K) |
19
+ | Blockquote | (Quill: Ctrl+Shift+Q; tiptap: toolbar) | toolbar `“` |
20
+ | Clear formatting | Ctrl+\\ | toolbar ✖ |
21
+ | Heading (H1 / H2 / H3) | (Quill: format dropdown; tiptap: select dropdown) | "Normal / Heading 1 / 2 / 3" |
22
+ | Undo / Redo | Ctrl+Z / Ctrl+Y | (no toolbar button) |
23
+ | Spell-check | (browser native — red underlines) | right-click word |
24
+ | Paste plain text | Ctrl+Shift+V | (browser native) |
25
+
26
+ ## Quill-only
27
+
28
+ | Action | Shortcut |
29
+ |---|---|
30
+ | Indent / outdent | Ctrl+] / Ctrl+[ |
31
+ | Color text | Ctrl+Shift+C |
32
+ | Format dropdown | toolbar (left side) |
33
+ | Inline code | toolbar `<>` |
34
+ | Code block | toolbar |
35
+ | Image inserter | (no built-in; use drag-and-drop or paste) |
36
+
37
+ Quill has a more elaborate toolbar with format-specific dropdowns (font,
38
+ size, color). Internally Quill uses its own *Delta* document model — copy/
39
+ paste from Word/Outlook sometimes leaves extra `<p><br></p>` empty
40
+ paragraphs that you'll see in the sent message body.
41
+
42
+ ## tiptap-only
43
+
44
+ | Action | Where |
45
+ |---|---|
46
+ | Heading select | left of toolbar |
47
+ | Toggle bold / italic / underline / strike | toolbar B / I / U / S |
48
+ | Blockquote | toolbar `“` |
49
+ | Image (drag-and-drop) | drop a file into the body |
50
+
51
+ tiptap is built on ProseMirror. Output HTML is cleaner than Quill on
52
+ Word/Outlook paste roundtrips. Bundle is smaller. Some Quill toolbar
53
+ features (inline code, indent shortcuts, color picker) aren't wired —
54
+ use the heading select / format menu instead.
55
+
56
+ ## Common features (across both)
57
+
58
+ - **Drag-and-drop attachments** — drop files anywhere on the compose
59
+ window to attach. Overlay highlights the drop target while dragging.
60
+ - **Edit in Word / LibreOffice** — toolbar **Edit in Word** button opens
61
+ the body in your default external editor (configurable in
62
+ Settings → External editor). Save in the external editor and the body
63
+ reloads here. Behind the scenes mailx writes a temporary `.docx` file
64
+ (see `~/.rmfmail/external-edit/`) and watches it for changes.
65
+ - **Auto-save drafts** — every 5 seconds (and on input debounce + on
66
+ blur). Drafts land in the Drafts folder via IMAP append.
67
+ - **Address auto-completion** — type a partial name in To/Cc/Bcc; matches
68
+ rank by recency × use-count. Group names from `contacts.jsonc → groups`
69
+ also surface here.
70
+ - **Address-field expansion** — recipient fields are auto-growing
71
+ textareas; long lists wrap to multiple lines.
72
+ - **Group expansion on send** — type a group name (e.g. `family`) in
73
+ To/Cc/Bcc and it expands to the address list at send time.
74
+ - **Ghost-text autocomplete** (off by default) — Settings →
75
+ AI autocomplete → on. Predicts the next words while you type.
76
+
77
+ ## When the toolbar doesn't appear
78
+
79
+ The editor loads from a CDN (jsdelivr). If your network can't reach it,
80
+ the toolbar disappears and a plain `contenteditable` fallback takes over.
81
+ Status bar shows the failure. mailx now tries the *other* editor before
82
+ falling all the way back; if both fail you get a plain textarea with no
83
+ shortcuts and no toolbar — sending still works.
84
+
85
+ ## See also
86
+
87
+ - `accounts.md`, `contacts.md`, `allowlist.md`, `clients.md`, `config.md`,
88
+ `preferences.md` — config-file references (these live in your GDrive
89
+ `.rmfmail/` folder).
90
+ - This `editor.md` is **app-internal** — it ships with each release and
91
+ documents the editor as it currently exists in the version you're
92
+ running. It is not deployed to your user folder.
@@ -0,0 +1,43 @@
1
+ # preferences.jsonc
2
+
3
+ > **Owned by rmfmail. Do not edit this file — your changes will be overwritten the next time the app starts.** This is reference documentation.
4
+
5
+ ## What this file documents
6
+
7
+ `preferences.jsonc` holds your shared UI / sync / autocomplete preferences, synced via `My Drive/home/.rmfmail/`.
8
+
9
+ ## Shape
10
+
11
+ ```jsonc
12
+ {
13
+ "ui": {
14
+ "theme": "system", // "system" | "light" | "dark"
15
+ "twoLine": false, // two-line message-list rows
16
+ "previewPane": true,
17
+ "previewSnippets": true,
18
+ "threaded": false,
19
+ "flaggedOnly": false,
20
+ "folderCounts": false,
21
+ "calendarSidebar": false,
22
+ "editor": "quill" // "quill" | "tiptap"
23
+ },
24
+ "sync": {
25
+ "intervalMinutes": 5, // full-sync interval (per-folder); IDLE handles INBOX inline
26
+ "historyDays": 30, // how far back to sync (overridable per-machine in config.jsonc)
27
+ "prefetch": true // background-fetch message bodies after metadata sync
28
+ },
29
+ "autocomplete": {
30
+ "enabled": false, // ghost-text completions in compose
31
+ "provider": "ollama", // "ollama" | "claude" | "openai"
32
+ "translateEnabled": false, // AI-powered Translate menu item in viewer
33
+ "proofreadEnabled": false
34
+ }
35
+ }
36
+ ```
37
+
38
+ ## Notes
39
+
40
+ - The View menu and Settings menu in the toolbar both write here.
41
+ - `sync.intervalMinutes` controls the full-folder sync cadence. INBOX uses RFC 2177 IDLE (instant push) on Dovecot accounts; Gmail accounts poll every 30s.
42
+ - `sync.historyDays` is a default; override per-machine via `config.jsonc`.
43
+ - AI features are off by default. Enabling `autocomplete.enabled` requires a configured provider (Ollama local, Claude API key, or OpenAI API key).
package/index.d.ts CHANGED
@@ -38,6 +38,9 @@ export declare function getStorageInfo(): {
38
38
  provider: string;
39
39
  mode: "mount" | "api" | "local";
40
40
  cloudPath?: string;
41
+ folderName?: string;
42
+ folderId?: string;
43
+ configDir?: string;
41
44
  cloudError?: string;
42
45
  };
43
46
  /** Fill in provider defaults for an account based on email domain.
@@ -78,7 +81,11 @@ declare const DEFAULT_ALLOWLIST: {
78
81
  };
79
82
  /** Load account configs */
80
83
  export declare function loadAccounts(): AccountConfig[];
81
- /** Load accounts with cloud API fallback (async — use when cloud settings may not be mounted) */
84
+ /** Load accounts, preferring the cloud copy when cloud is configured.
85
+ * The local file in `~/.rmfmail/` is an offline cache, NOT the source of
86
+ * truth — earlier versions returned the local copy whenever it was non-empty,
87
+ * which left the desktop reading a stale single-account file forever after
88
+ * the GDrive folder lookup got fixed. */
82
89
  export declare function loadAccountsAsync(): Promise<AccountConfig[]>;
83
90
  /** Strip default-valued fields from a normalized AccountConfig so the
84
91
  * serialized JSONC stays compact and human-editable. The previous version
@@ -127,8 +134,8 @@ export { getSharedDir };
127
134
  /** Initialize local config if it doesn't exist */
128
135
  export declare function initLocalConfig(sharedDir?: string, storePath?: string): void;
129
136
  /** Initialize config with Google Drive cloud storage.
130
- * Finds or creates the app-owned "mailx" folder via Drive API and stores its ID.
131
- * No mount scanning — API only. Existing settings at other paths (e.g., home/.mailx
137
+ * Finds or creates the app-owned ".rmfmail" folder via Drive API and stores its ID.
138
+ * No mount scanning — API only. Existing settings at other paths (e.g., home/.rmfmail
132
139
  * from Desktop sync) must be migrated manually or via config.jsonc importPath. */
133
140
  export declare function initCloudConfig(provider?: "gdrive"): Promise<void>;
134
141
  declare const DEFAULT_SETTINGS: MailxSettings;
@@ -137,4 +144,20 @@ export declare function getHistoryDays(accountId?: string): number;
137
144
  /** Get prefetch setting: download bodies during sync (default true) */
138
145
  export declare function getPrefetch(): boolean;
139
146
  export { DEFAULT_SETTINGS, DEFAULT_ALLOWLIST, DEFAULT_PREFERENCES, DEFAULT_AUTOCOMPLETE, LOCAL_DIR };
147
+ /** Deploy the app-owned `.md` reference docs to the shared cloud folder so
148
+ * users can read them next to the `.jsonc` files they document. The .md
149
+ * files live in the app bundle (`<workspace>/app/docs/` in dev, or
150
+ * `<package>/docs/` in published builds) and are overwritten on every
151
+ * release — the file header documents that fact, so users know not to
152
+ * edit them.
153
+ *
154
+ * Skip-path: a manifest file `.docs-version` on the cloud records the
155
+ * app version that last deployed. We re-deploy only when the running
156
+ * app's version differs, so startup doesn't pound Drive on every launch.
157
+ *
158
+ * This function is fire-and-forget at the call site; failures are logged
159
+ * but never throw. The `.md` files are reference material, not load-
160
+ * bearing — the app works without them.
161
+ */
162
+ export declare function deployDocs(appVersion: string): Promise<void>;
140
163
  //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAyGpG,QAAA,MAAM,SAAS,QAA4E,CAAC;AAiE5F,qFAAqF;AACrF,KAAK,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE;IAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAAC;AAE/G,wBAAgB,YAAY,CAAC,EAAE,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAM/D;AAOD,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAA2B;AAU7E,iBAAS,YAAY,IAAI,MAAM,CAgB9B;AAOD,sEAAsE;AACtE,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoCxE;AAED;;qCAEqC;AACrC,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BjF;AAyBD,2CAA2C;AAC3C,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED,4CAA4C;AAC5C,wBAAgB,cAAc,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CA+B3L;AAuID;;qDAEqD;AACrD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,GAAG,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,CA4D9E;AAMD,QAAA,MAAM,mBAAmB;;eAEE,QAAQ,GAAG,MAAM,GAAG,OAAO;gBAC3B,OAAO,GAAG,QAAQ;;;;;;;;;;;;;;;;;;;;CAoB5C,CAAC;AAEF,QAAA,MAAM,oBAAoB,EAAE,oBAS3B,CAAC;AAEF,QAAA,MAAM,iBAAiB;aACJ,MAAM,EAAE;aACR,MAAM,EAAE;gBACL,MAAM,EAAE;oBAOJ,MAAM,EAAE;oBACR,MAAM,EAAE;CACjC,CAAC;AAIF,2BAA2B;AAC3B,wBAAgB,YAAY,IAAI,aAAa,EAAE,CA0C9C;AAoCD;;;;0CAI0C;AAC1C,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAqBlE;AAED;;;;;;;;;;;;;;;iDAeiD;AACjD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,GAAG,CA+ChF;AAED,2BAA2B;AAC3B;;kCAEkC;AAClC,wBAAsB,YAAY,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B3E;AAED,wEAAwE;AACxE,wBAAgB,eAAe,IAAI,OAAO,mBAAmB,CAoB5D;AAED,uBAAuB;AACvB,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI,CAEhD;AAED,iCAAiC;AACjC,wBAAgB,gBAAgB,IAAI,oBAAoB,CAGvD;AAED,iCAAiC;AACjC,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAIrE;AAED,qCAAqC;AACrC,wBAAgB,aAAa,IAAI,OAAO,iBAAiB,CAExD;AAED,4EAA4E;AAC5E,wBAAsB,aAAa,CAAC,IAAI,EAAE,OAAO,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBjF;AAcD,6EAA6E;AAC7E,wBAAgB,YAAY,IAAI,aAAa,CAe5C;AAED,4CAA4C;AAC5C,wBAAsB,YAAY,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAGzE;AAED,oCAAoC;AACpC,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,qDAAqD;AACrD,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wCAAwC;AACxC,OAAO,EAAE,YAAY,EAAE,CAAC;AAKxB,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAkB5E;AAED;;;mFAGmF;AACnF,wBAAsB,eAAe,CAAC,QAAQ,GAAE,QAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAclF;AAED,QAAA,MAAM,gBAAgB,EAAE,aAMvB,CAAC;AAEF,8FAA8F;AAC9F,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAQzD;AAED,uEAAuE;AACvE,wBAAgB,WAAW,IAAI,OAAO,CAGrC;AAED,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,SAAS,EAAE,CAAC;AAErG;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmClE"}
package/index.js CHANGED
@@ -18,9 +18,131 @@
18
18
  import * as fs from "node:fs";
19
19
  import * as path from "node:path";
20
20
  import { parse as parseJsonc } from "jsonc-parser";
21
- import { getCloudProvider, gDriveFindOrCreateFolder } from "./cloud.js";
21
+ import { getCloudProvider, gDriveFindOrCreateFolder, gDriveValidateCachedFolder } from "./cloud.js";
22
+ const __dirname = import.meta.dirname;
22
23
  // ── Paths ──
23
- const LOCAL_DIR = path.join(process.env.USERPROFILE || process.env.HOME || ".", ".mailx");
24
+ // REMOVE 2026-06-15 one-shot migration of legacy ~/.mailx → ~/.rmfmail.
25
+ // Five cases handled (idempotent — running twice is safe):
26
+ // 1. only ~/.mailx: rename to ~/.rmfmail (atomic single move).
27
+ // 2. ~/.mailx contains ONLY a `mailxstore/` subdir while ~/.rmfmail is
28
+ // already the active config — move the body store across, rewrite
29
+ // body_path rows in the DB, then remove the empty ~/.mailx. This is
30
+ // the hybrid-state user (their config jumped to .rmfmail but the
31
+ // stored body files lived under .mailx because storePath was an
32
+ // absolute path).
33
+ // 3. both exist with other content in ~/.mailx: rename to ~/.mailx-old
34
+ // so it's visibly cruft.
35
+ // 4. only ~/.rmfmail (or neither): do nothing.
36
+ // 5 covers config.jsonc with absolute storePath pointing at ~/.mailx —
37
+ // rewritten to a relative "mailxstore" so the path follows the config dir.
38
+ {
39
+ const home = process.env.USERPROFILE || process.env.HOME || ".";
40
+ const oldDir = path.join(home, ".mailx");
41
+ const newDir = path.join(home, ".rmfmail");
42
+ const asideDir = path.join(home, ".mailx-old");
43
+ if (!fs.existsSync(newDir) && fs.existsSync(oldDir)) {
44
+ fs.renameSync(oldDir, newDir);
45
+ console.log("[migrate] ~/.mailx → ~/.rmfmail");
46
+ }
47
+ else if (fs.existsSync(newDir) && fs.existsSync(oldDir)) {
48
+ // Hybrid: figure out whether `.mailx/` is just a leftover store or
49
+ // has meaningful content.
50
+ let entries = [];
51
+ try {
52
+ entries = fs.readdirSync(oldDir);
53
+ }
54
+ catch { /* */ }
55
+ const onlyStore = entries.length === 1 && entries[0] === "mailxstore";
56
+ if (onlyStore) {
57
+ const oldStore = path.join(oldDir, "mailxstore");
58
+ const newStore = path.join(newDir, "mailxstore");
59
+ try {
60
+ fs.mkdirSync(newStore, { recursive: true });
61
+ // Recursive move (rename per top-level entry; rename across
62
+ // dirs on the same volume is atomic, fall back to copy+unlink
63
+ // if it fails — e.g. when the volumes differ).
64
+ const moveRecursive = (src, dst) => {
65
+ const stat = fs.statSync(src);
66
+ if (stat.isDirectory()) {
67
+ fs.mkdirSync(dst, { recursive: true });
68
+ for (const child of fs.readdirSync(src))
69
+ moveRecursive(path.join(src, child), path.join(dst, child));
70
+ try {
71
+ fs.rmdirSync(src);
72
+ }
73
+ catch { /* */ }
74
+ }
75
+ else {
76
+ try {
77
+ fs.renameSync(src, dst);
78
+ }
79
+ catch {
80
+ fs.copyFileSync(src, dst);
81
+ fs.unlinkSync(src);
82
+ }
83
+ }
84
+ };
85
+ for (const child of fs.readdirSync(oldStore)) {
86
+ moveRecursive(path.join(oldStore, child), path.join(newStore, child));
87
+ }
88
+ try {
89
+ fs.rmdirSync(oldStore);
90
+ }
91
+ catch { /* */ }
92
+ try {
93
+ fs.rmdirSync(oldDir);
94
+ }
95
+ catch { /* may still have files; let next case handle */ }
96
+ console.log("[migrate] moved ~/.mailx/mailxstore/* → ~/.rmfmail/mailxstore/");
97
+ }
98
+ catch (e) {
99
+ console.warn(`[migrate] mailxstore move failed: ${e.message}`);
100
+ }
101
+ }
102
+ else if (!fs.existsSync(asideDir)) {
103
+ fs.renameSync(oldDir, asideDir);
104
+ console.log("[migrate] ~/.mailx → ~/.mailx-old (safe to delete)");
105
+ }
106
+ }
107
+ // Body-path rewrite: any DB rows still pointing at the old absolute
108
+ // store path get translated to the new one. Fire-and-forget — the DB
109
+ // module exposes a method called from the daemon's startup; this
110
+ // module-level migration just touches config.jsonc.
111
+ const localCfg = path.join(newDir, "config.jsonc");
112
+ if (fs.existsSync(localCfg)) {
113
+ try {
114
+ const raw = fs.readFileSync(localCfg, "utf-8");
115
+ const stripped = raw.replace(/^\s*\/\/.*$/gm, "").replace(/,(\s*[}\]])/g, "$1");
116
+ const cfg = JSON.parse(stripped);
117
+ // Drop storePath entirely when it points at the legacy dir or
118
+ // is the default — config.jsonc shouldn't pin paths that follow
119
+ // from where LOCAL_DIR is. Users who actually need a custom
120
+ // store location keep that override; everyone else gets the
121
+ // default (~/.rmfmail/mailxstore) without ceremony.
122
+ if (typeof cfg.storePath === "string") {
123
+ const p = cfg.storePath;
124
+ const isLegacyAbs = /[\\/]\.mailx[\\/]mailxstore$/i.test(p);
125
+ const isDefaultRel = p === "mailxstore";
126
+ const isDefaultAbs = /[\\/]\.rmfmail[\\/]mailxstore$/i.test(p);
127
+ if (isLegacyAbs || isDefaultRel || isDefaultAbs) {
128
+ delete cfg.storePath;
129
+ fs.writeFileSync(localCfg, JSON.stringify(cfg, null, 2));
130
+ console.log("[migrate] config.jsonc storePath dropped (using default ~/.rmfmail/mailxstore)");
131
+ }
132
+ }
133
+ // Same for sharedDir.path label (cosmetic — folderId is what matters).
134
+ if (cfg.sharedDir && typeof cfg.sharedDir === "object" && cfg.sharedDir.path === "home/.mailx") {
135
+ cfg.sharedDir.path = "home/.rmfmail";
136
+ fs.writeFileSync(localCfg, JSON.stringify(cfg, null, 2));
137
+ console.log("[migrate] config.jsonc sharedDir.path → home/.rmfmail");
138
+ }
139
+ }
140
+ catch (e) {
141
+ console.warn(`[migrate] config.jsonc rewrite failed: ${e.message}`);
142
+ }
143
+ }
144
+ }
145
+ const LOCAL_DIR = path.join(process.env.USERPROFILE || process.env.HOME || ".", ".rmfmail");
24
146
  const LOCAL_CONFIG_PATH = path.join(LOCAL_DIR, "config.jsonc");
25
147
  const LEGACY_CONFIG_PATH = path.join(LOCAL_DIR, "config.json");
26
148
  const DEFAULT_STORE_PATH = path.join(LOCAL_DIR, "mailxstore");
@@ -107,10 +229,25 @@ function getSharedDir() {
107
229
  // Legacy settingsPath no longer used for shared dir — use loadLegacySettings() for reading only.
108
230
  return LOCAL_DIR;
109
231
  }
232
+ /** Once-per-process validation flag — verify the cached folderId points at
233
+ * an `.rmfmail` folder before trusting it. Catches the cross-version-cache
234
+ * corruption case where 1.0.504 cached a wrong ID and never re-discovered. */
235
+ let folderIdValidated = false;
110
236
  /** Read a file via cloud API (when filesystem mount not available) */
111
237
  export async function cloudRead(filename) {
112
238
  if (!pendingCloudConfig)
113
239
  return null;
240
+ // Validate cached folderId once per process. If it points somewhere
241
+ // other than an `.rmfmail` folder (e.g. an orphan from a buggy version),
242
+ // drop it and re-discover via gDriveFindOrCreateFolder.
243
+ if (pendingCloudConfig.folderId && !folderIdValidated) {
244
+ folderIdValidated = true;
245
+ const ok = await gDriveValidateCachedFolder(pendingCloudConfig.folderId);
246
+ if (!ok) {
247
+ pendingCloudConfig.folderId = undefined;
248
+ clearFolderIdInConfig();
249
+ }
250
+ }
114
251
  // Ensure we have a folder ID
115
252
  if (!pendingCloudConfig.folderId) {
116
253
  pendingCloudConfig.folderId = await gDriveFindOrCreateFolder() || undefined;
@@ -187,12 +324,25 @@ function saveFolderIdToConfig(folderId) {
187
324
  }
188
325
  catch { /* non-critical */ }
189
326
  }
327
+ /** Drop a stale folder ID from config.jsonc so the next cloudRead/cloudWrite
328
+ * re-discovers via gDriveFindOrCreateFolder. */
329
+ function clearFolderIdInConfig() {
330
+ try {
331
+ const config = readLocalConfig();
332
+ if (config.sharedDir && typeof config.sharedDir === "object" && !Array.isArray(config.sharedDir)) {
333
+ delete config.sharedDir.folderId;
334
+ atomicWrite(LOCAL_CONFIG_PATH, config);
335
+ }
336
+ }
337
+ catch { /* non-critical */ }
338
+ }
190
339
  /** Whether cloud API fallback is active */
191
340
  export function isCloudMode() {
192
341
  return pendingCloudConfig !== null;
193
342
  }
194
343
  /** Get storage provider info for display */
195
344
  export function getStorageInfo() {
345
+ const configDir = LOCAL_DIR;
196
346
  const config = readLocalConfig();
197
347
  if (config.sharedDir) {
198
348
  const entries = Array.isArray(config.sharedDir) ? config.sharedDir : [config.sharedDir];
@@ -200,7 +350,7 @@ export function getStorageInfo() {
200
350
  if (typeof entry === "string") {
201
351
  const resolved = resolveSharedEntry(entry);
202
352
  if (resolved && resolved !== LOCAL_DIR) {
203
- return { provider: "local", mode: "local", cloudPath: resolved };
353
+ return { provider: "local", mode: "local", cloudPath: resolved, configDir };
204
354
  }
205
355
  continue;
206
356
  }
@@ -208,20 +358,20 @@ export function getStorageInfo() {
208
358
  const name = (entry.provider === "gdrive" || entry.provider === "google") ? "gdrive" : entry.provider;
209
359
  if (entry.folderId) {
210
360
  // Has folder ID → API mode (don't scan filesystem for mounts)
211
- return { provider: name, mode: "api", cloudPath: entry.path, cloudError: lastCloudError || undefined };
361
+ return { provider: name, mode: "api", cloudPath: entry.path, folderName: entry.path, folderId: entry.folderId, configDir, cloudError: lastCloudError || undefined };
212
362
  }
213
363
  const resolved = resolveSharedEntry(entry);
214
364
  if (resolved && resolved !== LOCAL_DIR) {
215
- return { provider: name, mode: "mount", cloudPath: entry.path };
365
+ return { provider: name, mode: "mount", cloudPath: entry.path, folderName: entry.path, configDir };
216
366
  }
217
367
  }
218
368
  // Not mounted and no folderId — check pendingCloudConfig from initCloudConfig()
219
369
  if (pendingCloudConfig) {
220
370
  const name = (pendingCloudConfig.provider === "gdrive" || pendingCloudConfig.provider === "google") ? "gdrive" : pendingCloudConfig.provider;
221
- return { provider: name, mode: "api", cloudPath: pendingCloudConfig.path, cloudError: lastCloudError || undefined };
371
+ return { provider: name, mode: "api", cloudPath: pendingCloudConfig.path, folderName: pendingCloudConfig.path, configDir, cloudError: lastCloudError || undefined };
222
372
  }
223
373
  }
224
- return { provider: "local", mode: "local" };
374
+ return { provider: "local", mode: "local", configDir };
225
375
  }
226
376
  // ── File helpers ──
227
377
  /** Read JSON or JSONC file. If exact path not found, tries .json/.jsonc variant. */
@@ -532,27 +682,30 @@ function applyAccountOverrides(accounts) {
532
682
  }
533
683
  return accounts;
534
684
  }
535
- /** Load accounts with cloud API fallback (async — use when cloud settings may not be mounted) */
685
+ /** Load accounts, preferring the cloud copy when cloud is configured.
686
+ * The local file in `~/.rmfmail/` is an offline cache, NOT the source of
687
+ * truth — earlier versions returned the local copy whenever it was non-empty,
688
+ * which left the desktop reading a stale single-account file forever after
689
+ * the GDrive folder lookup got fixed. */
536
690
  export async function loadAccountsAsync() {
537
- // Try sync first (filesystem)
538
- const accounts = loadAccounts();
539
- if (accounts.length > 0)
540
- return accounts;
541
- // Try cloud API fallback
691
+ // Make sure pendingCloudConfig is initialized (calling getSharedDir as a
692
+ // side effect — it sets pendingCloudConfig from the local config.jsonc).
693
+ getSharedDir();
694
+ // Cloud configured → cloud is canonical.
542
695
  if (pendingCloudConfig) {
543
- console.log(" [cloud] Trying cloud API for accounts...");
544
696
  const content = await cloudRead("accounts.jsonc");
545
697
  if (content) {
546
698
  const data = parseJsonc(content);
547
699
  if (data?.accounts || Array.isArray(data)) {
548
700
  const raw = data.accounts || data;
549
701
  const globalName = data.name || "";
702
+ // cloudRead has already cached content to LOCAL_DIR.
550
703
  return applyAccountOverrides(raw.map((a) => normalizeAccount(a, globalName)));
551
704
  }
552
705
  }
553
- // Legacy settings.jsonc is no longer read use accounts.jsonc only
706
+ // Cloud unreachable / unparseable fall through to local cache.
554
707
  }
555
- return [];
708
+ return loadAccounts();
556
709
  }
557
710
  /** Strip default-valued fields from a normalized AccountConfig so the
558
711
  * serialized JSONC stays compact and human-editable. The previous version
@@ -797,27 +950,27 @@ export function initLocalConfig(sharedDir, storePath) {
797
950
  const config = {
798
951
  ...existing,
799
952
  sharedDir: resolvedSharedDir,
800
- storePath: storePath || existing.storePath || DEFAULT_STORE_PATH,
953
+ // storePath is now optional — omit when default. Resolves to
954
+ // ~/.rmfmail/mailxstore via getStorePath() if not specified.
955
+ ...(storePath || existing.storePath ? { storePath: storePath || existing.storePath } : {}),
801
956
  };
802
957
  fs.mkdirSync(LOCAL_DIR, { recursive: true });
803
958
  atomicWrite(LOCAL_CONFIG_PATH, config);
804
959
  }
805
960
  /** Initialize config with Google Drive cloud storage.
806
- * Finds or creates the app-owned "mailx" folder via Drive API and stores its ID.
807
- * No mount scanning — API only. Existing settings at other paths (e.g., home/.mailx
961
+ * Finds or creates the app-owned ".rmfmail" folder via Drive API and stores its ID.
962
+ * No mount scanning — API only. Existing settings at other paths (e.g., home/.rmfmail
808
963
  * from Desktop sync) must be migrated manually or via config.jsonc importPath. */
809
964
  export async function initCloudConfig(provider = "gdrive") {
810
965
  const existing = readLocalConfig();
811
966
  if (existing.sharedDir)
812
967
  return; // Already configured
813
- // Find or create the settings folder via Drive API tries "home/.mailx"
814
- // first (family convention), then "mailx" (default). The found path gets
815
- // saved so future lookups don't re-scan.
968
+ // Find or create the settings folder via Drive API. Stored path is the
969
+ // canonical post-rebrand location; the folderId is what actually drives
970
+ // subsequent reads/writes, so even legacy users with the old folder name
971
+ // work fine since gDriveFindOrCreateFolder resolves whichever exists.
816
972
  const folderId = await gDriveFindOrCreateFolder();
817
- // Detect which path was actually found by reading back from the API
818
- // (gDriveFindOrCreateFolder logs it). For now use "mailx" as default
819
- // label — the folderId is what matters for subsequent reads/writes.
820
- const sharedDir = { provider, path: "home/.mailx", folderId: folderId || undefined };
973
+ const sharedDir = { provider, path: "home/.rmfmail", folderId: folderId || undefined };
821
974
  const config = { ...existing, sharedDir, storePath: existing.storePath || DEFAULT_STORE_PATH };
822
975
  fs.mkdirSync(LOCAL_DIR, { recursive: true });
823
976
  atomicWrite(LOCAL_CONFIG_PATH, config);
@@ -848,4 +1001,59 @@ export function getPrefetch() {
848
1001
  return prefs.sync.prefetch !== false;
849
1002
  }
850
1003
  export { DEFAULT_SETTINGS, DEFAULT_ALLOWLIST, DEFAULT_PREFERENCES, DEFAULT_AUTOCOMPLETE, LOCAL_DIR };
1004
+ /** Deploy the app-owned `.md` reference docs to the shared cloud folder so
1005
+ * users can read them next to the `.jsonc` files they document. The .md
1006
+ * files live in the app bundle (`<workspace>/app/docs/` in dev, or
1007
+ * `<package>/docs/` in published builds) and are overwritten on every
1008
+ * release — the file header documents that fact, so users know not to
1009
+ * edit them.
1010
+ *
1011
+ * Skip-path: a manifest file `.docs-version` on the cloud records the
1012
+ * app version that last deployed. We re-deploy only when the running
1013
+ * app's version differs, so startup doesn't pound Drive on every launch.
1014
+ *
1015
+ * This function is fire-and-forget at the call site; failures are logged
1016
+ * but never throw. The `.md` files are reference material, not load-
1017
+ * bearing — the app works without them.
1018
+ */
1019
+ export async function deployDocs(appVersion) {
1020
+ if (!pendingCloudConfig?.folderId)
1021
+ return;
1022
+ const provider = getCloudProvider(pendingCloudConfig.provider, pendingCloudConfig.folderId);
1023
+ if (!provider)
1024
+ return;
1025
+ // Resolve the source docs dir. In dev the workspace has `app/docs/`;
1026
+ // in published packages we look for `docs/` next to this file.
1027
+ const candidates = [
1028
+ path.join(__dirname, "..", "..", "docs"), // workspace dev
1029
+ path.join(__dirname, "docs"), // sibling in published package
1030
+ path.join(__dirname, "..", "docs"), // one level up in some layouts
1031
+ ];
1032
+ let docsDir = "";
1033
+ for (const c of candidates) {
1034
+ if (fs.existsSync(c) && fs.readdirSync(c).some(f => f.endsWith(".md"))) {
1035
+ docsDir = c;
1036
+ break;
1037
+ }
1038
+ }
1039
+ if (!docsDir) {
1040
+ console.log(" [docs] no docs/ dir found in package — skipping deploy");
1041
+ return;
1042
+ }
1043
+ try {
1044
+ const deployedVersion = (await provider.read(".docs-version") || "").trim();
1045
+ if (deployedVersion === appVersion)
1046
+ return; // already up to date
1047
+ const mdFiles = fs.readdirSync(docsDir).filter(f => f.endsWith(".md"));
1048
+ for (const f of mdFiles) {
1049
+ const content = fs.readFileSync(path.join(docsDir, f), "utf-8");
1050
+ await provider.write(f, content);
1051
+ }
1052
+ await provider.write(".docs-version", appVersion);
1053
+ console.log(` [docs] deployed ${mdFiles.length} .md file(s) for app v${appVersion}`);
1054
+ }
1055
+ catch (e) {
1056
+ console.warn(` [docs] deploy failed: ${e.message}`);
1057
+ }
1058
+ }
851
1059
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,29 +1,39 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-settings",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
+ "files": [
8
+ "*.js",
9
+ "*.d.ts",
10
+ "*.d.ts.map",
11
+ "docs/**/*.md"
12
+ ],
7
13
  "scripts": {
8
14
  "build": "tsc",
15
+ "prepack": "node ./copy-docs.js",
9
16
  "release": "npmglobalize"
10
17
  },
11
18
  "license": "ISC",
12
19
  "dependencies": {
13
- "@bobfrankston/mailx-types": "^0.1.5",
20
+ "@bobfrankston/mailx-types": "^0.1.6",
14
21
  "jsonc-parser": "^3.3.1"
15
22
  },
16
23
  "repository": {
17
24
  "type": "git",
18
25
  "url": "https://github.com/BobFrankston/mailx-settings.git"
19
26
  },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
20
30
  ".dependencies": {
21
31
  "@bobfrankston/mailx-types": "file:../mailx-types",
22
32
  "jsonc-parser": "^3.3.1"
23
33
  },
24
34
  ".transformedSnapshot": {
25
35
  "dependencies": {
26
- "@bobfrankston/mailx-types": "^0.1.5",
36
+ "@bobfrankston/mailx-types": "^0.1.6",
27
37
  "jsonc-parser": "^3.3.1"
28
38
  }
29
39
  }
@@ -1 +0,0 @@
1
- {"fileNames":["c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es5.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2015.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2016.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2017.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2018.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2019.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2020.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2021.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2022.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2023.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2024.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.dom.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.dom.iterable.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.dom.asynciterable.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.webworker.importscripts.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.scripthost.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2015.core.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2015.collection.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2015.generator.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2015.iterable.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2015.promise.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2015.proxy.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2015.reflect.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2015.symbol.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2016.array.include.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2016.intl.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2017.date.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2017.object.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2017.string.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2017.intl.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2018.intl.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2018.promise.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2018.regexp.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2019.array.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2019.object.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2019.string.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2019.symbol.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2019.intl.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2020.bigint.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2020.date.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2020.promise.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2020.string.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2020.intl.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2020.number.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2021.promise.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2021.string.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2021.weakref.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2021.intl.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2022.array.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2022.error.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2022.intl.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2022.object.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2022.string.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2022.regexp.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2023.array.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2023.collection.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2023.intl.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2024.collection.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2024.object.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2024.promise.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2024.regexp.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.es2024.string.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.array.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.collection.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.intl.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.disposable.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.promise.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.decorators.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.iterator.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.float16.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.error.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.decorators.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.decorators.legacy.d.ts","c:/users/bob/appdata/roaming/npm/node_modules/typescript/lib/lib.esnext.full.d.ts","../../node_modules/jsonc-parser/lib/umd/main.d.ts","../mailx-types/index.d.ts","./index.ts","../../node_modules/@types/node/compatibility/iterators.d.ts","../../node_modules/@types/node/globals.typedarray.d.ts","../../node_modules/@types/node/buffer.buffer.d.ts","../../node_modules/@types/node/globals.d.ts","../../node_modules/@types/node/web-globals/abortcontroller.d.ts","../../node_modules/@types/node/web-globals/blob.d.ts","../../node_modules/@types/node/web-globals/console.d.ts","../../node_modules/@types/node/web-globals/crypto.d.ts","../../node_modules/@types/node/web-globals/domexception.d.ts","../../node_modules/@types/node/web-globals/encoding.d.ts","../../node_modules/@types/node/web-globals/events.d.ts","../../node_modules/undici-types/utility.d.ts","../../node_modules/undici-types/header.d.ts","../../node_modules/undici-types/readable.d.ts","../../node_modules/undici-types/fetch.d.ts","../../node_modules/undici-types/formdata.d.ts","../../node_modules/undici-types/connector.d.ts","../../node_modules/undici-types/client-stats.d.ts","../../node_modules/undici-types/client.d.ts","../../node_modules/undici-types/errors.d.ts","../../node_modules/undici-types/dispatcher.d.ts","../../node_modules/undici-types/global-dispatcher.d.ts","../../node_modules/undici-types/global-origin.d.ts","../../node_modules/undici-types/pool-stats.d.ts","../../node_modules/undici-types/pool.d.ts","../../node_modules/undici-types/handlers.d.ts","../../node_modules/undici-types/balanced-pool.d.ts","../../node_modules/undici-types/round-robin-pool.d.ts","../../node_modules/undici-types/h2c-client.d.ts","../../node_modules/undici-types/agent.d.ts","../../node_modules/undici-types/mock-interceptor.d.ts","../../node_modules/undici-types/mock-call-history.d.ts","../../node_modules/undici-types/mock-agent.d.ts","../../node_modules/undici-types/mock-client.d.ts","../../node_modules/undici-types/mock-pool.d.ts","../../node_modules/undici-types/snapshot-agent.d.ts","../../node_modules/undici-types/mock-errors.d.ts","../../node_modules/undici-types/proxy-agent.d.ts","../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../node_modules/undici-types/retry-handler.d.ts","../../node_modules/undici-types/retry-agent.d.ts","../../node_modules/undici-types/api.d.ts","../../node_modules/undici-types/cache-interceptor.d.ts","../../node_modules/undici-types/interceptors.d.ts","../../node_modules/undici-types/util.d.ts","../../node_modules/undici-types/cookies.d.ts","../../node_modules/undici-types/patch.d.ts","../../node_modules/undici-types/websocket.d.ts","../../node_modules/undici-types/eventsource.d.ts","../../node_modules/undici-types/diagnostics-channel.d.ts","../../node_modules/undici-types/content-type.d.ts","../../node_modules/undici-types/cache.d.ts","../../node_modules/undici-types/index.d.ts","../../node_modules/@types/node/web-globals/fetch.d.ts","../../node_modules/@types/node/web-globals/importmeta.d.ts","../../node_modules/@types/node/web-globals/messaging.d.ts","../../node_modules/@types/node/web-globals/navigator.d.ts","../../node_modules/@types/node/web-globals/performance.d.ts","../../node_modules/@types/node/web-globals/storage.d.ts","../../node_modules/@types/node/web-globals/streams.d.ts","../../node_modules/@types/node/web-globals/timers.d.ts","../../node_modules/@types/node/web-globals/url.d.ts","../../node_modules/@types/node/assert.d.ts","../../node_modules/@types/node/assert/strict.d.ts","../../node_modules/@types/node/async_hooks.d.ts","../../node_modules/@types/node/buffer.d.ts","../../node_modules/@types/node/child_process.d.ts","../../node_modules/@types/node/cluster.d.ts","../../node_modules/@types/node/console.d.ts","../../node_modules/@types/node/constants.d.ts","../../node_modules/@types/node/crypto.d.ts","../../node_modules/@types/node/dgram.d.ts","../../node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/@types/node/dns.d.ts","../../node_modules/@types/node/dns/promises.d.ts","../../node_modules/@types/node/domain.d.ts","../../node_modules/@types/node/events.d.ts","../../node_modules/@types/node/fs.d.ts","../../node_modules/@types/node/fs/promises.d.ts","../../node_modules/@types/node/http.d.ts","../../node_modules/@types/node/http2.d.ts","../../node_modules/@types/node/https.d.ts","../../node_modules/@types/node/inspector.d.ts","../../node_modules/@types/node/inspector.generated.d.ts","../../node_modules/@types/node/inspector/promises.d.ts","../../node_modules/@types/node/module.d.ts","../../node_modules/@types/node/net.d.ts","../../node_modules/buffer/index.d.ts","../../node_modules/@types/node/os.d.ts","../../node_modules/@types/node/path.d.ts","../../node_modules/@types/node/path/posix.d.ts","../../node_modules/@types/node/path/win32.d.ts","../../node_modules/@types/node/perf_hooks.d.ts","../../node_modules/@types/node/process.d.ts","../../node_modules/@types/node/punycode.d.ts","../../node_modules/@types/node/querystring.d.ts","../../node_modules/@types/node/quic.d.ts","../../node_modules/@types/node/readline.d.ts","../../node_modules/@types/node/readline/promises.d.ts","../../node_modules/@types/node/repl.d.ts","../../node_modules/@types/node/sea.d.ts","../../node_modules/@types/node/sqlite.d.ts","../../node_modules/@types/node/stream.d.ts","../../node_modules/@types/node/stream/consumers.d.ts","../../node_modules/@types/node/stream/promises.d.ts","../../node_modules/@types/node/stream/web.d.ts","../../node_modules/@types/node/string_decoder.d.ts","../../node_modules/@types/node/test.d.ts","../../node_modules/@types/node/test/reporters.d.ts","../../node_modules/@types/node/timers.d.ts","../../node_modules/@types/node/timers/promises.d.ts","../../node_modules/@types/node/tls.d.ts","../../node_modules/@types/node/trace_events.d.ts","../../node_modules/@types/node/tty.d.ts","../../node_modules/@types/node/url.d.ts","../../node_modules/@types/node/util.d.ts","../../node_modules/@types/node/util/types.d.ts","../../node_modules/@types/node/v8.d.ts","../../node_modules/@types/node/vm.d.ts","../../node_modules/@types/node/wasi.d.ts","../../node_modules/@types/node/worker_threads.d.ts","../../node_modules/@types/node/zlib.d.ts","../../node_modules/@types/node/index.d.ts","../../node_modules/@types/better-sqlite3/index.d.ts","../../node_modules/@types/connect/index.d.ts","../../node_modules/@types/body-parser/index.d.ts","../../node_modules/@types/send/index.d.ts","../../node_modules/@types/qs/index.d.ts","../../node_modules/@types/range-parser/index.d.ts","../../node_modules/@types/express-serve-static-core/index.d.ts","../../node_modules/@types/http-errors/index.d.ts","../../node_modules/@types/serve-static/index.d.ts","../../node_modules/@types/express/index.d.ts","../../node_modules/@types/ws/index.d.ts"],"fileIdsList":[[92,155,163,167,170,172,173,174,187],[92,155,163,167,170,172,173,174,187,212],[92,155,163,167,169,170,172,173,174,187,212,214],[92,155,163,167,169,170,172,173,174,187,212],[92,155,163,166,167,169,170,172,173,174,187,212,216,217,218],[92,155,163,167,170,172,173,174,187,215,219,221],[92,152,153,155,163,167,170,172,173,174,187],[92,154,155,163,167,170,172,173,174,187],[155,163,167,170,172,173,174,187],[92,155,163,167,170,172,173,174,187,195],[92,155,156,161,163,166,167,170,172,173,174,176,187,192,204],[92,155,156,157,163,166,167,170,172,173,174,187],[92,155,158,163,167,170,172,173,174,187,205],[92,155,159,160,163,167,170,172,173,174,178,187],[92,155,160,163,167,170,172,173,174,187,192,201],[92,155,161,163,166,167,170,172,173,174,176,187],[92,154,155,162,163,167,170,172,173,174,187],[92,155,163,164,167,170,172,173,174,187],[92,155,163,165,166,167,170,172,173,174,187],[92,154,155,163,166,167,170,172,173,174,187],[92,155,163,166,167,168,170,172,173,174,187,192,204],[92,155,163,166,167,168,170,172,173,174,187,192,195],[92,142,155,163,166,167,169,170,172,173,174,176,187,192,204],[92,155,163,166,167,169,170,172,173,174,176,187,192,201,204],[92,155,163,167,169,170,171,172,173,174,187,192,201,204],[90,91,92,93,94,95,96,97,98,99,100,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211],[92,155,163,166,167,170,172,173,174,187],[92,155,163,167,170,172,174,187],[92,155,163,167,170,172,173,174,175,187,204],[92,155,163,166,167,170,172,173,174,176,187,192],[92,155,163,167,170,172,173,174,178,187],[92,155,163,167,170,172,173,174,179,187],[92,155,163,166,167,170,172,173,174,182,187],[92,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211],[92,155,163,167,170,172,173,174,184,187],[92,155,163,167,170,172,173,174,185,187],[92,155,160,163,167,170,172,173,174,176,187,195],[92,155,163,166,167,170,172,173,174,187,188],[92,155,163,167,170,172,173,174,187,189,205,208],[92,155,163,166,167,170,172,173,174,187,192,194,195],[92,155,163,167,170,172,173,174,187,193,195],[92,155,163,167,170,172,173,174,187,195,205],[92,155,163,167,170,172,173,174,187,196],[92,152,155,163,167,170,172,173,174,187,192,198,204],[92,155,163,167,170,172,173,174,187,192,197],[92,155,163,166,167,170,172,173,174,187,199,200],[92,155,163,167,170,172,173,174,187,199,200],[92,155,160,163,167,170,172,173,174,176,187,192,201],[92,155,163,167,170,172,173,174,187,202],[92,155,163,167,170,172,173,174,176,187,203],[92,155,163,167,169,170,172,173,174,185,187,204],[92,155,163,167,170,172,173,174,187,205,206],[92,155,160,163,167,170,172,173,174,187,206],[92,155,163,167,170,172,173,174,187,192,207],[92,155,163,167,170,172,173,174,175,187,208],[92,155,163,167,170,172,173,174,187,209],[92,155,158,163,167,170,172,173,174,187],[92,155,160,163,167,170,172,173,174,187],[92,155,163,167,170,172,173,174,187,205],[92,142,155,163,167,170,172,173,174,187],[92,155,163,167,170,172,173,174,187,204],[92,155,163,167,170,172,173,174,187,210],[92,155,163,167,170,172,173,174,182,187],[92,155,163,167,170,172,173,174,187,200],[92,142,155,163,166,167,168,170,172,173,174,182,187,192,195,204,207,208,210],[92,155,163,167,170,172,173,174,187,192,211],[92,155,163,167,170,172,173,174,187,192,212],[92,155,163,167,169,170,172,173,174,187,212,220],[92,155,163,166,167,169,170,171,172,173,174,176,187,192,201,204,211,212],[92,107,110,113,114,155,163,167,170,172,173,174,187,204],[92,110,155,163,167,170,172,173,174,187,192,204],[92,110,114,155,163,167,170,172,173,174,187,204],[92,155,163,167,170,172,173,174,187,192],[92,104,155,163,167,170,172,173,174,187],[92,108,155,163,167,170,172,173,174,187],[92,106,107,110,155,163,167,170,172,173,174,187,204],[92,155,163,167,170,172,173,174,176,187,201],[92,104,155,163,167,170,172,173,174,187,212],[92,106,110,155,163,167,170,172,173,174,176,187,204],[92,101,102,103,105,109,155,163,166,167,170,172,173,174,187,192,204],[92,110,119,127,155,163,167,170,172,173,174,187],[92,102,108,155,163,167,170,172,173,174,187],[92,110,136,137,155,163,167,170,172,173,174,187],[92,102,105,110,155,163,167,170,172,173,174,187,195,204,212],[92,110,155,163,167,170,172,173,174,187],[92,106,110,155,163,167,170,172,173,174,187,204],[92,101,155,163,167,170,172,173,174,187],[92,104,105,106,108,109,110,111,112,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,137,138,139,140,141,155,163,167,170,172,173,174,187],[92,110,129,132,155,163,167,170,172,173,174,187],[92,110,119,120,121,155,163,167,170,172,173,174,187],[92,108,110,120,122,155,163,167,170,172,173,174,187],[92,109,155,163,167,170,172,173,174,187],[92,102,104,110,155,163,167,170,172,173,174,187],[92,110,114,120,122,155,163,167,170,172,173,174,187],[92,114,155,163,167,170,172,173,174,187],[92,108,110,113,155,163,167,170,172,173,174,187,204],[92,102,106,110,119,155,163,167,170,172,173,174,187],[92,110,129,155,163,167,170,172,173,174,187],[92,122,155,163,167,170,172,173,174,187],[92,104,110,136,155,163,167,170,172,173,174,187,195,210,212],[87,88,92,155,163,167,170,172,173,174,179,187]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"8fd575e12870e9944c7e1d62e1f5a73fcf23dd8d3a321f2a2c74c20d022283fe","impliedFormat":1},{"version":"2ab096661c711e4a81cc464fa1e6feb929a54f5340b46b0a07ac6bbf857471f0","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7a3c8b952931daebdfc7a2897c53c0a1c73624593fa070e46bd537e64dcd20a","affectsGlobalScope":true,"impliedFormat":1},{"version":"80e18897e5884b6723488d4f5652167e7bb5024f946743134ecc4aa4ee731f89","affectsGlobalScope":true,"impliedFormat":1},{"version":"cd034f499c6cdca722b60c04b5b1b78e058487a7085a8e0d6fb50809947ee573","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"87dc0f382502f5bbce5129bdc0aea21e19a3abbc19259e0b43ae038a9fc4e326","affectsGlobalScope":true,"impliedFormat":1},{"version":"b1cb28af0c891c8c96b2d6b7be76bd394fddcfdb4709a20ba05a7c1605eea0f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2fef54945a13095fdb9b84f705f2b5994597640c46afeb2ce78352fab4cb3279","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac77cb3e8c6d3565793eb90a8373ee8033146315a3dbead3bde8db5eaf5e5ec6","affectsGlobalScope":true,"impliedFormat":1},{"version":"56e4ed5aab5f5920980066a9409bfaf53e6d21d3f8d020c17e4de584d29600ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ece9f17b3866cc077099c73f4983bddbcb1dc7ddb943227f1ec070f529dedd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a6282c8827e4b9a95f4bf4f5c205673ada31b982f50572d27103df8ceb8013c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c9319a09485199c1f7b0498f2988d6d2249793ef67edda49d1e584746be9032","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3a2a0cee0f03ffdde24d89660eba2685bfbdeae955a6c67e8c4c9fd28928eeb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"60037901da1a425516449b9a20073aa03386cce92f7a1fd902d7602be3a7c2e9","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4b1d2c51d058fc21ec2629fff7a76249dec2e36e12960ea056e3ef89174080f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22adec94ef7047a6c9d1af3cb96be87a335908bf9ef386ae9fd50eeb37f44c47","affectsGlobalScope":true,"impliedFormat":1},{"version":"4245fee526a7d1754529d19227ecbf3be066ff79ebb6a380d78e41648f2f224d","affectsGlobalScope":true,"impliedFormat":1},{"version":"73f78680d4c08509933daf80947902f6ff41b6230f94dd002ae372620adb0f60","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5239f5c01bcfa9cd32f37c496cf19c61d69d37e48be9de612b541aac915805b","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"bde31fd423cd93b0eff97197a3f66df7c93e8c0c335cbeb113b7ff1ac35c23f4","impliedFormat":1},{"version":"f1d603af05e59e26aae3d9fa7bb0138e744bfbfc9f4793ddeaabe5c85da1d30f","impliedFormat":1},{"version":"63e5550ff8d769e7ffde021950158b06419ad126ec483fe372092f29e89fc5e8","impliedFormat":99},{"version":"bbdc2f2d77c889efee75b501065b228699427000af666df555b2f0a1d1052249","signature":"9beea4bc5b1a3615d8b0f0fe74ef0f03c94d251131b17fc7387c9b4d009fd440","impliedFormat":99},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"0ccdaa19852d25ecd84eec365c3bfa16e7859cadecf6e9ca6d0dbbbee439743f","affectsGlobalScope":true,"impliedFormat":1},{"version":"438b41419b1df9f1fbe33b5e1b18f5853432be205991d1b19f5b7f351675541e","affectsGlobalScope":true,"impliedFormat":1},{"version":"096116f8fedc1765d5bd6ef360c257b4a9048e5415054b3bf3c41b07f8951b0b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5e01375c9e124a83b52ee4b3244ed1a4d214a6cfb54ac73e164a823a4a7860a","affectsGlobalScope":true,"impliedFormat":1},{"version":"f90ae2bbce1505e67f2f6502392e318f5714bae82d2d969185c4a6cecc8af2fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b58e207b93a8f1c88bbf2a95ddc686ac83962b13830fe8ad3f404ffc7051fb4","affectsGlobalScope":true,"impliedFormat":1},{"version":"1fefabcb2b06736a66d2904074d56268753654805e829989a46a0161cd8412c5","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"c18a99f01eb788d849ad032b31cafd49de0b19e083fe775370834c5675d7df8e","affectsGlobalScope":true,"impliedFormat":1},{"version":"5247874c2a23b9a62d178ae84f2db6a1d54e6c9a2e7e057e178cc5eea13757fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdcf9ea426ad970f96ac930cd176d5c69c6c24eebd9fc580e1572d6c6a88f62c","impliedFormat":1},{"version":"23cd712e2ce083d68afe69224587438e5914b457b8acf87073c22494d706a3d0","impliedFormat":1},{"version":"156a859e21ef3244d13afeeba4e49760a6afa035c149dda52f0c45ea8903b338","impliedFormat":1},{"version":"10ec5e82144dfac6f04fa5d1d6c11763b3e4dbbac6d99101427219ab3e2ae887","impliedFormat":1},{"version":"615754924717c0b1e293e083b83503c0a872717ad5aa60ed7f1a699eb1b4ea5c","impliedFormat":1},{"version":"074de5b2fdead0165a2757e3aaef20f27a6347b1c36adea27d51456795b37682","impliedFormat":1},{"version":"68834d631c8838c715f225509cfc3927913b9cc7a4870460b5b60c8dbdb99baf","impliedFormat":1},{"version":"24371e69a38fc33e268d4a8716dbcda430d6c2c414a99ff9669239c4b8f40dea","impliedFormat":1},{"version":"ccab02f3920fc75c01174c47fcf67882a11daf16baf9e81701d0a94636e94556","impliedFormat":1},{"version":"3e11fce78ad8c0e1d1db4ba5f0652285509be3acdd519529bc8fcef85f7dafd9","impliedFormat":1},{"version":"ea6bc8de8b59f90a7a3960005fd01988f98fd0784e14bc6922dde2e93305ec7d","impliedFormat":1},{"version":"36107995674b29284a115e21a0618c4c2751b32a8766dd4cb3ba740308b16d59","impliedFormat":1},{"version":"914a0ae30d96d71915fc519ccb4efbf2b62c0ddfb3a3fc6129151076bc01dc60","impliedFormat":1},{"version":"9c32412007b5662fd34a8eb04292fb5314ec370d7016d1c2fb8aa193c807fe22","impliedFormat":1},{"version":"7fd1b31fd35876b0aa650811c25ec2c97a3c6387e5473eb18004bed86cdd76b6","impliedFormat":1},{"version":"4d327f7d72ad0918275cea3eee49a6a8dc8114ae1d5b7f3f5d0774de75f7439a","impliedFormat":1},{"version":"6ebe8ebb8659aaa9d1acbf3710d7dae3e923e97610238b9511c25dc39023a166","impliedFormat":1},{"version":"e85d7f8068f6a26710bff0cc8c0fc5e47f71089c3780fbede05857331d2ddec9","impliedFormat":1},{"version":"7befaf0e76b5671be1d47b77fcc65f2b0aad91cc26529df1904f4a7c46d216e9","impliedFormat":1},{"version":"0a60a292b89ca7218b8616f78e5bbd1c96b87e048849469cccb4355e98af959a","impliedFormat":1},{"version":"0b6e25234b4eec6ed96ab138d96eb70b135690d7dd01f3dd8a8ab291c35a683a","impliedFormat":1},{"version":"9666f2f84b985b62400d2e5ab0adae9ff44de9b2a34803c2c5bd3c8325b17dc0","impliedFormat":1},{"version":"40cd35c95e9cf22cfa5bd84e96408b6fcbca55295f4ff822390abb11afbc3dca","impliedFormat":1},{"version":"b1616b8959bf557feb16369c6124a97a0e74ed6f49d1df73bb4b9ddf68acf3f3","impliedFormat":1},{"version":"5b03a034c72146b61573aab280f295b015b9168470f2df05f6080a2122f9b4df","impliedFormat":1},{"version":"40b463c6766ca1b689bfcc46d26b5e295954f32ad43e37ee6953c0a677e4ae2b","impliedFormat":1},{"version":"249b9cab7f5d628b71308c7d9bb0a808b50b091e640ba3ed6e2d0516f4a8d91d","impliedFormat":1},{"version":"80aae6afc67faa5ac0b32b5b8bc8cc9f7fa299cff15cf09cc2e11fd28c6ae29e","impliedFormat":1},{"version":"f473cd2288991ff3221165dcf73cd5d24da30391f87e85b3dd4d0450c787a391","impliedFormat":1},{"version":"499e5b055a5aba1e1998f7311a6c441a369831c70905cc565ceac93c28083d53","impliedFormat":1},{"version":"8aee8b6d4f9f62cf3776cda1305fb18763e2aade7e13cea5bbe699112df85214","impliedFormat":1},{"version":"c63b9ada8c72f95aac5db92aea07e5e87ec810353cdf63b2d78f49a58662cf6c","impliedFormat":1},{"version":"1cc2a09e1a61a5222d4174ab358a9f9de5e906afe79dbf7363d871a7edda3955","impliedFormat":1},{"version":"5d0375ca7310efb77e3ef18d068d53784faf62705e0ad04569597ae0e755c401","impliedFormat":1},{"version":"59af37caec41ecf7b2e76059c9672a49e682c1a2aa6f9d7dc78878f53aa284d6","impliedFormat":1},{"version":"addf417b9eb3f938fddf8d81e96393a165e4be0d4a8b6402292f9c634b1cb00d","impliedFormat":1},{"version":"b64d4d1c5f877f9c666e98e833f0205edb9384acc46e98a1fef344f64d6aba44","impliedFormat":1},{"version":"adf27937dba6af9f08a68c5b1d3fce0ca7d4b960c57e6d6c844e7d1a8e53adae","impliedFormat":1},{"version":"12950411eeab8563b349cb7959543d92d8d02c289ed893d78499a19becb5a8cc","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"c9381908473a1c92cb8c516b184e75f4d226dad95c3a85a5af35f670064d9a2f","impliedFormat":1},{"version":"c3f5289820990ab66b70c7fb5b63cb674001009ff84b13de40619619a9c8175f","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3275d55fac10b799c9546804126239baf020d220136163f763b55a74e50e750","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa68a0a3b7cb32c00e39ee3cd31f8f15b80cac97dce51b6ee7fc14a1e8deb30b","affectsGlobalScope":true,"impliedFormat":1},{"version":"1cf059eaf468efcc649f8cf6075d3cb98e9a35a0fe9c44419ec3d2f5428d7123","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c36e755bced82df7fb6ce8169265d0a7bb046ab4e2cb6d0da0cb72b22033e89","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"7a93de4ff8a63bafe62ba86b89af1df0ccb5e40bb85b0c67d6bbcfdcf96bf3d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"90e85f9bc549dfe2b5749b45fe734144e96cd5d04b38eae244028794e142a77e","affectsGlobalScope":true,"impliedFormat":1},{"version":"e0a5deeb610b2a50a6350bd23df6490036a1773a8a71d70f2f9549ab009e67ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"3fad5618174d74a34ee006406d4eb37e8d07dd62eb1315dbf52f48d31a337547","impliedFormat":1},{"version":"7e49f52a159435fc8df4de9dc377ef5860732ca2dc9efec1640531d3cf5da7a3","impliedFormat":1},{"version":"dd4bde4bdc2e5394aed6855e98cf135dfdf5dd6468cad842e03116d31bbcc9bc","impliedFormat":1},{"version":"4d4e879009a84a47c05350b8dca823036ba3a29a3038efed1be76c9f81e45edf","affectsGlobalScope":true,"impliedFormat":1},{"version":"8b50a819485ffe0d237bf0d131e92178d14d11e2aa873d73615a9ec578b341f5","impliedFormat":1},{"version":"9ba13b47cb450a438e3076c4a3f6afb9dc85e17eae50f26d4b2d72c0688c9251","impliedFormat":1},{"version":"b64cd4401633ea4ecadfd700ddc8323a13b63b106ac7127c1d2726f32424622c","impliedFormat":1},{"version":"37c6e5fe5715814412b43cc9b50b24c67a63c4e04e753e0d1305970d65417a60","impliedFormat":1},{"version":"1d024184fb57c58c5c91823f9d10b4915a4867b7934e89115fd0d861a9df27c8","impliedFormat":1},{"version":"ee0e4946247f842c6dd483cbb60a5e6b484fee07996e3a7bc7343dfb68a04c5d","impliedFormat":1},{"version":"ef051f42b7e0ef5ca04552f54c4552eac84099d64b6c5ad0ef4033574b6035b8","impliedFormat":1},{"version":"853a43154f1d01b0173d9cbd74063507ece57170bad7a3b68f3fa1229ad0a92f","impliedFormat":1},{"version":"56231e3c39a031bfb0afb797690b20ed4537670c93c0318b72d5180833d98b72","impliedFormat":1},{"version":"5cc7c39031bfd8b00ad58f32143d59eb6ffc24f5d41a20931269011dccd36c5e","impliedFormat":1},{"version":"12d602a8fe4c2f2ba4f7804f5eda8ba07e0c83bf5cf0cda8baffa2e9967bfb77","affectsGlobalScope":true,"impliedFormat":1},{"version":"a856ab781967b62b288dfd85b860bef0e62f005ed4b1b8fa25c53ce17856acaf","impliedFormat":1},{"version":"cc25940cfb27aa538e60d465f98bb5068d4d7d33131861ace43f04fe6947d68f","impliedFormat":1},{"version":"8db46b61a690f15b245cf16270db044dc047dce9f93b103a59f50262f677ea1f","impliedFormat":1},{"version":"01ff95aa1443e3f7248974e5a771f513cb2ac158c8898f470a1792f817bee497","impliedFormat":1},{"version":"757227c8b345c57d76f7f0e3bbad7a91ffca23f1b2547cbed9e10025816c9cb7","impliedFormat":1},{"version":"959d0327c96dd9bb5521f3ed6af0c435996504cc8dd46baa8e12cb3b3518cef1","impliedFormat":1},{"version":"e1c1a0b4d1ead0de9eca52203aeb1f771f21e6238d6fcd15aa56ac2a02f1b7bf","impliedFormat":1},{"version":"101f482fd48cb4c7c0468dcc6d62c843d842977aea6235644b1edd05e81fbf22","impliedFormat":1},{"version":"266bee0a41e9c3ba335583e21e9277ae03822402cf5e8e1d99f5196853613b98","affectsGlobalScope":true,"impliedFormat":1},{"version":"386606f8a297988535cb1401959041cfa7f59d54b8a9ed09738e65c98684c976","impliedFormat":1},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","impliedFormat":1},{"version":"3ef397f12387eff17f550bc484ea7c27d21d43816bbe609d495107f44b97e933","impliedFormat":1},{"version":"1023282e2ba810bc07905d3668349fbd37a26411f0c8f94a70ef3c05fe523fcf","impliedFormat":1},{"version":"b214ebcf76c51b115453f69729ee8aa7b7f8eccdae2a922b568a45c2d7ff52f7","impliedFormat":1},{"version":"429c9cdfa7d126255779efd7e6d9057ced2d69c81859bbab32073bad52e9ba76","impliedFormat":1},{"version":"e236b5eba291f51bdf32c231673e6cab81b5410850e61f51a7a524dddadc0f95","impliedFormat":1},{"version":"ce8653341224f8b45ff46d2a06f2cacb96f841f768a886c9d8dd8ec0878b11bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f2c62938251b45715fd2a9887060ec4fbc8724727029d1cbce373747252bdd7","impliedFormat":1},{"version":"e3ace08b6bbd84655d41e244677b474fd995923ffef7149ddb68af8848b60b05","impliedFormat":1},{"version":"132580b0e86c48fab152bab850fc57a4b74fe915c8958d2ccb052b809a44b61c","impliedFormat":1},{"version":"90a278f5fab7557e69e97056c0841adf269c42697194f0bd5c5e69152637d4b3","impliedFormat":1},{"version":"69c9a5a9392e8564bd81116e1ed93b13205201fb44cb35a7fde8c9f9e21c4b23","impliedFormat":1},{"version":"5f8fc37f8434691ffac1bfd8fc2634647da2c0e84253ab5d2dd19a7718915b35","impliedFormat":1},{"version":"5981c2340fd8b076cae8efbae818d42c11ffc615994cb060b1cd390795f1be2b","impliedFormat":1},{"version":"f263485c9ca90df9fe7bb3a906db9701997dc6cae86ace1f8106ac8d2f7f677b","impliedFormat":1},{"version":"1edcf2f36fc332615846bde6dcc71a8fe526065505bc5e3dcfd65a14becdf698","affectsGlobalScope":true,"impliedFormat":1},{"version":"0250da3eb85c99624f974e77ef355cdf86f43980251bc371475c2b397ba55bcd","impliedFormat":1},{"version":"f1c93e046fb3d9b7f8249629f4b63dc068dd839b824dd0aa39a5e68476dc9420","impliedFormat":1},{"version":"3d3a5f27ffbc06c885dd4d5f9ee20de61faf877fe2c3a7051c4825903d9a7fdc","impliedFormat":1},{"version":"12806f9f085598ef930edaf2467a5fa1789a878fba077cd27e85dc5851e11834","impliedFormat":1},{"version":"1dbca38aa4b0db1f4f9e6edacc2780af7e028b733d2a98dd3598cd235ca0c97d","impliedFormat":1},{"version":"a43fe41c33d0a192a0ecaf9b92e87bef3709c9972e6d53c42c49251ccb962d69","impliedFormat":1},{"version":"a177959203c017fad3ecc4f3d96c8757a840957a4959a3ae00dab9d35961ca6c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6fc727ccf9b36e257ff982ea0badeffbfc2c151802f741bddff00c6af3b784cf","impliedFormat":1},{"version":"19143c930aef7ccf248549f3e78992f2f1049118ec5d4622e95025057d8e392b","impliedFormat":1},{"version":"4844a4c9b4b1e812b257676ed8a80b3f3be0e29bf05e742cc2ea9c3c6865e6c6","impliedFormat":1},{"version":"064878a60367e0407c42fb7ba02a2ea4d83257357dc20088e549bd4d89433e9c","impliedFormat":1},{"version":"cca8917838a876e2d7016c9b6af57cbf11fdf903c5fdd8e613fa31840b2957bf","impliedFormat":1},{"version":"d91ae55e4282c22b9c21bc26bd3ef637d3fe132507b10529ae68bf76f5de785b","impliedFormat":1},{"version":"b484ec11ba00e3a2235562a41898d55372ccabe607986c6fa4f4aba72093749f","impliedFormat":1},{"version":"7e8a671604329e178bb479c8f387715ebd40a091fc4a7552a0a75c2f3a21c65c","impliedFormat":1},{"version":"41ef7992c555671a8fe54db302788adefa191ded810a50329b79d20a6772d14c","impliedFormat":1},{"version":"041a7781b9127ab568d2cdcce62c58fdea7c7407f40b8c50045d7866a2727130","impliedFormat":1},{"version":"4c5e90ddbcd177ad3f2ffc909ae217c87820f1e968f6959e4b6ba38a8cec935e","impliedFormat":1},{"version":"b70dd9a44e1ac42f030bb12e7d79117eac7cb74170d72d381a1e7913320af23a","impliedFormat":1},{"version":"55cdbeebe76a1fa18bbd7e7bf73350a2173926bd3085bb050cf5a5397025ee4e","impliedFormat":1},{"version":"c2a6a737189ced24ffe0634e9239b087e4c26378d0490f95141b9b9b042b746c","impliedFormat":1},{"version":"104c67f0da1bdf0d94865419247e20eded83ce7f9911a1aa75fc675c077ca66e","impliedFormat":1},{"version":"cc0d0b339f31ce0ab3b7a5b714d8e578ce698f1e13d7f8c60bfb766baeb1d35c","impliedFormat":1},{"version":"d34aa8df2d0b18fb56b1d772ff9b3c7aea7256cf0d692f969be6e1d27b74d660","impliedFormat":1},{"version":"f4db16820c99b6db923ab18af5fecb02331d785c4c2a8a88373a0cfc08256589","impliedFormat":1},{"version":"2f5747b1508ccf83fad0c251ba1e5da2f5a30b78b09ffa1cfaf633045160afed","impliedFormat":1},{"version":"6823ccc7b5b77bbf898d878dbcad18aa45e0fa96bdd0abd0de98d514845d9ed9","affectsGlobalScope":true,"impliedFormat":1},{"version":"b71c603a539078a5e3a039b20f2b0a0d1708967530cf97dec8850a9ca45baa2b","impliedFormat":1},{"version":"168d88e14e0d81fe170e0dadd38ae9d217476c11435ea640ddb9b7382bdb6c1f","impliedFormat":1},{"version":"8e04cf0688e0d921111659c2b55851957017148fa7b977b02727477d155b3c47","impliedFormat":1},{"version":"1ba59c8bbeed2cb75b239bb12041582fa3e8ef32f8d0bd0ec802e38442d3f317","impliedFormat":1}],"root":[89],"options":{"allowJs":true,"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":199,"newLine":1,"noImplicitAny":true,"noImplicitReturns":false,"noImplicitThis":true,"outDir":"./","rootDir":"./","skipLibCheck":true,"sourceMap":true,"strict":true,"strictNullChecks":false,"target":99},"referencedMap":[[84,1],[85,1],[15,1],[13,1],[14,1],[19,1],[18,1],[2,1],[20,1],[21,1],[22,1],[23,1],[24,1],[25,1],[26,1],[27,1],[3,1],[28,1],[29,1],[4,1],[30,1],[34,1],[31,1],[32,1],[33,1],[35,1],[36,1],[37,1],[5,1],[38,1],[39,1],[40,1],[41,1],[6,1],[45,1],[42,1],[43,1],[44,1],[46,1],[7,1],[47,1],[52,1],[53,1],[48,1],[49,1],[50,1],[51,1],[8,1],[57,1],[54,1],[55,1],[56,1],[58,1],[9,1],[59,1],[60,1],[61,1],[63,1],[62,1],[64,1],[65,1],[10,1],[66,1],[67,1],[68,1],[11,1],[69,1],[70,1],[71,1],[72,1],[73,1],[1,1],[74,1],[75,1],[12,1],[79,1],[77,1],[82,1],[81,1],[86,1],[76,1],[80,1],[78,1],[83,1],[17,1],[16,1],[213,2],[215,3],[214,4],[219,5],[222,6],[220,1],[152,7],[153,7],[154,8],[92,9],[155,10],[156,11],[157,12],[90,1],[158,13],[159,14],[160,15],[161,16],[162,17],[163,18],[164,18],[165,19],[166,20],[167,21],[168,22],[93,1],[91,1],[169,23],[170,24],[171,25],[212,26],[172,27],[173,28],[174,27],[175,29],[176,30],[178,31],[179,32],[180,32],[181,32],[182,33],[183,34],[184,35],[185,36],[186,37],[187,38],[188,38],[189,39],[190,1],[191,1],[192,40],[193,41],[194,40],[195,42],[196,43],[197,44],[198,45],[199,46],[200,47],[201,48],[202,49],[203,50],[204,51],[205,52],[206,53],[207,54],[208,55],[209,56],[94,27],[95,1],[96,57],[97,58],[98,1],[99,59],[100,1],[143,60],[144,61],[145,62],[146,62],[147,63],[148,1],[149,10],[150,64],[151,61],[210,65],[211,66],[217,1],[218,1],[216,67],[221,68],[223,69],[177,1],[87,1],[119,70],[131,71],[116,72],[132,73],[141,74],[107,75],[108,76],[106,77],[140,2],[135,78],[139,79],[110,80],[128,81],[109,82],[138,83],[104,84],[105,78],[111,85],[112,1],[118,86],[115,85],[102,87],[142,88],[133,89],[122,90],[121,85],[123,91],[126,92],[120,93],[124,94],[136,2],[113,95],[114,96],[127,97],[103,73],[130,98],[129,85],[117,96],[125,99],[134,1],[101,1],[137,100],[89,101],[88,1]],"latestChangedDtsFile":"./index.d.ts","version":"5.9.2"}