@xopcai/xopc 0.0.246 → 0.0.248

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/src/update-offset-store.js +17 -54
  3. package/dist/extensions/telegram/xopc.extension.json +1 -1
  4. package/dist/extensions/weixin/src/auth/accounts.js +3 -5
  5. package/dist/extensions/weixin/src/monitor/monitor.js +3 -5
  6. package/dist/extensions/weixin/src/storage/sync-buf.d.ts +3 -6
  7. package/dist/extensions/weixin/src/storage/sync-buf.js +9 -22
  8. package/dist/gateway/static/root/assets/{activity-store-BlxqErph.js → activity-store-etpmyV7S.js} +1 -1
  9. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CJJzpYYS.js → agent-avatar-dicebear-BmKxSM1k.js} +1 -1
  10. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CUXApfcE.js +1 -0
  11. package/dist/gateway/static/root/assets/{agents-je3sRGmk.js → agents-DNq_GKuc.js} +1 -1
  12. package/dist/gateway/static/root/assets/{api-BbXzyQMj.js → api-B0-hLuZ1.js} +1 -1
  13. package/dist/gateway/static/root/assets/{app-management-settings-panel-Cnn3i00c.js → app-management-settings-panel-qfwAgyhQ.js} +1 -1
  14. package/dist/gateway/static/root/assets/{appearance-settings-BToQaw_v.js → appearance-settings-DqQVUpCC.js} +1 -1
  15. package/dist/gateway/static/root/assets/apps-page-dwIqYmXk.js +1 -0
  16. package/dist/gateway/static/root/assets/{archive-plugin-DD2SweEH.js → archive-plugin-BnMSgZvR.js} +1 -1
  17. package/dist/gateway/static/root/assets/{attachment-load-BFtcib5t.js → attachment-load-CejsQMev.js} +1 -1
  18. package/dist/gateway/static/root/assets/{automations-page-XS8wIl5o.js → automations-page-RC8EyoAf.js} +1 -1
  19. package/dist/gateway/static/root/assets/automations-workspace-SkdcSZ0i.js +6 -0
  20. package/dist/gateway/static/root/assets/{binary-plugins-Xs7pLHxR.js → binary-plugins-DGjppLSG.js} +1 -1
  21. package/dist/gateway/static/root/assets/{block-editor-BPdSzceB.js → block-editor-CWdP4bUc.js} +44 -44
  22. package/dist/gateway/static/root/assets/browser-settings-page-CKCa6TvG.js +8 -0
  23. package/dist/gateway/static/root/assets/{browser-workflow-inputs-BAAc151l.js → browser-workflow-inputs-BQ1Ilw_o.js} +1 -1
  24. package/dist/gateway/static/root/assets/{browser-workflows-page-DUPPvE30.js → browser-workflows-page-CJh4NyxT.js} +2 -2
  25. package/dist/gateway/static/root/assets/{capabilities-settings-panel-cl9kYilL.js → capabilities-settings-panel-DSp--zIZ.js} +5 -5
  26. package/dist/gateway/static/root/assets/channels-settings-CMd2dDrI.js +1 -0
  27. package/dist/gateway/static/root/assets/{channels-status-swr-CCBCtLDg.js → channels-status-swr-Ohhee4vm.js} +1 -1
  28. package/dist/gateway/static/root/assets/{chat-terminal-dock-DKW1M6aJ.js → chat-terminal-dock-BOtoKTK3.js} +2 -2
  29. package/dist/gateway/static/root/assets/connectors-page-udWs5Kdm.js +2 -0
  30. package/dist/gateway/static/root/assets/{cron-expression-Bijb0ZQu.js → cron-expression-DTj1V3Sw.js} +1 -1
  31. package/dist/gateway/static/root/assets/{date-picker-BZuHw-SY.js → date-picker-Yr6OCvGL.js} +1 -1
  32. package/dist/gateway/static/root/assets/{dependency-picker-BsBD2JFY.js → dependency-picker-DpN3XZg9.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-Ceuw3QKb.js → desktop-pet-DbGzggPF.js} +1 -1
  34. package/dist/gateway/static/root/assets/{desktop-pet-settings-DctOXexM.js → desktop-pet-settings-DinCToZh.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-debug-page-BNlMPATK.js → extension-debug-page-DgTtk4KC.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-page-CK4Uvzge.js → extension-page-DtQeiP6f.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-settings-page-CpnXXemw.js → extension-settings-page-DcguCgsH.js} +1 -1
  38. package/dist/gateway/static/root/assets/{gateway-config-api-C_mlpe-r.js → gateway-config-api-Br7lSf6H.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-config-swr-826dipyU.js → gateway-config-swr-DXuXtU1w.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-settings-DSSW17ed.js → gateway-settings-CdPoDMuj.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-startup-retry-DyvcAIMm.js → gateway-startup-retry-CzBzglzQ.js} +1 -1
  42. package/dist/gateway/static/root/assets/{heartbeat-settings-hbmIZTpg.js → heartbeat-settings-DHk1hawP.js} +1 -1
  43. package/dist/gateway/static/root/assets/home-page-YGipe_W6.js +1 -0
  44. package/dist/gateway/static/root/assets/{image-generation-api-D7cyfks6.js → image-generation-api-TIgsn04n.js} +1 -1
  45. package/dist/gateway/static/root/assets/{index-eZjksPvq.js → index-D5TQQpeb.js} +44 -44
  46. package/dist/gateway/static/root/assets/index-DReBaaTX.css +2 -0
  47. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BQrDwwgi.js → keyboard-shortcuts-settings-wsWuoa8p.js} +1 -1
  48. package/dist/gateway/static/root/assets/local-app-workbench-page-CpyvYyrb.js +2 -0
  49. package/dist/gateway/static/root/assets/{local-apps-page-D-YWD6LS.js → local-apps-page-CXrbrGo8.js} +1 -1
  50. package/dist/gateway/static/root/assets/local-context-graph-BjUf7fQ9.js +1 -0
  51. package/dist/gateway/static/root/assets/{locale-store-CBoCuIMx.js → locale-store-BJFLQY8O.js} +1 -1
  52. package/dist/gateway/static/root/assets/{logs-page-DvLc9l59.js → logs-page-CXKy6E_l.js} +2 -2
  53. package/dist/gateway/static/root/assets/{management-settings-DsULLUUv.js → management-settings-BdJZFR7U.js} +1 -1
  54. package/dist/gateway/static/root/assets/{markdown-split-CjqlP6IB.js → markdown-split-NK3ACVG2.js} +1 -1
  55. package/dist/gateway/static/root/assets/{markdown-view-BXsHghJd.js → markdown-view-DTF9v1gg.js} +1 -1
  56. package/dist/gateway/static/root/assets/{media-plugins-DQL029DU.js → media-plugins-F0jcUxyl.js} +1 -1
  57. package/dist/gateway/static/root/assets/messages-CHNYp8EQ.js +3 -0
  58. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-gauprAae.js → mobile-pairing-wizard-3NKCniSp.js} +1 -1
  59. package/dist/gateway/static/root/assets/models-hub-cache-nCfkBN8M.js +1 -0
  60. package/dist/gateway/static/root/assets/{notes-page-AsEfLZt9.js → notes-page-DuqLahi6.js} +1 -1
  61. package/dist/gateway/static/root/assets/notes-workbench-C7j9EdQk.js +5 -0
  62. package/dist/gateway/static/root/assets/{oauth-api-BjSUDIgq.js → oauth-api-8lP_qJpq.js} +1 -1
  63. package/dist/gateway/static/root/assets/{product-open-page-CAJeUXeU.js → product-open-page-CxGGlWA8.js} +1 -1
  64. package/dist/gateway/static/root/assets/project-detail-page-CfebYVX0.js +1 -0
  65. package/dist/gateway/static/root/assets/projects-page-48GvzSVa.js +1 -0
  66. package/dist/gateway/static/root/assets/{registry-api-BhGKnvLP.js → registry-api-CIsNlSBi.js} +1 -1
  67. package/dist/gateway/static/root/assets/remote-access-hub-64xj_s2m.js +1 -0
  68. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DH6EilMV.js → runtime-tools-settings-panel-YkjhiQfA.js} +2 -2
  69. package/dist/gateway/static/root/assets/{schema-form-DYHmEZeZ.js → schema-form-oFGf3G3s.js} +1 -1
  70. package/dist/gateway/static/root/assets/sessions-page-CcwcdRN8.js +1 -0
  71. package/dist/gateway/static/root/assets/settings-advanced-gate-BaN84CyW.js +1 -0
  72. package/dist/gateway/static/root/assets/{settings-page-BHwPd_M3.js → settings-page-C7VWs0IT.js} +1 -1
  73. package/dist/gateway/static/root/assets/setup-status-panel-DVVOCNbr.js +1 -0
  74. package/dist/gateway/static/root/assets/{share-preview-page-BjwrS03F.js → share-preview-page-t5oz18rh.js} +1 -1
  75. package/dist/gateway/static/root/assets/shares-settings-DUYbYLi7.js +1 -0
  76. package/dist/gateway/static/root/assets/skill-reload-api-BGyD0gB9.js +1 -0
  77. package/dist/gateway/static/root/assets/{skills-page-OHyK25op.js → skills-page-CjF8DTsN.js} +1 -1
  78. package/dist/gateway/static/root/assets/{skills-page.utils-DQx9ulmg.js → skills-page.utils-DEDTYs2W.js} +1 -1
  79. package/dist/gateway/static/root/assets/{system-settings-panel-wO7DWv4C.js → system-settings-panel-BSYuRgFI.js} +1 -1
  80. package/dist/gateway/static/root/assets/task-detail-page-YZYSTJH7.js +1 -0
  81. package/dist/gateway/static/root/assets/{theme-store-hybK3oC9.js → theme-store-O597U8q_.js} +1 -1
  82. package/dist/gateway/static/root/assets/{tunnel-api-CVC8BHZu.js → tunnel-api-FKUi9wDL.js} +1 -1
  83. package/dist/gateway/static/root/assets/{use-autosave-DMvRu2XZ.js → use-autosave-B5eUJ6Zq.js} +1 -1
  84. package/dist/gateway/static/root/assets/user-context-page-BCyiduKd.js +2 -0
  85. package/dist/gateway/static/root/assets/{voice-api-key-field-DuBK2NDG.js → voice-api-key-field-CMKSwz4C.js} +1 -1
  86. package/dist/gateway/static/root/assets/{voice-config-api-CBbiF1T3.js → voice-config-api-q7B6fOFB.js} +1 -1
  87. package/dist/gateway/static/root/assets/{work-discovery-overlay-B7VXWpDr.js → work-discovery-overlay-jhT2EzeH.js} +1 -1
  88. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BokVAsWN.js → workflow-run-setup-panel-DZmvLZjb.js} +2 -2
  89. package/dist/gateway/static/root/assets/workflows-page-DQC0TpMa.js +5 -0
  90. package/dist/gateway/static/root/index.html +12 -12
  91. package/dist/package.js +1 -1
  92. package/dist/src/agent/commands/command-registry.d.ts +1 -0
  93. package/dist/src/agent/commands/command-registry.js +12 -22
  94. package/dist/src/agent/ipc/inbox.d.ts +8 -31
  95. package/dist/src/agent/ipc/inbox.js +64 -133
  96. package/dist/src/agent/service/process-direct-one-shot.js +15 -10
  97. package/dist/src/agent/workflow/catalog.d.ts +1 -8
  98. package/dist/src/agent/workflow/catalog.js +44 -102
  99. package/dist/src/agent/workflow/index.d.ts +1 -1
  100. package/dist/src/agent/workflow/index.js +2 -2
  101. package/dist/src/automations/domain/types.d.ts +1 -0
  102. package/dist/src/automations/service/action-executor.js +2 -2
  103. package/dist/src/automations/service/automation-service.js +2 -2
  104. package/dist/src/channels/manager.d.ts +1 -1
  105. package/dist/src/channels/manager.js +2 -2
  106. package/dist/src/channels/outbound/persist-store.d.ts +2 -8
  107. package/dist/src/channels/outbound/persist-store.js +11 -38
  108. package/dist/src/channels/outbound-sender.d.ts +1 -1
  109. package/dist/src/channels/outbound-sender.js +2 -2
  110. package/dist/src/cli/commands/connectors.js +1 -1
  111. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  112. package/dist/src/config/schema.js +2 -2
  113. package/dist/src/connectors/auth-provider-registry.js +1 -1
  114. package/dist/src/connectors/composio-triggers.d.ts +2 -2
  115. package/dist/src/connectors/composio-triggers.js +8 -15
  116. package/dist/src/connectors/connected-source-ingestion.js +1 -1
  117. package/dist/src/connectors/health.js +1 -1
  118. package/dist/src/gateway/automation-agent-session.js +3 -0
  119. package/dist/src/gateway/heartbeat/service.js +1 -1
  120. package/dist/src/gateway/hono/lib/extension-store.js +8 -25
  121. package/dist/src/gateway/hono/routes/capabilities.js +1 -1
  122. package/dist/src/gateway/hono/routes/connectors.js +3 -3
  123. package/dist/src/gateway/hono/routes/mcp.js +1 -1
  124. package/dist/src/gateway/hono/routes/projects.js +1 -1
  125. package/dist/src/gateway/hono/routes/you.js +20 -4
  126. package/dist/src/gateway/service.js +4 -5
  127. package/dist/src/heartbeat/index.js +1 -1
  128. package/dist/src/notes/index.d.ts +1 -1
  129. package/dist/src/notes/index.js +2 -2
  130. package/dist/src/notes/paths.d.ts +0 -3
  131. package/dist/src/notes/paths.js +1 -10
  132. package/dist/src/notes/service.d.ts +0 -1
  133. package/dist/src/notes/service.js +0 -3
  134. package/dist/src/notes/store.d.ts +0 -2
  135. package/dist/src/notes/store.js +33 -80
  136. package/dist/src/share/hosted-session-share.d.ts +1 -4
  137. package/dist/src/share/hosted-session-share.js +14 -47
  138. package/dist/src/share/share-auto.d.ts +1 -1
  139. package/dist/src/share/share-auto.js +2 -2
  140. package/dist/src/share/share-store.d.ts +2 -7
  141. package/dist/src/share/share-store.js +153 -195
  142. package/dist/src/share/share-types.d.ts +0 -4
  143. package/dist/src/share/site-share-store.d.ts +3 -8
  144. package/dist/src/share/site-share-store.js +94 -153
  145. package/dist/src/share/site-share-types.d.ts +0 -4
  146. package/dist/src/storage/sqlite/connection.d.ts +1 -2
  147. package/dist/src/storage/sqlite/connection.js +50 -47
  148. package/dist/src/storage/sqlite/durable-queue.d.ts +16 -0
  149. package/dist/src/storage/sqlite/durable-queue.js +52 -0
  150. package/dist/src/storage/sqlite/durable-state.d.ts +16 -0
  151. package/dist/src/storage/sqlite/durable-state.js +43 -0
  152. package/dist/src/storage/sqlite/migrations/146_understanding_focus_exclusions.sql +9 -0
  153. package/dist/src/storage/sqlite/migrations/147_durable_application_state.sql +39 -0
  154. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  155. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  156. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  157. package/dist/src/storage/sqlite/schema.js +1 -1
  158. package/dist/src/storage/sqlite/understanding-focus-exclusions.d.ts +2 -0
  159. package/dist/src/storage/sqlite/understanding-focus-exclusions.js +24 -0
  160. package/dist/src/tui/tui-scoped-models.js +9 -6
  161. package/dist/src/tui/tui-startup-resources.js +1 -1
  162. package/dist/src/voice/dashscope/streaming-tts-stream.js +49 -0
  163. package/dist/src/voice/realtime/agentEngine.js +63 -18
  164. package/dist/src/voice/realtime/conversationTurn.d.ts +20 -0
  165. package/dist/src/voice/realtime/conversationTurn.js +83 -0
  166. package/dist/src/voice/realtime/omniEngine.js +72 -18
  167. package/dist/src/workflows/authoring/workflow-draft-store.d.ts +1 -5
  168. package/dist/src/workflows/authoring/workflow-draft-store.js +23 -43
  169. package/dist/src/workflows/index.js +2 -2
  170. package/dist/src/workflows/store/event-store.d.ts +1 -2
  171. package/dist/src/workflows/store/event-store.js +19 -64
  172. package/dist/src/workflows/store/paths.d.ts +0 -2
  173. package/dist/src/workflows/store/paths.js +1 -7
  174. package/dist/src/workflows/store/run-store.d.ts +0 -1
  175. package/dist/src/workflows/store/run-store.js +1 -24
  176. package/package.json +3 -3
  177. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-0dRjnL2s.js +0 -1
  178. package/dist/gateway/static/root/assets/apps-page-EpUZsl4h.js +0 -1
  179. package/dist/gateway/static/root/assets/automations-workspace-BGQdHrip.js +0 -6
  180. package/dist/gateway/static/root/assets/browser-settings-page-DJGcm7rH.js +0 -8
  181. package/dist/gateway/static/root/assets/channels-settings-BcIr-_GM.js +0 -1
  182. package/dist/gateway/static/root/assets/connectors-page-DNHqaZfX.js +0 -2
  183. package/dist/gateway/static/root/assets/home-page-CaVvW77l.js +0 -1
  184. package/dist/gateway/static/root/assets/index-Dbh5SXyV.css +0 -2
  185. package/dist/gateway/static/root/assets/local-app-workbench-page-D3K1XmOM.js +0 -2
  186. package/dist/gateway/static/root/assets/messages-BbdwoxVo.js +0 -3
  187. package/dist/gateway/static/root/assets/models-hub-cache-88f4fzYS.js +0 -1
  188. package/dist/gateway/static/root/assets/notes-workbench-CI30cDh3.js +0 -4
  189. package/dist/gateway/static/root/assets/project-detail-page-jO_4I5zN.js +0 -1
  190. package/dist/gateway/static/root/assets/projects-page-BrTGFME0.js +0 -1
  191. package/dist/gateway/static/root/assets/remote-access-hub-CH70D5SH.js +0 -1
  192. package/dist/gateway/static/root/assets/sessions-page-hbfUNtNs.js +0 -1
  193. package/dist/gateway/static/root/assets/settings-advanced-gate-Vg3_jua6.js +0 -1
  194. package/dist/gateway/static/root/assets/setup-status-panel-DkcpWSss.js +0 -1
  195. package/dist/gateway/static/root/assets/shares-settings-BL4DEt6p.js +0 -1
  196. package/dist/gateway/static/root/assets/skill-reload-api-CafhNktn.js +0 -1
  197. package/dist/gateway/static/root/assets/task-detail-page-anyomXsu.js +0 -1
  198. package/dist/gateway/static/root/assets/user-context-page-BBk9YdBn.js +0 -1
  199. package/dist/gateway/static/root/assets/workflows-page-RUTv0yvR.js +0 -5
@@ -1,32 +1,24 @@
1
1
  import { resolveStateDir } from "../config/paths-state.js";
2
2
  import { createLogger } from "../utils/logger/index.js";
3
3
  import { init_logger } from "../utils/logger.js";
4
+ import { requireXopcDatabase } from "../storage/sqlite/connection.js";
5
+ import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
4
6
  import { init_paths } from "../config/paths.js";
7
+ import { DurableState } from "../storage/sqlite/durable-state.js";
5
8
  import { SHARE_CONFIG_DEFAULTS } from "./share-types.js";
6
9
  import { isPathUnderWorkspace } from "../gateway/workspace-editor-path.js";
7
10
  import { logShareAudit } from "./share-audit.js";
8
11
  import { join, relative, resolve } from "node:path";
9
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
10
12
  import { randomBytes, randomUUID } from "node:crypto";
11
13
  import { lstat, readdir, realpath, rm, stat } from "node:fs/promises";
12
14
  //#region src/share/share-store.ts
13
15
  init_paths();
14
16
  init_logger();
15
17
  const log = createLogger("ShareStore");
16
- const SHARES_FILE = "shares.json";
17
18
  const CLEANUP_INTERVAL_MS = 10 * 6e4;
18
19
  const EXPIRED_RETENTION_MS = 1440 * 6e4;
19
- const MAX_STORED_RECORDS = 500;
20
- const TRUNCATE_TO = 200;
21
- const COUNTER_DEBOUNCE_MS = 2e3;
22
- function resolveSharesPath() {
23
- return join(resolveStateDir(), SHARES_FILE);
24
- }
25
20
  var ShareStore = class {
26
- shares = /* @__PURE__ */ new Map();
27
- tokenIndex = /* @__PURE__ */ new Map();
28
- dirty = false;
29
- debounceTimer = null;
21
+ shares = new DurableState("shares");
30
22
  cleanupTimer = null;
31
23
  config;
32
24
  listingCache = /* @__PURE__ */ new Map();
@@ -37,9 +29,15 @@ var ShareStore = class {
37
29
  ...SHARE_CONFIG_DEFAULTS,
38
30
  ...config
39
31
  };
40
- this.load();
41
32
  this.startCleanupTimer();
42
33
  }
34
+ saveNew(record) {
35
+ requireXopcDatabase();
36
+ runSqliteWriteTransaction(() => {
37
+ if (this.getActiveShares().length >= this.config.maxActiveShares) throw new Error("Maximum active shares reached");
38
+ this.shares.set(record.id, record);
39
+ });
40
+ }
43
41
  updateConfig(config) {
44
42
  this.config = {
45
43
  ...this.config,
@@ -193,8 +191,7 @@ var ShareStore = class {
193
191
  ...common,
194
192
  kind: "file"
195
193
  };
196
- this.shares.set(id, record);
197
- this.tokenIndex.set(token, id);
194
+ this.saveNew(record);
198
195
  return record;
199
196
  }
200
197
  createNoteShare(input) {
@@ -226,8 +223,7 @@ var ShareStore = class {
226
223
  createdByTokenHash: input.gatewayTokenHash,
227
224
  description: input.description
228
225
  };
229
- this.shares.set(record.id, record);
230
- this.tokenIndex.set(record.token, record.id);
226
+ this.saveNew(record);
231
227
  this.persistAndAudit(record, "share.create", `Note share created: ${record.fileName}`, {
232
228
  noteId: record.sourceNoteId,
233
229
  sourceVersion: record.sourceVersion,
@@ -237,20 +233,23 @@ var ShareStore = class {
237
233
  return record;
238
234
  }
239
235
  updateNoteSnapshot(id, patch) {
240
- const record = this.shares.get(id);
241
- if (!record || record.kind !== "note") return null;
242
- record.sourceVersion = patch.sourceVersion;
243
- record.fileSize = patch.artifactSize;
244
- record.attachmentCount = patch.attachmentCount;
245
- record.fileName = patch.fileName;
246
- record.snapshotRevision += 1;
247
- this.persistSync();
248
- logShareAudit("share.update", {
249
- shareId: id,
250
- noteId: record.sourceNoteId,
251
- snapshotRevision: record.snapshotRevision
252
- }, `Note share snapshot updated: ${record.fileName}`);
253
- return record;
236
+ requireXopcDatabase();
237
+ return runSqliteWriteTransaction(() => {
238
+ const record = this.shares.get(id);
239
+ if (!record || record.kind !== "note") return null;
240
+ record.sourceVersion = patch.sourceVersion;
241
+ record.fileSize = patch.artifactSize;
242
+ record.attachmentCount = patch.attachmentCount;
243
+ record.fileName = patch.fileName;
244
+ record.snapshotRevision += 1;
245
+ this.shares.set(record.id, record);
246
+ logShareAudit("share.update", {
247
+ shareId: id,
248
+ noteId: record.sourceNoteId,
249
+ snapshotRevision: record.snapshotRevision
250
+ }, `Note share snapshot updated: ${record.fileName}`);
251
+ return record;
252
+ });
254
253
  }
255
254
  getNoteShares(noteId) {
256
255
  return this.getAllShares().filter((record) => record.kind === "note" && record.sourceNoteId === noteId);
@@ -286,8 +285,7 @@ var ShareStore = class {
286
285
  createdByTokenHash: input.gatewayTokenHash,
287
286
  description: input.description
288
287
  };
289
- this.shares.set(record.id, record);
290
- this.tokenIndex.set(record.token, record.id);
288
+ this.saveNew(record);
291
289
  this.persistAndAudit(record, "share.create", `Session share created: ${record.fileName}`, {
292
290
  sourceSessionId: record.sourceSessionId,
293
291
  cutoffSeq: record.cutoffSeq,
@@ -300,26 +298,29 @@ var ShareStore = class {
300
298
  return this.getAllShares().filter((record) => record.kind === "session" && record.sourceSessionId === sessionId);
301
299
  }
302
300
  updateSessionSnapshot(id, patch) {
303
- const record = this.shares.get(id);
304
- if (!record || record.kind !== "session") return null;
305
- record.cutoffSeq = patch.cutoffSeq;
306
- record.fileSize = patch.artifactSize;
307
- record.messageCount = patch.messageCount;
308
- record.attachmentCount = patch.attachmentCount;
309
- record.includeToolActivities = patch.includeToolActivities;
310
- record.fileName = patch.fileName;
311
- record.snapshotRevision += 1;
312
- this.persistSync();
313
- logShareAudit("share.update", {
314
- shareId: id,
315
- sourceSessionId: record.sourceSessionId,
316
- cutoffSeq: record.cutoffSeq,
317
- snapshotRevision: record.snapshotRevision
318
- }, `Session share snapshot updated: ${record.fileName}`);
319
- return record;
301
+ requireXopcDatabase();
302
+ return runSqliteWriteTransaction(() => {
303
+ const record = this.shares.get(id);
304
+ if (!record || record.kind !== "session") return null;
305
+ record.cutoffSeq = patch.cutoffSeq;
306
+ record.fileSize = patch.artifactSize;
307
+ record.messageCount = patch.messageCount;
308
+ record.attachmentCount = patch.attachmentCount;
309
+ record.includeToolActivities = patch.includeToolActivities;
310
+ record.fileName = patch.fileName;
311
+ record.snapshotRevision += 1;
312
+ this.shares.set(record.id, record);
313
+ logShareAudit("share.update", {
314
+ shareId: id,
315
+ sourceSessionId: record.sourceSessionId,
316
+ cutoffSeq: record.cutoffSeq,
317
+ snapshotRevision: record.snapshotRevision
318
+ }, `Session share snapshot updated: ${record.fileName}`);
319
+ return record;
320
+ });
320
321
  }
321
322
  persistAndAudit(record, event, message, extra) {
322
- this.persistSync();
323
+ this.shares.set(record.id, record);
323
324
  logShareAudit(event, {
324
325
  shareId: record.id,
325
326
  tokenPrefix: record.token.slice(0, 8),
@@ -330,9 +331,7 @@ var ShareStore = class {
330
331
  return this.shares.get(id) ?? null;
331
332
  }
332
333
  getByToken(token) {
333
- const id = this.tokenIndex.get(token);
334
- if (!id) return null;
335
- return this.shares.get(id) ?? null;
334
+ return this.shares.values().find((record) => record.token === token) ?? null;
336
335
  }
337
336
  /** Validate a share is still accessible for download. Returns null reason if valid. */
338
337
  validateAccess(record) {
@@ -350,28 +349,40 @@ var ShareStore = class {
350
349
  };
351
350
  return { valid: true };
352
351
  }
353
- /** Increment download counter (used by directory & file downloads). Debounced persist. */
352
+ /** Increment download counter (used by directory & file downloads). Persisted before returning. */
354
353
  incrementDownloadCount(id) {
355
- const record = this.shares.get(id);
356
- if (!record) return;
357
- record.downloadCount++;
358
- this.scheduleDebouncedPersist();
354
+ this.shares.update(id, (record) => {
355
+ if (record) record.downloadCount++;
356
+ return {
357
+ value: record,
358
+ result: void 0
359
+ };
360
+ });
359
361
  }
360
362
  /** Atomically validate and consume one access in the single-threaded store. */
361
363
  consumeAccess(id) {
362
- const record = this.shares.get(id);
363
- if (!record) return {
364
- valid: false,
365
- reason: "not_found"
366
- };
367
- const validation = this.validateAccess(record);
368
- if (!validation.valid) return {
369
- valid: false,
370
- reason: validation.reason ?? "access_denied"
371
- };
372
- record.downloadCount++;
373
- this.scheduleDebouncedPersist();
374
- return { valid: true };
364
+ return this.shares.update(id, (record) => {
365
+ if (!record) return {
366
+ value: void 0,
367
+ result: {
368
+ valid: false,
369
+ reason: "not_found"
370
+ }
371
+ };
372
+ const validation = this.validateAccess(record);
373
+ if (!validation.valid) return {
374
+ value: record,
375
+ result: {
376
+ valid: false,
377
+ reason: validation.reason ?? "access_denied"
378
+ }
379
+ };
380
+ record.downloadCount++;
381
+ return {
382
+ value: record,
383
+ result: { valid: true }
384
+ };
385
+ });
375
386
  }
376
387
  /** Check if the file still exists and inode matches. */
377
388
  async validateFileIntegrity(record) {
@@ -504,74 +515,89 @@ var ShareStore = class {
504
515
  }
505
516
  /** Update thumbnail status. Persists immediately so generator restart is safe. */
506
517
  setThumbnailStatus(id, status) {
507
- const record = this.shares.get(id);
508
- if (!record) return;
509
- record.thumbnailStatus = status;
510
- if (status === "ready") record.thumbnailGeneratedAt = (/* @__PURE__ */ new Date()).toISOString();
511
- if (status === "failed") record.thumbnailFailedAt = (/* @__PURE__ */ new Date()).toISOString();
512
- this.persistSync();
518
+ requireXopcDatabase();
519
+ return runSqliteWriteTransaction(() => {
520
+ const record = this.shares.get(id);
521
+ if (!record) return;
522
+ record.thumbnailStatus = status;
523
+ if (status === "ready") record.thumbnailGeneratedAt = (/* @__PURE__ */ new Date()).toISOString();
524
+ if (status === "failed") record.thumbnailFailedAt = (/* @__PURE__ */ new Date()).toISOString();
525
+ this.shares.set(record.id, record);
526
+ });
513
527
  }
514
528
  /** Drop the listing cache for a share (used on revoke/update). */
515
529
  invalidateListingCache(shareId) {
516
530
  for (const key of this.listingCache.keys()) if (key.startsWith(`${shareId}::`)) this.listingCache.delete(key);
517
531
  }
518
532
  revoke(id) {
519
- const record = this.shares.get(id);
520
- if (!record) return false;
521
- record.revoked = true;
522
- this.cleanupStateArtifact(record);
523
- this.invalidateListingCache(id);
524
- this.persistSync();
525
- logShareAudit("share.revoke", {
526
- shareId: id,
527
- tokenPrefix: record.token.slice(0, 8),
528
- fileName: record.fileName
529
- }, `Share revoked: ${record.fileName}`);
530
- return true;
533
+ requireXopcDatabase();
534
+ return runSqliteWriteTransaction(() => {
535
+ const record = this.shares.get(id);
536
+ if (!record) return false;
537
+ record.revoked = true;
538
+ this.cleanupStateArtifact(record);
539
+ this.invalidateListingCache(id);
540
+ this.shares.set(record.id, record);
541
+ logShareAudit("share.revoke", {
542
+ shareId: id,
543
+ tokenPrefix: record.token.slice(0, 8),
544
+ fileName: record.fileName
545
+ }, `Share revoked: ${record.fileName}`);
546
+ return true;
547
+ });
531
548
  }
532
549
  revokeMany(ids) {
533
- let count = 0;
534
- for (const id of ids) {
535
- const record = this.shares.get(id);
536
- if (record && !record.revoked) {
550
+ requireXopcDatabase();
551
+ return runSqliteWriteTransaction(() => {
552
+ let count = 0;
553
+ for (const id of ids) {
554
+ const record = this.shares.get(id);
555
+ if (record && !record.revoked) {
556
+ record.revoked = true;
557
+ this.shares.set(record.id, record);
558
+ this.cleanupStateArtifact(record);
559
+ this.invalidateListingCache(id);
560
+ count++;
561
+ logShareAudit("share.revoke", {
562
+ shareId: id,
563
+ tokenPrefix: record.token.slice(0, 8),
564
+ fileName: record.fileName
565
+ }, `Share revoked (batch): ${record.fileName}`);
566
+ }
567
+ }
568
+ return count;
569
+ });
570
+ }
571
+ revokeExpired() {
572
+ requireXopcDatabase();
573
+ return runSqliteWriteTransaction(() => {
574
+ const now = Date.now();
575
+ let count = 0;
576
+ for (const record of this.shares.values()) if (!record.revoked && now >= new Date(record.expiresAt).getTime()) {
537
577
  record.revoked = true;
578
+ this.shares.set(record.id, record);
538
579
  this.cleanupStateArtifact(record);
539
- this.invalidateListingCache(id);
580
+ this.invalidateListingCache(record.id);
540
581
  count++;
541
- logShareAudit("share.revoke", {
542
- shareId: id,
543
- tokenPrefix: record.token.slice(0, 8),
544
- fileName: record.fileName
545
- }, `Share revoked (batch): ${record.fileName}`);
546
582
  }
547
- }
548
- if (count > 0) this.persistSync();
549
- return count;
550
- }
551
- revokeExpired() {
552
- const now = Date.now();
553
- let count = 0;
554
- for (const record of this.shares.values()) if (!record.revoked && now >= new Date(record.expiresAt).getTime()) {
555
- record.revoked = true;
556
- this.cleanupStateArtifact(record);
557
- this.invalidateListingCache(record.id);
558
- count++;
559
- }
560
- if (count > 0) this.persistSync();
561
- return count;
583
+ return count;
584
+ });
562
585
  }
563
586
  update(id, patch) {
564
- const record = this.shares.get(id);
565
- if (!record) return null;
566
- if (patch.extendTtlMs !== void 0) record.expiresAt = new Date(Date.now() + patch.extendTtlMs).toISOString();
567
- if (patch.maxViews !== void 0) record.maxViews = patch.maxViews;
568
- this.persistSync();
569
- logShareAudit("share.update", {
570
- shareId: id,
571
- tokenPrefix: record.token.slice(0, 8),
572
- patch
573
- }, `Share updated: ${record.fileName}`);
574
- return record;
587
+ requireXopcDatabase();
588
+ return runSqliteWriteTransaction(() => {
589
+ const record = this.shares.get(id);
590
+ if (!record) return null;
591
+ if (patch.extendTtlMs !== void 0) record.expiresAt = new Date(Date.now() + patch.extendTtlMs).toISOString();
592
+ if (patch.maxViews !== void 0) record.maxViews = patch.maxViews;
593
+ this.shares.set(record.id, record);
594
+ logShareAudit("share.update", {
595
+ shareId: id,
596
+ tokenPrefix: record.token.slice(0, 8),
597
+ patch
598
+ }, `Share updated: ${record.fileName}`);
599
+ return record;
600
+ });
575
601
  }
576
602
  getActiveShares() {
577
603
  const now = Date.now();
@@ -580,62 +606,6 @@ var ShareStore = class {
580
606
  getAllShares() {
581
607
  return [...this.shares.values()].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
582
608
  }
583
- load() {
584
- const path = resolveSharesPath();
585
- if (!existsSync(path)) return;
586
- try {
587
- const raw = readFileSync(path, "utf8");
588
- const data = JSON.parse(raw);
589
- if (data.version !== 1 && data.version !== 2 || !Array.isArray(data.shares)) return;
590
- const now = Date.now();
591
- let cleaned = 0;
592
- for (const record of data.shares) {
593
- if (now - new Date(record.expiresAt).getTime() > EXPIRED_RETENTION_MS) {
594
- cleaned++;
595
- continue;
596
- }
597
- this.shares.set(record.id, record);
598
- this.tokenIndex.set(record.token, record.id);
599
- }
600
- if (cleaned > 0) {
601
- log.info({ cleaned }, `Cleaned ${cleaned} expired share records on load`);
602
- this.persistSync();
603
- }
604
- } catch (err) {
605
- log.warn({ err }, "Failed to load shares.json");
606
- }
607
- }
608
- persistSync() {
609
- const path = resolveSharesPath();
610
- mkdirSync(resolveStateDir(), { recursive: true });
611
- let records = [...this.shares.values()];
612
- if (records.length > MAX_STORED_RECORDS) {
613
- records.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
614
- records = records.filter((r) => !r.revoked && Date.now() < new Date(r.expiresAt).getTime()).slice(0, TRUNCATE_TO);
615
- this.shares.clear();
616
- this.tokenIndex.clear();
617
- for (const r of records) {
618
- this.shares.set(r.id, r);
619
- this.tokenIndex.set(r.token, r.id);
620
- }
621
- }
622
- writeFileSync(path, `${JSON.stringify({
623
- version: 2,
624
- shares: records
625
- }, null, 2)}\n`, "utf8");
626
- }
627
- scheduleDebouncedPersist() {
628
- this.dirty = true;
629
- if (this.debounceTimer) return;
630
- this.debounceTimer = setTimeout(() => {
631
- this.debounceTimer = null;
632
- if (this.dirty) {
633
- this.dirty = false;
634
- this.persistSync();
635
- }
636
- }, COUNTER_DEBOUNCE_MS);
637
- this.debounceTimer.unref?.();
638
- }
639
609
  startCleanupTimer() {
640
610
  this.cleanupTimer = setInterval(() => {
641
611
  this.cleanupExpired();
@@ -650,7 +620,6 @@ var ShareStore = class {
650
620
  if (expiredMs >= 0) this.cleanupStateArtifact(record);
651
621
  if (expiredMs > EXPIRED_RETENTION_MS) {
652
622
  this.shares.delete(id);
653
- this.tokenIndex.delete(record.token);
654
623
  this.invalidateListingCache(id);
655
624
  if (this.onCleanup) try {
656
625
  this.onCleanup(record);
@@ -663,24 +632,13 @@ var ShareStore = class {
663
632
  removed++;
664
633
  }
665
634
  }
666
- if (removed > 0) {
667
- this.persistSync();
668
- log.debug({ removed }, `Cleaned ${removed} expired shares`);
669
- }
635
+ if (removed > 0) log.debug({ removed }, `Cleaned ${removed} expired shares`);
670
636
  }
671
637
  shutdown() {
672
638
  if (this.cleanupTimer) {
673
639
  clearInterval(this.cleanupTimer);
674
640
  this.cleanupTimer = null;
675
641
  }
676
- if (this.debounceTimer) {
677
- clearTimeout(this.debounceTimer);
678
- this.debounceTimer = null;
679
- }
680
- if (this.dirty) {
681
- this.dirty = false;
682
- this.persistSync();
683
- }
684
642
  this.listingCache.clear();
685
643
  }
686
644
  async resolveAndValidatePath(relPath, workspaceRoot) {
@@ -126,10 +126,6 @@ export interface CreateShareParams {
126
126
  /** Directory: walk depth cap (default 20). */
127
127
  maxDepth?: number;
128
128
  }
129
- export interface ShareStoreData {
130
- version: 1 | 2;
131
- shares: ShareRecord[];
132
- }
133
129
  export type ShareReachability = 'public' | 'lan' | 'local-only';
134
130
  export interface ResolvedShareUrl {
135
131
  shareUrl: string;
@@ -1,15 +1,12 @@
1
1
  import { type CreateSiteShareParams, type SiteShareConfig, type SiteShareRecord } from './site-share-types.js';
2
2
  export declare class SiteShareStore {
3
3
  private shares;
4
- private byToken;
5
- private bySubdomain;
6
4
  private config;
7
- private dirty;
8
- private debounceTimer;
9
5
  private cleanupTimer;
10
6
  /** Optional cleanup hook invoked when a record is dropped (e.g. delete staging dir). */
11
7
  private onCleanup;
12
8
  constructor(config?: Partial<SiteShareConfig>);
9
+ private saveNew;
13
10
  updateConfig(config: Partial<SiteShareConfig>): void;
14
11
  setCleanupHook(hook: (record: SiteShareRecord) => void): void;
15
12
  getConfig(): SiteShareConfig;
@@ -33,7 +30,7 @@ export declare class SiteShareStore {
33
30
  valid: boolean;
34
31
  reason?: string;
35
32
  };
36
- /** Increment counters when a request lands. Debounced persist. */
33
+ /** Increment counters when a request lands. Persisted before returning. */
37
34
  recordRequest(id: string, clientIp: string): void;
38
35
  setThumbnailStatus(id: string, status: 'pending' | 'ready' | 'failed'): void;
39
36
  revoke(id: string): boolean;
@@ -43,9 +40,7 @@ export declare class SiteShareStore {
43
40
  extendTtlMs?: number;
44
41
  maxRequests?: number | null;
45
42
  }): SiteShareRecord | null;
46
- private load;
47
- private persistSync;
48
- private scheduleDebouncedPersist;
43
+ private hasSubdomain;
49
44
  private startCleanupTimer;
50
45
  shutdown(): void;
51
46
  }