import assert from 'node:assert/strict'; import { test } from 'node:test'; import { closureUrl } from '@nibling/npm-gateway/protocol'; import { memoryCache } from '../src/gateway/index.ts'; import { handleRequest, type RouterEnv } from '../src/router.ts'; import { upstream } from '../src/upstream.ts'; // The query itself is tested in @nibling/npm-gateway; here, that the worker routes it, sends our // User-Agent upstream, and keeps its documents in the cache it is given. test('the worker answers dev.nibling.npm.getClosure from the cache it is given', async () => { const calls: string[] = []; const pending: Promise[] = []; const env: RouterEnv = { INDEX: { getByName: () => ({ getRecent: async () => ({ projects: [] }), getTrending: async () => ({ projects: [] }), getKnown: async () => [] }) }, APP_ORIGIN: 'https://nibling.run', SLINGSHOT_URL: 'https://slingshot.test', CONSTELLATION_URL: 'https://constellation.test', fetch: upstream(async (input, init) => { calls.push(`${new URL(String(input)).pathname} ${new Headers(init?.headers).get('user-agent')?.split('/')[0]}`); return Response.json({ 'dist-tags': { latest: '1.0.0' }, versions: { '1.0.0': { name: 'a', version: '1.0.0', dist: { tarball: 'https://registry.npmjs.org/a/-/a-1.0.0.tgz' } } } }); }), cache: memoryCache(() => 0), waitUntil: (promise) => void pending.push(promise), now: () => 0, }; const get = async () => { const url = closureUrl('https://api.nibling.run', { specs: ['a@^1'] }); const res = await handleRequest(new Request(url), env); const body = (await res.text()).trim().split('\n').map((l) => JSON.parse(l) as { t: string; name?: string; raw?: string }); await Promise.all(pending.splice(0)); return { res, body }; }; const first = await get(); assert.equal(first.res.status, 200); assert.deepEqual(first.body.map((l) => l.t), ['closure', 'spec', 'meta', 'end']); assert.deepEqual(calls, ['/a nibling.dev', '/a/1.0.0 nibling.dev']); const second = await get(); assert.equal(second.res.headers.get('x-nib-cache'), 'hit'); assert.equal(calls.length, 2); }); test('the worker names itself as an npm gateway in its did:web document', async () => { const env = { INDEX: { getByName: () => ({ getRecent: async () => ({ projects: [] }), getTrending: async () => ({ projects: [] }), getKnown: async () => [] }) }, APP_ORIGIN: 'https://nibling.run', SLINGSHOT_URL: 'https://slingshot.test', CONSTELLATION_URL: 'https://constellation.test', fetch: upstream(async () => new Response(null, { status: 500 })), cache: memoryCache(() => 0), waitUntil: () => undefined, now: () => 0, } satisfies RouterEnv; const doc = (await (await handleRequest(new Request('https://api.nibling.run/.well-known/did.json'), env)).json()) as { id: string; service: unknown[] }; assert.equal(doc.id, 'did:web:api.nibling.run'); assert.deepEqual(doc.service, [{ id: '#nibling_npm', type: 'NiblingNpmGateway', serviceEndpoint: 'https://api.nibling.run' }]); });