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:
@@ -1,6 +1,13 @@
|
|||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect, afterEach } from 'vitest';
|
||||||
import { formatBytes, gatewayLink, gatewayUrl, truncateCid } from '../helpers';
|
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', () => {
|
describe('formatBytes', () => {
|
||||||
it('formats 0 as "0 B"', () => {
|
it('formats 0 as "0 B"', () => {
|
||||||
expect(formatBytes(0)).toBe('0 B');
|
expect(formatBytes(0)).toBe('0 B');
|
||||||
@@ -68,18 +75,43 @@ describe('formatBytes', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('gatewayLink', () => {
|
describe('gatewayLink', () => {
|
||||||
it('returns correct gateway URL for valid CID', () => {
|
it('zet het CID achter het /ipfs/-segment van de gateway', () => {
|
||||||
const cid = 'QmTest123';
|
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', () => {
|
it('handles bafy CIDs', () => {
|
||||||
const cid = 'bafybeigdyrzt5xxyjaz6k3w3h3y7a7q7q7q7q7q7q7q7q7q7q7q7q7q';
|
const cid = 'bafybeigdyrzt5xxyjaz6k3w3h3y7a7q7q7q7q7q7q7q7q7q7q7q7q';
|
||||||
expect(gatewayLink(cid)).toBe('https://ipfs.maos.dedyn.io/bafybeigdyrzt5xxyjaz6k3w3h3y7a7q7q7q7q7q7q7q7q7q7q7q7q7q');
|
expect(gatewayLink(cid)).toBe('https://ipfs.maos.dedyn.io/ipfs/bafybeigdyrzt5xxyjaz6k3w3h3y7a7q7q7q7q7q7q7q7q7q7q7q7q');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles empty string', () => {
|
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
@@ -2,6 +2,8 @@
|
|||||||
* Utility om IPFS content te downloaden als bestand.
|
* Utility om IPFS content te downloaden als bestand.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { gatewayLink } from './helpers';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download een bestand van IPFS via de explorer/cat proxy.
|
* Download een bestand van IPFS via de explorer/cat proxy.
|
||||||
* Maakt een Blob van de response en simuleert een klik op <a download>.
|
* 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).
|
* Download via gateway (alternatief als proxy traag is).
|
||||||
*/
|
*/
|
||||||
export function downloadViaGateway(cid: string, filename?: string) {
|
export function downloadViaGateway(cid: string, filename?: string) {
|
||||||
const gateway = process.env.NEXT_PUBLIC_GATEWAY_URL || 'https://maos.dedyn.io';
|
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = `${gateway}/ipfs/${cid}`;
|
a.href = gatewayLink(cid);
|
||||||
a.download = filename || cid;
|
a.download = filename || cid;
|
||||||
a.target = '_blank';
|
a.target = '_blank';
|
||||||
a.rel = 'noopener noreferrer';
|
a.rel = 'noopener noreferrer';
|
||||||
|
|||||||
+24
-3
@@ -1,3 +1,5 @@
|
|||||||
|
import { gatewayUrl as configuredGatewayUrl } from './config';
|
||||||
|
|
||||||
/* ── Format bytes to human-readable size ── */
|
/* ── Format bytes to human-readable size ── */
|
||||||
export function formatBytes(bytes: number | bigint): string {
|
export function formatBytes(bytes: number | bigint): string {
|
||||||
const b = typeof bytes === 'bigint' ? Number(bytes) : bytes;
|
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];
|
return val < 10 ? val.toFixed(1) + ' ' + units[i] : Math.round(val) + ' ' + units[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Gateway link for CID ── */
|
/* ── Gateway link voor CID ── */
|
||||||
export function gatewayLink(cid: string): string {
|
|
||||||
return `https://ipfs.maos.dedyn.io/${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 */
|
/** Alias for gatewayLink — used in FilePreview */
|
||||||
|
|||||||
Reference in New Issue
Block a user