brains-mcp 1.61.2

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 (350) hide show
  1. package/README.md +95 -0
  2. package/dist/access/projectShares.d.ts +48 -0
  3. package/dist/access/projectShares.d.ts.map +1 -0
  4. package/dist/access/projectShares.js +203 -0
  5. package/dist/access/projectShares.js.map +1 -0
  6. package/dist/access/sharedInstructionsNote.d.ts +37 -0
  7. package/dist/access/sharedInstructionsNote.d.ts.map +1 -0
  8. package/dist/access/sharedInstructionsNote.js +76 -0
  9. package/dist/access/sharedInstructionsNote.js.map +1 -0
  10. package/dist/admin/seedUsers.d.ts +23 -0
  11. package/dist/admin/seedUsers.d.ts.map +1 -0
  12. package/dist/admin/seedUsers.js +168 -0
  13. package/dist/admin/seedUsers.js.map +1 -0
  14. package/dist/api/openapi.d.ts +2 -0
  15. package/dist/api/openapi.d.ts.map +1 -0
  16. package/dist/api/openapi.js +942 -0
  17. package/dist/api/openapi.js.map +1 -0
  18. package/dist/auth/clientStore.d.ts +43 -0
  19. package/dist/auth/clientStore.d.ts.map +1 -0
  20. package/dist/auth/clientStore.js +168 -0
  21. package/dist/auth/clientStore.js.map +1 -0
  22. package/dist/auth/deleteAccount.d.ts +34 -0
  23. package/dist/auth/deleteAccount.d.ts.map +1 -0
  24. package/dist/auth/deleteAccount.js +203 -0
  25. package/dist/auth/deleteAccount.js.map +1 -0
  26. package/dist/auth/oauth.d.ts +118 -0
  27. package/dist/auth/oauth.d.ts.map +1 -0
  28. package/dist/auth/oauth.js +491 -0
  29. package/dist/auth/oauth.js.map +1 -0
  30. package/dist/auth/patStore.d.ts +87 -0
  31. package/dist/auth/patStore.d.ts.map +1 -0
  32. package/dist/auth/patStore.js +308 -0
  33. package/dist/auth/patStore.js.map +1 -0
  34. package/dist/auth/supabase.d.ts +15 -0
  35. package/dist/auth/supabase.d.ts.map +1 -0
  36. package/dist/auth/supabase.js +66 -0
  37. package/dist/auth/supabase.js.map +1 -0
  38. package/dist/auth/tokenStore.d.ts +73 -0
  39. package/dist/auth/tokenStore.d.ts.map +1 -0
  40. package/dist/auth/tokenStore.js +261 -0
  41. package/dist/auth/tokenStore.js.map +1 -0
  42. package/dist/backup/drive.d.ts +24 -0
  43. package/dist/backup/drive.d.ts.map +1 -0
  44. package/dist/backup/drive.js +70 -0
  45. package/dist/backup/drive.js.map +1 -0
  46. package/dist/billing/tierStore.d.ts +59 -0
  47. package/dist/billing/tierStore.d.ts.map +1 -0
  48. package/dist/billing/tierStore.js +152 -0
  49. package/dist/billing/tierStore.js.map +1 -0
  50. package/dist/digest/activityDigest.d.ts +32 -0
  51. package/dist/digest/activityDigest.d.ts.map +1 -0
  52. package/dist/digest/activityDigest.js +299 -0
  53. package/dist/digest/activityDigest.js.map +1 -0
  54. package/dist/digest/digestCron.d.ts +40 -0
  55. package/dist/digest/digestCron.d.ts.map +1 -0
  56. package/dist/digest/digestCron.js +146 -0
  57. package/dist/digest/digestCron.js.map +1 -0
  58. package/dist/digest/digestPreferences.d.ts +25 -0
  59. package/dist/digest/digestPreferences.d.ts.map +1 -0
  60. package/dist/digest/digestPreferences.js +79 -0
  61. package/dist/digest/digestPreferences.js.map +1 -0
  62. package/dist/digest/emailSender.d.ts +20 -0
  63. package/dist/digest/emailSender.d.ts.map +1 -0
  64. package/dist/digest/emailSender.js +35 -0
  65. package/dist/digest/emailSender.js.map +1 -0
  66. package/dist/drive/client.d.ts +43 -0
  67. package/dist/drive/client.d.ts.map +1 -0
  68. package/dist/drive/client.js +282 -0
  69. package/dist/drive/client.js.map +1 -0
  70. package/dist/drive/errors.d.ts +27 -0
  71. package/dist/drive/errors.d.ts.map +1 -0
  72. package/dist/drive/errors.js +51 -0
  73. package/dist/drive/errors.js.map +1 -0
  74. package/dist/drive/fileCache.d.ts +22 -0
  75. package/dist/drive/fileCache.d.ts.map +1 -0
  76. package/dist/drive/fileCache.js +57 -0
  77. package/dist/drive/fileCache.js.map +1 -0
  78. package/dist/governance/accessControl.d.ts +87 -0
  79. package/dist/governance/accessControl.d.ts.map +1 -0
  80. package/dist/governance/accessControl.js +179 -0
  81. package/dist/governance/accessControl.js.map +1 -0
  82. package/dist/html/components.d.ts +8 -0
  83. package/dist/html/components.d.ts.map +1 -0
  84. package/dist/html/components.js +19 -0
  85. package/dist/html/components.js.map +1 -0
  86. package/dist/html/layout.d.ts +7 -0
  87. package/dist/html/layout.d.ts.map +1 -0
  88. package/dist/html/layout.js +24 -0
  89. package/dist/html/layout.js.map +1 -0
  90. package/dist/html/metricsUi.d.ts +8 -0
  91. package/dist/html/metricsUi.d.ts.map +1 -0
  92. package/dist/html/metricsUi.js +271 -0
  93. package/dist/html/metricsUi.js.map +1 -0
  94. package/dist/httpServer.d.ts +19 -0
  95. package/dist/httpServer.d.ts.map +1 -0
  96. package/dist/httpServer.js +3913 -0
  97. package/dist/httpServer.js.map +1 -0
  98. package/dist/index.d.ts +3 -0
  99. package/dist/index.d.ts.map +1 -0
  100. package/dist/index.js +40 -0
  101. package/dist/index.js.map +1 -0
  102. package/dist/jobs/asyncJobRegistry.d.ts +30 -0
  103. package/dist/jobs/asyncJobRegistry.d.ts.map +1 -0
  104. package/dist/jobs/asyncJobRegistry.js +70 -0
  105. package/dist/jobs/asyncJobRegistry.js.map +1 -0
  106. package/dist/observability/metricsQuery.d.ts +41 -0
  107. package/dist/observability/metricsQuery.d.ts.map +1 -0
  108. package/dist/observability/metricsQuery.js +106 -0
  109. package/dist/observability/metricsQuery.js.map +1 -0
  110. package/dist/observability/relevanceSignal.d.ts +26 -0
  111. package/dist/observability/relevanceSignal.d.ts.map +1 -0
  112. package/dist/observability/relevanceSignal.js +95 -0
  113. package/dist/observability/relevanceSignal.js.map +1 -0
  114. package/dist/observability/requestEvents.d.ts +31 -0
  115. package/dist/observability/requestEvents.d.ts.map +1 -0
  116. package/dist/observability/requestEvents.js +54 -0
  117. package/dist/observability/requestEvents.js.map +1 -0
  118. package/dist/observability/slowQueryAlert.d.ts +25 -0
  119. package/dist/observability/slowQueryAlert.d.ts.map +1 -0
  120. package/dist/observability/slowQueryAlert.js +67 -0
  121. package/dist/observability/slowQueryAlert.js.map +1 -0
  122. package/dist/observability/zeroResultTriage.d.ts +22 -0
  123. package/dist/observability/zeroResultTriage.d.ts.map +1 -0
  124. package/dist/observability/zeroResultTriage.js +116 -0
  125. package/dist/observability/zeroResultTriage.js.map +1 -0
  126. package/dist/search/embeddings.d.ts +31 -0
  127. package/dist/search/embeddings.d.ts.map +1 -0
  128. package/dist/search/embeddings.js +91 -0
  129. package/dist/search/embeddings.js.map +1 -0
  130. package/dist/search/fileWatcher.d.ts +28 -0
  131. package/dist/search/fileWatcher.d.ts.map +1 -0
  132. package/dist/search/fileWatcher.js +103 -0
  133. package/dist/search/fileWatcher.js.map +1 -0
  134. package/dist/search/hotQueryCache.d.ts +31 -0
  135. package/dist/search/hotQueryCache.d.ts.map +1 -0
  136. package/dist/search/hotQueryCache.js +103 -0
  137. package/dist/search/hotQueryCache.js.map +1 -0
  138. package/dist/search/postgresIndex.d.ts +439 -0
  139. package/dist/search/postgresIndex.d.ts.map +1 -0
  140. package/dist/search/postgresIndex.js +1610 -0
  141. package/dist/search/postgresIndex.js.map +1 -0
  142. package/dist/search/sqliteIndex.d.ts +66 -0
  143. package/dist/search/sqliteIndex.d.ts.map +1 -0
  144. package/dist/search/sqliteIndex.js +342 -0
  145. package/dist/search/sqliteIndex.js.map +1 -0
  146. package/dist/server.d.ts +43 -0
  147. package/dist/server.d.ts.map +1 -0
  148. package/dist/server.js +532 -0
  149. package/dist/server.js.map +1 -0
  150. package/dist/session/bundle.d.ts +53 -0
  151. package/dist/session/bundle.d.ts.map +1 -0
  152. package/dist/session/bundle.js +97 -0
  153. package/dist/session/bundle.js.map +1 -0
  154. package/dist/storage/client.d.ts +157 -0
  155. package/dist/storage/client.d.ts.map +1 -0
  156. package/dist/storage/client.js +825 -0
  157. package/dist/storage/client.js.map +1 -0
  158. package/dist/tools/addWebhookPattern.d.ts +15 -0
  159. package/dist/tools/addWebhookPattern.d.ts.map +1 -0
  160. package/dist/tools/addWebhookPattern.js +15 -0
  161. package/dist/tools/addWebhookPattern.js.map +1 -0
  162. package/dist/tools/appendLog.d.ts +18 -0
  163. package/dist/tools/appendLog.d.ts.map +1 -0
  164. package/dist/tools/appendLog.js +18 -0
  165. package/dist/tools/appendLog.js.map +1 -0
  166. package/dist/tools/auditIndex.d.ts +15 -0
  167. package/dist/tools/auditIndex.d.ts.map +1 -0
  168. package/dist/tools/auditIndex.js +165 -0
  169. package/dist/tools/auditIndex.js.map +1 -0
  170. package/dist/tools/batchDeletePages.d.ts +18 -0
  171. package/dist/tools/batchDeletePages.d.ts.map +1 -0
  172. package/dist/tools/batchDeletePages.js +143 -0
  173. package/dist/tools/batchDeletePages.js.map +1 -0
  174. package/dist/tools/coerce.d.ts +3 -0
  175. package/dist/tools/coerce.d.ts.map +1 -0
  176. package/dist/tools/coerce.js +12 -0
  177. package/dist/tools/coerce.js.map +1 -0
  178. package/dist/tools/createPage.d.ts +24 -0
  179. package/dist/tools/createPage.d.ts.map +1 -0
  180. package/dist/tools/createPage.js +99 -0
  181. package/dist/tools/createPage.js.map +1 -0
  182. package/dist/tools/createPages.d.ts +51 -0
  183. package/dist/tools/createPages.d.ts.map +1 -0
  184. package/dist/tools/createPages.js +91 -0
  185. package/dist/tools/createPages.js.map +1 -0
  186. package/dist/tools/deletePage.d.ts +19 -0
  187. package/dist/tools/deletePage.d.ts.map +1 -0
  188. package/dist/tools/deletePage.js +127 -0
  189. package/dist/tools/deletePage.js.map +1 -0
  190. package/dist/tools/exportWiki.d.ts +48 -0
  191. package/dist/tools/exportWiki.d.ts.map +1 -0
  192. package/dist/tools/exportWiki.js +233 -0
  193. package/dist/tools/exportWiki.js.map +1 -0
  194. package/dist/tools/extractLinks.d.ts +14 -0
  195. package/dist/tools/extractLinks.d.ts.map +1 -0
  196. package/dist/tools/extractLinks.js +25 -0
  197. package/dist/tools/extractLinks.js.map +1 -0
  198. package/dist/tools/generateClaudeInstructions.d.ts +27 -0
  199. package/dist/tools/generateClaudeInstructions.d.ts.map +1 -0
  200. package/dist/tools/generateClaudeInstructions.js +263 -0
  201. package/dist/tools/generateClaudeInstructions.js.map +1 -0
  202. package/dist/tools/generateGptInstructions.d.ts +27 -0
  203. package/dist/tools/generateGptInstructions.d.ts.map +1 -0
  204. package/dist/tools/generateGptInstructions.js +208 -0
  205. package/dist/tools/generateGptInstructions.js.map +1 -0
  206. package/dist/tools/getBacklinks.d.ts +12 -0
  207. package/dist/tools/getBacklinks.d.ts.map +1 -0
  208. package/dist/tools/getBacklinks.js +13 -0
  209. package/dist/tools/getBacklinks.js.map +1 -0
  210. package/dist/tools/getRelated.d.ts +12 -0
  211. package/dist/tools/getRelated.d.ts.map +1 -0
  212. package/dist/tools/getRelated.js +13 -0
  213. package/dist/tools/getRelated.js.map +1 -0
  214. package/dist/tools/healthCheck.d.ts +5 -0
  215. package/dist/tools/healthCheck.d.ts.map +1 -0
  216. package/dist/tools/healthCheck.js +167 -0
  217. package/dist/tools/healthCheck.js.map +1 -0
  218. package/dist/tools/importBrainSource.d.ts +36 -0
  219. package/dist/tools/importBrainSource.d.ts.map +1 -0
  220. package/dist/tools/importBrainSource.js +314 -0
  221. package/dist/tools/importBrainSource.js.map +1 -0
  222. package/dist/tools/importWikiZip.d.ts +60 -0
  223. package/dist/tools/importWikiZip.d.ts.map +1 -0
  224. package/dist/tools/importWikiZip.js +379 -0
  225. package/dist/tools/importWikiZip.js.map +1 -0
  226. package/dist/tools/initProject.d.ts +34 -0
  227. package/dist/tools/initProject.d.ts.map +1 -0
  228. package/dist/tools/initProject.js +443 -0
  229. package/dist/tools/initProject.js.map +1 -0
  230. package/dist/tools/instructionContext.d.ts +60 -0
  231. package/dist/tools/instructionContext.d.ts.map +1 -0
  232. package/dist/tools/instructionContext.js +210 -0
  233. package/dist/tools/instructionContext.js.map +1 -0
  234. package/dist/tools/listArchivedPages.d.ts +17 -0
  235. package/dist/tools/listArchivedPages.d.ts.map +1 -0
  236. package/dist/tools/listArchivedPages.js +51 -0
  237. package/dist/tools/listArchivedPages.js.map +1 -0
  238. package/dist/tools/listPages.d.ts +28 -0
  239. package/dist/tools/listPages.d.ts.map +1 -0
  240. package/dist/tools/listPages.js +166 -0
  241. package/dist/tools/listPages.js.map +1 -0
  242. package/dist/tools/listWebhooks.d.ts +7 -0
  243. package/dist/tools/listWebhooks.d.ts.map +1 -0
  244. package/dist/tools/listWebhooks.js +10 -0
  245. package/dist/tools/listWebhooks.js.map +1 -0
  246. package/dist/tools/movePage.d.ts +18 -0
  247. package/dist/tools/movePage.d.ts.map +1 -0
  248. package/dist/tools/movePage.js +182 -0
  249. package/dist/tools/movePage.js.map +1 -0
  250. package/dist/tools/pageHistory.d.ts +36 -0
  251. package/dist/tools/pageHistory.d.ts.map +1 -0
  252. package/dist/tools/pageHistory.js +60 -0
  253. package/dist/tools/pageHistory.js.map +1 -0
  254. package/dist/tools/patchPage.d.ts +141 -0
  255. package/dist/tools/patchPage.d.ts.map +1 -0
  256. package/dist/tools/patchPage.js +287 -0
  257. package/dist/tools/patchPage.js.map +1 -0
  258. package/dist/tools/pullSessionBundle.d.ts +34 -0
  259. package/dist/tools/pullSessionBundle.d.ts.map +1 -0
  260. package/dist/tools/pullSessionBundle.js +432 -0
  261. package/dist/tools/pullSessionBundle.js.map +1 -0
  262. package/dist/tools/purgeWiki.d.ts +23 -0
  263. package/dist/tools/purgeWiki.d.ts.map +1 -0
  264. package/dist/tools/purgeWiki.js +113 -0
  265. package/dist/tools/purgeWiki.js.map +1 -0
  266. package/dist/tools/pushSessionBundle.d.ts +139 -0
  267. package/dist/tools/pushSessionBundle.d.ts.map +1 -0
  268. package/dist/tools/pushSessionBundle.js +282 -0
  269. package/dist/tools/pushSessionBundle.js.map +1 -0
  270. package/dist/tools/readGovernanceAudit.d.ts +17 -0
  271. package/dist/tools/readGovernanceAudit.d.ts.map +1 -0
  272. package/dist/tools/readGovernanceAudit.js +21 -0
  273. package/dist/tools/readGovernanceAudit.js.map +1 -0
  274. package/dist/tools/readPage.d.ts +13 -0
  275. package/dist/tools/readPage.d.ts.map +1 -0
  276. package/dist/tools/readPage.js +46 -0
  277. package/dist/tools/readPage.js.map +1 -0
  278. package/dist/tools/removeWebhook.d.ts +14 -0
  279. package/dist/tools/removeWebhook.d.ts.map +1 -0
  280. package/dist/tools/removeWebhook.js +12 -0
  281. package/dist/tools/removeWebhook.js.map +1 -0
  282. package/dist/tools/resolveProject.d.ts +58 -0
  283. package/dist/tools/resolveProject.d.ts.map +1 -0
  284. package/dist/tools/resolveProject.js +175 -0
  285. package/dist/tools/resolveProject.js.map +1 -0
  286. package/dist/tools/restorePage.d.ts +47 -0
  287. package/dist/tools/restorePage.d.ts.map +1 -0
  288. package/dist/tools/restorePage.js +111 -0
  289. package/dist/tools/restorePage.js.map +1 -0
  290. package/dist/tools/searchPages.d.ts +28 -0
  291. package/dist/tools/searchPages.d.ts.map +1 -0
  292. package/dist/tools/searchPages.js +372 -0
  293. package/dist/tools/searchPages.js.map +1 -0
  294. package/dist/tools/setWebhook.d.ts +30 -0
  295. package/dist/tools/setWebhook.d.ts.map +1 -0
  296. package/dist/tools/setWebhook.js +30 -0
  297. package/dist/tools/setWebhook.js.map +1 -0
  298. package/dist/tools/shareProject.d.ts +25 -0
  299. package/dist/tools/shareProject.d.ts.map +1 -0
  300. package/dist/tools/shareProject.js +56 -0
  301. package/dist/tools/shareProject.js.map +1 -0
  302. package/dist/tools/suggestLinks.d.ts +29 -0
  303. package/dist/tools/suggestLinks.d.ts.map +1 -0
  304. package/dist/tools/suggestLinks.js +214 -0
  305. package/dist/tools/suggestLinks.js.map +1 -0
  306. package/dist/tools/updatePage.d.ts +27 -0
  307. package/dist/tools/updatePage.d.ts.map +1 -0
  308. package/dist/tools/updatePage.js +118 -0
  309. package/dist/tools/updatePage.js.map +1 -0
  310. package/dist/webhooks/dispatch.d.ts +49 -0
  311. package/dist/webhooks/dispatch.d.ts.map +1 -0
  312. package/dist/webhooks/dispatch.js +159 -0
  313. package/dist/webhooks/dispatch.js.map +1 -0
  314. package/dist/webhooks/webhookRules.d.ts +34 -0
  315. package/dist/webhooks/webhookRules.d.ts.map +1 -0
  316. package/dist/webhooks/webhookRules.js +129 -0
  317. package/dist/webhooks/webhookRules.js.map +1 -0
  318. package/dist/wiki/frontmatter.d.ts +45 -0
  319. package/dist/wiki/frontmatter.d.ts.map +1 -0
  320. package/dist/wiki/frontmatter.js +68 -0
  321. package/dist/wiki/frontmatter.js.map +1 -0
  322. package/dist/wiki/index.d.ts +22 -0
  323. package/dist/wiki/index.d.ts.map +1 -0
  324. package/dist/wiki/index.js +203 -0
  325. package/dist/wiki/index.js.map +1 -0
  326. package/dist/wiki/ingestPolicy.d.ts +18 -0
  327. package/dist/wiki/ingestPolicy.d.ts.map +1 -0
  328. package/dist/wiki/ingestPolicy.js +64 -0
  329. package/dist/wiki/ingestPolicy.js.map +1 -0
  330. package/dist/wiki/layoutLint.d.ts +51 -0
  331. package/dist/wiki/layoutLint.d.ts.map +1 -0
  332. package/dist/wiki/layoutLint.js +146 -0
  333. package/dist/wiki/layoutLint.js.map +1 -0
  334. package/dist/wiki/links.d.ts +6 -0
  335. package/dist/wiki/links.d.ts.map +1 -0
  336. package/dist/wiki/links.js +45 -0
  337. package/dist/wiki/links.js.map +1 -0
  338. package/dist/wiki/log.d.ts +58 -0
  339. package/dist/wiki/log.d.ts.map +1 -0
  340. package/dist/wiki/log.js +126 -0
  341. package/dist/wiki/log.js.map +1 -0
  342. package/dist/wiki/path.d.ts +8 -0
  343. package/dist/wiki/path.d.ts.map +1 -0
  344. package/dist/wiki/path.js +25 -0
  345. package/dist/wiki/path.js.map +1 -0
  346. package/dist/wiki/storageLimits.d.ts +163 -0
  347. package/dist/wiki/storageLimits.d.ts.map +1 -0
  348. package/dist/wiki/storageLimits.js +281 -0
  349. package/dist/wiki/storageLimits.js.map +1 -0
  350. package/package.json +81 -0
@@ -0,0 +1,261 @@
1
+ /**
2
+ * OAuth token persistence layer — local session sync.
3
+ *
4
+ * Provides a `TokenStore` interface with two implementations:
5
+ *
6
+ * - `LocalSQLiteTokenStore` — SQLite-backed, stored next to the search
7
+ * index under `<storageLocation>/.cache/oauth-tokens.db`. Zero extra
8
+ * dependencies (uses the already-bundled `better-sqlite3`). Suitable
9
+ * for single-instance local and Railway deployments.
10
+ *
11
+ * - `PostgresTokenStore` — Supabase PostgREST-backed, stored in an
12
+ * `oauth_tokens` table. Enables multi-instance / stateless deployments
13
+ * where the process may restart without losing active sessions. See
14
+ * `scripts/oauth-tokens.sql` for the required migration.
15
+ *
16
+ * `createTokenStore()` auto-selects the backend based on env vars:
17
+ * - `SUPABASE_URL` + `SUPABASE_SERVICE_ROLE_KEY` → PostgresTokenStore
18
+ * - otherwise → LocalSQLiteTokenStore
19
+ */
20
+ import fs from "fs";
21
+ import path from "path";
22
+ import Database from "better-sqlite3";
23
+ // ─── LocalSQLiteTokenStore ────────────────────────────────────────────────────
24
+ export class LocalSQLiteTokenStore {
25
+ db;
26
+ constructor(storageLocation) {
27
+ const cacheDir = path.join(storageLocation, ".cache");
28
+ fs.mkdirSync(cacheDir, { recursive: true });
29
+ const dbPath = path.join(cacheDir, "oauth-tokens.db");
30
+ this.db = new Database(dbPath);
31
+ this.db.pragma("journal_mode = WAL");
32
+ this.db.pragma("synchronous = NORMAL");
33
+ this.initSchema();
34
+ }
35
+ initSchema() {
36
+ this.db.exec(`
37
+ CREATE TABLE IF NOT EXISTS oauth_tokens (
38
+ type TEXT NOT NULL,
39
+ token TEXT NOT NULL,
40
+ client_id TEXT NOT NULL,
41
+ subject TEXT NOT NULL,
42
+ scope TEXT NOT NULL,
43
+ expires_at INTEGER NOT NULL,
44
+ redirect_uri TEXT,
45
+ code_challenge TEXT,
46
+ code_challenge_method TEXT,
47
+ PRIMARY KEY (type, token)
48
+ );
49
+ CREATE INDEX IF NOT EXISTS idx_oauth_tokens_expires_at
50
+ ON oauth_tokens (expires_at);
51
+ `);
52
+ }
53
+ async save(record) {
54
+ this.db
55
+ .prepare(`INSERT INTO oauth_tokens
56
+ (type, token, client_id, subject, scope, expires_at,
57
+ redirect_uri, code_challenge, code_challenge_method)
58
+ VALUES
59
+ (@type, @token, @client_id, @subject, @scope, @expires_at,
60
+ @redirect_uri, @code_challenge, @code_challenge_method)
61
+ ON CONFLICT(type, token) DO UPDATE SET
62
+ client_id = excluded.client_id,
63
+ subject = excluded.subject,
64
+ scope = excluded.scope,
65
+ expires_at = excluded.expires_at,
66
+ redirect_uri = excluded.redirect_uri,
67
+ code_challenge = excluded.code_challenge,
68
+ code_challenge_method = excluded.code_challenge_method`)
69
+ .run({
70
+ type: record.type,
71
+ token: record.token,
72
+ client_id: record.clientId,
73
+ subject: record.subject,
74
+ scope: JSON.stringify(record.scope),
75
+ expires_at: record.expiresAt,
76
+ redirect_uri: record.redirectUri ?? null,
77
+ code_challenge: record.codeChallenge ?? null,
78
+ code_challenge_method: record.codeChallengeMethod ?? null,
79
+ });
80
+ }
81
+ async find(type, token) {
82
+ const row = this.db
83
+ .prepare("SELECT * FROM oauth_tokens WHERE type = ? AND token = ? AND expires_at > ?")
84
+ .get(type, token, Date.now());
85
+ if (!row)
86
+ return null;
87
+ return rowToStoredToken(row);
88
+ }
89
+ async delete(type, token) {
90
+ this.db
91
+ .prepare("DELETE FROM oauth_tokens WHERE type = ? AND token = ?")
92
+ .run(type, token);
93
+ }
94
+ async deleteAllForSubject(subject, clientId, type) {
95
+ this.db
96
+ .prepare("DELETE FROM oauth_tokens WHERE subject = ? AND client_id = ? AND type = ?")
97
+ .run(subject, clientId, type);
98
+ }
99
+ async deleteAllTokensForSubject(subject) {
100
+ this.db
101
+ .prepare("DELETE FROM oauth_tokens WHERE subject = ?")
102
+ .run(subject);
103
+ }
104
+ async pruneExpired() {
105
+ this.db
106
+ .prepare("DELETE FROM oauth_tokens WHERE expires_at <= ?")
107
+ .run(Date.now());
108
+ }
109
+ }
110
+ export class PostgresTokenStore {
111
+ supabaseUrl;
112
+ serviceRoleKey;
113
+ constructor(supabaseUrl, serviceRoleKey) {
114
+ this.supabaseUrl = supabaseUrl.trim().replace(/\/$/, "");
115
+ this.serviceRoleKey = serviceRoleKey.trim();
116
+ }
117
+ authHeaders(extra) {
118
+ return {
119
+ apikey: this.serviceRoleKey,
120
+ authorization: `Bearer ${this.serviceRoleKey}`,
121
+ "content-type": "application/json",
122
+ prefer: "return=minimal",
123
+ ...extra,
124
+ };
125
+ }
126
+ get baseUrl() {
127
+ return `${this.supabaseUrl}/rest/v1/oauth_tokens`;
128
+ }
129
+ async save(record) {
130
+ const body = JSON.stringify({
131
+ type: record.type,
132
+ token: record.token,
133
+ client_id: record.clientId,
134
+ subject: record.subject,
135
+ scope: JSON.stringify(record.scope),
136
+ expires_at: record.expiresAt,
137
+ redirect_uri: record.redirectUri ?? null,
138
+ code_challenge: record.codeChallenge ?? null,
139
+ code_challenge_method: record.codeChallengeMethod ?? null,
140
+ });
141
+ const response = await fetch(this.baseUrl, {
142
+ method: "POST",
143
+ headers: this.authHeaders({ prefer: "resolution=merge-duplicates,return=minimal" }),
144
+ body,
145
+ });
146
+ if (!response.ok) {
147
+ const text = await response.text().catch(() => "");
148
+ throw new Error(`PostgresTokenStore.save failed (${response.status}): ${text}`);
149
+ }
150
+ }
151
+ async find(type, token) {
152
+ const url = `${this.baseUrl}?type=eq.${encodeURIComponent(type)}&token=eq.${encodeURIComponent(token)}&expires_at=gt.${Date.now()}&limit=1`;
153
+ const response = await fetch(url, {
154
+ method: "GET",
155
+ headers: this.authHeaders({ prefer: "return=representation" }),
156
+ }).catch(() => null);
157
+ if (!response || !response.ok)
158
+ return null;
159
+ const rows = (await response.json().catch(() => []));
160
+ const row = rows[0];
161
+ if (!row)
162
+ return null;
163
+ return postgresRowToStoredToken(row);
164
+ }
165
+ async delete(type, token) {
166
+ const url = `${this.baseUrl}?type=eq.${encodeURIComponent(type)}&token=eq.${encodeURIComponent(token)}`;
167
+ const response = await fetch(url, {
168
+ method: "DELETE",
169
+ headers: this.authHeaders(),
170
+ });
171
+ if (!response.ok) {
172
+ const text = await response.text().catch(() => "");
173
+ throw new Error(`PostgresTokenStore.delete failed (${response.status}): ${text}`);
174
+ }
175
+ }
176
+ async deleteAllForSubject(subject, clientId, type) {
177
+ const url = `${this.baseUrl}?subject=eq.${encodeURIComponent(subject)}&client_id=eq.${encodeURIComponent(clientId)}&type=eq.${encodeURIComponent(type)}`;
178
+ const response = await fetch(url, {
179
+ method: "DELETE",
180
+ headers: this.authHeaders(),
181
+ });
182
+ if (!response.ok) {
183
+ const text = await response.text().catch(() => "");
184
+ throw new Error(`PostgresTokenStore.deleteAllForSubject failed (${response.status}): ${text}`);
185
+ }
186
+ }
187
+ async deleteAllTokensForSubject(subject) {
188
+ const url = `${this.baseUrl}?subject=eq.${encodeURIComponent(subject)}`;
189
+ const response = await fetch(url, {
190
+ method: "DELETE",
191
+ headers: this.authHeaders(),
192
+ });
193
+ if (!response.ok) {
194
+ const text = await response.text().catch(() => "");
195
+ throw new Error(`PostgresTokenStore.deleteAllTokensForSubject failed (${response.status}): ${text}`);
196
+ }
197
+ }
198
+ async pruneExpired() {
199
+ const url = `${this.baseUrl}?expires_at=lte.${Date.now()}`;
200
+ await fetch(url, {
201
+ method: "DELETE",
202
+ headers: this.authHeaders(),
203
+ }).catch(() => null);
204
+ }
205
+ }
206
+ // ─── Factory ──────────────────────────────────────────────────────────────────
207
+ /**
208
+ * Select and instantiate a token store based on the environment:
209
+ * - SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY present → PostgresTokenStore
210
+ * - otherwise → LocalSQLiteTokenStore (stored under `storageLocation/.cache/`)
211
+ */
212
+ export function createTokenStore(storageLocation) {
213
+ const supabaseUrl = (process.env.SUPABASE_URL ?? "").trim();
214
+ const serviceRoleKey = (process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
215
+ if (supabaseUrl && serviceRoleKey) {
216
+ return new PostgresTokenStore(supabaseUrl, serviceRoleKey);
217
+ }
218
+ return new LocalSQLiteTokenStore(storageLocation);
219
+ }
220
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
221
+ function rowToStoredToken(row) {
222
+ let scope = [];
223
+ try {
224
+ scope = JSON.parse(row.scope);
225
+ }
226
+ catch {
227
+ scope = [];
228
+ }
229
+ return {
230
+ type: row.type,
231
+ token: row.token,
232
+ clientId: row.client_id,
233
+ subject: row.subject,
234
+ scope,
235
+ expiresAt: row.expires_at,
236
+ redirectUri: row.redirect_uri ?? undefined,
237
+ codeChallenge: row.code_challenge ?? undefined,
238
+ codeChallengeMethod: row.code_challenge_method ?? undefined,
239
+ };
240
+ }
241
+ function postgresRowToStoredToken(row) {
242
+ let scope = [];
243
+ try {
244
+ scope = JSON.parse(row.scope);
245
+ }
246
+ catch {
247
+ scope = [];
248
+ }
249
+ return {
250
+ type: row.type,
251
+ token: row.token,
252
+ clientId: row.client_id,
253
+ subject: row.subject,
254
+ scope,
255
+ expiresAt: Number(row.expires_at),
256
+ redirectUri: row.redirect_uri ?? undefined,
257
+ codeChallenge: row.code_challenge ?? undefined,
258
+ codeChallengeMethod: row.code_challenge_method ?? undefined,
259
+ };
260
+ }
261
+ //# sourceMappingURL=tokenStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenStore.js","sourceRoot":"","sources":["../../src/auth/tokenStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AA8CtC,iFAAiF;AAEjF,MAAM,OAAO,qBAAqB;IACf,EAAE,CAAoB;IAEvC,YAAY,eAAuB;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;QACtD,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;QACtD,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACrC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;QACvC,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAEO,UAAU;QAChB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;KAeZ,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAmB;QAC5B,IAAI,CAAC,EAAE;aACJ,OAAO,CACN;;;;;;;;;;;;;kEAa0D,CAC3D;aACA,GAAG,CAAC;YACH,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,SAAS,EAAE,MAAM,CAAC,QAAQ;YAC1B,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;YACnC,UAAU,EAAE,MAAM,CAAC,SAAS;YAC5B,YAAY,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI;YACxC,cAAc,EAAE,MAAM,CAAC,aAAa,IAAI,IAAI;YAC5C,qBAAqB,EAAE,MAAM,CAAC,mBAAmB,IAAI,IAAI;SAC1D,CAAC,CAAC;IACP,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAe,EAAE,KAAa;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;aAChB,OAAO,CACN,4EAA4E,CAC7E;aACA,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,CAAyB,CAAC;QAExD,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,OAAO,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAe,EAAE,KAAa;QACzC,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,uDAAuD,CAAC;aAChE,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,OAAe,EAAE,QAAgB,EAAE,IAAe;QAC1E,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,2EAA2E,CAAC;aACpF,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,yBAAyB,CAAC,OAAe;QAC7C,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,4CAA4C,CAAC;aACrD,GAAG,CAAC,OAAO,CAAC,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,gDAAgD,CAAC;aACzD,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACrB,CAAC;CACF;AAgBD,MAAM,OAAO,kBAAkB;IACZ,WAAW,CAAS;IACpB,cAAc,CAAS;IAExC,YAAY,WAAmB,EAAE,cAAsB;QACrD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC;IAC9C,CAAC;IAEO,WAAW,CAAC,KAA8B;QAChD,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,cAAc;YAC3B,aAAa,EAAE,UAAU,IAAI,CAAC,cAAc,EAAE;YAC9C,cAAc,EAAE,kBAAkB;YAClC,MAAM,EAAE,gBAAgB;YACxB,GAAG,KAAK;SACT,CAAC;IACJ,CAAC;IAED,IAAY,OAAO;QACjB,OAAO,GAAG,IAAI,CAAC,WAAW,uBAAuB,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAmB;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,SAAS,EAAE,MAAM,CAAC,QAAQ;YAC1B,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;YACnC,UAAU,EAAE,MAAM,CAAC,SAAS;YAC5B,YAAY,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI;YACxC,cAAc,EAAE,MAAM,CAAC,aAAa,IAAI,IAAI;YAC5C,qBAAqB,EAAE,MAAM,CAAC,mBAAmB,IAAI,IAAI;SAC1D,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE;YACzC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,4CAA4C,EAAE,CAAC;YACnF,IAAI;SACL,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,mCAAmC,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAe,EAAE,KAAa;QACvC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,YAAY,kBAAkB,CAAC,IAAI,CAAC,aAAa,kBAAkB,CAAC,KAAK,CAAC,kBAAkB,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC;QAC5I,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC;SAC/D,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAErB,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAE3C,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAkB,CAAC;QACtE,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QAEtB,OAAO,wBAAwB,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAe,EAAE,KAAa;QACzC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,YAAY,kBAAkB,CAAC,IAAI,CAAC,aAAa,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QACxG,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,QAAQ;YAChB,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE;SAC5B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,qCAAqC,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,OAAe,EAAE,QAAgB,EAAE,IAAe;QAC1E,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,eAAe,kBAAkB,CAAC,OAAO,CAAC,iBAAiB,kBAAkB,CAAC,QAAQ,CAAC,YAAY,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;QACzJ,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,QAAQ;YAChB,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE;SAC5B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,kDAAkD,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;IAED,KAAK,CAAC,yBAAyB,CAAC,OAAe;QAC7C,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,eAAe,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;QACxE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,QAAQ;YAChB,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE;SAC5B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,wDAAwD,QAAQ,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;QACvG,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,mBAAmB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAC3D,MAAM,KAAK,CAAC,GAAG,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE;SAC5B,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;CACF;AAED,iFAAiF;AAEjF;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,eAAuB;IACtD,MAAM,WAAW,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5D,MAAM,cAAc,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAE5E,IAAI,WAAW,IAAI,cAAc,EAAE,CAAC;QAClC,OAAO,IAAI,kBAAkB,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,IAAI,qBAAqB,CAAC,eAAe,CAAC,CAAC;AACpD,CAAC;AAED,iFAAiF;AAEjF,SAAS,gBAAgB,CAAC,GAAa;IACrC,IAAI,KAAK,GAAa,EAAE,CAAC;IACzB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAa,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,GAAG,EAAE,CAAC;IACb,CAAC;IAED,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAiB;QAC3B,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK;QACL,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,WAAW,EAAE,GAAG,CAAC,YAAY,IAAI,SAAS;QAC1C,aAAa,EAAE,GAAG,CAAC,cAAc,IAAI,SAAS;QAC9C,mBAAmB,EAAE,GAAG,CAAC,qBAAqB,IAAI,SAAS;KAC5D,CAAC;AACJ,CAAC;AAED,SAAS,wBAAwB,CAAC,GAAgB;IAChD,IAAI,KAAK,GAAa,EAAE,CAAC;IACzB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAa,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,GAAG,EAAE,CAAC;IACb,CAAC;IAED,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAiB;QAC3B,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK;QACL,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;QACjC,WAAW,EAAE,GAAG,CAAC,YAAY,IAAI,SAAS;QAC1C,aAAa,EAAE,GAAG,CAAC,cAAc,IAAI,SAAS;QAC9C,mBAAmB,EAAE,GAAG,CAAC,qBAAqB,IAAI,SAAS;KAC5D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Optional Google Drive backup for the brains wiki.
3
+ *
4
+ * This module is only activated when DRIVE_BACKUP_ENABLED=true and all
5
+ * required Google OAuth2 credentials are set. When active, every write to
6
+ * local storage is also mirrored to a single Drive folder asynchronously.
7
+ * Failures are logged but never propagated — Drive is backup, not primary.
8
+ */
9
+ export declare class DriveBackup {
10
+ private readonly drive;
11
+ private readonly folderId;
12
+ private constructor();
13
+ /**
14
+ * Return a DriveBackup instance if all required env vars are present,
15
+ * or null if backup is disabled or misconfigured.
16
+ */
17
+ static tryCreate(): DriveBackup | null;
18
+ /**
19
+ * Upsert a file to The Drive backup folder.
20
+ * Called fire-and-forget after every local write — errors are swallowed by the caller.
21
+ */
22
+ backup(name: string, content: string): Promise<void>;
23
+ }
24
+ //# sourceMappingURL=drive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drive.d.ts","sourceRoot":"","sources":["../../src/backup/drive.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAElC,OAAO;IAYP;;;OAGG;IACH,MAAM,CAAC,SAAS,IAAI,WAAW,GAAG,IAAI;IAwBtC;;;OAGG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA8B3D"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Optional Google Drive backup for the brains wiki.
3
+ *
4
+ * This module is only activated when DRIVE_BACKUP_ENABLED=true and all
5
+ * required Google OAuth2 credentials are set. When active, every write to
6
+ * local storage is also mirrored to a single Drive folder asynchronously.
7
+ * Failures are logged but never propagated — Drive is backup, not primary.
8
+ */
9
+ import { google } from "googleapis";
10
+ export class DriveBackup {
11
+ drive;
12
+ folderId;
13
+ constructor(clientId, clientSecret, refreshToken, folderId) {
14
+ const auth = new google.auth.OAuth2(clientId, clientSecret);
15
+ auth.setCredentials({ refresh_token: refreshToken });
16
+ this.drive = google.drive({ version: "v3", auth: auth });
17
+ this.folderId = folderId;
18
+ }
19
+ /**
20
+ * Return a DriveBackup instance if all required env vars are present,
21
+ * or null if backup is disabled or misconfigured.
22
+ */
23
+ static tryCreate() {
24
+ if (process.env.DRIVE_BACKUP_ENABLED !== "true")
25
+ return null;
26
+ const { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKEN, DRIVE_FOLDER_ID } = process.env;
27
+ if (!GOOGLE_CLIENT_ID || !GOOGLE_CLIENT_SECRET || !GOOGLE_REFRESH_TOKEN || !DRIVE_FOLDER_ID) {
28
+ console.warn("[backup] DRIVE_BACKUP_ENABLED=true but one or more required env vars are missing " +
29
+ "(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKEN, DRIVE_FOLDER_ID). " +
30
+ "Drive backup is disabled.");
31
+ return null;
32
+ }
33
+ console.info("[backup] Drive backup enabled. Folder:", DRIVE_FOLDER_ID);
34
+ return new DriveBackup(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKEN, DRIVE_FOLDER_ID);
35
+ }
36
+ /**
37
+ * Upsert a file to The Drive backup folder.
38
+ * Called fire-and-forget after every local write — errors are swallowed by the caller.
39
+ */
40
+ async backup(name, content) {
41
+ // Check if file already exists in Drive
42
+ const listRes = await this.drive.files.list({
43
+ q: `'${this.folderId}' in parents and name='${name}' and trashed=false`,
44
+ fields: "files(id)",
45
+ pageSize: 1,
46
+ });
47
+ const existing = listRes.data.files?.[0];
48
+ if (existing?.id) {
49
+ // Update existing file
50
+ await this.drive.files.update({
51
+ fileId: existing.id,
52
+ media: { mimeType: "text/plain", body: content },
53
+ fields: "id",
54
+ });
55
+ }
56
+ else {
57
+ // Create new file
58
+ await this.drive.files.create({
59
+ requestBody: {
60
+ name,
61
+ parents: [this.folderId],
62
+ mimeType: "text/plain",
63
+ },
64
+ media: { mimeType: "text/plain", body: content },
65
+ fields: "id",
66
+ });
67
+ }
68
+ }
69
+ }
70
+ //# sourceMappingURL=drive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drive.js","sourceRoot":"","sources":["../../src/backup/drive.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAY,MAAM,YAAY,CAAC;AAG9C,MAAM,OAAO,WAAW;IACL,KAAK,CAAiB;IACtB,QAAQ,CAAS;IAElC,YACE,QAAgB,EAChB,YAAoB,EACpB,YAAoB,EACpB,QAAgB;QAEhB,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC5D,IAAI,CAAC,cAAc,CAAC,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAA+B,EAAE,CAAC,CAAC;QACpF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,SAAS;QACd,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC;QAE7D,MAAM,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,eAAe,EAAE,GACrF,OAAO,CAAC,GAAG,CAAC;QAEd,IAAI,CAAC,gBAAgB,IAAI,CAAC,oBAAoB,IAAI,CAAC,oBAAoB,IAAI,CAAC,eAAe,EAAE,CAAC;YAC5F,OAAO,CAAC,IAAI,CACV,mFAAmF;gBACjF,mFAAmF;gBACnF,2BAA2B,CAC9B,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,wCAAwC,EAAE,eAAe,CAAC,CAAC;QACxE,OAAO,IAAI,WAAW,CACpB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,CAChB,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,OAAe;QACxC,wCAAwC;QACxC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;YAC1C,CAAC,EAAE,IAAI,IAAI,CAAC,QAAQ,0BAA0B,IAAI,qBAAqB;YACvE,MAAM,EAAE,WAAW;YACnB,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAEzC,IAAI,QAAQ,EAAE,EAAE,EAAE,CAAC;YACjB,uBAAuB;YACvB,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;gBAC5B,MAAM,EAAE,QAAQ,CAAC,EAAE;gBACnB,KAAK,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE;gBAChD,MAAM,EAAE,IAAI;aACb,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,kBAAkB;YAClB,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;gBAC5B,WAAW,EAAE;oBACX,IAAI;oBACJ,OAAO,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;oBACxB,QAAQ,EAAE,YAAY;iBACvB;gBACD,KAAK,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE;gBAChD,MAAM,EAAE,IAAI;aACb,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Billing tier lookup (GH #473).
3
+ *
4
+ * The page limit used to be decided by two env vars and god-mode membership, so
5
+ * the "Upgrade to Solo for 2,000 pages" message pointed at a tier that raised
6
+ * nothing. This resolves a user's tier so `getPageLimit` can honour it.
7
+ *
8
+ * PostgREST-backed, mirroring PostgresPATStore. There is no SQLite backend on
9
+ * purpose: `assertPageLimit` returns early unless the Postgres index is
10
+ * configured, so a local run never reaches a tier lookup.
11
+ *
12
+ * Failure is non-fatal by design. A missing table, an unreachable database or a
13
+ * malformed row all resolve to `null` — "no tier assigned" — and the caller
14
+ * falls back to the env-var defaults.
15
+ *
16
+ * That matters because on production, code and schema move on different
17
+ * triggers. Railway redeploys production code when `main` moves, but
18
+ * `apply-migrations.mjs` runs there only inside `deploy-production.yml`, which
19
+ * is `workflow_dispatch` and fires only when a human asks. So production can be
20
+ * running code that reads this table days before anyone applies it. (Staging
21
+ * does not have the gap — `deploy-staging.yml` runs migrations on every push to
22
+ * `main`.) Refusing writes in that window would take production down for
23
+ * everyone in exchange for a limit that is merely stale.
24
+ */
25
+ /** Tiers the pricing page sells, plus the two legacy names seedUsers already writes. */
26
+ export type BillingTier = "free" | "solo" | "pro" | "unlimited" | "free_beta" | "launch_user";
27
+ export declare const BILLING_TIERS: readonly BillingTier[];
28
+ export declare function isBillingTier(value: string): value is BillingTier;
29
+ export interface TierStore {
30
+ /** Resolve a subject's tier, or null when none is assigned or lookup fails. */
31
+ get(subject: string): Promise<BillingTier | null>;
32
+ /** Assign a tier. Returns false when the write fails. */
33
+ set(subject: string, tier: BillingTier, updatedBy: string): Promise<boolean>;
34
+ /** Drop cached lookups. */
35
+ invalidate(subject?: string): void;
36
+ }
37
+ export declare class PostgresTierStore implements TierStore {
38
+ private readonly supabaseUrl;
39
+ private readonly serviceRoleKey;
40
+ private readonly cache;
41
+ constructor(supabaseUrl: string, serviceRoleKey: string);
42
+ private get baseUrl();
43
+ private headers;
44
+ private cacheTtlMs;
45
+ private cacheSet;
46
+ invalidate(subject?: string): void;
47
+ get(subject: string): Promise<BillingTier | null>;
48
+ set(subject: string, tier: BillingTier, updatedBy: string): Promise<boolean>;
49
+ }
50
+ /** No-op store for deployments without Postgres — every lookup is "no tier". */
51
+ export declare class NullTierStore implements TierStore {
52
+ get(): Promise<BillingTier | null>;
53
+ set(): Promise<boolean>;
54
+ invalidate(): void;
55
+ }
56
+ export declare function getTierStore(): TierStore;
57
+ /** Test seam. */
58
+ export declare function setTierStore(store: TierStore | null): void;
59
+ //# sourceMappingURL=tierStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tierStore.d.ts","sourceRoot":"","sources":["../../src/billing/tierStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,wFAAwF;AACxF,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,WAAW,GAAG,WAAW,GAAG,aAAa,CAAC;AAE9F,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAO/C,CAAC;AAEF,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,WAAW,CAEjE;AAOD,MAAM,WAAW,SAAS;IACxB,+EAA+E;IAC/E,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAClD,yDAAyD;IACzD,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7E,2BAA2B;IAC3B,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,qBAAa,iBAAkB,YAAW,SAAS;IACjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;gBAE3C,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;IAKvD,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,QAAQ;IAQhB,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAK5B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA4BjD,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAoBnF;AAED,gFAAgF;AAChF,qBAAa,aAAc,YAAW,SAAS;IACvC,GAAG,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAGlC,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;IAG7B,UAAU,IAAI,IAAI;CAGnB;AAID,wBAAgB,YAAY,IAAI,SAAS,CAMxC;AAED,iBAAiB;AACjB,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAE1D"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Billing tier lookup (GH #473).
3
+ *
4
+ * The page limit used to be decided by two env vars and god-mode membership, so
5
+ * the "Upgrade to Solo for 2,000 pages" message pointed at a tier that raised
6
+ * nothing. This resolves a user's tier so `getPageLimit` can honour it.
7
+ *
8
+ * PostgREST-backed, mirroring PostgresPATStore. There is no SQLite backend on
9
+ * purpose: `assertPageLimit` returns early unless the Postgres index is
10
+ * configured, so a local run never reaches a tier lookup.
11
+ *
12
+ * Failure is non-fatal by design. A missing table, an unreachable database or a
13
+ * malformed row all resolve to `null` — "no tier assigned" — and the caller
14
+ * falls back to the env-var defaults.
15
+ *
16
+ * That matters because on production, code and schema move on different
17
+ * triggers. Railway redeploys production code when `main` moves, but
18
+ * `apply-migrations.mjs` runs there only inside `deploy-production.yml`, which
19
+ * is `workflow_dispatch` and fires only when a human asks. So production can be
20
+ * running code that reads this table days before anyone applies it. (Staging
21
+ * does not have the gap — `deploy-staging.yml` runs migrations on every push to
22
+ * `main`.) Refusing writes in that window would take production down for
23
+ * everyone in exchange for a limit that is merely stale.
24
+ */
25
+ const TIER_CACHE_TTL_MS = 60_000;
26
+ const TIER_CACHE_MAX_ENTRIES = 5_000;
27
+ export const BILLING_TIERS = [
28
+ "free",
29
+ "solo",
30
+ "pro",
31
+ "unlimited",
32
+ "free_beta",
33
+ "launch_user",
34
+ ];
35
+ export function isBillingTier(value) {
36
+ return BILLING_TIERS.includes(value);
37
+ }
38
+ export class PostgresTierStore {
39
+ supabaseUrl;
40
+ serviceRoleKey;
41
+ cache = new Map();
42
+ constructor(supabaseUrl, serviceRoleKey) {
43
+ this.supabaseUrl = supabaseUrl.trim().replace(/\/$/, "");
44
+ this.serviceRoleKey = serviceRoleKey.trim();
45
+ }
46
+ get baseUrl() {
47
+ return `${this.supabaseUrl}/rest/v1/user_tiers`;
48
+ }
49
+ headers(extra) {
50
+ return {
51
+ apikey: this.serviceRoleKey,
52
+ authorization: `Bearer ${this.serviceRoleKey}`,
53
+ "content-type": "application/json",
54
+ ...extra,
55
+ };
56
+ }
57
+ cacheTtlMs() {
58
+ const raw = parseInt(process.env.BRAINS_TIER_CACHE_TTL_MS ?? "", 10);
59
+ return Number.isFinite(raw) && raw >= 0 ? raw : TIER_CACHE_TTL_MS;
60
+ }
61
+ cacheSet(subject, tier) {
62
+ if (this.cache.size >= TIER_CACHE_MAX_ENTRIES) {
63
+ const oldest = this.cache.keys().next().value;
64
+ if (oldest !== undefined)
65
+ this.cache.delete(oldest);
66
+ }
67
+ this.cache.set(subject, { tier, at: Date.now() });
68
+ }
69
+ invalidate(subject) {
70
+ if (subject === undefined)
71
+ this.cache.clear();
72
+ else
73
+ this.cache.delete(subject);
74
+ }
75
+ async get(subject) {
76
+ if (!subject)
77
+ return null;
78
+ const hit = this.cache.get(subject);
79
+ if (hit && Date.now() - hit.at < this.cacheTtlMs())
80
+ return hit.tier;
81
+ try {
82
+ const url = `${this.baseUrl}?user_id=eq.${encodeURIComponent(subject)}&select=tier&limit=1`;
83
+ const res = await fetch(url, { headers: this.headers() });
84
+ if (!res.ok) {
85
+ // 404 here means the migration has not been applied to this database.
86
+ // Cache the negative so a missing table does not add a round trip to
87
+ // every write until someone deploys it.
88
+ this.cacheSet(subject, null);
89
+ return null;
90
+ }
91
+ const rows = (await res.json());
92
+ const raw = Array.isArray(rows) && rows.length > 0 ? rows[0]?.tier : undefined;
93
+ const tier = typeof raw === "string" && isBillingTier(raw) ? raw : null;
94
+ this.cacheSet(subject, tier);
95
+ return tier;
96
+ }
97
+ catch {
98
+ // Network/DNS failure. Do not cache — the next write should retry rather
99
+ // than run on a stale negative for the full TTL.
100
+ return null;
101
+ }
102
+ }
103
+ async set(subject, tier, updatedBy) {
104
+ if (!subject)
105
+ return false;
106
+ try {
107
+ const res = await fetch(this.baseUrl, {
108
+ method: "POST",
109
+ headers: this.headers({ prefer: "resolution=merge-duplicates,return=minimal" }),
110
+ body: JSON.stringify({
111
+ user_id: subject,
112
+ tier,
113
+ updated_by: updatedBy,
114
+ updated_at: new Date().toISOString(),
115
+ }),
116
+ });
117
+ if (!res.ok)
118
+ return false;
119
+ this.cacheSet(subject, tier);
120
+ return true;
121
+ }
122
+ catch {
123
+ return false;
124
+ }
125
+ }
126
+ }
127
+ /** No-op store for deployments without Postgres — every lookup is "no tier". */
128
+ export class NullTierStore {
129
+ async get() {
130
+ return null;
131
+ }
132
+ async set() {
133
+ return false;
134
+ }
135
+ invalidate() {
136
+ /* nothing cached */
137
+ }
138
+ }
139
+ let cached = null;
140
+ export function getTierStore() {
141
+ if (cached)
142
+ return cached;
143
+ const url = (process.env.SUPABASE_URL ?? "").trim();
144
+ const key = (process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
145
+ cached = url && key ? new PostgresTierStore(url, key) : new NullTierStore();
146
+ return cached;
147
+ }
148
+ /** Test seam. */
149
+ export function setTierStore(store) {
150
+ cached = store;
151
+ }
152
+ //# sourceMappingURL=tierStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tierStore.js","sourceRoot":"","sources":["../../src/billing/tierStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * activityDigest.ts
3
+ *
4
+ * Gathers weekly activity signals from a user's wiki storage and generates
5
+ * the digest markdown content and email body.
6
+ *
7
+ * Signals collected:
8
+ * - Pages created / modified (from log.md events + file listing)
9
+ * - Decisions made (pages tagged "decision" modified this week)
10
+ * - Open loops closed (pages tagged "open-loop" with status resolved)
11
+ * - Active tags (tags appearing in recently modified pages)
12
+ */
13
+ import type { StorageClient } from "../storage/client.js";
14
+ export interface DigestSignals {
15
+ weekLabel: string;
16
+ weekRange: string;
17
+ pagesCreated: string[];
18
+ pagesModified: string[];
19
+ decisionsMade: string[];
20
+ loopsClosed: string[];
21
+ activeTags: Array<{
22
+ tag: string;
23
+ count: number;
24
+ }>;
25
+ totalEvents: number;
26
+ }
27
+ export declare function isoWeekLabel(date: Date): string;
28
+ export declare function gatherDigestSignals(drive: StorageClient, now?: Date, userId?: string): Promise<DigestSignals>;
29
+ export declare function buildDigestMarkdown(signals: DigestSignals, dateStr: string): string;
30
+ export declare function buildDigestHtml(signals: DigestSignals): string;
31
+ export declare function buildDigestText(signals: DigestSignals): string;
32
+ //# sourceMappingURL=activityDigest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activityDigest.d.ts","sourceRoot":"","sources":["../../src/digest/activityDigest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAK1D,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD,WAAW,EAAE,MAAM,CAAC;CACrB;AAID,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAW/C;AAyFD,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,aAAa,EACpB,GAAG,GAAE,IAAiB,EACtB,MAAM,SAAK,GACV,OAAO,CAAC,aAAa,CAAC,CAyGxB;AAID,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CA6CnF;AAID,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAyD9D;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CA0B9D"}