From 530db5b96bac9d7cebea7001f546074da40b89ed Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Sat, 27 Apr 2024 22:41:01 +0200 Subject: [PATCH 1/5] Adapt to new async db functions --- .github/workflows/node.js.yml | 25 --- .woodpecker.yaml | 13 ++ lib/index.js | 357 ++++++++++++++++++++-------------- package.json | 6 +- test/index.test.js | 72 +++---- 5 files changed, 262 insertions(+), 211 deletions(-) delete mode 100644 .github/workflows/node.js.yml create mode 100644 .woodpecker.yaml diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml deleted file mode 100644 index b3558e2..0000000 --- a/.github/workflows/node.js.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: CI - -on: - push: - branches: [master] - pull_request: - branches: [master] - -jobs: - test: - runs-on: ubuntu-latest - timeout-minutes: 10 - - strategy: - matrix: - node-version: [18.x, 20.x] - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - run: npm install - - run: npm test diff --git a/.woodpecker.yaml b/.woodpecker.yaml new file mode 100644 index 0000000..d254f8d --- /dev/null +++ b/.woodpecker.yaml @@ -0,0 +1,13 @@ +matrix: + NODE_VERSION: + - 18 + - 20 + +steps: + test: + when: + event: [push] + image: node:${NODE_VERSION} + commands: + - npm install + - npm test \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 1ac8e10..9f21c52 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,6 @@ const Obz = require('obz') const MsgV4 = require('ppppp-db/msg-v4') +const pull = require('pull-stream') const PREFIX = 'set_v1__' @@ -191,23 +192,35 @@ function initSet(peer, config) { /** * @param {string} id * @param {string} subdomain + * @param {(err: Error | null, tangle?: any) => void} cb */ - function readSet(id, subdomain) { + function readSet(id, subdomain, cb) { const domain = fromSubdomain(subdomain) const mootID = MsgV4.getMootID(id, domain) - const tangle = peer.db.getTangle(mootID) - if (!tangle) return new Set() - const msgIDs = tangle.topoSort() - const set = new Set() - for (const msgID of msgIDs) { - const msg = peer.db.get(msgID) - if (isValidSetMsg(msg)) { - const { add, del } = msg.data - for (const value of add) set.add(value) - for (const value of del) set.delete(value) - } - } - return set + // @ts-ignore + peer.db.getTangle(mootID, (err, tangle) => { + if (err) return cb(err) + if (!tangle) return cb(null, new Set()) + const msgIDs = tangle.topoSort() + const set = new Set() + pull( + pull.values(msgIDs), + pull.asyncMap((msgID, cb) => { + peer.db.get(msgID, cb) + }), + pull.drain((msg) => { + if (isValidSetMsg(msg)) { + const { add, del } = msg.data + for (const value of add) set.add(value) + for (const value of del) set.delete(value) + } + }, (err) => { + // prettier-ignore + if (err) return cb(Error("Stream failed on readSet()", { cause: err })) + return cb(null, set) + }) + ) + }) } /** @@ -278,25 +291,29 @@ function initSet(peer, config) { /** * @param {string} subdomain + * @param {CB} cb */ - function _squeezePotential(subdomain) { + function _squeezePotential(subdomain, cb) { // prettier-ignore - if (!loadedAccountID) throw new Error('Cannot squeeze potential before loading') + if (!loadedAccountID) return cb(Error('Cannot squeeze potential before loading')) // TODO: improve this so that the squeezePotential is the size of the // tangle suffix built as a slice from the fieldRoots const mootID = MsgV4.getMootID(loadedAccountID, fromSubdomain(subdomain)) - const tangle = peer.db.getTangle(mootID) - if (!tangle) return 0 - const maxDepth = tangle.maxDepth - const currentItemRoots = itemRoots.getAll(subdomain) - let minDepth = Infinity - for (const item in currentItemRoots) { - for (const msgID of currentItemRoots[item]) { - const depth = tangle.getDepth(msgID) - if (depth < minDepth) minDepth = depth + // @ts-ignore + peer.db.getTangle(mootID, (err, tangle) => { + if (err) return cb(err) + if (!tangle) return cb(null, 0) + const maxDepth = tangle.maxDepth + const currentItemRoots = itemRoots.getAll(subdomain) + let minDepth = Infinity + for (const item in currentItemRoots) { + for (const msgID of currentItemRoots[item]) { + const depth = tangle.getDepth(msgID) + if (depth < minDepth) minDepth = depth + } } - } - return maxDepth - minDepth + return cb(null, maxDepth - minDepth) + }) } //#endregion @@ -320,8 +337,8 @@ function initSet(peer, config) { // microtask is needed to ensure that loadPromise is assigned BEFORE this // body is executed (which in turn does inversion of control when `cb` or // `resolve` is called) - queueMicrotask(() => { - for (const rec of peer.db.records()) { + queueMicrotask(async () => { + for await (const rec of peer.db.records()) { if (!rec.msg) continue maybeLearnAboutSet(rec.id, rec.msg) } @@ -354,39 +371,43 @@ function initSet(peer, config) { loaded(() => { // TODO this error needs to be put into the `cb`, not thrown assert(!!loadedAccountID, 'Cannot add to Set before loading') - const currentSet = readSet(loadedAccountID, subdomain) - if (currentSet.has(value)) return cb(null, false) - const domain = fromSubdomain(subdomain) + readSet(loadedAccountID, subdomain, (err, currentSet) => { + if (err) return cb(err) - // Populate supersedes - const supersedes = [] - const toDeleteFromItemRoots = new Map() - const currentItemRoots = itemRoots.getAll(subdomain) - for (const item in currentItemRoots) { - // If we are re-adding this item, OR if this item has been deleted, - // then we should update roots - if (item === value || !currentSet.has(item)) { - supersedes.push(...currentItemRoots[item]) - for (const msgID of currentItemRoots[item]) { - toDeleteFromItemRoots.set(msgID, item) + if (currentSet.has(value)) return cb(null, false) + const domain = fromSubdomain(subdomain) + + // Populate supersedes + const supersedes = [] + const toDeleteFromItemRoots = new Map() + const currentItemRoots = itemRoots.getAll(subdomain) + for (const item in currentItemRoots) { + // If we are re-adding this item, OR if this item has been deleted, + // then we should update roots + if (item === value || !currentSet.has(item)) { + supersedes.push(...currentItemRoots[item]) + for (const msgID of currentItemRoots[item]) { + toDeleteFromItemRoots.set(msgID, item) + } } } - } - const data = { add: [value], del: [], supersedes } - peer.db.feed.publish( - { account: loadedAccountID, domain, data }, - (err, rec) => { - // prettier-ignore - if (err) return cb(new Error(`Failed to create msg when adding to Set "${subdomain}"`, { cause: err })) - for (const [msgID, item] of toDeleteFromItemRoots) { - itemRoots.del(subdomain, item, msgID) - } + const data = { add: [value], del: [], supersedes } + peer.db.feed.publish( + { account: loadedAccountID, domain, data }, // @ts-ignore - cb(null, true) - watch.set({ event: 'add', subdomain, value }) - } - ) + (err, rec) => { + // prettier-ignore + if (err) return cb(new Error(`Failed to create msg when adding to Set "${subdomain}"`, { cause: err })) + for (const [msgID, item] of toDeleteFromItemRoots) { + itemRoots.del(subdomain, item, msgID) + } + // @ts-ignore + cb(null, true) + watch.set({ event: 'add', subdomain, value }) + } + ) + }) }) } @@ -404,99 +425,126 @@ function initSet(peer, config) { loaded(() => { // TODO this error needs to be put into the `cb`, not thrown assert(!!loadedAccountID, 'Cannot add to Set before loading') - const currentSet = readSet(loadedAccountID, subdomain) - if (!currentSet.has(value)) return cb(null, false) - const domain = fromSubdomain(subdomain) + readSet(loadedAccountID, subdomain, (err, currentSet) => { + if (err) return cb(err) - // Populate supersedes - const supersedes = [] - const currentItemRoots = itemRoots.getAll(subdomain) - for (const item in currentItemRoots) { - if (item === value || !currentSet.has(item)) { - supersedes.push(...currentItemRoots[item]) + if (!currentSet.has(value)) return cb(null, false) + const domain = fromSubdomain(subdomain) + + // Populate supersedes + const supersedes = [] + const currentItemRoots = itemRoots.getAll(subdomain) + for (const item in currentItemRoots) { + if (item === value || !currentSet.has(item)) { + supersedes.push(...currentItemRoots[item]) + } } - } - const data = { add: [], del: [value], supersedes } - peer.db.feed.publish( - { account: loadedAccountID, domain, data }, - (err, rec) => { - // prettier-ignore - if (err) return cb(new Error(`Failed to create msg when deleting from Set "${subdomain}"`, { cause: err })) + const data = { add: [], del: [value], supersedes } + peer.db.feed.publish( + { account: loadedAccountID, domain, data }, // @ts-ignore - cb(null, true) - watch.set({ event: 'del', subdomain, value }) - } - ) + (err, rec) => { + // prettier-ignore + if (err) return cb(new Error(`Failed to create msg when deleting from Set "${subdomain}"`, { cause: err })) + // @ts-ignore + cb(null, true) + watch.set({ event: 'del', subdomain, value }) + } + ) + }) }) } /** * @param {string} subdomain * @param {any} value - * @param {string=} id + * @param {string?} id + * @param {CB} cb */ - function has(subdomain, value, id) { + function has(subdomain, value, id, cb) { assert(!!loadedAccountID, 'Cannot call has() before loading') - const set = readSet(id ?? loadedAccountID, subdomain) - return set.has(value) + readSet(id ?? loadedAccountID, subdomain, (err, set) => { + if (err) return cb(err) + + return cb(null, set.has(value)) + }) } /** * @param {string} subdomain - * @param {string=} id + * @param {string?} id + * @param {CB>} cb */ - function values(subdomain, id) { + function values(subdomain, id, cb) { assert(!!loadedAccountID, 'Cannot call values() before loading') - const set = readSet(id ?? loadedAccountID, subdomain) - return [...set] + readSet(id ?? loadedAccountID, subdomain, (err, set) => { + if (err) return cb(err) + + return cb(null, [...set]) + }) } /** * @public * @param {string} tangleID - * @returns {number} + * @param {CB} cb */ - function minGhostDepth(tangleID) { - return Math.max(0, minRequiredDepth(tangleID) - ghostSpan) + function minGhostDepth(tangleID, cb) { + minRequiredDepth(tangleID, (err, minDepth) => { + if (err) return cb(err) + + return cb(null, Math.max(0, minDepth - ghostSpan)) + }) } /** * @public * @param {string} tangleID - * @returns {number} + * @param {CB} cb */ - function minRequiredDepth(tangleID) { - const tangle = peer.db.getTangle(tangleID) + function minRequiredDepth(tangleID, cb) { + // @ts-ignore + peer.db.getTangle(tangleID, (err, tangle) => { + if (err) return cb(err) - // prettier-ignore - if (!tangle) return 0 - // prettier-ignore - if (!MsgV4.isMoot(tangle.root)) throw new Error(`Tangle "${tangleID}" is not a moot`) - const domain = tangle.root.metadata.domain - // prettier-ignore - if (!domain.startsWith(PREFIX)) throw new Error(`Tangle "${tangleID}" is not a Set moot`) + // prettier-ignore + if (!tangle) return cb(null, 0) + // prettier-ignore + if (!MsgV4.isMoot(tangle.root)) return cb(Error(`Tangle "${tangleID}" is not a moot`)) + const domain = tangle.root.metadata.domain + // prettier-ignore + if (!domain.startsWith(PREFIX)) return cb(Error(`Tangle "${tangleID}" is not a Set moot`)) - // Discover item roots - const itemRoots = new Set() - const msgIDs = tangle.topoSort() - for (const msgID of msgIDs) { - const msg = peer.db.get(msgID) - if (!msg?.data) continue - for (const supersededMsgID of msg.data.supersedes) { - itemRoots.delete(supersededMsgID) - } - itemRoots.add(msgID) - } + // Discover item roots + const itemRoots = new Set() + pull( + pull.values(tangle.topoSort()), + pull.asyncMap((msgID, cb) => { + peer.db.getRecord(msgID, cb) + }), + pull.drain((rec) => { + const { msg, id: msgID } = rec + if (!msg?.data) return + for (const supersededMsgID of msg.data.supersedes) { + itemRoots.delete(supersededMsgID) + } + itemRoots.add(msgID) + }, (err) => { + if (err) return cb(Error("Failed to iterate over tangle messages in minRequiredDepth()", { cause: err })) - // Get minimum depth of all item roots - let minDepth = Infinity - for (const msgID of itemRoots) { - const depth = tangle.getDepth(msgID) - if (depth < minDepth) minDepth = depth - } - return minDepth + // Get minimum depth of all item roots + let minDepth = Infinity + for (const msgID of itemRoots) { + const depth = tangle.getDepth(msgID) + if (depth < minDepth) minDepth = depth + } + + return cb(null, minDepth) + }) + ) + }) } /** @@ -514,20 +562,27 @@ function initSet(peer, config) { * @public * @param {MsgID} ghostableMsgID * @param {MsgID} tangleID + * @param {(err: Error | null, ghostable?: boolean) => void} cb */ - function isGhostable(ghostableMsgID, tangleID) { - if (ghostableMsgID === tangleID) return false + function isGhostable(ghostableMsgID, tangleID, cb) { + if (ghostableMsgID === tangleID) return cb(null, false) - const msg = peer.db.get(ghostableMsgID) + // @ts-ignore + peer.db.get(ghostableMsgID, (err, msg) => { + if (err) return cb(err) - // prettier-ignore - if (!msg) throw new Error(`isGhostable() msgID "${ghostableMsgID}" does not exist in the database`) + // prettier-ignore + if (!msg) return cb(Error(`isGhostable() msgID "${ghostableMsgID}" does not exist in the database`)) - const minItemRootDepth = minRequiredDepth(tangleID) - const minGhostDepth = minItemRootDepth - ghostSpan - const msgDepth = msg.metadata.tangles[tangleID].depth - if (minGhostDepth <= msgDepth && msgDepth < minItemRootDepth) return true - return false + minRequiredDepth(tangleID, (err, minItemRootDepth) => { + if (err) return cb(err) + + const minGhostDepth = minItemRootDepth - ghostSpan + const msgDepth = msg.metadata.tangles[tangleID].depth + if (minGhostDepth <= msgDepth && msgDepth < minItemRootDepth) return cb(null, true) + return cb(null, false) + }) + }) } /** @@ -562,31 +617,37 @@ function initSet(peer, config) { // TODO this error needs to be put into the `cb`, not thrown assert(!!loadedAccountID, 'Cannot squeeze Set before loading') - const potential = _squeezePotential(subdomain) - if (potential < 1) return cb(null, false) + _squeezePotential(subdomain, (err, potential) => { + if (err) return cb(err) - loaded(() => { - // TODO this error needs to be put into the `cb`, not thrown - assert(!!loadedAccountID, 'Cannot squeeze Set before loading') - const domain = fromSubdomain(subdomain) - const currentSet = readSet(loadedAccountID, subdomain) + if (potential < 1) return cb(null, false) - const supersedes = [] - const currentItemRoots = itemRoots.getAll(subdomain) - for (const item in currentItemRoots) { - supersedes.push(...currentItemRoots[item]) - } + loaded(() => { + // TODO this error needs to be put into the `cb`, not thrown + assert(!!loadedAccountID, 'Cannot squeeze Set before loading') + const domain = fromSubdomain(subdomain) + readSet(loadedAccountID, subdomain, (err, currentSet) => { + if (err) return cb(err) - const data = { add: [...currentSet], del: [], supersedes } - peer.db.feed.publish( - { account: loadedAccountID, domain, data }, - (err, rec) => { - // prettier-ignore - if (err) return cb(new Error(`Failed to create msg when squeezing Set "${subdomain}"`, { cause: err })) - // @ts-ignore - cb(null, true) - } - ) + const supersedes = [] + const currentItemRoots = itemRoots.getAll(subdomain) + for (const item in currentItemRoots) { + supersedes.push(...currentItemRoots[item]) + } + + const data = { add: [...currentSet], del: [], supersedes } + peer.db.feed.publish( + { account: loadedAccountID, domain, data }, + // @ts-ignore + (err, rec) => { + // prettier-ignore + if (err) return cb(new Error(`Failed to create msg when squeezing Set "${subdomain}"`, { cause: err })) + // @ts-ignore + cb(null, true) + } + ) + }) + }) }) } //#endregion diff --git a/package.json b/package.json index 3705bcf..633f961 100644 --- a/package.json +++ b/package.json @@ -25,12 +25,14 @@ "node": ">=16" }, "dependencies": { + "obz": "~1.1.0", + "pull-stream": "^3.7.0" }, "devDependencies": { + "@types/pull-stream": "^3.6.7", "bs58": "^5.0.0", "c8": "7", - "obz": "~1.1.0", - "ppppp-db": "github:staltz/ppppp-db#667b33779d98aff12a9b0cd2d7c80469a95cd04e", + "ppppp-db": "https://codeberg.org/pzp/pzp-db/archive/master.tar.gz", "ppppp-caps": "github:staltz/ppppp-caps#93fa810b9a40b78aef4872d4c2a8412cccb52929", "ppppp-keypair": "github:staltz/ppppp-keypair#61ef4420578f450dc2cc7b1efc1c5a691a871c74", "rimraf": "^4.4.0", diff --git a/test/index.test.js b/test/index.test.js index 03f538a..cf65a66 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -37,9 +37,9 @@ test('setup', async (t) => { assert.equal(peer.set.getGhostSpan(), 4, 'getGhostSpan') }) -function lastMsgID() { +async function lastMsgID() { let last - for (const item of peer.db.records()) { + for await (const item of peer.db.records()) { last = item } return last.id @@ -56,10 +56,10 @@ test('Set add(), del(), has(), watch()', async (t) => { const stopWatch = peer.set.watch((ev) => actualWatch.push(ev)) // Add 1st - assert.equal(peer.set.has('follows', '1st'), false, 'doesnt have 1st') + assert.equal(await p(peer.set.has)('follows', '1st', null), false, 'doesnt have 1st') assert(await p(peer.set.add)('follows', '1st'), 'add 1st') - assert.equal(peer.set.has('follows', '1st'), true, 'has 1st') - add1 = lastMsgID() + assert.equal(await p(peer.set.has)('follows', '1st', null), true, 'has 1st') + add1 = await lastMsgID() assert.deepEqual( peer.set._getItemRoots('follows'), { '1st': [add1] }, @@ -67,10 +67,10 @@ test('Set add(), del(), has(), watch()', async (t) => { ) // Add 2nd - assert.equal(peer.set.has('follows', '2nd'), false, 'doesnt have 2nd') + assert.equal(await p(peer.set.has)('follows', '2nd', null), false, 'doesnt have 2nd') assert(await p(peer.set.add)('follows', '2nd'), 'add 2nd') - assert.equal(peer.set.has('follows', '2nd'), true, 'has 2nd') - add2 = lastMsgID() + assert.equal(await p(peer.set.has)('follows', '2nd', null), true, 'has 2nd') + add2 = await lastMsgID() assert.deepEqual( peer.set._getItemRoots('follows'), { '1st': [add1], '2nd': [add2] }, @@ -78,10 +78,10 @@ test('Set add(), del(), has(), watch()', async (t) => { ) // Del 1st - assert.equal(peer.set.has('follows', '1st'), true, 'has 1st') + assert.equal(await p(peer.set.has)('follows', '1st', null), true, 'has 1st') assert(await p(peer.set.del)('follows', '1st'), 'del 1st') - assert.equal(peer.set.has('follows', '1st'), false, 'doesnt have 1st') - del1 = lastMsgID() + assert.equal(await p(peer.set.has)('follows', '1st', null), false, 'doesnt have 1st') + del1 = await lastMsgID() assert.deepEqual( peer.set._getItemRoots('follows'), { '1st': [del1], '2nd': [add2] }, @@ -93,10 +93,10 @@ test('Set add(), del(), has(), watch()', async (t) => { assert.deepEqual(actualWatch, expectedWatch, 'watch() events') // Add 3rd - assert.equal(peer.set.has('follows', '3rd'), false, 'doesnt have 3rd') + assert.equal(await p(peer.set.has)('follows', '3rd', null), false, 'doesnt have 3rd') assert(await p(peer.set.add)('follows', '3rd'), 'add 3rd') - assert.equal(peer.set.has('follows', '3rd'), true, 'has 3rd') - add3 = lastMsgID() + assert.equal(await p(peer.set.has)('follows', '3rd', null), true, 'has 3rd') + add3 = await lastMsgID() assert.deepEqual( peer.set._getItemRoots('follows'), { '3rd': [add3], '2nd': [add2] }, @@ -104,10 +104,10 @@ test('Set add(), del(), has(), watch()', async (t) => { ) // Del 2nd - assert.equal(peer.set.has('follows', '2nd'), true, 'has 2nd') + assert.equal(await p(peer.set.has)('follows', '2nd', null), true, 'has 2nd') assert(await p(peer.set.del)('follows', '2nd'), 'del 2nd') // msg seq 4 - assert.equal(peer.set.has('follows', '2nd'), false, 'doesnt have 2nd') - del2 = lastMsgID() + assert.equal(await p(peer.set.has)('follows', '2nd', null), false, 'doesnt have 2nd') + del2 = await lastMsgID() assert.deepEqual( peer.set._getItemRoots('follows'), { '3rd': [add3], '2nd': [del2] }, @@ -120,7 +120,7 @@ test('Set add(), del(), has(), watch()', async (t) => { false, 'del 2nd idempotent' ) - assert.equal(peer.set.has('follows', '2nd'), false, 'doesnt have 2nd') + assert.equal(await p(peer.set.has)('follows', '2nd', null), false, 'doesnt have 2nd') assert.deepEqual( peer.set._getItemRoots('follows'), { '3rd': [add3], '2nd': [del2] }, @@ -131,12 +131,12 @@ test('Set add(), del(), has(), watch()', async (t) => { let add4, add5 test('Set values()', async (t) => { assert(await p(peer.set.add)('follows', '4th'), 'add 4th') - add4 = lastMsgID() + add4 = await lastMsgID() assert(await p(peer.set.add)('follows', '5th'), 'add 5th') - add5 = lastMsgID() + add5 = await lastMsgID() const expected = new Set(['3rd', '4th', '5th']) - for (const item of peer.set.values('follows')) { + for (const item of await p(peer.set.values)('follows', null)) { assert.equal(expected.has(item), true, 'values() item') expected.delete(item) } @@ -150,12 +150,12 @@ test('predsl Set squeeze', async (t) => { 'itemRoots before squeeze' ) - assert.equal(peer.set._squeezePotential('follows'), 3, 'squeezePotential=3') + assert.equal(await p(peer.set._squeezePotential)('follows'), 3, 'squeezePotential=3') assert.equal(await p(peer.set.squeeze)('follows'), true, 'squeezed') - const squeezed = lastMsgID() + const squeezed = await lastMsgID() - assert.equal(peer.set._squeezePotential('follows'), 0, 'squeezePotential=0') + assert.equal(await p(peer.set._squeezePotential)('follows'), 0, 'squeezePotential=0') assert.deepEqual( peer.set._getItemRoots('follows'), @@ -168,17 +168,17 @@ test('predsl Set squeeze', async (t) => { false, 'squeeze again idempotent' ) - const squeezed2 = lastMsgID() + const squeezed2 = await lastMsgID() assert.equal(squeezed, squeezed2, 'squeezed msgID is same') }) -test('Set isGhostable', (t) => { +test('Set isGhostable', async (t) => { const moot = MsgV4.createMoot(aliceID, 'set_v1__follows', aliceKeypair) const mootID = MsgV4.getMsgID(moot) assert.equal(mootID, peer.set.getFeedID('follows'), 'getFeedID') - const tangle = peer.db.getTangle(mootID) + const tangle = await p(peer.db.getTangle)(mootID) const msgIDs = tangle.topoSort() const itemRoots = peer.set._getItemRoots('follows') @@ -190,15 +190,15 @@ test('Set isGhostable', (t) => { // Remember from the setup, that ghostSpan=4 assert.equal(msgIDs.length, 9) - assert.equal(peer.set.isGhostable(msgIDs[0], mootID), false) // moot - assert.equal(peer.set.isGhostable(msgIDs[1], mootID), false) - assert.equal(peer.set.isGhostable(msgIDs[2], mootID), false) - assert.equal(peer.set.isGhostable(msgIDs[3], mootID), false) - assert.equal(peer.set.isGhostable(msgIDs[4], mootID), true) // in ghostSpan - assert.equal(peer.set.isGhostable(msgIDs[5], mootID), true) // in ghostSpan - assert.equal(peer.set.isGhostable(msgIDs[6], mootID), true) // in ghostSpan - assert.equal(peer.set.isGhostable(msgIDs[7], mootID), true) // in ghostSpan - assert.equal(peer.set.isGhostable(msgIDs[8], mootID), false) // item root + assert.equal(await p(peer.set.isGhostable)(msgIDs[0], mootID), false) // moot + assert.equal(await p(peer.set.isGhostable)(msgIDs[1], mootID), false) + assert.equal(await p(peer.set.isGhostable)(msgIDs[2], mootID), false) + assert.equal(await p(peer.set.isGhostable)(msgIDs[3], mootID), false) + assert.equal(await p(peer.set.isGhostable)(msgIDs[4], mootID), true) // in ghostSpan + assert.equal(await p(peer.set.isGhostable)(msgIDs[5], mootID), true) // in ghostSpan + assert.equal(await p(peer.set.isGhostable)(msgIDs[6], mootID), true) // in ghostSpan + assert.equal(await p(peer.set.isGhostable)(msgIDs[7], mootID), true) // in ghostSpan + assert.equal(await p(peer.set.isGhostable)(msgIDs[8], mootID), false) // item root }) test('teardown', async (t) => { From a44c0e7097d37c823f41d4b3f1b4c06ae1d61c7b Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Sat, 27 Apr 2024 22:56:30 +0200 Subject: [PATCH 2/5] Use published pzp-keypair --- package.json | 2 +- test/index.test.js | 2 +- test/util.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 633f961..c095d39 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "c8": "7", "ppppp-db": "https://codeberg.org/pzp/pzp-db/archive/master.tar.gz", "ppppp-caps": "github:staltz/ppppp-caps#93fa810b9a40b78aef4872d4c2a8412cccb52929", - "ppppp-keypair": "github:staltz/ppppp-keypair#61ef4420578f450dc2cc7b1efc1c5a691a871c74", + "pzp-keypair": "^1.0.0", "rimraf": "^4.4.0", "secret-stack": "~8.1.0", "secret-handshake-ext": "0.0.10", diff --git a/test/index.test.js b/test/index.test.js index cf65a66..91c7f31 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -6,7 +6,7 @@ const rimraf = require('rimraf') const MsgV4 = require('ppppp-db/msg-v4') const p = require('node:util').promisify const { createPeer } = require('./util') -const Keypair = require('ppppp-keypair') +const Keypair = require('pzp-keypair') const DIR = path.join(os.tmpdir(), 'ppppp-set') rimraf.sync(DIR) diff --git a/test/util.js b/test/util.js index ff47a08..e351d07 100644 --- a/test/util.js +++ b/test/util.js @@ -2,7 +2,7 @@ const OS = require('node:os') const Path = require('node:path') const rimraf = require('rimraf') const caps = require('ppppp-caps') -const Keypair = require('ppppp-keypair') +const Keypair = require('pzp-keypair') function createPeer(config) { if (config.name) { From a2e57bd38dac623a8abd6a1d465651c1705af1aa Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Sat, 27 Apr 2024 23:09:21 +0200 Subject: [PATCH 3/5] Use released pzp-caps --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c095d39..22624a9 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "bs58": "^5.0.0", "c8": "7", "ppppp-db": "https://codeberg.org/pzp/pzp-db/archive/master.tar.gz", - "ppppp-caps": "github:staltz/ppppp-caps#93fa810b9a40b78aef4872d4c2a8412cccb52929", + "pzp-caps": "^1.0.0", "pzp-keypair": "^1.0.0", "rimraf": "^4.4.0", "secret-stack": "~8.1.0", From 483f0371360d9ccef531e933e59470baf6e5f3ce Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Sat, 27 Apr 2024 23:19:51 +0200 Subject: [PATCH 4/5] Update pzp-caps require --- test/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/util.js b/test/util.js index e351d07..8976b10 100644 --- a/test/util.js +++ b/test/util.js @@ -1,7 +1,7 @@ const OS = require('node:os') const Path = require('node:path') const rimraf = require('rimraf') -const caps = require('ppppp-caps') +const caps = require('pzp-caps') const Keypair = require('pzp-keypair') function createPeer(config) { From d6c52696e3c38e17526509c38661c99b79d575e8 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Sat, 27 Apr 2024 23:55:58 +0200 Subject: [PATCH 5/5] Rename to pzp --- README.md | 6 ++---- lib/index.js | 10 +++++----- package.json | 10 +++++----- test/index.test.js | 4 ++-- test/util.js | 4 ++-- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 4aa7f19..1b945c0 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ -**Work in progress** +# pzp-set ## Installation -We're not on npm yet. In your package.json, include this as - ```js -"ppppp-set": "github:staltz/ppppp-set" +npm install pzp-set ``` diff --git a/lib/index.js b/lib/index.js index 9f21c52..8f74abe 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,12 +1,12 @@ const Obz = require('obz') -const MsgV4 = require('ppppp-db/msg-v4') +const MsgV4 = require('pzp-db/msg-v4') const pull = require('pull-stream') const PREFIX = 'set_v1__' /** - * @typedef {ReturnType} PPPPPDB - * @typedef {import('ppppp-db').RecPresent} RecPresent + * @typedef {ReturnType} pzpDB + * @typedef {import('pzp-db').RecPresent} RecPresent * @typedef {{ * hook: ( * cb: ( @@ -34,7 +34,7 @@ const PREFIX = 'set_v1__' /** * @template [T = any] - * @typedef {import('ppppp-db/msg-v4').Msg} Msg + * @typedef {import('pzp-db/msg-v4').Msg} Msg */ /** @@ -76,7 +76,7 @@ function assert(check, message) { } /** - * @param {{ db: PPPPPDB, close: ClosableHook }} peer + * @param {{ db: pzpDB, close: ClosableHook }} peer * @param {Config} config */ function initSet(peer, config) { diff --git a/package.json b/package.json index 22624a9..fa20006 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { - "name": "ppppp-set", - "version": "1.0.0", + "name": "pzp-set", + "version": "0.0.1", "description": "Set data structure over append-only logs with pruning", "author": "Andre Staltz ", "license": "MIT", - "homepage": "https://github.com/staltz/ppppp-set", + "homepage": "https://codeberg.org/pzp/pzp-set", "repository": { "type": "git", - "url": "git@github.com:staltz/ppppp-set.git" + "url": "git@codeberg.org:pzp/pzp-set.git" }, "main": "index.js", "files": [ @@ -32,7 +32,7 @@ "@types/pull-stream": "^3.6.7", "bs58": "^5.0.0", "c8": "7", - "ppppp-db": "https://codeberg.org/pzp/pzp-db/archive/master.tar.gz", + "pzp-db": "^1.0.1", "pzp-caps": "^1.0.0", "pzp-keypair": "^1.0.0", "rimraf": "^4.4.0", diff --git a/test/index.test.js b/test/index.test.js index 91c7f31..d006b4a 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -3,12 +3,12 @@ const assert = require('node:assert') const path = require('node:path') const os = require('node:os') const rimraf = require('rimraf') -const MsgV4 = require('ppppp-db/msg-v4') +const MsgV4 = require('pzp-db/msg-v4') const p = require('node:util').promisify const { createPeer } = require('./util') const Keypair = require('pzp-keypair') -const DIR = path.join(os.tmpdir(), 'ppppp-set') +const DIR = path.join(os.tmpdir(), 'pzp-set') rimraf.sync(DIR) const aliceKeypair = Keypair.generate('ed25519', 'alice') diff --git a/test/util.js b/test/util.js index 8976b10..8eead46 100644 --- a/test/util.js +++ b/test/util.js @@ -9,7 +9,7 @@ function createPeer(config) { const name = config.name const tmp = OS.tmpdir() config.global ??= {} - config.global.path ??= Path.join(tmp, `ppppp-set-${name}-${Date.now()}`) + config.global.path ??= Path.join(tmp, `pzp-set-${name}-${Date.now()}`) config.global.keypair ??= Keypair.generate('ed25519', name) delete config.name } @@ -27,7 +27,7 @@ function createPeer(config) { return require('secret-stack/bare')() .use(require('secret-stack/plugins/net')) .use(require('secret-handshake-ext/secret-stack')) - .use(require('ppppp-db')) + .use(require('pzp-db')) .use(require('ssb-box')) .use(require('../lib')) .call(null, {