chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
/**
* Which source answers "who last changed this file": the account's server
* where it serves the dev.pdsjs.git reads, the walk in this page where it
* does not, or where the server will not open the repository whole.
*/
import { beforeEach, describe, expect, it, vi } from 'vitest';
/** Fresh module state per test, because the route's standing is remembered. */
async function load() {
vi.resetModules();
const git = await import('../src/lib/git.js');
git.account.did = 'did:plc:owner';
git.account.pds = 'https://pds.example.com';
git.account.handle = 'owner.example.com';
return git;
}
/** @type {string[]} */
let asked = [];
/** @param {(url: string) => Response} answer */
function stubFetch(answer) {
asked = [];
vi.stubGlobal('fetch', async (/** @type {string|URL|Request} */ input) => {
const url = String(
typeof input === 'object' && 'url' in input ? input.url : input,
);
asked.push(url);
return answer(url);
});
}
const json = (body, status = 200) =>
new Response(JSON.stringify(body), {
status,
headers: { 'Content-Type': 'application/json; charset=utf-8' },
});
const text = (body, status = 404) =>
new Response(body, { status, headers: { 'Content-Type': 'text/plain' } });
beforeEach(() => {
vi.unstubAllGlobals();
// The git service decision probes this page's own origin first; the stubs
// below refuse that probe, so the account's PDS stays the service.
vi.stubGlobal('location', new URL('https://site.example/'));
});
describe('lastCommitOf', () => {
const commit = { sha: 'a'.repeat(40), message: 'change it\n' };
const READS = [
'getTree',
'listFiles',
'getFile',
'getRaw',
'listCommits',
'getCommit',
'getLastCommit',
].map((name) => ({ value: `dev.pdsjs.git.${name}` }));
const methodAsks = () => asked.filter((url) => url.includes('getLastCommit'));
it('asks the method where describe lists the reads, never the route', async () => {
stubFetch((url) => {
if (url.includes('community.lexicon.service.describe')) {
return json({ methods: READS });
}
if (url.includes('dev.pdsjs.git.getLastCommit')) return json({ commit });
return text('');
});
const { lastCommitOf } = await load();
expect(await lastCommitOf('repo', 'main', 'src/index.js')).toEqual(commit);
expect(methodAsks()[0]).toBe(
'https://pds.example.com/xrpc/dev.pdsjs.git.getLastCommit' +
'?repo=repo&ref=main&path=src%2Findex.js',
);
});
// The server downloads a chain without indexes only up to a limit. Past
// it, this page reads the repository, and does not ask the server again.
it('reads for itself a repository the server will not open whole', async () => {
stubFetch((url) => {
if (url.includes('community.lexicon.service.describe')) {
return json({ methods: READS });
}
if (url.includes('dev.pdsjs.git.getLastCommit')) {
return json({ error: 'RepositoryTooLarge', message: 'too big' }, 400);
}
return json({ error: 'RecordNotFound' }, 404);
});
const { lastCommitOf } = await load();
// No record is in hand, so the in-page reader answers nothing.
expect(await lastCommitOf('repo', 'main', 'a.txt')).toBeNull();
expect(await lastCommitOf('repo', 'main', 'b.txt')).toBeNull();
expect(methodAsks()).toHaveLength(1);
});
it('walks in this page where the server serves no reads', async () => {
stubFetch(() => text(''));
const { lastCommitOf } = await load();
// No record is in hand, so the in-page reader answers nothing, and
// nothing asked the server for a commit.
expect(await lastCommitOf('repo', 'main', 'a.txt')).toBeNull();
expect(methodAsks()).toHaveLength(0);
});
});