diff --git a/src/lib/encoding.test.ts b/src/lib/encoding.test.ts index 2f4cd9ad..9d4857ef 100644 --- a/src/lib/encoding.test.ts +++ b/src/lib/encoding.test.ts @@ -247,6 +247,14 @@ describe('Manifest parsing', () => { expect(id).to.equal('cG7Hdi_iTQPoEYgQJFqJ8NMpN4KoZ-vH_j7pG4iP7NI'); }); + it('should return wildcard file for files not present in manifest', async ()=>{ + const id=await resolveManifestStreamPath( + exampleManifestStream(), + 'path/that/does/not/exist.txt' + ); + expect(id).to.equal('vNIcG7HdiMpFqJ8NZN4KopG4_iTQPoH_j7iP7EYgQJ-') + }) + it('should return the ID for non-index paths', async () => { // TODO use an array here const id1 = await resolveManifestStreamPath( diff --git a/src/lib/encoding.ts b/src/lib/encoding.ts index ead72d81..a3e21de1 100644 --- a/src/lib/encoding.ts +++ b/src/lib/encoding.ts @@ -231,6 +231,7 @@ export function parseManifestStream(stream: Readable): EventEmitter { let currentKey: string | undefined; const keyPath: Array = []; let indexPath: string | undefined; + let wildcardPath: string | undefined; let paths: { [k: string]: string } = {}; let hasValidManifestKey = false; // { "manifest": "arweave/paths" } let hasValidManifestVersion = false; // { "version": "0.1.0" } @@ -277,8 +278,8 @@ export function parseManifestStream(stream: Readable): EventEmitter { hasValidManifestKey = true; } - // Manifest version - { "version": "0.1.0" } - if (keyPath.length === 0 && currentKey === 'version' && data === '0.1.0') { + // Manifest version - { "version": "0.2.0" } or { "version": "0.1.0" } + if (keyPath.length === 0 && currentKey === 'version' && ["0.1.0", "0.2.0"].includes(data)) { hasValidManifestVersion = true; } @@ -295,6 +296,30 @@ export function parseManifestStream(stream: Readable): EventEmitter { paths = {}; } } + + // Wildcard - { "*": { "path": "404.html" } } + if ( + keyPath.length === 1 && + keyPath[0] === '*' && + currentKey === 'path' + ) { + wildcardPath = data; + // Resolve if the path id is already known + if (wildcardPath !== undefined && paths[wildcardPath] !== undefined) { + emitter.emit('wildcard', { path: wildcardPath, id: paths[wildcardPath] }); + paths = {}; + } + } + + // Wildcard - { "*": { "id": "wildcard-id" } } + if ( + keyPath.length === 1 && + keyPath[0] === '*' && + currentKey === 'id' + ) { + emitter.emit('wildcard', { path: null, id: data }); + paths = {}; + } // Paths - { "paths": { "some/path/file.html": { "id": "" } } if ( @@ -311,6 +336,9 @@ export function parseManifestStream(stream: Readable): EventEmitter { } else if (p === indexPath) { emitter.emit('index', { path: p, id: data }); paths = {}; + } else if (p === wildcardPath){ + emitter.emit('wildcard', { path: p, id: data }); + paths = {}; } } }); @@ -324,20 +352,26 @@ export function resolveManifestStreamPath( ): Promise { return new Promise((resolve, reject) => { const emitter = parseManifestStream(stream); - + let resolved=false // Remove trailing slashes from path - treat /path and /path/ the same + let wildcard; const sanitizedPath = path !== undefined ? path.replace(/\/+$/g, '') : ''; emitter.on('error', (err) => { + resolved=true reject(err); }); emitter.on('end', () => { - resolve(undefined); + if(!resolved){ + resolved=true + resolve(wildcard); + } }); emitter.on('index', (data) => { if (sanitizedPath === '') { + resolved=true resolve(data.id); } }); @@ -345,8 +379,14 @@ export function resolveManifestStreamPath( emitter.on('path', (data) => { const trimmedDataPath = data.path.replace(/\/+$/g, ''); if (sanitizedPath !== '' && trimmedDataPath === sanitizedPath) { + resolved=true resolve(data.id); } }); + + emitter.on('wildcard',(data) => { + wildcard=data + }) + }); } diff --git a/test/mock_files/manifests/example_manifest.json b/test/mock_files/manifests/example_manifest.json index 95672c70..e12a273b 100644 --- a/test/mock_files/manifests/example_manifest.json +++ b/test/mock_files/manifests/example_manifest.json @@ -1,8 +1,11 @@ { "manifest": "arweave/paths", - "version": "0.1.0", + "version": "0.2.0", + "*":{ + "id":"vNIcG7HdiMpFqJ8NZN4KopG4_iTQPoH_j7iP7EYgQJ-" + }, "index": { - "path": "index.html" + "path": "index.html", }, "paths": { "index.html": {