libp2r2p 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/base93/index.js +193 -0
- package/package.json +23 -1
- package/AGENTS.md +0 -20
- package/tests/base16.test.js +0 -19
- package/tests/base64.test.js +0 -18
- package/tests/content-key-event.test.js +0 -48
- package/tests/fixtures/nip44v3-vectors.json +0 -1
- package/tests/helpers/test-signer.js +0 -185
- package/tests/idb-queue.test.js +0 -153
- package/tests/idb.test.js +0 -91
- package/tests/nip44-v3.test.js +0 -73
- package/tests/nip46.test.js +0 -668
- package/tests/private-channel.test.js +0 -1912
- package/tests/private-message.test.js +0 -501
- package/tests/private-messenger.test.js +0 -1737
- package/tests/queries.test.js +0 -101
- package/tests/queue-parity.test.js +0 -105
- package/tests/relay-hll.test.js +0 -32
- package/tests/relay-pool.test.js +0 -2063
- package/tests/temporary-storage.test.js +0 -89
- package/tests/web-storage-queue.test.js +0 -480
package/tests/idb-queue.test.js
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import { IDBFactory, IDBKeyRange } from 'fake-indexeddb'
|
|
4
|
-
import { createQueue } from '../idb-queue/index.js'
|
|
5
|
-
|
|
6
|
-
function queueFor (factory, prefix, options = {}) {
|
|
7
|
-
return createQueue({ prefix, indexedDB: factory, ...options })
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
async function values (iterator) {
|
|
11
|
-
const out = []
|
|
12
|
-
for await (const item of iterator) out.push(item.value)
|
|
13
|
-
return out
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
test('idb queue supports ordered queue and positional operations', async () => {
|
|
17
|
-
const queue = await queueFor(new IDBFactory(), 'ordered')
|
|
18
|
-
|
|
19
|
-
await queue.push({ value: 'middle' })
|
|
20
|
-
await queue.unshift({ value: 'first' })
|
|
21
|
-
await queue.push({ value: 'last' })
|
|
22
|
-
assert.equal(await queue.setAt(1, { value: 'MIDDLE' }), 1)
|
|
23
|
-
assert.equal(await queue.insertAt(2, { value: 'between' }), 2)
|
|
24
|
-
|
|
25
|
-
assert.equal((await queue.shift()).value, 'first')
|
|
26
|
-
assert.equal((await queue.removeAt(1)).value, 'between')
|
|
27
|
-
assert.equal((await queue.shift()).value, 'MIDDLE')
|
|
28
|
-
assert.equal((await queue.pop()).value, 'last')
|
|
29
|
-
assert.equal(await queue.shift(), null)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('idb queue keeps predicate parity and skips sparse removals', async () => {
|
|
33
|
-
const queue = await queueFor(new IDBFactory(), 'predicate')
|
|
34
|
-
await queue.push({ value: 'a' })
|
|
35
|
-
await queue.push({ value: 'c' })
|
|
36
|
-
assert.equal(await queue.insertWhere(item => item.value === 'c', { value: 'b' }), 1)
|
|
37
|
-
assert.equal(await queue.some(item => item.value === 'b'), true)
|
|
38
|
-
await queue.removeWhere(item => item.value === 'b')
|
|
39
|
-
|
|
40
|
-
assert.deepEqual(await values(queue.storedItems()), ['a', 'c'])
|
|
41
|
-
assert.equal((await queue.shift()).value, 'a')
|
|
42
|
-
assert.equal((await queue.shift()).value, 'c')
|
|
43
|
-
assert.equal(await queue.shift(), null)
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
test('idb queue streams live values and supports reverse snapshots', async () => {
|
|
47
|
-
const queue = await queueFor(new IDBFactory(), 'streams')
|
|
48
|
-
await queue.push({ value: 'first' })
|
|
49
|
-
await queue.push({ value: 'second' })
|
|
50
|
-
|
|
51
|
-
assert.deepEqual(await values(queue.reverseStoredItems()), ['second', 'first'])
|
|
52
|
-
const iterator = queue.items()
|
|
53
|
-
assert.equal((await iterator.next()).value.value, 'first')
|
|
54
|
-
assert.equal((await iterator.next()).value.value, 'second')
|
|
55
|
-
const pending = iterator.next()
|
|
56
|
-
await queue.push({ value: 'third' })
|
|
57
|
-
assert.equal((await pending).value.value, 'third')
|
|
58
|
-
await iterator.return()
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
test('idb queue enforces byte budgets and persists across queue instances', async () => {
|
|
62
|
-
const factory = new IDBFactory()
|
|
63
|
-
const queue = await queueFor(factory, 'capacity', { maxBytes: 450, evictionPolicy: 'fifo' })
|
|
64
|
-
await queue.push({ value: 'a'.repeat(120) })
|
|
65
|
-
await queue.push({ value: 'b'.repeat(120) })
|
|
66
|
-
await queue.push({ value: 'c'.repeat(120) })
|
|
67
|
-
|
|
68
|
-
assert.equal((await queue.shift()).value, 'b'.repeat(120))
|
|
69
|
-
assert.equal((await queue.shift()).value, 'c'.repeat(120))
|
|
70
|
-
|
|
71
|
-
const unbounded = await queueFor(factory, 'reopen')
|
|
72
|
-
await unbounded.push({ value: 'a'.repeat(120) })
|
|
73
|
-
await unbounded.push({ value: 'b'.repeat(120) })
|
|
74
|
-
await unbounded.push({ value: 'c'.repeat(120) })
|
|
75
|
-
const bounded = await queueFor(factory, 'reopen', { maxBytes: 450, evictionPolicy: 'fifo' })
|
|
76
|
-
assert.equal((await bounded.shift()).value, 'b'.repeat(120))
|
|
77
|
-
assert.equal((await bounded.shift()).value, 'c'.repeat(120))
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
test('idb queue exposes indexed equality, range, and deletion operations', async () => {
|
|
81
|
-
const queue = await queueFor(new IDBFactory(), 'indexed', {
|
|
82
|
-
indexes: {
|
|
83
|
-
byKind: 'kind',
|
|
84
|
-
byChannelTime: ['channel', 'time'],
|
|
85
|
-
byKey: { keyPath: 'key', unique: true }
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
await queue.push({ value: 'a', kind: 'message', channel: 'one', time: 10, key: 'a' })
|
|
89
|
-
await queue.push({ value: 'b', kind: 'message', channel: 'one', time: 20, key: 'b' })
|
|
90
|
-
await queue.push({ value: 'c', kind: 'seed', channel: 'two', time: 30, key: 'c' })
|
|
91
|
-
|
|
92
|
-
assert.equal((await queue.getBy('byKey', 'b')).value, 'b')
|
|
93
|
-
assert.equal(await queue.someBy('byKind', 'seed'), true)
|
|
94
|
-
assert.deepEqual(
|
|
95
|
-
await values(queue.storedItemsBy('byChannelTime', IDBKeyRange.bound(['one', 0], ['one', 20]))),
|
|
96
|
-
['a', 'b']
|
|
97
|
-
)
|
|
98
|
-
assert.deepEqual((await queue.removeBy('byKind', 'message')).map(item => item.value), ['a', 'b'])
|
|
99
|
-
assert.deepEqual(await values(queue.storedItems()), ['c'])
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
test('idb queue evolves additive indexes and rejects incompatible definitions', async () => {
|
|
103
|
-
const factory = new IDBFactory()
|
|
104
|
-
const first = await queueFor(factory, 'schema', { indexes: { byKind: 'kind' } })
|
|
105
|
-
await first.push({ value: 'a', kind: 'message', channel: 'one' })
|
|
106
|
-
const second = await queueFor(factory, 'schema', {
|
|
107
|
-
indexes: { byKind: 'kind', byChannel: 'channel' }
|
|
108
|
-
})
|
|
109
|
-
assert.equal((await second.getBy('byChannel', 'one')).value, 'a')
|
|
110
|
-
await assert.rejects(
|
|
111
|
-
queueFor(factory, 'schema', { indexes: { byKind: 'channel' } }),
|
|
112
|
-
/QUEUE_INDEX_SCHEMA_MISMATCH/
|
|
113
|
-
)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test('idb queue supports unique compound indexes', async () => {
|
|
117
|
-
const queue = await queueFor(new IDBFactory(), 'compound', {
|
|
118
|
-
indexes: {
|
|
119
|
-
byChannelTypeEventId: {
|
|
120
|
-
keyPath: ['channel', 'type', 'event.id'],
|
|
121
|
-
unique: true
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
})
|
|
125
|
-
await queue.push({ value: 'first', channel: 'one', type: 'tell', event: { id: 'event' } })
|
|
126
|
-
await queue.push({ value: 'second', channel: 'one', type: 'reply', event: { id: 'event' } })
|
|
127
|
-
await queue.push({ value: 'third', channel: 'two', type: 'tell', event: { id: 'event' } })
|
|
128
|
-
|
|
129
|
-
assert.equal(await queue.someBy('byChannelTypeEventId', ['one', 'tell', 'event']), true)
|
|
130
|
-
await assert.rejects(
|
|
131
|
-
queue.push({ value: 'duplicate', channel: 'one', type: 'tell', event: { id: 'event' } }),
|
|
132
|
-
/ConstraintError/
|
|
133
|
-
)
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
test('idb queue rolls back failed writes without an operation journal', async () => {
|
|
137
|
-
const queue = await queueFor(new IDBFactory(), 'atomic')
|
|
138
|
-
await queue.push({ value: 'kept' })
|
|
139
|
-
|
|
140
|
-
await assert.rejects(queue.push({ value: 'bad', nonCloneable: () => {} }))
|
|
141
|
-
assert.equal((await queue.shift()).value, 'kept')
|
|
142
|
-
assert.equal(await queue.shift(), null)
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
test('idb queue rejects unavailable IndexedDB and clears atomically', async () => {
|
|
146
|
-
await assert.rejects(createQueue({ prefix: 'missing', indexedDB: null }), /IDB_UNAVAILABLE/)
|
|
147
|
-
|
|
148
|
-
const queue = await queueFor(new IDBFactory(), 'clear')
|
|
149
|
-
await queue.push({ value: 'first' })
|
|
150
|
-
await queue.push({ value: 'second' })
|
|
151
|
-
await queue.clear()
|
|
152
|
-
assert.equal(await queue.shift(), null)
|
|
153
|
-
})
|
package/tests/idb.test.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import { IDBFactory } from 'fake-indexeddb'
|
|
4
|
-
import { run } from '../idb/index.js'
|
|
5
|
-
|
|
6
|
-
function deferred () {
|
|
7
|
-
let resolve
|
|
8
|
-
let reject
|
|
9
|
-
const promise = new Promise((nextResolve, nextReject) => {
|
|
10
|
-
resolve = nextResolve
|
|
11
|
-
reject = nextReject
|
|
12
|
-
})
|
|
13
|
-
return { promise, resolve, reject }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function transactionDone (tx) {
|
|
17
|
-
return new Promise((resolve, reject) => {
|
|
18
|
-
tx.oncomplete = () => resolve()
|
|
19
|
-
tx.onabort = () => reject(tx.error || new Error('IDB_TRANSACTION_ABORTED'))
|
|
20
|
-
tx.onerror = () => reject(tx.error || new Error('IDB_TRANSACTION_FAILED'))
|
|
21
|
-
})
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function openRowsDb () {
|
|
25
|
-
const indexedDB = new IDBFactory()
|
|
26
|
-
return new Promise((resolve, reject) => {
|
|
27
|
-
const request = indexedDB.open('idb-run-test', 1)
|
|
28
|
-
request.onerror = () => reject(request.error)
|
|
29
|
-
request.onupgradeneeded = () => {
|
|
30
|
-
const store = request.result.createObjectStore('rows', { keyPath: 'id' })
|
|
31
|
-
store.createIndex('byGroup', 'group')
|
|
32
|
-
}
|
|
33
|
-
request.onsuccess = () => resolve(request.result)
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
test('run performs store and index requests inside a shared transaction', async () => {
|
|
38
|
-
const db = await openRowsDb()
|
|
39
|
-
const tx = db.transaction(['rows'], 'readwrite')
|
|
40
|
-
const done = transactionDone(tx)
|
|
41
|
-
|
|
42
|
-
await run('put', [{ id: 'one', group: 'alpha', value: 1 }], 'rows', null, { db, tx })
|
|
43
|
-
await run('put', [{ id: 'two', group: 'beta', value: 2 }], 'rows', null, { db, tx })
|
|
44
|
-
const found = await run('get', ['alpha'], 'rows', 'byGroup', { db, tx })
|
|
45
|
-
|
|
46
|
-
assert.equal(found.result.id, 'one')
|
|
47
|
-
await done
|
|
48
|
-
db.close()
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
test('run supports the reusable deferred cursor pattern', async () => {
|
|
52
|
-
const db = await openRowsDb()
|
|
53
|
-
const setup = db.transaction(['rows'], 'readwrite')
|
|
54
|
-
const setupDone = transactionDone(setup)
|
|
55
|
-
await run('put', [{ id: 'one', group: 'alpha' }], 'rows', null, { db, tx: setup })
|
|
56
|
-
await run('put', [{ id: 'two', group: 'beta' }], 'rows', null, { db, tx: setup })
|
|
57
|
-
await setupDone
|
|
58
|
-
|
|
59
|
-
const tx = db.transaction(['rows'], 'readonly')
|
|
60
|
-
const done = transactionDone(tx)
|
|
61
|
-
const p = deferred()
|
|
62
|
-
let cursor = (await run('openCursor', [], 'rows', null, { db, tx, p })).result
|
|
63
|
-
const ids = []
|
|
64
|
-
while (cursor) {
|
|
65
|
-
ids.push(cursor.value.id)
|
|
66
|
-
Object.assign(p, deferred())
|
|
67
|
-
cursor.continue()
|
|
68
|
-
cursor = (await p.promise).result
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
assert.deepEqual(ids, ['one', 'two'])
|
|
72
|
-
await done
|
|
73
|
-
db.close()
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
test('run aborts a transaction when a request fails', async () => {
|
|
77
|
-
const db = await openRowsDb()
|
|
78
|
-
const tx = db.transaction(['rows'], 'readwrite')
|
|
79
|
-
const done = transactionDone(tx)
|
|
80
|
-
|
|
81
|
-
await run('add', [{ id: 'one', group: 'alpha' }], 'rows', null, { db, tx })
|
|
82
|
-
await assert.rejects(
|
|
83
|
-
run('add', [{ id: 'one', group: 'beta' }], 'rows', null, { db, tx })
|
|
84
|
-
)
|
|
85
|
-
await assert.rejects(done)
|
|
86
|
-
|
|
87
|
-
const read = db.transaction(['rows'], 'readonly')
|
|
88
|
-
const row = await run('get', ['one'], 'rows', null, { db, tx: read })
|
|
89
|
-
assert.equal(row.result, undefined)
|
|
90
|
-
db.close()
|
|
91
|
-
})
|
package/tests/nip44-v3.test.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import { readFileSync } from 'node:fs'
|
|
4
|
-
import { getPublicKey } from 'nostr-tools'
|
|
5
|
-
import { sha256 } from '@noble/hashes/sha2.js'
|
|
6
|
-
|
|
7
|
-
import * as nip44v3 from '../nip44-v3/index.js'
|
|
8
|
-
import { bytesToHex, hexToBytes } from '../base16/index.js'
|
|
9
|
-
|
|
10
|
-
const vectors = JSON.parse(readFileSync(new URL('./fixtures/nip44v3-vectors.json', import.meta.url), 'utf8'))
|
|
11
|
-
|
|
12
|
-
function pubOf (sec) {
|
|
13
|
-
return getPublicKey(hexToBytes(sec))
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
test('nip44-v3 passes the vendored upstream self-test vectors', () => {
|
|
17
|
-
const fails = []
|
|
18
|
-
const check = (section, name, cond, detail = '') => {
|
|
19
|
-
if (!cond) fails.push(`[${section}] ${name}${detail ? `: ${detail}` : ''}`)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
for (const [i, v] of (vectors.encrypt_decrypt || []).entries()) {
|
|
23
|
-
const sec1 = hexToBytes(v.secret1)
|
|
24
|
-
const sec2 = hexToBytes(v.secret2)
|
|
25
|
-
const pub1 = pubOf(v.secret1)
|
|
26
|
-
const pub2 = pubOf(v.secret2)
|
|
27
|
-
const nonce = hexToBytes(v.nonce)
|
|
28
|
-
const scope = hexToBytes(v.scope_hex)
|
|
29
|
-
const plaintext = hexToBytes(v.plaintext_hex)
|
|
30
|
-
const keys = nip44v3.deriveKeys(sec1, pub2, nonce)
|
|
31
|
-
check('encrypt_decrypt', `ed[${i}] prk`, bytesToHex(keys.prk) === v.prk)
|
|
32
|
-
check('encrypt_decrypt', `ed[${i}] encryption_key`, bytesToHex(keys.encryption_key) === v.encryption_key)
|
|
33
|
-
check('encrypt_decrypt', `ed[${i}] mac_key`, bytesToHex(keys.mac_key) === v.mac_key)
|
|
34
|
-
check('encrypt_decrypt', `ed[${i}] encrypt party1`, nip44v3.encryptBytes(sec1, pub2, v.kind, scope, plaintext, nonce) === v.ciphertext)
|
|
35
|
-
check('encrypt_decrypt', `ed[${i}] encrypt party2`, nip44v3.encryptBytes(sec2, pub1, v.kind, scope, plaintext, nonce) === v.ciphertext)
|
|
36
|
-
check('encrypt_decrypt', `ed[${i}] decrypt party1`, bytesToHex(nip44v3.decryptBytes(sec1, pub2, v.kind, scope, v.ciphertext)) === v.plaintext_hex)
|
|
37
|
-
check('encrypt_decrypt', `ed[${i}] decrypt party2`, bytesToHex(nip44v3.decryptBytes(sec2, pub1, v.kind, scope, v.ciphertext)) === v.plaintext_hex)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
for (const [i, v] of (vectors.decrypt_only || []).entries()) {
|
|
41
|
-
check('decrypt_only', `do[${i}]`, bytesToHex(nip44v3.decryptBytes(hexToBytes(v.secret1), pubOf(v.secret2), v.kind, hexToBytes(v.scope_hex), v.ciphertext)) === v.plaintext_hex)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
for (const [i, v] of (vectors.long_encrypt_decrypt || []).entries()) {
|
|
45
|
-
const pattern = hexToBytes(v.pattern_hex)
|
|
46
|
-
const plaintext = new Uint8Array(pattern.length * v.repeat)
|
|
47
|
-
for (let r = 0; r < v.repeat; r++) plaintext.set(pattern, r * pattern.length)
|
|
48
|
-
const scope = hexToBytes(v.scope_hex)
|
|
49
|
-
const ciphertext = nip44v3.encryptBytes(hexToBytes(v.secret1), pubOf(v.secret2), v.kind, scope, plaintext, hexToBytes(v.nonce))
|
|
50
|
-
check('long_encrypt_decrypt', `long[${i}] sha256`, bytesToHex(sha256(nip44v3.toBytes(ciphertext))) === v.ciphertext_sha256)
|
|
51
|
-
check('long_encrypt_decrypt', `long[${i}] round-trip`, bytesToHex(nip44v3.decryptBytes(hexToBytes(v.secret1), pubOf(v.secret2), v.kind, scope, ciphertext)) === bytesToHex(plaintext))
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
for (const row of (vectors.padded_length || [])) {
|
|
55
|
-
check('padded_length', `pad[${row[0]}]`, nip44v3.targetSize(row[0]) === row[1])
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
for (const [i, v] of (vectors.invalid_decryption || []).entries()) {
|
|
59
|
-
assert.throws(() => nip44v3.decryptBytes(hexToBytes(v.secret), v.public, v.kind, hexToBytes(v.scope_hex), v.ciphertext), Error, `invalid vector ${i} should reject`)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
assert.deepEqual(fails, [])
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
test('nip44-v3 byte payload helpers round-trip arbitrary bytes', () => {
|
|
66
|
-
const alice = hexToBytes('1'.repeat(64))
|
|
67
|
-
const bob = hexToBytes('2'.repeat(64))
|
|
68
|
-
const plaintext = nip44v3.b64encode(new Uint8Array([0, 1, 2, 127, 128, 255]))
|
|
69
|
-
const ciphertext = nip44v3.nip07Encrypt(alice, getPublicKey(bob), '30078', 'spec.nostr.land/nip44v3', plaintext)
|
|
70
|
-
|
|
71
|
-
assert.equal(nip44v3.nip07Decrypt(bob, getPublicKey(alice), 30078, 'spec.nostr.land/nip44v3', ciphertext), plaintext)
|
|
72
|
-
assert.throws(() => nip44v3.nip07Decrypt(bob, getPublicKey(alice), 1, 'spec.nostr.land/nip44v3', ciphertext), /kind mismatch/)
|
|
73
|
-
})
|