From 36537c83266afabe08774b7ef83703bf5a0ccaba Mon Sep 17 00:00:00 2001 From: Utkarsh Date: Mon, 9 Mar 2026 23:30:36 +0530 Subject: [PATCH] fix(ts-sdk): replace sqlite3 with better-sqlite3 to fix native binding resolution (#4270) --- docs/changelog.mdx | 17 + mem0-ts/package.json | 10 +- mem0-ts/pnpm-lock.yaml | 794 +----------------- mem0-ts/src/oss/package.json | 3 +- mem0-ts/src/oss/src/storage/SQLiteManager.ts | 70 +- .../tests/better-sqlite3-migration.test.ts | 377 +++++++++ mem0-ts/src/oss/src/vector_stores/memory.ts | 130 ++- mem0-ts/tsup.config.ts | 2 +- 8 files changed, 515 insertions(+), 888 deletions(-) create mode 100644 mem0-ts/src/oss/src/tests/better-sqlite3-migration.test.ts diff --git a/docs/changelog.mdx b/docs/changelog.mdx index 1bd729cbc..bf55b3510 100644 --- a/docs/changelog.mdx +++ b/docs/changelog.mdx @@ -729,6 +729,23 @@ mode: "wide" + + +**Breaking Changes:** +- **Dependencies:** Minimum Node.js version for OSS sqlite features is now Node 20+ (due to `better-sqlite3` v12) + +**Bug Fixes:** +- **OSS Storage:** Replaced `sqlite3` with `better-sqlite3` to fix native binding resolution failures under jiti-based loaders (e.g. OpenClaw plugin system). Fixes issues where the `bindings` module walked V8 stack frames with synthetic filenames, failing to locate the native `.node` addon. +- **OSS Storage:** Fixed async init race condition in `SQLiteManager` — `init()` is now synchronous +- **OSS Vector Store:** Migrated `MemoryVectorStore` from `sqlite3` to `better-sqlite3` with transactional batch inserts + +**Improvements:** +- **Performance:** Cached prepared statements in `SQLiteManager` for faster history operations +- **Performance:** Batch `insert()` in `MemoryVectorStore` wrapped in a transaction for atomicity +- **Build:** Updated `tsup.config.ts` externals from `sqlite3` to `better-sqlite3` + + + **New Features & Updates:** diff --git a/mem0-ts/package.json b/mem0-ts/package.json index af195ad40..4a54d8f71 100644 --- a/mem0-ts/package.json +++ b/mem0-ts/package.json @@ -1,6 +1,6 @@ { "name": "mem0ai", - "version": "2.2.4", + "version": "2.3.0", "description": "The Memory Layer For Your AI Apps", "main": "./dist/index.js", "module": "./dist/index.mjs", @@ -77,6 +77,7 @@ "author": "Deshraj Yadav", "license": "Apache-2.0", "devDependencies": { + "@types/better-sqlite3": "^7.6.13", "@types/node": "^22.7.6", "@types/uuid": "^9.0.8", "dotenv": "^16.4.5", @@ -108,14 +109,13 @@ "@supabase/supabase-js": "^2.49.1", "@types/jest": "29.5.14", "@types/pg": "8.11.0", - "@types/sqlite3": "3.1.11", + "better-sqlite3": "^12.6.2", "cloudflare": "^4.2.0", "groq-sdk": "0.3.0", "neo4j-driver": "^5.28.1", "ollama": "^0.5.14", "pg": "8.11.3", - "redis": "^4.6.13", - "sqlite3": "5.1.7" + "redis": "^4.6.13" }, "engines": { "node": ">=18" @@ -127,7 +127,7 @@ "pnpm": { "onlyBuiltDependencies": [ "esbuild", - "sqlite3" + "better-sqlite3" ] } } diff --git a/mem0-ts/pnpm-lock.yaml b/mem0-ts/pnpm-lock.yaml index 39bf21201..b964b207f 100644 --- a/mem0-ts/pnpm-lock.yaml +++ b/mem0-ts/pnpm-lock.yaml @@ -40,12 +40,12 @@ importers: "@types/pg": specifier: 8.11.0 version: 8.11.0 - "@types/sqlite3": - specifier: 3.1.11 - version: 3.1.11 axios: specifier: 1.13.6 version: 1.13.6 + better-sqlite3: + specifier: ^12.6.2 + version: 12.6.2 cloudflare: specifier: ^4.2.0 version: 4.3.0(encoding@0.1.13) @@ -67,9 +67,6 @@ importers: redis: specifier: ^4.6.13 version: 4.7.0 - sqlite3: - specifier: 5.1.7 - version: 5.1.7 uuid: specifier: 9.0.1 version: 9.0.1 @@ -77,6 +74,9 @@ importers: specifier: ^3.24.1 version: 3.24.2 devDependencies: + "@types/better-sqlite3": + specifier: ^7.6.13 + version: 7.6.13 "@types/node": specifier: ^22.7.6 version: 22.13.5 @@ -740,12 +740,6 @@ packages: } engines: { node: ">=14" } - "@gar/promisify@1.1.3": - resolution: - { - integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==, - } - "@google/genai@1.2.0": resolution: { @@ -966,20 +960,6 @@ packages: } engines: { node: ">= 8" } - "@npmcli/fs@1.1.1": - resolution: - { - integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==, - } - - "@npmcli/move-file@1.1.2": - resolution: - { - integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==, - } - engines: { node: ">=10" } - deprecated: This functionality has been moved to @npmcli/fs - "@pkgjs/parseargs@0.11.0": resolution: { @@ -1277,13 +1257,6 @@ packages: integrity: sha512-lKaptKQB5/juEF5+jzmBeZlz69MdHZuxf+0f50NwhL+IE//m4ZnOeWlsKRjjsM0fVayZiQKqLvYdBn0RLkhGiQ==, } - "@tootallnate/once@1.1.2": - resolution: - { - integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==, - } - engines: { node: ">= 6" } - "@tsconfig/node10@1.0.11": resolution: { @@ -1332,6 +1305,12 @@ packages: integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==, } + "@types/better-sqlite3@7.6.13": + resolution: + { + integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==, + } + "@types/estree@1.0.6": resolution: { @@ -1410,12 +1389,6 @@ packages: integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==, } - "@types/sqlite3@3.1.11": - resolution: - { - integrity: sha512-KYF+QgxAnnAh7DWPdNDroxkDI3/MspH1NMx6m/N/6fT1G6+jvsw4/ZePt8R8cr7ta58aboeTfYFBDxTJ5yv15w==, - } - "@types/stack-utils@2.0.3": resolution: { @@ -1459,12 +1432,6 @@ packages: } engines: { node: ">=20.0.0" } - abbrev@1.1.1: - resolution: - { - integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==, - } - abort-controller@3.0.0: resolution: { @@ -1494,13 +1461,6 @@ packages: engines: { node: ">=0.4.0" } hasBin: true - agent-base@6.0.2: - resolution: - { - integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==, - } - engines: { node: ">= 6.0.0" } - agent-base@7.1.3: resolution: { @@ -1515,13 +1475,6 @@ packages: } engines: { node: ">= 8.0.0" } - aggregate-error@3.1.0: - resolution: - { - integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==, - } - engines: { node: ">=8" } - ajv@6.12.6: resolution: { @@ -1583,20 +1536,6 @@ packages: } engines: { node: ">= 8" } - aproba@2.0.0: - resolution: - { - integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==, - } - - are-we-there-yet@3.0.1: - resolution: - { - integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==, - } - engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } - deprecated: This package is no longer supported. - arg@4.1.3: resolution: { @@ -1685,6 +1624,13 @@ packages: integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, } + better-sqlite3@12.6.2: + resolution: + { + integrity: sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==, + } + engines: { node: 20.x || 22.x || 23.x || 24.x || 25.x } + bignumber.js@9.2.0: resolution: { @@ -1819,13 +1765,6 @@ packages: } engines: { node: ">=8" } - cacache@15.3.0: - resolution: - { - integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==, - } - engines: { node: ">= 10" } - call-bind-apply-helpers@1.0.2: resolution: { @@ -1907,13 +1846,6 @@ packages: integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==, } - chownr@2.0.0: - resolution: - { - integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==, - } - engines: { node: ">=10" } - ci-info@3.9.0: resolution: { @@ -1927,13 +1859,6 @@ packages: integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==, } - clean-stack@2.2.0: - resolution: - { - integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==, - } - engines: { node: ">=6" } - cliui@8.0.1: resolution: { @@ -1980,13 +1905,6 @@ packages: integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, } - color-support@1.1.3: - resolution: - { - integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==, - } - hasBin: true - combined-stream@1.0.8: resolution: { @@ -2014,12 +1932,6 @@ packages: } engines: { node: ^14.18.0 || >=16.10.0 } - console-control-strings@1.1.0: - resolution: - { - integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==, - } - console-table-printer@2.12.1: resolution: { @@ -2173,12 +2085,6 @@ packages: } engines: { node: ">=0.4.0" } - delegates@1.0.0: - resolution: - { - integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==, - } - depd@2.0.0: resolution: { @@ -2304,19 +2210,6 @@ packages: integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==, } - env-paths@2.2.1: - resolution: - { - integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==, - } - engines: { node: ">=6" } - - err-code@2.0.3: - resolution: - { - integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==, - } - error-ex@1.3.2: resolution: { @@ -2626,13 +2519,6 @@ packages: integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==, } - fs-minipass@2.1.0: - resolution: - { - integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==, - } - engines: { node: ">= 8" } - fs.realpath@1.0.0: resolution: { @@ -2653,14 +2539,6 @@ packages: integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, } - gauge@4.0.4: - resolution: - { - integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==, - } - engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } - deprecated: This package is no longer supported. - gaxios@6.7.1: resolution: { @@ -2826,12 +2704,6 @@ packages: } engines: { node: ">= 0.4" } - has-unicode@2.0.1: - resolution: - { - integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==, - } - hasown@2.0.2: resolution: { @@ -2852,12 +2724,6 @@ packages: integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==, } - http-cache-semantics@4.1.1: - resolution: - { - integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==, - } - http-errors@2.0.0: resolution: { @@ -2865,13 +2731,6 @@ packages: } engines: { node: ">= 0.8" } - http-proxy-agent@4.0.1: - resolution: - { - integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==, - } - engines: { node: ">= 6" } - http-proxy-agent@7.0.2: resolution: { @@ -2879,13 +2738,6 @@ packages: } engines: { node: ">= 14" } - https-proxy-agent@5.0.1: - resolution: - { - integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==, - } - engines: { node: ">= 6" } - https-proxy-agent@7.0.6: resolution: { @@ -2940,19 +2792,6 @@ packages: } engines: { node: ">=0.8.19" } - indent-string@4.0.0: - resolution: - { - integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, - } - engines: { node: ">=8" } - - infer-owner@1.0.4: - resolution: - { - integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==, - } - inflight@1.0.6: resolution: { @@ -2972,13 +2811,6 @@ packages: integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, } - ip-address@9.0.5: - resolution: - { - integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==, - } - engines: { node: ">= 12" } - ipaddr.js@1.9.1: resolution: { @@ -3056,12 +2888,6 @@ packages: engines: { node: ">=14.16" } hasBin: true - is-lambda@1.0.1: - resolution: - { - integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==, - } - is-number@7.0.0: resolution: { @@ -3384,12 +3210,6 @@ packages: } hasBin: true - jsbn@1.1.0: - resolution: - { - integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==, - } - jsesc@3.1.0: resolution: { @@ -3593,13 +3413,6 @@ packages: integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, } - lru-cache@6.0.0: - resolution: - { - integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, - } - engines: { node: ">=10" } - make-dir@4.0.0: resolution: { @@ -3613,13 +3426,6 @@ packages: integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==, } - make-fetch-happen@9.1.0: - resolution: - { - integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==, - } - engines: { node: ">= 10" } - makeerror@1.0.12: resolution: { @@ -3741,55 +3547,6 @@ packages: integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, } - minipass-collect@1.0.2: - resolution: - { - integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==, - } - engines: { node: ">= 8" } - - minipass-fetch@1.4.1: - resolution: - { - integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==, - } - engines: { node: ">=8" } - - minipass-flush@1.0.5: - resolution: - { - integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==, - } - engines: { node: ">= 8" } - - minipass-pipeline@1.2.4: - resolution: - { - integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==, - } - engines: { node: ">=8" } - - minipass-sized@1.0.3: - resolution: - { - integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==, - } - engines: { node: ">=8" } - - minipass@3.3.6: - resolution: - { - integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==, - } - engines: { node: ">=8" } - - minipass@5.0.0: - resolution: - { - integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==, - } - engines: { node: ">=8" } - minipass@7.1.2: resolution: { @@ -3797,27 +3554,12 @@ packages: } engines: { node: ">=16 || 14 >=14.17" } - minizlib@2.1.2: - resolution: - { - integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==, - } - engines: { node: ">= 8" } - mkdirp-classic@0.5.3: resolution: { integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==, } - mkdirp@1.0.4: - resolution: - { - integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==, - } - engines: { node: ">=10" } - hasBin: true - ms@2.1.3: resolution: { @@ -3857,13 +3599,6 @@ packages: integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, } - negotiator@0.6.4: - resolution: - { - integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==, - } - engines: { node: ">= 0.6" } - negotiator@1.0.0: resolution: { @@ -3896,12 +3631,6 @@ packages: } engines: { node: ">=10" } - node-addon-api@7.1.1: - resolution: - { - integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==, - } - node-domexception@1.0.0: resolution: { @@ -3921,14 +3650,6 @@ packages: encoding: optional: true - node-gyp@8.4.1: - resolution: - { - integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==, - } - engines: { node: ">= 10.12.0" } - hasBin: true - node-int64@0.4.0: resolution: { @@ -3949,14 +3670,6 @@ packages: engines: { node: ">=10" } hasBin: true - nopt@5.0.0: - resolution: - { - integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==, - } - engines: { node: ">=6" } - hasBin: true - normalize-package-data@6.0.2: resolution: { @@ -3978,14 +3691,6 @@ packages: } engines: { node: ">=8" } - npmlog@6.0.2: - resolution: - { - integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==, - } - engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } - deprecated: This package is no longer supported. - object-assign@4.1.1: resolution: { @@ -4082,13 +3787,6 @@ packages: } engines: { node: ">=8" } - p-map@4.0.0: - resolution: - { - integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==, - } - engines: { node: ">=10" } - p-queue@6.6.2: resolution: { @@ -4400,6 +4098,7 @@ packages: integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==, } engines: { node: ">=10" } + deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. hasBin: true prettier@3.5.2: @@ -4417,24 +4116,6 @@ packages: } engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } - promise-inflight@1.0.1: - resolution: - { - integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==, - } - peerDependencies: - bluebird: "*" - peerDependenciesMeta: - bluebird: - optional: true - - promise-retry@2.0.1: - resolution: - { - integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==, - } - engines: { node: ">=10" } - prompts@2.4.2: resolution: { @@ -4590,13 +4271,6 @@ packages: engines: { node: ">= 0.4" } hasBin: true - retry@0.12.0: - resolution: - { - integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==, - } - engines: { node: ">= 4" } - retry@0.13.1: resolution: { @@ -4611,14 +4285,6 @@ packages: } engines: { iojs: ">=1.0.0", node: ">=0.10.0" } - rimraf@3.0.2: - resolution: - { - integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==, - } - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@5.0.10: resolution: { @@ -4701,12 +4367,6 @@ packages: } engines: { node: ">= 18" } - set-blocking@2.0.0: - resolution: - { - integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==, - } - setprototypeof@1.2.0: resolution: { @@ -4806,27 +4466,6 @@ packages: } engines: { node: ">=8" } - smart-buffer@4.2.0: - resolution: - { - integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==, - } - engines: { node: ">= 6.0.0", npm: ">= 3.0.0" } - - socks-proxy-agent@6.2.1: - resolution: - { - integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==, - } - engines: { node: ">= 10" } - - socks@2.8.4: - resolution: - { - integrity: sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==, - } - engines: { node: ">= 10.0.0", npm: ">= 3.0.0" } - source-map-js@1.2.1: resolution: { @@ -4891,25 +4530,6 @@ packages: integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==, } - sprintf-js@1.1.3: - resolution: - { - integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==, - } - - sqlite3@5.1.7: - resolution: - { - integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==, - } - - ssri@8.0.1: - resolution: - { - integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==, - } - engines: { node: ">= 8" } - stack-utils@2.0.6: resolution: { @@ -5042,13 +4662,6 @@ packages: } engines: { node: ">=6" } - tar@6.2.1: - resolution: - { - integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==, - } - engines: { node: ">=10" } - test-exclude@6.0.0: resolution: { @@ -5280,18 +4893,6 @@ packages: } engines: { node: ">=14.0" } - unique-filename@1.1.1: - resolution: - { - integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==, - } - - unique-slug@2.0.2: - resolution: - { - integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==, - } - unpipe@1.0.0: resolution: { @@ -5425,12 +5026,6 @@ packages: engines: { node: ">= 8" } hasBin: true - wide-align@1.1.5: - resolution: - { - integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==, - } - wrap-ansi@7.0.0: resolution: { @@ -5948,9 +5543,6 @@ snapshots: "@fastify/busboy@2.1.1": {} - "@gar/promisify@1.1.3": - optional: true - "@google/genai@1.2.0(@modelcontextprotocol/sdk@1.12.1)(encoding@0.1.13)": dependencies: "@modelcontextprotocol/sdk": 1.12.1 @@ -6217,18 +5809,6 @@ snapshots: "@nodelib/fs.scandir": 2.1.5 fastq: 1.19.1 - "@npmcli/fs@1.1.1": - dependencies: - "@gar/promisify": 1.1.3 - semver: 7.7.1 - optional: true - - "@npmcli/move-file@1.1.2": - dependencies: - mkdirp: 1.0.4 - rimraf: 3.0.2 - optional: true - "@pkgjs/parseargs@0.11.0": optional: true @@ -6381,9 +5961,6 @@ snapshots: - bufferutil - utf-8-validate - "@tootallnate/once@1.1.2": - optional: true - "@tsconfig/node10@1.0.11": {} "@tsconfig/node12@1.0.11": {} @@ -6413,6 +5990,10 @@ snapshots: dependencies: "@babel/types": 7.26.9 + "@types/better-sqlite3@7.6.13": + dependencies: + "@types/node": 22.13.5 + "@types/estree@1.0.6": {} "@types/graceful-fs@4.1.9": @@ -6459,10 +6040,6 @@ snapshots: "@types/retry@0.12.0": {} - "@types/sqlite3@3.1.11": - dependencies: - "@types/node": 22.13.5 - "@types/stack-utils@2.0.3": {} "@types/uuid@10.0.0": {} @@ -6487,9 +6064,6 @@ snapshots: transitivePeerDependencies: - supports-color - abbrev@1.1.1: - optional: true - abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -6505,25 +6079,12 @@ snapshots: acorn@8.14.0: {} - agent-base@6.0.2: - dependencies: - debug: 4.4.0(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - optional: true - agent-base@7.1.3: {} agentkeepalive@4.6.0: dependencies: humanize-ms: 1.2.1 - aggregate-error@3.1.0: - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - optional: true - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -6554,15 +6115,6 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - aproba@2.0.0: - optional: true - - are-we-there-yet@3.0.1: - dependencies: - delegates: 1.0.0 - readable-stream: 3.6.2 - optional: true - arg@4.1.3: {} argparse@1.0.10: @@ -6642,6 +6194,11 @@ snapshots: base64-js@1.5.1: {} + better-sqlite3@12.6.2: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.3 + bignumber.js@9.2.0: {} binary-extensions@2.3.0: {} @@ -6727,30 +6284,6 @@ snapshots: cac@6.7.14: {} - cacache@15.3.0: - dependencies: - "@npmcli/fs": 1.1.1 - "@npmcli/move-file": 1.1.2 - chownr: 2.0.0 - fs-minipass: 2.1.0 - glob: 7.2.3 - infer-owner: 1.0.4 - lru-cache: 6.0.0 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - mkdirp: 1.0.4 - p-map: 4.0.0 - promise-inflight: 1.0.1 - rimraf: 3.0.2 - ssri: 8.0.1 - tar: 6.2.1 - unique-filename: 1.1.1 - transitivePeerDependencies: - - bluebird - optional: true - call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -6796,15 +6329,10 @@ snapshots: chownr@1.1.4: {} - chownr@2.0.0: {} - ci-info@3.9.0: {} cjs-module-lexer@1.4.3: {} - clean-stack@2.2.0: - optional: true - cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -6835,9 +6363,6 @@ snapshots: color-name@1.1.4: {} - color-support@1.1.3: - optional: true - combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -6848,9 +6373,6 @@ snapshots: consola@3.4.2: {} - console-control-strings@1.1.0: - optional: true - console-table-printer@2.12.1: dependencies: simple-wcswidth: 1.0.1 @@ -6926,9 +6448,6 @@ snapshots: delayed-stream@1.0.0: {} - delegates@1.0.0: - optional: true - depd@2.0.0: {} detect-libc@2.0.3: {} @@ -6983,12 +6502,6 @@ snapshots: dependencies: once: 1.4.0 - env-paths@2.2.1: - optional: true - - err-code@2.0.3: - optional: true - error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 @@ -7212,10 +6725,6 @@ snapshots: fs-constants@1.0.0: {} - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -7223,18 +6732,6 @@ snapshots: function-bind@1.1.2: {} - gauge@4.0.4: - dependencies: - aproba: 2.0.0 - color-support: 1.1.3 - console-control-strings: 1.1.0 - has-unicode: 2.0.1 - signal-exit: 3.0.7 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wide-align: 1.1.5 - optional: true - gaxios@6.7.1(encoding@0.1.13): dependencies: extend: 3.0.2 @@ -7359,9 +6856,6 @@ snapshots: dependencies: has-symbols: 1.1.0 - has-unicode@2.0.1: - optional: true - hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -7372,9 +6866,6 @@ snapshots: html-escaper@2.0.2: {} - http-cache-semantics@4.1.1: - optional: true - http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -7383,15 +6874,6 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 - http-proxy-agent@4.0.1: - dependencies: - "@tootallnate/once": 1.1.2 - agent-base: 6.0.2 - debug: 4.4.0(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - optional: true - http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 @@ -7399,14 +6881,6 @@ snapshots: transitivePeerDependencies: - supports-color - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.0(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - optional: true - https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.3 @@ -7435,12 +6909,6 @@ snapshots: imurmurhash@0.1.4: {} - indent-string@4.0.0: - optional: true - - infer-owner@1.0.4: - optional: true - inflight@1.0.6: dependencies: once: 1.4.0 @@ -7450,12 +6918,6 @@ snapshots: ini@1.3.8: {} - ip-address@9.0.5: - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 - optional: true - ipaddr.js@1.9.1: {} is-arrayish@0.2.1: {} @@ -7486,9 +6948,6 @@ snapshots: dependencies: is-docker: 3.0.0 - is-lambda@1.0.1: - optional: true - is-number@7.0.0: {} is-promise@4.0.0: {} @@ -7877,9 +7336,6 @@ snapshots: argparse: 1.0.10 esprima: 4.0.1 - jsbn@1.1.0: - optional: true - jsesc@3.1.0: {} json-bigint@1.0.0: @@ -7983,40 +7439,12 @@ snapshots: dependencies: yallist: 3.1.1 - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - optional: true - make-dir@4.0.0: dependencies: semver: 7.7.1 make-error@1.3.6: {} - make-fetch-happen@9.1.0: - dependencies: - agentkeepalive: 4.6.0 - cacache: 15.3.0 - http-cache-semantics: 4.1.1 - http-proxy-agent: 4.0.1 - https-proxy-agent: 5.0.1 - is-lambda: 1.0.1 - lru-cache: 6.0.0 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-fetch: 1.4.1 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - negotiator: 0.6.4 - promise-retry: 2.0.1 - socks-proxy-agent: 6.2.1 - ssri: 8.0.1 - transitivePeerDependencies: - - bluebird - - supports-color - optional: true - makeerror@1.0.12: dependencies: tmpl: 1.0.5 @@ -8072,52 +7500,10 @@ snapshots: minimist@1.2.8: {} - minipass-collect@1.0.2: - dependencies: - minipass: 3.3.6 - optional: true - - minipass-fetch@1.4.1: - dependencies: - minipass: 3.3.6 - minipass-sized: 1.0.3 - minizlib: 2.1.2 - optionalDependencies: - encoding: 0.1.13 - optional: true - - minipass-flush@1.0.5: - dependencies: - minipass: 3.3.6 - optional: true - - minipass-pipeline@1.2.4: - dependencies: - minipass: 3.3.6 - optional: true - - minipass-sized@1.0.3: - dependencies: - minipass: 3.3.6 - optional: true - - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - - minipass@5.0.0: {} - minipass@7.1.2: {} - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - mkdirp-classic@0.5.3: {} - mkdirp@1.0.4: {} - ms@2.1.3: {} mustache@4.2.0: {} @@ -8135,9 +7521,6 @@ snapshots: natural-compare@1.4.0: {} - negotiator@0.6.4: - optional: true - negotiator@1.0.0: {} neo4j-driver-bolt-connection@5.28.1: @@ -8158,8 +7541,6 @@ snapshots: dependencies: semver: 7.7.1 - node-addon-api@7.1.1: {} - node-domexception@1.0.0: {} node-fetch@2.7.0(encoding@0.1.13): @@ -8168,23 +7549,6 @@ snapshots: optionalDependencies: encoding: 0.1.13 - node-gyp@8.4.1: - dependencies: - env-paths: 2.2.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - make-fetch-happen: 9.1.0 - nopt: 5.0.0 - npmlog: 6.0.2 - rimraf: 3.0.2 - semver: 7.7.1 - tar: 6.2.1 - which: 2.0.2 - transitivePeerDependencies: - - bluebird - - supports-color - optional: true - node-int64@0.4.0: {} node-releases@2.0.19: {} @@ -8202,11 +7566,6 @@ snapshots: touch: 3.1.1 undefsafe: 2.0.5 - nopt@5.0.0: - dependencies: - abbrev: 1.1.1 - optional: true - normalize-package-data@6.0.2: dependencies: hosted-git-info: 7.0.2 @@ -8219,14 +7578,6 @@ snapshots: dependencies: path-key: 3.1.1 - npmlog@6.0.2: - dependencies: - are-we-there-yet: 3.0.1 - console-control-strings: 1.1.0 - gauge: 4.0.4 - set-blocking: 2.0.0 - optional: true - object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -8285,11 +7636,6 @@ snapshots: dependencies: p-limit: 2.3.0 - p-map@4.0.0: - dependencies: - aggregate-error: 3.1.0 - optional: true - p-queue@6.6.2: dependencies: eventemitter3: 4.0.7 @@ -8463,15 +7809,6 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 - promise-inflight@1.0.1: - optional: true - - promise-retry@2.0.1: - dependencies: - err-code: 2.0.3 - retry: 0.12.0 - optional: true - prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -8563,18 +7900,10 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - retry@0.12.0: - optional: true - retry@0.13.1: {} reusify@1.1.0: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - optional: true - rimraf@5.0.10: dependencies: glob: 10.4.5 @@ -8658,9 +7987,6 @@ snapshots: transitivePeerDependencies: - supports-color - set-blocking@2.0.0: - optional: true - setprototypeof@1.2.0: {} shebang-command@2.0.0: @@ -8719,24 +8045,6 @@ snapshots: slash@3.0.0: {} - smart-buffer@4.2.0: - optional: true - - socks-proxy-agent@6.2.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.0(supports-color@5.5.0) - socks: 2.8.4 - transitivePeerDependencies: - - supports-color - optional: true - - socks@2.8.4: - dependencies: - ip-address: 9.0.5 - smart-buffer: 4.2.0 - optional: true - source-map-js@1.2.1: optional: true @@ -8769,26 +8077,6 @@ snapshots: sprintf-js@1.0.3: {} - sprintf-js@1.1.3: - optional: true - - sqlite3@5.1.7: - dependencies: - bindings: 1.5.0 - node-addon-api: 7.1.1 - prebuild-install: 7.1.3 - tar: 6.2.1 - optionalDependencies: - node-gyp: 8.4.1 - transitivePeerDependencies: - - bluebird - - supports-color - - ssri@8.0.1: - dependencies: - minipass: 3.3.6 - optional: true - stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -8871,15 +8159,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - tar@6.2.1: - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - test-exclude@6.0.0: dependencies: "@istanbuljs/schema": 0.1.3 @@ -9018,16 +8297,6 @@ snapshots: dependencies: "@fastify/busboy": 2.1.1 - unique-filename@1.1.1: - dependencies: - unique-slug: 2.0.2 - optional: true - - unique-slug@2.0.2: - dependencies: - imurmurhash: 0.1.4 - optional: true - unpipe@1.0.0: {} update-browserslist-db@1.1.3(browserslist@4.24.4): @@ -9092,11 +8361,6 @@ snapshots: dependencies: isexe: 2.0.0 - wide-align@1.1.5: - dependencies: - string-width: 4.2.3 - optional: true - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 diff --git a/mem0-ts/src/oss/package.json b/mem0-ts/src/oss/package.json index e2cb5ca62..19d856cea 100644 --- a/mem0-ts/src/oss/package.json +++ b/mem0-ts/src/oss/package.json @@ -19,7 +19,6 @@ "@types/node": "^20.11.19", "@types/pg": "^8.11.0", "@types/redis": "^4.0.10", - "@types/sqlite3": "^3.1.11", "@types/uuid": "^9.0.8", "cloudflare": "^4.2.0", "dotenv": "^16.4.4", @@ -27,7 +26,7 @@ "openai": "^4.28.0", "pg": "^8.11.3", "redis": "^4.7.0", - "sqlite3": "^5.1.7", + "better-sqlite3": "^12.6.2", "uuid": "^9.0.1", "zod": "^3.22.4" }, diff --git a/mem0-ts/src/oss/src/storage/SQLiteManager.ts b/mem0-ts/src/oss/src/storage/SQLiteManager.ts index 32143b37a..89c2a6d17 100644 --- a/mem0-ts/src/oss/src/storage/SQLiteManager.ts +++ b/mem0-ts/src/oss/src/storage/SQLiteManager.ts @@ -1,16 +1,18 @@ -import sqlite3 from "sqlite3"; +import Database from "better-sqlite3"; import { HistoryManager } from "./base"; export class SQLiteManager implements HistoryManager { - private db: sqlite3.Database; + private db: Database.Database; + private stmtInsert!: Database.Statement; + private stmtSelect!: Database.Statement; constructor(dbPath: string) { - this.db = new sqlite3.Database(dbPath); - this.init().catch(console.error); + this.db = new Database(dbPath); + this.init(); } - private async init() { - await this.run(` + private init(): void { + this.db.exec(` CREATE TABLE IF NOT EXISTS memory_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, memory_id TEXT NOT NULL, @@ -22,24 +24,14 @@ export class SQLiteManager implements HistoryManager { is_deleted INTEGER DEFAULT 0 ) `); - } - - private async run(sql: string, params: any[] = []): Promise { - return new Promise((resolve, reject) => { - this.db.run(sql, params, (err) => { - if (err) reject(err); - else resolve(); - }); - }); - } - - private async all(sql: string, params: any[] = []): Promise { - return new Promise((resolve, reject) => { - this.db.all(sql, params, (err, rows) => { - if (err) reject(err); - else resolve(rows); - }); - }); + this.stmtInsert = this.db.prepare( + `INSERT INTO memory_history + (memory_id, previous_value, new_value, action, created_at, updated_at, is_deleted) + VALUES (?, ?, ?, ?, ?, ?, ?)`, + ); + this.stmtSelect = this.db.prepare( + "SELECT * FROM memory_history WHERE memory_id = ? ORDER BY id DESC", + ); } async addHistory( @@ -51,32 +43,24 @@ export class SQLiteManager implements HistoryManager { updatedAt?: string, isDeleted: number = 0, ): Promise { - await this.run( - `INSERT INTO memory_history - (memory_id, previous_value, new_value, action, created_at, updated_at, is_deleted) - VALUES (?, ?, ?, ?, ?, ?, ?)`, - [ - memoryId, - previousValue, - newValue, - action, - createdAt, - updatedAt, - isDeleted, - ], + this.stmtInsert.run( + memoryId, + previousValue, + newValue, + action, + createdAt ?? null, + updatedAt ?? null, + isDeleted, ); } async getHistory(memoryId: string): Promise { - return this.all( - "SELECT * FROM memory_history WHERE memory_id = ? ORDER BY id DESC", - [memoryId], - ); + return this.stmtSelect.all(memoryId) as any[]; } async reset(): Promise { - await this.run("DROP TABLE IF EXISTS memory_history"); - await this.init(); + this.db.exec("DROP TABLE IF EXISTS memory_history"); + this.init(); } close(): void { diff --git a/mem0-ts/src/oss/src/tests/better-sqlite3-migration.test.ts b/mem0-ts/src/oss/src/tests/better-sqlite3-migration.test.ts new file mode 100644 index 000000000..0edf309b7 --- /dev/null +++ b/mem0-ts/src/oss/src/tests/better-sqlite3-migration.test.ts @@ -0,0 +1,377 @@ +/** + * Tests for the sqlite3 → better-sqlite3 migration. + * + * Covers: + * - SQLiteManager: all HistoryManager interface methods + * - MemoryVectorStore: insert, search, get, update, delete, list, userId mgmt + * - File-based persistence and in-memory mode + * - Backward compatibility: same schema, same data shapes + */ + +import { SQLiteManager } from "../storage/SQLiteManager"; +import { MemoryVectorStore } from "../vector_stores/memory"; +import fs from "fs"; +import path from "path"; +import os from "os"; + +// --------------------------------------------------------------------------- +// SQLiteManager tests +// --------------------------------------------------------------------------- + +describe("SQLiteManager (better-sqlite3)", () => { + let mgr: SQLiteManager; + + beforeEach(() => { + mgr = new SQLiteManager(":memory:"); + }); + + afterEach(() => { + mgr.close(); + }); + + it("creates an in-memory database without errors", () => { + expect(mgr).toBeDefined(); + }); + + it("addHistory inserts a row that getHistory returns", async () => { + await mgr.addHistory( + "mem-001", + null, + "User likes TypeScript", + "ADD", + "2026-01-01T00:00:00Z", + ); + + const history = await mgr.getHistory("mem-001"); + expect(history).toHaveLength(1); + expect(history[0].memory_id).toBe("mem-001"); + expect(history[0].new_value).toBe("User likes TypeScript"); + expect(history[0].action).toBe("ADD"); + expect(history[0].previous_value).toBeNull(); + expect(history[0].is_deleted).toBe(0); + }); + + it("returns history in DESC order (most recent first)", async () => { + await mgr.addHistory("mem-002", null, "First", "ADD", "2026-01-01"); + await mgr.addHistory( + "mem-002", + "First", + "Updated", + "UPDATE", + "2026-01-01", + "2026-01-02", + ); + await mgr.addHistory( + "mem-002", + "Updated", + null, + "DELETE", + undefined, + undefined, + 1, + ); + + const history = await mgr.getHistory("mem-002"); + expect(history).toHaveLength(3); + expect(history[0].action).toBe("DELETE"); + expect(history[1].action).toBe("UPDATE"); + expect(history[2].action).toBe("ADD"); + expect(history[0].is_deleted).toBe(1); + }); + + it("isolates history by memory_id", async () => { + await mgr.addHistory("mem-A", null, "Fact A", "ADD", "2026-01-01"); + await mgr.addHistory("mem-B", null, "Fact B", "ADD", "2026-01-01"); + + expect(await mgr.getHistory("mem-A")).toHaveLength(1); + expect(await mgr.getHistory("mem-B")).toHaveLength(1); + expect((await mgr.getHistory("mem-A"))[0].new_value).toBe("Fact A"); + expect((await mgr.getHistory("mem-B"))[0].new_value).toBe("Fact B"); + }); + + it("handles NULL/undefined optional fields correctly", async () => { + await mgr.addHistory( + "mem-null", + null, + null, + "DELETE", + undefined, + undefined, + 1, + ); + + const history = await mgr.getHistory("mem-null"); + expect(history).toHaveLength(1); + expect(history[0].previous_value).toBeNull(); + expect(history[0].new_value).toBeNull(); + expect(history[0].created_at).toBeNull(); + expect(history[0].updated_at).toBeNull(); + }); + + it("reset() clears all history and allows re-insertion", async () => { + await mgr.addHistory("mem-003", null, "Fact", "ADD", "2026-01-01"); + expect(await mgr.getHistory("mem-003")).toHaveLength(1); + + await mgr.reset(); + expect(await mgr.getHistory("mem-003")).toHaveLength(0); + + await mgr.addHistory("mem-004", null, "New fact", "ADD", "2026-02-01"); + expect(await mgr.getHistory("mem-004")).toHaveLength(1); + }); + + it("works with file-based database and persists data", async () => { + const dbPath = path.join(os.tmpdir(), `mem0-test-history-${Date.now()}.db`); + + try { + const fmgr = new SQLiteManager(dbPath); + await fmgr.addHistory( + "mem-file", + null, + "Persistent", + "ADD", + "2026-01-01", + ); + fmgr.close(); + + expect(fs.existsSync(dbPath)).toBe(true); + expect(fs.statSync(dbPath).size).toBeGreaterThan(0); + + // Reopen and verify + const fmgr2 = new SQLiteManager(dbPath); + const history = await fmgr2.getHistory("mem-file"); + expect(history).toHaveLength(1); + expect(history[0].new_value).toBe("Persistent"); + fmgr2.close(); + } finally { + if (fs.existsSync(dbPath)) fs.unlinkSync(dbPath); + } + }); + + it("handles many rapid insertions", async () => { + for (let i = 0; i < 100; i++) { + await mgr.addHistory( + `mem-rapid-${i}`, + null, + `Fact ${i}`, + "ADD", + new Date().toISOString(), + ); + } + + for (let i = 0; i < 100; i++) { + const h = await mgr.getHistory(`mem-rapid-${i}`); + expect(h).toHaveLength(1); + expect(h[0].new_value).toBe(`Fact ${i}`); + } + }); +}); + +// --------------------------------------------------------------------------- +// MemoryVectorStore tests +// --------------------------------------------------------------------------- + +describe("MemoryVectorStore (better-sqlite3)", () => { + const DIM = 4; + let store: MemoryVectorStore; + let dbPath: string; + + function normalize(v: number[]): number[] { + const norm = Math.sqrt(v.reduce((s, x) => s + x * x, 0)); + return v.map((x) => x / norm); + } + + beforeEach(() => { + dbPath = path.join(os.tmpdir(), `mem0-test-vectors-${Date.now()}.db`); + store = new MemoryVectorStore({ dimension: DIM, dbPath } as any); + }); + + afterEach(() => { + if (fs.existsSync(dbPath)) fs.unlinkSync(dbPath); + }); + + it("insert + get returns the stored payload", async () => { + const v = normalize([1, 0, 0, 0]); + await store.insert([v], ["id-1"], [{ data: "hello", userId: "u1" }]); + + const result = await store.get("id-1"); + expect(result).not.toBeNull(); + expect(result!.id).toBe("id-1"); + expect(result!.payload.data).toBe("hello"); + expect(result!.payload.userId).toBe("u1"); + }); + + it("get returns null for non-existent id", async () => { + const result = await store.get("nope"); + expect(result).toBeNull(); + }); + + it("search returns results sorted by cosine similarity", async () => { + const v1 = normalize([1, 0, 0, 0]); + const v2 = normalize([0, 1, 0, 0]); + const v3 = normalize([1, 1, 0, 0]); + + await store.insert( + [v1, v2, v3], + ["id-1", "id-2", "id-3"], + [{ data: "exact" }, { data: "orthogonal" }, { data: "close" }], + ); + + const results = await store.search(v1, 3); + expect(results).toHaveLength(3); + expect(results[0].id).toBe("id-1"); + expect(results[0].score).toBeCloseTo(1.0, 5); + expect(results[1].id).toBe("id-3"); + expect(results[2].id).toBe("id-2"); + expect(results[2].score).toBeCloseTo(0, 5); + }); + + it("search respects limit", async () => { + const vectors = []; + const ids = []; + const payloads = []; + for (let i = 0; i < 10; i++) { + const v = [0, 0, 0, 0]; + v[i % DIM] = 1; + vectors.push(normalize(v)); + ids.push(`id-${i}`); + payloads.push({ data: `item-${i}` }); + } + await store.insert(vectors, ids, payloads); + + const results = await store.search(normalize([1, 0, 0, 0]), 3); + expect(results).toHaveLength(3); + }); + + it("search respects filters", async () => { + const v = normalize([1, 0, 0, 0]); + await store.insert( + [v, v], + ["id-1", "id-2"], + [ + { data: "a", userId: "alice" }, + { data: "b", userId: "bob" }, + ], + ); + + const results = await store.search(v, 10, { userId: "alice" }); + expect(results).toHaveLength(1); + expect(results[0].id).toBe("id-1"); + }); + + it("search throws on dimension mismatch", async () => { + await expect(store.search([1, 0, 0], 10)).rejects.toThrow( + "dimension mismatch", + ); + }); + + it("insert throws on dimension mismatch", async () => { + await expect( + store.insert([[1, 0, 0]], ["id-1"], [{ data: "x" }]), + ).rejects.toThrow("dimension mismatch"); + }); + + it("update modifies the stored vector and payload", async () => { + const v1 = normalize([1, 0, 0, 0]); + const v2 = normalize([0, 1, 0, 0]); + await store.insert([v1], ["id-1"], [{ data: "original" }]); + + await store.update("id-1", v2, { data: "updated" }); + + const result = await store.get("id-1"); + expect(result!.payload.data).toBe("updated"); + + const results = await store.search(v2, 1); + expect(results[0].id).toBe("id-1"); + expect(results[0].score).toBeCloseTo(1.0, 5); + }); + + it("delete removes the vector", async () => { + const v = normalize([1, 0, 0, 0]); + await store.insert([v], ["id-1"], [{ data: "doomed" }]); + + await store.delete("id-1"); + expect(await store.get("id-1")).toBeNull(); + }); + + it("deleteCol drops and recreates table", async () => { + const v = normalize([1, 0, 0, 0]); + await store.insert([v], ["id-1"], [{ data: "will be gone" }]); + + await store.deleteCol(); + expect(await store.get("id-1")).toBeNull(); + + await store.insert([v], ["id-2"], [{ data: "fresh" }]); + expect(await store.get("id-2")).not.toBeNull(); + }); + + it("list returns all vectors with optional filters", async () => { + const v = normalize([1, 0, 0, 0]); + await store.insert( + [v, v, v], + ["id-1", "id-2", "id-3"], + [ + { data: "a", userId: "alice" }, + { data: "b", userId: "bob" }, + { data: "c", userId: "alice" }, + ], + ); + + const [all, totalAll] = await store.list(); + expect(all).toHaveLength(3); + expect(totalAll).toBe(3); + + const [filtered, totalFiltered] = await store.list({ userId: "alice" }); + expect(filtered).toHaveLength(2); + expect(totalFiltered).toBe(2); + }); + + it("list respects limit", async () => { + const v = normalize([1, 0, 0, 0]); + await store.insert( + [v, v, v], + ["id-1", "id-2", "id-3"], + [{ data: "a" }, { data: "b" }, { data: "c" }], + ); + + const [results] = await store.list(undefined, 2); + expect(results).toHaveLength(2); + }); + + it("getUserId generates and persists a userId", async () => { + const id1 = await store.getUserId(); + expect(typeof id1).toBe("string"); + expect(id1.length).toBeGreaterThan(0); + + const id2 = await store.getUserId(); + expect(id2).toBe(id1); + }); + + it("setUserId overrides the stored userId", async () => { + await store.setUserId("custom-user-123"); + const id = await store.getUserId(); + expect(id).toBe("custom-user-123"); + }); + + it("INSERT OR REPLACE upserts on id conflict", async () => { + const v1 = normalize([1, 0, 0, 0]); + const v2 = normalize([0, 1, 0, 0]); + await store.insert([v1], ["id-1"], [{ data: "original" }]); + await store.insert([v2], ["id-1"], [{ data: "replaced" }]); + + const result = await store.get("id-1"); + expect(result!.payload.data).toBe("replaced"); + + const [all] = await store.list(); + expect(all).toHaveLength(1); + }); + + it("file-based database persists across reopens", async () => { + const v = normalize([1, 0, 0, 0]); + await store.insert([v], ["id-persist"], [{ data: "persistent" }]); + + const store2 = new MemoryVectorStore({ dimension: DIM, dbPath } as any); + const result = await store2.get("id-persist"); + expect(result).not.toBeNull(); + expect(result!.payload.data).toBe("persistent"); + }); +}); diff --git a/mem0-ts/src/oss/src/vector_stores/memory.ts b/mem0-ts/src/oss/src/vector_stores/memory.ts index 711fa320d..4aed96838 100644 --- a/mem0-ts/src/oss/src/vector_stores/memory.ts +++ b/mem0-ts/src/oss/src/vector_stores/memory.ts @@ -1,6 +1,6 @@ import { VectorStore } from "./base"; import { SearchFilters, VectorStoreConfig, VectorStoreResult } from "../types"; -import sqlite3 from "sqlite3"; +import Database from "better-sqlite3"; import path from "path"; interface MemoryVector { @@ -10,7 +10,7 @@ interface MemoryVector { } export class MemoryVectorStore implements VectorStore { - private db: sqlite3.Database; + private db: Database.Database; private dimension: number; private dbPath: string; @@ -20,12 +20,12 @@ export class MemoryVectorStore implements VectorStore { if (config.dbPath) { this.dbPath = config.dbPath; } - this.db = new sqlite3.Database(this.dbPath); - this.init().catch(console.error); + this.db = new Database(this.dbPath); + this.init(); } - private async init() { - await this.run(` + private init(): void { + this.db.exec(` CREATE TABLE IF NOT EXISTS vectors ( id TEXT PRIMARY KEY, vector BLOB NOT NULL, @@ -33,7 +33,7 @@ export class MemoryVectorStore implements VectorStore { ) `); - await this.run(` + this.db.exec(` CREATE TABLE IF NOT EXISTS memory_migrations ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT NOT NULL UNIQUE @@ -41,33 +41,6 @@ export class MemoryVectorStore implements VectorStore { `); } - private async run(sql: string, params: any[] = []): Promise { - return new Promise((resolve, reject) => { - this.db.run(sql, params, (err) => { - if (err) reject(err); - else resolve(); - }); - }); - } - - private async all(sql: string, params: any[] = []): Promise { - return new Promise((resolve, reject) => { - this.db.all(sql, params, (err, rows) => { - if (err) reject(err); - else resolve(rows); - }); - }); - } - - private async getOne(sql: string, params: any[] = []): Promise { - return new Promise((resolve, reject) => { - this.db.get(sql, params, (err, row) => { - if (err) reject(err); - else resolve(row); - }); - }); - } - private cosineSimilarity(a: number[], b: number[]): number { let dotProduct = 0; let normA = 0; @@ -92,18 +65,23 @@ export class MemoryVectorStore implements VectorStore { ids: string[], payloads: Record[], ): Promise { - for (let i = 0; i < vectors.length; i++) { - if (vectors[i].length !== this.dimension) { - throw new Error( - `Vector dimension mismatch. Expected ${this.dimension}, got ${vectors[i].length}`, - ); - } - const vectorBuffer = Buffer.from(new Float32Array(vectors[i]).buffer); - await this.run( - `INSERT OR REPLACE INTO vectors (id, vector, payload) VALUES (?, ?, ?)`, - [ids[i], vectorBuffer, JSON.stringify(payloads[i])], - ); - } + const stmt = this.db.prepare( + `INSERT OR REPLACE INTO vectors (id, vector, payload) VALUES (?, ?, ?)`, + ); + const insertMany = this.db.transaction( + (vecs: number[][], vIds: string[], vPayloads: Record[]) => { + for (let i = 0; i < vecs.length; i++) { + if (vecs[i].length !== this.dimension) { + throw new Error( + `Vector dimension mismatch. Expected ${this.dimension}, got ${vecs[i].length}`, + ); + } + const vectorBuffer = Buffer.from(new Float32Array(vecs[i]).buffer); + stmt.run(vIds[i], vectorBuffer, JSON.stringify(vPayloads[i])); + } + }, + ); + insertMany(vectors, ids, payloads); } async search( @@ -117,11 +95,15 @@ export class MemoryVectorStore implements VectorStore { ); } - const rows = await this.all(`SELECT * FROM vectors`); + const rows = this.db.prepare(`SELECT * FROM vectors`).all() as any[]; const results: VectorStoreResult[] = []; for (const row of rows) { - const vector = new Float32Array(row.vector.buffer); + const vector = new Float32Array( + row.vector.buffer, + row.vector.byteOffset, + row.vector.byteLength / 4, + ); const payload = JSON.parse(row.payload); const memoryVector: MemoryVector = { id: row.id, @@ -144,9 +126,9 @@ export class MemoryVectorStore implements VectorStore { } async get(vectorId: string): Promise { - const row = await this.getOne(`SELECT * FROM vectors WHERE id = ?`, [ - vectorId, - ]); + const row = this.db + .prepare(`SELECT * FROM vectors WHERE id = ?`) + .get(vectorId) as any; if (!row) return null; const payload = JSON.parse(row.payload); @@ -167,34 +149,38 @@ export class MemoryVectorStore implements VectorStore { ); } const vectorBuffer = Buffer.from(new Float32Array(vector).buffer); - await this.run(`UPDATE vectors SET vector = ?, payload = ? WHERE id = ?`, [ - vectorBuffer, - JSON.stringify(payload), - vectorId, - ]); + this.db + .prepare(`UPDATE vectors SET vector = ?, payload = ? WHERE id = ?`) + .run(vectorBuffer, JSON.stringify(payload), vectorId); } async delete(vectorId: string): Promise { - await this.run(`DELETE FROM vectors WHERE id = ?`, [vectorId]); + this.db.prepare(`DELETE FROM vectors WHERE id = ?`).run(vectorId); } async deleteCol(): Promise { - await this.run(`DROP TABLE IF EXISTS vectors`); - await this.init(); + this.db.exec(`DROP TABLE IF EXISTS vectors`); + this.init(); } async list( filters?: SearchFilters, limit: number = 100, ): Promise<[VectorStoreResult[], number]> { - const rows = await this.all(`SELECT * FROM vectors`); + const rows = this.db.prepare(`SELECT * FROM vectors`).all() as any[]; const results: VectorStoreResult[] = []; for (const row of rows) { const payload = JSON.parse(row.payload); const memoryVector: MemoryVector = { id: row.id, - vector: Array.from(new Float32Array(row.vector.buffer)), + vector: Array.from( + new Float32Array( + row.vector.buffer, + row.vector.byteOffset, + row.vector.byteLength / 4, + ), + ), payload, }; @@ -210,9 +196,9 @@ export class MemoryVectorStore implements VectorStore { } async getUserId(): Promise { - const row = await this.getOne( - `SELECT user_id FROM memory_migrations LIMIT 1`, - ); + const row = this.db + .prepare(`SELECT user_id FROM memory_migrations LIMIT 1`) + .get() as any; if (row) { return row.user_id; } @@ -221,20 +207,20 @@ export class MemoryVectorStore implements VectorStore { const randomUserId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); - await this.run(`INSERT INTO memory_migrations (user_id) VALUES (?)`, [ - randomUserId, - ]); + this.db + .prepare(`INSERT INTO memory_migrations (user_id) VALUES (?)`) + .run(randomUserId); return randomUserId; } async setUserId(userId: string): Promise { - await this.run(`DELETE FROM memory_migrations`); - await this.run(`INSERT INTO memory_migrations (user_id) VALUES (?)`, [ - userId, - ]); + this.db.prepare(`DELETE FROM memory_migrations`).run(); + this.db + .prepare(`INSERT INTO memory_migrations (user_id) VALUES (?)`) + .run(userId); } async initialize(): Promise { - await this.init(); + this.init(); } } diff --git a/mem0-ts/tsup.config.ts b/mem0-ts/tsup.config.ts index 2c32ac3b8..d5f94125a 100644 --- a/mem0-ts/tsup.config.ts +++ b/mem0-ts/tsup.config.ts @@ -7,7 +7,7 @@ const external = [ "uuid", "pg", "zod", - "sqlite3", + "better-sqlite3", "@qdrant/js-client-rest", "redis", ];