fix: share-links missen het /ipfs/-segment

- gatewayLink() bouwde <gateway>/<cid>; dat pad bestaat niet in deze app
- Nu <gateway>/ipfs/<cid>, wat overeenkomt met de route GET /ipfs/<cid>
- Gateway-basis komt uit gatewayUrl() in lib/config.ts (NEXT_PUBLIC_GATEWAY_URL)
- Optionele filename -> ?filename=, uitgeconsumed door dezelfde route
- downloadViaGateway() hergebruikt de helper i.p.v. eigen gateway-constant
  (valideerde fallback-host was de oude maos.dedyn.io)
- helpers.test.ts legde het foute pad vast; asserties vervangen door de
  werkelijke vorm + een test op de config-override
This commit is contained in:
maikrolf
2026-10-01 19:13:43 +02:00
parent 88f2c7e5aa
commit 4a5b146713
3 changed files with 65 additions and 11 deletions
+38 -6
View File
@@ -1,6 +1,13 @@
import { describe, it, expect } from 'vitest';
import { describe, it, expect, afterEach } from 'vitest';
import { formatBytes, gatewayLink, gatewayUrl, truncateCid } from '../helpers';
const ORIGINAL_GATEWAY = process.env.NEXT_PUBLIC_GATEWAY_URL;
afterEach(() => {
if (ORIGINAL_GATEWAY === undefined) delete process.env.NEXT_PUBLIC_GATEWAY_URL;
else process.env.NEXT_PUBLIC_GATEWAY_URL = ORIGINAL_GATEWAY;
});
describe('formatBytes', () => {
it('formats 0 as "0 B"', () => {
expect(formatBytes(0)).toBe('0 B');
@@ -68,18 +75,43 @@ describe('formatBytes', () => {
});
describe('gatewayLink', () => {
it('returns correct gateway URL for valid CID', () => {
it('zet het CID achter het /ipfs/-segment van de gateway', () => {
const cid = 'QmTest123';
expect(gatewayLink(cid)).toBe('https://ipfs.maos.dedyn.io/QmTest123');
expect(gatewayLink(cid)).toBe('https://ipfs.maos.dedyn.io/ipfs/QmTest123');
});
it('handles bafy CIDs', () => {
const cid = 'bafybeigdyrzt5xxyjaz6k3w3h3y7a7q7q7q7q7q7q7q7q7q7q7q7q7q';
expect(gatewayLink(cid)).toBe('https://ipfs.maos.dedyn.io/bafybeigdyrzt5xxyjaz6k3w3h3y7a7q7q7q7q7q7q7q7q7q7q7q7q7q');
const cid = 'bafybeigdyrzt5xxyjaz6k3w3h3y7a7q7q7q7q7q7q7q7q7q7q7q7q';
expect(gatewayLink(cid)).toBe('https://ipfs.maos.dedyn.io/ipfs/bafybeigdyrzt5xxyjaz6k3w3h3y7a7q7q7q7q7q7q7q7q7q7q7q7q');
});
it('handles empty string', () => {
expect(gatewayLink('')).toBe('https://ipfs.maos.dedyn.io/');
expect(gatewayLink('')).toBe('https://ipfs.maos.dedyn.io/ipfs/');
});
it('volgt de geconfigureerde gateway uit config.ts', () => {
process.env.NEXT_PUBLIC_GATEWAY_URL = 'https://gateway.example.org';
expect(gatewayLink('QmTest123')).toBe('https://gateway.example.org/ipfs/QmTest123');
});
it('verwijdert een trailing slash van de geconfigureerde gateway', () => {
process.env.NEXT_PUBLIC_GATEWAY_URL = 'https://gateway.example.org/';
expect(gatewayLink('QmTest123')).toBe('https://gateway.example.org/ipfs/QmTest123');
});
it('laat de gateway nooit dubbel sluiten als de CID leeg is', () => {
process.env.NEXT_PUBLIC_GATEWAY_URL = 'https://gateway.example.org/';
expect(gatewayLink('')).toBe('https://gateway.example.org/ipfs/');
});
it('voegt een ?filename= suffix toe voor de gateway-route', () => {
expect(gatewayLink('QmTest123', 'rap portaal.txt')).toBe(
'https://ipfs.maos.dedyn.io/ipfs/QmTest123?filename=rap%20portaal.txt',
);
});
it('laat de query-string weg als er geen filename is', () => {
expect(gatewayLink('QmTest123')).not.toContain('?');
});
});
+3 -2
View File
@@ -2,6 +2,8 @@
* Utility om IPFS content te downloaden als bestand.
*/
import { gatewayLink } from './helpers';
/**
* Download een bestand van IPFS via de explorer/cat proxy.
* Maakt een Blob van de response en simuleert een klik op <a download>.
@@ -34,9 +36,8 @@ export async function downloadFile(cid: string, filename?: string): Promise<void
* Download via gateway (alternatief als proxy traag is).
*/
export function downloadViaGateway(cid: string, filename?: string) {
const gateway = process.env.NEXT_PUBLIC_GATEWAY_URL || 'https://maos.dedyn.io';
const a = document.createElement('a');
a.href = `${gateway}/ipfs/${cid}`;
a.href = gatewayLink(cid);
a.download = filename || cid;
a.target = '_blank';
a.rel = 'noopener noreferrer';
+24 -3
View File
@@ -1,3 +1,5 @@
import { gatewayUrl as configuredGatewayUrl } from './config';
/* ── Format bytes to human-readable size ── */
export function formatBytes(bytes: number | bigint): string {
const b = typeof bytes === 'bigint' ? Number(bytes) : bytes;
@@ -8,9 +10,28 @@ export function formatBytes(bytes: number | bigint): string {
return val < 10 ? val.toFixed(1) + ' ' + units[i] : Math.round(val) + ' ' + units[i];
}
/* ── Gateway link for CID ── */
export function gatewayLink(cid: string): string {
return `https://ipfs.maos.dedyn.io/${cid}`;
/* ── Gateway link voor CID ── */
/**
* Basis-URL van de gateway, zonder trailing slash.
* Eén bron van waarheid: `gatewayUrl()` in `src/lib/config.ts`
* (env `NEXT_PUBLIC_GATEWAY_URL`, fallback `https://ipfs.maos.dedyn.io`).
*/
export function gatewayBaseUrl(): string {
return configuredGatewayUrl().replace(/\/+$/, '');
}
/**
* Deelbare gateway-link voor een CID.
*
* Het pad moet het `/ipfs/`-segment bevatten: de portal served content op
* `GET /ipfs/<cid>` (`src/app/ipfs/[cid]/route.ts`), niet op `/<cid>`.
* Een optionele `filename` komt als `?filename=` terecht, wat diezelfde route
* in `Content-Disposition` verwerkt.
*/
export function gatewayLink(cid: string, filename?: string): string {
const suffix = filename ? `?filename=${encodeURIComponent(filename)}` : '';
return `${gatewayBaseUrl()}/ipfs/${cid}${suffix}`;
}
/** Alias for gatewayLink — used in FilePreview */