@ainc/fs 0.1.23 → 0.1.24

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/download.js CHANGED
@@ -20,6 +20,7 @@ const node_stream_1 = require("node:stream");
20
20
  const promises_2 = require("node:stream/promises");
21
21
  const retry_1 = require("./retry");
22
22
  const md5_1 = require("./md5");
23
+ const promises_3 = require("./promises");
23
24
  const concurrency_1 = require("./concurrency");
24
25
  /**
25
26
  *****************************************
@@ -52,7 +53,7 @@ async function download(dest, url, options = {}) {
52
53
  *****************************************
53
54
  */
54
55
  async function downloadFileByChunk(dest, url, init, options) {
55
- const stats = await (0, promises_1.stat)(dest).catch(err => err.code === 'ENOENT' ? null : Promise.reject(err));
56
+ const stats = await (0, promises_3.stat)(dest).catch(err => err.code === 'ENOENT' ? null : Promise.reject(err));
56
57
  // 已经存在文件,不再下载
57
58
  if (stats && stats.isFile() && !options.force) {
58
59
  options.onProgress && options.onProgress(stats.size, stats.size);
@@ -93,7 +94,7 @@ async function downloadFileByChunk(dest, url, init, options) {
93
94
  // 创建下载目录
94
95
  await (0, promises_1.mkdir)(dir, { recursive: true });
95
96
  // 合并文件
96
- await chunkConcurrency.execute(path => pipe(path, stream));
97
+ await chunkConcurrency.execute(path => (0, promises_3.pipe)((0, node_fs_1.createReadStream)(path), stream, { end: false }));
97
98
  // 结束传输
98
99
  stream.end();
99
100
  // 重命名临时文件
@@ -156,26 +157,13 @@ function getDownloadURL(url) {
156
157
  function getDownloadDir(url, options) {
157
158
  return (0, node_path_1.join)((0, node_os_1.tmpdir)(), 'downloads', generateDownloadID(getDownloadURL(url), options));
158
159
  }
159
- /**
160
- *****************************************
161
- * 写入文件流
162
- *****************************************
163
- */
164
- function pipe(src, dest) {
165
- return new Promise((resolve, reject) => {
166
- const stream = (0, node_fs_1.createReadStream)(src);
167
- stream.once('close', resolve);
168
- stream.once('error', reject);
169
- stream.pipe(dest, { end: false });
170
- });
171
- }
172
160
  /**
173
161
  *****************************************
174
162
  * 下载文件
175
163
  *****************************************
176
164
  */
177
165
  async function downloadFile(dest, url, init, options) {
178
- const stats = await (0, promises_1.stat)(dest).catch(err => err.code === 'ENOENT' ? null : Promise.reject(err));
166
+ const stats = await (0, promises_3.stat)(dest);
179
167
  // 已经存在文件,不再下载
180
168
  if (stats && stats.isFile() && !options.force) {
181
169
  options.onProgress && options.onProgress(stats.size, stats.size);
package/dist/gzip.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { ZlibOptions } from 'node:zlib';
2
+ /**
3
+ *****************************************
4
+ * gzip
5
+ *****************************************
6
+ */
7
+ export declare function gzip(src: string, dest: string, options?: ZlibOptions): Promise<string>;
8
+ /**
9
+ *****************************************
10
+ * ungzip
11
+ *****************************************
12
+ */
13
+ export declare function ungzip(src: string, dest: string, options?: ZlibOptions): Promise<string>;
package/dist/gzip.js ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2026-03-20 23:07:36
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.gzip = gzip;
10
+ exports.ungzip = ungzip;
11
+ /**
12
+ *****************************************
13
+ * 加载依赖
14
+ *****************************************
15
+ */
16
+ const node_fs_1 = require("node:fs");
17
+ const node_zlib_1 = require("node:zlib");
18
+ const promises_1 = require("./promises");
19
+ /**
20
+ *****************************************
21
+ * gzip
22
+ *****************************************
23
+ */
24
+ function gzip(src, dest, options) {
25
+ return new Promise((resolve, reject) => {
26
+ const readable = (0, node_fs_1.createReadStream)(src);
27
+ const gzip = (0, node_zlib_1.createGzip)(options);
28
+ const writable = (0, node_fs_1.createWriteStream)(dest);
29
+ readable.pipe(gzip)
30
+ .pipe(writable)
31
+ .once('finish', () => resolve(dest))
32
+ .once('error', err => (0, promises_1.rm)(dest).then(() => reject(err)));
33
+ });
34
+ }
35
+ /**
36
+ *****************************************
37
+ * ungzip
38
+ *****************************************
39
+ */
40
+ function ungzip(src, dest, options) {
41
+ return new Promise((resolve, reject) => {
42
+ const readable = (0, node_fs_1.createReadStream)(src);
43
+ const gzip = (0, node_zlib_1.createGunzip)(options);
44
+ const writable = (0, node_fs_1.createWriteStream)(dest);
45
+ readable.pipe(gzip)
46
+ .pipe(writable)
47
+ .once('finish', () => resolve(dest))
48
+ .once('error', err => (0, promises_1.rm)(dest).then(() => reject(err)));
49
+ });
50
+ }
package/dist/index.d.ts CHANGED
@@ -41,7 +41,7 @@ export { md5 } from './md5';
41
41
  export { json, jsonc } from './jsonc';
42
42
  export { findUp } from './findUp';
43
43
  export { download } from './download';
44
- export { downloadFile } from './downloadFile';
44
+ export { gzip, ungzip } from './gzip';
45
45
  export { loadPackageDescription, resolvePackageDescription } from './loadPackageDescription';
46
46
  export { loadTsConfig, loadCompilerOptions, resolveTsConfig } from './loadTsConfig';
47
47
  export { resolveAlias, resolveDict } from './resolveAlias';
@@ -19,7 +19,7 @@
19
19
  {"path": "./jsonc", "names": ["json", "jsonc"]},
20
20
  {"path": "./findUp", "names": ["findUp"]},
21
21
  {"path": "./download", "names": ["download"]},
22
- {"path": "./downloadFile", "names": ["downloadFile"]},
22
+ {"path": "./gzip", "names": ["gzip", "ungzip"]},
23
23
  {"path": "./loadPackageDescription", "names": ["loadPackageDescription", "resolvePackageDescription"]},
24
24
  {"path": "./loadTsConfig", "names": ["loadTsConfig", "loadCompilerOptions", "resolveTsConfig"]},
25
25
  {"path": "./resolveAlias", "names": ["resolveAlias", "resolveDict"]},
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
  'use strict';
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.resolveModuleId = exports.resolveModuleDirs = exports.resolveModuleDir = exports.resolveExports = exports.resolveImports = exports.resolveDirect = exports.resolveFile = exports.resolvePath = exports.resolvePaths = exports.resolveDict = exports.resolveAlias = exports.resolveTsConfig = exports.loadCompilerOptions = exports.loadTsConfig = exports.resolvePackageDescription = exports.loadPackageDescription = exports.downloadFile = exports.download = exports.findUp = exports.jsonc = exports.json = exports.md5 = exports.lookup = exports.rm = exports.copy = exports.writeFile = exports.readFile = exports.isFile = exports.isDir = exports.stat = exports.isEsmPackage = exports.isEsmFile = exports.isEsmModule = exports.dirname = exports.isRelative = exports.relative = exports.isAbsolute = exports.join = exports.resolve = exports.Dict = exports.retry = exports.cache = exports.split = exports.match = exports.nil = exports.noop = exports.unary = exports.sys = void 0;
9
+ exports.resolveModuleId = exports.resolveModuleDirs = exports.resolveModuleDir = exports.resolveExports = exports.resolveImports = exports.resolveDirect = exports.resolveFile = exports.resolvePath = exports.resolvePaths = exports.resolveDict = exports.resolveAlias = exports.resolveTsConfig = exports.loadCompilerOptions = exports.loadTsConfig = exports.resolvePackageDescription = exports.loadPackageDescription = exports.ungzip = exports.gzip = exports.download = exports.findUp = exports.jsonc = exports.json = exports.md5 = exports.lookup = exports.rm = exports.copy = exports.writeFile = exports.readFile = exports.isFile = exports.isDir = exports.stat = exports.isEsmPackage = exports.isEsmFile = exports.isEsmModule = exports.dirname = exports.isRelative = exports.relative = exports.isAbsolute = exports.join = exports.resolve = exports.Dict = exports.retry = exports.cache = exports.split = exports.match = exports.nil = exports.noop = exports.unary = exports.sys = void 0;
10
10
  /**
11
11
  *****************************************
12
12
  * 文件系统
@@ -73,8 +73,9 @@ var findUp_1 = require("./findUp");
73
73
  Object.defineProperty(exports, "findUp", { enumerable: true, get: function () { return findUp_1.findUp; } });
74
74
  var download_1 = require("./download");
75
75
  Object.defineProperty(exports, "download", { enumerable: true, get: function () { return download_1.download; } });
76
- var downloadFile_1 = require("./downloadFile");
77
- Object.defineProperty(exports, "downloadFile", { enumerable: true, get: function () { return downloadFile_1.downloadFile; } });
76
+ var gzip_1 = require("./gzip");
77
+ Object.defineProperty(exports, "gzip", { enumerable: true, get: function () { return gzip_1.gzip; } });
78
+ Object.defineProperty(exports, "ungzip", { enumerable: true, get: function () { return gzip_1.ungzip; } });
78
79
  var loadPackageDescription_1 = require("./loadPackageDescription");
79
80
  Object.defineProperty(exports, "loadPackageDescription", { enumerable: true, get: function () { return loadPackageDescription_1.loadPackageDescription; } });
80
81
  Object.defineProperty(exports, "resolvePackageDescription", { enumerable: true, get: function () { return loadPackageDescription_1.resolvePackageDescription; } });
@@ -0,0 +1,69 @@
1
+ /**
2
+ *****************************************
3
+ * 加载依赖
4
+ *****************************************
5
+ */
6
+ import { Readable, Writable, PipeOptions } from 'node:stream';
7
+ import { Mode, RmOptions, StatOptions as IStatOptions } from 'node:fs';
8
+ /**
9
+ *****************************************
10
+ * 状态选项
11
+ *****************************************
12
+ */
13
+ export interface StatOptions extends IStatOptions {
14
+ bigint?: false | undefined;
15
+ }
16
+ /**
17
+ *****************************************
18
+ * 获取文件状态
19
+ *****************************************
20
+ */
21
+ export declare function stat(path: string, options?: StatOptions): Promise<import("node:fs").Stats | null>;
22
+ /**
23
+ *****************************************
24
+ * 删除文件
25
+ *****************************************
26
+ */
27
+ export declare function rm(path: string, options?: RmOptions): Promise<void>;
28
+ /**
29
+ *****************************************
30
+ * 选项
31
+ *****************************************
32
+ */
33
+ export interface MkdirOptions {
34
+ force?: boolean;
35
+ mode?: Mode | undefined;
36
+ recursive?: boolean;
37
+ }
38
+ /**
39
+ *****************************************
40
+ * 创建文件目录
41
+ *****************************************
42
+ */
43
+ export declare function mkdir(path: string, options?: MkdirOptions): Promise<boolean>;
44
+ /**
45
+ *****************************************
46
+ * pipe
47
+ *****************************************
48
+ */
49
+ export declare function pipe(src: Readable, dest: Writable, options?: PipeOptions): Promise<unknown>;
50
+ /**
51
+ *****************************************
52
+ * 读取文件
53
+ *****************************************
54
+ */
55
+ export declare function readFile(path: string): Promise<string | undefined>;
56
+ /**
57
+ *****************************************
58
+ * 选项
59
+ *****************************************
60
+ */
61
+ export interface WriteFileOptions {
62
+ force?: boolean;
63
+ }
64
+ /**
65
+ *****************************************
66
+ * 写入文件
67
+ *****************************************
68
+ */
69
+ export declare function writeFile(path: string, content: string, options?: WriteFileOptions): Promise<boolean>;
@@ -0,0 +1,103 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2026-03-21 12:37:59
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.stat = stat;
10
+ exports.rm = rm;
11
+ exports.mkdir = mkdir;
12
+ exports.pipe = pipe;
13
+ exports.readFile = readFile;
14
+ exports.writeFile = writeFile;
15
+ const node_path_1 = require("node:path");
16
+ const fs = require("node:fs/promises");
17
+ /**
18
+ *****************************************
19
+ * 获取文件状态
20
+ *****************************************
21
+ */
22
+ async function stat(path, options) {
23
+ return fs.stat(path, options).catch(err => err.code === 'ENOENT' ? null : Promise.reject(err));
24
+ }
25
+ /**
26
+ *****************************************
27
+ * 删除文件
28
+ *****************************************
29
+ */
30
+ async function rm(path, options) {
31
+ if (await stat(path)) {
32
+ await fs.rm(path, { force: true, recursive: true, ...options });
33
+ }
34
+ }
35
+ /**
36
+ *****************************************
37
+ * 创建文件目录
38
+ *****************************************
39
+ */
40
+ async function mkdir(path, options) {
41
+ const stats = await stat(path);
42
+ const opts = { recursive: true, ...options };
43
+ // 创建目录
44
+ if (!stats) {
45
+ await fs.mkdir(path, opts);
46
+ return true;
47
+ }
48
+ else if (stats.isDirectory()) {
49
+ return true;
50
+ }
51
+ else if (!opts.force) {
52
+ return false;
53
+ }
54
+ else {
55
+ await fs.unlink(path);
56
+ await fs.mkdir(path, opts);
57
+ return true;
58
+ }
59
+ }
60
+ /**
61
+ *****************************************
62
+ * pipe
63
+ *****************************************
64
+ */
65
+ async function pipe(src, dest, options) {
66
+ return new Promise((resolve, reject) => {
67
+ src.once('close', resolve);
68
+ src.once('error', reject);
69
+ src.pipe(dest, options);
70
+ });
71
+ }
72
+ /**
73
+ *****************************************
74
+ * 读取文件
75
+ *****************************************
76
+ */
77
+ async function readFile(path) {
78
+ const stats = await stat(path);
79
+ if (stats && !stats.isDirectory()) {
80
+ return fs.readFile(path, 'utf8');
81
+ }
82
+ }
83
+ /**
84
+ *****************************************
85
+ * 写入文件
86
+ *****************************************
87
+ */
88
+ async function writeFile(path, content, options) {
89
+ const stats = await stat(path);
90
+ if (stats) {
91
+ if (!options || !options.force) {
92
+ return false;
93
+ }
94
+ else {
95
+ await rm(path);
96
+ }
97
+ }
98
+ // 写入文件内容
99
+ await fs.mkdir((0, node_path_1.dirname)(path), { recursive: true });
100
+ await fs.writeFile(path, content);
101
+ // 返回结果
102
+ return true;
103
+ }
package/esm/download.mjs CHANGED
@@ -12,12 +12,13 @@
12
12
  */
13
13
  import { tmpdir } from 'node:os';
14
14
  import { resolve, join, dirname } from 'node:path';
15
- import { stat, mkdir, rm, rename } from 'node:fs/promises';
15
+ import { mkdir, rm, rename } from 'node:fs/promises';
16
16
  import { createReadStream, createWriteStream } from 'node:fs';
17
17
  import { Readable } from 'node:stream';
18
18
  import { pipeline } from 'node:stream/promises';
19
19
  import { retry } from './retry.mjs';
20
20
  import { md5 } from './md5.mjs';
21
+ import { stat, pipe } from './promises.mjs';
21
22
  import { Concurrency } from './concurrency.mjs';
22
23
  /**
23
24
  *****************************************
@@ -91,7 +92,7 @@ async function downloadFileByChunk(dest, url, init, options) {
91
92
  // 创建下载目录
92
93
  await mkdir(dir, { recursive: true });
93
94
  // 合并文件
94
- await chunkConcurrency.execute(path => pipe(path, stream));
95
+ await chunkConcurrency.execute(path => pipe(createReadStream(path), stream, { end: false }));
95
96
  // 结束传输
96
97
  stream.end();
97
98
  // 重命名临时文件
@@ -154,26 +155,13 @@ function getDownloadURL(url) {
154
155
  function getDownloadDir(url, options) {
155
156
  return join(tmpdir(), 'downloads', generateDownloadID(getDownloadURL(url), options));
156
157
  }
157
- /**
158
- *****************************************
159
- * 写入文件流
160
- *****************************************
161
- */
162
- function pipe(src, dest) {
163
- return new Promise((resolve, reject) => {
164
- const stream = createReadStream(src);
165
- stream.once('close', resolve);
166
- stream.once('error', reject);
167
- stream.pipe(dest, { end: false });
168
- });
169
- }
170
158
  /**
171
159
  *****************************************
172
160
  * 下载文件
173
161
  *****************************************
174
162
  */
175
163
  async function downloadFile(dest, url, init, options) {
176
- const stats = await stat(dest).catch(err => err.code === 'ENOENT' ? null : Promise.reject(err));
164
+ const stats = await stat(dest);
177
165
  // 已经存在文件,不再下载
178
166
  if (stats && stats.isFile() && !options.force) {
179
167
  options.onProgress && options.onProgress(stats.size, stats.size);
package/esm/gzip.mjs ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2026-03-20 23:07:36
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ /**
9
+ *****************************************
10
+ * 加载依赖
11
+ *****************************************
12
+ */
13
+ import { createReadStream, createWriteStream } from 'node:fs';
14
+ import { createGzip, createGunzip } from 'node:zlib';
15
+ import { rm } from './promises.mjs';
16
+ /**
17
+ *****************************************
18
+ * gzip
19
+ *****************************************
20
+ */
21
+ export function gzip(src, dest, options) {
22
+ return new Promise((resolve, reject) => {
23
+ const readable = createReadStream(src);
24
+ const gzip = createGzip(options);
25
+ const writable = createWriteStream(dest);
26
+ readable.pipe(gzip)
27
+ .pipe(writable)
28
+ .once('finish', () => resolve(dest))
29
+ .once('error', err => rm(dest).then(() => reject(err)));
30
+ });
31
+ }
32
+ /**
33
+ *****************************************
34
+ * ungzip
35
+ *****************************************
36
+ */
37
+ export function ungzip(src, dest, options) {
38
+ return new Promise((resolve, reject) => {
39
+ const readable = createReadStream(src);
40
+ const gzip = createGunzip(options);
41
+ const writable = createWriteStream(dest);
42
+ readable.pipe(gzip)
43
+ .pipe(writable)
44
+ .once('finish', () => resolve(dest))
45
+ .once('error', err => rm(dest).then(() => reject(err)));
46
+ });
47
+ }
@@ -19,7 +19,7 @@
19
19
  {"path": "./jsonc", "names": ["json", "jsonc"]},
20
20
  {"path": "./findUp", "names": ["findUp"]},
21
21
  {"path": "./download", "names": ["download"]},
22
- {"path": "./downloadFile", "names": ["downloadFile"]},
22
+ {"path": "./gzip", "names": ["gzip", "ungzip"]},
23
23
  {"path": "./loadPackageDescription", "names": ["loadPackageDescription", "resolvePackageDescription"]},
24
24
  {"path": "./loadTsConfig", "names": ["loadTsConfig", "loadCompilerOptions", "resolveTsConfig"]},
25
25
  {"path": "./resolveAlias", "names": ["resolveAlias", "resolveDict"]},
package/esm/index.mjs CHANGED
@@ -40,7 +40,7 @@ export { md5 } from './md5.mjs';
40
40
  export { json, jsonc } from './jsonc.mjs';
41
41
  export { findUp } from './findUp.mjs';
42
42
  export { download } from './download.mjs';
43
- export { downloadFile } from './downloadFile.mjs';
43
+ export { gzip, ungzip } from './gzip.mjs';
44
44
  export { loadPackageDescription, resolvePackageDescription } from './loadPackageDescription.mjs';
45
45
  export { loadTsConfig, loadCompilerOptions, resolveTsConfig } from './loadTsConfig.mjs';
46
46
  export { resolveAlias, resolveDict } from './resolveAlias.mjs';
@@ -0,0 +1,96 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2026-03-21 12:37:59
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ import { dirname } from 'node:path';
9
+ import * as fs from 'node:fs/promises';
10
+ /**
11
+ *****************************************
12
+ * 获取文件状态
13
+ *****************************************
14
+ */
15
+ export async function stat(path, options) {
16
+ return fs.stat(path, options).catch(err => err.code === 'ENOENT' ? null : Promise.reject(err));
17
+ }
18
+ /**
19
+ *****************************************
20
+ * 删除文件
21
+ *****************************************
22
+ */
23
+ export async function rm(path, options) {
24
+ if (await stat(path)) {
25
+ await fs.rm(path, { force: true, recursive: true, ...options });
26
+ }
27
+ }
28
+ /**
29
+ *****************************************
30
+ * 创建文件目录
31
+ *****************************************
32
+ */
33
+ export async function mkdir(path, options) {
34
+ const stats = await stat(path);
35
+ const opts = { recursive: true, ...options };
36
+ // 创建目录
37
+ if (!stats) {
38
+ await fs.mkdir(path, opts);
39
+ return true;
40
+ }
41
+ else if (stats.isDirectory()) {
42
+ return true;
43
+ }
44
+ else if (!opts.force) {
45
+ return false;
46
+ }
47
+ else {
48
+ await fs.unlink(path);
49
+ await fs.mkdir(path, opts);
50
+ return true;
51
+ }
52
+ }
53
+ /**
54
+ *****************************************
55
+ * pipe
56
+ *****************************************
57
+ */
58
+ export async function pipe(src, dest, options) {
59
+ return new Promise((resolve, reject) => {
60
+ src.once('close', resolve);
61
+ src.once('error', reject);
62
+ src.pipe(dest, options);
63
+ });
64
+ }
65
+ /**
66
+ *****************************************
67
+ * 读取文件
68
+ *****************************************
69
+ */
70
+ export async function readFile(path) {
71
+ const stats = await stat(path);
72
+ if (stats && !stats.isDirectory()) {
73
+ return fs.readFile(path, 'utf8');
74
+ }
75
+ }
76
+ /**
77
+ *****************************************
78
+ * 写入文件
79
+ *****************************************
80
+ */
81
+ export async function writeFile(path, content, options) {
82
+ const stats = await stat(path);
83
+ if (stats) {
84
+ if (!options || !options.force) {
85
+ return false;
86
+ }
87
+ else {
88
+ await rm(path);
89
+ }
90
+ }
91
+ // 写入文件内容
92
+ await fs.mkdir(dirname(path), { recursive: true });
93
+ await fs.writeFile(path, content);
94
+ // 返回结果
95
+ return true;
96
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainc/fs",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "Let's do something nice with @ainc/esb!",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
@@ -32,15 +32,13 @@
32
32
  "publishConfig": {
33
33
  "access": "public"
34
34
  },
35
- "dependencies": {
36
- "typescript": "^5.9.3"
37
- },
38
35
  "devDependencies": {
39
36
  "@jest/globals": "30.2.0",
40
37
  "@swc/core": "^1.15.8",
41
38
  "@swc/jest": "^0.2.39",
42
39
  "@types/node": "^25.0.3",
43
- "jest": "^30.2.0"
40
+ "jest": "^30.2.0",
41
+ "typescript": "^5.9.3"
44
42
  },
45
43
  "scripts": {
46
44
  "build": "pnpm clean && pnpm compile && pnpm esm && pnpm exports",