/**
* Test: Write achievements page using the production writeContentViaWebSocket
*/
import { writeContentViaWebSocket } from "../src/yjs-ws-writer.js";
import { markdownToSchema } from "../src/markdown-parser.js";
import { loadEncryptedCookie } from "../src/crypto.js";
import * as fs from "fs";
import * as path from "path";
import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const envFile = fs.readFileSync(path.resolve(__dirname, "..", ".env"), "utf-8");
for (const line of envFile.split("\n")) {
const m = line.match(/^([^#=]+)=(.*)$/);
if (m) process.env[m[1].trim()] = m[2].trim();
}
const host = process.env.FUSEBASE_HOST!;
// Prefer encrypted cookie store, fall back to env
const stored = loadEncryptedCookie();
const cookie = stored?.cookie || process.env.FUSEBASE_COOKIE!;
console.log(`π Cookie source: ${stored?.cookie ? "encrypted store" : ".env file"} (${cookie.length} chars)`);
const wsId = "45h7lom5ryjak34u";
const pageId = "FLkcqYXSj0gZ6KMQ";
const markdown = `# π Fusebase MCP β Project Achievements
## Overview
This document tracks the milestones achieved in building native Fusebase MCP integration β from initial API discovery to full Y.js WebSocket content writing.
---
## π¬ Phase 1: API Discovery & Authentication
- **Cookie-based auth** β Reverse-engineered session cookie format from browser traffic
- **Encrypted cookie storage** β AES-256-GCM encrypted persistence in data/cookie.enc
- **Auto-refresh** β Playwright-based cookie renewal when sessions expire
- **API mapping** β Documented 40+ internal REST endpoints across workspaces, pages, folders, tasks, tags, files, and members
---
## π¦ Phase 2: MCP Server Foundation
- **18 core tools** β Full CRUD for pages, folders, tasks, tags, files, and members
- **Cached workspace/folder data** β Persistent JSON cache with TTL for fast lookups
- **API response logging** β Rotated log files for debugging API changes
- **Zod schema validation** β Type-safe parameter handling for all tools
---
## π Phase 3: Content Reading
- **HTML content extraction** β get_page_content returns rendered HTML from pages
- **Attachment listing** β Images, files, audio with MIME types and UUIDs
- **Page metadata** β Title, dates, size, sharing status, emoji
---
## βοΈ Phase 4: Content Writing (The Hard Part)
- **Markdown parser** β Converts markdown to Fusebase's ContentBlock schema
- **Block types** β Headings (H1/H2/H3), paragraphs, bullet lists, numbered lists, checklists, dividers, blockquotes, code blocks
- **Inline formatting** β Bold, italic with toggle-attribute pattern
- **Y.js WebSocket protocol** β Reverse-engineered the complete binary sync protocol
---
## π Phase 5: Native Y.js WebSocket Writer
- **7 iterations** to crack the protocol (V1 through V7b)
- **Key discovery** β Y.js uses a SEPARATE raw WebSocket on text.nimbusweb.me, not Socket.IO
- **JWT auth in URL** β Token obtained from /tokens endpoint, passed as query parameter
- **V2 binary encoding** β Server requires encv2=true for update encoding
- **Binary message protocol** β Sync Step 1/2/Update, Awareness, Ping/Pong
- **532-byte first successful write** β Content verified via dump endpoint
---
## π Achievement Summary
1. **Tools Implemented** β 18 Core + Extended Set
1. **Content Types Supported** β 8 Block Types + 2 Inline Formats
1. **Protocol Iterations** β 7 Versions to Working Writer
1. **Lines of Production Code** β ~600 (writer + schema + parser)
1. **Authentication Methods** β Cookie + JWT + WebSocket Token
---
## π― Technical Highlights
> The breakthrough came from capturing live WebSocket traffic via Playwright CDP β revealing that Fusebase routes Y.js sync through a dedicated text.nimbusweb.me host with JWT authentication embedded in the URL query string.
> Every content edit in Fusebase β from typing a single character to pasting an entire document β flows through this Y.js CRDT sync protocol. By speaking this protocol natively, the MCP server can write content with the same fidelity as the browser editor.
`;
async function main() {
console.log("π Converting markdown to schema...");
const blocks = markdownToSchema(markdown);
console.log(` ${blocks.length} blocks`);
console.log("π Writing via native Y.js WebSocket...");
const result = await writeContentViaWebSocket(host, wsId, pageId, cookie, blocks, { replace: true });
if (result.success) {
console.log("β
SUCCESS! Content written to page.");
console.log(` https://${host}/note/${pageId}`);
} else {
console.log(`β FAILED: ${result.error}`);
}
}
main().catch(console.error);