@tauri-apps/plugin-fs 2.4.5 → 2.5.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.
package/dist-js/index.cjs CHANGED
@@ -9,6 +9,19 @@ var core = require('@tauri-apps/api/core');
9
9
  /**
10
10
  * Access the file system.
11
11
  *
12
+ * ## iOS security-scoped resources
13
+ *
14
+ * On iOS, the `fs` plugin automatically manages access to security-scoped resources when a file URL is accessed.
15
+ * This is required for files outside the app's sandbox (e.g., from file picker).
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { open } from '@tauri-apps/plugin-fs';
20
+ *
21
+ * const file = await open('file:///path/to/file.txt');
22
+ * await file.close();
23
+ * ```
24
+ *
12
25
  * ## Security
13
26
  *
14
27
  * This module prevents path traversal, not allowing parent directory accessors to be used
@@ -431,7 +444,7 @@ async function readFile(path, options) {
431
444
  return arr instanceof ArrayBuffer ? new Uint8Array(arr) : Uint8Array.from(arr);
432
445
  }
433
446
  /**
434
- * Reads and returns the entire contents of a file as UTF-8 string.
447
+ * Reads and returns the entire contents of a file as a string using the specified encoding (default: UTF-8).
435
448
  * @example
436
449
  * ```typescript
437
450
  * import { readTextFile, BaseDirectory } from '@tauri-apps/plugin-fs';
@@ -449,10 +462,10 @@ async function readTextFile(path, options) {
449
462
  options
450
463
  });
451
464
  const bytes = arr instanceof ArrayBuffer ? arr : Uint8Array.from(arr);
452
- return new TextDecoder().decode(bytes);
465
+ return new TextDecoder(options?.encoding ?? 'utf-8').decode(bytes);
453
466
  }
454
467
  /**
455
- * Returns an async {@linkcode AsyncIterableIterator} over the lines of a file as UTF-8 string.
468
+ * Returns an async {@linkcode AsyncIterableIterator} over the lines of a file, decoded using the specified encoding (default: UTF-8).
456
469
  * @example
457
470
  * ```typescript
458
471
  * import { readTextFileLines, BaseDirectory } from '@tauri-apps/plugin-fs';
@@ -475,10 +488,13 @@ async function readTextFileLines(path, options) {
475
488
  path: pathStr,
476
489
  rid: null,
477
490
  async next() {
491
+ const decoder = new TextDecoder(options?.encoding ?? 'utf-8');
478
492
  if (this.rid === null) {
493
+ // Use the normalized encoding label for options.
494
+ const encoding = decoder.encoding;
479
495
  this.rid = await core.invoke('plugin:fs|read_text_file_lines', {
480
496
  path: pathStr,
481
- options
497
+ options: options != null ? { ...options, encoding } : undefined
482
498
  });
483
499
  }
484
500
  const arr = await core.invoke('plugin:fs|read_text_file_lines_next', { rid: this.rid });
@@ -494,7 +510,7 @@ async function readTextFileLines(path, options) {
494
510
  this.rid = null;
495
511
  return { value: null, done };
496
512
  }
497
- const line = new TextDecoder().decode(bytes.slice(0, bytes.byteLength - 1));
513
+ const line = decoder.decode(bytes.slice(0, bytes.byteLength - 1));
498
514
  return {
499
515
  value: line,
500
516
  done
@@ -781,6 +797,71 @@ async function size(path) {
781
797
  path: path instanceof URL ? path.toString() : path
782
798
  });
783
799
  }
800
+ /**
801
+ * Starts accessing a security-scoped resource for the given file URL.
802
+ * This should be called when you're accessing a file that was opened
803
+ * using a security-scoped URL (e.g., from a file picker).
804
+ *
805
+ * Note that accessing security-scoped resources is automatically managed by the plugin on iOS, so you don't need to call this function
806
+ * unless you want to manage the scope manually.
807
+ *
808
+ * You must call {@linkcode stopAccessingSecurityScopedResource} when you're done accessing the resource.
809
+ *
810
+ * #### Platform-specific
811
+ *
812
+ * - **iOS:** Starts accessing the security-scoped resource.
813
+ * - **Other platforms:** does nothing.
814
+ *
815
+ * @example
816
+ * ```typescript
817
+ * import { startAccessingSecurityScopedResource } from '@tauri-apps/plugin-fs';
818
+ *
819
+ * const filePath = 'file:///path/to/file.txt';
820
+ * await startAccessingSecurityScopedResource(filePath);
821
+ * // ... use the resource ...
822
+ * ```
823
+ *
824
+ * @since 2.5.0
825
+ */
826
+ async function startAccessingSecurityScopedResource(path) {
827
+ if (path instanceof URL && path.protocol !== 'file:') {
828
+ throw new TypeError('Must be a file URL.');
829
+ }
830
+ await core.invoke('plugin:fs|start_accessing_security_scoped_resource', {
831
+ path: path instanceof URL ? path.toString() : path
832
+ });
833
+ }
834
+ /**
835
+ * Stops accessing a security-scoped resource for the given file URL.
836
+ * This should be called when you're done accessing a file that was opened
837
+ * using a security-scoped URL (e.g., from a file picker) when using manual tracking via {@linkcode startAccessingSecurityScopedResource}.
838
+ *
839
+ * #### Platform-specific
840
+ *
841
+ * - **iOS:** Stops accessing the security-scoped resource.
842
+ * - **Other platforms:** does nothing.
843
+ *
844
+ * @example
845
+ * ```typescript
846
+ * import { stopAccessingSecurityScopedResource } from '@tauri-apps/plugin-fs';
847
+ *
848
+ * const filePath = 'file:///path/to/file.txt';
849
+ * await startAccessingSecurityScopedResource(filePath);
850
+ * // ... use the resource ...
851
+ * // when you're done with the resource:
852
+ * await stopAccessingSecurityScopedResource(filePath);
853
+ * ```
854
+ *
855
+ * @since 2.5.0
856
+ */
857
+ async function stopAccessingSecurityScopedResource(path) {
858
+ if (path instanceof URL && path.protocol !== 'file:') {
859
+ throw new TypeError('Must be a file URL.');
860
+ }
861
+ await core.invoke('plugin:fs|stop_accessing_security_scoped_resource', {
862
+ path: path instanceof URL ? path.toString() : path
863
+ });
864
+ }
784
865
 
785
866
  Object.defineProperty(exports, "BaseDirectory", {
786
867
  enumerable: true,
@@ -800,7 +881,9 @@ exports.readTextFileLines = readTextFileLines;
800
881
  exports.remove = remove;
801
882
  exports.rename = rename;
802
883
  exports.size = size;
884
+ exports.startAccessingSecurityScopedResource = startAccessingSecurityScopedResource;
803
885
  exports.stat = stat;
886
+ exports.stopAccessingSecurityScopedResource = stopAccessingSecurityScopedResource;
804
887
  exports.truncate = truncate;
805
888
  exports.watch = watch;
806
889
  exports.watchImmediate = watchImmediate;
@@ -1,6 +1,19 @@
1
1
  /**
2
2
  * Access the file system.
3
3
  *
4
+ * ## iOS security-scoped resources
5
+ *
6
+ * On iOS, the `fs` plugin automatically manages access to security-scoped resources when a file URL is accessed.
7
+ * This is required for files outside the app's sandbox (e.g., from file picker).
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { open } from '@tauri-apps/plugin-fs';
12
+ *
13
+ * const file = await open('file:///path/to/file.txt');
14
+ * await file.close();
15
+ * ```
16
+ *
4
17
  * ## Security
5
18
  *
6
19
  * This module prevents path traversal, not allowing parent directory accessors to be used
@@ -524,6 +537,8 @@ declare function readDir(path: string | URL, options?: ReadDirOptions): Promise<
524
537
  interface ReadFileOptions {
525
538
  /** Base directory for `path` */
526
539
  baseDir?: BaseDirectory;
540
+ /** Text encoding to use when reading a text file. Defaults to 'utf-8'. */
541
+ encoding?: string;
527
542
  }
528
543
  /**
529
544
  * Reads and resolves to the entire contents of a file as an array of bytes.
@@ -538,7 +553,7 @@ interface ReadFileOptions {
538
553
  */
539
554
  declare function readFile(path: string | URL, options?: ReadFileOptions): Promise<Uint8Array<ArrayBuffer>>;
540
555
  /**
541
- * Reads and returns the entire contents of a file as UTF-8 string.
556
+ * Reads and returns the entire contents of a file as a string using the specified encoding (default: UTF-8).
542
557
  * @example
543
558
  * ```typescript
544
559
  * import { readTextFile, BaseDirectory } from '@tauri-apps/plugin-fs';
@@ -549,7 +564,7 @@ declare function readFile(path: string | URL, options?: ReadFileOptions): Promis
549
564
  */
550
565
  declare function readTextFile(path: string | URL, options?: ReadFileOptions): Promise<string>;
551
566
  /**
552
- * Returns an async {@linkcode AsyncIterableIterator} over the lines of a file as UTF-8 string.
567
+ * Returns an async {@linkcode AsyncIterableIterator} over the lines of a file, decoded using the specified encoding (default: UTF-8).
553
568
  * @example
554
569
  * ```typescript
555
570
  * import { readTextFileLines, BaseDirectory } from '@tauri-apps/plugin-fs';
@@ -858,5 +873,56 @@ declare function watchImmediate(paths: string | string[] | URL | URL[], cb: (eve
858
873
  * @since 2.1.0
859
874
  */
860
875
  declare function size(path: string | URL): Promise<number>;
876
+ /**
877
+ * Starts accessing a security-scoped resource for the given file URL.
878
+ * This should be called when you're accessing a file that was opened
879
+ * using a security-scoped URL (e.g., from a file picker).
880
+ *
881
+ * Note that accessing security-scoped resources is automatically managed by the plugin on iOS, so you don't need to call this function
882
+ * unless you want to manage the scope manually.
883
+ *
884
+ * You must call {@linkcode stopAccessingSecurityScopedResource} when you're done accessing the resource.
885
+ *
886
+ * #### Platform-specific
887
+ *
888
+ * - **iOS:** Starts accessing the security-scoped resource.
889
+ * - **Other platforms:** does nothing.
890
+ *
891
+ * @example
892
+ * ```typescript
893
+ * import { startAccessingSecurityScopedResource } from '@tauri-apps/plugin-fs';
894
+ *
895
+ * const filePath = 'file:///path/to/file.txt';
896
+ * await startAccessingSecurityScopedResource(filePath);
897
+ * // ... use the resource ...
898
+ * ```
899
+ *
900
+ * @since 2.5.0
901
+ */
902
+ declare function startAccessingSecurityScopedResource(path: string | URL): Promise<void>;
903
+ /**
904
+ * Stops accessing a security-scoped resource for the given file URL.
905
+ * This should be called when you're done accessing a file that was opened
906
+ * using a security-scoped URL (e.g., from a file picker) when using manual tracking via {@linkcode startAccessingSecurityScopedResource}.
907
+ *
908
+ * #### Platform-specific
909
+ *
910
+ * - **iOS:** Stops accessing the security-scoped resource.
911
+ * - **Other platforms:** does nothing.
912
+ *
913
+ * @example
914
+ * ```typescript
915
+ * import { stopAccessingSecurityScopedResource } from '@tauri-apps/plugin-fs';
916
+ *
917
+ * const filePath = 'file:///path/to/file.txt';
918
+ * await startAccessingSecurityScopedResource(filePath);
919
+ * // ... use the resource ...
920
+ * // when you're done with the resource:
921
+ * await stopAccessingSecurityScopedResource(filePath);
922
+ * ```
923
+ *
924
+ * @since 2.5.0
925
+ */
926
+ declare function stopAccessingSecurityScopedResource(path: string | URL): Promise<void>;
861
927
  export type { CreateOptions, OpenOptions, CopyFileOptions, MkdirOptions, DirEntry, ReadDirOptions, ReadFileOptions, RemoveOptions, RenameOptions, StatOptions, TruncateOptions, WriteFileOptions, ExistsOptions, FileInfo, WatchOptions, DebouncedWatchOptions, WatchEvent, WatchEventKind, WatchEventKindAccess, WatchEventKindCreate, WatchEventKindModify, WatchEventKindRemove, UnwatchFn };
862
- export { BaseDirectory, FileHandle, create, open, copyFile, mkdir, readDir, readFile, readTextFile, readTextFileLines, remove, rename, SeekMode, stat, lstat, truncate, writeFile, writeTextFile, exists, watch, watchImmediate, size };
928
+ export { BaseDirectory, FileHandle, create, open, copyFile, mkdir, readDir, readFile, readTextFile, readTextFileLines, remove, rename, SeekMode, stat, lstat, truncate, writeFile, writeTextFile, exists, watch, watchImmediate, size, startAccessingSecurityScopedResource, stopAccessingSecurityScopedResource };
package/dist-js/index.js CHANGED
@@ -7,6 +7,19 @@ import { Resource, invoke, Channel } from '@tauri-apps/api/core';
7
7
  /**
8
8
  * Access the file system.
9
9
  *
10
+ * ## iOS security-scoped resources
11
+ *
12
+ * On iOS, the `fs` plugin automatically manages access to security-scoped resources when a file URL is accessed.
13
+ * This is required for files outside the app's sandbox (e.g., from file picker).
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { open } from '@tauri-apps/plugin-fs';
18
+ *
19
+ * const file = await open('file:///path/to/file.txt');
20
+ * await file.close();
21
+ * ```
22
+ *
10
23
  * ## Security
11
24
  *
12
25
  * This module prevents path traversal, not allowing parent directory accessors to be used
@@ -429,7 +442,7 @@ async function readFile(path, options) {
429
442
  return arr instanceof ArrayBuffer ? new Uint8Array(arr) : Uint8Array.from(arr);
430
443
  }
431
444
  /**
432
- * Reads and returns the entire contents of a file as UTF-8 string.
445
+ * Reads and returns the entire contents of a file as a string using the specified encoding (default: UTF-8).
433
446
  * @example
434
447
  * ```typescript
435
448
  * import { readTextFile, BaseDirectory } from '@tauri-apps/plugin-fs';
@@ -447,10 +460,10 @@ async function readTextFile(path, options) {
447
460
  options
448
461
  });
449
462
  const bytes = arr instanceof ArrayBuffer ? arr : Uint8Array.from(arr);
450
- return new TextDecoder().decode(bytes);
463
+ return new TextDecoder(options?.encoding ?? 'utf-8').decode(bytes);
451
464
  }
452
465
  /**
453
- * Returns an async {@linkcode AsyncIterableIterator} over the lines of a file as UTF-8 string.
466
+ * Returns an async {@linkcode AsyncIterableIterator} over the lines of a file, decoded using the specified encoding (default: UTF-8).
454
467
  * @example
455
468
  * ```typescript
456
469
  * import { readTextFileLines, BaseDirectory } from '@tauri-apps/plugin-fs';
@@ -473,10 +486,13 @@ async function readTextFileLines(path, options) {
473
486
  path: pathStr,
474
487
  rid: null,
475
488
  async next() {
489
+ const decoder = new TextDecoder(options?.encoding ?? 'utf-8');
476
490
  if (this.rid === null) {
491
+ // Use the normalized encoding label for options.
492
+ const encoding = decoder.encoding;
477
493
  this.rid = await invoke('plugin:fs|read_text_file_lines', {
478
494
  path: pathStr,
479
- options
495
+ options: options != null ? { ...options, encoding } : undefined
480
496
  });
481
497
  }
482
498
  const arr = await invoke('plugin:fs|read_text_file_lines_next', { rid: this.rid });
@@ -492,7 +508,7 @@ async function readTextFileLines(path, options) {
492
508
  this.rid = null;
493
509
  return { value: null, done };
494
510
  }
495
- const line = new TextDecoder().decode(bytes.slice(0, bytes.byteLength - 1));
511
+ const line = decoder.decode(bytes.slice(0, bytes.byteLength - 1));
496
512
  return {
497
513
  value: line,
498
514
  done
@@ -779,5 +795,70 @@ async function size(path) {
779
795
  path: path instanceof URL ? path.toString() : path
780
796
  });
781
797
  }
798
+ /**
799
+ * Starts accessing a security-scoped resource for the given file URL.
800
+ * This should be called when you're accessing a file that was opened
801
+ * using a security-scoped URL (e.g., from a file picker).
802
+ *
803
+ * Note that accessing security-scoped resources is automatically managed by the plugin on iOS, so you don't need to call this function
804
+ * unless you want to manage the scope manually.
805
+ *
806
+ * You must call {@linkcode stopAccessingSecurityScopedResource} when you're done accessing the resource.
807
+ *
808
+ * #### Platform-specific
809
+ *
810
+ * - **iOS:** Starts accessing the security-scoped resource.
811
+ * - **Other platforms:** does nothing.
812
+ *
813
+ * @example
814
+ * ```typescript
815
+ * import { startAccessingSecurityScopedResource } from '@tauri-apps/plugin-fs';
816
+ *
817
+ * const filePath = 'file:///path/to/file.txt';
818
+ * await startAccessingSecurityScopedResource(filePath);
819
+ * // ... use the resource ...
820
+ * ```
821
+ *
822
+ * @since 2.5.0
823
+ */
824
+ async function startAccessingSecurityScopedResource(path) {
825
+ if (path instanceof URL && path.protocol !== 'file:') {
826
+ throw new TypeError('Must be a file URL.');
827
+ }
828
+ await invoke('plugin:fs|start_accessing_security_scoped_resource', {
829
+ path: path instanceof URL ? path.toString() : path
830
+ });
831
+ }
832
+ /**
833
+ * Stops accessing a security-scoped resource for the given file URL.
834
+ * This should be called when you're done accessing a file that was opened
835
+ * using a security-scoped URL (e.g., from a file picker) when using manual tracking via {@linkcode startAccessingSecurityScopedResource}.
836
+ *
837
+ * #### Platform-specific
838
+ *
839
+ * - **iOS:** Stops accessing the security-scoped resource.
840
+ * - **Other platforms:** does nothing.
841
+ *
842
+ * @example
843
+ * ```typescript
844
+ * import { stopAccessingSecurityScopedResource } from '@tauri-apps/plugin-fs';
845
+ *
846
+ * const filePath = 'file:///path/to/file.txt';
847
+ * await startAccessingSecurityScopedResource(filePath);
848
+ * // ... use the resource ...
849
+ * // when you're done with the resource:
850
+ * await stopAccessingSecurityScopedResource(filePath);
851
+ * ```
852
+ *
853
+ * @since 2.5.0
854
+ */
855
+ async function stopAccessingSecurityScopedResource(path) {
856
+ if (path instanceof URL && path.protocol !== 'file:') {
857
+ throw new TypeError('Must be a file URL.');
858
+ }
859
+ await invoke('plugin:fs|stop_accessing_security_scoped_resource', {
860
+ path: path instanceof URL ? path.toString() : path
861
+ });
862
+ }
782
863
 
783
- export { FileHandle, SeekMode, copyFile, create, exists, lstat, mkdir, open, readDir, readFile, readTextFile, readTextFileLines, remove, rename, size, stat, truncate, watch, watchImmediate, writeFile, writeTextFile };
864
+ export { FileHandle, SeekMode, copyFile, create, exists, lstat, mkdir, open, readDir, readFile, readTextFile, readTextFileLines, remove, rename, size, startAccessingSecurityScopedResource, stat, stopAccessingSecurityScopedResource, truncate, watch, watchImmediate, writeFile, writeTextFile };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tauri-apps/plugin-fs",
3
- "version": "2.4.5",
3
+ "version": "2.5.1",
4
4
  "description": "Access the file system.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "authors": [
@@ -25,6 +25,6 @@
25
25
  "LICENSE"
26
26
  ],
27
27
  "dependencies": {
28
- "@tauri-apps/api": "^2.8.0"
28
+ "@tauri-apps/api": "^2.11.0"
29
29
  }
30
30
  }