@jbctechsolutions/mcp-office365 2.5.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. package/README.md +66 -57
  2. package/dist/approval/hash.d.ts +8 -8
  3. package/dist/approval/token-manager.d.ts +37 -19
  4. package/dist/approval/token-manager.d.ts.map +1 -1
  5. package/dist/approval/token-manager.js +133 -37
  6. package/dist/approval/token-manager.js.map +1 -1
  7. package/dist/approval/types.d.ts +7 -3
  8. package/dist/approval/types.d.ts.map +1 -1
  9. package/dist/cli.d.ts +21 -0
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +100 -2
  12. package/dist/cli.js.map +1 -1
  13. package/dist/database/repository.d.ts +48 -48
  14. package/dist/database/repository.d.ts.map +1 -1
  15. package/dist/database/repository.js.map +1 -1
  16. package/dist/delta/mirror.d.ts +67 -0
  17. package/dist/delta/mirror.d.ts.map +1 -0
  18. package/dist/delta/mirror.js +183 -0
  19. package/dist/delta/mirror.js.map +1 -0
  20. package/dist/graph/auth/account-id.d.ts +19 -0
  21. package/dist/graph/auth/account-id.d.ts.map +1 -0
  22. package/dist/graph/auth/account-id.js +55 -0
  23. package/dist/graph/auth/account-id.js.map +1 -0
  24. package/dist/graph/auth/config.d.ts +1 -1
  25. package/dist/graph/auth/config.d.ts.map +1 -1
  26. package/dist/graph/auth/config.js +13 -1
  27. package/dist/graph/auth/config.js.map +1 -1
  28. package/dist/graph/auth/device-code-flow.d.ts +3 -1
  29. package/dist/graph/auth/device-code-flow.d.ts.map +1 -1
  30. package/dist/graph/auth/device-code-flow.js +42 -14
  31. package/dist/graph/auth/device-code-flow.js.map +1 -1
  32. package/dist/graph/auth/index.d.ts +1 -0
  33. package/dist/graph/auth/index.d.ts.map +1 -1
  34. package/dist/graph/auth/index.js +1 -0
  35. package/dist/graph/auth/index.js.map +1 -1
  36. package/dist/graph/auth/token-cache.js +2 -2
  37. package/dist/graph/auth/token-cache.js.map +1 -1
  38. package/dist/graph/client/graph-client.d.ts +141 -8
  39. package/dist/graph/client/graph-client.d.ts.map +1 -1
  40. package/dist/graph/client/graph-client.js +536 -48
  41. package/dist/graph/client/graph-client.js.map +1 -1
  42. package/dist/graph/client/immutable-id-middleware.d.ts +50 -0
  43. package/dist/graph/client/immutable-id-middleware.d.ts.map +1 -0
  44. package/dist/graph/client/immutable-id-middleware.js +137 -0
  45. package/dist/graph/client/immutable-id-middleware.js.map +1 -0
  46. package/dist/graph/content-readers.d.ts +0 -12
  47. package/dist/graph/content-readers.d.ts.map +1 -1
  48. package/dist/graph/content-readers.js +0 -21
  49. package/dist/graph/content-readers.js.map +1 -1
  50. package/dist/graph/index.d.ts +5 -6
  51. package/dist/graph/index.d.ts.map +1 -1
  52. package/dist/graph/index.js +5 -6
  53. package/dist/graph/index.js.map +1 -1
  54. package/dist/graph/mailbox-adapter.d.ts +15 -15
  55. package/dist/graph/mappers/contact-mapper.d.ts +4 -1
  56. package/dist/graph/mappers/contact-mapper.d.ts.map +1 -1
  57. package/dist/graph/mappers/contact-mapper.js +7 -3
  58. package/dist/graph/mappers/contact-mapper.js.map +1 -1
  59. package/dist/graph/mappers/email-mapper.d.ts.map +1 -1
  60. package/dist/graph/mappers/email-mapper.js +7 -4
  61. package/dist/graph/mappers/email-mapper.js.map +1 -1
  62. package/dist/graph/mappers/event-mapper.d.ts.map +1 -1
  63. package/dist/graph/mappers/event-mapper.js +6 -3
  64. package/dist/graph/mappers/event-mapper.js.map +1 -1
  65. package/dist/graph/mappers/folder-mapper.d.ts +0 -4
  66. package/dist/graph/mappers/folder-mapper.d.ts.map +1 -1
  67. package/dist/graph/mappers/folder-mapper.js +9 -19
  68. package/dist/graph/mappers/folder-mapper.js.map +1 -1
  69. package/dist/graph/mappers/index.d.ts +2 -2
  70. package/dist/graph/mappers/index.d.ts.map +1 -1
  71. package/dist/graph/mappers/index.js +2 -2
  72. package/dist/graph/mappers/index.js.map +1 -1
  73. package/dist/graph/mappers/task-mapper.d.ts +4 -2
  74. package/dist/graph/mappers/task-mapper.d.ts.map +1 -1
  75. package/dist/graph/mappers/task-mapper.js +7 -5
  76. package/dist/graph/mappers/task-mapper.js.map +1 -1
  77. package/dist/graph/mappers/utils.d.ts +0 -10
  78. package/dist/graph/mappers/utils.d.ts.map +1 -1
  79. package/dist/graph/mappers/utils.js +0 -19
  80. package/dist/graph/mappers/utils.js.map +1 -1
  81. package/dist/graph/repository.d.ts +409 -276
  82. package/dist/graph/repository.d.ts.map +1 -1
  83. package/dist/graph/repository.js +772 -1082
  84. package/dist/graph/repository.js.map +1 -1
  85. package/dist/ids/mint.d.ts +31 -0
  86. package/dist/ids/mint.d.ts.map +1 -0
  87. package/dist/ids/mint.js +36 -0
  88. package/dist/ids/mint.js.map +1 -0
  89. package/dist/ids/next-action.d.ts +29 -0
  90. package/dist/ids/next-action.d.ts.map +1 -0
  91. package/dist/ids/next-action.js +58 -0
  92. package/dist/ids/next-action.js.map +1 -0
  93. package/dist/ids/resolver.d.ts +31 -0
  94. package/dist/ids/resolver.d.ts.map +1 -0
  95. package/dist/ids/resolver.js +52 -0
  96. package/dist/ids/resolver.js.map +1 -0
  97. package/dist/ids/schema.d.ts +91 -0
  98. package/dist/ids/schema.d.ts.map +1 -0
  99. package/dist/ids/schema.js +131 -0
  100. package/dist/ids/schema.js.map +1 -0
  101. package/dist/ids/token.d.ts +62 -0
  102. package/dist/ids/token.d.ts.map +1 -0
  103. package/dist/ids/token.js +225 -0
  104. package/dist/ids/token.js.map +1 -0
  105. package/dist/index.d.ts +10 -6
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +255 -5925
  108. package/dist/index.js.map +1 -1
  109. package/dist/parsers/index.d.ts +0 -1
  110. package/dist/parsers/index.d.ts.map +1 -1
  111. package/dist/parsers/index.js +0 -1
  112. package/dist/parsers/index.js.map +1 -1
  113. package/dist/registry/all-tools.d.ts +14 -0
  114. package/dist/registry/all-tools.d.ts.map +1 -0
  115. package/dist/registry/all-tools.js +68 -0
  116. package/dist/registry/all-tools.js.map +1 -0
  117. package/dist/registry/context.d.ts +19 -0
  118. package/dist/registry/context.d.ts.map +1 -0
  119. package/dist/registry/context.js +20 -0
  120. package/dist/registry/context.js.map +1 -0
  121. package/dist/registry/define-tool.d.ts +15 -0
  122. package/dist/registry/define-tool.d.ts.map +1 -0
  123. package/dist/registry/define-tool.js +8 -0
  124. package/dist/registry/define-tool.js.map +1 -0
  125. package/dist/registry/elicit-links.d.ts +35 -0
  126. package/dist/registry/elicit-links.d.ts.map +1 -0
  127. package/dist/registry/elicit-links.js +102 -0
  128. package/dist/registry/elicit-links.js.map +1 -0
  129. package/dist/registry/elicitor.d.ts +24 -0
  130. package/dist/registry/elicitor.d.ts.map +1 -0
  131. package/dist/registry/elicitor.js +51 -0
  132. package/dist/registry/elicitor.js.map +1 -0
  133. package/dist/registry/index.d.ts +13 -0
  134. package/dist/registry/index.d.ts.map +1 -0
  135. package/dist/registry/index.js +8 -0
  136. package/dist/registry/index.js.map +1 -0
  137. package/dist/registry/registry.d.ts +73 -0
  138. package/dist/registry/registry.d.ts.map +1 -0
  139. package/dist/registry/registry.js +221 -0
  140. package/dist/registry/registry.js.map +1 -0
  141. package/dist/registry/types.d.ts +146 -0
  142. package/dist/registry/types.d.ts.map +1 -0
  143. package/dist/registry/types.js +6 -0
  144. package/dist/registry/types.js.map +1 -0
  145. package/dist/search/compiler.d.ts +49 -0
  146. package/dist/search/compiler.d.ts.map +1 -0
  147. package/dist/search/compiler.js +168 -0
  148. package/dist/search/compiler.js.map +1 -0
  149. package/dist/signature.js +2 -2
  150. package/dist/signature.js.map +1 -1
  151. package/dist/state/delta-store.d.ts +85 -0
  152. package/dist/state/delta-store.d.ts.map +1 -0
  153. package/dist/state/delta-store.js +124 -0
  154. package/dist/state/delta-store.js.map +1 -0
  155. package/dist/state/migrate.d.ts +23 -0
  156. package/dist/state/migrate.d.ts.map +1 -0
  157. package/dist/state/migrate.js +81 -0
  158. package/dist/state/migrate.js.map +1 -0
  159. package/dist/state/schema.d.ts +26 -0
  160. package/dist/state/schema.d.ts.map +1 -0
  161. package/dist/state/schema.js +77 -0
  162. package/dist/state/schema.js.map +1 -0
  163. package/dist/state/store.d.ts +155 -0
  164. package/dist/state/store.d.ts.map +1 -0
  165. package/dist/state/store.js +321 -0
  166. package/dist/state/store.js.map +1 -0
  167. package/dist/tools/calendar-graph.d.ts +41 -0
  168. package/dist/tools/calendar-graph.d.ts.map +1 -0
  169. package/dist/tools/calendar-graph.js +299 -0
  170. package/dist/tools/calendar-graph.js.map +1 -0
  171. package/dist/tools/calendar-permissions.d.ts +17 -7
  172. package/dist/tools/calendar-permissions.d.ts.map +1 -1
  173. package/dist/tools/calendar-permissions.js +60 -4
  174. package/dist/tools/calendar-permissions.js.map +1 -1
  175. package/dist/tools/calendar.d.ts +133 -82
  176. package/dist/tools/calendar.d.ts.map +1 -1
  177. package/dist/tools/calendar.js +249 -136
  178. package/dist/tools/calendar.js.map +1 -1
  179. package/dist/tools/categories.d.ts +14 -4
  180. package/dist/tools/categories.d.ts.map +1 -1
  181. package/dist/tools/categories.js +59 -2
  182. package/dist/tools/categories.js.map +1 -1
  183. package/dist/tools/checklist-items.d.ts +19 -9
  184. package/dist/tools/checklist-items.d.ts.map +1 -1
  185. package/dist/tools/checklist-items.js +71 -5
  186. package/dist/tools/checklist-items.js.map +1 -1
  187. package/dist/tools/contact-folders.d.ts +50 -0
  188. package/dist/tools/contact-folders.d.ts.map +1 -0
  189. package/dist/tools/contact-folders.js +136 -0
  190. package/dist/tools/contact-folders.js.map +1 -0
  191. package/dist/tools/contacts-graph.d.ts +45 -0
  192. package/dist/tools/contacts-graph.d.ts.map +1 -0
  193. package/dist/tools/contacts-graph.js +174 -0
  194. package/dist/tools/contacts-graph.js.map +1 -0
  195. package/dist/tools/contacts.d.ts +61 -30
  196. package/dist/tools/contacts.d.ts.map +1 -1
  197. package/dist/tools/contacts.js +150 -93
  198. package/dist/tools/contacts.js.map +1 -1
  199. package/dist/tools/excel.d.ts +20 -10
  200. package/dist/tools/excel.d.ts.map +1 -1
  201. package/dist/tools/excel.js +82 -6
  202. package/dist/tools/excel.js.map +1 -1
  203. package/dist/tools/focused-overrides.d.ts +14 -4
  204. package/dist/tools/focused-overrides.d.ts.map +1 -1
  205. package/dist/tools/focused-overrides.js +59 -2
  206. package/dist/tools/focused-overrides.js.map +1 -1
  207. package/dist/tools/index.d.ts +4 -5
  208. package/dist/tools/index.d.ts.map +1 -1
  209. package/dist/tools/index.js +4 -6
  210. package/dist/tools/index.js.map +1 -1
  211. package/dist/tools/linked-resources.d.ts +17 -7
  212. package/dist/tools/linked-resources.d.ts.map +1 -1
  213. package/dist/tools/linked-resources.js +60 -4
  214. package/dist/tools/linked-resources.js.map +1 -1
  215. package/dist/tools/mail-graph.d.ts +38 -0
  216. package/dist/tools/mail-graph.d.ts.map +1 -0
  217. package/dist/tools/mail-graph.js +187 -0
  218. package/dist/tools/mail-graph.js.map +1 -0
  219. package/dist/tools/mail-rules.d.ts +20 -8
  220. package/dist/tools/mail-rules.d.ts.map +1 -1
  221. package/dist/tools/mail-rules.js +63 -7
  222. package/dist/tools/mail-rules.js.map +1 -1
  223. package/dist/tools/mail-send.d.ts +39 -27
  224. package/dist/tools/mail-send.d.ts.map +1 -1
  225. package/dist/tools/mail-send.js +249 -24
  226. package/dist/tools/mail-send.js.map +1 -1
  227. package/dist/tools/mail.d.ts +91 -68
  228. package/dist/tools/mail.d.ts.map +1 -1
  229. package/dist/tools/mail.js +232 -243
  230. package/dist/tools/mail.js.map +1 -1
  231. package/dist/tools/mailbox-organization.d.ts +51 -34
  232. package/dist/tools/mailbox-organization.d.ts.map +1 -1
  233. package/dist/tools/mailbox-organization.js +318 -35
  234. package/dist/tools/mailbox-organization.js.map +1 -1
  235. package/dist/tools/mailbox-settings.d.ts +59 -0
  236. package/dist/tools/mailbox-settings.d.ts.map +1 -0
  237. package/dist/tools/mailbox-settings.js +136 -0
  238. package/dist/tools/mailbox-settings.js.map +1 -0
  239. package/dist/tools/meetings.d.ts +24 -14
  240. package/dist/tools/meetings.d.ts.map +1 -1
  241. package/dist/tools/meetings.js +82 -6
  242. package/dist/tools/meetings.js.map +1 -1
  243. package/dist/tools/onedrive.d.ts +26 -16
  244. package/dist/tools/onedrive.d.ts.map +1 -1
  245. package/dist/tools/onedrive.js +140 -11
  246. package/dist/tools/onedrive.js.map +1 -1
  247. package/dist/tools/onenote.d.ts +63 -0
  248. package/dist/tools/onenote.d.ts.map +1 -0
  249. package/dist/tools/onenote.js +221 -0
  250. package/dist/tools/onenote.js.map +1 -0
  251. package/dist/tools/people.d.ts +10 -0
  252. package/dist/tools/people.d.ts.map +1 -1
  253. package/dist/tools/people.js +94 -0
  254. package/dist/tools/people.js.map +1 -1
  255. package/dist/tools/planner-visualization.d.ts +15 -5
  256. package/dist/tools/planner-visualization.d.ts.map +1 -1
  257. package/dist/tools/planner-visualization.js +58 -4
  258. package/dist/tools/planner-visualization.js.map +1 -1
  259. package/dist/tools/planner.d.ts +69 -39
  260. package/dist/tools/planner.d.ts.map +1 -1
  261. package/dist/tools/planner.js +231 -23
  262. package/dist/tools/planner.js.map +1 -1
  263. package/dist/tools/scheduling.d.ts +12 -0
  264. package/dist/tools/scheduling.d.ts.map +1 -1
  265. package/dist/tools/scheduling.js +38 -0
  266. package/dist/tools/scheduling.js.map +1 -1
  267. package/dist/tools/shared-mailbox.d.ts +164 -0
  268. package/dist/tools/shared-mailbox.d.ts.map +1 -0
  269. package/dist/tools/shared-mailbox.js +318 -0
  270. package/dist/tools/shared-mailbox.js.map +1 -0
  271. package/dist/tools/sharepoint-lists.d.ts +131 -0
  272. package/dist/tools/sharepoint-lists.d.ts.map +1 -0
  273. package/dist/tools/sharepoint-lists.js +246 -0
  274. package/dist/tools/sharepoint-lists.js.map +1 -0
  275. package/dist/tools/sharepoint.d.ts +24 -14
  276. package/dist/tools/sharepoint.d.ts.map +1 -1
  277. package/dist/tools/sharepoint.js +85 -9
  278. package/dist/tools/sharepoint.js.map +1 -1
  279. package/dist/tools/task-attachments.d.ts +17 -7
  280. package/dist/tools/task-attachments.d.ts.map +1 -1
  281. package/dist/tools/task-attachments.js +60 -4
  282. package/dist/tools/task-attachments.js.map +1 -1
  283. package/dist/tools/task-lists.d.ts +56 -0
  284. package/dist/tools/task-lists.d.ts.map +1 -0
  285. package/dist/tools/task-lists.js +155 -0
  286. package/dist/tools/task-lists.js.map +1 -0
  287. package/dist/tools/tasks-graph.d.ts +49 -0
  288. package/dist/tools/tasks-graph.d.ts.map +1 -0
  289. package/dist/tools/tasks-graph.js +193 -0
  290. package/dist/tools/tasks-graph.js.map +1 -0
  291. package/dist/tools/tasks.d.ts +121 -29
  292. package/dist/tools/tasks.d.ts.map +1 -1
  293. package/dist/tools/tasks.js +136 -84
  294. package/dist/tools/tasks.js.map +1 -1
  295. package/dist/tools/teams.d.ts +57 -46
  296. package/dist/tools/teams.d.ts.map +1 -1
  297. package/dist/tools/teams.js +288 -26
  298. package/dist/tools/teams.js.map +1 -1
  299. package/dist/tools/what-changed.d.ts +48 -0
  300. package/dist/tools/what-changed.d.ts.map +1 -0
  301. package/dist/tools/what-changed.js +149 -0
  302. package/dist/tools/what-changed.js.map +1 -0
  303. package/dist/types/calendar.d.ts +1 -1
  304. package/dist/types/calendar.d.ts.map +1 -1
  305. package/dist/types/calendar.js.map +1 -1
  306. package/dist/types/contacts.d.ts +1 -1
  307. package/dist/types/contacts.d.ts.map +1 -1
  308. package/dist/types/contacts.js.map +1 -1
  309. package/dist/types/mail.d.ts +1 -1
  310. package/dist/types/mail.d.ts.map +1 -1
  311. package/dist/types/mail.js.map +1 -1
  312. package/dist/utils/errors.d.ts +110 -38
  313. package/dist/utils/errors.d.ts.map +1 -1
  314. package/dist/utils/errors.js +239 -56
  315. package/dist/utils/errors.js.map +1 -1
  316. package/dist/visualization/types.d.ts +4 -4
  317. package/package.json +2 -3
  318. package/dist/applescript/account-repository.d.ts +0 -30
  319. package/dist/applescript/account-repository.d.ts.map +0 -1
  320. package/dist/applescript/account-repository.js +0 -38
  321. package/dist/applescript/account-repository.js.map +0 -1
  322. package/dist/applescript/account-scripts.d.ts +0 -21
  323. package/dist/applescript/account-scripts.d.ts.map +0 -1
  324. package/dist/applescript/account-scripts.js +0 -180
  325. package/dist/applescript/account-scripts.js.map +0 -1
  326. package/dist/applescript/calendar-manager.d.ts +0 -44
  327. package/dist/applescript/calendar-manager.d.ts.map +0 -1
  328. package/dist/applescript/calendar-manager.js +0 -92
  329. package/dist/applescript/calendar-manager.js.map +0 -1
  330. package/dist/applescript/calendar-writer.d.ts +0 -36
  331. package/dist/applescript/calendar-writer.d.ts.map +0 -1
  332. package/dist/applescript/calendar-writer.js +0 -94
  333. package/dist/applescript/calendar-writer.js.map +0 -1
  334. package/dist/applescript/content-readers.d.ts +0 -114
  335. package/dist/applescript/content-readers.d.ts.map +0 -1
  336. package/dist/applescript/content-readers.js +0 -328
  337. package/dist/applescript/content-readers.js.map +0 -1
  338. package/dist/applescript/executor.d.ts +0 -60
  339. package/dist/applescript/executor.d.ts.map +0 -1
  340. package/dist/applescript/executor.js +0 -173
  341. package/dist/applescript/executor.js.map +0 -1
  342. package/dist/applescript/index.d.ts +0 -20
  343. package/dist/applescript/index.d.ts.map +0 -1
  344. package/dist/applescript/index.js +0 -29
  345. package/dist/applescript/index.js.map +0 -1
  346. package/dist/applescript/mail-sender.d.ts +0 -38
  347. package/dist/applescript/mail-sender.d.ts.map +0 -1
  348. package/dist/applescript/mail-sender.js +0 -67
  349. package/dist/applescript/mail-sender.js.map +0 -1
  350. package/dist/applescript/parser.d.ts +0 -235
  351. package/dist/applescript/parser.d.ts.map +0 -1
  352. package/dist/applescript/parser.js +0 -496
  353. package/dist/applescript/parser.js.map +0 -1
  354. package/dist/applescript/repository.d.ts +0 -64
  355. package/dist/applescript/repository.d.ts.map +0 -1
  356. package/dist/applescript/repository.js +0 -444
  357. package/dist/applescript/repository.js.map +0 -1
  358. package/dist/applescript/scripts.d.ts +0 -265
  359. package/dist/applescript/scripts.d.ts.map +0 -1
  360. package/dist/applescript/scripts.js +0 -1483
  361. package/dist/applescript/scripts.js.map +0 -1
  362. package/dist/parsers/olk15.d.ts +0 -87
  363. package/dist/parsers/olk15.d.ts.map +0 -1
  364. package/dist/parsers/olk15.js +0 -368
  365. package/dist/parsers/olk15.js.map +0 -1
  366. package/dist/tools/notes.d.ts +0 -74
  367. package/dist/tools/notes.d.ts.map +0 -1
  368. package/dist/tools/notes.js +0 -136
  369. package/dist/tools/notes.js.map +0 -1
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Copyright (c) 2026 JBC Tech Solutions, LLC
3
+ * Licensed under the MIT License. See LICENSE file in the project root.
4
+ */
5
+ export class DeltaStore {
6
+ db;
7
+ now;
8
+ constructor(db, now) {
9
+ this.db = db;
10
+ this.now = now;
11
+ }
12
+ /** Returns the stored delta cursor for a resource, or null when un-synced. */
13
+ getDeltaLink(accountId, resource) {
14
+ const row = this.db
15
+ .prepare('SELECT delta_link FROM delta_links WHERE account_id = ? AND resource = ?')
16
+ .get(accountId, resource);
17
+ return row?.delta_link ?? null;
18
+ }
19
+ /** Returns the cursor plus its last-sync time (for age-based re-baseline), or null. */
20
+ getCursor(accountId, resource) {
21
+ const row = this.db
22
+ .prepare('SELECT delta_link, synced_at FROM delta_links WHERE account_id = ? AND resource = ?')
23
+ .get(accountId, resource);
24
+ if (row === undefined)
25
+ return null;
26
+ return { deltaLink: row.delta_link, syncedAt: row.synced_at };
27
+ }
28
+ /** Returns the set of graph ids already mirrored for a resource. */
29
+ getSeenIds(accountId, resource) {
30
+ const rows = this.db
31
+ .prepare('SELECT graph_id FROM delta_items WHERE account_id = ? AND resource = ?')
32
+ .all(accountId, resource);
33
+ return new Set(rows.map((r) => r.graph_id));
34
+ }
35
+ /** Looks up a single mirrored item (for labelling a delete), or null. */
36
+ getItem(accountId, resource, graphId) {
37
+ const raw = this.db
38
+ .prepare('SELECT graph_id, token, summary, snapshot FROM delta_items WHERE account_id = ? AND resource = ? AND graph_id = ?')
39
+ .get(accountId, resource, graphId);
40
+ if (raw === undefined)
41
+ return null;
42
+ return { graphId: raw.graph_id, token: raw.token, summary: raw.summary, snapshot: raw.snapshot };
43
+ }
44
+ /** Number of items mirrored for a resource (baseline / status reporting). */
45
+ countItems(accountId, resource) {
46
+ const row = this.db
47
+ .prepare('SELECT COUNT(*) AS n FROM delta_items WHERE account_id = ? AND resource = ?')
48
+ .get(accountId, resource);
49
+ return row.n;
50
+ }
51
+ /**
52
+ * Applies a completed sync round atomically: refresh the cursor and apply all
53
+ * upserts/deletes in one transaction, so a crash mid-write never leaves the
54
+ * mirror ahead of (or behind) its cursor. An empty `deltaLink` clears the
55
+ * cursor row, forcing the next call to re-baseline (used when Graph returns no
56
+ * usable deltaLink).
57
+ */
58
+ commit(commit) {
59
+ const apply = this.db.transaction((c) => {
60
+ // A baseline replaces the mirror wholesale, so no stale row from a prior
61
+ // (possibly cursor-less) round can survive to inflate counts or force a
62
+ // future add to misclassify as an update.
63
+ if (c.replaceMirror === true) {
64
+ this.db.prepare('DELETE FROM delta_items WHERE account_id = ? AND resource = ?').run(c.accountId, c.resource);
65
+ }
66
+ if (c.deltaLink.length > 0) {
67
+ this.db
68
+ .prepare(`INSERT INTO delta_links (account_id, resource, delta_link, synced_at)
69
+ VALUES (@accountId, @resource, @deltaLink, @syncedAt)
70
+ ON CONFLICT(account_id, resource) DO UPDATE SET
71
+ delta_link = excluded.delta_link,
72
+ synced_at = excluded.synced_at`)
73
+ .run({ accountId: c.accountId, resource: c.resource, deltaLink: c.deltaLink, syncedAt: c.syncedAt });
74
+ }
75
+ else {
76
+ this.db
77
+ .prepare('DELETE FROM delta_links WHERE account_id = ? AND resource = ?')
78
+ .run(c.accountId, c.resource);
79
+ }
80
+ const upsert = this.db.prepare(`INSERT INTO delta_items (account_id, resource, graph_id, token, summary, snapshot, first_seen, last_changed)
81
+ VALUES (@accountId, @resource, @graphId, @token, @summary, @snapshot, @now, @now)
82
+ ON CONFLICT(account_id, resource, graph_id) DO UPDATE SET
83
+ token = excluded.token,
84
+ summary = excluded.summary,
85
+ snapshot = excluded.snapshot,
86
+ last_changed = excluded.last_changed`);
87
+ for (const item of c.upserts) {
88
+ upsert.run({
89
+ accountId: c.accountId,
90
+ resource: c.resource,
91
+ graphId: item.graphId,
92
+ token: item.token,
93
+ summary: item.summary,
94
+ snapshot: item.snapshot ?? null,
95
+ now: c.syncedAt,
96
+ });
97
+ }
98
+ const del = this.db.prepare('DELETE FROM delta_items WHERE account_id = ? AND resource = ? AND graph_id = ?');
99
+ for (const graphId of c.deletes) {
100
+ del.run(c.accountId, c.resource, graphId);
101
+ }
102
+ });
103
+ apply(commit);
104
+ }
105
+ /**
106
+ * Clears the cursor and mirror for a resource (or every resource for the
107
+ * account when `resource` is omitted), forcing a fresh baseline on the next
108
+ * sync. Local-only; never touches the user's Graph data.
109
+ */
110
+ reset(accountId, resource) {
111
+ const wipe = this.db.transaction(() => {
112
+ if (resource != null) {
113
+ this.db.prepare('DELETE FROM delta_links WHERE account_id = ? AND resource = ?').run(accountId, resource);
114
+ this.db.prepare('DELETE FROM delta_items WHERE account_id = ? AND resource = ?').run(accountId, resource);
115
+ }
116
+ else {
117
+ this.db.prepare('DELETE FROM delta_links WHERE account_id = ?').run(accountId);
118
+ this.db.prepare('DELETE FROM delta_items WHERE account_id = ?').run(accountId);
119
+ }
120
+ });
121
+ wipe();
122
+ }
123
+ }
124
+ //# sourceMappingURL=delta-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta-store.js","sourceRoot":"","sources":["../../src/state/delta-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Copyright (c) 2026 JBC Tech Solutions, LLC
3
+ * Licensed under the MIT License. See LICENSE file in the project root.
4
+ */
5
+ import type Database from 'better-sqlite3';
6
+ type DB = Database.Database;
7
+ /** Reads the applied schema version (0 when never migrated). */
8
+ export declare function getSchemaVersion(db: DB): number;
9
+ /**
10
+ * Applies pending schema migrations in order, each in its own transaction so a
11
+ * failure leaves the schema at the last good version. Running with no pending
12
+ * migrations is a no-op.
13
+ */
14
+ export declare function runMigrations(db: DB): void;
15
+ /**
16
+ * Copies a legacy `~/.outlook-mcp/tokens.json` into the new state dir exactly
17
+ * once (D15): only when the marker is unset AND the new dir has no tokens.json.
18
+ * The legacy dir is left untouched; the marker is set regardless so the check
19
+ * never repeats.
20
+ */
21
+ export declare function migrateLegacyTokens(db: DB, newDir: string, legacyDir: string): void;
22
+ export {};
23
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/state/migrate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAO3C,KAAK,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC;AAoB5B,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,CAI/C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,CAqB1C;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,IAAI,CAgBN"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Copyright (c) 2026 JBC Tech Solutions, LLC
3
+ * Licensed under the MIT License. See LICENSE file in the project root.
4
+ */
5
+ /**
6
+ * Boot-time migrations for the durable state store (U4):
7
+ * - Schema migrations applied in order, tracked via the `meta` table (idempotent).
8
+ * - One-shot legacy token copy from `~/.outlook-mcp` (D15), never overwriting an
9
+ * existing token cache, gated by a `meta` marker so it runs at most once.
10
+ */
11
+ import { chmodSync, copyFileSync, existsSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ import { MIGRATIONS, META_SCHEMA_VERSION, META_LEGACY_TOKENS_MIGRATED, } from './schema.js';
14
+ /** Creates the meta table if absent (needed before reading the schema version). */
15
+ function ensureMetaTable(db) {
16
+ db.exec('CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);');
17
+ }
18
+ function getMeta(db, key) {
19
+ const row = db.prepare('SELECT value FROM meta WHERE key = ?').get(key);
20
+ return row?.value ?? null;
21
+ }
22
+ function setMeta(db, key, value) {
23
+ db.prepare('INSERT INTO meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value').run(key, value);
24
+ }
25
+ /** Reads the applied schema version (0 when never migrated). */
26
+ export function getSchemaVersion(db) {
27
+ const raw = getMeta(db, META_SCHEMA_VERSION);
28
+ const parsed = raw != null ? Number.parseInt(raw, 10) : 0;
29
+ return Number.isFinite(parsed) ? parsed : 0;
30
+ }
31
+ /**
32
+ * Applies pending schema migrations in order, each in its own transaction so a
33
+ * failure leaves the schema at the last good version. Running with no pending
34
+ * migrations is a no-op.
35
+ */
36
+ export function runMigrations(db) {
37
+ ensureMetaTable(db);
38
+ let current = getSchemaVersion(db);
39
+ // Downgrade guard: a db migrated by a newer build (version beyond this build's
40
+ // migration count) must not be operated on blindly against an unknown schema.
41
+ // Throwing here routes the caller to its degraded in-memory fallback.
42
+ if (current > MIGRATIONS.length) {
43
+ throw new Error(`state.db schema version ${current} is newer than this build supports (${MIGRATIONS.length}).`);
44
+ }
45
+ while (current < MIGRATIONS.length) {
46
+ const sql = MIGRATIONS[current];
47
+ if (sql == null)
48
+ break;
49
+ const apply = db.transaction((migrationSql, next) => {
50
+ db.exec(migrationSql);
51
+ setMeta(db, META_SCHEMA_VERSION, String(next));
52
+ });
53
+ apply(sql, current + 1);
54
+ current += 1;
55
+ }
56
+ }
57
+ /**
58
+ * Copies a legacy `~/.outlook-mcp/tokens.json` into the new state dir exactly
59
+ * once (D15): only when the marker is unset AND the new dir has no tokens.json.
60
+ * The legacy dir is left untouched; the marker is set regardless so the check
61
+ * never repeats.
62
+ */
63
+ export function migrateLegacyTokens(db, newDir, legacyDir) {
64
+ if (getMeta(db, META_LEGACY_TOKENS_MIGRATED) === '1') {
65
+ return;
66
+ }
67
+ const newTokens = join(newDir, 'tokens.json');
68
+ const legacyTokens = join(legacyDir, 'tokens.json');
69
+ if (!existsSync(newTokens) && existsSync(legacyTokens)) {
70
+ copyFileSync(legacyTokens, newTokens);
71
+ // The copied cache holds OAuth material — restrict it like state.db (D18).
72
+ try {
73
+ chmodSync(newTokens, 0o600);
74
+ }
75
+ catch {
76
+ // Best-effort; non-POSIX filesystems ignore modes.
77
+ }
78
+ }
79
+ setMeta(db, META_LEGACY_TOKENS_MIGRATED, '1');
80
+ }
81
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/state/migrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Copyright (c) 2026 JBC Tech Solutions, LLC
3
+ * Licensed under the MIT License. See LICENSE file in the project root.
4
+ */
5
+ /**
6
+ * SQLite schema for the durable state store (U4). Each entry in {@link MIGRATIONS}
7
+ * moves the schema forward by one version; the applied version is tracked in the
8
+ * `meta` table so boot migration is idempotent and ordered.
9
+ *
10
+ * Tables (D3/D7/D8):
11
+ * - `aliases` — durable-ID token → Graph ID map (composite/mutable IDs).
12
+ * - `approval_tokens` — two-phase approval tokens + redemption receipts.
13
+ * - `meta` — schema version + one-shot migration markers.
14
+ * - `delta_links` — per-resource Graph delta cursors (U12 mirror).
15
+ * - `delta_items` — local mirror of seen items, to classify add/update/delete.
16
+ */
17
+ /** Ordered forward migrations. Index i migrates schema version i → i+1. */
18
+ export declare const MIGRATIONS: readonly string[];
19
+ /** The schema version this build expects (equals the migration count). */
20
+ export declare const SCHEMA_VERSION: number;
21
+ /** meta keys. */
22
+ export declare const META_SCHEMA_VERSION = "schema_version";
23
+ export declare const META_LEGACY_TOKENS_MIGRATED = "legacy_tokens_migrated";
24
+ /** Retention window for redeemed/expired approval tokens (D8): 90 days. */
25
+ export declare const APPROVAL_RETENTION_MS: number;
26
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/state/schema.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;GAWG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAmDvC,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,cAAc,QAAoB,CAAC;AAEhD,iBAAiB;AACjB,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AACpD,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AAEpE,2EAA2E;AAC3E,eAAO,MAAM,qBAAqB,QAA2B,CAAC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Copyright (c) 2026 JBC Tech Solutions, LLC
3
+ * Licensed under the MIT License. See LICENSE file in the project root.
4
+ */
5
+ /**
6
+ * SQLite schema for the durable state store (U4). Each entry in {@link MIGRATIONS}
7
+ * moves the schema forward by one version; the applied version is tracked in the
8
+ * `meta` table so boot migration is idempotent and ordered.
9
+ *
10
+ * Tables (D3/D7/D8):
11
+ * - `aliases` — durable-ID token → Graph ID map (composite/mutable IDs).
12
+ * - `approval_tokens` — two-phase approval tokens + redemption receipts.
13
+ * - `meta` — schema version + one-shot migration markers.
14
+ * - `delta_links` — per-resource Graph delta cursors (U12 mirror).
15
+ * - `delta_items` — local mirror of seen items, to classify add/update/delete.
16
+ */
17
+ /** Ordered forward migrations. Index i migrates schema version i → i+1. */
18
+ export const MIGRATIONS = [
19
+ // v0 → v1: initial durable-state schema.
20
+ `
21
+ CREATE TABLE IF NOT EXISTS aliases (
22
+ token TEXT PRIMARY KEY,
23
+ graph_id TEXT NOT NULL,
24
+ entity_type TEXT NOT NULL,
25
+ account_id TEXT NOT NULL,
26
+ mutable INTEGER NOT NULL DEFAULT 0,
27
+ created_at INTEGER NOT NULL
28
+ );
29
+
30
+ CREATE TABLE IF NOT EXISTS approval_tokens (
31
+ token TEXT PRIMARY KEY,
32
+ operation_key TEXT UNIQUE,
33
+ action TEXT NOT NULL,
34
+ target_json TEXT NOT NULL,
35
+ content_hash TEXT,
36
+ account_id TEXT NOT NULL,
37
+ expires_at INTEGER NOT NULL,
38
+ redeemed_at INTEGER,
39
+ receipt_json TEXT,
40
+ created_at INTEGER NOT NULL
41
+ );
42
+
43
+ CREATE INDEX IF NOT EXISTS idx_approval_tokens_expires_at ON approval_tokens (expires_at);
44
+ `,
45
+ // v1 → v2: delta-sync mirror (U12). One cursor row per (account, resource),
46
+ // plus a per-item mirror so a subsequent delta round can tell an added item
47
+ // from an updated one (Graph delta reports both as a plain value entry).
48
+ `
49
+ CREATE TABLE IF NOT EXISTS delta_links (
50
+ account_id TEXT NOT NULL,
51
+ resource TEXT NOT NULL,
52
+ delta_link TEXT NOT NULL,
53
+ synced_at INTEGER NOT NULL,
54
+ PRIMARY KEY (account_id, resource)
55
+ );
56
+
57
+ CREATE TABLE IF NOT EXISTS delta_items (
58
+ account_id TEXT NOT NULL,
59
+ resource TEXT NOT NULL,
60
+ graph_id TEXT NOT NULL,
61
+ token TEXT NOT NULL,
62
+ summary TEXT NOT NULL DEFAULT '',
63
+ snapshot TEXT,
64
+ first_seen INTEGER NOT NULL,
65
+ last_changed INTEGER NOT NULL,
66
+ PRIMARY KEY (account_id, resource, graph_id)
67
+ );
68
+ `,
69
+ ];
70
+ /** The schema version this build expects (equals the migration count). */
71
+ export const SCHEMA_VERSION = MIGRATIONS.length;
72
+ /** meta keys. */
73
+ export const META_SCHEMA_VERSION = 'schema_version';
74
+ export const META_LEGACY_TOKENS_MIGRATED = 'legacy_tokens_migrated';
75
+ /** Retention window for redeemed/expired approval tokens (D8): 90 days. */
76
+ export const APPROVAL_RETENTION_MS = 90 * 24 * 60 * 60 * 1000;
77
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/state/schema.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;GAWG;AAEH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,UAAU,GAAsB;IAC3C,yCAAyC;IACzC;;;;;;;;;;;;;;;;;;;;;;;;GAwBC;IACD,4EAA4E;IAC5E,4EAA4E;IAC5E,yEAAyE;IACzE;;;;;;;;;;;;;;;;;;;;GAoBC;CACF,CAAC;AAEF,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC;AAEhD,iBAAiB;AACjB,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AACpD,MAAM,CAAC,MAAM,2BAA2B,GAAG,wBAAwB,CAAC;AAEpE,2EAA2E;AAC3E,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Copyright (c) 2026 JBC Tech Solutions, LLC
3
+ * Licensed under the MIT License. See LICENSE file in the project root.
4
+ */
5
+ import { DeltaStore } from './delta-store.js';
6
+ /** A durable-ID alias row. */
7
+ export interface AliasRow {
8
+ token: string;
9
+ graphId: string;
10
+ entityType: string;
11
+ accountId: string;
12
+ mutable: boolean;
13
+ createdAt: number;
14
+ }
15
+ /** Input for minting an alias. */
16
+ export interface AliasInput {
17
+ token: string;
18
+ graphId: string;
19
+ entityType: string;
20
+ accountId: string;
21
+ mutable?: boolean;
22
+ createdAt?: number;
23
+ }
24
+ /** Input for staging a two-phase approval token. */
25
+ export interface ApprovalTokenInput {
26
+ token: string;
27
+ operationKey?: string | null;
28
+ action: string;
29
+ targetJson: string;
30
+ contentHash?: string | null;
31
+ accountId: string;
32
+ expiresAt: number;
33
+ createdAt?: number;
34
+ }
35
+ /** A stored approval-token row (read view). */
36
+ export interface ApprovalTokenRow {
37
+ token: string;
38
+ action: string;
39
+ targetJson: string;
40
+ contentHash: string | null;
41
+ expiresAt: number;
42
+ redeemedAt: number | null;
43
+ receiptJson: string | null;
44
+ createdAt: number;
45
+ }
46
+ /** Outcome of an atomic approval-token consume. */
47
+ export type ConsumeResult = {
48
+ status: 'consumed';
49
+ receiptJson: string | null;
50
+ } | {
51
+ status: 'already_redeemed';
52
+ receiptJson: string | null;
53
+ } | {
54
+ status: 'expired';
55
+ } | {
56
+ status: 'foreign_account';
57
+ } | {
58
+ status: 'not_found';
59
+ };
60
+ /** Options for {@link StateStore.open}. */
61
+ export interface StateStoreOptions {
62
+ /** Override the state directory (defaults to `~/.mcp-office365`). */
63
+ dir?: string;
64
+ /** Override the legacy directory to migrate tokens from. */
65
+ legacyDir?: string;
66
+ /** Clock, for deterministic tests. */
67
+ now?: () => number;
68
+ /** Warning sink (defaults to stderr). */
69
+ warn?: (message: string) => void;
70
+ }
71
+ export declare class StateStore {
72
+ /** True when running from an in-memory fallback (durability degraded). */
73
+ readonly degraded: boolean;
74
+ /** The db path, or ':memory:' when degraded. */
75
+ readonly path: string;
76
+ /** Effective `journal_mode` pragma (e.g. 'wal'). */
77
+ readonly journalMode: string;
78
+ /** Effective `busy_timeout` pragma in ms. */
79
+ readonly busyTimeout: number;
80
+ /** Delta-sync mirror storage (U12), sharing this store's connection. */
81
+ readonly delta: DeltaStore;
82
+ private readonly db;
83
+ private readonly now;
84
+ private constructor();
85
+ /**
86
+ * Opens (creating if needed) the durable store. On any failure to use the
87
+ * on-disk db (corrupt/locked file, unwritable dir) it degrades to an in-memory
88
+ * store, emits a stderr warning, and reports `degraded = true` — the server
89
+ * stays usable, only durability is lost for the run.
90
+ */
91
+ static open(options?: StateStoreOptions): StateStore;
92
+ /** Inserts or replaces a durable-ID alias. */
93
+ putAlias(input: AliasInput): void;
94
+ /**
95
+ * Resolves an alias token, scoped to `accountId` (D7 account stamping). The
96
+ * account is a mandatory, fail-closed argument: a row minted under a different
97
+ * account is invisible, so no caller can accidentally resolve a foreign
98
+ * account's durable ID into a live Graph ID by omitting the scope.
99
+ */
100
+ getAlias(token: string, accountId: string): AliasRow | null;
101
+ /**
102
+ * Atomically registers an alias with D1a collision enforcement, in a single
103
+ * IMMEDIATE transaction so the check-and-write is not a read-then-write race:
104
+ * two concurrent immutable registrations of the same token cannot both pass
105
+ * the check and then clobber each other. Returns `'collision'` when a
106
+ * *different* Graph ID already occupies the token for an immutable entity
107
+ * (neither the stored nor the new row is mutable); otherwise upserts and
108
+ * returns `'ok'`.
109
+ */
110
+ registerAlias(input: AliasInput): 'ok' | 'collision';
111
+ /**
112
+ * Returns an alias row regardless of account, or null. Reserved for two
113
+ * internal uses that must see across accounts: foreign-account disambiguation
114
+ * during resolution, and collision detection at mint time (D1a). It is NOT a
115
+ * resolution path — {@link getAlias} (account-scoped) is the only one of those.
116
+ */
117
+ getAliasUnscoped(token: string): AliasRow | null;
118
+ /**
119
+ * Returns the account a token was minted under (any account), or null when the
120
+ * token is unknown. Distinguishes "foreign account" from "unknown" during
121
+ * resolution so a foreign token yields a typed ID_FOREIGN_ACCOUNT.
122
+ */
123
+ getAliasAccount(token: string): string | null;
124
+ /**
125
+ * Reads an approval token scoped to `accountId` (or null). A read view for
126
+ * validation/preview; redemption still goes through {@link consumeApprovalToken}
127
+ * so the atomic guard is never bypassed.
128
+ */
129
+ getApprovalToken(token: string, accountId: string): ApprovalTokenRow | null;
130
+ /** Stages a two-phase approval token. */
131
+ putApprovalToken(input: ApprovalTokenInput): void;
132
+ /**
133
+ * Atomically consumes an approval token (D8). The guarded `UPDATE … WHERE
134
+ * redeemed_at IS NULL AND expires_at > now RETURNING` means only one caller —
135
+ * across processes sharing the db — can win the redemption; the loser sees
136
+ * `already_redeemed` and can return the stored receipt. Expiry is enforced
137
+ * here at the trust boundary (not left to callers): an expired token that
138
+ * still authorizes a send/delete would defeat the whole point of a time-boxed
139
+ * two-phase approval. Foreign-account tokens are refused.
140
+ */
141
+ consumeApprovalToken(args: {
142
+ token: string;
143
+ accountId: string;
144
+ receiptJson?: string | null;
145
+ now?: number;
146
+ }): ConsumeResult;
147
+ /**
148
+ * Deletes approval tokens whose expiry is older than the retention window
149
+ * (D8, 90 days). Recently-expired receipts linger so idempotent redemption
150
+ * still returns them. Returns the number of rows purged.
151
+ */
152
+ purgeExpired(now: number): number;
153
+ close(): void;
154
+ }
155
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/state/store.ts"],"names":[],"mappings":"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"}