@@ -3,7 +3,7 @@ import path from "path";
33import mime from "mime-types" ;
44import { pathToFileURL } from "url" ;
55
6- function generateDirectoryListing ( dirPath , entries , allFilesForPublishing ) {
6+ function generateDirectoryListing ( dirPath , entries ) {
77 const parentPath = path . dirname ( dirPath ) ;
88 const parentDirName = path . basename ( parentPath ) || 'Parent Directory' ;
99
@@ -92,8 +92,26 @@ function generateDirectoryListing(dirPath, entries, allFilesForPublishing) {
9292 <div id="result"></div>
9393
9494 <script>
95- // This list is now pre-compiled by the main process with all recursive files and correct paths!
96- const allFiles = ${ JSON . stringify ( allFilesForPublishing ) } ;
95+ let manifestCache = null;
96+
97+ async function loadManifest() {
98+ if (manifestCache) return manifestCache;
99+
100+ const manifestUrl = new URL(window.location.href);
101+ manifestUrl.searchParams.set('__publishManifest', '1');
102+
103+ const response = await fetch(manifestUrl.toString(), {
104+ headers: { 'Accept': 'application/json' }
105+ });
106+
107+ if (!response.ok) {
108+ throw new Error('Failed to load directory manifest');
109+ }
110+
111+ const data = await response.json();
112+ manifestCache = data.files || [];
113+ return manifestCache;
114+ }
97115
98116 async function publishDirectory() {
99117 const protocol = document.getElementById('protocolSelect').value;
@@ -106,20 +124,21 @@ function generateDirectoryListing(dirPath, entries, allFilesForPublishing) {
106124 publishBtn.disabled = true;
107125
108126 try {
109- if (allFiles.length === 0) {
127+ const files = await loadManifest();
128+
129+ if (files.length === 0) {
110130 throw new Error('No files found in this directory or its subdirectories.');
111131 }
112-
132+
113133 if (protocol === 'hyper') {
114- // Hypercore upload
115134 const hyperdriveUrl = await generateHyperdriveKey('directory-' + Date.now());
116135 console.log('Hyper base URL:', hyperdriveUrl);
117-
118- for (const fileEntry of allFiles ) {
136+
137+ for (const fileEntry of files ) {
119138 const url = hyperdriveUrl + encodeURIComponent(fileEntry.relativePath);
120139 console.log('Uploading', fileEntry.relativePath, 'to', url);
121-
122- const fileResponse = await fetch('file://' + fileEntry.path );
140+
141+ const fileResponse = await fetch(fileEntry.fileUrl );
123142 const blob = await fileResponse.blob();
124143
125144 const uploadResponse = await fetch(url, {
@@ -143,26 +162,20 @@ function generateDirectoryListing(dirPath, entries, allFilesForPublishing) {
143162 result.appendChild(hyperAnchor);
144163
145164 } else {
146- // IPFS upload - exactly like upload.html
147165 const formData = new FormData();
148-
149- for (const fileEntry of allFiles) {
150- console.log('Processing file:', fileEntry.relativePath, 'size:', fileEntry.size);
151-
152- // Convert base64 back to blob
153- const binaryString = atob(fileEntry.base64);
154- const bytes = new Uint8Array(binaryString.length);
155- for (let i = 0; i < binaryString.length; i++) {
156- bytes[i] = binaryString.charCodeAt(i);
166+
167+ for (const fileEntry of files) {
168+ console.log('Processing file:', fileEntry.relativePath);
169+
170+ const response = await fetch(fileEntry.fileUrl);
171+ if (!response.ok) {
172+ throw new Error('Failed to read ' + fileEntry.relativePath);
157173 }
158- const blob = new Blob([bytes], { type: 'application/octet-stream' });
159-
160- // Use the relative path as the file name to preserve directory structure
174+ const blob = await response.blob();
175+
161176 const fileName = fileEntry.relativePath || fileEntry.name;
162- console.log('Creating File with name:', fileName);
163- const file = new File([blob], fileName, { type: 'application/octet-stream' });
164-
165- // The third argument to append() is what IPFS uses as the filename.
177+ const file = new File([blob], fileName, { type: blob.type || 'application/octet-stream' });
178+
166179 formData.append('file', file, fileName);
167180 }
168181
@@ -253,19 +266,17 @@ export async function createHandler() {
253266 const subFiles = await getFilesRecursive ( fullPath , relativePath ) ;
254267 allFiles . push ( ...subFiles ) ;
255268 } else {
256- // Read the file content and convert to base64 for embedding
257269 try {
258- const fileContent = await fs . readFile ( fullPath ) ;
259- const base64Content = fileContent . toString ( 'base64' ) ;
270+ const stat = await fs . stat ( fullPath ) ;
260271 allFiles . push ( {
261272 name : entry . name ,
262273 path : fullPath ,
263- relativePath : relativePath ,
264- base64 : base64Content ,
265- size : fileContent . length
274+ relativePath,
275+ size : stat . size ,
276+ fileUrl : pathToFileURL ( fullPath ) . href
266277 } ) ;
267278 } catch ( err ) {
268- console . error ( 'Could not read file:' , fullPath , err ) ;
279+ console . error ( 'Could not stat file:' , fullPath , err ) ;
269280 }
270281 }
271282 }
@@ -288,6 +299,18 @@ export async function createHandler() {
288299 console . log ( 'Path stats:' , filePath , 'isDirectory:' , stats . isDirectory ( ) , 'isFile:' , stats . isFile ( ) ) ;
289300
290301 if ( stats . isDirectory ( ) ) {
302+ // Handle manifest requests first (used for publishing)
303+ if ( url . searchParams . get ( '__publishManifest' ) === '1' ) {
304+ const manifest = await getFilesRecursive ( filePath , '' ) ;
305+ return new Response ( JSON . stringify ( { files : manifest } ) , {
306+ status : 200 ,
307+ headers : {
308+ 'Content-Type' : 'application/json; charset=utf-8' ,
309+ 'Cache-Control' : 'no-cache'
310+ }
311+ } ) ;
312+ }
313+
291314 // For directories, read entries for the current level to display
292315 const dirEntries = await fs . readdir ( filePath ) ;
293316 const entryStats = await Promise . all (
@@ -309,13 +332,7 @@ export async function createHandler() {
309332
310333 const validEntries = entryStats . filter ( e => e !== null ) ;
311334
312- // **BEFORE** generating the HTML, read the *entire* directory recursively.
313- // This gives the script embedded in the HTML the full list of files to publish.
314- // Don't use the directory name as base path - just use empty string
315- // so paths are relative to the current directory
316- const allFilesForPublishing = await getFilesRecursive ( filePath , '' ) ;
317-
318- const html = generateDirectoryListing ( filePath , validEntries , allFilesForPublishing ) ;
335+ const html = generateDirectoryListing ( filePath , validEntries ) ;
319336
320337 return new Response ( html , {
321338 status : 200 ,
0 commit comments