@metamask-previews/utils 11.12.1-preview-9962b7e

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 (112) hide show
  1. package/CHANGELOG.md +584 -0
  2. package/LICENSE +15 -0
  3. package/README.md +106 -0
  4. package/dist/assert.d.ts +61 -0
  5. package/dist/assert.d.ts.map +1 -0
  6. package/dist/assert.js +115 -0
  7. package/dist/assert.js.map +1 -0
  8. package/dist/base64.d.ts +25 -0
  9. package/dist/base64.d.ts.map +1 -0
  10. package/dist/base64.js +30 -0
  11. package/dist/base64.js.map +1 -0
  12. package/dist/bytes.d.ts +198 -0
  13. package/dist/bytes.d.ts.map +1 -0
  14. package/dist/bytes.js +406 -0
  15. package/dist/bytes.js.map +1 -0
  16. package/dist/caip-types.d.ts +294 -0
  17. package/dist/caip-types.d.ts.map +1 -0
  18. package/dist/caip-types.js +369 -0
  19. package/dist/caip-types.js.map +1 -0
  20. package/dist/checksum.d.ts +2 -0
  21. package/dist/checksum.d.ts.map +1 -0
  22. package/dist/checksum.js +4 -0
  23. package/dist/checksum.js.map +1 -0
  24. package/dist/coercers.d.ts +97 -0
  25. package/dist/coercers.d.ts.map +1 -0
  26. package/dist/coercers.js +159 -0
  27. package/dist/coercers.js.map +1 -0
  28. package/dist/collections.d.ts +39 -0
  29. package/dist/collections.d.ts.map +1 -0
  30. package/dist/collections.js +105 -0
  31. package/dist/collections.js.map +1 -0
  32. package/dist/encryption-types.d.ts +7 -0
  33. package/dist/encryption-types.d.ts.map +1 -0
  34. package/dist/encryption-types.js +2 -0
  35. package/dist/encryption-types.js.map +1 -0
  36. package/dist/errors.d.ts +68 -0
  37. package/dist/errors.d.ts.map +1 -0
  38. package/dist/errors.js +121 -0
  39. package/dist/errors.js.map +1 -0
  40. package/dist/fs.d.ts +133 -0
  41. package/dist/fs.d.ts.map +1 -0
  42. package/dist/fs.js +210 -0
  43. package/dist/fs.js.map +1 -0
  44. package/dist/hashing.d.ts +28 -0
  45. package/dist/hashing.d.ts.map +1 -0
  46. package/dist/hashing.js +59 -0
  47. package/dist/hashing.js.map +1 -0
  48. package/dist/hex.d.ts +117 -0
  49. package/dist/hex.d.ts.map +1 -0
  50. package/dist/hex.js +174 -0
  51. package/dist/hex.js.map +1 -0
  52. package/dist/index.d.ts +26 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +21 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/json.d.ts +398 -0
  57. package/dist/json.d.ts.map +1 -0
  58. package/dist/json.js +402 -0
  59. package/dist/json.js.map +1 -0
  60. package/dist/keyring.d.ts +243 -0
  61. package/dist/keyring.d.ts.map +1 -0
  62. package/dist/keyring.js +2 -0
  63. package/dist/keyring.js.map +1 -0
  64. package/dist/logging.d.ts +30 -0
  65. package/dist/logging.d.ts.map +1 -0
  66. package/dist/logging.js +35 -0
  67. package/dist/logging.js.map +1 -0
  68. package/dist/misc.d.ts +127 -0
  69. package/dist/misc.d.ts.map +1 -0
  70. package/dist/misc.js +142 -0
  71. package/dist/misc.js.map +1 -0
  72. package/dist/mnemonic.d.ts +14 -0
  73. package/dist/mnemonic.d.ts.map +1 -0
  74. package/dist/mnemonic.js +25 -0
  75. package/dist/mnemonic.js.map +1 -0
  76. package/dist/node.d.ts +3 -0
  77. package/dist/node.d.ts.map +1 -0
  78. package/dist/node.js +3 -0
  79. package/dist/node.js.map +1 -0
  80. package/dist/number.d.ts +74 -0
  81. package/dist/number.d.ts.map +1 -0
  82. package/dist/number.js +95 -0
  83. package/dist/number.js.map +1 -0
  84. package/dist/opaque.d.ts +6 -0
  85. package/dist/opaque.d.ts.map +1 -0
  86. package/dist/opaque.js +2 -0
  87. package/dist/opaque.js.map +1 -0
  88. package/dist/promise.d.ts +45 -0
  89. package/dist/promise.d.ts.map +1 -0
  90. package/dist/promise.js +40 -0
  91. package/dist/promise.js.map +1 -0
  92. package/dist/superstruct.d.ts +20 -0
  93. package/dist/superstruct.d.ts.map +1 -0
  94. package/dist/superstruct.js +24 -0
  95. package/dist/superstruct.js.map +1 -0
  96. package/dist/time.d.ts +49 -0
  97. package/dist/time.d.ts.map +1 -0
  98. package/dist/time.js +62 -0
  99. package/dist/time.js.map +1 -0
  100. package/dist/transaction-types.d.ts +117 -0
  101. package/dist/transaction-types.d.ts.map +1 -0
  102. package/dist/transaction-types.js +2 -0
  103. package/dist/transaction-types.js.map +1 -0
  104. package/dist/unitsConversion.d.ts +80 -0
  105. package/dist/unitsConversion.d.ts.map +1 -0
  106. package/dist/unitsConversion.js +209 -0
  107. package/dist/unitsConversion.js.map +1 -0
  108. package/dist/versions.d.ts +101 -0
  109. package/dist/versions.d.ts.map +1 -0
  110. package/dist/versions.js +85 -0
  111. package/dist/versions.js.map +1 -0
  112. package/package.json +122 -0
package/dist/errors.js ADDED
@@ -0,0 +1,121 @@
1
+ import { ErrorWithCause } from 'pony-cause';
2
+ import { isNullOrUndefined, isObject } from './misc.js';
3
+ /**
4
+ * Type guard for determining whether the given value is an instance of Error.
5
+ * For errors generated via `fs.promises`, `error instanceof Error` won't work,
6
+ * so we have to come up with another way of testing.
7
+ *
8
+ * @param error - The object to check.
9
+ * @returns A boolean.
10
+ */
11
+ function isError(error) {
12
+ return (error instanceof Error ||
13
+ (isObject(error) && error.constructor.name === 'Error'));
14
+ }
15
+ /**
16
+ * Type guard for determining whether the given value is an error object with a
17
+ * `code` property such as the type of error that Node throws for filesystem
18
+ * operations, etc.
19
+ *
20
+ * @param error - The object to check.
21
+ * @returns A boolean.
22
+ */
23
+ export function isErrorWithCode(error) {
24
+ return typeof error === 'object' && error !== null && 'code' in error;
25
+ }
26
+ /**
27
+ * Type guard for determining whether the given value is an error object with a
28
+ * `message` property, such as an instance of Error.
29
+ *
30
+ * @param error - The object to check.
31
+ * @returns A boolean.
32
+ */
33
+ export function isErrorWithMessage(error) {
34
+ return typeof error === 'object' && error !== null && 'message' in error;
35
+ }
36
+ /**
37
+ * Type guard for determining whether the given value is an error object with a
38
+ * `stack` property, such as an instance of Error.
39
+ *
40
+ * @param error - The object to check.
41
+ * @returns A boolean.
42
+ */
43
+ export function isErrorWithStack(error) {
44
+ return typeof error === 'object' && error !== null && 'stack' in error;
45
+ }
46
+ /**
47
+ * Attempts to obtain the message from a possible error object, defaulting to an
48
+ * empty string if it is impossible to do so.
49
+ *
50
+ * @param error - The possible error to get the message from.
51
+ * @returns The message if `error` is an object with a `message` property;
52
+ * the string version of `error` if it is not `undefined` or `null`; otherwise
53
+ * an empty string.
54
+ */
55
+ export function getErrorMessage(error) {
56
+ if (isErrorWithMessage(error) && typeof error.message === 'string') {
57
+ return error.message;
58
+ }
59
+ if (isNullOrUndefined(error)) {
60
+ return '';
61
+ }
62
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string -- Stringifying an arbitrary value is the documented fallback here, so `[object Object]` is an accepted result rather than a mistake.
63
+ return String(error);
64
+ }
65
+ /**
66
+ * Builds a new error object, linking it to the original error via the `cause`
67
+ * property if it is an Error.
68
+ *
69
+ * This function is useful to reframe error messages in general, but is
70
+ * _critical_ when interacting with any of Node's filesystem functions as
71
+ * provided via `fs.promises`, because these do not produce stack traces in the
72
+ * case of an I/O error (see <https://github.com/nodejs/node/issues/30944>).
73
+ *
74
+ * @param originalError - The error to be wrapped (something throwable).
75
+ * @param message - The desired message of the new error.
76
+ * @returns A new error object.
77
+ */
78
+ export function wrapError(originalError, message) {
79
+ if (isError(originalError)) {
80
+ let error;
81
+ if (Error.length === 2) {
82
+ // for some reason `tsserver` is not complaining that the
83
+ // Error constructor doesn't support a second argument in the editor,
84
+ // but `tsc` does. Error causes are not supported by our current tsc target (ES2020, we need ES2022 to make this work)
85
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
86
+ // @ts-ignore
87
+ error = new Error(message, { cause: originalError });
88
+ }
89
+ else {
90
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
91
+ // @ts-ignore
92
+ error = new ErrorWithCause(message, { cause: originalError });
93
+ }
94
+ if (isErrorWithCode(originalError)) {
95
+ error.code = originalError.code;
96
+ }
97
+ return error;
98
+ }
99
+ if (message.length > 0) {
100
+ return new Error(`${String(originalError)}: ${message}`);
101
+ }
102
+ return new Error(String(originalError));
103
+ }
104
+ /**
105
+ * Ensures we have a proper Error object.
106
+ * If the input is already an Error, returns it unchanged.
107
+ * Otherwise, converts to an Error with an appropriate message and preserves
108
+ * the original value as the cause.
109
+ *
110
+ * @param error - The caught error (could be Error, string, or unknown).
111
+ * @returns A proper Error instance.
112
+ */
113
+ export function ensureError(error) {
114
+ if (isError(error)) {
115
+ return error;
116
+ }
117
+ const newError = new Error('Unknown error');
118
+ newError.cause = error;
119
+ return newError;
120
+ }
121
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAExD;;;;;;;GAOG;AACH,SAAS,OAAO,CAAC,KAAc;IAC7B,OAAO,CACL,KAAK,YAAY,KAAK;QACtB,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,OAAO,CAAC,CACxD,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,CAAC;AACxE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAc;IAEd,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,SAAS,IAAI,KAAK,CAAC;AAC3E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,CAAC;AACzE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,kBAAkB,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACnE,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IAED,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,sMAAsM;IACtM,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,SAAS,CACvB,aAAwB,EACxB,OAAe;IAEf,IAAI,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QAC3B,IAAI,KAAgC,CAAC;QACrC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,yDAAyD;YACzD,qEAAqE;YACrE,sHAAsH;YACtH,6DAA6D;YAC7D,aAAa;YACb,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;QACvD,CAAC;aAAM,CAAC;YACN,6DAA6D;YAC7D,aAAa;YACb,KAAK,GAAG,IAAI,cAAc,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;QAChE,CAAC;QAED,IAAI,eAAe,CAAC,aAAa,CAAC,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC;QAClC,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,IAAI,KAAK,CAAC,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAgC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACzE,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;IACvB,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import { ErrorWithCause } from 'pony-cause';\n\nimport { isNullOrUndefined, isObject } from './misc.js';\n\n/**\n * Type guard for determining whether the given value is an instance of Error.\n * For errors generated via `fs.promises`, `error instanceof Error` won't work,\n * so we have to come up with another way of testing.\n *\n * @param error - The object to check.\n * @returns A boolean.\n */\nfunction isError(error: unknown): error is Error {\n return (\n error instanceof Error ||\n (isObject(error) && error.constructor.name === 'Error')\n );\n}\n\n/**\n * Type guard for determining whether the given value is an error object with a\n * `code` property such as the type of error that Node throws for filesystem\n * operations, etc.\n *\n * @param error - The object to check.\n * @returns A boolean.\n */\nexport function isErrorWithCode(error: unknown): error is { code: string } {\n return typeof error === 'object' && error !== null && 'code' in error;\n}\n\n/**\n * Type guard for determining whether the given value is an error object with a\n * `message` property, such as an instance of Error.\n *\n * @param error - The object to check.\n * @returns A boolean.\n */\nexport function isErrorWithMessage(\n error: unknown,\n): error is { message: string } {\n return typeof error === 'object' && error !== null && 'message' in error;\n}\n\n/**\n * Type guard for determining whether the given value is an error object with a\n * `stack` property, such as an instance of Error.\n *\n * @param error - The object to check.\n * @returns A boolean.\n */\nexport function isErrorWithStack(error: unknown): error is { stack: string } {\n return typeof error === 'object' && error !== null && 'stack' in error;\n}\n\n/**\n * Attempts to obtain the message from a possible error object, defaulting to an\n * empty string if it is impossible to do so.\n *\n * @param error - The possible error to get the message from.\n * @returns The message if `error` is an object with a `message` property;\n * the string version of `error` if it is not `undefined` or `null`; otherwise\n * an empty string.\n */\nexport function getErrorMessage(error: unknown): string {\n if (isErrorWithMessage(error) && typeof error.message === 'string') {\n return error.message;\n }\n\n if (isNullOrUndefined(error)) {\n return '';\n }\n\n // eslint-disable-next-line @typescript-eslint/no-base-to-string -- Stringifying an arbitrary value is the documented fallback here, so `[object Object]` is an accepted result rather than a mistake.\n return String(error);\n}\n\n/**\n * Builds a new error object, linking it to the original error via the `cause`\n * property if it is an Error.\n *\n * This function is useful to reframe error messages in general, but is\n * _critical_ when interacting with any of Node's filesystem functions as\n * provided via `fs.promises`, because these do not produce stack traces in the\n * case of an I/O error (see <https://github.com/nodejs/node/issues/30944>).\n *\n * @param originalError - The error to be wrapped (something throwable).\n * @param message - The desired message of the new error.\n * @returns A new error object.\n */\nexport function wrapError<Throwable>(\n originalError: Throwable,\n message: string,\n): Error & { code?: string } {\n if (isError(originalError)) {\n let error: Error & { code?: string };\n if (Error.length === 2) {\n // for some reason `tsserver` is not complaining that the\n // Error constructor doesn't support a second argument in the editor,\n // but `tsc` does. Error causes are not supported by our current tsc target (ES2020, we need ES2022 to make this work)\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n error = new Error(message, { cause: originalError });\n } else {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n error = new ErrorWithCause(message, { cause: originalError });\n }\n\n if (isErrorWithCode(originalError)) {\n error.code = originalError.code;\n }\n\n return error;\n }\n\n if (message.length > 0) {\n return new Error(`${String(originalError)}: ${message}`);\n }\n\n return new Error(String(originalError));\n}\n\n/**\n * Ensures we have a proper Error object.\n * If the input is already an Error, returns it unchanged.\n * Otherwise, converts to an Error with an appropriate message and preserves\n * the original value as the cause.\n *\n * @param error - The caught error (could be Error, string, or unknown).\n * @returns A proper Error instance.\n */\nexport function ensureError(error: unknown): Error {\n if (isError(error)) {\n return error;\n }\n\n const newError: Error & { cause?: unknown } = new Error('Unknown error');\n newError.cause = error;\n return newError;\n}\n"]}
package/dist/fs.d.ts ADDED
@@ -0,0 +1,133 @@
1
+ import type { Json } from './json.js';
2
+ /**
3
+ * Information about the file sandbox provided to tests that need temporary
4
+ * access to the filesystem.
5
+ */
6
+ export type FileSandbox = {
7
+ directoryPath: string;
8
+ withinSandbox: (test: (args: {
9
+ directoryPath: string;
10
+ }) => Promise<void>) => Promise<void>;
11
+ };
12
+ /**
13
+ * Read the file at the given path, assuming its content is encoded as UTF-8.
14
+ *
15
+ * @param filePath - The path to the file.
16
+ * @returns The content of the file.
17
+ * @throws An error with a stack trace if reading fails in any way.
18
+ */
19
+ export declare function readFile(filePath: string): Promise<string>;
20
+ /**
21
+ * Write content to the file at the given path, creating the directory structure
22
+ * for the file automatically if necessary.
23
+ *
24
+ * @param filePath - The path to the file.
25
+ * @param content - The new content of the file.
26
+ * @throws An error with a stack trace if writing fails in any way.
27
+ */
28
+ export declare function writeFile(filePath: string, content: string): Promise<void>;
29
+ /**
30
+ * Read the assumed JSON file at the given path, attempts to parse it, and
31
+ * get the resulting object. Supports a custom parser (in case you want to
32
+ * use the [JSON5](https://www.npmjs.com/package/json5) package instead).
33
+ *
34
+ * @param filePath - The path segments pointing to the JSON file. Will be passed
35
+ * to path.join().
36
+ * @param options - Options to this function.
37
+ * @param options.parser - The parser object to use. Defaults to `JSON`.
38
+ * @param options.parser.parse - A function that parses JSON data.
39
+ * @returns The object corresponding to the parsed JSON file, typed against the
40
+ * struct.
41
+ * @throws An error with a stack trace if reading fails in any way, or if the
42
+ * parsed value is not a plain object.
43
+ */
44
+ export declare function readJsonFile<Value extends Json>(filePath: string, { parser, }?: {
45
+ parser?: {
46
+ parse: (text: Parameters<typeof JSON.parse>[0]) => ReturnType<typeof JSON.parse>;
47
+ };
48
+ }): Promise<Value>;
49
+ /**
50
+ * Attempt to write the given JSON-like value to the file at the given path,
51
+ * creating the directory structure for the file automatically if necessary.
52
+ * Adds a newline to the end of the file. Supports a custom parser (in case you
53
+ * want to use the [JSON5](https://www.npmjs.com/package/json5) package
54
+ * instead).
55
+ *
56
+ * @param filePath - The path to write the JSON file to, including the file
57
+ * itself.
58
+ * @param jsonValue - The JSON-like value to write to the file. Make sure that
59
+ * JSON.stringify can handle it.
60
+ * @param options - The options to this function.
61
+ * @param options.prettify - Whether to format the JSON as it is turned into a
62
+ * string such that it is broken up into separate lines (using 2 spaces as
63
+ * indentation).
64
+ * @param options.stringifier - The stringifier to use. Defaults to `JSON`.
65
+ * @param options.stringifier.stringify - A function that stringifies JSON.
66
+ * @returns The object corresponding to the parsed JSON file, typed against the
67
+ * struct.
68
+ * @throws An error with a stack trace if writing fails in any way.
69
+ */
70
+ export declare function writeJsonFile(filePath: string, jsonValue: Json, { stringifier, prettify, }?: {
71
+ stringifier?: {
72
+ stringify: typeof JSON.stringify;
73
+ };
74
+ prettify?: boolean;
75
+ }): Promise<void>;
76
+ /**
77
+ * Test the given path to determine whether it represents a file.
78
+ *
79
+ * @param filePath - The path to a (supposed) file on the filesystem.
80
+ * @returns A promise for true if the file exists or false otherwise.
81
+ * @throws An error with a stack trace if reading fails in any way.
82
+ */
83
+ export declare function fileExists(filePath: string): Promise<boolean>;
84
+ /**
85
+ * Test the given path to determine whether it represents a directory.
86
+ *
87
+ * @param directoryPath - The path to a (supposed) directory on the filesystem.
88
+ * @returns A promise for true if the file exists or false otherwise.
89
+ * @throws An error with a stack trace if reading fails in any way.
90
+ */
91
+ export declare function directoryExists(directoryPath: string): Promise<boolean>;
92
+ /**
93
+ * Create the given directory along with any directories leading up to the
94
+ * directory, or do nothing if the directory already exists.
95
+ *
96
+ * @param directoryPath - The path to the desired directory.
97
+ * @throws An error with a stack trace if reading fails in any way.
98
+ */
99
+ export declare function ensureDirectoryStructureExists(directoryPath: string): Promise<void>;
100
+ /**
101
+ * Remove the given file or directory if it exists, or do nothing if it does
102
+ * not.
103
+ *
104
+ * @param entryPath - The path to the file or directory.
105
+ * @throws An error with a stack trace if removal fails in any way.
106
+ */
107
+ export declare function forceRemove(entryPath: string): Promise<void>;
108
+ /**
109
+ * Construct a sandbox object which can be used in tests that need temporary
110
+ * access to the filesystem.
111
+ *
112
+ * @param projectName - The name of the project.
113
+ * @returns The sandbox object. This contains a `withinSandbox` function which
114
+ * can be used in tests (see example).
115
+ * @example
116
+ * ```typescript
117
+ * const { withinSandbox } = createSandbox('utils');
118
+ *
119
+ * // ... later ...
120
+ *
121
+ * it('does something with the filesystem', async () => {
122
+ * await withinSandbox(async ({ directoryPath }) => {
123
+ * await fs.promises.writeFile(
124
+ * path.join(directoryPath, 'some-file'),
125
+ * 'some content',
126
+ * 'utf8'
127
+ * );
128
+ * })
129
+ * });
130
+ * ```
131
+ */
132
+ export declare function createSandbox(projectName: string): FileSandbox;
133
+ //# sourceMappingURL=fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,CACb,IAAI,EAAE,CAAC,IAAI,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,KACrD,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMhE;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,YAAY,CAAC,KAAK,SAAS,IAAI,EACnD,QAAQ,EAAE,MAAM,EAChB,EACE,MAAa,GACd,GAAE;IACD,MAAM,CAAC,EAAE;QACP,KAAK,EAAE,CACL,IAAI,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KACnC,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC;KACpC,CAAC;CACE,GACL,OAAO,CAAC,KAAK,CAAC,CAOhB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,IAAI,EACf,EACE,WAAkB,EAClB,QAAgB,GACjB,GAAE;IACD,WAAW,CAAC,EAAE;QACZ,SAAS,EAAE,OAAO,IAAI,CAAC,SAAS,CAAC;KAClC,CAAC;IACF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACf,GACL,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAWnE;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAc7E;AAED;;;;;;GAMG;AACH,wBAAsB,8BAA8B,CAClD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASlE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAqB9D"}
package/dist/fs.js ADDED
@@ -0,0 +1,210 @@
1
+ // This file is intended to be used only in a Node.js context.
2
+ /* eslint-disable import-x/no-nodejs-modules */
3
+ import fs from 'fs';
4
+ import os from 'os';
5
+ import path from 'path';
6
+ import * as uuid from 'uuid';
7
+ import { isErrorWithCode, wrapError } from './errors.js';
8
+ /**
9
+ * Read the file at the given path, assuming its content is encoded as UTF-8.
10
+ *
11
+ * @param filePath - The path to the file.
12
+ * @returns The content of the file.
13
+ * @throws An error with a stack trace if reading fails in any way.
14
+ */
15
+ export async function readFile(filePath) {
16
+ try {
17
+ return await fs.promises.readFile(filePath, 'utf8');
18
+ }
19
+ catch (error) {
20
+ throw wrapError(error, `Could not read file '${filePath}'`);
21
+ }
22
+ }
23
+ /**
24
+ * Write content to the file at the given path, creating the directory structure
25
+ * for the file automatically if necessary.
26
+ *
27
+ * @param filePath - The path to the file.
28
+ * @param content - The new content of the file.
29
+ * @throws An error with a stack trace if writing fails in any way.
30
+ */
31
+ export async function writeFile(filePath, content) {
32
+ try {
33
+ await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
34
+ await fs.promises.writeFile(filePath, content);
35
+ }
36
+ catch (error) {
37
+ throw wrapError(error, `Could not write file '${filePath}'`);
38
+ }
39
+ }
40
+ /**
41
+ * Read the assumed JSON file at the given path, attempts to parse it, and
42
+ * get the resulting object. Supports a custom parser (in case you want to
43
+ * use the [JSON5](https://www.npmjs.com/package/json5) package instead).
44
+ *
45
+ * @param filePath - The path segments pointing to the JSON file. Will be passed
46
+ * to path.join().
47
+ * @param options - Options to this function.
48
+ * @param options.parser - The parser object to use. Defaults to `JSON`.
49
+ * @param options.parser.parse - A function that parses JSON data.
50
+ * @returns The object corresponding to the parsed JSON file, typed against the
51
+ * struct.
52
+ * @throws An error with a stack trace if reading fails in any way, or if the
53
+ * parsed value is not a plain object.
54
+ */
55
+ export async function readJsonFile(filePath, { parser = JSON, } = {}) {
56
+ try {
57
+ const content = await fs.promises.readFile(filePath, 'utf8');
58
+ return parser.parse(content);
59
+ }
60
+ catch (error) {
61
+ throw wrapError(error, `Could not read JSON file '${filePath}'`);
62
+ }
63
+ }
64
+ /**
65
+ * Attempt to write the given JSON-like value to the file at the given path,
66
+ * creating the directory structure for the file automatically if necessary.
67
+ * Adds a newline to the end of the file. Supports a custom parser (in case you
68
+ * want to use the [JSON5](https://www.npmjs.com/package/json5) package
69
+ * instead).
70
+ *
71
+ * @param filePath - The path to write the JSON file to, including the file
72
+ * itself.
73
+ * @param jsonValue - The JSON-like value to write to the file. Make sure that
74
+ * JSON.stringify can handle it.
75
+ * @param options - The options to this function.
76
+ * @param options.prettify - Whether to format the JSON as it is turned into a
77
+ * string such that it is broken up into separate lines (using 2 spaces as
78
+ * indentation).
79
+ * @param options.stringifier - The stringifier to use. Defaults to `JSON`.
80
+ * @param options.stringifier.stringify - A function that stringifies JSON.
81
+ * @returns The object corresponding to the parsed JSON file, typed against the
82
+ * struct.
83
+ * @throws An error with a stack trace if writing fails in any way.
84
+ */
85
+ export async function writeJsonFile(filePath, jsonValue, { stringifier = JSON, prettify = false, } = {}) {
86
+ try {
87
+ await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
88
+ const json = prettify
89
+ ? stringifier.stringify(jsonValue, null, ' ')
90
+ : stringifier.stringify(jsonValue);
91
+ await fs.promises.writeFile(filePath, json);
92
+ }
93
+ catch (error) {
94
+ throw wrapError(error, `Could not write JSON file '${filePath}'`);
95
+ }
96
+ }
97
+ /**
98
+ * Test the given path to determine whether it represents a file.
99
+ *
100
+ * @param filePath - The path to a (supposed) file on the filesystem.
101
+ * @returns A promise for true if the file exists or false otherwise.
102
+ * @throws An error with a stack trace if reading fails in any way.
103
+ */
104
+ export async function fileExists(filePath) {
105
+ try {
106
+ const stats = await fs.promises.stat(filePath);
107
+ return stats.isFile();
108
+ }
109
+ catch (error) {
110
+ if (isErrorWithCode(error) && error.code === 'ENOENT') {
111
+ return false;
112
+ }
113
+ throw wrapError(error, `Could not determine if file exists '${filePath}'`);
114
+ }
115
+ }
116
+ /**
117
+ * Test the given path to determine whether it represents a directory.
118
+ *
119
+ * @param directoryPath - The path to a (supposed) directory on the filesystem.
120
+ * @returns A promise for true if the file exists or false otherwise.
121
+ * @throws An error with a stack trace if reading fails in any way.
122
+ */
123
+ export async function directoryExists(directoryPath) {
124
+ try {
125
+ const stats = await fs.promises.stat(directoryPath);
126
+ return stats.isDirectory();
127
+ }
128
+ catch (error) {
129
+ if (isErrorWithCode(error) && error.code === 'ENOENT') {
130
+ return false;
131
+ }
132
+ throw wrapError(error, `Could not determine if directory exists '${directoryPath}'`);
133
+ }
134
+ }
135
+ /**
136
+ * Create the given directory along with any directories leading up to the
137
+ * directory, or do nothing if the directory already exists.
138
+ *
139
+ * @param directoryPath - The path to the desired directory.
140
+ * @throws An error with a stack trace if reading fails in any way.
141
+ */
142
+ export async function ensureDirectoryStructureExists(directoryPath) {
143
+ try {
144
+ await fs.promises.mkdir(directoryPath, { recursive: true });
145
+ }
146
+ catch (error) {
147
+ throw wrapError(error, `Could not create directory structure '${directoryPath}'`);
148
+ }
149
+ }
150
+ /**
151
+ * Remove the given file or directory if it exists, or do nothing if it does
152
+ * not.
153
+ *
154
+ * @param entryPath - The path to the file or directory.
155
+ * @throws An error with a stack trace if removal fails in any way.
156
+ */
157
+ export async function forceRemove(entryPath) {
158
+ try {
159
+ return await fs.promises.rm(entryPath, {
160
+ recursive: true,
161
+ force: true,
162
+ });
163
+ }
164
+ catch (error) {
165
+ throw wrapError(error, `Could not remove file or directory '${entryPath}'`);
166
+ }
167
+ }
168
+ /**
169
+ * Construct a sandbox object which can be used in tests that need temporary
170
+ * access to the filesystem.
171
+ *
172
+ * @param projectName - The name of the project.
173
+ * @returns The sandbox object. This contains a `withinSandbox` function which
174
+ * can be used in tests (see example).
175
+ * @example
176
+ * ```typescript
177
+ * const { withinSandbox } = createSandbox('utils');
178
+ *
179
+ * // ... later ...
180
+ *
181
+ * it('does something with the filesystem', async () => {
182
+ * await withinSandbox(async ({ directoryPath }) => {
183
+ * await fs.promises.writeFile(
184
+ * path.join(directoryPath, 'some-file'),
185
+ * 'some content',
186
+ * 'utf8'
187
+ * );
188
+ * })
189
+ * });
190
+ * ```
191
+ */
192
+ export function createSandbox(projectName) {
193
+ const directoryPath = path.join(os.tmpdir(), projectName, uuid.v4());
194
+ return {
195
+ directoryPath,
196
+ async withinSandbox(test) {
197
+ if (await directoryExists(directoryPath)) {
198
+ throw new Error(`${directoryPath} already exists. Cannot continue.`);
199
+ }
200
+ await ensureDirectoryStructureExists(directoryPath);
201
+ try {
202
+ await test({ directoryPath });
203
+ }
204
+ finally {
205
+ await forceRemove(directoryPath);
206
+ }
207
+ },
208
+ };
209
+ }
210
+ //# sourceMappingURL=fs.js.map
package/dist/fs.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"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","sourcesContent":["// This file is intended to be used only in a Node.js context.\n/* eslint-disable import-x/no-nodejs-modules */\n\nimport fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport * as uuid from 'uuid';\n\nimport { isErrorWithCode, wrapError } from './errors.js';\nimport type { Json } from './json.js';\n\n/**\n * Information about the file sandbox provided to tests that need temporary\n * access to the filesystem.\n */\nexport type FileSandbox = {\n directoryPath: string;\n withinSandbox: (\n test: (args: { directoryPath: string }) => Promise<void>,\n ) => Promise<void>;\n};\n\n/**\n * Read the file at the given path, assuming its content is encoded as UTF-8.\n *\n * @param filePath - The path to the file.\n * @returns The content of the file.\n * @throws An error with a stack trace if reading fails in any way.\n */\nexport async function readFile(filePath: string): Promise<string> {\n try {\n return await fs.promises.readFile(filePath, 'utf8');\n } catch (error) {\n throw wrapError(error, `Could not read file '${filePath}'`);\n }\n}\n\n/**\n * Write content to the file at the given path, creating the directory structure\n * for the file automatically if necessary.\n *\n * @param filePath - The path to the file.\n * @param content - The new content of the file.\n * @throws An error with a stack trace if writing fails in any way.\n */\nexport async function writeFile(\n filePath: string,\n content: string,\n): Promise<void> {\n try {\n await fs.promises.mkdir(path.dirname(filePath), { recursive: true });\n await fs.promises.writeFile(filePath, content);\n } catch (error) {\n throw wrapError(error, `Could not write file '${filePath}'`);\n }\n}\n\n/**\n * Read the assumed JSON file at the given path, attempts to parse it, and\n * get the resulting object. Supports a custom parser (in case you want to\n * use the [JSON5](https://www.npmjs.com/package/json5) package instead).\n *\n * @param filePath - The path segments pointing to the JSON file. Will be passed\n * to path.join().\n * @param options - Options to this function.\n * @param options.parser - The parser object to use. Defaults to `JSON`.\n * @param options.parser.parse - A function that parses JSON data.\n * @returns The object corresponding to the parsed JSON file, typed against the\n * struct.\n * @throws An error with a stack trace if reading fails in any way, or if the\n * parsed value is not a plain object.\n */\nexport async function readJsonFile<Value extends Json>(\n filePath: string,\n {\n parser = JSON,\n }: {\n parser?: {\n parse: (\n text: Parameters<typeof JSON.parse>[0],\n ) => ReturnType<typeof JSON.parse>;\n };\n } = {},\n): Promise<Value> {\n try {\n const content = await fs.promises.readFile(filePath, 'utf8');\n return parser.parse(content);\n } catch (error) {\n throw wrapError(error, `Could not read JSON file '${filePath}'`);\n }\n}\n\n/**\n * Attempt to write the given JSON-like value to the file at the given path,\n * creating the directory structure for the file automatically if necessary.\n * Adds a newline to the end of the file. Supports a custom parser (in case you\n * want to use the [JSON5](https://www.npmjs.com/package/json5) package\n * instead).\n *\n * @param filePath - The path to write the JSON file to, including the file\n * itself.\n * @param jsonValue - The JSON-like value to write to the file. Make sure that\n * JSON.stringify can handle it.\n * @param options - The options to this function.\n * @param options.prettify - Whether to format the JSON as it is turned into a\n * string such that it is broken up into separate lines (using 2 spaces as\n * indentation).\n * @param options.stringifier - The stringifier to use. Defaults to `JSON`.\n * @param options.stringifier.stringify - A function that stringifies JSON.\n * @returns The object corresponding to the parsed JSON file, typed against the\n * struct.\n * @throws An error with a stack trace if writing fails in any way.\n */\nexport async function writeJsonFile(\n filePath: string,\n jsonValue: Json,\n {\n stringifier = JSON,\n prettify = false,\n }: {\n stringifier?: {\n stringify: typeof JSON.stringify;\n };\n prettify?: boolean;\n } = {},\n): Promise<void> {\n try {\n await fs.promises.mkdir(path.dirname(filePath), { recursive: true });\n const json = prettify\n ? stringifier.stringify(jsonValue, null, ' ')\n : stringifier.stringify(jsonValue);\n await fs.promises.writeFile(filePath, json);\n } catch (error) {\n throw wrapError(error, `Could not write JSON file '${filePath}'`);\n }\n}\n\n/**\n * Test the given path to determine whether it represents a file.\n *\n * @param filePath - The path to a (supposed) file on the filesystem.\n * @returns A promise for true if the file exists or false otherwise.\n * @throws An error with a stack trace if reading fails in any way.\n */\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n const stats = await fs.promises.stat(filePath);\n return stats.isFile();\n } catch (error) {\n if (isErrorWithCode(error) && error.code === 'ENOENT') {\n return false;\n }\n\n throw wrapError(error, `Could not determine if file exists '${filePath}'`);\n }\n}\n\n/**\n * Test the given path to determine whether it represents a directory.\n *\n * @param directoryPath - The path to a (supposed) directory on the filesystem.\n * @returns A promise for true if the file exists or false otherwise.\n * @throws An error with a stack trace if reading fails in any way.\n */\nexport async function directoryExists(directoryPath: string): Promise<boolean> {\n try {\n const stats = await fs.promises.stat(directoryPath);\n return stats.isDirectory();\n } catch (error) {\n if (isErrorWithCode(error) && error.code === 'ENOENT') {\n return false;\n }\n\n throw wrapError(\n error,\n `Could not determine if directory exists '${directoryPath}'`,\n );\n }\n}\n\n/**\n * Create the given directory along with any directories leading up to the\n * directory, or do nothing if the directory already exists.\n *\n * @param directoryPath - The path to the desired directory.\n * @throws An error with a stack trace if reading fails in any way.\n */\nexport async function ensureDirectoryStructureExists(\n directoryPath: string,\n): Promise<void> {\n try {\n await fs.promises.mkdir(directoryPath, { recursive: true });\n } catch (error) {\n throw wrapError(\n error,\n `Could not create directory structure '${directoryPath}'`,\n );\n }\n}\n\n/**\n * Remove the given file or directory if it exists, or do nothing if it does\n * not.\n *\n * @param entryPath - The path to the file or directory.\n * @throws An error with a stack trace if removal fails in any way.\n */\nexport async function forceRemove(entryPath: string): Promise<void> {\n try {\n return await fs.promises.rm(entryPath, {\n recursive: true,\n force: true,\n });\n } catch (error) {\n throw wrapError(error, `Could not remove file or directory '${entryPath}'`);\n }\n}\n\n/**\n * Construct a sandbox object which can be used in tests that need temporary\n * access to the filesystem.\n *\n * @param projectName - The name of the project.\n * @returns The sandbox object. This contains a `withinSandbox` function which\n * can be used in tests (see example).\n * @example\n * ```typescript\n * const { withinSandbox } = createSandbox('utils');\n *\n * // ... later ...\n *\n * it('does something with the filesystem', async () => {\n * await withinSandbox(async ({ directoryPath }) => {\n * await fs.promises.writeFile(\n * path.join(directoryPath, 'some-file'),\n * 'some content',\n * 'utf8'\n * );\n * })\n * });\n * ```\n */\nexport function createSandbox(projectName: string): FileSandbox {\n const directoryPath = path.join(os.tmpdir(), projectName, uuid.v4());\n\n return {\n directoryPath,\n async withinSandbox(\n test: (args: { directoryPath: string }) => Promise<void>,\n ) {\n if (await directoryExists(directoryPath)) {\n throw new Error(`${directoryPath} already exists. Cannot continue.`);\n }\n\n await ensureDirectoryStructureExists(directoryPath);\n\n try {\n await test({ directoryPath });\n } finally {\n await forceRemove(directoryPath);\n }\n },\n };\n}\n"]}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Compute a SHA-256 digest for a given byte array.
3
+ *
4
+ * Uses the native crypto implementation and falls back to noble.
5
+ *
6
+ * @param bytes - A byte array.
7
+ * @returns The SHA-256 hash as a byte array.
8
+ */
9
+ export declare function sha256(bytes: Uint8Array): Promise<Uint8Array>;
10
+ /**
11
+ * Compute a SHA-512 digest for a given byte array.
12
+ *
13
+ * Uses the native crypto implementation and falls back to noble.
14
+ *
15
+ * @param bytes - A byte array.
16
+ * @returns The SHA-512 hash as a byte array.
17
+ */
18
+ export declare function sha512(bytes: Uint8Array): Promise<Uint8Array>;
19
+ /**
20
+ * Compute a SHA-384 digest for a given byte array.
21
+ *
22
+ * Uses the native crypto implementation and falls back to noble.
23
+ *
24
+ * @param bytes - A byte array.
25
+ * @returns The SHA-384 hash as a byte array.
26
+ */
27
+ export declare function sha384(bytes: Uint8Array): Promise<Uint8Array>;
28
+ //# sourceMappingURL=hashing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashing.d.ts","sourceRoot":"","sources":["../src/hashing.ts"],"names":[],"mappings":"AAMA;;;;;;;GAOG;AAMH,wBAAsB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAYnE;AAED;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAYnE;AAED;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAYnE"}
@@ -0,0 +1,59 @@
1
+ import { sha256 as nobleSha256 } from '@noble/hashes/sha256';
2
+ import { sha512 as nobleSha512, sha384 as nobleSha384, } from '@noble/hashes/sha512';
3
+ /**
4
+ * Compute a SHA-256 digest for a given byte array.
5
+ *
6
+ * Uses the native crypto implementation and falls back to noble.
7
+ *
8
+ * @param bytes - A byte array.
9
+ * @returns The SHA-256 hash as a byte array.
10
+ */
11
+ // `crypto.subtle.digest` takes a `BufferSource`, which TypeScript 7 will not
12
+ // accept a plain `Uint8Array` for: it is now generic over the buffer, so it
13
+ // could be backed by a `SharedArrayBuffer`. Runtimes accept those, and
14
+ // narrowing the exported signatures below would break callers, so the
15
+ // assertion is kept at the call sites.
16
+ export async function sha256(bytes) {
17
+ // Use crypto.subtle.digest whenever possible as it is faster.
18
+ if ('crypto' in globalThis &&
19
+ typeof globalThis.crypto === 'object' &&
20
+ globalThis.crypto.subtle?.digest) {
21
+ return new Uint8Array(await globalThis.crypto.subtle.digest('SHA-256', bytes));
22
+ }
23
+ return nobleSha256(bytes);
24
+ }
25
+ /**
26
+ * Compute a SHA-512 digest for a given byte array.
27
+ *
28
+ * Uses the native crypto implementation and falls back to noble.
29
+ *
30
+ * @param bytes - A byte array.
31
+ * @returns The SHA-512 hash as a byte array.
32
+ */
33
+ export async function sha512(bytes) {
34
+ // Use crypto.subtle.digest whenever possible as it is faster.
35
+ if ('crypto' in globalThis &&
36
+ typeof globalThis.crypto === 'object' &&
37
+ globalThis.crypto.subtle?.digest) {
38
+ return new Uint8Array(await globalThis.crypto.subtle.digest('SHA-512', bytes));
39
+ }
40
+ return nobleSha512(bytes);
41
+ }
42
+ /**
43
+ * Compute a SHA-384 digest for a given byte array.
44
+ *
45
+ * Uses the native crypto implementation and falls back to noble.
46
+ *
47
+ * @param bytes - A byte array.
48
+ * @returns The SHA-384 hash as a byte array.
49
+ */
50
+ export async function sha384(bytes) {
51
+ // Use crypto.subtle.digest whenever possible as it is faster.
52
+ if ('crypto' in globalThis &&
53
+ typeof globalThis.crypto === 'object' &&
54
+ globalThis.crypto.subtle?.digest) {
55
+ return new Uint8Array(await globalThis.crypto.subtle.digest('SHA-384', bytes));
56
+ }
57
+ return nobleSha384(bytes);
58
+ }
59
+ //# sourceMappingURL=hashing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashing.js","sourceRoot":"","sources":["../src/hashing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EACL,MAAM,IAAI,WAAW,EACrB,MAAM,IAAI,WAAW,GACtB,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;GAOG;AACH,6EAA6E;AAC7E,4EAA4E;AAC5E,uEAAuE;AACvE,sEAAsE;AACtE,uCAAuC;AACvC,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,KAAiB;IAC5C,8DAA8D;IAC9D,IACE,QAAQ,IAAI,UAAU;QACtB,OAAO,UAAU,CAAC,MAAM,KAAK,QAAQ;QACrC,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAChC,CAAC;QACD,OAAO,IAAI,UAAU,CACnB,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAqB,CAAC,CACxE,CAAC;IACJ,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,KAAiB;IAC5C,8DAA8D;IAC9D,IACE,QAAQ,IAAI,UAAU;QACtB,OAAO,UAAU,CAAC,MAAM,KAAK,QAAQ;QACrC,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAChC,CAAC;QACD,OAAO,IAAI,UAAU,CACnB,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAqB,CAAC,CACxE,CAAC;IACJ,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,KAAiB;IAC5C,8DAA8D;IAC9D,IACE,QAAQ,IAAI,UAAU;QACtB,OAAO,UAAU,CAAC,MAAM,KAAK,QAAQ;QACrC,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAChC,CAAC;QACD,OAAO,IAAI,UAAU,CACnB,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAqB,CAAC,CACxE,CAAC;IACJ,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC","sourcesContent":["import { sha256 as nobleSha256 } from '@noble/hashes/sha256';\nimport {\n sha512 as nobleSha512,\n sha384 as nobleSha384,\n} from '@noble/hashes/sha512';\n\n/**\n * Compute a SHA-256 digest for a given byte array.\n *\n * Uses the native crypto implementation and falls back to noble.\n *\n * @param bytes - A byte array.\n * @returns The SHA-256 hash as a byte array.\n */\n// `crypto.subtle.digest` takes a `BufferSource`, which TypeScript 7 will not\n// accept a plain `Uint8Array` for: it is now generic over the buffer, so it\n// could be backed by a `SharedArrayBuffer`. Runtimes accept those, and\n// narrowing the exported signatures below would break callers, so the\n// assertion is kept at the call sites.\nexport async function sha256(bytes: Uint8Array): Promise<Uint8Array> {\n // Use crypto.subtle.digest whenever possible as it is faster.\n if (\n 'crypto' in globalThis &&\n typeof globalThis.crypto === 'object' &&\n globalThis.crypto.subtle?.digest\n ) {\n return new Uint8Array(\n await globalThis.crypto.subtle.digest('SHA-256', bytes as BufferSource),\n );\n }\n return nobleSha256(bytes);\n}\n\n/**\n * Compute a SHA-512 digest for a given byte array.\n *\n * Uses the native crypto implementation and falls back to noble.\n *\n * @param bytes - A byte array.\n * @returns The SHA-512 hash as a byte array.\n */\nexport async function sha512(bytes: Uint8Array): Promise<Uint8Array> {\n // Use crypto.subtle.digest whenever possible as it is faster.\n if (\n 'crypto' in globalThis &&\n typeof globalThis.crypto === 'object' &&\n globalThis.crypto.subtle?.digest\n ) {\n return new Uint8Array(\n await globalThis.crypto.subtle.digest('SHA-512', bytes as BufferSource),\n );\n }\n return nobleSha512(bytes);\n}\n\n/**\n * Compute a SHA-384 digest for a given byte array.\n *\n * Uses the native crypto implementation and falls back to noble.\n *\n * @param bytes - A byte array.\n * @returns The SHA-384 hash as a byte array.\n */\nexport async function sha384(bytes: Uint8Array): Promise<Uint8Array> {\n // Use crypto.subtle.digest whenever possible as it is faster.\n if (\n 'crypto' in globalThis &&\n typeof globalThis.crypto === 'object' &&\n globalThis.crypto.subtle?.digest\n ) {\n return new Uint8Array(\n await globalThis.crypto.subtle.digest('SHA-384', bytes as BufferSource),\n );\n }\n return nobleSha384(bytes);\n}\n"]}