diff --git a/package-lock.json b/package-lock.json index 99100ee..9a73cc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@syncpoint/matrix-client-api", - "version": "2.3.0", + "version": "3.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@syncpoint/matrix-client-api", - "version": "2.3.0", + "version": "3.0.0", "license": "MIT", "dependencies": { "@matrix-org/matrix-sdk-crypto-wasm": "^17.1.0", @@ -15,11 +15,9 @@ }, "devDependencies": { "@faker-js/faker": "^7.6.0", - "levelup": "^5.1.1", - "memdown": "^6.1.1", + "memory-level": "^3.1.0", "mocha": "^10.2.0", - "oxlint": "^1.56.0", - "subleveldown": "^6.0.1" + "oxlint": "^1.56.0" } }, "node_modules/@faker-js/faker": { @@ -364,23 +362,32 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/abstract-leveldown": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", - "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", - "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "node_modules/abstract-level": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-3.1.1.tgz", + "integrity": "sha512-CW2gKbJFTuX1feMvOrvsVMmijAOgI9kg2Ie9Dq3gOcMt/dVVoVmqNlLcEUCT13NxHFMEajcUcVBIplbyDroDiw==", "dev": true, "license": "MIT", "dependencies": { "buffer": "^6.0.3", - "catering": "^2.0.0", "is-buffer": "^2.0.5", - "level-concat-iterator": "^3.0.0", - "level-supports": "^2.0.1", - "queue-microtask": "^1.2.3" + "level-supports": "^6.2.0", + "level-transcoder": "^1.0.1", + "maybe-combine-errors": "^1.0.0", + "module-error": "^1.0.1" }, "engines": { - "node": ">=10" + "node": ">=18" + } + }, + "node_modules/abstract-level/node_modules/level-supports": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-6.2.0.tgz", + "integrity": "sha512-QNxVXP0IRnBmMsJIh+sb2kwNCYcKciQZJEt+L1hPCHrKNELllXhvrlClVHXBYZVT+a7aTSM6StgNXdAldoab3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" } }, "node_modules/ansi-colors": { @@ -539,16 +546,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/catering": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", - "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -663,28 +660,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deferred-leveldown": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-7.0.0.tgz", - "integrity": "sha512-QKN8NtuS3BC6m0B8vAnBls44tX1WXAFATUsJlruyAYbZpysWV3siH6o/i3g9DCHauzodksO60bdj5NazNbjCmg==", - "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", - "dev": true, - "license": "MIT", - "dependencies": { - "abstract-leveldown": "^7.2.0", - "inherits": "^2.0.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/defined": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", - "integrity": "sha512-zpqiCT8bODLu3QSmLLic8xJnYWBFjOSu/fBCm189oAiTtPq/PSanNACKZDS7kgSyCJY7P+IcODzlIogBK/9RBg==", - "dev": true, - "license": "MIT" - }, "node_modules/diff": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", @@ -701,23 +676,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/encoding-down": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-7.1.0.tgz", - "integrity": "sha512-ky47X5jP84ryk5EQmvedQzELwVJPjCgXDQZGeb9F6r4PdChByCGHTBrVcF3h8ynKVJ1wVbkxTsDC8zBROPypgQ==", - "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", - "dev": true, - "license": "MIT", - "dependencies": { - "abstract-leveldown": "^7.2.0", - "inherits": "^2.0.3", - "level-codec": "^10.0.0", - "level-errors": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1031,96 +989,18 @@ "url": "https://github.com/sindresorhus/ky?sponsor=1" } }, - "node_modules/level-codec": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-10.0.0.tgz", - "integrity": "sha512-QW3VteVNAp6c/LuV6nDjg7XDXx9XHK4abmQarxZmlRSDyXYk20UdaJTSX6yzVvQ4i0JyWSB7jert0DsyD/kk6g==", - "deprecated": "Superseded by level-transcoder (https://github.com/Level/community#faq)", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^6.0.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/level-concat-iterator": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", - "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", - "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", - "dev": true, - "license": "MIT", - "dependencies": { - "catering": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/level-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-3.0.1.tgz", - "integrity": "sha512-tqTL2DxzPDzpwl0iV5+rBCv65HWbHp6eutluHNcVIftKZlQN//b6GEnZDM2CvGZvzGYMwyPtYppYnydBQd2SMQ==", - "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/level-iterator-stream": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-5.0.0.tgz", - "integrity": "sha512-wnb1+o+CVFUDdiSMR/ZymE2prPs3cjVLlXuDeSq9Zb8o032XrabGEXcTCsBxprAtseO3qvFeGzh6406z9sOTRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/level-option-wrap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/level-option-wrap/-/level-option-wrap-1.1.0.tgz", - "integrity": "sha512-gQouC22iCqHuBLNl4BHxEZUxLvUKALAtT/Q0c6ziOxZQ8c02G/gyxHWNbLbxUzRNfMrRnbt6TZT3gNe8VBqQeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "defined": "~0.0.0" - } - }, - "node_modules/level-supports": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", - "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/levelup": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-5.1.1.tgz", - "integrity": "sha512-0mFCcHcEebOwsQuk00WJwjLI6oCjbBuEYdh/RaRqhjnyVlzqf41T1NnDtCedumZ56qyIh8euLFDqV1KfzTAVhg==", - "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", "dev": true, "license": "MIT", "dependencies": { - "catering": "^2.0.0", - "deferred-leveldown": "^7.0.0", - "level-errors": "^3.0.1", - "level-iterator-stream": "^5.0.0", - "level-supports": "^2.0.1", - "queue-microtask": "^1.2.3" + "buffer": "^6.0.3", + "module-error": "^1.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/locate-path": { @@ -1154,29 +1034,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ltgt": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", - "integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==", + "node_modules/maybe-combine-errors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/maybe-combine-errors/-/maybe-combine-errors-1.0.0.tgz", + "integrity": "sha512-eefp6IduNPT6fVdwPp+1NgD0PML1NU5P6j1Mj5nz1nidX8/sWY7119WL8vTAHgqfsY74TzW0w1XPgdYEKkGZ5A==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=10" + } }, - "node_modules/memdown": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/memdown/-/memdown-6.1.1.tgz", - "integrity": "sha512-vh2RiuVrn6Vv73088C1KzLwy9+hhRwoZsgddYqIoVuFFrcoc2Rt+lq/KrmkFn6ulko7AtQ0AvqtYid35exb38A==", - "deprecated": "Superseded by memory-level (https://github.com/Level/community#faq)", + "node_modules/memory-level": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-3.1.0.tgz", + "integrity": "sha512-mTqFVi5iReKcjue/pag0OY4VNU7dlagCyjjPwWGierpk1Bpl9WjOxgXIswymPW3Q9bj3Foay+Z16mPGnKzvTkQ==", "dev": true, "license": "MIT", "dependencies": { - "abstract-leveldown": "^7.2.0", - "buffer": "^6.0.3", + "abstract-level": "^3.1.0", "functional-red-black-tree": "^1.0.1", - "inherits": "^2.0.1", - "ltgt": "^2.2.0" + "module-error": "^1.0.1" }, "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/minimatch": { @@ -1228,6 +1108,16 @@ "node": ">= 14.0.0" } }, + "node_modules/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1349,27 +1239,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -1380,31 +1249,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/reachdown": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reachdown/-/reachdown-1.1.0.tgz", - "integrity": "sha512-6LsdRe4cZyOjw4NnvbhUd/rGG7WQ9HMopPr+kyL018Uci4kijtxcGR5kVb5Ln13k4PEE+fEFQbjfOvNw7cnXmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -1456,16 +1300,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -1504,25 +1338,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/subleveldown": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/subleveldown/-/subleveldown-6.0.1.tgz", - "integrity": "sha512-Cnf+cn2wISXU2xflY1SFIqfX4hG2d6lFk2P5F8RDQLmiqN9Ir4ExNfUFH6xnmizMseM/t+nMsDUKjN9Kw6ShFA==", - "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", - "dev": true, - "license": "MIT", - "dependencies": { - "abstract-leveldown": "^7.2.0", - "encoding-down": "^7.1.0", - "inherits": "^2.0.3", - "level-option-wrap": "^1.1.0", - "levelup": "^5.1.1", - "reachdown": "^1.1.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -1551,13 +1366,6 @@ "node": ">=8.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, "node_modules/workerpool": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", diff --git a/package.json b/package.json index e42ade9..b1906a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@syncpoint/matrix-client-api", - "version": "2.3.0", + "version": "3.0.0", "description": "A minimal client API for [matrix]", "main": "index.mjs", "scripts": { @@ -23,10 +23,8 @@ }, "devDependencies": { "@faker-js/faker": "^7.6.0", - "levelup": "^5.1.1", - "memdown": "^6.1.1", + "memory-level": "^3.1.0", "mocha": "^10.2.0", - "oxlint": "^1.56.0", - "subleveldown": "^6.0.1" + "oxlint": "^1.56.0" } } diff --git a/src/command-api.mjs b/src/command-api.mjs index 92ebd69..83a3257 100644 --- a/src/command-api.mjs +++ b/src/command-api.mjs @@ -7,7 +7,7 @@ class CommandAPI { * @param {import('./room-members.mjs').RoomMemberCache} memberCache * @param {Object} [options={}] * @param {Function} [options.encryptEvent] - async (roomId, eventType, content, memberIds) => encryptedContent - * @param {Object} [options.db] - A levelup-compatible database instance for persistent queue storage + * @param {Object} [options.db] - An abstract-level database instance for persistent queue storage */ constructor (httpAPI, memberCache, options = {}) { this.httpAPI = httpAPI diff --git a/src/queue.mjs b/src/queue.mjs index 38b2829..847311b 100644 --- a/src/queue.mjs +++ b/src/queue.mjs @@ -19,7 +19,7 @@ const formatKey = n => `${KEY_PREFIX}${String(n).padStart(PAD_LENGTH, '0')}` const parseKey = key => Number(key.slice(KEY_PREFIX.length)) /** - * A persistent FIFO queue backed by a LevelDB instance (levelup/subleveldown API). + * A persistent FIFO queue backed by an abstract-level database. * * Serializable commands (arrays with string function name) are persisted to disk. * Non-serializable commands (callbacks) are held in memory only. @@ -29,7 +29,7 @@ const parseKey = key => Number(key.slice(KEY_PREFIX.length)) */ class FIFO { /** - * @param {Object} db - A levelup-compatible database instance (e.g. subleveldown) + * @param {Object} db - An abstract-level database instance (e.g. a sublevel) */ constructor (db) { this.db = db @@ -47,23 +47,16 @@ class FIFO { const log = getLogger() const entries = [] - await new Promise((resolve, reject) => { - const stream = this.db.createReadStream({ gte: `${KEY_PREFIX}0`, lte: `${KEY_PREFIX}\xFF` }) - stream.on('data', ({ key, value }) => { - const k = typeof key === 'string' ? key : key.toString() - const seq = parseKey(k) - const command = typeof value === 'string' ? JSON.parse(value) : value - entries.push({ seq, key: k, command }) - }) - stream.on('error', reject) - stream.on('end', resolve) - }) + const raw = await this.db.iterator({ gte: `${KEY_PREFIX}0`, lte: `${KEY_PREFIX}\xFF` }).all() + for (const [key, value] of raw) { + const seq = parseKey(key) + entries.push({ seq, key, command: value }) + } // Restore the counter (persisted separately to survive acknowledge) try { const savedCounter = await this.db.get(COUNTER_KEY) - const parsed = typeof savedCounter === 'string' ? Number(JSON.parse(savedCounter)) : Number(savedCounter) - if (!isNaN(parsed)) this.counter = parsed + if (savedCounter != null) this.counter = Number(savedCounter) } catch { // Key not found — counter stays at 0 } @@ -101,12 +94,10 @@ class FIFO { if (typeof functionName !== 'function') { this.counter++ key = formatKey(this.counter) - await new Promise((resolve, reject) => { - this.db.batch([ - { type: 'put', key, value: JSON.stringify(command) }, - { type: 'put', key: COUNTER_KEY, value: JSON.stringify(this.counter) } - ], err => err ? reject(err) : resolve()) - }) + await this.db.batch([ + { type: 'put', key, value: command }, + { type: 'put', key: COUNTER_KEY, value: this.counter } + ]) } if (!this.pendingResolvers.length) this._addPromise() @@ -131,9 +122,7 @@ class FIFO { */ async acknowledge (key) { if (key) { - await new Promise((resolve, reject) => { - this.db.del(key, err => err ? reject(err) : resolve()) - }) + await this.db.del(key) } } diff --git a/test/queue.test.mjs b/test/queue.test.mjs index f4717d6..893a93c 100644 --- a/test/queue.test.mjs +++ b/test/queue.test.mjs @@ -1,13 +1,10 @@ import assert from 'node:assert/strict' import { describe, it, beforeEach } from 'mocha' -import memdown from 'memdown' -import levelup from 'levelup' -import subleveldown from 'subleveldown' +import { MemoryLevel } from 'memory-level' import { FIFO } from '../src/queue.mjs' const createDB = () => { - const db = levelup(memdown()) - return subleveldown(db, 'command-queue', { valueEncoding: 'json' }) + return new MemoryLevel({ valueEncoding: 'json' }) } describe('Persistent FIFO Queue', function () {