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.
- package/README.md +95 -0
- package/dist/access/projectShares.d.ts +48 -0
- package/dist/access/projectShares.d.ts.map +1 -0
- package/dist/access/projectShares.js +203 -0
- package/dist/access/projectShares.js.map +1 -0
- package/dist/access/sharedInstructionsNote.d.ts +37 -0
- package/dist/access/sharedInstructionsNote.d.ts.map +1 -0
- package/dist/access/sharedInstructionsNote.js +76 -0
- package/dist/access/sharedInstructionsNote.js.map +1 -0
- package/dist/admin/seedUsers.d.ts +23 -0
- package/dist/admin/seedUsers.d.ts.map +1 -0
- package/dist/admin/seedUsers.js +168 -0
- package/dist/admin/seedUsers.js.map +1 -0
- package/dist/api/openapi.d.ts +2 -0
- package/dist/api/openapi.d.ts.map +1 -0
- package/dist/api/openapi.js +942 -0
- package/dist/api/openapi.js.map +1 -0
- package/dist/auth/clientStore.d.ts +43 -0
- package/dist/auth/clientStore.d.ts.map +1 -0
- package/dist/auth/clientStore.js +168 -0
- package/dist/auth/clientStore.js.map +1 -0
- package/dist/auth/deleteAccount.d.ts +34 -0
- package/dist/auth/deleteAccount.d.ts.map +1 -0
- package/dist/auth/deleteAccount.js +203 -0
- package/dist/auth/deleteAccount.js.map +1 -0
- package/dist/auth/oauth.d.ts +118 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +491 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/patStore.d.ts +87 -0
- package/dist/auth/patStore.d.ts.map +1 -0
- package/dist/auth/patStore.js +308 -0
- package/dist/auth/patStore.js.map +1 -0
- package/dist/auth/supabase.d.ts +15 -0
- package/dist/auth/supabase.d.ts.map +1 -0
- package/dist/auth/supabase.js +66 -0
- package/dist/auth/supabase.js.map +1 -0
- package/dist/auth/tokenStore.d.ts +73 -0
- package/dist/auth/tokenStore.d.ts.map +1 -0
- package/dist/auth/tokenStore.js +261 -0
- package/dist/auth/tokenStore.js.map +1 -0
- package/dist/backup/drive.d.ts +24 -0
- package/dist/backup/drive.d.ts.map +1 -0
- package/dist/backup/drive.js +70 -0
- package/dist/backup/drive.js.map +1 -0
- package/dist/billing/tierStore.d.ts +59 -0
- package/dist/billing/tierStore.d.ts.map +1 -0
- package/dist/billing/tierStore.js +152 -0
- package/dist/billing/tierStore.js.map +1 -0
- package/dist/digest/activityDigest.d.ts +32 -0
- package/dist/digest/activityDigest.d.ts.map +1 -0
- package/dist/digest/activityDigest.js +299 -0
- package/dist/digest/activityDigest.js.map +1 -0
- package/dist/digest/digestCron.d.ts +40 -0
- package/dist/digest/digestCron.d.ts.map +1 -0
- package/dist/digest/digestCron.js +146 -0
- package/dist/digest/digestCron.js.map +1 -0
- package/dist/digest/digestPreferences.d.ts +25 -0
- package/dist/digest/digestPreferences.d.ts.map +1 -0
- package/dist/digest/digestPreferences.js +79 -0
- package/dist/digest/digestPreferences.js.map +1 -0
- package/dist/digest/emailSender.d.ts +20 -0
- package/dist/digest/emailSender.d.ts.map +1 -0
- package/dist/digest/emailSender.js +35 -0
- package/dist/digest/emailSender.js.map +1 -0
- package/dist/drive/client.d.ts +43 -0
- package/dist/drive/client.d.ts.map +1 -0
- package/dist/drive/client.js +282 -0
- package/dist/drive/client.js.map +1 -0
- package/dist/drive/errors.d.ts +27 -0
- package/dist/drive/errors.d.ts.map +1 -0
- package/dist/drive/errors.js +51 -0
- package/dist/drive/errors.js.map +1 -0
- package/dist/drive/fileCache.d.ts +22 -0
- package/dist/drive/fileCache.d.ts.map +1 -0
- package/dist/drive/fileCache.js +57 -0
- package/dist/drive/fileCache.js.map +1 -0
- package/dist/governance/accessControl.d.ts +87 -0
- package/dist/governance/accessControl.d.ts.map +1 -0
- package/dist/governance/accessControl.js +179 -0
- package/dist/governance/accessControl.js.map +1 -0
- package/dist/html/components.d.ts +8 -0
- package/dist/html/components.d.ts.map +1 -0
- package/dist/html/components.js +19 -0
- package/dist/html/components.js.map +1 -0
- package/dist/html/layout.d.ts +7 -0
- package/dist/html/layout.d.ts.map +1 -0
- package/dist/html/layout.js +24 -0
- package/dist/html/layout.js.map +1 -0
- package/dist/html/metricsUi.d.ts +8 -0
- package/dist/html/metricsUi.d.ts.map +1 -0
- package/dist/html/metricsUi.js +271 -0
- package/dist/html/metricsUi.js.map +1 -0
- package/dist/httpServer.d.ts +19 -0
- package/dist/httpServer.d.ts.map +1 -0
- package/dist/httpServer.js +3913 -0
- package/dist/httpServer.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs/asyncJobRegistry.d.ts +30 -0
- package/dist/jobs/asyncJobRegistry.d.ts.map +1 -0
- package/dist/jobs/asyncJobRegistry.js +70 -0
- package/dist/jobs/asyncJobRegistry.js.map +1 -0
- package/dist/observability/metricsQuery.d.ts +41 -0
- package/dist/observability/metricsQuery.d.ts.map +1 -0
- package/dist/observability/metricsQuery.js +106 -0
- package/dist/observability/metricsQuery.js.map +1 -0
- package/dist/observability/relevanceSignal.d.ts +26 -0
- package/dist/observability/relevanceSignal.d.ts.map +1 -0
- package/dist/observability/relevanceSignal.js +95 -0
- package/dist/observability/relevanceSignal.js.map +1 -0
- package/dist/observability/requestEvents.d.ts +31 -0
- package/dist/observability/requestEvents.d.ts.map +1 -0
- package/dist/observability/requestEvents.js +54 -0
- package/dist/observability/requestEvents.js.map +1 -0
- package/dist/observability/slowQueryAlert.d.ts +25 -0
- package/dist/observability/slowQueryAlert.d.ts.map +1 -0
- package/dist/observability/slowQueryAlert.js +67 -0
- package/dist/observability/slowQueryAlert.js.map +1 -0
- package/dist/observability/zeroResultTriage.d.ts +22 -0
- package/dist/observability/zeroResultTriage.d.ts.map +1 -0
- package/dist/observability/zeroResultTriage.js +116 -0
- package/dist/observability/zeroResultTriage.js.map +1 -0
- package/dist/search/embeddings.d.ts +31 -0
- package/dist/search/embeddings.d.ts.map +1 -0
- package/dist/search/embeddings.js +91 -0
- package/dist/search/embeddings.js.map +1 -0
- package/dist/search/fileWatcher.d.ts +28 -0
- package/dist/search/fileWatcher.d.ts.map +1 -0
- package/dist/search/fileWatcher.js +103 -0
- package/dist/search/fileWatcher.js.map +1 -0
- package/dist/search/hotQueryCache.d.ts +31 -0
- package/dist/search/hotQueryCache.d.ts.map +1 -0
- package/dist/search/hotQueryCache.js +103 -0
- package/dist/search/hotQueryCache.js.map +1 -0
- package/dist/search/postgresIndex.d.ts +439 -0
- package/dist/search/postgresIndex.d.ts.map +1 -0
- package/dist/search/postgresIndex.js +1610 -0
- package/dist/search/postgresIndex.js.map +1 -0
- package/dist/search/sqliteIndex.d.ts +66 -0
- package/dist/search/sqliteIndex.d.ts.map +1 -0
- package/dist/search/sqliteIndex.js +342 -0
- package/dist/search/sqliteIndex.js.map +1 -0
- package/dist/server.d.ts +43 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +532 -0
- package/dist/server.js.map +1 -0
- package/dist/session/bundle.d.ts +53 -0
- package/dist/session/bundle.d.ts.map +1 -0
- package/dist/session/bundle.js +97 -0
- package/dist/session/bundle.js.map +1 -0
- package/dist/storage/client.d.ts +157 -0
- package/dist/storage/client.d.ts.map +1 -0
- package/dist/storage/client.js +825 -0
- package/dist/storage/client.js.map +1 -0
- package/dist/tools/addWebhookPattern.d.ts +15 -0
- package/dist/tools/addWebhookPattern.d.ts.map +1 -0
- package/dist/tools/addWebhookPattern.js +15 -0
- package/dist/tools/addWebhookPattern.js.map +1 -0
- package/dist/tools/appendLog.d.ts +18 -0
- package/dist/tools/appendLog.d.ts.map +1 -0
- package/dist/tools/appendLog.js +18 -0
- package/dist/tools/appendLog.js.map +1 -0
- package/dist/tools/auditIndex.d.ts +15 -0
- package/dist/tools/auditIndex.d.ts.map +1 -0
- package/dist/tools/auditIndex.js +165 -0
- package/dist/tools/auditIndex.js.map +1 -0
- package/dist/tools/batchDeletePages.d.ts +18 -0
- package/dist/tools/batchDeletePages.d.ts.map +1 -0
- package/dist/tools/batchDeletePages.js +143 -0
- package/dist/tools/batchDeletePages.js.map +1 -0
- package/dist/tools/coerce.d.ts +3 -0
- package/dist/tools/coerce.d.ts.map +1 -0
- package/dist/tools/coerce.js +12 -0
- package/dist/tools/coerce.js.map +1 -0
- package/dist/tools/createPage.d.ts +24 -0
- package/dist/tools/createPage.d.ts.map +1 -0
- package/dist/tools/createPage.js +99 -0
- package/dist/tools/createPage.js.map +1 -0
- package/dist/tools/createPages.d.ts +51 -0
- package/dist/tools/createPages.d.ts.map +1 -0
- package/dist/tools/createPages.js +91 -0
- package/dist/tools/createPages.js.map +1 -0
- package/dist/tools/deletePage.d.ts +19 -0
- package/dist/tools/deletePage.d.ts.map +1 -0
- package/dist/tools/deletePage.js +127 -0
- package/dist/tools/deletePage.js.map +1 -0
- package/dist/tools/exportWiki.d.ts +48 -0
- package/dist/tools/exportWiki.d.ts.map +1 -0
- package/dist/tools/exportWiki.js +233 -0
- package/dist/tools/exportWiki.js.map +1 -0
- package/dist/tools/extractLinks.d.ts +14 -0
- package/dist/tools/extractLinks.d.ts.map +1 -0
- package/dist/tools/extractLinks.js +25 -0
- package/dist/tools/extractLinks.js.map +1 -0
- package/dist/tools/generateClaudeInstructions.d.ts +27 -0
- package/dist/tools/generateClaudeInstructions.d.ts.map +1 -0
- package/dist/tools/generateClaudeInstructions.js +263 -0
- package/dist/tools/generateClaudeInstructions.js.map +1 -0
- package/dist/tools/generateGptInstructions.d.ts +27 -0
- package/dist/tools/generateGptInstructions.d.ts.map +1 -0
- package/dist/tools/generateGptInstructions.js +208 -0
- package/dist/tools/generateGptInstructions.js.map +1 -0
- package/dist/tools/getBacklinks.d.ts +12 -0
- package/dist/tools/getBacklinks.d.ts.map +1 -0
- package/dist/tools/getBacklinks.js +13 -0
- package/dist/tools/getBacklinks.js.map +1 -0
- package/dist/tools/getRelated.d.ts +12 -0
- package/dist/tools/getRelated.d.ts.map +1 -0
- package/dist/tools/getRelated.js +13 -0
- package/dist/tools/getRelated.js.map +1 -0
- package/dist/tools/healthCheck.d.ts +5 -0
- package/dist/tools/healthCheck.d.ts.map +1 -0
- package/dist/tools/healthCheck.js +167 -0
- package/dist/tools/healthCheck.js.map +1 -0
- package/dist/tools/importBrainSource.d.ts +36 -0
- package/dist/tools/importBrainSource.d.ts.map +1 -0
- package/dist/tools/importBrainSource.js +314 -0
- package/dist/tools/importBrainSource.js.map +1 -0
- package/dist/tools/importWikiZip.d.ts +60 -0
- package/dist/tools/importWikiZip.d.ts.map +1 -0
- package/dist/tools/importWikiZip.js +379 -0
- package/dist/tools/importWikiZip.js.map +1 -0
- package/dist/tools/initProject.d.ts +34 -0
- package/dist/tools/initProject.d.ts.map +1 -0
- package/dist/tools/initProject.js +443 -0
- package/dist/tools/initProject.js.map +1 -0
- package/dist/tools/instructionContext.d.ts +60 -0
- package/dist/tools/instructionContext.d.ts.map +1 -0
- package/dist/tools/instructionContext.js +210 -0
- package/dist/tools/instructionContext.js.map +1 -0
- package/dist/tools/listArchivedPages.d.ts +17 -0
- package/dist/tools/listArchivedPages.d.ts.map +1 -0
- package/dist/tools/listArchivedPages.js +51 -0
- package/dist/tools/listArchivedPages.js.map +1 -0
- package/dist/tools/listPages.d.ts +28 -0
- package/dist/tools/listPages.d.ts.map +1 -0
- package/dist/tools/listPages.js +166 -0
- package/dist/tools/listPages.js.map +1 -0
- package/dist/tools/listWebhooks.d.ts +7 -0
- package/dist/tools/listWebhooks.d.ts.map +1 -0
- package/dist/tools/listWebhooks.js +10 -0
- package/dist/tools/listWebhooks.js.map +1 -0
- package/dist/tools/movePage.d.ts +18 -0
- package/dist/tools/movePage.d.ts.map +1 -0
- package/dist/tools/movePage.js +182 -0
- package/dist/tools/movePage.js.map +1 -0
- package/dist/tools/pageHistory.d.ts +36 -0
- package/dist/tools/pageHistory.d.ts.map +1 -0
- package/dist/tools/pageHistory.js +60 -0
- package/dist/tools/pageHistory.js.map +1 -0
- package/dist/tools/patchPage.d.ts +141 -0
- package/dist/tools/patchPage.d.ts.map +1 -0
- package/dist/tools/patchPage.js +287 -0
- package/dist/tools/patchPage.js.map +1 -0
- package/dist/tools/pullSessionBundle.d.ts +34 -0
- package/dist/tools/pullSessionBundle.d.ts.map +1 -0
- package/dist/tools/pullSessionBundle.js +432 -0
- package/dist/tools/pullSessionBundle.js.map +1 -0
- package/dist/tools/purgeWiki.d.ts +23 -0
- package/dist/tools/purgeWiki.d.ts.map +1 -0
- package/dist/tools/purgeWiki.js +113 -0
- package/dist/tools/purgeWiki.js.map +1 -0
- package/dist/tools/pushSessionBundle.d.ts +139 -0
- package/dist/tools/pushSessionBundle.d.ts.map +1 -0
- package/dist/tools/pushSessionBundle.js +282 -0
- package/dist/tools/pushSessionBundle.js.map +1 -0
- package/dist/tools/readGovernanceAudit.d.ts +17 -0
- package/dist/tools/readGovernanceAudit.d.ts.map +1 -0
- package/dist/tools/readGovernanceAudit.js +21 -0
- package/dist/tools/readGovernanceAudit.js.map +1 -0
- package/dist/tools/readPage.d.ts +13 -0
- package/dist/tools/readPage.d.ts.map +1 -0
- package/dist/tools/readPage.js +46 -0
- package/dist/tools/readPage.js.map +1 -0
- package/dist/tools/removeWebhook.d.ts +14 -0
- package/dist/tools/removeWebhook.d.ts.map +1 -0
- package/dist/tools/removeWebhook.js +12 -0
- package/dist/tools/removeWebhook.js.map +1 -0
- package/dist/tools/resolveProject.d.ts +58 -0
- package/dist/tools/resolveProject.d.ts.map +1 -0
- package/dist/tools/resolveProject.js +175 -0
- package/dist/tools/resolveProject.js.map +1 -0
- package/dist/tools/restorePage.d.ts +47 -0
- package/dist/tools/restorePage.d.ts.map +1 -0
- package/dist/tools/restorePage.js +111 -0
- package/dist/tools/restorePage.js.map +1 -0
- package/dist/tools/searchPages.d.ts +28 -0
- package/dist/tools/searchPages.d.ts.map +1 -0
- package/dist/tools/searchPages.js +372 -0
- package/dist/tools/searchPages.js.map +1 -0
- package/dist/tools/setWebhook.d.ts +30 -0
- package/dist/tools/setWebhook.d.ts.map +1 -0
- package/dist/tools/setWebhook.js +30 -0
- package/dist/tools/setWebhook.js.map +1 -0
- package/dist/tools/shareProject.d.ts +25 -0
- package/dist/tools/shareProject.d.ts.map +1 -0
- package/dist/tools/shareProject.js +56 -0
- package/dist/tools/shareProject.js.map +1 -0
- package/dist/tools/suggestLinks.d.ts +29 -0
- package/dist/tools/suggestLinks.d.ts.map +1 -0
- package/dist/tools/suggestLinks.js +214 -0
- package/dist/tools/suggestLinks.js.map +1 -0
- package/dist/tools/updatePage.d.ts +27 -0
- package/dist/tools/updatePage.d.ts.map +1 -0
- package/dist/tools/updatePage.js +118 -0
- package/dist/tools/updatePage.js.map +1 -0
- package/dist/webhooks/dispatch.d.ts +49 -0
- package/dist/webhooks/dispatch.d.ts.map +1 -0
- package/dist/webhooks/dispatch.js +159 -0
- package/dist/webhooks/dispatch.js.map +1 -0
- package/dist/webhooks/webhookRules.d.ts +34 -0
- package/dist/webhooks/webhookRules.d.ts.map +1 -0
- package/dist/webhooks/webhookRules.js +129 -0
- package/dist/webhooks/webhookRules.js.map +1 -0
- package/dist/wiki/frontmatter.d.ts +45 -0
- package/dist/wiki/frontmatter.d.ts.map +1 -0
- package/dist/wiki/frontmatter.js +68 -0
- package/dist/wiki/frontmatter.js.map +1 -0
- package/dist/wiki/index.d.ts +22 -0
- package/dist/wiki/index.d.ts.map +1 -0
- package/dist/wiki/index.js +203 -0
- package/dist/wiki/index.js.map +1 -0
- package/dist/wiki/ingestPolicy.d.ts +18 -0
- package/dist/wiki/ingestPolicy.d.ts.map +1 -0
- package/dist/wiki/ingestPolicy.js +64 -0
- package/dist/wiki/ingestPolicy.js.map +1 -0
- package/dist/wiki/layoutLint.d.ts +51 -0
- package/dist/wiki/layoutLint.d.ts.map +1 -0
- package/dist/wiki/layoutLint.js +146 -0
- package/dist/wiki/layoutLint.js.map +1 -0
- package/dist/wiki/links.d.ts +6 -0
- package/dist/wiki/links.d.ts.map +1 -0
- package/dist/wiki/links.js +45 -0
- package/dist/wiki/links.js.map +1 -0
- package/dist/wiki/log.d.ts +58 -0
- package/dist/wiki/log.d.ts.map +1 -0
- package/dist/wiki/log.js +126 -0
- package/dist/wiki/log.js.map +1 -0
- package/dist/wiki/path.d.ts +8 -0
- package/dist/wiki/path.d.ts.map +1 -0
- package/dist/wiki/path.js +25 -0
- package/dist/wiki/path.js.map +1 -0
- package/dist/wiki/storageLimits.d.ts +163 -0
- package/dist/wiki/storageLimits.d.ts.map +1 -0
- package/dist/wiki/storageLimits.js +281 -0
- package/dist/wiki/storageLimits.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { StorageClient } from "../storage/client.js";
|
|
2
|
+
import { type BillingTier } from "../billing/tierStore.js";
|
|
3
|
+
export declare const PAGE_LIMIT = 100;
|
|
4
|
+
export declare const STORAGE_LIMIT_BYTES: number;
|
|
5
|
+
/**
|
|
6
|
+
* Per-page size cap. 100 pages x 100 KB = the 10 MB total we advertise, so
|
|
7
|
+
* bounding each page locally gives the same guarantee the aggregate byte cap
|
|
8
|
+
* used to — without needing a total-bytes figure, which could only be had by
|
|
9
|
+
* listing every object in storage (GH #413).
|
|
10
|
+
*
|
|
11
|
+
* Sized against real usage: across all non-system pages in production, no
|
|
12
|
+
* account outside god mode has a page over 21 KB (p99 ~19 KB). 100 KB is ~5x
|
|
13
|
+
* the largest page any real user has written.
|
|
14
|
+
*/
|
|
15
|
+
export declare const PAGE_SIZE_LIMIT_BYTES: number;
|
|
16
|
+
export declare function isLimitEnforcementEnabled(): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Page allowance per billing tier, matching what the pricing page sells
|
|
19
|
+
* (`apps/web/src/components/Pricing.tsx`). `null` means uncapped.
|
|
20
|
+
*
|
|
21
|
+
* `free` is the post-beta allowance: 50. During beta the free allowance is 100,
|
|
22
|
+
* which is what `free_beta` carries — see BETA_FREE_PAGE_LIMIT below. Users who
|
|
23
|
+
* signed up during beta keep 100 permanently by holding a `free_beta` row, so
|
|
24
|
+
* ending beta changes what new signups get and nothing else.
|
|
25
|
+
*
|
|
26
|
+
* `launch_user` is the legacy name `src/admin/seedUsers.ts` writes and is
|
|
27
|
+
* treated as a beta-era account.
|
|
28
|
+
*/
|
|
29
|
+
export declare const TIER_PAGE_LIMITS: Record<BillingTier, number | null>;
|
|
30
|
+
/** Free allowance while the beta is running. */
|
|
31
|
+
export declare const BETA_FREE_PAGE_LIMIT = 100;
|
|
32
|
+
/** Free allowance once the beta has ended. */
|
|
33
|
+
export declare const POST_BETA_FREE_PAGE_LIMIT = 50;
|
|
34
|
+
/**
|
|
35
|
+
* Is the beta still running?
|
|
36
|
+
*
|
|
37
|
+
* Defaults to **true**: ending the beta must be a deliberate act, because it
|
|
38
|
+
* halves the free allowance. A missing or malformed env var therefore leaves
|
|
39
|
+
* users with the more generous limit rather than silently tightening it.
|
|
40
|
+
*/
|
|
41
|
+
export declare function isBetaActive(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Returns the free-tier page limit for a subject with no assigned tier.
|
|
44
|
+
* Returns null for god-mode subjects (unlimited).
|
|
45
|
+
*
|
|
46
|
+
* During beta this is 100; afterwards 50. Overridable with
|
|
47
|
+
* BRAINS_BETA_PAGE_LIMIT / BRAINS_FREE_PAGE_LIMIT respectively.
|
|
48
|
+
*
|
|
49
|
+
* **This no longer keys off how many pages the subject has written.** The
|
|
50
|
+
* previous implementation used `existingPageCount > 0` as a proxy for "is a
|
|
51
|
+
* beta user", which got it backwards: a genuine new signup during the beta has
|
|
52
|
+
* zero pages and was given 50 — the post-beta allowance — and then jumped to
|
|
53
|
+
* 100 the moment they saved their first page. The cap moved as a side effect of
|
|
54
|
+
* using the product, and the people it under-served were exactly the ones the
|
|
55
|
+
* beta was meant to be generous to (GH #473).
|
|
56
|
+
*
|
|
57
|
+
* `existingPageCount` is retained in the signature because callers already
|
|
58
|
+
* compute it and dropping it would churn them for nothing.
|
|
59
|
+
*
|
|
60
|
+
* This is the fallback used when a subject has no assigned tier. Callers that
|
|
61
|
+
* can await should prefer resolveTieredPageLimit(), which honours the tier.
|
|
62
|
+
*/
|
|
63
|
+
export declare function getPageLimit(subject: string, _existingPageCount: number): number | null;
|
|
64
|
+
/**
|
|
65
|
+
* Returns the per-page byte cap for a subject, or null when uncapped
|
|
66
|
+
* (god mode). Overridable via BRAINS_PAGE_SIZE_LIMIT_BYTES.
|
|
67
|
+
*/
|
|
68
|
+
export declare function getPageSizeLimit(subject: string): number | null;
|
|
69
|
+
export declare class PageSizeError extends Error {
|
|
70
|
+
readonly code: "PAGE_TOO_LARGE";
|
|
71
|
+
readonly size: number;
|
|
72
|
+
readonly limit: number;
|
|
73
|
+
constructor(name: string, size: number, limit: number);
|
|
74
|
+
toJSON(): {
|
|
75
|
+
ok: boolean;
|
|
76
|
+
error: "PAGE_TOO_LARGE";
|
|
77
|
+
message: string;
|
|
78
|
+
size: number;
|
|
79
|
+
limit: number;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Enforces the per-page size cap. Synchronous — no storage or DB call — so it
|
|
84
|
+
* adds nothing to write latency. No-op for god-mode subjects and for
|
|
85
|
+
* unattributed writes (api-key / connector-key modes, which have no quota).
|
|
86
|
+
*/
|
|
87
|
+
export declare function assertPageSize(subject: string, name: string, content: string): void;
|
|
88
|
+
/**
|
|
89
|
+
* Names the cheapest tier that would actually raise the caller's current limit.
|
|
90
|
+
*
|
|
91
|
+
* The old message hard-coded "Upgrade to Solo for 2,000 pages" for everyone,
|
|
92
|
+
* which told a Solo customer sitting at 2,000 pages to upgrade to the plan they
|
|
93
|
+
* were already on — and, before tiers were honoured at all, pointed everyone at
|
|
94
|
+
* an upgrade that raised nothing (GH #473).
|
|
95
|
+
*/
|
|
96
|
+
export declare function upgradeHint(limit: number): string;
|
|
97
|
+
export declare class PageLimitError extends Error {
|
|
98
|
+
readonly code: "LIMIT_EXCEEDED";
|
|
99
|
+
readonly current: number;
|
|
100
|
+
readonly limit: number;
|
|
101
|
+
constructor(current: number, limit: number);
|
|
102
|
+
toJSON(): {
|
|
103
|
+
ok: boolean;
|
|
104
|
+
error: "LIMIT_EXCEEDED";
|
|
105
|
+
message: string;
|
|
106
|
+
current: number;
|
|
107
|
+
limit: number;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Resolves a subject's page limit, honouring their assigned billing tier.
|
|
112
|
+
*
|
|
113
|
+
* Order matters. God mode wins outright, so an admin never has a lookup stand
|
|
114
|
+
* between them and a write. Otherwise an assigned tier decides, and only when
|
|
115
|
+
* there is no tier row do we fall back to the env-var defaults — which keeps
|
|
116
|
+
* every existing account on exactly the limit it had before tiers existed.
|
|
117
|
+
*
|
|
118
|
+
* A failed lookup is indistinguishable from "no tier assigned", deliberately:
|
|
119
|
+
* see the note in tierStore.ts on why a database that has not had the migration
|
|
120
|
+
* applied must degrade to the old behaviour rather than refuse writes.
|
|
121
|
+
*/
|
|
122
|
+
export declare function resolveTieredPageLimit(subject: string, existingPageCount: number): Promise<number | null>;
|
|
123
|
+
/**
|
|
124
|
+
* Checks the tier page limit for a subject before creating newPagesCount pages.
|
|
125
|
+
* No-op when subject is empty, Postgres is not configured, or the subject is in god mode.
|
|
126
|
+
* Throws PageLimitError when current + newPagesCount would exceed the limit.
|
|
127
|
+
*/
|
|
128
|
+
export declare function assertPageLimit(subject: string, newPagesCount: number): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Resolves the page limit context for a subject in a single Postgres query.
|
|
131
|
+
* Returns null limit for god-mode subjects or when Postgres is not configured.
|
|
132
|
+
* Use this when you need to check the limit multiple times (e.g. per create in a bundle),
|
|
133
|
+
* instead of calling assertPageLimit() per page which would query Postgres repeatedly.
|
|
134
|
+
*/
|
|
135
|
+
export declare function resolvePageLimitContext(subject: string): Promise<{
|
|
136
|
+
currentCount: number;
|
|
137
|
+
limit: number | null;
|
|
138
|
+
}>;
|
|
139
|
+
export declare class StorageLimitError extends Error {
|
|
140
|
+
readonly code: "STORAGE_LIMIT_EXCEEDED";
|
|
141
|
+
readonly limit: {
|
|
142
|
+
type: "pages" | "storage_bytes";
|
|
143
|
+
current: number;
|
|
144
|
+
max: number;
|
|
145
|
+
};
|
|
146
|
+
constructor(type: "pages" | "storage_bytes", current: number, max: number);
|
|
147
|
+
toJSON(): {
|
|
148
|
+
error: "STORAGE_LIMIT_EXCEEDED";
|
|
149
|
+
message: string;
|
|
150
|
+
limit: {
|
|
151
|
+
type: "pages" | "storage_bytes";
|
|
152
|
+
current: number;
|
|
153
|
+
max: number;
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Checks page count and total storage bytes against beta limits.
|
|
159
|
+
* No-op unless BRAINS_ENFORCE_LIMITS=true.
|
|
160
|
+
* Throws StorageLimitError when a limit is exceeded.
|
|
161
|
+
*/
|
|
162
|
+
export declare function assertWithinLimits(drive: StorageClient): Promise<void>;
|
|
163
|
+
//# sourceMappingURL=storageLimits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storageLimits.d.ts","sourceRoot":"","sources":["../../src/wiki/storageLimits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { getPostgresSearchIndex } from "../search/postgresIndex.js";
|
|
2
|
+
import { getTierStore } from "../billing/tierStore.js";
|
|
3
|
+
export const PAGE_LIMIT = 100;
|
|
4
|
+
export const STORAGE_LIMIT_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
5
|
+
/**
|
|
6
|
+
* Per-page size cap. 100 pages x 100 KB = the 10 MB total we advertise, so
|
|
7
|
+
* bounding each page locally gives the same guarantee the aggregate byte cap
|
|
8
|
+
* used to — without needing a total-bytes figure, which could only be had by
|
|
9
|
+
* listing every object in storage (GH #413).
|
|
10
|
+
*
|
|
11
|
+
* Sized against real usage: across all non-system pages in production, no
|
|
12
|
+
* account outside god mode has a page over 21 KB (p99 ~19 KB). 100 KB is ~5x
|
|
13
|
+
* the largest page any real user has written.
|
|
14
|
+
*/
|
|
15
|
+
export const PAGE_SIZE_LIMIT_BYTES = 100 * 1024; // 100 KB
|
|
16
|
+
export function isLimitEnforcementEnabled() {
|
|
17
|
+
return (process.env.BRAINS_ENFORCE_LIMITS ?? "").trim().toLowerCase() === "true";
|
|
18
|
+
}
|
|
19
|
+
// ── Tier-based page limits ───────────────────────────────────────────────────
|
|
20
|
+
/**
|
|
21
|
+
* Page allowance per billing tier, matching what the pricing page sells
|
|
22
|
+
* (`apps/web/src/components/Pricing.tsx`). `null` means uncapped.
|
|
23
|
+
*
|
|
24
|
+
* `free` is the post-beta allowance: 50. During beta the free allowance is 100,
|
|
25
|
+
* which is what `free_beta` carries — see BETA_FREE_PAGE_LIMIT below. Users who
|
|
26
|
+
* signed up during beta keep 100 permanently by holding a `free_beta` row, so
|
|
27
|
+
* ending beta changes what new signups get and nothing else.
|
|
28
|
+
*
|
|
29
|
+
* `launch_user` is the legacy name `src/admin/seedUsers.ts` writes and is
|
|
30
|
+
* treated as a beta-era account.
|
|
31
|
+
*/
|
|
32
|
+
export const TIER_PAGE_LIMITS = {
|
|
33
|
+
free: 50,
|
|
34
|
+
solo: 2_000,
|
|
35
|
+
pro: 10_000,
|
|
36
|
+
unlimited: null,
|
|
37
|
+
free_beta: 100,
|
|
38
|
+
launch_user: 100,
|
|
39
|
+
};
|
|
40
|
+
/** Free allowance while the beta is running. */
|
|
41
|
+
export const BETA_FREE_PAGE_LIMIT = 100;
|
|
42
|
+
/** Free allowance once the beta has ended. */
|
|
43
|
+
export const POST_BETA_FREE_PAGE_LIMIT = 50;
|
|
44
|
+
/**
|
|
45
|
+
* Is the beta still running?
|
|
46
|
+
*
|
|
47
|
+
* Defaults to **true**: ending the beta must be a deliberate act, because it
|
|
48
|
+
* halves the free allowance. A missing or malformed env var therefore leaves
|
|
49
|
+
* users with the more generous limit rather than silently tightening it.
|
|
50
|
+
*/
|
|
51
|
+
export function isBetaActive() {
|
|
52
|
+
return (process.env.BRAINS_BETA_ACTIVE ?? "true").trim().toLowerCase() !== "false";
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Returns the free-tier page limit for a subject with no assigned tier.
|
|
56
|
+
* Returns null for god-mode subjects (unlimited).
|
|
57
|
+
*
|
|
58
|
+
* During beta this is 100; afterwards 50. Overridable with
|
|
59
|
+
* BRAINS_BETA_PAGE_LIMIT / BRAINS_FREE_PAGE_LIMIT respectively.
|
|
60
|
+
*
|
|
61
|
+
* **This no longer keys off how many pages the subject has written.** The
|
|
62
|
+
* previous implementation used `existingPageCount > 0` as a proxy for "is a
|
|
63
|
+
* beta user", which got it backwards: a genuine new signup during the beta has
|
|
64
|
+
* zero pages and was given 50 — the post-beta allowance — and then jumped to
|
|
65
|
+
* 100 the moment they saved their first page. The cap moved as a side effect of
|
|
66
|
+
* using the product, and the people it under-served were exactly the ones the
|
|
67
|
+
* beta was meant to be generous to (GH #473).
|
|
68
|
+
*
|
|
69
|
+
* `existingPageCount` is retained in the signature because callers already
|
|
70
|
+
* compute it and dropping it would churn them for nothing.
|
|
71
|
+
*
|
|
72
|
+
* This is the fallback used when a subject has no assigned tier. Callers that
|
|
73
|
+
* can await should prefer resolveTieredPageLimit(), which honours the tier.
|
|
74
|
+
*/
|
|
75
|
+
export function getPageLimit(subject, _existingPageCount) {
|
|
76
|
+
const godModeSubjects = (process.env.BRAINS_GOD_MODE_SUBJECTS ?? "")
|
|
77
|
+
.split(",").map((s) => s.trim()).filter(Boolean);
|
|
78
|
+
if (godModeSubjects.includes(subject))
|
|
79
|
+
return null;
|
|
80
|
+
const beta = isBetaActive();
|
|
81
|
+
const raw = parseInt(beta
|
|
82
|
+
? (process.env.BRAINS_BETA_PAGE_LIMIT ?? String(BETA_FREE_PAGE_LIMIT))
|
|
83
|
+
: (process.env.BRAINS_FREE_PAGE_LIMIT ?? String(POST_BETA_FREE_PAGE_LIMIT)), 10);
|
|
84
|
+
return Number.isFinite(raw) && raw > 0
|
|
85
|
+
? raw
|
|
86
|
+
: beta ? BETA_FREE_PAGE_LIMIT : POST_BETA_FREE_PAGE_LIMIT;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Returns the per-page byte cap for a subject, or null when uncapped
|
|
90
|
+
* (god mode). Overridable via BRAINS_PAGE_SIZE_LIMIT_BYTES.
|
|
91
|
+
*/
|
|
92
|
+
export function getPageSizeLimit(subject) {
|
|
93
|
+
const godModeSubjects = (process.env.BRAINS_GOD_MODE_SUBJECTS ?? "")
|
|
94
|
+
.split(",").map((s) => s.trim()).filter(Boolean);
|
|
95
|
+
if (godModeSubjects.includes(subject))
|
|
96
|
+
return null;
|
|
97
|
+
const raw = parseInt(process.env.BRAINS_PAGE_SIZE_LIMIT_BYTES ?? "", 10);
|
|
98
|
+
return Number.isFinite(raw) && raw > 0 ? raw : PAGE_SIZE_LIMIT_BYTES;
|
|
99
|
+
}
|
|
100
|
+
export class PageSizeError extends Error {
|
|
101
|
+
code = "PAGE_TOO_LARGE";
|
|
102
|
+
size;
|
|
103
|
+
limit;
|
|
104
|
+
constructor(name, size, limit) {
|
|
105
|
+
super(`'${name}' is ${Math.round(size / 1024)} KB, over the ${Math.round(limit / 1024)} KB per-page limit. ` +
|
|
106
|
+
`Split it into smaller linked pages.`);
|
|
107
|
+
this.name = "PageSizeError";
|
|
108
|
+
this.size = size;
|
|
109
|
+
this.limit = limit;
|
|
110
|
+
}
|
|
111
|
+
toJSON() {
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
error: this.code,
|
|
115
|
+
message: this.message,
|
|
116
|
+
size: this.size,
|
|
117
|
+
limit: this.limit,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Enforces the per-page size cap. Synchronous — no storage or DB call — so it
|
|
123
|
+
* adds nothing to write latency. No-op for god-mode subjects and for
|
|
124
|
+
* unattributed writes (api-key / connector-key modes, which have no quota).
|
|
125
|
+
*/
|
|
126
|
+
export function assertPageSize(subject, name, content) {
|
|
127
|
+
if (!subject)
|
|
128
|
+
return;
|
|
129
|
+
const limit = getPageSizeLimit(subject);
|
|
130
|
+
if (limit === null)
|
|
131
|
+
return; // god mode
|
|
132
|
+
const size = Buffer.byteLength(content, "utf8");
|
|
133
|
+
if (size > limit) {
|
|
134
|
+
throw new PageSizeError(name, size, limit);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Names the cheapest tier that would actually raise the caller's current limit.
|
|
139
|
+
*
|
|
140
|
+
* The old message hard-coded "Upgrade to Solo for 2,000 pages" for everyone,
|
|
141
|
+
* which told a Solo customer sitting at 2,000 pages to upgrade to the plan they
|
|
142
|
+
* were already on — and, before tiers were honoured at all, pointed everyone at
|
|
143
|
+
* an upgrade that raised nothing (GH #473).
|
|
144
|
+
*/
|
|
145
|
+
export function upgradeHint(limit) {
|
|
146
|
+
const next = ["solo", "pro", "unlimited"]
|
|
147
|
+
.map((tier) => ({ tier, cap: TIER_PAGE_LIMITS[tier] }))
|
|
148
|
+
.find(({ cap }) => cap === null || cap > limit);
|
|
149
|
+
if (!next)
|
|
150
|
+
return "You are on the highest plan — remove some pages to continue.";
|
|
151
|
+
const name = next.tier === "unlimited" ? "Unlimited" : next.tier === "pro" ? "Pro" : "Solo";
|
|
152
|
+
return next.cap === null
|
|
153
|
+
? `Upgrade to ${name} for unlimited pages.`
|
|
154
|
+
: `Upgrade to ${name} for ${next.cap.toLocaleString("en-US")} pages.`;
|
|
155
|
+
}
|
|
156
|
+
export class PageLimitError extends Error {
|
|
157
|
+
code = "LIMIT_EXCEEDED";
|
|
158
|
+
current;
|
|
159
|
+
limit;
|
|
160
|
+
constructor(current, limit) {
|
|
161
|
+
super(`Page limit reached (${limit} pages). ${upgradeHint(limit)}`);
|
|
162
|
+
this.name = "PageLimitError";
|
|
163
|
+
this.current = current;
|
|
164
|
+
this.limit = limit;
|
|
165
|
+
}
|
|
166
|
+
toJSON() {
|
|
167
|
+
return {
|
|
168
|
+
ok: false,
|
|
169
|
+
error: this.code,
|
|
170
|
+
message: this.message,
|
|
171
|
+
current: this.current,
|
|
172
|
+
limit: this.limit,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Resolves a subject's page limit, honouring their assigned billing tier.
|
|
178
|
+
*
|
|
179
|
+
* Order matters. God mode wins outright, so an admin never has a lookup stand
|
|
180
|
+
* between them and a write. Otherwise an assigned tier decides, and only when
|
|
181
|
+
* there is no tier row do we fall back to the env-var defaults — which keeps
|
|
182
|
+
* every existing account on exactly the limit it had before tiers existed.
|
|
183
|
+
*
|
|
184
|
+
* A failed lookup is indistinguishable from "no tier assigned", deliberately:
|
|
185
|
+
* see the note in tierStore.ts on why a database that has not had the migration
|
|
186
|
+
* applied must degrade to the old behaviour rather than refuse writes.
|
|
187
|
+
*/
|
|
188
|
+
export async function resolveTieredPageLimit(subject, existingPageCount) {
|
|
189
|
+
const envLimit = getPageLimit(subject, existingPageCount);
|
|
190
|
+
if (envLimit === null)
|
|
191
|
+
return null; // god mode — no lookup needed
|
|
192
|
+
const tier = await getTierStore().get(subject);
|
|
193
|
+
if (tier === null)
|
|
194
|
+
return envLimit;
|
|
195
|
+
return TIER_PAGE_LIMITS[tier];
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Checks the tier page limit for a subject before creating newPagesCount pages.
|
|
199
|
+
* No-op when subject is empty, Postgres is not configured, or the subject is in god mode.
|
|
200
|
+
* Throws PageLimitError when current + newPagesCount would exceed the limit.
|
|
201
|
+
*/
|
|
202
|
+
export async function assertPageLimit(subject, newPagesCount) {
|
|
203
|
+
if (!subject)
|
|
204
|
+
return;
|
|
205
|
+
const pgIndex = getPostgresSearchIndex();
|
|
206
|
+
if (!pgIndex.isConfigured())
|
|
207
|
+
return;
|
|
208
|
+
const currentCount = await pgIndex.countActivePages(subject);
|
|
209
|
+
const limit = await resolveTieredPageLimit(subject, currentCount);
|
|
210
|
+
if (limit === null)
|
|
211
|
+
return; // god mode or unlimited tier
|
|
212
|
+
if (currentCount + newPagesCount > limit) {
|
|
213
|
+
throw new PageLimitError(currentCount, limit);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Resolves the page limit context for a subject in a single Postgres query.
|
|
218
|
+
* Returns null limit for god-mode subjects or when Postgres is not configured.
|
|
219
|
+
* Use this when you need to check the limit multiple times (e.g. per create in a bundle),
|
|
220
|
+
* instead of calling assertPageLimit() per page which would query Postgres repeatedly.
|
|
221
|
+
*/
|
|
222
|
+
export async function resolvePageLimitContext(subject) {
|
|
223
|
+
if (!subject)
|
|
224
|
+
return { currentCount: 0, limit: null };
|
|
225
|
+
const pgIndex = getPostgresSearchIndex();
|
|
226
|
+
if (!pgIndex.isConfigured())
|
|
227
|
+
return { currentCount: 0, limit: null };
|
|
228
|
+
const currentCount = await pgIndex.countActivePages(subject);
|
|
229
|
+
const limit = await resolveTieredPageLimit(subject, currentCount);
|
|
230
|
+
return { currentCount, limit };
|
|
231
|
+
}
|
|
232
|
+
export class StorageLimitError extends Error {
|
|
233
|
+
code;
|
|
234
|
+
limit;
|
|
235
|
+
constructor(type, current, max) {
|
|
236
|
+
const message = type === "pages"
|
|
237
|
+
? `You've reached the ${max}-page limit for this brain. Remove some pages or start a new brain with a separate email to continue.`
|
|
238
|
+
: `You've reached the ${Math.round(max / 1024 / 1024)}MB storage limit for this brain. Remove some pages to continue.`;
|
|
239
|
+
super(message);
|
|
240
|
+
this.name = "StorageLimitError";
|
|
241
|
+
this.code = "STORAGE_LIMIT_EXCEEDED";
|
|
242
|
+
this.limit = { type, current, max };
|
|
243
|
+
}
|
|
244
|
+
toJSON() {
|
|
245
|
+
return {
|
|
246
|
+
error: this.code,
|
|
247
|
+
message: this.message,
|
|
248
|
+
limit: this.limit,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Checks page count and total storage bytes against beta limits.
|
|
254
|
+
* No-op unless BRAINS_ENFORCE_LIMITS=true.
|
|
255
|
+
* Throws StorageLimitError when a limit is exceeded.
|
|
256
|
+
*/
|
|
257
|
+
export async function assertWithinLimits(drive) {
|
|
258
|
+
if (!isLimitEnforcementEnabled())
|
|
259
|
+
return;
|
|
260
|
+
// Postgres-backed deployments never take the listing path: page count is
|
|
261
|
+
// enforced by assertPageLimit() (a single count=exact query, and the tiered
|
|
262
|
+
// per-subject limit is the one that actually governs), and total bytes are
|
|
263
|
+
// bounded by assertPageSize()'s per-page cap.
|
|
264
|
+
//
|
|
265
|
+
// drive.listFiles() walks Supabase Storage one HTTP request per folder — 468
|
|
266
|
+
// round trips on a 398-folder wiki — and unlike the index rebuild it was
|
|
267
|
+
// awaited before any work began, putting ~1.5s directly into every
|
|
268
|
+
// create_page call (GH #413).
|
|
269
|
+
if (getPostgresSearchIndex().isConfigured())
|
|
270
|
+
return;
|
|
271
|
+
const files = await drive.listFiles();
|
|
272
|
+
const pageCount = files.length;
|
|
273
|
+
const totalBytes = files.reduce((sum, f) => sum + (f.size ?? 0), 0);
|
|
274
|
+
if (pageCount >= PAGE_LIMIT) {
|
|
275
|
+
throw new StorageLimitError("pages", pageCount, PAGE_LIMIT);
|
|
276
|
+
}
|
|
277
|
+
if (totalBytes >= STORAGE_LIMIT_BYTES) {
|
|
278
|
+
throw new StorageLimitError("storage_bytes", totalBytes, STORAGE_LIMIT_BYTES);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=storageLimits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storageLimits.js","sourceRoot":"","sources":["../../src/wiki/storageLimits.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "brains-mcp",
|
|
3
|
+
"version": "1.61.2",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/spacecowboyian/brains.git"
|
|
7
|
+
},
|
|
8
|
+
"description": "Personal wiki and memory MCP server for AI assistants — store, search, and recall structured notes from Claude and ChatGPT.",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"!dist/editor",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"start": "node dist/index.js",
|
|
19
|
+
"dev": "tsx watch src/index.ts",
|
|
20
|
+
"bench:search": "npm run build && node scripts/benchmark-search.mjs",
|
|
21
|
+
"migrate": "node scripts/apply-migrations.mjs",
|
|
22
|
+
"bench:longmemeval": "tsx benchmark/longmemeval/run.ts",
|
|
23
|
+
"bench:longmemeval:scheduled": "bash benchmark/longmemeval/bench.sh",
|
|
24
|
+
"smoke:api": "node scripts/smoke-api.mjs",
|
|
25
|
+
"migrate:storage": "node scripts/migrate-storage-to-supabase.mjs",
|
|
26
|
+
"populate:index": "node scripts/populate-pages-index.mjs",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"lint": "eslint src tests --ext .ts",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"commitlint": "commitlint --edit",
|
|
32
|
+
"release": "semantic-release",
|
|
33
|
+
"release:dry": "semantic-release --dry-run --no-ci",
|
|
34
|
+
"prepare": "husky",
|
|
35
|
+
"bench:convomem": "tsx benchmark/convomem/run.ts",
|
|
36
|
+
"bench:locomo": "tsx benchmark/locomo/run.ts",
|
|
37
|
+
"bench:qa-judge": "tsx benchmark/longmemeval/qa-judge.ts",
|
|
38
|
+
"bench:locomo:qa": "tsx benchmark/locomo/qa-judge.ts",
|
|
39
|
+
"bench:convomem:qa": "tsx benchmark/convomem/qa-judge.ts",
|
|
40
|
+
"backfill:embeddings": "node scripts/backfill-embeddings.mjs",
|
|
41
|
+
"bench:convomem:diag": "tsx benchmark/convomem/diag-scale.ts",
|
|
42
|
+
"bench:brains-native": "tsx benchmark/brains-native/run.ts",
|
|
43
|
+
"bench:brains-native:qa": "BENCH_MODE=qa tsx benchmark/brains-native/run.ts",
|
|
44
|
+
"bench:brains-native:generate": "tsx benchmark/brains-native/generate-queries.ts"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@modelcontextprotocol/sdk": "^1.10.0",
|
|
48
|
+
"adm-zip": "^0.5.17",
|
|
49
|
+
"better-sqlite3": "^11.10.0",
|
|
50
|
+
"chokidar": "^4.0.3",
|
|
51
|
+
"googleapis": "^144.0.0",
|
|
52
|
+
"gray-matter": "^4.0.3",
|
|
53
|
+
"openai": "^6.44.0",
|
|
54
|
+
"zod": "^3.23.8"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@commitlint/cli": "^20.5.0",
|
|
58
|
+
"@commitlint/config-conventional": "^20.5.0",
|
|
59
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
60
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
61
|
+
"@semantic-release/git": "^10.0.1",
|
|
62
|
+
"@semantic-release/github": "^12.0.8",
|
|
63
|
+
"@semantic-release/npm": "^13.1.5",
|
|
64
|
+
"@semantic-release/release-notes-generator": "^14.1.1",
|
|
65
|
+
"@types/adm-zip": "^0.5.8",
|
|
66
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
67
|
+
"@types/node": "^20.14.0",
|
|
68
|
+
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
69
|
+
"@typescript-eslint/parser": "^7.0.0",
|
|
70
|
+
"conventional-changelog-conventionalcommits": "^9.3.1",
|
|
71
|
+
"eslint": "^8.57.0",
|
|
72
|
+
"husky": "^9.1.7",
|
|
73
|
+
"semantic-release": "^25.0.3",
|
|
74
|
+
"tsx": "^4.15.0",
|
|
75
|
+
"typescript": "^5.4.5",
|
|
76
|
+
"vitest": "^1.6.0"
|
|
77
|
+
},
|
|
78
|
+
"engines": {
|
|
79
|
+
"node": ">=20"
|
|
80
|
+
}
|
|
81
|
+
}
|