add flat: boolean to subfs definition in place.wisp.fs to define if to merge flat or as a subdirectory, handle this logic better across backend and hosting service
···118118 type: 'string',
119119 format: 'at-uri',
120120 description:
121121- 'AT-URI pointing to a place.wisp.subfs record containing this subtree',
121121+ 'AT-URI pointing to a place.wisp.subfs record containing this subtree.',
122122+ },
123123+ flat: {
124124+ type: 'boolean',
125125+ description:
126126+ "If true, the subfs record's root entries are merged (flattened) into the parent directory, replacing the subfs entry. If false (default), the subfs entries are placed in a subdirectory with the subfs entry's name. Flat merging is useful for splitting large directories across multiple records while maintaining a flat structure.",
122127 },
123128 },
124129 },
···131136 main: {
132137 type: 'record',
133138 description:
134134- 'Virtual filesystem manifest within a place.wisp.fs record',
139139+ 'Virtual filesystem subtree referenced by place.wisp.fs records. When a subfs entry is expanded, its root entries are merged (flattened) into the parent directory, allowing large directories to be split across multiple records while maintaining a flat structure.',
135140 record: {
136141 type: 'object',
137142 required: ['root', 'createdAt'],
···230235 type: 'string',
231236 format: 'at-uri',
232237 description:
233233- 'AT-URI pointing to another place.wisp.subfs record for nested subtrees',
238238+ "AT-URI pointing to another place.wisp.subfs record for nested subtrees. When expanded, the referenced record's root entries are merged (flattened) into the parent directory, allowing recursive splitting of large directory structures.",
234239 },
235240 },
236241 },
···9393export interface Subfs {
9494 $type?: 'place.wisp.fs#subfs'
9595 type: 'subfs'
9696- /** AT-URI pointing to a place.wisp.subfs record containing this subtree */
9696+ /** AT-URI pointing to a place.wisp.subfs record containing this subtree. */
9797 subject: string
9898+ /** If true, the subfs record's root entries are merged (flattened) into the parent directory, replacing the subfs entry. If false (default), the subfs entries are placed in a subdirectory with the subfs entry's name. Flat merging is useful for splitting large directories across multiple records while maintaining a flat structure. */
9999+ flat?: boolean
98100}
99101100102const hashSubfs = 'subfs'
···9292export interface Subfs {
9393 $type?: 'place.wisp.subfs#subfs'
9494 type: 'subfs'
9595- /** AT-URI pointing to another place.wisp.subfs record for nested subtrees */
9595+ /** AT-URI pointing to another place.wisp.subfs record for nested subtrees. When expanded, the referenced record's root entries are merged (flattened) into the parent directory, allowing recursive splitting of large directory structures. */
9696 subject: string
9797}
9898
···295295 const node = entry.node;
296296297297 if ('type' in node && node.type === 'subfs') {
298298- // Merge subfs entries into parent directory
298298+ // Check if this is a flat merge or subdirectory merge (default to flat if not specified)
299299+ const subfsNode = node as any;
300300+ const isFlat = subfsNode.flat !== false; // Default to true
299301 const subfsEntries = subfsMap.get(fullPath);
302302+300303 if (subfsEntries) {
301301- console.log(`Merging subfs node at ${fullPath} (${subfsEntries.length} entries)`);
302302- // Recursively process the merged entries in case they contain nested subfs
303303- const processedEntries = replaceSubfsInEntries(subfsEntries, currentPath);
304304- result.push(...processedEntries);
304304+ console.log(`Merging subfs node at ${fullPath} (${subfsEntries.length} entries, flat: ${isFlat})`);
305305+306306+ if (isFlat) {
307307+ // Flat merge: hoist entries directly into parent directory
308308+ const processedEntries = replaceSubfsInEntries(subfsEntries, currentPath);
309309+ result.push(...processedEntries);
310310+ } else {
311311+ // Subdirectory merge: create a directory with the subfs node's name
312312+ const processedEntries = replaceSubfsInEntries(subfsEntries, fullPath);
313313+ result.push({
314314+ name: entry.name,
315315+ node: {
316316+ type: 'directory',
317317+ entries: processedEntries
318318+ }
319319+ });
320320+ }
305321 } else {
306322 // If fetch failed, skip this entry
307323 console.warn(`Failed to fetch subfs at ${fullPath}, skipping`);
···491507492508 // Download new/changed files concurrently - increased from 3 to 20 for much better performance
493509 const downloadLimit = 20;
510510+ let successCount = 0;
511511+ let failureCount = 0;
512512+494513 for (let i = 0; i < downloadTasks.length; i += downloadLimit) {
495514 const batch = downloadTasks.slice(i, i + downloadLimit);
496496- await Promise.all(batch.map(task => task()));
515515+ const results = await Promise.allSettled(batch.map(task => task()));
516516+517517+ // Count successes and failures
518518+ results.forEach((result, index) => {
519519+ if (result.status === 'fulfilled') {
520520+ successCount++;
521521+ } else {
522522+ failureCount++;
523523+ console.error(`[Cache] Failed to download file (continuing with others):`, result.reason);
524524+ }
525525+ });
526526+497527 if (downloadTasks.length > downloadLimit) {
498498- console.log(`[Cache Progress] Downloaded ${Math.min(i + downloadLimit, downloadTasks.length)}/${downloadTasks.length} files`);
528528+ console.log(`[Cache Progress] Downloaded ${Math.min(i + downloadLimit, downloadTasks.length)}/${downloadTasks.length} files (${failureCount} failed)`);
499529 }
530530+ }
531531+532532+ if (failureCount > 0) {
533533+ console.warn(`[Cache] Completed with ${successCount} successful and ${failureCount} failed file downloads`);
500534 }
501535}
502536···555589 }
556590557591 const blobUrl = `${pdsEndpoint}/xrpc/com.atproto.sync.getBlob?did=${encodeURIComponent(did)}&cid=${encodeURIComponent(cid)}`;
592592+593593+ console.log(`[Cache] Fetching blob for file: ${filePath}, CID: ${cid}`);
558594559595 // Allow up to 500MB per file blob, with 5 minute timeout
560596 let content = await safeFetchBlob(blobUrl, { maxSize: 500 * 1024 * 1024, timeout: 300000 });
+2-1
lexicons/fs.json
···5151 "required": ["type", "subject"],
5252 "properties": {
5353 "type": { "type": "string", "const": "subfs" },
5454- "subject": { "type": "string", "format": "at-uri", "description": "AT-URI pointing to a place.wisp.subfs record containing this subtree. When expanded, the subfs record's root entries are merged (flattened) into the parent directory - the subfs entry itself is removed and replaced by all entries from the referenced record's root. This allows splitting large directories across multiple records while maintaining a flat structure." }
5454+ "subject": { "type": "string", "format": "at-uri", "description": "AT-URI pointing to a place.wisp.subfs record containing this subtree." },
5555+ "flat": { "type": "boolean", "description": "If true, the subfs record's root entries are merged (flattened) into the parent directory, replacing the subfs entry. If false (default), the subfs entries are placed in a subdirectory with the subfs entry's name. Flat merging is useful for splitting large directories across multiple records while maintaining a flat structure." }
5556 }
5657 }
5758 }
+8-3
src/lexicons/lexicons.ts
···118118 type: 'string',
119119 format: 'at-uri',
120120 description:
121121- 'AT-URI pointing to a place.wisp.subfs record containing this subtree',
121121+ 'AT-URI pointing to a place.wisp.subfs record containing this subtree.',
122122+ },
123123+ flat: {
124124+ type: 'boolean',
125125+ description:
126126+ "If true, the subfs record's root entries are merged (flattened) into the parent directory, replacing the subfs entry. If false (default), the subfs entries are placed in a subdirectory with the subfs entry's name. Flat merging is useful for splitting large directories across multiple records while maintaining a flat structure.",
122127 },
123128 },
124129 },
···131136 main: {
132137 type: 'record',
133138 description:
134134- 'Virtual filesystem manifest within a place.wisp.fs record',
139139+ 'Virtual filesystem subtree referenced by place.wisp.fs records. When a subfs entry is expanded, its root entries are merged (flattened) into the parent directory, allowing large directories to be split across multiple records while maintaining a flat structure.',
135140 record: {
136141 type: 'object',
137142 required: ['root', 'createdAt'],
···230235 type: 'string',
231236 format: 'at-uri',
232237 description:
233233- 'AT-URI pointing to another place.wisp.subfs record for nested subtrees',
238238+ "AT-URI pointing to another place.wisp.subfs record for nested subtrees. When expanded, the referenced record's root entries are merged (flattened) into the parent directory, allowing recursive splitting of large directory structures.",
234239 },
235240 },
236241 },
+3-1
src/lexicons/types/place/wisp/fs.ts
···9393export interface Subfs {
9494 $type?: 'place.wisp.fs#subfs'
9595 type: 'subfs'
9696- /** AT-URI pointing to a place.wisp.subfs record containing this subtree */
9696+ /** AT-URI pointing to a place.wisp.subfs record containing this subtree. */
9797 subject: string
9898+ /** If true, the subfs record's root entries are merged (flattened) into the parent directory, replacing the subfs entry. If false (default), the subfs entries are placed in a subdirectory with the subfs entry's name. Flat merging is useful for splitting large directories across multiple records while maintaining a flat structure. */
9999+ flat?: boolean
98100}
99101100102const hashSubfs = 'subfs'
+1-1
src/lexicons/types/place/wisp/subfs.ts
···9292export interface Subfs {
9393 $type?: 'place.wisp.subfs#subfs'
9494 type: 'subfs'
9595- /** AT-URI pointing to another place.wisp.subfs record for nested subtrees */
9595+ /** AT-URI pointing to another place.wisp.subfs record for nested subtrees. When expanded, the referenced record's root entries are merged (flattened) into the parent directory, allowing recursive splitting of large directory structures. */
9696 subject: string
9797}
9898