@zaclinley/dsh-mailharbor 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -989,7 +989,8 @@ async function openPath(path) {
989
989
  }
990
990
 
991
991
  // src/host/api.ts
992
- import { existsSync as existsSync6, rmSync } from "node:fs";
992
+ import { existsSync as existsSync6, mkdirSync as mkdirSync5, rmSync, writeFileSync as writeFileSync5 } from "node:fs";
993
+ import { basename, join as join6 } from "node:path";
993
994
 
994
995
  // src/host/mail-write.ts
995
996
  import { DatabaseSync } from "node:sqlite";
@@ -3123,7 +3124,7 @@ ${conversation.trim()}
3123
3124
  }
3124
3125
 
3125
3126
  // src/host/version.ts
3126
- var VERSION = "0.20.0";
3127
+ var VERSION = "0.22.0";
3127
3128
 
3128
3129
  // src/host/api.ts
3129
3130
  init_smtp();
@@ -3277,6 +3278,13 @@ function buildRouter(runtime) {
3277
3278
  try {
3278
3279
  await runtime.provider(account).setFlag(detail.mailbox, detail.uid, "\\Flagged", starred);
3279
3280
  } catch {
3281
+ runtime.actionQueue(account).enqueue({
3282
+ type: "flag",
3283
+ mailbox: detail.mailbox,
3284
+ uid: detail.uid,
3285
+ flag: "\\Flagged",
3286
+ value: starred
3287
+ });
3280
3288
  }
3281
3289
  }
3282
3290
  return { starred };
@@ -3292,6 +3300,12 @@ function buildRouter(runtime) {
3292
3300
  try {
3293
3301
  await runtime.provider(account).move(detail.mailbox, detail.uid, target);
3294
3302
  } catch {
3303
+ runtime.actionQueue(account).enqueue({
3304
+ type: "move",
3305
+ mailbox: detail.mailbox,
3306
+ uid: detail.uid,
3307
+ target
3308
+ });
3295
3309
  }
3296
3310
  }
3297
3311
  moveLocalMessage(runtime.paths(account).mailDb, Number(params.id), target);
@@ -3317,6 +3331,13 @@ function buildRouter(runtime) {
3317
3331
  try {
3318
3332
  await runtime.provider(account).setSeen(detail.mailbox, detail.uid, action === "read");
3319
3333
  } catch {
3334
+ runtime.actionQueue(account).enqueue({
3335
+ type: "flag",
3336
+ mailbox: detail.mailbox,
3337
+ uid: detail.uid,
3338
+ flag: "\\Seen",
3339
+ value: action === "read"
3340
+ });
3320
3341
  }
3321
3342
  }
3322
3343
  count += 1;
@@ -3327,6 +3348,12 @@ function buildRouter(runtime) {
3327
3348
  try {
3328
3349
  await runtime.provider(account).move(detail.mailbox, detail.uid, target);
3329
3350
  } catch {
3351
+ runtime.actionQueue(account).enqueue({
3352
+ type: "move",
3353
+ mailbox: detail.mailbox,
3354
+ uid: detail.uid,
3355
+ target
3356
+ });
3330
3357
  }
3331
3358
  }
3332
3359
  moveLocalMessage(runtime.paths(account).mailDb, Number(detail.id), target);
@@ -3338,6 +3365,13 @@ function buildRouter(runtime) {
3338
3365
  try {
3339
3366
  await runtime.provider(account).setFlag(detail.mailbox, detail.uid, "\\Flagged", starred);
3340
3367
  } catch {
3368
+ runtime.actionQueue(account).enqueue({
3369
+ type: "flag",
3370
+ mailbox: detail.mailbox,
3371
+ uid: detail.uid,
3372
+ flag: "\\Flagged",
3373
+ value: starred
3374
+ });
3341
3375
  }
3342
3376
  }
3343
3377
  count += 1;
@@ -3959,7 +3993,49 @@ function buildRouter(runtime) {
3959
3993
  throw aiHttpError(error);
3960
3994
  }
3961
3995
  });
3962
- router.get("/projects", () => ({ items: runtime.projects().list().map(projectView) }));
3996
+ router.post("/projects/:id/attachment", async ({ params, body }) => {
3997
+ const payload = await body();
3998
+ const account = accountFromPayload(runtime, payload);
3999
+ const project = runtime.projects().get(String(params.id ?? ""));
4000
+ if (project === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
4001
+ const emailId = Number(payload.emailId ?? 0);
4002
+ const attachmentId = Number(payload.attachmentId ?? 0);
4003
+ const file = runtime.database(account).attachment(emailId, attachmentId);
4004
+ if (file === void 0) throw new HttpError(404, "\u9644\u4EF6\u4E0D\u5B58\u5728");
4005
+ const dir = join6(project.path, "attachments");
4006
+ mkdirSync5(dir, { recursive: true });
4007
+ const safe = basename(file.filename).replace(/[/\\:*?"<>|]/g, "_") || "attachment";
4008
+ let target = join6(dir, safe);
4009
+ let index = 1;
4010
+ while (existsSync6(target)) {
4011
+ const dot = safe.lastIndexOf(".");
4012
+ const stem = dot > 0 ? safe.slice(0, dot) : safe;
4013
+ const ext = dot > 0 ? safe.slice(dot) : "";
4014
+ target = join6(dir, `${stem}-${String(index)}${ext}`);
4015
+ index += 1;
4016
+ }
4017
+ writeFileSync5(target, Buffer.from(file.data));
4018
+ return { ok: true, path: target, filename: basename(target) };
4019
+ });
4020
+ router.get("/projects", () => {
4021
+ const counts = /* @__PURE__ */ new Map();
4022
+ for (const account of runtime.current.accounts) {
4023
+ for (const task of runtime.tasks().list({ accountId: account.id })) {
4024
+ const projectId = task.projectId ?? "";
4025
+ if (projectId === "") continue;
4026
+ const entry = counts.get(projectId) ?? { total: 0, done: 0 };
4027
+ entry.total += 1;
4028
+ if (task.status === "COMPLETED") entry.done += 1;
4029
+ counts.set(projectId, entry);
4030
+ }
4031
+ }
4032
+ return {
4033
+ items: runtime.projects().list().map((project) => {
4034
+ const stat = counts.get(project.id);
4035
+ return { ...projectView(project), taskTotal: stat?.total ?? 0, taskDone: stat?.done ?? 0 };
4036
+ })
4037
+ };
4038
+ });
3963
4039
  router.get("/projects/for", ({ url }) => {
3964
4040
  const account = accountFromPayload(runtime, { accountId: url.searchParams.get("accountId") ?? void 0 });
3965
4041
  const key = url.searchParams.get("key") ?? "";
@@ -4472,7 +4548,7 @@ ${signature}`;
4472
4548
 
4473
4549
  // src/host/runtime.ts
4474
4550
  import { existsSync as existsSync8, statSync } from "node:fs";
4475
- import { join as join7 } from "node:path";
4551
+ import { join as join8 } from "node:path";
4476
4552
 
4477
4553
  // src/host/secrets.ts
4478
4554
  import { spawnSync } from "node:child_process";
@@ -4662,7 +4738,7 @@ var CredentialManager = class {
4662
4738
  };
4663
4739
 
4664
4740
  // src/host/ai-store.ts
4665
- import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync5, renameSync as renameSync4, writeFileSync as writeFileSync5 } from "node:fs";
4741
+ import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as renameSync4, writeFileSync as writeFileSync6 } from "node:fs";
4666
4742
  import { dirname as dirname2 } from "node:path";
4667
4743
  var MAX_THREADS = 50;
4668
4744
  var MAX_CARDS_PER_THREAD = 50;
@@ -4690,9 +4766,9 @@ var AiThreadStore = class {
4690
4766
  prune(data);
4691
4767
  const text2 = `${JSON.stringify(data, null, 2)}
4692
4768
  `;
4693
- mkdirSync5(dirname2(this.file), { recursive: true });
4769
+ mkdirSync6(dirname2(this.file), { recursive: true });
4694
4770
  const temp = `${this.file}.${String(process.pid)}.tmp`;
4695
- writeFileSync5(temp, text2, { mode: 384 });
4771
+ writeFileSync6(temp, text2, { mode: 384 });
4696
4772
  renameSync4(temp, this.file);
4697
4773
  }
4698
4774
  get(key) {
@@ -4802,7 +4878,7 @@ function prune(data) {
4802
4878
  }
4803
4879
 
4804
4880
  // src/host/mail-flags.ts
4805
- import { mkdirSync as mkdirSync6, readFileSync as readFileSync6, renameSync as renameSync5, writeFileSync as writeFileSync6 } from "node:fs";
4881
+ import { mkdirSync as mkdirSync7, readFileSync as readFileSync6, renameSync as renameSync5, writeFileSync as writeFileSync7 } from "node:fs";
4806
4882
  import { dirname as dirname3 } from "node:path";
4807
4883
  var MailFlagsStore = class {
4808
4884
  file;
@@ -4822,9 +4898,9 @@ var MailFlagsStore = class {
4822
4898
  return this.keys;
4823
4899
  }
4824
4900
  flush() {
4825
- mkdirSync6(dirname3(this.file), { recursive: true });
4901
+ mkdirSync7(dirname3(this.file), { recursive: true });
4826
4902
  const temp = `${this.file}.${String(process.pid)}.tmp`;
4827
- writeFileSync6(temp, `${JSON.stringify({ starred: [...this.load()] }, null, 2)}
4903
+ writeFileSync7(temp, `${JSON.stringify({ starred: [...this.load()] }, null, 2)}
4828
4904
  `, {
4829
4905
  encoding: "utf8",
4830
4906
  mode: 384
@@ -4853,10 +4929,87 @@ var MailFlagsStore = class {
4853
4929
  }
4854
4930
  };
4855
4931
 
4856
- // src/host/tasks.ts
4932
+ // src/host/action-queue.ts
4857
4933
  import { randomUUID as randomUUID4 } from "node:crypto";
4858
- import { mkdirSync as mkdirSync7 } from "node:fs";
4934
+ import { mkdirSync as mkdirSync8, readFileSync as readFileSync7, renameSync as renameSync6, writeFileSync as writeFileSync8 } from "node:fs";
4859
4935
  import { dirname as dirname4 } from "node:path";
4936
+ var ActionQueueStore = class {
4937
+ file;
4938
+ items = null;
4939
+ constructor(file) {
4940
+ this.file = file;
4941
+ }
4942
+ load() {
4943
+ if (this.items !== null) return this.items;
4944
+ try {
4945
+ const parsed = JSON.parse(readFileSync7(this.file, "utf8"));
4946
+ this.items = Array.isArray(parsed) ? parsed.filter((item) => typeof item?.id === "string") : [];
4947
+ } catch {
4948
+ this.items = [];
4949
+ }
4950
+ return this.items;
4951
+ }
4952
+ flush() {
4953
+ mkdirSync8(dirname4(this.file), { recursive: true });
4954
+ const temp = `${this.file}.${String(process.pid)}.tmp`;
4955
+ writeFileSync8(temp, `${JSON.stringify(this.load(), null, 2)}
4956
+ `, { encoding: "utf8", mode: 384 });
4957
+ renameSync6(temp, this.file);
4958
+ }
4959
+ list() {
4960
+ return [...this.load()];
4961
+ }
4962
+ enqueue(action) {
4963
+ const items = this.load();
4964
+ const filtered = items.filter(
4965
+ (item) => !(item.type === action.type && item.mailbox === action.mailbox && item.uid === action.uid && (action.type === "move" || item.flag === action.flag))
4966
+ );
4967
+ filtered.push({ ...action, id: randomUUID4(), createdAt: (/* @__PURE__ */ new Date()).toISOString() });
4968
+ this.items = filtered;
4969
+ this.flush();
4970
+ }
4971
+ remove(ids) {
4972
+ if (ids.length === 0) return;
4973
+ const set = new Set(ids);
4974
+ this.items = this.load().filter((item) => !set.has(item.id));
4975
+ this.flush();
4976
+ }
4977
+ /** Try every queued action; keep the ones the server still rejects. */
4978
+ async flushTo(executor) {
4979
+ const pending = this.list();
4980
+ const done = [];
4981
+ let failed = 0;
4982
+ for (const action of pending) {
4983
+ try {
4984
+ if (action.type === "flag") {
4985
+ await executor.setFlag(
4986
+ action.mailbox,
4987
+ action.uid,
4988
+ action.flag ?? "\\Flagged",
4989
+ action.value !== false
4990
+ );
4991
+ } else if (action.target !== void 0) {
4992
+ await executor.move(action.mailbox, action.uid, action.target);
4993
+ }
4994
+ done.push(action.id);
4995
+ } catch {
4996
+ failed += 1;
4997
+ const current = this.load().find((item) => item.id === action.id);
4998
+ if (current !== void 0) {
4999
+ current.attempts = (current.attempts ?? 0) + 1;
5000
+ if (current.attempts >= 5) done.push(action.id);
5001
+ }
5002
+ }
5003
+ }
5004
+ this.remove(done);
5005
+ return { sent: done.length, failed };
5006
+ }
5007
+ };
5008
+
5009
+ // src/host/tasks.ts
5010
+ import { randomUUID as randomUUID5 } from "node:crypto";
5011
+ import { mkdirSync as mkdirSync9 } from "node:fs";
5012
+ import { dirname as dirname5 } from "node:path";
4860
5013
  import { DatabaseSync as DatabaseSync5 } from "node:sqlite";
4861
5014
  var STATUSES = /* @__PURE__ */ new Set(["NEEDS-ACTION", "IN-PROCESS", "COMPLETED", "CANCELLED"]);
4862
5015
  function now() {
@@ -4905,7 +5058,7 @@ var TaskStore = class {
4905
5058
  }
4906
5059
  open() {
4907
5060
  if (this.db !== null) return this.db;
4908
- mkdirSync7(dirname4(this.file), { recursive: true });
5061
+ mkdirSync9(dirname5(this.file), { recursive: true });
4909
5062
  const db = new DatabaseSync5(this.file);
4910
5063
  db.exec("PRAGMA journal_mode=WAL");
4911
5064
  db.exec("PRAGMA busy_timeout=10000");
@@ -4982,7 +5135,7 @@ var TaskStore = class {
4982
5135
  if (title === "") throw new Error("\u4EFB\u52A1\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A");
4983
5136
  if (title.length > 300) throw new Error("\u4EFB\u52A1\u6807\u9898\u8FC7\u957F");
4984
5137
  const status = statusOf(input.status);
4985
- const id = `task_${randomUUID4()}`;
5138
+ const id = `task_${randomUUID5()}`;
4986
5139
  const stamp3 = now();
4987
5140
  this.open().prepare(
4988
5141
  `INSERT INTO tasks (id, account_id, project_id, uid, title, notes, due, status, priority, owner,
@@ -4992,7 +5145,7 @@ var TaskStore = class {
4992
5145
  id,
4993
5146
  input.accountId,
4994
5147
  input.projectId ?? null,
4995
- `${randomUUID4()}@dsh-mailharbor`,
5148
+ `${randomUUID5()}@dsh-mailharbor`,
4996
5149
  title,
4997
5150
  String(input.notes ?? ""),
4998
5151
  String(input.due ?? ""),
@@ -5088,7 +5241,7 @@ var TaskStore = class {
5088
5241
  );
5089
5242
  return this.get(String(existing.id));
5090
5243
  }
5091
- const id = `task_${randomUUID4()}`;
5244
+ const id = `task_${randomUUID5()}`;
5092
5245
  const stamp3 = now();
5093
5246
  db.prepare(
5094
5247
  `INSERT INTO tasks (id, account_id, calendar_href, href, etag, uid, title, notes, due, status, priority,
@@ -5100,7 +5253,7 @@ var TaskStore = class {
5100
5253
  input.calendarHref,
5101
5254
  input.href,
5102
5255
  input.etag,
5103
- input.todo.uid || `${randomUUID4()}@dsh-mailharbor`,
5256
+ input.todo.uid || `${randomUUID5()}@dsh-mailharbor`,
5104
5257
  String(input.todo.title || "(\u65E0\u6807\u9898)"),
5105
5258
  String(input.todo.notes ?? ""),
5106
5259
  String(input.todo.due ?? ""),
@@ -5144,9 +5297,9 @@ var TaskStore = class {
5144
5297
  };
5145
5298
 
5146
5299
  // src/host/drafts.ts
5147
- import { randomUUID as randomUUID5 } from "node:crypto";
5148
- import { mkdirSync as mkdirSync8, readFileSync as readFileSync7, renameSync as renameSync6, writeFileSync as writeFileSync7 } from "node:fs";
5149
- import { dirname as dirname5, join as join6 } from "node:path";
5300
+ import { randomUUID as randomUUID6 } from "node:crypto";
5301
+ import { mkdirSync as mkdirSync10, readFileSync as readFileSync8, renameSync as renameSync7, writeFileSync as writeFileSync9 } from "node:fs";
5302
+ import { dirname as dirname6, join as join7 } from "node:path";
5150
5303
  function text(value) {
5151
5304
  return value === void 0 || value === null ? "" : String(value);
5152
5305
  }
@@ -5157,7 +5310,7 @@ function isDraft(value) {
5157
5310
  return value !== null && typeof value === "object" && typeof value.id === "string";
5158
5311
  }
5159
5312
  function draftPath(root) {
5160
- return join6(root, "drafts.json");
5313
+ return join7(root, "drafts.json");
5161
5314
  }
5162
5315
  var DraftStore = class {
5163
5316
  file;
@@ -5170,18 +5323,18 @@ var DraftStore = class {
5170
5323
  }
5171
5324
  load() {
5172
5325
  try {
5173
- const parsed = JSON.parse(readFileSync7(this.file, "utf8"));
5326
+ const parsed = JSON.parse(readFileSync8(this.file, "utf8"));
5174
5327
  this.items = Array.isArray(parsed) ? parsed.filter(isDraft) : [];
5175
5328
  } catch {
5176
5329
  this.items = [];
5177
5330
  }
5178
5331
  }
5179
5332
  flush() {
5180
- mkdirSync8(dirname5(this.file), { recursive: true });
5333
+ mkdirSync10(dirname6(this.file), { recursive: true });
5181
5334
  const temp = `${this.file}.${String(process.pid)}.${String(Date.now())}.tmp`;
5182
- writeFileSync7(temp, `${JSON.stringify(this.items, null, 2)}
5335
+ writeFileSync9(temp, `${JSON.stringify(this.items, null, 2)}
5183
5336
  `, { encoding: "utf8", mode: 384 });
5184
- renameSync6(temp, this.file);
5337
+ renameSync7(temp, this.file);
5185
5338
  }
5186
5339
  list() {
5187
5340
  return [...this.items].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt)).map((draft) => ({ ...draft }));
@@ -5215,7 +5368,7 @@ var DraftStore = class {
5215
5368
  return { ...existing };
5216
5369
  }
5217
5370
  const draft = {
5218
- id: randomUUID5(),
5371
+ id: randomUUID6(),
5219
5372
  accountId: this.accountId,
5220
5373
  ...fields,
5221
5374
  updatedAt: now2
@@ -5240,8 +5393,8 @@ var DraftStore = class {
5240
5393
  init_imap();
5241
5394
 
5242
5395
  // src/host/read-state.ts
5243
- import { mkdirSync as mkdirSync9, readFileSync as readFileSync8, renameSync as renameSync7, writeFileSync as writeFileSync8 } from "node:fs";
5244
- import { dirname as dirname6 } from "node:path";
5396
+ import { mkdirSync as mkdirSync11, readFileSync as readFileSync9, renameSync as renameSync8, writeFileSync as writeFileSync10 } from "node:fs";
5397
+ import { dirname as dirname7 } from "node:path";
5245
5398
  var ReadStateStore = class {
5246
5399
  file;
5247
5400
  keys = null;
@@ -5251,7 +5404,7 @@ var ReadStateStore = class {
5251
5404
  load() {
5252
5405
  if (this.keys !== null) return this.keys;
5253
5406
  try {
5254
- const parsed = JSON.parse(readFileSync8(this.file, "utf8"));
5407
+ const parsed = JSON.parse(readFileSync9(this.file, "utf8"));
5255
5408
  const list = Array.isArray(parsed) ? parsed : Array.isArray(parsed?.unread) ? parsed.unread : [];
5256
5409
  this.keys = new Set(list.filter((key) => typeof key === "string" && key !== ""));
5257
5410
  } catch {
@@ -5260,14 +5413,14 @@ var ReadStateStore = class {
5260
5413
  return this.keys;
5261
5414
  }
5262
5415
  flush() {
5263
- mkdirSync9(dirname6(this.file), { recursive: true });
5416
+ mkdirSync11(dirname7(this.file), { recursive: true });
5264
5417
  const temp = `${this.file}.${String(process.pid)}.tmp`;
5265
- writeFileSync8(temp, `${JSON.stringify({ unread: [...this.load()] }, null, 2)}
5418
+ writeFileSync10(temp, `${JSON.stringify({ unread: [...this.load()] }, null, 2)}
5266
5419
  `, {
5267
5420
  encoding: "utf8",
5268
5421
  mode: 384
5269
5422
  });
5270
- renameSync7(temp, this.file);
5423
+ renameSync8(temp, this.file);
5271
5424
  }
5272
5425
  isUnread(key) {
5273
5426
  return key !== "" && this.load().has(key);
@@ -5332,6 +5485,7 @@ var MailHarborRuntime = class {
5332
5485
  projectStore = null;
5333
5486
  taskStore = null;
5334
5487
  flagStores = /* @__PURE__ */ new Map();
5488
+ actionQueues = /* @__PURE__ */ new Map();
5335
5489
  referenceJobs = /* @__PURE__ */ new Map();
5336
5490
  disposed = false;
5337
5491
  constructor(options = {}) {
@@ -5346,13 +5500,13 @@ var MailHarborRuntime = class {
5346
5500
  }
5347
5501
  projects() {
5348
5502
  if (this.projectStore === null) {
5349
- this.projectStore = new ProjectStore(join7(this.config.dataDir, "projects.json"));
5503
+ this.projectStore = new ProjectStore(join8(this.config.dataDir, "projects.json"));
5350
5504
  }
5351
5505
  return this.projectStore;
5352
5506
  }
5353
5507
  tasks() {
5354
5508
  if (this.taskStore === null) {
5355
- this.taskStore = new TaskStore(join7(this.config.dataDir, "state", "state.db"));
5509
+ this.taskStore = new TaskStore(join8(this.config.dataDir, "state", "state.db"));
5356
5510
  }
5357
5511
  return this.taskStore;
5358
5512
  }
@@ -5432,6 +5586,22 @@ var MailHarborRuntime = class {
5432
5586
  paths(account) {
5433
5587
  return accountRuntime(account);
5434
5588
  }
5589
+ actionQueue(account) {
5590
+ const file = join8(this.paths(account).root, "actions-queue.json");
5591
+ const existing = this.actionQueues.get(account.id);
5592
+ if (existing !== void 0 && existing.signature === file) return existing.value;
5593
+ const created = new ActionQueueStore(file);
5594
+ this.actionQueues.set(account.id, { signature: file, value: created });
5595
+ return created;
5596
+ }
5597
+ async flushActions(account) {
5598
+ if (!this.hasCredentials(account)) return { sent: 0, failed: 0 };
5599
+ try {
5600
+ return await this.actionQueue(account).flushTo(this.provider(account));
5601
+ } catch {
5602
+ return { sent: 0, failed: 0 };
5603
+ }
5604
+ }
5435
5605
  referencesStatus(account) {
5436
5606
  return this.referenceJobs.get(account.id) ?? {
5437
5607
  running: false,
@@ -5521,7 +5691,7 @@ var MailHarborRuntime = class {
5521
5691
  return created;
5522
5692
  }
5523
5693
  aiThreads(account) {
5524
- const file = join7(this.paths(account).root, "ai-threads.json");
5694
+ const file = join8(this.paths(account).root, "ai-threads.json");
5525
5695
  const existing = this.aiStores.get(account.id);
5526
5696
  if (existing !== void 0 && existing.signature === file) return existing.value;
5527
5697
  const created = new AiThreadStore(file);
@@ -5529,7 +5699,7 @@ var MailHarborRuntime = class {
5529
5699
  return created;
5530
5700
  }
5531
5701
  flags(account) {
5532
- const file = join7(this.paths(account).root, "starred.json");
5702
+ const file = join8(this.paths(account).root, "starred.json");
5533
5703
  const existing = this.flagStores.get(account.id);
5534
5704
  if (existing !== void 0 && existing.signature === file) return existing.value;
5535
5705
  const created = new MailFlagsStore(file);
@@ -5537,7 +5707,7 @@ var MailHarborRuntime = class {
5537
5707
  return created;
5538
5708
  }
5539
5709
  readState(account) {
5540
- const file = join7(this.paths(account).root, "read-state.json");
5710
+ const file = join8(this.paths(account).root, "read-state.json");
5541
5711
  const existing = this.readStores.get(account.id);
5542
5712
  if (existing !== void 0 && existing.signature === file) return existing.value;
5543
5713
  const created = new ReadStateStore(file);
@@ -5603,6 +5773,7 @@ var MailHarborRuntime = class {
5603
5773
  if (status.exitCode === 0) status.lastSuccessAt = status.finishedAt;
5604
5774
  this.databases.get(account.id)?.value.close();
5605
5775
  this.databases.delete(account.id);
5776
+ if (status.exitCode === 0) void this.flushActions(account).catch(() => void 0);
5606
5777
  }
5607
5778
  })();
5608
5779
  this.backups.set(account.id, job);
@@ -6047,6 +6218,7 @@ function apply(ctx) {
6047
6218
  const disposers = [];
6048
6219
  if (activeAccount2 !== void 0) {
6049
6220
  setTimeout(() => runtime.startReferencesBackfill(activeAccount2), 3e3);
6221
+ setTimeout(() => void runtime.flushActions(activeAccount2).catch(() => void 0), 6e3);
6050
6222
  }
6051
6223
  const start = () => {
6052
6224
  disposers.push(ctx.webServer.register({ kind: "prefix", path: ROUTE, handler }));