import test from 'brittle'
import fs from 'bare-fs'
import path from 'bare-path'
import os from 'bare-os'
import Corestore from 'corestore'
import * as Y from 'yjs'
import { SharedNotebook } from '../lib/multiwriter/shared-notebook.js'
function tmpDir () {
const dir = path.join(os.tmpdir(), 'hn-snb-' + Date.now() + '-' + Math.random().toString(36).slice(2))
fs.mkdirSync(dir, { recursive: true })
return dir
}
function rmrf (dir) {
try {
for (const f of fs.readdirSync(dir)) {
const fp = path.join(dir, f)
const stat = fs.statSync(fp)
if (stat.isDirectory()) rmrf(fp)
else fs.unlinkSync(fp)
}
fs.rmdirSync(dir)
} catch {}
}
test('create and get note', async (t) => {
const dir = tmpDir()
const store = new Corestore(dir)
const nb = new SharedNotebook(store, 'test-nb')
await nb.ready()
const { noteId } = await nb.createNote({ title: 'Hello World', author: 'alice', tags: ['greeting'] })
t.ok(noteId, 'noteId is returned')
t.is(noteId.length, 16, 'noteId is 16 hex chars')
const note = await nb.getNote(noteId)
t.ok(note, 'note exists')
t.is(note.title, 'Hello World')
t.is(note.author, 'alice')
t.alike(note.tags, ['greeting'])
t.ok(note.createdAt, 'has createdAt')
await nb.close()
await store.close()
rmrf(dir)
})
test('apply Yjs update and reconstruct', async (t) => {
const dir = tmpDir()
const store = new Corestore(dir)
const nb = new SharedNotebook(store, 'yjs-nb')
await nb.ready()
const { noteId } = await nb.createNote({ title: 'Yjs Note', author: 'alice' })
// Create a Y.Doc, insert text, encode update
const doc = new Y.Doc()
const text = doc.getText('content')
text.insert(0, 'Hello collaborative world!')
const update = Y.encodeStateAsUpdate(doc)
await nb.applyYjsUpdate(noteId, update, 'alice')
// Verify cached doc has the text
const cachedDoc = nb.getDoc(noteId)
t.ok(cachedDoc, 'cached doc exists')
t.is(cachedDoc.getText('content').toString(), 'Hello collaborative world!')
// Reconstruct from Autobase storage
const reconstructed = await nb.reconstructDoc(noteId)
t.ok(reconstructed, 'reconstructed doc exists')
t.is(reconstructed.getText('content').toString(), 'Hello collaborative world!')
await nb.close()
await store.close()
rmrf(dir)
})
test('list notes — create 2, verify 2', async (t) => {
const dir = tmpDir()
const store = new Corestore(dir)
const nb = new SharedNotebook(store, 'list-nb')
await nb.ready()
await nb.createNote({ title: 'Note A', author: 'alice' })
await nb.createNote({ title: 'Note B', author: 'bob' })
const notes = await nb.listNotes()
t.is(notes.length, 2, 'two notes listed')
const titles = notes.map(n => n.title).sort()
t.alike(titles, ['Note A', 'Note B'])
await nb.close()
await store.close()
rmrf(dir)
})
test('delete note', async (t) => {
const dir = tmpDir()
const store = new Corestore(dir)
const nb = new SharedNotebook(store, 'del-nb')
await nb.ready()
const { noteId } = await nb.createNote({ title: 'To Delete', author: 'alice' })
let note = await nb.getNote(noteId)
t.ok(note, 'note exists before delete')
await nb.deleteNote(noteId, 'alice')
note = await nb.getNote(noteId)
t.is(note, null, 'note is null after delete')
await nb.close()
await store.close()
rmrf(dir)
})
test('add media metadata', async (t) => {
const dir = tmpDir()
const store = new Corestore(dir)
const nb = new SharedNotebook(store, 'media-nb')
await nb.ready()
const { noteId } = await nb.createNote({ title: 'Media Note', author: 'alice' })
await nb.addMedia(noteId, {
hash: 'abc123def456',
mimeType: 'image/png',
filename: 'photo.png',
size: 12345
}, 'alice')
const media = await nb.getMedia(noteId, 'abc123def456')
t.ok(media, 'media exists')
t.is(media.hash, 'abc123def456')
t.is(media.mimeType, 'image/png')
t.is(media.filename, 'photo.png')
t.is(media.size, 12345)
t.is(media.author, 'alice')
t.ok(media.addedAt, 'has addedAt')
// Remove media
await nb.removeMedia(noteId, 'abc123def456', 'alice')
const removed = await nb.getMedia(noteId, 'abc123def456')
t.is(removed, null, 'media removed')
await nb.close()
await store.close()
rmrf(dir)
})
test('bootstrapKey available after ready', async (t) => {
const dir = tmpDir()
const store = new Corestore(dir)
const nb = new SharedNotebook(store, 'key-nb')
await nb.ready()
t.ok(nb.bootstrapKey, 'bootstrapKey exists')
t.is(nb.bootstrapKey.length, 32, 'bootstrapKey is 32 bytes')
t.ok(nb.localWriterKey, 'localWriterKey exists')
t.is(nb.localWriterKey.length, 32, 'localWriterKey is 32 bytes')
await nb.close()
await store.close()
rmrf(dir)
})