~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
118 lines · 3.8 KB Raw History
// The drive browser over the real SQLite actor storage. The package's own
// tests page a fake whose cursor is an index; this storage returns an rkey and
// stops sending one on a short page, so the paging loop is only honest here.

import Database from 'better-sqlite3';
import { describe, expect, it } from 'vitest';
import {
  CID,
  cborEncodeDagCbor,
  cidToString,
  createBlobCid,
  createCid,
} from '../packages/core/src/repo.js';
import { createDriveBrowser } from '../packages/drive/src/browser.js';
import { createActorStorage } from '../packages/storage-sqlite/src/index.js';

const DID = 'did:plc:drivestorage';

// The folder record every nested file names by key.
const FOLDER_RKEY = '3rfolder0001';

// Above the browser's 100-record page size, so paging runs several times and
// the final short page ends it.
const FILE_COUNT = 250;

async function seeded() {
  const actorStorage = createActorStorage(new Database(':memory:'));
  await actorStorage.setDid(DID);

  const folderValue = cborEncodeDagCbor({
    $type: 'dev.pdsjs.drive.folder',
    name: 'photos',
    createdAt: '2026-08-14T00:00:00.000Z',
  });
  await actorStorage.putRecord(
    `at://${DID}/dev.pdsjs.drive.folder/${FOLDER_RKEY}`,
    cidToString(await createCid(folderValue)),
    'dev.pdsjs.drive.folder',
    FOLDER_RKEY,
    folderValue,
  );

  /** @type {Map<string, Uint8Array>} */
  const blobStore = new Map();
  for (let index = 0; index < FILE_COUNT; index += 1) {
    const data = new TextEncoder().encode(`contents of file ${index}`);
    blobStore.set(cidToString(await createBlobCid(data)), data);
    const value = cborEncodeDagCbor({
      $type: 'dev.pdsjs.drive.file',
      name: `file-${String(index).padStart(3, '0')}.txt`,
      // Half at the top level, half nested, so both branches page.
      ...(index % 2 === 0 ? { folder: FOLDER_RKEY } : {}),
      parts: [
        {
          $type: 'blob',
          ref: new CID(await createBlobCid(data)),
          mimeType: 'application/octet-stream',
          size: data.length,
        },
      ],
      mimeType: 'text/plain',
      createdAt: '2026-08-14T00:00:00.000Z',
    });
    const rkey = `3rkey${String(index).padStart(4, '0')}`;
    await actorStorage.putRecord(
      `at://${DID}/dev.pdsjs.drive.file/${rkey}`,
      cidToString(await createCid(value)),
      'dev.pdsjs.drive.file',
      rkey,
      value,
    );
  }

  const blobs = /** @type {any} */ ({
    get: async (/** @type {string} */ _did, /** @type {string} */ cid) => {
      const data = blobStore.get(cid);
      return data ? { data, mimeType: 'application/octet-stream' } : null;
    },
  });

  return createDriveBrowser({
    actorStorage: /** @type {any} */ (actorStorage),
    blobs,
    getDid: async () => DID,
  });
}

describe('drive browser over sqlite storage', () => {
  it('pages every record, not just the first page', async () => {
    const browser = await seeded();
    const root = await browser.listFolder('');
    expect(root?.totalFiles).toBe(FILE_COUNT);
    expect(root?.files).toHaveLength(FILE_COUNT / 2);
    expect(root?.folders).toEqual([
      {
        rkey: FOLDER_RKEY,
        name: 'photos',
        files: FILE_COUNT / 2,
        size: expect.any(Number),
        createdAt: '2026-08-14T00:00:00.000Z',
      },
    ]);
  });

  it('lists a nested folder across pages', async () => {
    const browser = await seeded();
    const nested = await browser.listFolder(FOLDER_RKEY);
    expect(nested?.files).toHaveLength(FILE_COUNT / 2);
    expect(nested?.folders).toEqual([]);
  });

  it('reads the bytes of one file back', async () => {
    const browser = await seeded();
    const file = await browser.readFile('3rkey0000');
    expect(new TextDecoder().decode(file?.bytes)).toBe('contents of file 0');
    expect(file?.mimeType).toBe('text/plain');
  });
});