@nextcloud/files 3.9.2 → 3.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,709 @@
1
+ "use strict";
2
+ const path = require("path");
3
+ const paths = require("@nextcloud/paths");
4
+ const logger$1 = require("@nextcloud/logger");
5
+ const auth = require("@nextcloud/auth");
6
+ const router = require("@nextcloud/router");
7
+ const cancelablePromise = require("cancelable-promise");
8
+ const webdav = require("webdav");
9
+ const _public = require("@nextcloud/sharing/public");
10
+ const logger = logger$1.getLoggerBuilder().setApp("@nextcloud/files").detectUser().build();
11
+ var Permission = /* @__PURE__ */ ((Permission2) => {
12
+ Permission2[Permission2["NONE"] = 0] = "NONE";
13
+ Permission2[Permission2["CREATE"] = 4] = "CREATE";
14
+ Permission2[Permission2["READ"] = 1] = "READ";
15
+ Permission2[Permission2["UPDATE"] = 2] = "UPDATE";
16
+ Permission2[Permission2["DELETE"] = 8] = "DELETE";
17
+ Permission2[Permission2["SHARE"] = 16] = "SHARE";
18
+ Permission2[Permission2["ALL"] = 31] = "ALL";
19
+ return Permission2;
20
+ })(Permission || {});
21
+ var FileType = /* @__PURE__ */ ((FileType2) => {
22
+ FileType2["Folder"] = "folder";
23
+ FileType2["File"] = "file";
24
+ return FileType2;
25
+ })(FileType || {});
26
+ const isDavResource = function(source, davService) {
27
+ return source.match(davService) !== null;
28
+ };
29
+ const validateData = (data, davService) => {
30
+ if (data.id && typeof data.id !== "number") {
31
+ throw new Error("Invalid id type of value");
32
+ }
33
+ if (!data.source) {
34
+ throw new Error("Missing mandatory source");
35
+ }
36
+ try {
37
+ new URL(data.source);
38
+ } catch (e) {
39
+ throw new Error("Invalid source format, source must be a valid URL");
40
+ }
41
+ if (!data.source.startsWith("http")) {
42
+ throw new Error("Invalid source format, only http(s) is supported");
43
+ }
44
+ if (data.displayname && typeof data.displayname !== "string") {
45
+ throw new Error("Invalid displayname type");
46
+ }
47
+ if (data.mtime && !(data.mtime instanceof Date)) {
48
+ throw new Error("Invalid mtime type");
49
+ }
50
+ if (data.crtime && !(data.crtime instanceof Date)) {
51
+ throw new Error("Invalid crtime type");
52
+ }
53
+ if (!data.mime || typeof data.mime !== "string" || !data.mime.match(/^[-\w.]+\/[-+\w.]+$/gi)) {
54
+ throw new Error("Missing or invalid mandatory mime");
55
+ }
56
+ if ("size" in data && typeof data.size !== "number" && data.size !== void 0) {
57
+ throw new Error("Invalid size type");
58
+ }
59
+ if ("permissions" in data && data.permissions !== void 0 && !(typeof data.permissions === "number" && data.permissions >= Permission.NONE && data.permissions <= Permission.ALL)) {
60
+ throw new Error("Invalid permissions");
61
+ }
62
+ if (data.owner && data.owner !== null && typeof data.owner !== "string") {
63
+ throw new Error("Invalid owner type");
64
+ }
65
+ if (data.attributes && typeof data.attributes !== "object") {
66
+ throw new Error("Invalid attributes type");
67
+ }
68
+ if (data.root && typeof data.root !== "string") {
69
+ throw new Error("Invalid root type");
70
+ }
71
+ if (data.root && !data.root.startsWith("/")) {
72
+ throw new Error("Root must start with a leading slash");
73
+ }
74
+ if (data.root && !data.source.includes(data.root)) {
75
+ throw new Error("Root must be part of the source");
76
+ }
77
+ if (data.root && isDavResource(data.source, davService)) {
78
+ const service = data.source.match(davService)[0];
79
+ if (!data.source.includes(path.join(service, data.root))) {
80
+ throw new Error("The root must be relative to the service. e.g /files/emma");
81
+ }
82
+ }
83
+ if (data.status && !Object.values(NodeStatus).includes(data.status)) {
84
+ throw new Error("Status must be a valid NodeStatus");
85
+ }
86
+ };
87
+ var NodeStatus = /* @__PURE__ */ ((NodeStatus2) => {
88
+ NodeStatus2["NEW"] = "new";
89
+ NodeStatus2["FAILED"] = "failed";
90
+ NodeStatus2["LOADING"] = "loading";
91
+ NodeStatus2["LOCKED"] = "locked";
92
+ return NodeStatus2;
93
+ })(NodeStatus || {});
94
+ class Node {
95
+ _data;
96
+ _attributes;
97
+ _knownDavService = /(remote|public)\.php\/(web)?dav/i;
98
+ readonlyAttributes = Object.entries(Object.getOwnPropertyDescriptors(Node.prototype)).filter((e) => typeof e[1].get === "function" && e[0] !== "__proto__").map((e) => e[0]);
99
+ handler = {
100
+ set: (target, prop, value) => {
101
+ if (this.readonlyAttributes.includes(prop)) {
102
+ return false;
103
+ }
104
+ return Reflect.set(target, prop, value);
105
+ },
106
+ deleteProperty: (target, prop) => {
107
+ if (this.readonlyAttributes.includes(prop)) {
108
+ return false;
109
+ }
110
+ return Reflect.deleteProperty(target, prop);
111
+ },
112
+ // TODO: This is deprecated and only needed for files v3
113
+ get: (target, prop, receiver) => {
114
+ if (this.readonlyAttributes.includes(prop)) {
115
+ logger.warn(`Accessing "Node.attributes.${prop}" is deprecated, access it directly on the Node instance.`);
116
+ return Reflect.get(this, prop);
117
+ }
118
+ return Reflect.get(target, prop, receiver);
119
+ }
120
+ };
121
+ constructor(data, davService) {
122
+ validateData(data, davService || this._knownDavService);
123
+ this._data = {
124
+ // TODO: Remove with next major release, this is just for compatibility
125
+ displayname: data.attributes?.displayname,
126
+ ...data,
127
+ attributes: {}
128
+ };
129
+ this._attributes = new Proxy(this._data.attributes, this.handler);
130
+ this.update(data.attributes ?? {});
131
+ if (davService) {
132
+ this._knownDavService = davService;
133
+ }
134
+ }
135
+ /**
136
+ * Get the source url to this object
137
+ * There is no setter as the source is not meant to be changed manually.
138
+ * You can use the rename or move method to change the source.
139
+ */
140
+ get source() {
141
+ return this._data.source.replace(/\/$/i, "");
142
+ }
143
+ /**
144
+ * Get the encoded source url to this object for requests purposes
145
+ */
146
+ get encodedSource() {
147
+ const { origin } = new URL(this.source);
148
+ return origin + paths.encodePath(this.source.slice(origin.length));
149
+ }
150
+ /**
151
+ * Get this object name
152
+ * There is no setter as the source is not meant to be changed manually.
153
+ * You can use the rename or move method to change the source.
154
+ */
155
+ get basename() {
156
+ return path.basename(this.source);
157
+ }
158
+ /**
159
+ * The nodes displayname
160
+ * By default the display name and the `basename` are identical,
161
+ * but it is possible to have a different name. This happens
162
+ * on the files app for example for shared folders.
163
+ */
164
+ get displayname() {
165
+ return this._data.displayname || this.basename;
166
+ }
167
+ /**
168
+ * Set the displayname
169
+ */
170
+ set displayname(displayname) {
171
+ this._data.displayname = displayname;
172
+ }
173
+ /**
174
+ * Get this object's extension
175
+ * There is no setter as the source is not meant to be changed manually.
176
+ * You can use the rename or move method to change the source.
177
+ */
178
+ get extension() {
179
+ return path.extname(this.source);
180
+ }
181
+ /**
182
+ * Get the directory path leading to this object
183
+ * Will use the relative path to root if available
184
+ *
185
+ * There is no setter as the source is not meant to be changed manually.
186
+ * You can use the rename or move method to change the source.
187
+ */
188
+ get dirname() {
189
+ if (this.root) {
190
+ let source = this.source;
191
+ if (this.isDavResource) {
192
+ source = source.split(this._knownDavService).pop();
193
+ }
194
+ const firstMatch = source.indexOf(this.root);
195
+ const root = this.root.replace(/\/$/, "");
196
+ return path.dirname(source.slice(firstMatch + root.length) || "/");
197
+ }
198
+ const url = new URL(this.source);
199
+ return path.dirname(url.pathname);
200
+ }
201
+ /**
202
+ * Get the file mime
203
+ * There is no setter as the mime is not meant to be changed
204
+ */
205
+ get mime() {
206
+ return this._data.mime;
207
+ }
208
+ /**
209
+ * Get the file modification time
210
+ */
211
+ get mtime() {
212
+ return this._data.mtime;
213
+ }
214
+ /**
215
+ * Set the file modification time
216
+ */
217
+ set mtime(mtime) {
218
+ this._data.mtime = mtime;
219
+ }
220
+ /**
221
+ * Get the file creation time
222
+ * There is no setter as the creation time is not meant to be changed
223
+ */
224
+ get crtime() {
225
+ return this._data.crtime;
226
+ }
227
+ /**
228
+ * Get the file size
229
+ */
230
+ get size() {
231
+ return this._data.size;
232
+ }
233
+ /**
234
+ * Set the file size
235
+ */
236
+ set size(size) {
237
+ this.updateMtime();
238
+ this._data.size = size;
239
+ }
240
+ /**
241
+ * Get the file attribute
242
+ * This contains all additional attributes not provided by the Node class
243
+ */
244
+ get attributes() {
245
+ return this._attributes;
246
+ }
247
+ /**
248
+ * Get the file permissions
249
+ */
250
+ get permissions() {
251
+ if (this.owner === null && !this.isDavResource) {
252
+ return Permission.READ;
253
+ }
254
+ return this._data.permissions !== void 0 ? this._data.permissions : Permission.NONE;
255
+ }
256
+ /**
257
+ * Set the file permissions
258
+ */
259
+ set permissions(permissions) {
260
+ this.updateMtime();
261
+ this._data.permissions = permissions;
262
+ }
263
+ /**
264
+ * Get the file owner
265
+ * There is no setter as the owner is not meant to be changed
266
+ */
267
+ get owner() {
268
+ if (!this.isDavResource) {
269
+ return null;
270
+ }
271
+ return this._data.owner;
272
+ }
273
+ /**
274
+ * Is this a dav-related resource ?
275
+ */
276
+ get isDavResource() {
277
+ return isDavResource(this.source, this._knownDavService);
278
+ }
279
+ /**
280
+ * @deprecated use `isDavResource` instead - will be removed in next major version.
281
+ */
282
+ get isDavRessource() {
283
+ return this.isDavResource;
284
+ }
285
+ /**
286
+ * Get the dav root of this object
287
+ * There is no setter as the root is not meant to be changed
288
+ */
289
+ get root() {
290
+ if (this._data.root) {
291
+ return this._data.root.replace(/^(.+)\/$/, "$1");
292
+ }
293
+ if (this.isDavResource) {
294
+ const root = path.dirname(this.source);
295
+ return root.split(this._knownDavService).pop() || null;
296
+ }
297
+ return null;
298
+ }
299
+ /**
300
+ * Get the absolute path of this object relative to the root
301
+ */
302
+ get path() {
303
+ if (this.root) {
304
+ let source = this.source;
305
+ if (this.isDavResource) {
306
+ source = source.split(this._knownDavService).pop();
307
+ }
308
+ const firstMatch = source.indexOf(this.root);
309
+ const root = this.root.replace(/\/$/, "");
310
+ return source.slice(firstMatch + root.length) || "/";
311
+ }
312
+ return (this.dirname + "/" + this.basename).replace(/\/\//g, "/");
313
+ }
314
+ /**
315
+ * Get the node id if defined.
316
+ * There is no setter as the fileid is not meant to be changed
317
+ */
318
+ get fileid() {
319
+ return this._data?.id;
320
+ }
321
+ /**
322
+ * Get the node status.
323
+ */
324
+ get status() {
325
+ return this._data?.status;
326
+ }
327
+ /**
328
+ * Set the node status.
329
+ */
330
+ set status(status) {
331
+ this._data.status = status;
332
+ }
333
+ /**
334
+ * Get the node data
335
+ */
336
+ get data() {
337
+ return structuredClone(this._data);
338
+ }
339
+ /**
340
+ * Move the node to a new destination
341
+ *
342
+ * @param {string} destination the new source.
343
+ * e.g. https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg
344
+ */
345
+ move(destination) {
346
+ validateData({ ...this._data, source: destination }, this._knownDavService);
347
+ const oldBasename = this.basename;
348
+ this._data.source = destination;
349
+ if (this.displayname === oldBasename && this.basename !== oldBasename) {
350
+ this.displayname = this.basename;
351
+ }
352
+ this.updateMtime();
353
+ }
354
+ /**
355
+ * Rename the node
356
+ * This aliases the move method for easier usage
357
+ *
358
+ * @param basename The new name of the node
359
+ */
360
+ rename(basename2) {
361
+ if (basename2.includes("/")) {
362
+ throw new Error("Invalid basename");
363
+ }
364
+ this.move(path.dirname(this.source) + "/" + basename2);
365
+ }
366
+ /**
367
+ * Update the mtime if exists
368
+ */
369
+ updateMtime() {
370
+ if (this._data.mtime) {
371
+ this._data.mtime = /* @__PURE__ */ new Date();
372
+ }
373
+ }
374
+ /**
375
+ * Update the attributes of the node
376
+ * Warning, updating attributes will NOT automatically update the mtime.
377
+ *
378
+ * @param attributes The new attributes to update on the Node attributes
379
+ */
380
+ update(attributes) {
381
+ for (const [name, value] of Object.entries(attributes)) {
382
+ try {
383
+ if (value === void 0) {
384
+ delete this.attributes[name];
385
+ } else {
386
+ this.attributes[name] = value;
387
+ }
388
+ } catch (e) {
389
+ if (e instanceof TypeError) {
390
+ continue;
391
+ }
392
+ throw e;
393
+ }
394
+ }
395
+ }
396
+ }
397
+ class File extends Node {
398
+ get type() {
399
+ return FileType.File;
400
+ }
401
+ /**
402
+ * Returns a clone of the file
403
+ */
404
+ clone() {
405
+ return new File(this.data);
406
+ }
407
+ }
408
+ class Folder extends Node {
409
+ constructor(data) {
410
+ super({
411
+ ...data,
412
+ mime: "httpd/unix-directory"
413
+ });
414
+ }
415
+ get type() {
416
+ return FileType.Folder;
417
+ }
418
+ get extension() {
419
+ return null;
420
+ }
421
+ get mime() {
422
+ return "httpd/unix-directory";
423
+ }
424
+ /**
425
+ * Returns a clone of the folder
426
+ */
427
+ clone() {
428
+ return new Folder(this.data);
429
+ }
430
+ }
431
+ const parsePermissions = function(permString = "") {
432
+ let permissions = Permission.NONE;
433
+ if (!permString) {
434
+ return permissions;
435
+ }
436
+ if (permString.includes("C") || permString.includes("K")) {
437
+ permissions |= Permission.CREATE;
438
+ }
439
+ if (permString.includes("G")) {
440
+ permissions |= Permission.READ;
441
+ }
442
+ if (permString.includes("W") || permString.includes("N") || permString.includes("V")) {
443
+ permissions |= Permission.UPDATE;
444
+ }
445
+ if (permString.includes("D")) {
446
+ permissions |= Permission.DELETE;
447
+ }
448
+ if (permString.includes("R")) {
449
+ permissions |= Permission.SHARE;
450
+ }
451
+ return permissions;
452
+ };
453
+ const defaultDavProperties = [
454
+ "d:getcontentlength",
455
+ "d:getcontenttype",
456
+ "d:getetag",
457
+ "d:getlastmodified",
458
+ "d:creationdate",
459
+ "d:displayname",
460
+ "d:quota-available-bytes",
461
+ "d:resourcetype",
462
+ "nc:has-preview",
463
+ "nc:is-encrypted",
464
+ "nc:mount-type",
465
+ "oc:comments-unread",
466
+ "oc:favorite",
467
+ "oc:fileid",
468
+ "oc:owner-display-name",
469
+ "oc:owner-id",
470
+ "oc:permissions",
471
+ "oc:size"
472
+ ];
473
+ const defaultDavNamespaces = {
474
+ d: "DAV:",
475
+ nc: "http://nextcloud.org/ns",
476
+ oc: "http://owncloud.org/ns",
477
+ ocs: "http://open-collaboration-services.org/ns"
478
+ };
479
+ const registerDavProperty = function(prop, namespace = { nc: "http://nextcloud.org/ns" }) {
480
+ if (typeof window._nc_dav_properties === "undefined") {
481
+ window._nc_dav_properties = [...defaultDavProperties];
482
+ window._nc_dav_namespaces = { ...defaultDavNamespaces };
483
+ }
484
+ const namespaces = { ...window._nc_dav_namespaces, ...namespace };
485
+ if (window._nc_dav_properties.find((search) => search === prop)) {
486
+ logger.warn(`${prop} already registered`, { prop });
487
+ return false;
488
+ }
489
+ if (prop.startsWith("<") || prop.split(":").length !== 2) {
490
+ logger.error(`${prop} is not valid. See example: 'oc:fileid'`, { prop });
491
+ return false;
492
+ }
493
+ const ns = prop.split(":")[0];
494
+ if (!namespaces[ns]) {
495
+ logger.error(`${prop} namespace unknown`, { prop, namespaces });
496
+ return false;
497
+ }
498
+ window._nc_dav_properties.push(prop);
499
+ window._nc_dav_namespaces = namespaces;
500
+ return true;
501
+ };
502
+ const getDavProperties = function() {
503
+ if (typeof window._nc_dav_properties === "undefined") {
504
+ window._nc_dav_properties = [...defaultDavProperties];
505
+ }
506
+ return window._nc_dav_properties.map((prop) => `<${prop} />`).join(" ");
507
+ };
508
+ const getDavNameSpaces = function() {
509
+ if (typeof window._nc_dav_namespaces === "undefined") {
510
+ window._nc_dav_namespaces = { ...defaultDavNamespaces };
511
+ }
512
+ return Object.keys(window._nc_dav_namespaces).map((ns) => `xmlns:${ns}="${window._nc_dav_namespaces?.[ns]}"`).join(" ");
513
+ };
514
+ const getDefaultPropfind = function() {
515
+ return `<?xml version="1.0"?>
516
+ <d:propfind ${getDavNameSpaces()}>
517
+ <d:prop>
518
+ ${getDavProperties()}
519
+ </d:prop>
520
+ </d:propfind>`;
521
+ };
522
+ const getFavoritesReport = function() {
523
+ return `<?xml version="1.0"?>
524
+ <oc:filter-files ${getDavNameSpaces()}>
525
+ <d:prop>
526
+ ${getDavProperties()}
527
+ </d:prop>
528
+ <oc:filter-rules>
529
+ <oc:favorite>1</oc:favorite>
530
+ </oc:filter-rules>
531
+ </oc:filter-files>`;
532
+ };
533
+ const getRecentSearch = function(lastModified) {
534
+ return `<?xml version="1.0" encoding="UTF-8"?>
535
+ <d:searchrequest ${getDavNameSpaces()}
536
+ xmlns:ns="https://github.com/icewind1991/SearchDAV/ns">
537
+ <d:basicsearch>
538
+ <d:select>
539
+ <d:prop>
540
+ ${getDavProperties()}
541
+ </d:prop>
542
+ </d:select>
543
+ <d:from>
544
+ <d:scope>
545
+ <d:href>/files/${auth.getCurrentUser()?.uid}/</d:href>
546
+ <d:depth>infinity</d:depth>
547
+ </d:scope>
548
+ </d:from>
549
+ <d:where>
550
+ <d:and>
551
+ <d:or>
552
+ <d:not>
553
+ <d:eq>
554
+ <d:prop>
555
+ <d:getcontenttype/>
556
+ </d:prop>
557
+ <d:literal>httpd/unix-directory</d:literal>
558
+ </d:eq>
559
+ </d:not>
560
+ <d:eq>
561
+ <d:prop>
562
+ <oc:size/>
563
+ </d:prop>
564
+ <d:literal>0</d:literal>
565
+ </d:eq>
566
+ </d:or>
567
+ <d:gt>
568
+ <d:prop>
569
+ <d:getlastmodified/>
570
+ </d:prop>
571
+ <d:literal>${lastModified}</d:literal>
572
+ </d:gt>
573
+ </d:and>
574
+ </d:where>
575
+ <d:orderby>
576
+ <d:order>
577
+ <d:prop>
578
+ <d:getlastmodified/>
579
+ </d:prop>
580
+ <d:descending/>
581
+ </d:order>
582
+ </d:orderby>
583
+ <d:limit>
584
+ <d:nresults>100</d:nresults>
585
+ <ns:firstresult>0</ns:firstresult>
586
+ </d:limit>
587
+ </d:basicsearch>
588
+ </d:searchrequest>`;
589
+ };
590
+ function getRootPath() {
591
+ if (_public.isPublicShare()) {
592
+ return `/files/${_public.getSharingToken()}`;
593
+ }
594
+ return `/files/${auth.getCurrentUser()?.uid}`;
595
+ }
596
+ const defaultRootPath = getRootPath();
597
+ function getRemoteURL() {
598
+ const url = router.generateRemoteUrl("dav");
599
+ if (_public.isPublicShare()) {
600
+ return url.replace("remote.php", "public.php");
601
+ }
602
+ return url;
603
+ }
604
+ const defaultRemoteURL = getRemoteURL();
605
+ const getClient = function(remoteURL = defaultRemoteURL, headers = {}) {
606
+ const client = webdav.createClient(remoteURL, { headers });
607
+ function setHeaders(token) {
608
+ client.setHeaders({
609
+ ...headers,
610
+ // Add this so the server knows it is an request from the browser
611
+ "X-Requested-With": "XMLHttpRequest",
612
+ // Inject user auth
613
+ requesttoken: token ?? ""
614
+ });
615
+ }
616
+ auth.onRequestTokenUpdate(setHeaders);
617
+ setHeaders(auth.getRequestToken());
618
+ const patcher = webdav.getPatcher();
619
+ patcher.patch("fetch", (url, options) => {
620
+ const headers2 = options.headers;
621
+ if (headers2?.method) {
622
+ options.method = headers2.method;
623
+ delete headers2.method;
624
+ }
625
+ return fetch(url, options);
626
+ });
627
+ return client;
628
+ };
629
+ const getFavoriteNodes = (davClient, path2 = "/", davRoot = defaultRootPath) => {
630
+ const controller = new AbortController();
631
+ return new cancelablePromise.CancelablePromise(async (resolve, reject, onCancel) => {
632
+ onCancel(() => controller.abort());
633
+ try {
634
+ const contentsResponse = await davClient.getDirectoryContents(`${davRoot}${path2}`, {
635
+ signal: controller.signal,
636
+ details: true,
637
+ data: getFavoritesReport(),
638
+ headers: {
639
+ // see getClient for patched webdav client
640
+ method: "REPORT"
641
+ },
642
+ includeSelf: true
643
+ });
644
+ const nodes = contentsResponse.data.filter((node) => node.filename !== path2).map((result) => resultToNode(result, davRoot));
645
+ resolve(nodes);
646
+ } catch (error) {
647
+ reject(error);
648
+ }
649
+ });
650
+ };
651
+ const resultToNode = function(node, filesRoot = defaultRootPath, remoteURL = defaultRemoteURL) {
652
+ let userId = auth.getCurrentUser()?.uid;
653
+ if (_public.isPublicShare()) {
654
+ userId = userId ?? "anonymous";
655
+ } else if (!userId) {
656
+ throw new Error("No user id found");
657
+ }
658
+ const props = node.props;
659
+ const permissions = parsePermissions(props?.permissions);
660
+ const owner = String(props?.["owner-id"] || userId);
661
+ const id = props.fileid || 0;
662
+ const mtime = new Date(Date.parse(node.lastmod));
663
+ const crtime = new Date(Date.parse(props.creationdate));
664
+ const nodeData = {
665
+ id,
666
+ source: `${remoteURL}${node.filename}`,
667
+ mtime: !isNaN(mtime.getTime()) && mtime.getTime() !== 0 ? mtime : void 0,
668
+ crtime: !isNaN(crtime.getTime()) && crtime.getTime() !== 0 ? crtime : void 0,
669
+ mime: node.mime || "application/octet-stream",
670
+ // Manually cast to work around for https://github.com/perry-mitchell/webdav-client/pull/380
671
+ displayname: props.displayname !== void 0 ? String(props.displayname) : void 0,
672
+ size: props?.size || Number.parseInt(props.getcontentlength || "0"),
673
+ // The fileid is set to -1 for failed requests
674
+ status: id < 0 ? NodeStatus.FAILED : void 0,
675
+ permissions,
676
+ owner,
677
+ root: filesRoot,
678
+ attributes: {
679
+ ...node,
680
+ ...props,
681
+ hasPreview: props?.["has-preview"]
682
+ }
683
+ };
684
+ delete nodeData.attributes?.props;
685
+ return node.type === "file" ? new File(nodeData) : new Folder(nodeData);
686
+ };
687
+ exports.File = File;
688
+ exports.FileType = FileType;
689
+ exports.Folder = Folder;
690
+ exports.Node = Node;
691
+ exports.NodeStatus = NodeStatus;
692
+ exports.Permission = Permission;
693
+ exports.defaultDavNamespaces = defaultDavNamespaces;
694
+ exports.defaultDavProperties = defaultDavProperties;
695
+ exports.defaultRemoteURL = defaultRemoteURL;
696
+ exports.defaultRootPath = defaultRootPath;
697
+ exports.getClient = getClient;
698
+ exports.getDavNameSpaces = getDavNameSpaces;
699
+ exports.getDavProperties = getDavProperties;
700
+ exports.getDefaultPropfind = getDefaultPropfind;
701
+ exports.getFavoriteNodes = getFavoriteNodes;
702
+ exports.getFavoritesReport = getFavoritesReport;
703
+ exports.getRecentSearch = getRecentSearch;
704
+ exports.getRemoteURL = getRemoteURL;
705
+ exports.getRootPath = getRootPath;
706
+ exports.logger = logger;
707
+ exports.parsePermissions = parsePermissions;
708
+ exports.registerDavProperty = registerDavProperty;
709
+ exports.resultToNode = resultToNode;