@socketsecurity/lib 4.3.0 → 5.0.0

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/README.md +1 -1
  3. package/dist/constants/node.js +1 -1
  4. package/dist/{package-default-node-range.js → constants/package-default-node-range.js} +1 -1
  5. package/dist/constants/packages.js +3 -3
  6. package/dist/{dlx-binary.d.ts → dlx/binary.d.ts} +2 -2
  7. package/dist/{dlx-binary.js → dlx/binary.js} +17 -17
  8. package/dist/dlx/cache.d.ts +25 -0
  9. package/dist/dlx/cache.js +32 -0
  10. package/dist/dlx/dir.d.ts +24 -0
  11. package/dist/dlx/dir.js +79 -0
  12. package/dist/{dlx-manifest.js → dlx/manifest.js} +7 -7
  13. package/dist/{dlx-package.d.ts → dlx/package.d.ts} +2 -2
  14. package/dist/{dlx-package.js → dlx/package.js} +16 -16
  15. package/dist/dlx/packages.d.ts +24 -0
  16. package/dist/dlx/packages.js +125 -0
  17. package/dist/dlx/paths.d.ts +31 -0
  18. package/dist/dlx/paths.js +75 -0
  19. package/dist/fs.d.ts +103 -55
  20. package/dist/fs.js +149 -41
  21. package/dist/json/edit.d.ts +16 -0
  22. package/dist/json/edit.js +217 -0
  23. package/dist/json/format.d.ts +140 -0
  24. package/dist/json/format.js +121 -0
  25. package/dist/json/parse.d.ts +76 -0
  26. package/dist/{json.js → json/parse.js} +4 -4
  27. package/dist/json/types.d.ts +229 -0
  28. package/dist/json/types.js +17 -0
  29. package/dist/objects.d.ts +61 -61
  30. package/dist/objects.js +30 -30
  31. package/dist/packages/{editable.js → edit.js} +18 -32
  32. package/dist/packages/operations.js +3 -3
  33. package/dist/packages.d.ts +2 -2
  34. package/dist/packages.js +5 -5
  35. package/dist/promises.d.ts +19 -19
  36. package/dist/promises.js +14 -14
  37. package/dist/sorts.d.ts +10 -10
  38. package/dist/sorts.js +19 -19
  39. package/dist/strings.d.ts +63 -63
  40. package/dist/strings.js +18 -18
  41. package/dist/suppress-warnings.js +4 -0
  42. package/package.json +59 -35
  43. package/dist/dlx.d.ts +0 -104
  44. package/dist/dlx.js +0 -220
  45. package/dist/json.d.ts +0 -196
  46. /package/dist/{lifecycle-script-names.d.ts → constants/lifecycle-script-names.d.ts} +0 -0
  47. /package/dist/{lifecycle-script-names.js → constants/lifecycle-script-names.js} +0 -0
  48. /package/dist/{maintained-node-versions.d.ts → constants/maintained-node-versions.d.ts} +0 -0
  49. /package/dist/{maintained-node-versions.js → constants/maintained-node-versions.js} +0 -0
  50. /package/dist/{package-default-node-range.d.ts → constants/package-default-node-range.d.ts} +0 -0
  51. /package/dist/{package-default-socket-categories.d.ts → constants/package-default-socket-categories.d.ts} +0 -0
  52. /package/dist/{package-default-socket-categories.js → constants/package-default-socket-categories.js} +0 -0
  53. /package/dist/{dlx-manifest.d.ts → dlx/manifest.d.ts} +0 -0
  54. /package/dist/packages/{editable.d.ts → edit.d.ts} +0 -0
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ /* Socket Lib - Built with esbuild */
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var paths_exports = {};
21
+ __export(paths_exports, {
22
+ getDlxInstalledPackageDir: () => getDlxInstalledPackageDir,
23
+ getDlxPackageDir: () => getDlxPackageDir,
24
+ getDlxPackageJsonPath: () => getDlxPackageJsonPath,
25
+ getDlxPackageNodeModulesDir: () => getDlxPackageNodeModulesDir,
26
+ isInSocketDlx: () => isInSocketDlx
27
+ });
28
+ module.exports = __toCommonJS(paths_exports);
29
+ var import_normalize = require("../paths/normalize");
30
+ var import_socket = require("../paths/socket");
31
+ let _path;
32
+ // @__NO_SIDE_EFFECTS__
33
+ function getPath() {
34
+ if (_path === void 0) {
35
+ _path = require("node:path");
36
+ }
37
+ return _path;
38
+ }
39
+ function getDlxInstalledPackageDir(packageName) {
40
+ const path = /* @__PURE__ */ getPath();
41
+ return (0, import_normalize.normalizePath)(
42
+ path.join(getDlxPackageNodeModulesDir(packageName), packageName)
43
+ );
44
+ }
45
+ function getDlxPackageDir(packageName) {
46
+ const path = /* @__PURE__ */ getPath();
47
+ return (0, import_normalize.normalizePath)(path.join((0, import_socket.getSocketDlxDir)(), packageName));
48
+ }
49
+ function getDlxPackageJsonPath(packageName) {
50
+ const path = /* @__PURE__ */ getPath();
51
+ return (0, import_normalize.normalizePath)(
52
+ path.join(getDlxInstalledPackageDir(packageName), "package.json")
53
+ );
54
+ }
55
+ function getDlxPackageNodeModulesDir(packageName) {
56
+ const path = /* @__PURE__ */ getPath();
57
+ return (0, import_normalize.normalizePath)(path.join(getDlxPackageDir(packageName), "node_modules"));
58
+ }
59
+ function isInSocketDlx(filePath) {
60
+ if (!filePath) {
61
+ return false;
62
+ }
63
+ const path = /* @__PURE__ */ getPath();
64
+ const dlxDir = (0, import_socket.getSocketDlxDir)();
65
+ const absolutePath = (0, import_normalize.normalizePath)(path.resolve(filePath));
66
+ return absolutePath.startsWith(`${dlxDir}/`);
67
+ }
68
+ // Annotate the CommonJS export names for ESM import in node:
69
+ 0 && (module.exports = {
70
+ getDlxInstalledPackageDir,
71
+ getDlxPackageDir,
72
+ getDlxPackageJsonPath,
73
+ getDlxPackageNodeModulesDir,
74
+ isInSocketDlx
75
+ });
package/dist/fs.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import type { Abortable } from 'events';
6
6
  import type { MakeDirectoryOptions, ObjectEncodingOptions, OpenMode, PathLike } from 'fs';
7
- import type { JsonReviver } from './json';
7
+ import type { JsonReviver } from './json/types';
8
8
  import { type Remap } from './objects';
9
9
  /**
10
10
  * Supported text encodings for Node.js Buffers.
@@ -282,6 +282,13 @@ export declare function findUp(name: string | string[] | readonly string[], opti
282
282
  */
283
283
  /*@__NO_SIDE_EFFECTS__*/
284
284
  export declare function findUpSync(name: string | string[] | readonly string[], options?: FindUpSyncOptions | undefined): string;
285
+ /**
286
+ * Invalidate the cached allowed directories.
287
+ * Called automatically by the paths/rewire module when paths are overridden in tests.
288
+ *
289
+ * @internal Used for test rewiring
290
+ */
291
+ export declare function invalidatePathCache(): void;
285
292
  /**
286
293
  * Check if a path is a directory asynchronously.
287
294
  * Returns `true` for directories, `false` for files or non-existent paths.
@@ -351,53 +358,37 @@ export declare function isDirEmptySync(dirname: PathLike, options?: IsDirEmptyOp
351
358
  /*@__NO_SIDE_EFFECTS__*/
352
359
  export declare function isSymLinkSync(filepath: PathLike): boolean;
353
360
  /**
354
- * Result of file readability validation.
355
- * Contains lists of valid and invalid file paths.
356
- */
357
- export interface ValidateFilesResult {
358
- /**
359
- * File paths that passed validation and are readable.
360
- */
361
- validPaths: string[];
362
- /**
363
- * File paths that failed validation (unreadable, permission denied, or non-existent).
364
- * Common with Yarn Berry PnP virtual filesystem, pnpm symlinks, or filesystem race conditions.
365
- */
366
- invalidPaths: string[];
367
- }
368
- /**
369
- * Validate that file paths are readable before processing.
370
- * Filters out files from glob results that cannot be accessed (common with
371
- * Yarn Berry PnP virtual filesystem, pnpm content-addressable store symlinks,
372
- * or filesystem race conditions in CI/CD environments).
361
+ * Normalize encoding string to canonical form.
362
+ * Handles common encodings inline for performance, delegates to slowCases for others.
373
363
  *
374
- * This defensive pattern prevents ENOENT errors when files exist in glob
375
- * results but are not accessible via standard filesystem operations.
364
+ * Based on Node.js internal/util.js normalizeEncoding implementation.
365
+ * @see https://github.com/nodejs/node/blob/ae62b36d442b7bf987e85ae6e0df0f02cc1bb17f/lib/internal/util.js#L247-L310
376
366
  *
377
- * @param filepaths - Array of file paths to validate
378
- * @returns Object with `validPaths` (readable) and `invalidPaths` (unreadable)
367
+ * @param enc - Encoding to normalize (can be null/undefined)
368
+ * @returns Normalized encoding string, defaults to 'utf8'
379
369
  *
380
370
  * @example
381
371
  * ```ts
382
- * import { validateFiles } from '@socketsecurity/lib/fs'
383
- *
384
- * const files = ['package.json', '.pnp.cjs/virtual-file.json']
385
- * const { validPaths, invalidPaths } = validateFiles(files)
386
- *
387
- * console.log(`Valid: ${validPaths.length}`)
388
- * console.log(`Invalid: ${invalidPaths.length}`)
372
+ * normalizeEncoding('UTF-8') // Returns 'utf8'
373
+ * normalizeEncoding('binary') // Returns 'latin1'
374
+ * normalizeEncoding('ucs-2') // Returns 'utf16le'
375
+ * normalizeEncoding(null) // Returns 'utf8'
389
376
  * ```
377
+ */
378
+ /*@__NO_SIDE_EFFECTS__*/
379
+ export declare function normalizeEncoding(enc: BufferEncoding | string | null | undefined): BufferEncoding;
380
+ /**
381
+ * Move the "slow cases" to a separate function to make sure this function gets
382
+ * inlined properly. That prioritizes the common case.
390
383
  *
391
- * @example
392
- * ```ts
393
- * // Typical usage in Socket CLI commands
394
- * const packagePaths = await getPackageFilesForScan(targets)
395
- * const { validPaths } = validateFiles(packagePaths)
396
- * await sdk.uploadManifestFiles(orgSlug, validPaths)
397
- * ```
384
+ * Based on Node.js internal/util.js normalizeEncoding implementation.
385
+ * @see https://github.com/nodejs/node/blob/ae62b36d442b7bf987e85ae6e0df0f02cc1bb17f/lib/internal/util.js#L247-L310
386
+ *
387
+ * @param enc - Encoding to normalize
388
+ * @returns Normalized encoding string, defaults to 'utf8' for unknown encodings
398
389
  */
399
390
  /*@__NO_SIDE_EFFECTS__*/
400
- export declare function validateFiles(filepaths: string[] | readonly string[]): ValidateFilesResult;
391
+ export declare function normalizeEncodingSlow(enc: string): BufferEncoding;
401
392
  /**
402
393
  * Read directory names asynchronously with filtering and sorting.
403
394
  * Returns only directory names (not files), with optional filtering for empty directories
@@ -554,7 +545,7 @@ export declare function readFileUtf8Sync(filepath: PathLike, options?: ReadFileO
554
545
  * ```
555
546
  */
556
547
  /*@__NO_SIDE_EFFECTS__*/
557
- export declare function readJson(filepath: PathLike, options?: ReadJsonOptions | string | undefined): Promise<import("./json").JsonValue>;
548
+ export declare function readJson(filepath: PathLike, options?: ReadJsonOptions | string | undefined): Promise<import("./json/types").JsonValue>;
558
549
  /**
559
550
  * Read and parse a JSON file synchronously.
560
551
  * Reads the file as UTF-8 text and parses it as JSON.
@@ -584,14 +575,7 @@ export declare function readJson(filepath: PathLike, options?: ReadJsonOptions |
584
575
  * ```
585
576
  */
586
577
  /*@__NO_SIDE_EFFECTS__*/
587
- export declare function readJsonSync(filepath: PathLike, options?: ReadJsonOptions | string | undefined): import("./json").JsonValue;
588
- /**
589
- * Invalidate the cached allowed directories.
590
- * Called automatically by the paths/rewire module when paths are overridden in tests.
591
- *
592
- * @internal Used for test rewiring
593
- */
594
- export declare function invalidatePathCache(): void;
578
+ export declare function readJsonSync(filepath: PathLike, options?: ReadJsonOptions | string | undefined): import("./json/types").JsonValue;
595
579
  /**
596
580
  * Safely delete a file or directory asynchronously with built-in protections.
597
581
  * Uses `del` for safer deletion that prevents removing cwd and above by default.
@@ -707,14 +691,15 @@ export declare function safeMkdirSync(path: PathLike, options?: MakeDirectoryOpt
707
691
  * Safely read a file asynchronously, returning undefined on error.
708
692
  * Useful when you want to attempt reading a file without handling errors explicitly.
709
693
  * Returns undefined for any error (file not found, permission denied, etc.).
694
+ * Defaults to UTF-8 encoding, returning a string unless encoding is explicitly set to null.
710
695
  *
711
696
  * @param filepath - Path to file
712
697
  * @param options - Read options including encoding and default value
713
- * @returns Promise resolving to file contents, or undefined on error
698
+ * @returns Promise resolving to file contents (string by default), or undefined on error
714
699
  *
715
700
  * @example
716
701
  * ```ts
717
- * // Try to read a file, get undefined if it doesn't exist
702
+ * // Try to read a file as UTF-8 string (default), get undefined if it doesn't exist
718
703
  * const content = await safeReadFile('./optional-config.txt')
719
704
  * if (content) {
720
705
  * console.log('Config found:', content)
@@ -722,33 +707,48 @@ export declare function safeMkdirSync(path: PathLike, options?: MakeDirectoryOpt
722
707
  *
723
708
  * // Read with specific encoding
724
709
  * const data = await safeReadFile('./data.txt', { encoding: 'utf8' })
710
+ *
711
+ * // Read as Buffer by setting encoding to null
712
+ * const buffer = await safeReadFile('./binary.dat', { encoding: null })
725
713
  * ```
726
714
  */
727
715
  /*@__NO_SIDE_EFFECTS__*/
728
- export declare function safeReadFile(filepath: PathLike, options?: SafeReadOptions | undefined): Promise<NonSharedBuffer>;
716
+ export declare function safeReadFile(filepath: PathLike, options: SafeReadOptions & {
717
+ encoding: null;
718
+ }): Promise<Buffer | undefined>;
719
+ /*@__NO_SIDE_EFFECTS__*/
720
+ export declare function safeReadFile(filepath: PathLike, options?: SafeReadOptions | undefined): Promise<string | undefined>;
729
721
  /**
730
722
  * Safely read a file synchronously, returning undefined on error.
731
723
  * Useful when you want to attempt reading a file without handling errors explicitly.
732
724
  * Returns undefined for any error (file not found, permission denied, etc.).
725
+ * Defaults to UTF-8 encoding, returning a string unless encoding is explicitly set to null.
733
726
  *
734
727
  * @param filepath - Path to file
735
728
  * @param options - Read options including encoding and default value
736
- * @returns File contents, or undefined on error
729
+ * @returns File contents (string by default), or undefined on error
737
730
  *
738
731
  * @example
739
732
  * ```ts
740
- * // Try to read a config file
733
+ * // Try to read a config file as UTF-8 string (default)
741
734
  * const config = safeReadFileSync('./config.txt')
742
735
  * if (config) {
743
736
  * console.log('Config loaded successfully')
744
737
  * }
745
738
  *
746
- * // Read binary file safely
739
+ * // Read with explicit encoding
740
+ * const data = safeReadFileSync('./data.txt', { encoding: 'utf8' })
741
+ *
742
+ * // Read binary file by setting encoding to null
747
743
  * const buffer = safeReadFileSync('./image.png', { encoding: null })
748
744
  * ```
749
745
  */
750
746
  /*@__NO_SIDE_EFFECTS__*/
751
- export declare function safeReadFileSync(filepath: PathLike, options?: SafeReadOptions | undefined): string | NonSharedBuffer;
747
+ export declare function safeReadFileSync(filepath: PathLike, options: SafeReadOptions & {
748
+ encoding: null;
749
+ }): Buffer | undefined;
750
+ /*@__NO_SIDE_EFFECTS__*/
751
+ export declare function safeReadFileSync(filepath: PathLike, options?: SafeReadOptions | undefined): string | undefined;
752
752
  /**
753
753
  * Safely get file stats asynchronously, returning undefined on error.
754
754
  * Useful for checking file existence and properties without error handling.
@@ -812,6 +812,54 @@ export declare function safeStatsSync(filepath: PathLike, options?: ReadFileOpti
812
812
  */
813
813
  /*@__NO_SIDE_EFFECTS__*/
814
814
  export declare function uniqueSync(filepath: PathLike): string;
815
+ /**
816
+ * Result of file readability validation.
817
+ * Contains lists of valid and invalid file paths.
818
+ */
819
+ export interface ValidateFilesResult {
820
+ /**
821
+ * File paths that passed validation and are readable.
822
+ */
823
+ validPaths: string[];
824
+ /**
825
+ * File paths that failed validation (unreadable, permission denied, or non-existent).
826
+ * Common with Yarn Berry PnP virtual filesystem, pnpm symlinks, or filesystem race conditions.
827
+ */
828
+ invalidPaths: string[];
829
+ }
830
+ /**
831
+ * Validate that file paths are readable before processing.
832
+ * Filters out files from glob results that cannot be accessed (common with
833
+ * Yarn Berry PnP virtual filesystem, pnpm content-addressable store symlinks,
834
+ * or filesystem race conditions in CI/CD environments).
835
+ *
836
+ * This defensive pattern prevents ENOENT errors when files exist in glob
837
+ * results but are not accessible via standard filesystem operations.
838
+ *
839
+ * @param filepaths - Array of file paths to validate
840
+ * @returns Object with `validPaths` (readable) and `invalidPaths` (unreadable)
841
+ *
842
+ * @example
843
+ * ```ts
844
+ * import { validateFiles } from '@socketsecurity/lib/fs'
845
+ *
846
+ * const files = ['package.json', '.pnp.cjs/virtual-file.json']
847
+ * const { validPaths, invalidPaths } = validateFiles(files)
848
+ *
849
+ * console.log(`Valid: ${validPaths.length}`)
850
+ * console.log(`Invalid: ${invalidPaths.length}`)
851
+ * ```
852
+ *
853
+ * @example
854
+ * ```ts
855
+ * // Typical usage in Socket CLI commands
856
+ * const packagePaths = await getPackageFilesForScan(targets)
857
+ * const { validPaths } = validateFiles(packagePaths)
858
+ * await sdk.uploadManifestFiles(orgSlug, validPaths)
859
+ * ```
860
+ */
861
+ /*@__NO_SIDE_EFFECTS__*/
862
+ export declare function validateFiles(filepaths: string[] | readonly string[]): ValidateFilesResult;
815
863
  /**
816
864
  * Write JSON content to a file asynchronously with formatting.
817
865
  * Stringifies the value with configurable indentation and line endings.
package/dist/fs.js CHANGED
@@ -26,6 +26,8 @@ __export(fs_exports, {
26
26
  isDirEmptySync: () => isDirEmptySync,
27
27
  isDirSync: () => isDirSync,
28
28
  isSymLinkSync: () => isSymLinkSync,
29
+ normalizeEncoding: () => normalizeEncoding,
30
+ normalizeEncodingSlow: () => normalizeEncodingSlow,
29
31
  readDirNames: () => readDirNames,
30
32
  readDirNamesSync: () => readDirNamesSync,
31
33
  readFileBinary: () => readFileBinary,
@@ -52,7 +54,7 @@ var import_process = require("./constants/process");
52
54
  var import_arrays = require("./arrays");
53
55
  var import_del = require("./external/del");
54
56
  var import_globs = require("./globs");
55
- var import_json = require("./json");
57
+ var import_parse = require("./json/parse");
56
58
  var import_objects = require("./objects");
57
59
  var import_normalize = require("./paths/normalize");
58
60
  var import_rewire = require("./paths/rewire");
@@ -66,6 +68,26 @@ const defaultRemoveOptions = (0, import_objects.objectFreeze)({
66
68
  recursive: true,
67
69
  retryDelay: 200
68
70
  });
71
+ let _cachedAllowedDirs;
72
+ function getAllowedDirectories() {
73
+ if (_cachedAllowedDirs === void 0) {
74
+ const path = /* @__PURE__ */ getPath();
75
+ _cachedAllowedDirs = [
76
+ path.resolve((0, import_socket.getOsTmpDir)()),
77
+ path.resolve((0, import_socket.getSocketCacacheDir)()),
78
+ path.resolve((0, import_socket.getSocketUserDir)())
79
+ ];
80
+ }
81
+ return _cachedAllowedDirs;
82
+ }
83
+ let _buffer;
84
+ // @__NO_SIDE_EFFECTS__
85
+ function getBuffer() {
86
+ if (_buffer === void 0) {
87
+ _buffer = require("node:buffer");
88
+ }
89
+ return _buffer;
90
+ }
69
91
  let _fs;
70
92
  // @__NO_SIDE_EFFECTS__
71
93
  function getFs() {
@@ -201,6 +223,10 @@ function findUpSync(name, options) {
201
223
  }
202
224
  return void 0;
203
225
  }
226
+ function invalidatePathCache() {
227
+ _cachedAllowedDirs = void 0;
228
+ }
229
+ (0, import_rewire.registerCacheInvalidation)(invalidatePathCache);
204
230
  // @__NO_SIDE_EFFECTS__
205
231
  async function isDir(filepath) {
206
232
  return !!(await /* @__PURE__ */ safeStats(filepath))?.isDirectory();
@@ -250,20 +276,75 @@ function isSymLinkSync(filepath) {
250
276
  return false;
251
277
  }
252
278
  // @__NO_SIDE_EFFECTS__
253
- function validateFiles(filepaths) {
254
- const fs = /* @__PURE__ */ getFs();
255
- const validPaths = [];
256
- const invalidPaths = [];
257
- const { R_OK } = fs.constants;
258
- for (const filepath of filepaths) {
259
- try {
260
- fs.accessSync(filepath, R_OK);
261
- validPaths.push(filepath);
262
- } catch {
263
- invalidPaths.push(filepath);
279
+ function normalizeEncoding(enc) {
280
+ return enc == null || enc === "utf8" || enc === "utf-8" ? "utf8" : /* @__PURE__ */ normalizeEncodingSlow(enc);
281
+ }
282
+ // @__NO_SIDE_EFFECTS__
283
+ function normalizeEncodingSlow(enc) {
284
+ const { length } = enc;
285
+ if (length === 4) {
286
+ if (enc === "ucs2" || enc === "UCS2") {
287
+ return "utf16le";
288
+ }
289
+ if (enc.toLowerCase() === "ucs2") {
290
+ return "utf16le";
291
+ }
292
+ } else if (length === 3 && enc === "hex" || enc === "HEX" || enc.toLowerCase() === "hex") {
293
+ return "hex";
294
+ } else if (length === 5) {
295
+ if (enc === "ascii") {
296
+ return "ascii";
297
+ }
298
+ if (enc === "ucs-2") {
299
+ return "utf16le";
300
+ }
301
+ if (enc === "ASCII") {
302
+ return "ascii";
303
+ }
304
+ if (enc === "UCS-2") {
305
+ return "utf16le";
306
+ }
307
+ enc = enc.toLowerCase();
308
+ if (enc === "ascii") {
309
+ return "ascii";
310
+ }
311
+ if (enc === "ucs-2") {
312
+ return "utf16le";
313
+ }
314
+ } else if (length === 6) {
315
+ if (enc === "base64") {
316
+ return "base64";
317
+ }
318
+ if (enc === "latin1" || enc === "binary") {
319
+ return "latin1";
320
+ }
321
+ if (enc === "BASE64") {
322
+ return "base64";
323
+ }
324
+ if (enc === "LATIN1" || enc === "BINARY") {
325
+ return "latin1";
326
+ }
327
+ enc = enc.toLowerCase();
328
+ if (enc === "base64") {
329
+ return "base64";
330
+ }
331
+ if (enc === "latin1" || enc === "binary") {
332
+ return "latin1";
333
+ }
334
+ } else if (length === 7) {
335
+ if (enc === "utf16le" || enc === "UTF16LE" || enc.toLowerCase() === "utf16le") {
336
+ return "utf16le";
337
+ }
338
+ } else if (length === 8) {
339
+ if (enc === "utf-16le" || enc === "UTF-16LE" || enc.toLowerCase() === "utf-16le") {
340
+ return "utf16le";
341
+ }
342
+ } else if (length === 9) {
343
+ if (enc === "base64url" || enc === "BASE64URL" || enc.toLowerCase() === "base64url") {
344
+ return "base64url";
264
345
  }
265
346
  }
266
- return { __proto__: null, validPaths, invalidPaths };
347
+ return "utf8";
267
348
  }
268
349
  // @__NO_SIDE_EFFECTS__
269
350
  async function readDirNames(dirname, options) {
@@ -350,8 +431,8 @@ async function readJson(filepath, options) {
350
431
  try {
351
432
  content = await fs.promises.readFile(filepath, {
352
433
  __proto__: null,
353
- encoding: "utf8",
354
- ...fsOptions
434
+ ...fsOptions,
435
+ encoding: "utf8"
355
436
  });
356
437
  } catch (e) {
357
438
  if (shouldThrow) {
@@ -374,7 +455,7 @@ Check file permissions or run with appropriate access.`,
374
455
  }
375
456
  return void 0;
376
457
  }
377
- return (0, import_json.jsonParse)(content, {
458
+ return (0, import_parse.jsonParse)(content, {
378
459
  filepath: String(filepath),
379
460
  reviver,
380
461
  throws: shouldThrow
@@ -393,8 +474,8 @@ function readJsonSync(filepath, options) {
393
474
  try {
394
475
  content = fs.readFileSync(filepath, {
395
476
  __proto__: null,
396
- encoding: "utf8",
397
- ...fsOptions
477
+ ...fsOptions,
478
+ encoding: "utf8"
398
479
  });
399
480
  } catch (e) {
400
481
  if (shouldThrow) {
@@ -417,28 +498,12 @@ Check file permissions or run with appropriate access.`,
417
498
  }
418
499
  return void 0;
419
500
  }
420
- return (0, import_json.jsonParse)(content, {
501
+ return (0, import_parse.jsonParse)(content, {
421
502
  filepath: String(filepath),
422
503
  reviver,
423
504
  throws: shouldThrow
424
505
  });
425
506
  }
426
- let _cachedAllowedDirs;
427
- function getAllowedDirectories() {
428
- if (_cachedAllowedDirs === void 0) {
429
- const path = /* @__PURE__ */ getPath();
430
- _cachedAllowedDirs = [
431
- path.resolve((0, import_socket.getOsTmpDir)()),
432
- path.resolve((0, import_socket.getSocketCacacheDir)()),
433
- path.resolve((0, import_socket.getSocketUserDir)())
434
- ];
435
- }
436
- return _cachedAllowedDirs;
437
- }
438
- function invalidatePathCache() {
439
- _cachedAllowedDirs = void 0;
440
- }
441
- (0, import_rewire.registerCacheInvalidation)(invalidatePathCache);
442
507
  async function safeDelete(filepath, options) {
443
508
  const opts = { __proto__: null, ...options };
444
509
  const patterns = (0, import_arrays.isArray)(filepath) ? filepath.map(import_normalize.pathLikeToString) : [(0, import_normalize.pathLikeToString)(filepath)];
@@ -523,29 +588,54 @@ function safeMkdirSync(path, options) {
523
588
  }
524
589
  // @__NO_SIDE_EFFECTS__
525
590
  async function safeReadFile(filepath, options) {
526
- const opts = typeof options === "string" ? { encoding: options } : options;
591
+ const opts = typeof options === "string" ? { __proto__: null, encoding: options } : { __proto__: null, ...options };
592
+ const { defaultValue, ...rawReadOpts } = opts;
593
+ const readOpts = { __proto__: null, ...rawReadOpts };
594
+ const shouldReturnBuffer = readOpts.encoding === null;
595
+ const encoding = shouldReturnBuffer ? null : /* @__PURE__ */ normalizeEncoding(readOpts.encoding);
527
596
  const fs = /* @__PURE__ */ getFs();
528
597
  try {
529
598
  return await fs.promises.readFile(filepath, {
599
+ __proto__: null,
530
600
  signal: abortSignal,
531
- ...opts
601
+ ...readOpts,
602
+ encoding
532
603
  });
533
604
  } catch {
534
605
  }
535
- return void 0;
606
+ if (defaultValue === void 0) {
607
+ return void 0;
608
+ }
609
+ if (shouldReturnBuffer) {
610
+ const { Buffer: Buffer2 } = /* @__PURE__ */ getBuffer();
611
+ return Buffer2.isBuffer(defaultValue) ? defaultValue : void 0;
612
+ }
613
+ return typeof defaultValue === "string" ? defaultValue : String(defaultValue);
536
614
  }
537
615
  // @__NO_SIDE_EFFECTS__
538
616
  function safeReadFileSync(filepath, options) {
539
- const opts = typeof options === "string" ? { encoding: options } : options;
617
+ const opts = typeof options === "string" ? { __proto__: null, encoding: options } : { __proto__: null, ...options };
618
+ const { defaultValue, ...rawReadOpts } = opts;
619
+ const readOpts = { __proto__: null, ...rawReadOpts };
620
+ const shouldReturnBuffer = readOpts.encoding === null;
621
+ const encoding = shouldReturnBuffer ? null : /* @__PURE__ */ normalizeEncoding(readOpts.encoding);
540
622
  const fs = /* @__PURE__ */ getFs();
541
623
  try {
542
624
  return fs.readFileSync(filepath, {
543
625
  __proto__: null,
544
- ...opts
626
+ ...readOpts,
627
+ encoding
545
628
  });
546
629
  } catch {
547
630
  }
548
- return void 0;
631
+ if (defaultValue === void 0) {
632
+ return void 0;
633
+ }
634
+ if (shouldReturnBuffer) {
635
+ const { Buffer: Buffer2 } = /* @__PURE__ */ getBuffer();
636
+ return Buffer2.isBuffer(defaultValue) ? defaultValue : void 0;
637
+ }
638
+ return typeof defaultValue === "string" ? defaultValue : String(defaultValue);
549
639
  }
550
640
  // @__NO_SIDE_EFFECTS__
551
641
  async function safeStats(filepath) {
@@ -589,6 +679,22 @@ function uniqueSync(filepath) {
589
679
  } while (fs.existsSync(uniquePath));
590
680
  return (0, import_normalize.normalizePath)(uniquePath);
591
681
  }
682
+ // @__NO_SIDE_EFFECTS__
683
+ function validateFiles(filepaths) {
684
+ const fs = /* @__PURE__ */ getFs();
685
+ const validPaths = [];
686
+ const invalidPaths = [];
687
+ const { R_OK } = fs.constants;
688
+ for (const filepath of filepaths) {
689
+ try {
690
+ fs.accessSync(filepath, R_OK);
691
+ validPaths.push(filepath);
692
+ } catch {
693
+ invalidPaths.push(filepath);
694
+ }
695
+ }
696
+ return { __proto__: null, validPaths, invalidPaths };
697
+ }
592
698
  async function writeJson(filepath, jsonContent, options) {
593
699
  const opts = typeof options === "string" ? { encoding: options } : options;
594
700
  const { EOL, finalEOL, replacer, spaces, ...fsOptions } = {
@@ -638,6 +744,8 @@ function writeJsonSync(filepath, jsonContent, options) {
638
744
  isDirEmptySync,
639
745
  isDirSync,
640
746
  isSymLinkSync,
747
+ normalizeEncoding,
748
+ normalizeEncodingSlow,
641
749
  readDirNames,
642
750
  readDirNamesSync,
643
751
  readFileBinary,
@@ -0,0 +1,16 @@
1
+ import type { EditableJsonConstructor } from './types';
2
+ /**
3
+ * Get the EditableJson class for JSON file manipulation.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { getEditableJsonClass } from '@socketsecurity/lib/json'
8
+ *
9
+ * const EditableJson = getEditableJsonClass<MyConfigType>()
10
+ * const config = await EditableJson.load('./config.json')
11
+ * config.update({ someField: 'newValue' })
12
+ * await config.save({ sort: true })
13
+ * ```
14
+ */
15
+ /*@__NO_SIDE_EFFECTS__*/
16
+ export declare function getEditableJsonClass<T = Record<string, unknown>>(): EditableJsonConstructor<T>;