PageSourceSearch

https://id.priyadi.net/assets/lib/file-manager/services/FileSystemService-EHMbqgt.js

js priyadi.net collected 2026-10-02 06:19:56 UTC 114,581 bytes, 2,522 lines download raw bytes

1function _array_like_to_array(arr, len) {
2    if (len == null || len > arr.length) len = arr.length;
3    for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
4    return arr2;
5}
6function _array_without_holes(arr) {
7    if (Array.isArray(arr)) return _array_like_to_array(arr);
8}
9function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
10    try {
11        var info = gen[key](arg);
12        var value = info.value;
13    } catch (error) {
14        reject(error);
15        return;
16    }
17    if (info.done) {
18        resolve(value);
19    } else {
20        Promise.resolve(value).then(_next, _throw);
21    }
22}
23function _async_to_generator(fn) {
24    return function() {
25        var self = this, args = arguments;
26        return new Promise(function(resolve, reject) {
27            var gen = fn.apply(self, args);
28            function _next(value) {
29                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
30            }
31            function _throw(err) {
32                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
33            }
34            _next(undefined);
35        });
36    };
37}
38function _class_call_check(instance, Constructor) {
39    if (!(instance instanceof Constructor)) {
40        throw new TypeError("Cannot call a class as a function");
41    }
42}
43function _defineProperties(target, props) {
44    for(var i = 0; i < props.length; i++){
45        var descriptor = props[i];
46        descriptor.enumerable = descriptor.enumerable || false;
47        descriptor.configurable = true;
48        if ("value" in descriptor) descriptor.writable = true;
49        Object.defineProperty(target, descriptor.key, descriptor);
50    }
51}
52function _create_class(Constructor, protoProps, staticProps) {
53    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
54    if (staticProps) _defineProperties(Constructor, staticProps);
55    return Constructor;
56}
57function _define_property(obj, key, value) {
58    if (key in obj) {
59        Object.defineProperty(obj, key, {
60            value: value,
61            enumerable: true,
62            configurable: true,
63            writable: true
64        });
65    } else {
66        obj[key] = value;
67    }
68    return obj;
69}
70function _instanceof(left, right) {
71    if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
72        return !!right[Symbol.hasInstance](left);
73    } else {
74        return left instanceof right;
75    }
76}
77function _iterable_to_array(iter) {
78    if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
79}
80function _non_iterable_spread() {
81    throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
82}
83function _to_consumable_array(arr) {
84    return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
85}
86function _unsupported_iterable_to_array(o, minLen) {
87    if (!o) return;
88    if (typeof o === "string") return _array_like_to_array(o, minLen);
89    var n = Object.prototype.toString.call(o).slice(8, -1);
90    if (n === "Object" && o.constructor) n = o.constructor.name;
91    if (n === "Map" || n === "Set") return Array.from(n);
92    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
93}
94function _ts_generator(thisArg, body) {
95    var f, y, t, g, _ = {
96        label: 0,
97        sent: function() {
98            if (t[0] & 1) throw t[1];
99            return t[1];
100        },
101        trys: [],
102        ops: []
103    };
104    return(g = {
105        next: verb(0),
106        "throw": verb(1),
107        "return": verb(2)
108    }, typeof Symbol === "function" && (g[Symbol.iterator] = function() {
109        return this;
110    }), g);
111    function verb(n) {
112        return function(v) {
113            return step([
114                n,
115                v
116            ]);
117        };
118    }
119    function step(op) {
120        if (f) throw new TypeError("Generator is already executing.");
121        while(_)try {
122            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
123            if (y = 0, t) op = [
124                op[0] & 2,
125                t.value
126            ];
127            switch(op[0]){
128                case 0:
129                case 1:
130                    t = op;
131                    break;
132                case 4:
133                    _.label++;
134                    return {
135                        value: op[1],
136                        done: false
137                    };
138                case 5:
139                    _.label++;
140                    y = op[1];
141                    op = [
142                        0
143                    ];
144                    continue;
145                case 7:
146                    op = _.ops.pop();
147                    _.trys.pop();
148                    continue;
149                default:
150                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
151                        _ = 0;
152                        continue;
153                    }
154                    if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
155                        _.label = op[1];
156                        break;
157                    }
158                    if (op[0] === 6 && _.label < t[1]) {
159                        _.label = t[1];
160                        t = op;
161                        break;
162                    }
163                    if (t && _.label < t[2]) {
164                        _.label = t[2];
165                        _.ops.push(op);
166                        break;
167                    }
168                    if (t[2]) _.ops.pop();
169                    _.trys.pop();
170                    continue;
171            }
172            op = body.call(thisArg, _);
173        } catch (e) {
174            op = [
175                6,
176                e
177            ];
178            y = 0;
179        } finally{
180            f = t = 0;
181        }
182        if (op[0] & 5) throw op[1];
183        return {
184            value: op[0] ? op[1] : void 0,
185            done: true
186        };
187    }
188}
189import { FileSystemNode } from "../models/FileSystemNode.js";
190/**
191 * Service for interacting with the FileSystem API
192 *
193 * Handles API calls, caching, and event dispatching for file system operations.
194 * Uses opaque node identifiers from the API - never parses or constructs them client-side.
195 *
196 * THE WIRE, AND WHY IT LOOKS LIKE THIS
197 * ------------------------------------
198 * Every call below goes to `/api/v1/files*` — the same official,
199 * documented, scope-gated endpoints a third-party API client or an MCP
200 * agent drives. There is no longer a private `/fs/*` surface behind the
201 * file manager, which is the whole point of the exercise: one
202 * implementation, one authorization path, one set of bugs.
203 *
204 * Two things the endpoints do differently for us, both deliberate and
205 * both documented server-side:
206 *
207 *  - `Accept: application/jsonl` asks for the flat node shape rather
208 *    than a JSON:API document. That shape embeds a directory's ancestor
209 *    chain and a symlink's resolved target inline, which the tree, the
210 *    breadcrumb and the open-a-symlink path all need on every row, and
211 *    which JSON:API would put in `included` — somewhere a *stream* has
212 *    nowhere to put. The listing additionally comes back unpaginated,
213 *    because this client sorts the complete set client-side.
214 *  - Writes send a JSON:API request envelope (`{data: {type, …}}`),
215 *    because the request half of the codec is not negotiable.
216 *
217 * Failures are always JSON:API `errors` documents, hence
218 * `readErrorMessage()`. The result shapes this class *returns* are
219 * unchanged from when it spoke to `/fs/*`: it is the seam, and the
220 * controllers above it should not know the wire changed.
221 */ export var FileSystemService = /*#__PURE__*/ function() {
222    "use strict";
223    function FileSystemService(config) {
224        _class_call_check(this, FileSystemService);
225        _define_property(this, "config", void 0);
226        _define_property(this, "cache", new Map());
227        _define_property(this, "eventHandlers", new Map());
228        _define_property(this, "abortControllers", new Map());
229        this.config = config;
230    }
231    _create_class(FileSystemService, [
232        {
233            key: "getCachedNode",
234            value: /**
235     * Get node from cache (uses state controller if provided, otherwise internal 
235cache)
236     */ function getCachedNode(identifier) {
237                if (this.config.stateController) {
238                    return this.config.stateController.getCachedNode(identifier);
239                }
240                return this.cache.get(identifier);
241            }
242        },
243        {
244            key: "hasInCache",
245            value: /**
246     * Check if node is in cache (uses state controller if provided, otherwise internal cache)
247     */ function hasInCache(identifier) {
248                if (this.config.stateController) {
249                    return this.config.stateController.hasNodeInCache(identifier);
250                }
251                return this.cache.has(identifier);
252            }
253        },
254        {
255            key: "setCachedNode",
256            value: /**
257     * Add node to cache (uses state controller if provided, otherwise internal cache)
258     */ function setCachedNode(identifier, node) {
259                if (this.config.stateController) {
260                    this.config.stateController.cacheNode(identifier, node);
261                } else {
262                    this.cache.set(identifier, node);
263                }
264            }
265        },
266        {
267            key: "handleAuthenticationError",
268            value: /**
269     * Check if response indicates authentication failure and reload page if so.
270     * Returns true if the page will reload (caller should stop processing).
271     */ function handleAuthenticationError(response) {
272                // Check for 401 Unauthorized (session expired)
273                if (response.status === 401) {
274                    window.location.reload();
275                    return true;
276                }
277                // A file served from the content endpoint carries an attachment
278                // disposition and may legitimately be text/html — the user is allowed to
279                // edit their own HTML. The login page never sets that header, so this
280                // check has to come before the one below or opening any .html file
281                // reloads the page.
282                var disposition = response.headers.get("Content-Disposition") || "";
283                if (disposition.includes("attachment")) {
284                    return false;
285                }
286                // Check if a successful response returned HTML instead of JSON (login page redirect).
287                // Only check on 2xx/3xx responses; 4xx/5xx HTML responses are legitimate server errors,
288                // not login redirects (e.g. Symfony error pages for permission denied on mode 0 directories).
289                if (response.ok) {
290                    var contentType = response.headers.get("Content-Type") || "";
291                    if (contentType.includes("text/html")) {
292                        window.location.reload();
293                        return true;
294                    }
295                }
296                return false;
297            }
298        },
299        {
300            /**
301     * Subscribe to file system events
302     */ key: "on",
303            value: function on(type, handler) {
304                var _this = this;
305                if (!this.eventHandlers.has(type)) {
306                    this.eventHandlers.set(type, new Set());
307                }
308                this.eventHandlers.get(type).add(handler);
309                // Return unsubscribe function
310                return function() {
311                    var _this_eventHandlers_get;
312                    (_this_eventHandlers_get = _this.eventHandlers.get(type)) === null || _this_eventHandlers_get === void 0 ? void 0 : _this_eventHandlers_get.delete(handler);
313                };
314            }
315        },
316        {
317            key: "emit",
318            value: /**
319     * Emit an event to all subscribers
320     */ function emit(event) {
321                var handlers = this.eventHandlers.get(event.type);
322                if (handlers) {
323                    handlers.forEach(function(handler) {
324                        return handler(event);
325                    });
326                }
327            }
328        },
329        {
330            key: "nodeUrl",
331            value: /**
332     * The URL of one node.
333     *
334     * The identifier is base64url, so it needs no escaping to be a path
335     * segment — it is encoded anyway, because "the identifier is opaque"
336     * is a promise this client keeps rather than an assumption it makes.
337     */ function nodeUrl(identifier) {
338                var suffix = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "";
339                return "/api/v1/files/".concat(encodeURIComponent(identifier)).concat(suffix);
340            }
341        },
342        {
343            key: "postAction",
344            value: /**
345     * Perform one of the verbs on a node.
346     *
347     * A verb does not get a route of its own: `POST {id}/actions` with
348     * the action named by the posted `data.type` is how the whole API
349     * spells "do this to that". The response is the flat shape — an
350     * affected node for most actions, a report for the removals and the
351     * batches.
352     */ function postAction(identifier, action) {
353                var attributes = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {};
354                var _this = this;
355                return _async_to_generator(function() {
356                    return _ts_generator(this, function(_state) {
357                        switch(_state.label){
358                            case 0:
359                                return [
360                                    4,
361                                    _this.send("POST", _this.nodeUrl(identifier, "/actions"), {
362                                        type: action,
363                                        attributes: attributes
364                                    })
365                                ];
366                            case 1:
367                                return [
368                                    2,
369                                    _state.sent()
370                                ];
371                        }
372                    });
373                })();
374            }
375        },
376        {
377            key: "send",
378            value: /**
379     * Send a JSON:API resource object and read the flat answer.
380     *
381     * The asymmetry is the codec's: request bodies must be JSON:API
382     * envelopes, responses are negotiated, and this client asks for the
383     * flat one.
384     */ function send(method, url, resource) {
385                var _this = this;
386                return _async_to_generator(function() {
387                    var response;
388                    return _ts_generator(this, function(_state) {
389                        switch(_state.label){
390                            case 0:
391                                return [
392                                    4,
393                                    fetch(url, {
394                                        method: method,
395                                        headers: {
396                                            "Accept": FileSystemService.FLAT,
397                                            "Content-Type": FileSystemService.JSON_API
398                                        },
399                                        body: JSON.stringify({
400                                            data: resource
401                                        })
402                                    })
403                                ];
404                            case 1:
405                                response = _state.sent();
406                                return [
407                                    4,
408                                    _this.readJson(response)
409                                ];
410                            case 2:
411                                return [
412                                    2,
413                                    _state.sent()
414                                ];
415                        }
416                    });
417                })();
418            }
419        },
420        {
421            key: "request",
422            value: /**
423     * A GET or DELETE answering the flat shape.
424     */ function request(method, url) {
425                var _this = this;
426                return _async_to_generator(function() {
427                    var response;
428                    return _ts_generator(this, function(_state) {
429                        switch(_state.label){
430                            case 0:
431                                return [
432                                    4,
433                                    fetch(url, {
434                                        method: method,
435                                        headers: {
436                                            "Accept": FileSystemService.FLAT
437                                        }
438                                    })
439                                ];
440                            case 1:
441                                response = _state.sent();
442                                return [
443                                    4,
444                                    _this.readJson(response)
445                                ];
446                            case 2:
447                                return [
448                                    2,
449                                    _state.sent()
450                                ];
451                        }
452                    });
453                })();
454            }
455        },
456        {
457            key: "readJson",
458            value: /**
459     * Session expiry first, then the error document, then the body.
460     */ function readJson(response) {
461                var _this = this;
462                return _async_to_generator(function() {
463                    var _;
464                    return _ts_generator(this, function(_state) {
465                        switch(_state.label){
466                            case 0:
467                                if (_this.handleAuthenticationError(response)) {
468                                    throw new Error("Session expired");
469                                }
470                                if (!!response.ok) return [
471                                    3,
472                                    2
473                                ];
474                                _ = Error.bind;
475                                return [
476                                    4,
477                                    _this.readErrorMessage(response)
478                                ];
479                            case 1:
480                                throw new (_.apply(Error, [
481                                    void 0,
482                                    _state.sent()
483                                ]));
484                            case 2:
485                                return [
486                                    4,
487                                    response.json()
488                                ];
489                            case 3:
490                                return [
491                                    2,
492                                    _state.sent()
493                                ];
494                        }
495                    });
496                })();
497            }
498        },
499        {
500            key: "cancelPendingRequest",
501            value: /**
502     * Cancel any pending request
503     */ function cancelPendingRequest(key) {
504                var controller = this.abortControllers.get(key);
505                if (controller) {
506                    controller.abort();
507                    this.abortControllers.delete(key);
508                }
509            }
510        },
511        {
512            key: "getNode",
513            value: /**
514     * Fetch metadata for a single node by its opaque identifier
515     */ function getNode(identifier) {
516                var useCache = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : true;
517                var _this = this;
518                return _async_to_generator(function() {
519                    var controller, response, _, data, node, error;
520                    return _ts_generator(this, function(_state) {
521                        switch(_state.label){
522                            case 0:
523                                // Check cache first
524                                if (useCache && _this.hasInCache(identifier)) {
525                                    return [
526                                        2,
527                                        _this.getCachedNode(identifier)
528                                    ];
529                                }
530                                _this.cancelPendingRequest("meta:".concat(identifier));
531                                controller = new AbortController();
532                                _this.abortControllers.set("meta:".concat(identifier), controller);
533                                _this.emit({
534                                    type: "node:loading",
535                                    identifier: identifier
536                                });
537                                _state.label = 1;
538                            case 1:
539                                _state.trys.push([
540                                    1,
541                                    6,
542                                    7,
543                                    8
544                                ]);
545                                return [
546                                    4,
547                                    fetch(_this.nodeUrl(identifier), {
548                                        signal: controller.signal,
549                                        headers: {
550                                            "Accept": FileSystemService.FLAT
551                                        }
552                                    })
553                                ];
554                            case 2:
555                                response = _state.sent();
556                                // Check for authentication failure before processing response
557                                if (_this.handleAuthenticationError(response)) {
558                                    throw new Error("Session expired");
559                                }
560                                if (!!response.ok) return [
561                                    3,
562                                    4
563                                ];
564                                _ = Error.bind;
565                                return [
566                                    4,
567                                    _this.readErrorMessage(response)
568                                ];
569                            case 3:
570                                throw new (_.apply(Error, [
571                                    void 0,
572                                    _state.sent()
573                                ]));
574                            case 4:
575                                return [
576                                    4,
577                                    response.json()
578                                ];
579                            case 5:
580                                data = _state.sent();
581                                node = FileSystemNode.fromData(data);
582                                // Cache the node by its identifier
583                                _this.setCachedNode(identifier, node);
584                                _this.emit({
585                                    type: "node:loaded",
586                                    identifier: identifier,
587                                    node: node
588                                });
589                                return [
590                                    2,
591                                    node
592                                ];
593                            case 6:
594                                error = _state.sent();
595                                if (_instanceof(error, Error) && error.
595name === "AbortError") {
596                                    throw error; // Re-throw abort errors
597                                }
598                                _this.emit({
599                                    type: "node:error",
600                                    identifier: identifier,
601                                    error: error
602                                });
603                                throw error;
604                            case 7:
605                                _this.abortControllers.delete("meta:".concat(identifier));
606                                return [
607                                    7
608                                ];
609                            case 8:
610                                return [
611                                    2
612                                ];
613                        }
614                    });
615                })();
616            }
617        },
618        {
619            key: "getChildren",
620            value: /**
621     * Fetch children of a directory using streaming JSONL
622     */ function getChildren(identifier) {
623                var _this = this;
624                return _async_to_generator(function() {
625                    var children;
626                    return _ts_generator(this, function(_state) {
627                        switch(_state.label){
628                            case 0:
629                                children = [];
630                                return [
631                                    4,
632                                    _this.getChildrenStreaming(identifier, function(child) {
633                                        children.push(child);
634                                    })
635                                ];
636                            case 1:
637                                _state.sent();
638                                return [
639                                    2,
640                                    children
641                                ];
642                        }
643                    });
644                })();
645            }
646        },
647        {
648            key: "getChildrenStreaming",
649            value: /**
650     * Fetch children of a directory using streaming JSONL with incremental callback.
651     * Calls onChild for each child as it's parsed from the stream.
652     * Also detects and emits events when subdirectories are found.
653     */ function getChildrenStreaming(identifier, onChild) {
654                var _this = this;
655                return _async_to_generator(function() {
656                    var controller, foundSubdirectory, parentNode, onChildWithSubdirectoryDetection, response, _, allChildren, error;
657                    return _ts_generator(this, function(_state) {
658                        switch(_state.label){
659                            case 0:
660                                _this.cancelPendingRequest("list:".concat(identifier));
661                                controller = new AbortController();
662                                _this.abortControllers.set("list:".concat(identifier), controller);
663                                _this.emit({
664                                    type: "children:loading",
665                                    identifier: identifier
666                                });
667                                // Track if we've found a subdirectory
668                                foundSubdirectory = false;
669                                parentNode = _this.getCachedNode(identifier);
670                                // Wrapper to detect subdirectories during streaming
671                                onChildWithSubdirectoryDetection = function(child) {
672                                    // If this is the first directory found, emit event and update parent
673                                    if (!foundSubdirectory && child.isDirectory()) {
674                                        foundSubdirectory = true;
675                                        if (parentNode && parentNode.isDirectory()) {
676                                            parentNode.hasSubdirectory = true;
677                                            _this.emit({
678                                                type: "directory:hasSubdirectory",
679                                                identifier: identifier,
680                                                node: parentNode
681                                            });
682                                        }
683                                    }
684                                    onChild(child);
685                                };
686                                _state.label = 1;
687                            case 1:
688                                _state.trys.push([
689                                    1,
690                                    6,
691                                    7,
692                                    8
693                                ]);
694                                return [
695                                    4,
696                                    fetch("/api/v1/files?filter%5Bdirectory%5D=".concat(encodeURIComponent(identifier)), {
697                                        signal: controller.signal,
698                                        headers: {
699                                            "Accept": FileSystemService.FLAT
700                                        }
701                                    })
702                                ];
703                            case 2:
704                                response = _state.sent();
705                                // Check for authentication failure before processing response
706                                if (_this.handleAuthenticationError(response)) {
707                                    throw new Error("Session expired");
708                                }
709                                if (!!response.ok) return [
710                                    3,
711                                    4
712                                ];
713                                _ = Error.bind;
714                                return [
715                                    4,
716                                    _this.readErrorMessage(response)
717                                ];
718                            case 3:
719                                throw new (_.apply(Error, [
720                                    void 0,
721                                    _state.sent()
722                                ]));
723                            case 4:
724                                return [
725                                    4,
726                                    _this.parseJsonlResponseStreaming(response, onChildWithSubdirectoryDetection)
727                                ];
728                            case 5:
729                                allChildren = _state.sent();
730                                // Update cache for the parent directory if it exists
731                                if (parentNode && parentNode.isDirectory()) {
732                                    parentNode.children = allChildren;
733                                    // After all children loaded, if no subdirectory was found, set hasSubdirectory to false
734                                    if (!foundSubdirectory) {
735                                        parentNode.hasSubdirectory = false;
736                                    }
737                                }
738                                // Cache each child by its identifier
739                                allChildren.forEach(function(child) {
740                                    _this.setCachedNode(child.id, child);
741                                });
742                                _this.emit({
743                                    type: "children:loaded",
744                                    identifier: identifier,
745                                    children: allChildren
746                                });
747                                return [
748                                    3,
749                                    8
750                                ];
751                            case 6:
752                                error = _state.sent();
753                                if (_instanceof(error, Error) && error.name === "AbortError") {
754                                    throw error;
755                                }
756                                _this.emit({
757                                    type: "children:error",
758                                    identifier: identifier,
759                                    error: error
760                                });
761                                throw error;
762                            case 7:
763                                _this.abortControllers.delete("list:".concat(identifier));
764                                return [
765                                    7
766                                ];
767                            case 8:
768                                return [
769                                    2
770                                ];
771                        }
772                    });
773                })();
774            }
775        },
776        {
777            key: "parseJsonlResponseStreaming",
778            value: /**
779     * Parse JSONL (JSON Lines) response with streaming callback
780     */ function parseJsonlResponseStreaming(response, onChild) {
781                return _async_to_generator(function() {
782                    var children, text, lines, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, line, data, node, reader, decoder, buffer, _ref, done, value, data1, node1, lines1, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, line1, trimmedLine, data2, node2;
783                    return _ts_generator(this, function(_state) {
784                        switch(_state.label){
785                            case 0:
786                                children = [];
787                                if (!!response.body) return [
788                                    3,
789                                    2
790                                ];
791                                return [
792                                    4,
793                                    response.text()
794                                ];
795                            case 1:
796                                text = _state.sent();
797                                lines = text.trim().split("\n").filter(function(line) {
798                                    return line.length > 0;
799                                });
800                                _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
801                                try {
802                                    for(_iterator = lines[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
803                                        line = _step.value;
804                                        data = JSON.parse(line);
805                                        node = FileSystemNode.fromData(data);
806                                        children.push(node);
807                                        onChild(node);
808                                    }
809                                } catch (err) {
810                                    _didIteratorError = true;
811                                    _iteratorError = err;
812                                } finally{
813                                    try {
814                                        if (!_iteratorNormalCompletion && _iterator.return != null) {
815                                            _iterator.return();
816                                        }
817                                    } finally{
818                                        if (_didIteratorError) {
819                                            throw _iteratorError;
820                                        }
821                                    }
822                                }
823                                return [
824                                    2,
825                                    children
826                                ];
827                            case 2:
828                                reader = response.body.getReader();
829                                decoder = new TextDecoder();
830                                buffer = "";
831                                _state.label = 3;
832                            case 3:
833                                _state.trys.push([
834                                    3,
835                                    ,
836                                    7,
837                                    8
838                                ]);
839                                _state.label = 4;
840                            case 4:
841                                if (!true) return [
842                                    3,
843                                    6
844                                ];
845                                return [
846                                    4,
847                                    reader.read()
848                                ];
849                            case 5:
850                                _ref = _state.sent(), done = _ref.done, value = _ref.value;
851                                if (done) {
852                                    // Process any remaining data in buffer
853                                    if (buffer.trim()) {
854                                        data1 = JSON.parse(buffer.trim());
855                                        node1 = FileSystemNode.fromData(data1);
856                                        children.push(node1);
857                                        onChild(node1);
858                                    }
859                                    return [
860                                        3,
861                                        6
862                                    ];
863                                }
864                                buffer += decoder.decode(value, {
865                                    stream: true
866                                });
867                                // Process complete lines
868                                lines1 = buffer.split("\n");
869                                // Keep the last incomplete line in the buffer
870                                buffer = lines1.pop() || "";
871                                _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
872                                try {
873                                    for(_iterator1 = lines1[Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
874                                        line1 = _step1.value;
875                                        trimmedLine = line1.trim();
876                                        if (trimmedLine) {
877                                            data2 = JSON.parse(trimmedLine);
878                                            node2 = FileSystemNode.fromData(data2);
879                                            children.push(node2);
880                                            onChild(node2);
881                                        }
882                                    }
883                                } catch (err) {
884                                    _didIteratorError1 = true;
885                                    _iteratorError1 = err;
886                                } finally{
887                                    try {
888                                        if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
889                                            _iterator1.return();
890                                        }
891                                    } finally{
892                                        if (_didIteratorError1) {
893                                            throw _iteratorError1;
894                                        }
895                                    }
896                                }
897                                return [
898                                    3,
899                                    4
900                                ];
901                            case 6:
902                                return [
903                                    3,
904                                    8
905                                ];
906                            case 7:
907                                reader.releaseLock();
908                                return [
909                                    7
910                                ];
911                            case 8:
912                                return [
913                                    2,
914                                    children
915                                ];
916                        }
917                    });
918                })();
919            }
920        },
921        {
922            key: "loadDirectory",
923            value: /**
924     * Load a directory and its children by identifier
925     */ function loadDirectory(identifier) {
926                var _this = this;
927                return _async_to_generator(function() {
928                    var node, children;
929                    return _ts_generator(this, function(_state) {
930                        switch(_state.label){
931                            case 0:
932                                return [
933                                    4,
934                                    _this.getNode(identifier)
935                                ];
936                            case 1:
937                                node = _state.sent();
938                                if (!node.isDirectory()) {
939                                    throw new Error("Node is not a directory");
940                                }
941                                if (!!node.hasLoadedChildren) return [
942                                    3,
943                                    5
944                                ];
945                                node.isLoading = true;
946                                _state.label = 2;
947                            case 2:
948                                _state.trys.push([
949                                    2,
950                                    ,
951                                    4,
952                                    5
953                                ]);
954                                return [
955                                    4,
956                                    _this.getChildren(identifier)
957                                ];
958                            case 3:
959                                children = _state.sent();
960                                node.children = children;
961                                return [
962                                    3,
963                                    5
964                                ];
965                            case 4:
966                                node.isLoading = false;
967                                return [
968                                    7
969                                ];
970                            case 5:
971                                return [
972                                    2,
973                                    node
974                                ];
975                        }
976                    });
977                })();
978            }
979        },
980        {
981            key: "loadDirectoryStreaming",
982            value: /**
983     * Load a directory with streaming children updates.
984     * Calls onChildrenUpdate with the node and accumulated children as they stream in (debounced).
985     */ function loadDirectoryStreaming(identifier, onChildrenUpdate) {
986                var debounceMs = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : 50;
987                var _this = this;
988                return _async_to_generator(function() {
989                    var node, debounceTimer, pendingUpdate, scheduleUpdate;
990                    return _ts_generator(this, function(_state) {
991                        switch(_state.label){
992                            case 0:
993                                return [
994                                    4,
995                                    _this.getNode(identifier)
996                                ];
997                            case 1:
998                                node = _state.sent();
999                                if (!node.isDirectory()) {
1000                                    throw new Error("Node is not a directory");
1001                                }
1002                                if (!!node.hasLoadedChildren) return [
1003                                    3,
1004                                    6
1005                                ];
1006                                node.isLoading = true;
1007                                node.children = []; // Initialize empty array
1008                                debounceTimer = null;
1009                                pendingUpdate = false;
1010                                scheduleUpdate = function() {
1011                                    pendingUpdate = true;
1012                                    if (!debounceTimer) {
1013                                        debounceTimer = setTimeout(function() {
1014                                            debounceTimer = null;
1015                                            if (pendingUpdate) {
1016                                                pendingUpdate = false;
1017                                                onChildrenUpdate(node, _to_consumable_array(node.children));
1018                                            }
1019                                        }, debounceMs);
1020                                    }
1021                                };
1022                                _state.label = 2;
1023                            case 2:
1024                                _state.trys.push([
1025                                    2,
1026                                    ,
1027                                    4,
1028                                    5
1029                                ]);
1030                                return [
1031                                    4,
1032                                    _this.getChildrenStreaming(identifier, function(child) {
1033                                        node.children.push(child);
1034                                        scheduleUpdate();
1035                                    })
1036                                ];
1037                            case 3:
1038                                _state.sent();
1039                                // Final flush - ensure last update is sent
1040                                if (debounceTimer) {
1041                                    clearTimeout(debounceTimer);
1042                                }
1043                                onChildrenUpdate(node, _to_consumable_array(node.children));
1044                                return [
1045                                    3,
1046                                    5
1047                                ];
1048                            case 4:
1049                                node.isLoading = false;
1050                                if (debounceTimer) {
1051                                    clearTimeout(debounceTimer);
1052                                }
1053                                return [
1054                                    7
1055                                ];
1056                            case 5:
1057                                return [
1058                                    3,
1059                                    7
1060                                ];
1061                            case 6:
1062                                // Already loaded, just call the callback with existing children
1063                                onChildrenUpdate(node, _to_consumable_array(node.children));
1064                                _state.label = 7;
1065                            case 7:
1066                                return [
1067                                    2,
1068                                    node
1069                                ];
1070                        }
1071                    });
1072                })();
1073            }
1074        },
1075        {
1076            /**
1077     * Get the download URL for a file by its opaque identifier.
1078     *
1079     * This is the same endpoint the editor reads from; the attachment
1080     * disposition it responds with is what makes a browser save the file
1081     * instead of navigating to it.
1082     */ key: "getDownloadUrl",
1083            value: function getDownloadUrl(identifier) {
1084                return this.nodeUrl(identifier, "/content");
1085            }
1086        },
1087        {
1088            /**
1089     * Get the upload URL for a directory by its opaque identifier
1090     */ key: "getUploadUrl",
1091            value: function getUploadUrl(identifier) {
1092                return this.nodeUrl(identifier, "/uploads");
1093            }
1094        },
1095        {
1096            key: "trash",
1097            value: /**
1098     * Move a file or directory to trash.
1099     * Returns a TrashResult with status indicating success, not_found, or error.
1100     */ function trash(identifier) {
1101                var _this = this;
1102                return _async_to_generator(function() {
1103                    var report;
1104                    return _ts_generator(this, function(_state) {
1105                        switch(_state.label){
1106                            case 0:
1107                                return [
1108                                    4,
1109                                    _this.postAction(identifier, "file-trash")
1110                                ];
1111                            case 1:
1112                                report = _state.sent();
1113                                // Invalidate cache for the trashed identifier (regardless of status)
1114                                _this.invalidate(identifier);
1115                                return [
1116                                    2,
1117                                    {
1118                                        success: true,
1119                                        status: report.status === "already-absent" ? "not_found" : "trashed"
1120                                    }
1121                                ];
1122                        }
1123                    });
1124                })();
1125            }
1126        },
1127        {
1128            key: "trashMultiple",
1129            value: /**
1130     * Move multiple files or directories to trash.
1131     * Returns an object with successful identifiers (including not_found) and errors.
1132     * Identifiers that were 'not_found' are still considered success since the end state is the same.
1133     */ function trashMultiple(identifiers) {
1134                var _this = this;
1135                return _async_to_generator(function() {
1136                    var results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, identifier, result, error, err;
1137                    return _ts_generator(this, function(_state) {
1138                        switch(_state.label){
1139                            case 0:
1140                                results = {
1141                                    success: [],
1142                                    notFound: [],
1143                                    errors: []
1144                                };
1145                                _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1146                                _state.label = 1;
1147                            case 1:
1148                                _state.trys.push([
1149                                    1,
1150                                    8,
1151                                    9,
1152                                    10
1153                                ]);
1154                                _iterator = identifiers[Symbol.iterator]();
1155                                _state.label = 2;
1156                            case 2:
1157                                if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
1158                                    3,
1159                                    7
1160                                ];
1161                                identifier = _step.value;
1162                                _state.label = 3;
1163                            case 3:
1164                                _state.trys.push([
1165                                    3,
1166                                    5,
1167                                    ,
1168                                    6
1169                                ]);
1170                                return [
1171                                    4,
1172                                    _this.trash(identifier)
1173                                ];
1174                            case 4:
1175                                result = _state.sent();
1176                                if (result.status === "not_found") {
1177                                    results.notFound.push(identifier);
1178                                } else {
1179                                    results.success.push(identifier);
1180                                }
1181                                return [
1182                                    3,
1183                                    6
1184                                ];
1185                            case 5:
1186                                error = _state.sent();
1187                                results.errors.push({
1188                                    identifier: identifier,
1189                                    error: _instanceof(error, Error) ? error.message : String(error)
1190                                });
1191                                return [
1192                                    3,
1193                                    6
1194                                ];
1195                            case 6:
1196                                _iteratorNormalCompletion = true;
1197                                return [
1198                                    3,
1199                                    2
1200                                ];
1201                            case 7:
1202                                return [
1203                                    3,
1204                                    10
1205                                ];
1206                            case 8:
1207                                err = _state.sent();
1208                                _didIteratorError = true;
1209                                _iteratorError = err;
1210                                return [
1211                                    3,
1212                                    10
1213                                ];
1214                            case 9:
1215                                try {
1216                                    if (!_iteratorNormalCompletion && _iterator.return != null) {
1217                                        _iterator.return();
1218                                    }
1219                                } finally{
1220                                    if (_didIteratorError) {
1221                                        throw _iteratorError;
1222                                    }
1223                                }
1224                                return [
1225                                    7
1226                                ];
1227                            case 10:
1228                                return [
1229                                    2,
1230                                    results
1231                                ];
1232                        }
1233                    });
1234                })();
1235            }
1236        },
1237        {
1238            key: "permanentDelete",
1239            value: /**
1240     * Permanently delete a file or directory (bypassing trash).
1241     * Returns a DeleteResult with status indicating success, not_found, or error.
1242     */ function permanentDelete(identifier) {
1243                var _this = this;
1244                return _async_to_generator(function() {
1245                    var report;
1246                    return _ts_generator(this, function(_state) {
1247                        switch(_state.label){
1248                            case 0:
1249                                return [
1250                                    4,
1251                                    _this.request("DELETE", _this.nodeUrl(identifier))
1252                                ];
1253                            case 1:
1254                                report = _state.sent();
1255                                // Invalidate cache for the deleted identifier (regardless of status)
1256                                _this.invalidate(identifier);
1257                                return [
1258                                    2,
1259                                    {
1260                                        success: true,
1261                                        status: report.status === "already-absent" ? "not_found" : "deleted"
1262                                    }
1263                                ];
1264                        }
1265                    });
1266                })();
1267            }
1268        },
1269        {
1270            key: "permanentDeleteMultiple",
1271            value: /**
1272     * Permanently delete multiple files or directories (bypassing trash).
1273     * Returns an object with successful identifiers (including not_found) and errors.
1274     */ function permanentDeleteMultiple(identifiers) {
1275                var _this = this;
1276                return _async_to_generator(function() {
1277                    var results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, identifier, result, error, err;
1278                    return _ts_generator(this, function(_state) {
1279                        switch(_state.label){
1280                            case 0:
1281                                results = {
1282                                    success: [],
1283                                    notFound: [],
1284                                    errors: []
1285                                };
1286                                _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1287                                _state.label = 1;
1288                            case 1:
1289                                _state.trys.push([
1290                                    1,
1291                                    8,
1292                                    9,
1293                                    10
1294                                ]);
1295                                _iterator = identifiers[Symbol.iterator]();
1296                                _state.label = 2;
1297                            case 2:
1298                                if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
1299                                    3,
1300                                    7
1301                                ];
1302                                identifier = _step.value;
1303                                _state.label = 3;
1304                            case 3:
1305                                _state.trys.push([
1306                                    3,
1307                                    5,
1308                                    ,
1309                                    6
1310                                ]);
1311                                return [
1312                                    4,
1313                                    _this.permanentDelete(identifier)
1314                                ];
1315                            case 4:
1316                                result = _state.sent();
1317                                if (result.status === "not_found") {
1318                                    results.notFound.push(identifier);
1319                                } else {
1320                                    results.success.push(identifier);
1321                                }
1322                                return [
1323                                    3,
1324                                    6
1325                                ];
1326                            case 5:
1327                                error = _state.sent();
1328                                results.errors.push({
1329                                    identifier: identifier,
1330                                    error: _instanceof(error, Error) ? error.message : String(error)
1331                                });
1332                                return [
1333                                    3,
1334                                    6
1335                                ];
1336                            case 6:
1337                                _iteratorNormalCompletion = true;
1338                                return [
1339                                    3,
1340                                    2
1341                                ];
1342                            case 7:
1343                                return [
1344                                    3,
1345                                    10
1346                                ];
1347                            case 8:
1348                                err = _state.sent();
1349                                _didIteratorError = true;
1350                                _iteratorError = err;
1351                                return [
1352                                    3,
1353                                    10
1354                                ];
1355                            case 9:
1356                                try {
1357                                    if (!_iteratorNormalCompletion && _iterator.return != null) {
1358                                        _iterator.return();
1359                                    }
1360                                } finally{
1361                                    if (_didIteratorError) {
1362                                        throw _iteratorError;
1363                                    }
1364                                }
1365                                return [
1366                                    7
1367                                ];
1368                            case 10:
1369                                return [
1370                                    2,
1371                                    results
1372                                ];
1373                        }
1374                    });
1375                })();
1376            }
1377        },
1378        {
1379            key: "restore",
1380            value: /**
1381     * Restore a file or directory from trash.
1382     * Returns a RestoreResult with status indicating success or error.
1383     */ function restore(identifier) {
1384                var _this = this;
1385                return _async_to_generator(function() {
1386                    var node;
1387                    return _ts_generator(this, function(_state) {
1388                        switch(_state.label){
1389                            case 0:
1390                                return [
1391                                    4,
1392                                    _this.postAction(identifier, "file-restore")
1393                                ];
1394                            case 1:
1395                                node = _state.sent();
1396                                // Invalidate cache for the restored identifier
1397                                _this.invalidate(identifier);
1398                                return [
1399                                    2,
1400                                    {
1401                                        success: true,
1402                                        status: "restored",
1403                                        node: node
1404                                    }
1405                                ];
1406                        }
1407                    });
1408                })();
1409            }
1410        },
1411        {
1412            key: "restoreMultiple",
1413            value: /**
1414     * Restore multiple entries from trash.
1415     */ function restoreMultiple(identifiers) {
1416                var _this = this;
1417                return _async_to_generator(function() {
1418                    var results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, identifier, error, err;
1419                    return _ts_generator(this, function(_state) {
1420                        switch(_state.label){
1421                            case 0:
1422                                results = {
1423                                    success: [],
1424                                    errors: []
1425                                };
1426                                _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1427                                _state.label = 1;
1428                            case 1:
1429                                _state.trys.push([
1430                                    1,
1431                                    8,
1432                                    9,
1433                                    10
1434                                ]);
1435                                _iterator = identifiers[Symbol.iterator]();
1436                                _state.label = 2;
1437                            case 2:
1438                                if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
1439                                    3,
1440                                    7
1441                                ];
1442                                identifier = _step.value;
1443                                _state.label = 3;
1444                            case 3:
1445                                _state.trys.push([
1446                                    3,
1447                                    5,
1448                                    ,
1449                                    6
1450                                ]);
1451                                return [
1452                                    4,
1453                                    _this.restore(identifier)
1454                                ];
1455                            case 4:
1456                                _state.sent();
1457                                results.success.push(identifier);
1458                                return [
1459                                    3,
1460                                    6
1461                                ];
1462                            case 5:
1463                                error = _state.sent();
1464                                results.errors.push({
1465                                    identifier: identifier,
1466                                    error: _instanceof(error, Error) ? error.message : 
1466String(error)
1467                                });
1468                                return [
1469                                    3,
1470                                    6
1471                                ];
1472                            case 6:
1473                                _iteratorNormalCompletion = true;
1474                                return [
1475                                    3,
1476                                    2
1477                                ];
1478                            case 7:
1479                                return [
1480                                    3,
1481                                    10
1482                                ];
1483                            case 8:
1484                                err = _state.sent();
1485                                _didIteratorError = true;
1486                                _iteratorError = err;
1487                                return [
1488                                    3,
1489                                    10
1490                                ];
1491                            case 9:
1492                                try {
1493                                    if (!_iteratorNormalCompletion && _iterator.return != null) {
1494                                        _iterator.return();
1495                                    }
1496                                } finally{
1497                                    if (_didIteratorError) {
1498                                        throw _iteratorError;
1499                                    }
1500                                }
1501                                return [
1502                                    7
1503                                ];
1504                            case 10:
1505                                return [
1506                                    2,
1507                                    results
1508                                ];
1509                        }
1510                    });
1511                })();
1512            }
1513        },
1514        {
1515            key: "clearFromTrash",
1516            value: /**
1517     * Permanently delete one or all entries from trash.
1518     * When called with the trash root identifier, clears the entire trash.
1519     */ function clearFromTrash(identifier) {
1520                var _this = this;
1521                return _async_to_generator(function() {
1522                    return _ts_generator(this, function(_state) {
1523                        switch(_state.label){
1524                            case 0:
1525                                return [
1526                                    4,
1527                                    _this.postAction(identifier, "file-clear-trash")
1528                                ];
1529                            case 1:
1530                                _state.sent();
1531                                // Invalidate cache
1532                                _this.invalidate(identifier);
1533                                return [
1534                                    2,
1535                                    {
1536                                        success: true,
1537                                        status: "cleared"
1538                                    }
1539                                ];
1540                        }
1541                    });
1542                })();
1543            }
1544        },
1545        {
1546            key: "clearFromTrashMultiple",
1547            value: /**
1548     * Permanently delete multiple entries from trash.
1549     */ function clearFromTrashMultiple(identifiers) {
1550                var _this = this;
1551                return _async_to_generator(function() {
1552                    var results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, identifier, error, err;
1553                    return _ts_generator(this, function(_state) {
1554                        switch(_state.label){
1555                            case 0:
1556                                results = {
1557                                    success: [],
1558                                    errors: []
1559                                };
1560                                _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1561                                _state.label = 1;
1562                            case 1:
1563                                _state.trys.push([
1564                                    1,
1565                                    8,
1566                                    9,
1567                                    10
1568                                ]);
1569                                _iterator = identifiers[Symbol.iterator]();
1570                                _state.label = 2;
1571                            case 2:
1572                                if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
1573                                    3,
1574                                    7
1575                                ];
1576                                identifier = _step.value;
1577                                _state.label = 3;
1578                            case 3:
1579                                _state.trys.push([
1580                                    3,
1581                                    5,
1582                                    ,
1583                                    6
1584                                ]);
1585                                return [
1586                                    4,
1587                                    _this.clearFromTrash(identifier)
1588                                ];
1589                            case 4:
1590                                _state.sent();
1591                                results.success.push(identifier);
1592                                return [
1593                                    3,
1594                                    6
1595                                ];
1596                            case 5:
1597                                error = _state.sent();
1598                                results.errors.push({
1599                                    identifier: identifier,
1600                                    error: _instanceof(error, Error) ? error.message : 
1600String(error)
1601                                });
1602                                return [
1603                                    3,
1604                                    6
1605                                ];
1606                            case 6:
1607                                _iteratorNormalCompletion = true;
1608                                return [
1609                                    3,
1610                                    2
1611                                ];
1612                            case 7:
1613                                return [
1614                                    3,
1615                                    10
1616                                ];
1617                            case 8:
1618                                err = _state.sent();
1619                                _didIteratorError = true;
1620                                _iteratorError = err;
1621                                return [
1622                                    3,
1623                                    10
1624                                ];
1625                            case 9:
1626                                try {
1627                                    if (!_iteratorNormalCompletion && _iterator.return != null) {
1628                                        _iterator.return();
1629                                    }
1630                                } finally{
1631                                    if (_didIteratorError) {
1632                                        throw _iteratorError;
1633                                    }
1634                                }
1635                                return [
1636                                    7
1637                                ];
1638                            case 10:
1639                                return [
1640                                    2,
1641                                    results
1642                                ];
1643                        }
1644                    });
1645                })();
1646            }
1647        },
1648        {
1649            key: "rename",
1650            value: /**
1651     * Rename a file or directory.
1652     *
1653     * @param identifier The opaque identifier of the file/directory to rename
1654     * @param newName The new name (not a path, just the base name)
1655     * @returns RenameResult with the new identifier and updated node data
1656     */ function rename(identifier, newName) {
1657                var _this = this;
1658                return _async_to_generator(function() {
1659                    var node;
1660                    return _ts_generator(this, function(_state) {
1661                        switch(_state.label){
1662                            case 0:
1663                                return [
1664                                    4,
1665                                    _this.send("PATCH", _this.nodeUrl(identifier), {
1666                                        type: "files",
1667                                        attributes: {
1668                                            name: newName
1669                                        }
1670                                    })
1671                                ];
1672                            case 1:
1673                                node = _state.sent();
1674                                // Invalidate cache for the old identifier. The new one is a
1675                                // different string: an identifier encodes the path.
1676                                _this.invalidate(identifier);
1677                                _this.setCachedNode(node["@id"], FileSystemNode.fromData(node));
1678                                return [
1679                                    2,
1680                                    {
1681                                        success: true,
1682                                        status: "renamed",
1683                                        newPath: node.path,
1684                                        newIdentifier: node["@id"],
1685                                        node: node
1686                                    }
1687                                ];
1688                        }
1689                    });
1690                })();
1691            }
1692        },
1693        {
1694            key: "getFileContent",
1695            value: /**
1696     * Get the text content of a file for editing.
1697     *
1698     * The endpoint streams the file's bytes, so the body is the content itself
1699     * rather than a JSON envelope wrapping it.
1700     *
1701     * @param identifier The opaque identifier of the file to read
1702     * @returns FileContentResult with the file content and its media type
1703     */ function getFileContent(identifier) {
1704                var _this = this;
1705                return _async_to_generator(function() {
1706                    var response, _, _tmp;
1707                    return _ts_generator(this, function(_state) {
1708                        switch(_state.label){
1709                            case 0:
1710                                return [
1711                                    4,
1712                                    fetch(_this.getDownloadUrl(identifier), {
1713                                        method: "GET",
1714                                        headers: {
1715                                            "Accept": "*/*"
1716                                        }
1717                                    })
1718                                ];
1719                            case 1:
1720                                response = _state.sent();
1721                                // Check for authentication failure before processing response
1722                                if (_this.handleAuthenticationError(response)) {
1723                                    throw new Error("Session expired");
1724                                }
1725                                if (!!response.ok) return [
1726                                    3,
1727                                    3
1728                                ];
1729                                _ = Error.bind;
1730                                return [
1731                                    4,
1732                                    _this.readErrorMessage(response)
1733                                ];
1734                            case 2:
1735                                throw new (_.apply(Error, [
1736                                    void 0,
1737                                    _state.sent()
1738                                ]));
1739                            case 3:
1740                                _tmp = {};
1741                                return [
1742                                    4,
1743                                    response.text()
1744                                ];
1745                            case 4:
1746                                return [
1747                                    2,
1748                                    (_tmp.content = _state.sent(), _tmp.mediaType = (response.headers.get("Content-Type") || "").split(";")[0].trim(), _tmp)
1749                                ];
1750                        }
1751                    });
1752                })();
1753            }
1754        },
1755        {
1756            key: "readErrorMessage",
1757            value: /**
1758     * Extract an error message from a failed response.
1759     *
1760     * Every failure under `/api/v1` is a JSON:API `errors` document —
1761     * including from the byte-transfer routes, which are outside the
1762     * codec for their *successes* only. Only the first error is
1763     * reported: these messages end up in a toast, and a validation
1764     * failure with one violation per field would be an unreadable wall.
1765     *
1766     * The text fallback is not dead code. A response that never reached
1767     * the application — an edge 502, a login page from an expired
1768     * session on a route that does not 401 — is not JSON at all.
1769     */ function readErrorMessage(response) {
1770                return _async_to_generator(function() {
1771                    var fallback, _data_errors, body, data, first, e;
1772                    return _ts_generator(this, function(_state) {
1773                        switch(_state.label){
1774                            case 0:
1775                                fallback = "HTTP ".concat(response.status, ": ").concat(response.statusText);
1776                                _state.label = 1;
1777                            case 1:
1778                                _state.trys.push([
1779                                    1,
1780                                    3,
1781                                    ,
1782                                    4
1783                                ]);
1784                                return [
1785                                    4,
1786                                    response.text()
1787                                ];
1788                            case 2:
1789                                body = _state.sent();
1790                                data = JSON.parse(body);
1791                                first = (_data_errors = data.errors) === null || _data_errors === void 0 ? void 0 : _data_errors[0];
1792                                if (typeof (first === null || first === void 0 ? void 0 : first.detail) === "string") {
1793                                    return [
1794                                        2,
1795                                        first.detail
1796                                    ];
1797                                }
1798                                return [
1799                                    2,
1800                                    typeof (first === null || first === void 0 ? void 0 : first.title) === "string" ? first.title : fallback
1801                                ];
1802                            case 3:
1803                                e = _state.sent();
1804                                return [
1805                                    2,
1806                                    fallback
1807                                ];
1808                            case 4:
1809                                return [
1810                                    2
1811                                ];
1812                        }
1813                    });
1814                })();
1815            }
1816        },
1817        {
1818            key: "saveFileContent",
1819            value: /**
1820     * Save the text content of a file.
1821     *
1822     * @param identifier The opaque identifier of the file to save
1823     * @param content The new text content
1824     * @returns SaveContentResult indicating success, including updated node data
1825     */ function saveFileContent(identifier, content) {
1826                var _this = this;
1827                return _async_to_generator(function() {
1828                    var response, _;
1829                    return _ts_generator(this, function(_state) {
1830                        switch(_state.label){
1831                            case 0:
1832                                return [
1833                                    4,
1834                                    fetch(_this.nodeUrl(identifier, "/content"), {
1835                                        method: "PUT",
1836                                        headers: {
1837                                            "Content-Type": "application/octet-stream"
1838                                        },
1839                                        body: content
1840                                    })
1841                                ];
1842                            case 1:
1843                                response = _state.sent();
1844                                // Check for authentication failure before processing response
1845                                if (_this.handleAuthenticationError(response)) {
1846                                    throw new Error("Session expired");
1847                                }
1848                                if (!!response.ok) return [
1849                                    3,
1850                                    3
1851                                ];
1852                                _ = Error.bind;
1853                                return [
1854                                    4,
1855                                    _this.readErrorMessage(response)
1856                                ];
1857                            case 2:
1858                                throw new (_.apply(Error, [
1859                                    void 0,
1860                                    _state.sent()
1861                                ]));
1862                            case 3:
1863                                // A 204: the write does not answer with the node. Its size and
1864                                // its modification time both just changed, so the cached copy
1865                                // is stale and is dropped — the caller re-reads it if it needs
1866                                // to show either. Re-`stat`ing on every save to describe a
1867                                // write the caller performed would be a round trip for
1868                                // something nobody always looks at.
1869                                _this.invalidate(identifier);
1870                                return [
1871                                    2,
1872                                    {
1873                                        success: true
1874                                    }
1875                                ];
1876                        }
1877                    });
1878                })();
1879            }
1880        },
1881        {
1882            key: "createDirectory",
1883            value: /**
1884     * Create a new directory inside a parent directory.
1885     *
1886     * @param parentIdentifier The opaque identifier of the parent directory
1887     * @param name The name for the new directory
1888     * @returns CreateDirectoryResult with the new directory data
1889     */ function createDirectory(parentIdentifier, name) {
1890                var _this = this;
1891                return _async_to_generator(function() {
1892                    return _ts_generator(this, function(_state) {
1893                        switch(_state.label){
1894                            case 0:
1895                                return [
1896                                    4,
1897                                    _this.create(parentIdentifier, name, "directories")
1898                                ];
1899                            case 1:
1900                                return [
1901                                    2,
1902                                    _state.sent()
1903                                ];
1904                        }
1905                    });
1906                })();
1907            }
1908        },
1909        {
1910            key: "createFile",
1911            value: /**
1912     * Create a new empty file in a directory.
1913     * 
1914     * @param parentIdentifier The opaque identifier of the parent directory
1915     * @param name The name of the file to create
1916     * @returns CreateFileResult with the new file data
1917     */ function createFile(parentIdentifier, name) {
1918                var _this = this;
1919                return _async_to_generator(function() {
1920                    return _ts_generator(this, function(_state) {
1921                        switch(_state.label){
1922                            case 0:
1923                                return [
1924                                    4,
1925                                    _this.create(parentIdentifier, name, "files")
1926                                ];
1927                            case 1:
1928                                return [
1929                                    2,
1930                                    _state.sent()
1931                                ];
1932                        }
1933                    });
1934                })();
1935            }
1936        },
1937        {
1938            key: "create",
1939            value: /**
1940     * Create one node in a directory.
1941     *
1942     * `mkdir` and `touch` were two endpoints; they are one now, and the
1943     * *posted resource type* is what chooses the kind. The containing
1944     * directory is a relationship rather than a path segment, which is
1945     * what makes this a create of a `files` resource rather than an
1946     * action on the parent.
1947     */ function create(parentIdentifier, name, type) {
1948                var _this = this;
1949                return _async_to_generator(function() {
1950                    var node;
1951                    return _ts_generator(this, function(_state) {
1952                        switch(_state.label){
1953                            case 0:
1954                                return [
1955                                    4,
1956                                    _this.send("POST", "/api/v1/files", {
1957                                        type: type,
1958                                        attributes: {
1959                                            name: name
1960                                        },
1961                                        relationships: {
1962                                            parent: {
1963                                                data: {
1964                                                    type: "directories",
1965                                                    id: parentIdentifier
1966                                                }
1967                                            }
1968                                        }
1969                                    })
1970                                ];
1971                            case 1:
1972                                node = _state.sent();
1973                                // Invalidate cache for the parent directory (new child added)
1974                                _this.invalidate(parentIdentifier);
1975                                _this.setCachedNode(node["@id"], FileSystemNode.fromData(node));
1976                                return [
1977                                    2,
1978                                    {
1979                                        success: true,
1980                                        status: "created",
1981                                        path: node.path,
1982                                        identifier: node["@id"],
1983                                        node: node
1984                                    }
1985                                ];
1986                        }
1987                    });
1988                })();
1989            }
1990        },
1991        {
1992            key: "copyMultiple",
1993            value: /**
1994     * Copy multiple files/directories to a target directory.
1995     * 
1996     * @param sourceIdentifiers Array of source opaque identifiers to copy
1997     * @param targetIdentifier The opaque identifier of the target directory
1998     * @returns CopyMoveMultipleResult with results for each source
1999     */ function copyMultiple(sourceIdentifiers, targetIdentifier) {
2000                var _this = this;
2001                return _async_to_generator(function() {
2002                    return _ts_generator(this, function(_state) {
2003                        switch(_state.label){
2004                            case 0:
2005                                return [
2006                                    4,
2007                                    _this.transfer("file-copy-from", sourceIdentifiers, targetIdentifier)
2008                                ];
2009                            case 1:
2010                                return [
2011                                    2,
2012                                    _state.sent()
2013                                ];
2014                        }
2015                    });
2016                })();
2017            }
2018        },
2019        {
2020            key: "moveMultiple",
2021            value: /**
2022     * Move multiple files/directories to a target directory.
2023     * 
2024     * @param sourceIdentifiers Array of source opaque identifiers to move
2025     * @param targetIdentifier The opaque identifier of the target directory
2026     * @returns CopyMoveMultipleResult with results for each source
2027     */ function moveMultiple(sourceIdentifiers, targetIdentifier) {
2028                var _this = this;
2029                return _async_to_generator(function() {
2030                    return _ts_generator(this, function(_state) {
2031                        switch(_state.label){
2032                            case 0:
2033                                return [
2034                                    4,
2035                                    _this.transfer("file-move-from", sourceIdentifiers, targetIdentifier)
2036                                ];
2037                            case 1:
2038                                return [
2039                                    2,
2040                                    _state.sent()
2041                                ];
2042                        }
2043                    });
2044                })();
2045            }
2046        },
2047        {
2048            key: "transfer",
2049            value: /**
2050     * Bring a batch of nodes into a directory, by copy or by move.
2051     *
2052     * Batch on purpose: a multi-selection paste is one request, and one
2053     * source failing (a name already taken at the destination) reports
2054     * against that source and leaves the rest of the batch alone.
2055     * Splitting it into N requests would lose the partial-failure
2056     * report as well as costing N round trips.
2057     */ function transfer(action, sourceIdentifiers, targetIdentifier) {
2058                var _this = this;
2059                return _async_to_generator(function() {
2060                    var report, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, sourceIdentifier;
2061                    return _ts_generator(this, function(_state) {
2062                        switch(_state.label){
2063                            case 0:
2064                                return [
2065                                    4,
2066                                    _this.postAction(targetIdentifier, action, {
2067                                        sources: sourceIdentifiers
2068                                    })
2069                                ];
2070                            case 1:
2071                                report = _state.sent();
2072                                // Invalidate the target (new children) and, for a move, every
2073                                // source: it is not where it was.
2074                                _this.invalidate(targetIdentifier);
2075                                if (action === "file-move-from") {
2076                                    _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2077                                    try {
2078                                        for(_iterator = sourceIdentifiers[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2079                                            sourceIdentifier = _step.value;
2080                                            _this.invalidate(sourceIdentifier);
2081                                        }
2082                                    } catch (err) {
2083                                        _didIteratorError = true;
2084                                        _iteratorError = err;
2085                                    } finally{
2086                                        try {
2087                                            if (!_iteratorNormalCompletion && _iterator.return != null) {
2088                                                _iterator.return();
2089                                            }
2090                                        } finally{
2091                                            if (_didIteratorError) {
2092                                                throw _iteratorError;
2093                                            }
2094                                        }
2095                                    }
2096                                }
2097                                return [
2098                                    2,
2099                                    {
2100                                        results: report.results.map(function(item) {
2101                                            var _item_node, _item_node1;
2102                                            if (item.node) {
2103                                                _this.setCachedNode(item.node["@id"], FileSystemNode.fromData(item.node));
2104                                            }
2105                                            var _item_node2, _item_error;
2106                                            return {
2107                                                success: item.transferred,
2108                                                sourceIdentifier: item.source,
2109                                                status: item.transferred ? action === "file-move-from" ? "moved" : "copied" : "error",
2110                                                destinationPath: (_item_node = item.node) === null || _item_node === void 0 ? void 0 : _item_node.path,
2111                                                destinationIdentifier: (_item_node1 = item.node) === null || _item_node1 === void 0 ? void 0 : _item_node1["@id"],
2112                                                node: (_item_node2 = item.node) !== null && _item_node2 !== void 0 ? _item_node2 : undefined,
2113                                                error: (_item_error = item.error) !== null && _item_error !== void 0 ? _item_error : undefined
2114                                            };
2115                                        })
2116                                    }
2117                                ];
2118                        }
2119                    });
2120                })();
2121            }
2122        },
2123        {
2124            key: "changeWebPermission",
2125            value: /**
2126     * Change the web permission of a node.
2127     * 
2128     * @param identifier - The node identifier
2129     * @param permission - The permission to set: 'none', 'read-only', or 'read-write'
2130     * @param recursive - Whether to apply recursively to all children
2131     * @returns Promise with the result including updated node data
2132     */ function changeWebPermission(identifier, permission, recursive) {
2133                var _this = this;
2134                return _async_to_generator(function() {
2135                    var node, error;
2136                    return _ts_generator(this, function(_state) {
2137                        switch(_state.label){
2138                            case 0:
2139                                _state.trys.push([
2140                                    0,
2141                                    2,
2142                                    ,
2143                                    3
2144                                ]);
2145                                return [
2146                                    4,
2147                                    _this.postAction(identifier, "file-set-web-permission", {
2148                                        permission: permission,
2149                                        recursive: recursive
2150                                    })
2151                                ];
2152                            case 1:
2153                                node = _state.sent();
2154                                // The mode changed, so the cached copy is stale; replace it
2155                                // with the one the write answered rather than dropping it.
2156                                _this.setCachedNode(identifier, FileSystemNode.fromData(node));
2157                                return [
2158                                    2,
2159                                    {
2160                                        success: true,
2161                                        node: node
2162                                    }
2163                                ];
2164                            case 2:
2165                                error = _state.sent();
2166                                if (_instanceof(error, Error) && error.message === "Session expired") {
2167                                    throw error;
2168                                }
2169                                return [
2170                                    2,
2171                                    {
2172                                        success: false,
2173                                        error: _instanceof(error, Error) ? error.message : 
2173String(error)
2174                                    }
2175                                ];
2176                            case 3:
2177                                return [
2178                                    2
2179                                ];
2180                        }
2181                    });
2182                })();
2183            }
2184        },
2185        {
2186            key: "recalculateSize",
2187            value: /**
2188     * Recalculate the size of a directory.
2189     * 
2190     * @param identifier - The directory identifier
2191     * @returns Promise with the recalculated size
2192     */ function recalculateSize(identifier) {
2193                var _this = this;
2194                return _async_to_generator(function() {
2195                    var node, _node_size, error;
2196                    return _ts_generator(this, function(_state) {
2197                        switch(_state.label){
2198                            case 0:
2199                                _state.trys.push([
2200                                    0,
2201                                    2,
2202                                    ,
2203                                    3
2204                                ]);
2205                                return [
2206                                    4,
2207                                    _this.postAction(identifier, "file-recalculate-size")
2208                                ];
2209                            case 1:
2210                                node = _state.sent();
2211                                // Invalidate cache for this node so it gets refreshed
2212                                _this.invalidate(identifier);
2213                                return [
2214                                    2,
2215                                    {
2216                                        success: true,
2217                                        size: (_node_size = node.size) !== null && _node_size !== void 0 ? _node_size : 0
2218                                    }
2219                                ];
2220                            case 2:
2221                                error = _state.sent();
2222                                if (_instanceof(error, Error) && error.message === "Session expired") {
2223                                    throw error;
2224                                }
2225                                return [
2226                                    2,
2227                                    {
2228                                        success: false,
2229                                        size: 0,
2230                                        error: _instanceof(error, Error) ? error.message : String(error)
2231                                    }
2232                                ];
2233                            case 3:
2234                                return [
2235                                    2
2236                                ];
2237                        }
2238                    });
2239                })();
2240            }
2241        },
2242        {
2243            key: "archive",
2244            value: /**
2245     * Create an archive from selected files/directories.
2246     *
2247     * @param directoryIdentifier The opaque identifier of the directory containing the items
2248     * @param format The archive format (tar.gz, zip, 7z, etc.)
2249     * @param items Array of basenames to include in the archive
2250     * @returns ArchiveResult with the created archive node
2251     */ function archive(directoryIdentifier, format, items) {
2252                var _this = this;
2253                return _async_to_generator(function() {
2254                    var node, error;
2255                    return _ts_generator(this, function(_state) {
2256                        switch(_state.label){
2257                            case 0:
2258                                _state.trys.push([
2259                                    0,
2260                                    2,
2261                                    ,
2262                                    3
2263                                ]);
2264                                return [
2265                                    4,
2266                                    _this.postAction(directoryIdentifier, "file-archive", {
2267                                        format: format,
2268                                        items: items
2269                                    })
2270                                ];
2271                            case 1:
2272                                node = _state.sent();
2273                                // Invalidate directory cache to refresh listing
2274                                _this.invalidate(directoryIdentifier);
2275                                return [
2276                                    2,
2277                                    {
2278                                        success: true,
2279                                        status: "created",
2280                                        node: node
2281                                    }
2282                                ];
2283                            case 2:
2284                                error = _state.sent();
2285                                if (_instanceof(error, Error) && error.message === "Session expired") {
2286                                    throw error;
2287                                }
2288                                return [
2289                                    2,
2290                                    {
2291                                        success: false,
2292                                        status: "error",
2293                                        error: _instanceof(error, Error) ? error.message : 
2293String(error)
2294                                    }
2295                                ];
2296                            case 3:
2297                                return [
2298                                    2
2299                                ];
2300                        }
2301                    });
2302                })();
2303            }
2304        },
2305        {
2306            /**
2307     * Download an archive stream from selected files/directories without creating a file on disk.
2308     *
2309     * @param directoryIdentifier The opaque identifier of the directory containing the items
2310     * @param format The archive format (tar.gz, zip, 7z, etc.)
2311     * @param items Array of basenames to include in the archive
2312     * @returns void - triggers browser download
2313     */ key: "archiveDownload",
2314            value: function archiveDownload(directoryIdentifier, format, items) {
2315                var _this = this;
2316                var _this1 = this;
2317                // Use fetch to get the blob, then create a download link.
2318                // A plain JSON body, not a JSON:API envelope: this route is one
2319                // of the byte transfers, which sit outside the codec.
2320                fetch(this.nodeUrl(directoryIdentifier, "/content/archive"), {
2321                    method: "POST",
2322                    headers: {
2323                        "Accept": "application/octet-stream",
2324                        "Content-Type": "application/json"
2325                    },
2326                    body: JSON.stringify({
2327                        format: format,
2328                        items: items
2329                    })
2330                }).then(function() {
2331                    var _ref = _async_to_generator(function(response) {
2332                        var _, contentDisposition, filename, filenameMatch;
2333                        return _ts_generator(this, function(_state) {
2334                            switch(_state.label){
2335                                case 0:
2336                                    if (!!response.ok) return [
2337                                        3,
2338                                        2
2339                                    ];
2340                                    _ = Error.bind;
2341                                    return [
2342                                        4,
2343                                        _this1.readErrorMessage(response)
2344                                    ];
2345                                case 1:
2346                                    throw new (_.apply(Error, [
2347                                        void 0,
2348                                        _state.sent()
2349                                    ]));
2350                                case 2:
2351                                    // Get the filename from Content-Disposition header
2352                                    contentDisposition = response.headers.get("Content-Disposition");
2353                                    filename = "archive.".concat(format);
2354                                    if (contentDisposition) {
2355                                        filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
2356                                        if (filenameMatch && filenameMatch[1]) {
2357                                            filename = filenameMatch[1].replace(/['"]/g, "");
2358                                        }
2359                                    }
2360                                    // Convert response to blob
2361                                    return [
2362                                        2,
2363                                        response.blob().then(function(blob) {
2364                                            return {
2365                                                blob: blob,
2366                                                filename: filename
2367                                            };
2368                                        })
2369                                    ];
2370                            }
2371                        });
2372                    });
2373                    return function(response) {
2374                        return _ref.apply(this, arguments);
2375                    };
2376                }()).then(function(param) {
2377                    var blob = param.blob, filename = param.filename;
2378                    // Create a download link and trigger it
2379                    var url = window.URL.createObjectURL(blob);
2380                    var a = document.createElement("a");
2381                    a.style.display = "none";
2382                    a.href = url;
2383                    a.download = filename;
2384                    document.body.appendChild(a);
2385                    a.click();
2386                    window.URL.revokeObjectURL(url);
2387                    document.body.removeChild(a);
2388                }).catch(function(error) {
2389                    console.error("Failed to download archive:", error);
2390                    // Dispatch error event
2391                    if (_this.config.eventTarget) {
2392                        _this.config.eventTarget.dispatchEvent(new CustomEvent("fs:error", {
2393                            detail: {
2394                                error: error.message
2395                            }
2396                        }));
2397                    }
2398                });
2399            }
2400        },
2401        {
2402            key: "extract",
2403            value: /**
2404     * Extract an archive to current directory or a new folder.
2405     *
2406     * @param fileIdentifier The opaque identifier of the archive file
2407     * @param mode Extract mode: 'here' or 'folder'
2408     * @returns ExtractResult with the extracted nodes
2409     */ function extract(fileIdentifier, mode) {
2410                var _this = this;
2411                return _async_to_generator(function() {
2412                    var extracted, error;
2413                    return _ts_generator(this, function(_state) {
2414                        switch(_state.label){
2415                            case 0:
2416                                _state.trys.push([
2417                                    0,
2418                                    2,
2419                                    ,
2420                                    3
2421                                ]);
2422                                return [
2423                                    4,
2424                                    _this.postAction(fileIdentifier, "file-extract", {
2425                                        mode: mode
2426                                    })
2427                                ];
2428                            case 1:
2429                                extracted = _state.sent();
2430                                // Invalidate file cache and parent to refresh listing
2431                                _this.invalidate(fileIdentifier);
2432                                return [
2433                                    2,
2434                                    {
2435                                        success: true,
2436                                        status: "extracted",
2437                                        nodes: extracted.items
2438                                    }
2439                                ];
2440                            case 2:
2441                                error = _state.sent();
2442                                if (_instanceof(error, Error) && error.message === "Session expired") {
2443                                    throw error;
2444                                }
2445                                return [
2446                                    2,
2447                                    {
2448                                        success: false,
2449                                        status: "error",
2450                                        nodes: [],
2451                                        error: _instanceof(error, Error) ? error.message : String(error)
2452                                    }
2453                                ];
2454                            case 3:
2455                                return [
2456                                    2
2457                                ];
2458                        }
2459                    });
2460                })();
2461            }
2462        },
2463        {
2464            /**
2465     * Clear the cache
2466     */ key: "clearCache",
2467            value: function clearCache() {
2468                if (this.config.stateController) {
2469                    this.config.stateController.clearCache();
2470                } else {
2471                    this.cache.clear();
2472                }
2473            }
2474        },
2475        {
2476            /**
2477     * Remove a specific identifier from cache
2478     */ key: "invalidate",
2479            value: function invalidate(identifier) {
2480                if (this.config.stateController) {
2481                    this.config.stateController.invalidateNode(identifier);
2482                } else {
2483                    this.cache.delete(identifier);
2484                }
2485            }
2486        },
2487        {
2488            /**
2489     * Cancel all pending requests
2490     */ key: "cancelAll",
2491            value: function cancelAll() {
2492                this.abortControllers.forEach(function(controller) {
2493                    return controller.abort();
2494                });
2495                this.abortControllers.clear();
2496            }
2497        },
2498        {
2499            /**
2500     * Get cached node if available
2501     */ key: "getCached",
2502            value: function getCached(identifier) {
2503                return this.getCachedNode(identifier);
2504            }
2505        },
2506        {
2507            key: "rootIdentifier",
2508            get: /**
2509     * Get the root identifier for this filesystem
2510     */ function get() {
2511                return this.config.rootIdentifier;
2512            }
2513        }
2514    ]);
2515    return FileSystemService;
2516}();
2517/**
2518     * The flat representation. See the class docblock.
2519     */ _define_property(FileSystemService, "FLAT", "application/jsonl");
2520/**
2521     * The JSON:API media type, for request bodies.
2522     */ _define_property(FileSystemService, "JSON_API", "application/vnd.api+json");

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.