atomically 1.7.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +0 -3
- package/dist/{consts.d.ts → constants.d.ts} +6 -4
- package/dist/constants.js +20 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.js +125 -106
- package/dist/types.d.ts +12 -12
- package/dist/types.js +2 -3
- package/dist/utils/lang.d.ts +6 -6
- package/dist/utils/lang.js +14 -14
- package/dist/utils/scheduler.d.ts +1 -1
- package/dist/utils/scheduler.js +4 -5
- package/dist/utils/temp.d.ts +1 -1
- package/dist/utils/temp.js +18 -15
- package/{LICENSE → license} +0 -0
- package/package.json +22 -32
- package/{README.md → readme.md} +3 -3
- package/src/constants.ts +39 -0
- package/src/index.ts +153 -93
- package/src/types.ts +9 -9
- package/src/utils/lang.ts +18 -12
- package/src/utils/scheduler.ts +5 -3
- package/src/utils/temp.ts +18 -13
- package/tasks/benchmark.js +16 -12
- package/test/{basic.js → basic.cjs} +47 -49
- package/test/{concurrency.js → concurrency.cjs} +6 -8
- package/test/{integration.js → integration.cjs} +44 -46
- package/tsconfig.json +1 -26
- package/.nvmrc +0 -1
- package/dist/consts.js +0 -28
- package/dist/utils/attemptify.d.ts +0 -4
- package/dist/utils/attemptify.js +0 -25
- package/dist/utils/fs.d.ts +0 -34
- package/dist/utils/fs.js +0 -42
- package/dist/utils/fs_handlers.d.ts +0 -7
- package/dist/utils/fs_handlers.js +0 -28
- package/dist/utils/retryify.d.ts +0 -4
- package/dist/utils/retryify.js +0 -45
- package/dist/utils/retryify_queue.d.ts +0 -15
- package/dist/utils/retryify_queue.js +0 -58
- package/src/consts.ts +0 -30
- package/src/utils/attemptify.ts +0 -42
- package/src/utils/fs.ts +0 -51
- package/src/utils/fs_handlers.ts +0 -45
- package/src/utils/retryify.ts +0 -78
- package/src/utils/retryify_queue.ts +0 -95
package/.editorconfig
CHANGED
|
@@ -3,11 +3,13 @@ declare const DEFAULT_FILE_MODE = 438;
|
|
|
3
3
|
declare const DEFAULT_FOLDER_MODE = 511;
|
|
4
4
|
declare const DEFAULT_READ_OPTIONS: {};
|
|
5
5
|
declare const DEFAULT_WRITE_OPTIONS: {};
|
|
6
|
-
declare const
|
|
7
|
-
declare const
|
|
8
|
-
declare const
|
|
6
|
+
declare const DEFAULT_USER_UID: number;
|
|
7
|
+
declare const DEFAULT_USER_GID: number;
|
|
8
|
+
declare const DEFAULT_TIMEOUT_ASYNC = 7500;
|
|
9
|
+
declare const DEFAULT_TIMEOUT_SYNC = 1000;
|
|
10
|
+
declare const IS_POSIX: boolean;
|
|
9
11
|
declare const IS_USER_ROOT: boolean;
|
|
10
12
|
declare const LIMIT_BASENAME_LENGTH = 128;
|
|
11
13
|
declare const LIMIT_FILES_DESCRIPTORS = 10000;
|
|
12
14
|
declare const NOOP: () => void;
|
|
13
|
-
export { DEFAULT_ENCODING, DEFAULT_FILE_MODE, DEFAULT_FOLDER_MODE, DEFAULT_READ_OPTIONS, DEFAULT_WRITE_OPTIONS, DEFAULT_TIMEOUT_ASYNC, DEFAULT_TIMEOUT_SYNC, IS_POSIX, IS_USER_ROOT, LIMIT_BASENAME_LENGTH, LIMIT_FILES_DESCRIPTORS, NOOP };
|
|
15
|
+
export { DEFAULT_ENCODING, DEFAULT_FILE_MODE, DEFAULT_FOLDER_MODE, DEFAULT_READ_OPTIONS, DEFAULT_WRITE_OPTIONS, DEFAULT_USER_UID, DEFAULT_USER_GID, DEFAULT_TIMEOUT_ASYNC, DEFAULT_TIMEOUT_SYNC, IS_POSIX, IS_USER_ROOT, LIMIT_BASENAME_LENGTH, LIMIT_FILES_DESCRIPTORS, NOOP };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/* IMPORT */
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import process from 'node:process';
|
|
4
|
+
/* MAIN */
|
|
5
|
+
const DEFAULT_ENCODING = 'utf8';
|
|
6
|
+
const DEFAULT_FILE_MODE = 0o666;
|
|
7
|
+
const DEFAULT_FOLDER_MODE = 0o777;
|
|
8
|
+
const DEFAULT_READ_OPTIONS = {};
|
|
9
|
+
const DEFAULT_WRITE_OPTIONS = {};
|
|
10
|
+
const DEFAULT_USER_UID = os.userInfo().uid;
|
|
11
|
+
const DEFAULT_USER_GID = os.userInfo().gid;
|
|
12
|
+
const DEFAULT_TIMEOUT_ASYNC = 7500;
|
|
13
|
+
const DEFAULT_TIMEOUT_SYNC = 1000;
|
|
14
|
+
const IS_POSIX = !!process.getuid;
|
|
15
|
+
const IS_USER_ROOT = process.getuid ? !process.getuid() : false;
|
|
16
|
+
const LIMIT_BASENAME_LENGTH = 128; //TODO: Fetch the real limit from the filesystem //TODO: Fetch the whole-path length limit too
|
|
17
|
+
const LIMIT_FILES_DESCRIPTORS = 10000; //TODO: Fetch the real limit from the filesystem
|
|
18
|
+
const NOOP = () => { };
|
|
19
|
+
/* EXPORT */
|
|
20
|
+
export { DEFAULT_ENCODING, DEFAULT_FILE_MODE, DEFAULT_FOLDER_MODE, DEFAULT_READ_OPTIONS, DEFAULT_WRITE_OPTIONS, DEFAULT_USER_UID, DEFAULT_USER_GID, DEFAULT_TIMEOUT_ASYNC, DEFAULT_TIMEOUT_SYNC, IS_POSIX, IS_USER_ROOT, LIMIT_BASENAME_LENGTH, LIMIT_FILES_DESCRIPTORS, NOOP };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { Callback, Data, Path, ReadOptions, WriteOptions } from './types';
|
|
3
|
-
declare function readFile(filePath: Path, options:
|
|
2
|
+
import type { Callback, Data, Encoding, Path, ReadOptions, WriteOptions } from './types';
|
|
3
|
+
declare function readFile(filePath: Path, options: Encoding | ReadOptions & {
|
|
4
4
|
encoding: string;
|
|
5
5
|
}): Promise<string>;
|
|
6
6
|
declare function readFile(filePath: Path, options?: ReadOptions): Promise<Buffer>;
|
|
7
|
-
declare function readFileSync(filePath: Path, options:
|
|
7
|
+
declare function readFileSync(filePath: Path, options: Encoding | ReadOptions & {
|
|
8
8
|
encoding: string;
|
|
9
9
|
}): string;
|
|
10
10
|
declare function readFileSync(filePath: Path, options?: ReadOptions): Buffer;
|
|
11
|
-
declare
|
|
12
|
-
declare
|
|
11
|
+
declare function writeFile(filePath: Path, data: Data, callback?: Callback): Promise<void>;
|
|
12
|
+
declare function writeFile(filePath: Path, data: Data, options?: Encoding | WriteOptions, callback?: Callback): Promise<void>;
|
|
13
|
+
declare function writeFileSync(filePath: Path, data: Data, options?: Encoding | WriteOptions): void;
|
|
13
14
|
export { readFile, readFileSync, writeFile, writeFileSync };
|
package/dist/index.js
CHANGED
|
@@ -1,177 +1,196 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/* IMPORT */
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
function readFile(filePath, options = consts_1.DEFAULT_READ_OPTIONS) {
|
|
12
|
-
var _a;
|
|
13
|
-
if (lang_1.default.isString(options))
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'stubborn-fs';
|
|
4
|
+
import { DEFAULT_ENCODING, DEFAULT_FILE_MODE, DEFAULT_FOLDER_MODE, DEFAULT_READ_OPTIONS, DEFAULT_WRITE_OPTIONS, DEFAULT_USER_UID, DEFAULT_USER_GID, DEFAULT_TIMEOUT_ASYNC, DEFAULT_TIMEOUT_SYNC, IS_POSIX } from './constants.js';
|
|
5
|
+
import { isException, isFunction, isString, isUndefined } from './utils/lang.js';
|
|
6
|
+
import Scheduler from './utils/scheduler.js';
|
|
7
|
+
import Temp from './utils/temp.js';
|
|
8
|
+
function readFile(filePath, options = DEFAULT_READ_OPTIONS) {
|
|
9
|
+
if (isString(options))
|
|
14
10
|
return readFile(filePath, { encoding: options });
|
|
15
|
-
const timeout = Date.now() + ((
|
|
16
|
-
return
|
|
11
|
+
const timeout = Date.now() + ((options.timeout ?? DEFAULT_TIMEOUT_ASYNC) || -1);
|
|
12
|
+
return fs.retry.readFile(timeout)(filePath, options);
|
|
17
13
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
function readFileSync(filePath, options = consts_1.DEFAULT_READ_OPTIONS) {
|
|
21
|
-
var _a;
|
|
22
|
-
if (lang_1.default.isString(options))
|
|
14
|
+
function readFileSync(filePath, options = DEFAULT_READ_OPTIONS) {
|
|
15
|
+
if (isString(options))
|
|
23
16
|
return readFileSync(filePath, { encoding: options });
|
|
24
|
-
const timeout = Date.now() + ((
|
|
25
|
-
return
|
|
17
|
+
const timeout = Date.now() + ((options.timeout ?? DEFAULT_TIMEOUT_SYNC) || -1);
|
|
18
|
+
return fs.retry.readFileSync(timeout)(filePath, options);
|
|
26
19
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (lang_1.default.isFunction(options))
|
|
31
|
-
return writeFile(filePath, data, consts_1.DEFAULT_WRITE_OPTIONS, options);
|
|
20
|
+
function writeFile(filePath, data, options, callback) {
|
|
21
|
+
if (isFunction(options))
|
|
22
|
+
return writeFile(filePath, data, DEFAULT_WRITE_OPTIONS, options);
|
|
32
23
|
const promise = writeFileAsync(filePath, data, options);
|
|
33
24
|
if (callback)
|
|
34
25
|
promise.then(callback, callback);
|
|
35
26
|
return promise;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
var _a;
|
|
40
|
-
if (lang_1.default.isString(options))
|
|
27
|
+
}
|
|
28
|
+
async function writeFileAsync(filePath, data, options = DEFAULT_WRITE_OPTIONS) {
|
|
29
|
+
if (isString(options))
|
|
41
30
|
return writeFileAsync(filePath, data, { encoding: options });
|
|
42
|
-
const timeout = Date.now() + ((
|
|
43
|
-
let schedulerCustomDisposer = null
|
|
31
|
+
const timeout = Date.now() + ((options.timeout ?? DEFAULT_TIMEOUT_ASYNC) || -1);
|
|
32
|
+
let schedulerCustomDisposer = null;
|
|
33
|
+
let schedulerDisposer = null;
|
|
34
|
+
let tempDisposer = null;
|
|
35
|
+
let tempPath = null;
|
|
36
|
+
let fd = null;
|
|
44
37
|
try {
|
|
45
38
|
if (options.schedule)
|
|
46
39
|
schedulerCustomDisposer = await options.schedule(filePath);
|
|
47
|
-
schedulerDisposer = await
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
schedulerDisposer = await Scheduler.schedule(filePath);
|
|
41
|
+
const filePathReal = await fs.attempt.realpath(filePath);
|
|
42
|
+
const filePathExists = !!filePathReal;
|
|
43
|
+
filePath = filePathReal || filePath;
|
|
44
|
+
[tempPath, tempDisposer] = Temp.get(filePath, options.tmpCreate || Temp.create, !(options.tmpPurge === false));
|
|
45
|
+
const useStatChown = IS_POSIX && isUndefined(options.chown);
|
|
46
|
+
const useStatMode = isUndefined(options.mode);
|
|
47
|
+
if (filePathExists && (useStatChown || useStatMode)) {
|
|
48
|
+
const stats = await fs.attempt.stat(filePath);
|
|
49
|
+
if (stats) {
|
|
54
50
|
options = { ...options };
|
|
55
|
-
if (useStatChown)
|
|
56
|
-
options.chown = { uid:
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
if (useStatChown) {
|
|
52
|
+
options.chown = { uid: stats.uid, gid: stats.gid };
|
|
53
|
+
}
|
|
54
|
+
if (useStatMode) {
|
|
55
|
+
options.mode = stats.mode;
|
|
56
|
+
}
|
|
59
57
|
}
|
|
60
58
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
59
|
+
if (!filePathExists) {
|
|
60
|
+
const parentPath = path.dirname(filePath);
|
|
61
|
+
await fs.attempt.mkdir(parentPath, {
|
|
62
|
+
mode: DEFAULT_FOLDER_MODE,
|
|
63
|
+
recursive: true
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
fd = await fs.retry.open(timeout)(tempPath, 'w', options.mode || DEFAULT_FILE_MODE);
|
|
67
|
+
if (options.tmpCreated) {
|
|
68
68
|
options.tmpCreated(tempPath);
|
|
69
|
-
if (lang_1.default.isString(data)) {
|
|
70
|
-
await fs_1.default.writeRetry(timeout)(fd, data, 0, options.encoding || consts_1.DEFAULT_ENCODING);
|
|
71
69
|
}
|
|
72
|
-
|
|
73
|
-
await
|
|
70
|
+
if (isString(data)) {
|
|
71
|
+
await fs.retry.write(timeout)(fd, data, 0, options.encoding || DEFAULT_ENCODING);
|
|
72
|
+
}
|
|
73
|
+
else if (!isUndefined(data)) {
|
|
74
|
+
await fs.retry.write(timeout)(fd, data, 0, data.length, 0);
|
|
74
75
|
}
|
|
75
76
|
if (options.fsync !== false) {
|
|
76
77
|
if (options.fsyncWait !== false) {
|
|
77
|
-
await
|
|
78
|
+
await fs.retry.fsync(timeout)(fd);
|
|
78
79
|
}
|
|
79
80
|
else {
|
|
80
|
-
|
|
81
|
+
fs.attempt.fsync(fd);
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
|
-
await
|
|
84
|
+
await fs.retry.close(timeout)(fd);
|
|
84
85
|
fd = null;
|
|
85
|
-
if (options.chown)
|
|
86
|
-
await
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
if (options.chown && (options.chown.uid !== DEFAULT_USER_UID || options.chown.gid !== DEFAULT_USER_GID)) {
|
|
87
|
+
await fs.attempt.chown(tempPath, options.chown.uid, options.chown.gid);
|
|
88
|
+
}
|
|
89
|
+
if (options.mode && options.mode !== DEFAULT_FILE_MODE) {
|
|
90
|
+
await fs.attempt.chmod(tempPath, options.mode);
|
|
91
|
+
}
|
|
89
92
|
try {
|
|
90
|
-
await
|
|
93
|
+
await fs.retry.rename(timeout)(tempPath, filePath);
|
|
91
94
|
}
|
|
92
95
|
catch (error) {
|
|
96
|
+
if (!isException(error))
|
|
97
|
+
throw error;
|
|
93
98
|
if (error.code !== 'ENAMETOOLONG')
|
|
94
99
|
throw error;
|
|
95
|
-
await
|
|
100
|
+
await fs.retry.rename(timeout)(tempPath, Temp.truncate(filePath));
|
|
96
101
|
}
|
|
97
102
|
tempDisposer();
|
|
98
103
|
tempPath = null;
|
|
99
104
|
}
|
|
100
105
|
finally {
|
|
101
106
|
if (fd)
|
|
102
|
-
await
|
|
107
|
+
await fs.attempt.close(fd);
|
|
103
108
|
if (tempPath)
|
|
104
|
-
|
|
109
|
+
Temp.purge(tempPath);
|
|
105
110
|
if (schedulerCustomDisposer)
|
|
106
111
|
schedulerCustomDisposer();
|
|
107
112
|
if (schedulerDisposer)
|
|
108
113
|
schedulerDisposer();
|
|
109
114
|
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (lang_1.default.isString(options))
|
|
115
|
+
}
|
|
116
|
+
function writeFileSync(filePath, data, options = DEFAULT_WRITE_OPTIONS) {
|
|
117
|
+
if (isString(options))
|
|
114
118
|
return writeFileSync(filePath, data, { encoding: options });
|
|
115
|
-
const timeout = Date.now() + ((
|
|
116
|
-
let tempDisposer = null
|
|
119
|
+
const timeout = Date.now() + ((options.timeout ?? DEFAULT_TIMEOUT_SYNC) || -1);
|
|
120
|
+
let tempDisposer = null;
|
|
121
|
+
let tempPath = null;
|
|
122
|
+
let fd = null;
|
|
117
123
|
try {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
+
const filePathReal = fs.attempt.realpathSync(filePath);
|
|
125
|
+
const filePathExists = !!filePathReal;
|
|
126
|
+
filePath = filePathReal || filePath;
|
|
127
|
+
[tempPath, tempDisposer] = Temp.get(filePath, options.tmpCreate || Temp.create, !(options.tmpPurge === false));
|
|
128
|
+
const useStatChown = IS_POSIX && isUndefined(options.chown);
|
|
129
|
+
const useStatMode = isUndefined(options.mode);
|
|
130
|
+
if (filePathExists && (useStatChown || useStatMode)) {
|
|
131
|
+
const stats = fs.attempt.statSync(filePath);
|
|
132
|
+
if (stats) {
|
|
124
133
|
options = { ...options };
|
|
125
|
-
if (useStatChown)
|
|
126
|
-
options.chown = { uid:
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
if (useStatChown) {
|
|
135
|
+
options.chown = { uid: stats.uid, gid: stats.gid };
|
|
136
|
+
}
|
|
137
|
+
if (useStatMode) {
|
|
138
|
+
options.mode = stats.mode;
|
|
139
|
+
}
|
|
129
140
|
}
|
|
130
141
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
142
|
+
if (!filePathExists) {
|
|
143
|
+
const parentPath = path.dirname(filePath);
|
|
144
|
+
fs.attempt.mkdirSync(parentPath, {
|
|
145
|
+
mode: DEFAULT_FOLDER_MODE,
|
|
146
|
+
recursive: true
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
fd = fs.retry.openSync(timeout)(tempPath, 'w', options.mode || DEFAULT_FILE_MODE);
|
|
150
|
+
if (options.tmpCreated) {
|
|
138
151
|
options.tmpCreated(tempPath);
|
|
139
|
-
if (lang_1.default.isString(data)) {
|
|
140
|
-
fs_1.default.writeSyncRetry(timeout)(fd, data, 0, options.encoding || consts_1.DEFAULT_ENCODING);
|
|
141
152
|
}
|
|
142
|
-
|
|
143
|
-
|
|
153
|
+
if (isString(data)) {
|
|
154
|
+
fs.retry.writeSync(timeout)(fd, data, 0, options.encoding || DEFAULT_ENCODING);
|
|
155
|
+
}
|
|
156
|
+
else if (!isUndefined(data)) {
|
|
157
|
+
fs.retry.writeSync(timeout)(fd, data, 0, data.length, 0);
|
|
144
158
|
}
|
|
145
159
|
if (options.fsync !== false) {
|
|
146
160
|
if (options.fsyncWait !== false) {
|
|
147
|
-
|
|
161
|
+
fs.retry.fsyncSync(timeout)(fd);
|
|
148
162
|
}
|
|
149
163
|
else {
|
|
150
|
-
|
|
164
|
+
fs.attempt.fsync(fd);
|
|
151
165
|
}
|
|
152
166
|
}
|
|
153
|
-
|
|
167
|
+
fs.retry.closeSync(timeout)(fd);
|
|
154
168
|
fd = null;
|
|
155
|
-
if (options.chown)
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
169
|
+
if (options.chown && (options.chown.uid !== DEFAULT_USER_UID || options.chown.gid !== DEFAULT_USER_GID)) {
|
|
170
|
+
fs.attempt.chownSync(tempPath, options.chown.uid, options.chown.gid);
|
|
171
|
+
}
|
|
172
|
+
if (options.mode && options.mode !== DEFAULT_FILE_MODE) {
|
|
173
|
+
fs.attempt.chmodSync(tempPath, options.mode);
|
|
174
|
+
}
|
|
159
175
|
try {
|
|
160
|
-
|
|
176
|
+
fs.retry.renameSync(timeout)(tempPath, filePath);
|
|
161
177
|
}
|
|
162
178
|
catch (error) {
|
|
179
|
+
if (!isException(error))
|
|
180
|
+
throw error;
|
|
163
181
|
if (error.code !== 'ENAMETOOLONG')
|
|
164
182
|
throw error;
|
|
165
|
-
|
|
183
|
+
fs.retry.renameSync(timeout)(tempPath, Temp.truncate(filePath));
|
|
166
184
|
}
|
|
167
185
|
tempDisposer();
|
|
168
186
|
tempPath = null;
|
|
169
187
|
}
|
|
170
188
|
finally {
|
|
171
189
|
if (fd)
|
|
172
|
-
|
|
190
|
+
fs.attempt.closeSync(fd);
|
|
173
191
|
if (tempPath)
|
|
174
|
-
|
|
192
|
+
Temp.purge(tempPath);
|
|
175
193
|
}
|
|
176
|
-
}
|
|
177
|
-
|
|
194
|
+
}
|
|
195
|
+
/* EXPORT */
|
|
196
|
+
export { readFile, readFileSync, writeFile, writeFileSync };
|
package/dist/types.d.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
encoding?:
|
|
2
|
+
type Callback = (error: Exception | void) => void;
|
|
3
|
+
type Data = Uint8Array | string | undefined;
|
|
4
|
+
type Disposer = () => void;
|
|
5
|
+
type Encoding = 'ascii' | 'base64' | 'binary' | 'hex' | 'latin1' | 'utf8' | 'utf-8' | 'utf16le' | 'ucs2' | 'ucs-2';
|
|
6
|
+
type Exception = NodeJS.ErrnoException;
|
|
7
|
+
type Path = string;
|
|
8
|
+
type ReadOptions = {
|
|
9
|
+
encoding?: Encoding | null;
|
|
10
10
|
mode?: string | number | false;
|
|
11
11
|
timeout?: number;
|
|
12
12
|
};
|
|
13
|
-
|
|
13
|
+
type WriteOptions = {
|
|
14
14
|
chown?: {
|
|
15
15
|
gid: number;
|
|
16
16
|
uid: number;
|
|
17
17
|
} | false;
|
|
18
|
-
encoding?:
|
|
18
|
+
encoding?: Encoding | null;
|
|
19
19
|
fsync?: boolean;
|
|
20
20
|
fsyncWait?: boolean;
|
|
21
21
|
mode?: string | number | false;
|
|
22
22
|
schedule?: (filePath: string) => Promise<Disposer>;
|
|
23
23
|
timeout?: number;
|
|
24
24
|
tmpCreate?: (filePath: string) => string;
|
|
25
|
-
tmpCreated?: (filePath: string) =>
|
|
25
|
+
tmpCreated?: (filePath: string) => void;
|
|
26
26
|
tmpPurge?: boolean;
|
|
27
27
|
};
|
|
28
|
-
export { Callback, Data, Disposer,
|
|
28
|
+
export type { Callback, Data, Disposer, Encoding, Exception, Path, ReadOptions, WriteOptions };
|
package/dist/types.js
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
/* MAIN */
|
|
2
|
+
export {};
|
package/dist/utils/lang.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
declare const isException: (value: unknown) => value is NodeJS.ErrnoException;
|
|
3
|
+
declare const isFunction: (value: unknown) => value is Function;
|
|
4
|
+
declare const isString: (value: unknown) => value is string;
|
|
5
|
+
declare const isUndefined: (value: unknown) => value is undefined;
|
|
6
|
+
export { isException, isFunction, isString, isUndefined };
|
package/dist/utils/lang.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
/*
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
/* IMPORT */
|
|
2
|
+
/* MAIN */
|
|
3
|
+
const isException = (value) => {
|
|
4
|
+
return (value instanceof Error) && ('code' in value);
|
|
5
|
+
};
|
|
6
|
+
const isFunction = (value) => {
|
|
7
|
+
return (typeof value === 'function');
|
|
8
|
+
};
|
|
9
|
+
const isString = (value) => {
|
|
10
|
+
return (typeof value === 'string');
|
|
11
|
+
};
|
|
12
|
+
const isUndefined = (value) => {
|
|
13
|
+
return (value === undefined);
|
|
14
14
|
};
|
|
15
15
|
/* EXPORT */
|
|
16
|
-
|
|
16
|
+
export { isException, isFunction, isString, isUndefined };
|
package/dist/utils/scheduler.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/* IMPORT */
|
|
3
|
-
|
|
4
|
-
/* VARIABLES */
|
|
2
|
+
/* HELPERS */
|
|
5
3
|
const Queues = {};
|
|
6
|
-
/*
|
|
4
|
+
/* MAIN */
|
|
7
5
|
//TODO: Maybe publish this as a standalone package
|
|
8
6
|
const Scheduler = {
|
|
7
|
+
/* API */
|
|
9
8
|
next: (id) => {
|
|
10
9
|
const queue = Queues[id];
|
|
11
10
|
if (!queue)
|
|
@@ -32,4 +31,4 @@ const Scheduler = {
|
|
|
32
31
|
}
|
|
33
32
|
};
|
|
34
33
|
/* EXPORT */
|
|
35
|
-
|
|
34
|
+
export default Scheduler;
|
package/dist/utils/temp.d.ts
CHANGED
package/dist/utils/temp.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/* IMPORT */
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/*
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'stubborn-fs';
|
|
4
|
+
import whenExit from 'when-exit';
|
|
5
|
+
import { LIMIT_BASENAME_LENGTH } from '../constants.js';
|
|
6
|
+
/* MAIN */
|
|
8
7
|
//TODO: Maybe publish this as a standalone package
|
|
9
8
|
const Temp = {
|
|
9
|
+
/* VARIABLES */
|
|
10
10
|
store: {},
|
|
11
|
+
/* API */
|
|
11
12
|
create: (filePath) => {
|
|
12
|
-
const randomness = `000000${Math.floor(Math.random() * 16777215).toString(16)}`.slice(-6)
|
|
13
|
-
timestamp = Date.now().toString().slice(-10)
|
|
14
|
-
prefix = 'tmp-'
|
|
13
|
+
const randomness = `000000${Math.floor(Math.random() * 16777215).toString(16)}`.slice(-6); // 6 random-enough hex characters
|
|
14
|
+
const timestamp = Date.now().toString().slice(-10); // 10 precise timestamp digits
|
|
15
|
+
const prefix = 'tmp-';
|
|
16
|
+
const suffix = `.${prefix}${timestamp}${randomness}`;
|
|
17
|
+
const tempPath = `${filePath}${suffix}`;
|
|
15
18
|
return tempPath;
|
|
16
19
|
},
|
|
17
20
|
get: (filePath, creator, purge = true) => {
|
|
@@ -26,13 +29,13 @@ const Temp = {
|
|
|
26
29
|
if (!Temp.store[filePath])
|
|
27
30
|
return;
|
|
28
31
|
delete Temp.store[filePath];
|
|
29
|
-
|
|
32
|
+
fs.attempt.unlink(filePath);
|
|
30
33
|
},
|
|
31
34
|
purgeSync: (filePath) => {
|
|
32
35
|
if (!Temp.store[filePath])
|
|
33
36
|
return;
|
|
34
37
|
delete Temp.store[filePath];
|
|
35
|
-
|
|
38
|
+
fs.attempt.unlinkSync(filePath);
|
|
36
39
|
},
|
|
37
40
|
purgeSyncAll: () => {
|
|
38
41
|
for (const filePath in Temp.store) {
|
|
@@ -41,16 +44,16 @@ const Temp = {
|
|
|
41
44
|
},
|
|
42
45
|
truncate: (filePath) => {
|
|
43
46
|
const basename = path.basename(filePath);
|
|
44
|
-
if (basename.length <=
|
|
47
|
+
if (basename.length <= LIMIT_BASENAME_LENGTH)
|
|
45
48
|
return filePath; //FIXME: Rough and quick attempt at detecting ok lengths
|
|
46
49
|
const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(basename);
|
|
47
50
|
if (!truncable)
|
|
48
51
|
return filePath; //FIXME: No truncable part detected, can't really do much without also changing the parent path, which is unsafe, hoping for the best here
|
|
49
|
-
const truncationLength = basename.length -
|
|
52
|
+
const truncationLength = basename.length - LIMIT_BASENAME_LENGTH;
|
|
50
53
|
return `${filePath.slice(0, -basename.length)}${truncable[1]}${truncable[2].slice(0, -truncationLength)}${truncable[3]}`; //FIXME: The truncable part might be shorter than needed here
|
|
51
54
|
}
|
|
52
55
|
};
|
|
53
56
|
/* INIT */
|
|
54
|
-
|
|
57
|
+
whenExit(Temp.purgeSyncAll); // Ensuring purgeable temp files are purged on exit
|
|
55
58
|
/* EXPORT */
|
|
56
|
-
|
|
59
|
+
export default Temp;
|
package/{LICENSE → license}
RENAMED
|
File without changes
|