@hanzo/s3 0.6.4 → 8.0.7
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/LICENSE +202 -0
- package/MAINTAINERS.md +62 -0
- package/README.md +262 -0
- package/README_zh_CN.md +192 -0
- package/dist/esm/AssumeRoleProvider.d.mts +86 -0
- package/dist/esm/AssumeRoleProvider.mjs +183 -0
- package/dist/esm/CredentialProvider.d.mts +22 -0
- package/dist/esm/CredentialProvider.mjs +48 -0
- package/dist/esm/Credentials.d.mts +22 -0
- package/dist/esm/Credentials.mjs +38 -0
- package/dist/esm/IamAwsProvider.d.mts +27 -0
- package/dist/esm/IamAwsProvider.mjs +189 -0
- package/dist/esm/errors.d.mts +82 -0
- package/dist/esm/errors.mjs +117 -0
- package/dist/esm/helpers.d.mts +156 -0
- package/dist/esm/helpers.mjs +218 -0
- package/dist/esm/internal/async.d.mts +9 -0
- package/dist/esm/internal/async.mjs +14 -0
- package/dist/esm/internal/callbackify.d.mts +1 -0
- package/dist/esm/internal/callbackify.mjs +15 -0
- package/dist/esm/internal/client.d.mts +394 -0
- package/dist/esm/internal/client.mjs +3007 -0
- package/dist/esm/internal/copy-conditions.d.mts +10 -0
- package/dist/esm/internal/copy-conditions.mjs +25 -0
- package/dist/esm/internal/extensions.d.mts +18 -0
- package/dist/esm/internal/extensions.mjs +114 -0
- package/dist/esm/internal/helper.d.mts +177 -0
- package/dist/esm/internal/helper.mjs +552 -0
- package/dist/esm/internal/join-host-port.d.mts +11 -0
- package/dist/esm/internal/join-host-port.mjs +23 -0
- package/dist/esm/internal/post-policy.d.mts +17 -0
- package/dist/esm/internal/post-policy.mjs +98 -0
- package/dist/esm/internal/request.d.mts +11 -0
- package/dist/esm/internal/request.mjs +75 -0
- package/dist/esm/internal/response.d.mts +8 -0
- package/dist/esm/internal/response.mjs +16 -0
- package/dist/esm/internal/s3-endpoints.d.mts +38 -0
- package/dist/esm/internal/s3-endpoints.mjs +68 -0
- package/dist/esm/internal/type.d.mts +482 -0
- package/dist/esm/internal/type.mjs +30 -0
- package/dist/esm/internal/xml-parser.d.mts +93 -0
- package/dist/esm/internal/xml-parser.mjs +819 -0
- package/dist/esm/notification.d.mts +58 -0
- package/dist/esm/notification.mjs +209 -0
- package/dist/esm/s3.d.mts +40 -0
- package/dist/esm/s3.mjs +86 -0
- package/dist/esm/signing.d.mts +5 -0
- package/dist/esm/signing.mjs +258 -0
- package/dist/main/AssumeRoleProvider.d.ts +86 -0
- package/dist/main/AssumeRoleProvider.js +191 -0
- package/dist/main/CredentialProvider.d.ts +22 -0
- package/dist/main/CredentialProvider.js +55 -0
- package/dist/main/Credentials.d.ts +22 -0
- package/dist/main/Credentials.js +45 -0
- package/dist/main/IamAwsProvider.d.ts +27 -0
- package/dist/main/IamAwsProvider.js +198 -0
- package/dist/main/errors.d.ts +82 -0
- package/dist/main/errors.js +138 -0
- package/dist/main/helpers.d.ts +156 -0
- package/dist/main/helpers.js +233 -0
- package/dist/main/internal/async.d.ts +9 -0
- package/dist/main/internal/async.js +24 -0
- package/dist/main/internal/callbackify.d.ts +1 -0
- package/dist/main/internal/callbackify.js +21 -0
- package/dist/main/internal/client.d.ts +394 -0
- package/dist/main/internal/client.js +3014 -0
- package/dist/main/internal/copy-conditions.d.ts +10 -0
- package/dist/main/internal/copy-conditions.js +31 -0
- package/dist/main/internal/extensions.d.ts +18 -0
- package/dist/main/internal/extensions.js +122 -0
- package/dist/main/internal/helper.d.ts +177 -0
- package/dist/main/internal/helper.js +608 -0
- package/dist/main/internal/join-host-port.d.ts +11 -0
- package/dist/main/internal/join-host-port.js +29 -0
- package/dist/main/internal/post-policy.d.ts +17 -0
- package/dist/main/internal/post-policy.js +107 -0
- package/dist/main/internal/request.d.ts +11 -0
- package/dist/main/internal/request.js +83 -0
- package/dist/main/internal/response.d.ts +8 -0
- package/dist/main/internal/response.js +24 -0
- package/dist/main/internal/s3-endpoints.d.ts +38 -0
- package/dist/main/internal/s3-endpoints.js +73 -0
- package/dist/main/internal/type.d.ts +482 -0
- package/dist/main/internal/type.js +42 -0
- package/dist/main/internal/xml-parser.d.ts +93 -0
- package/dist/main/internal/xml-parser.js +849 -0
- package/dist/main/notification.d.ts +58 -0
- package/dist/main/notification.js +230 -0
- package/dist/main/s3.d.ts +40 -0
- package/dist/main/s3.js +117 -0
- package/dist/main/signing.d.ts +5 -0
- package/dist/main/signing.js +269 -0
- package/package.json +146 -39
- package/src/AssumeRoleProvider.ts +262 -0
- package/src/CredentialProvider.ts +54 -0
- package/src/Credentials.ts +44 -0
- package/src/IamAwsProvider.ts +234 -0
- package/src/errors.ts +120 -0
- package/src/helpers.ts +354 -0
- package/src/internal/async.ts +14 -0
- package/src/internal/callbackify.ts +19 -0
- package/src/internal/client.ts +3412 -0
- package/src/internal/copy-conditions.ts +30 -0
- package/src/internal/extensions.ts +140 -0
- package/src/internal/helper.ts +606 -0
- package/src/internal/join-host-port.ts +23 -0
- package/src/internal/post-policy.ts +99 -0
- package/src/internal/request.ts +102 -0
- package/src/internal/response.ts +26 -0
- package/src/internal/s3-endpoints.ts +70 -0
- package/src/internal/type.ts +577 -0
- package/src/internal/xml-parser.ts +871 -0
- package/src/notification.ts +254 -0
- package/src/s3.ts +155 -0
- package/src/signing.ts +325 -0
- package/lib/index.js +0 -450
- package/lib/index.js.map +0 -7
- package/lib/perfTest.js +0 -91
- package/lib/perfTest.js.map +0 -7
package/src/helpers.ts
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
import * as path from 'node:path'
|
|
3
|
+
|
|
4
|
+
import * as querystring from 'query-string'
|
|
5
|
+
|
|
6
|
+
import * as errors from './errors.ts'
|
|
7
|
+
import {
|
|
8
|
+
getEncryptionHeaders,
|
|
9
|
+
isEmpty,
|
|
10
|
+
isEmptyObject,
|
|
11
|
+
isNumber,
|
|
12
|
+
isObject,
|
|
13
|
+
isString,
|
|
14
|
+
isValidBucketName,
|
|
15
|
+
isValidObjectName,
|
|
16
|
+
} from './internal/helper.ts'
|
|
17
|
+
import type { Encryption, ObjectMetaData, RequestHeaders } from './internal/type.ts'
|
|
18
|
+
import { RETENTION_MODES } from './internal/type.ts'
|
|
19
|
+
|
|
20
|
+
export { ENCRYPTION_TYPES, LEGAL_HOLD_STATUS, RETENTION_MODES, RETENTION_VALIDITY_UNITS } from './internal/type.ts'
|
|
21
|
+
|
|
22
|
+
export const DEFAULT_REGION = 'us-east-1'
|
|
23
|
+
|
|
24
|
+
export const PRESIGN_EXPIRY_DAYS_MAX = 24 * 60 * 60 * 7 // 7 days in seconds
|
|
25
|
+
|
|
26
|
+
export interface ICopySourceOptions {
|
|
27
|
+
Bucket: string
|
|
28
|
+
Object: string
|
|
29
|
+
/**
|
|
30
|
+
* Valid versionId
|
|
31
|
+
*/
|
|
32
|
+
VersionID?: string
|
|
33
|
+
/**
|
|
34
|
+
* Etag to match
|
|
35
|
+
*/
|
|
36
|
+
MatchETag?: string
|
|
37
|
+
/**
|
|
38
|
+
* Etag to exclude
|
|
39
|
+
*/
|
|
40
|
+
NoMatchETag?: string
|
|
41
|
+
/**
|
|
42
|
+
* Modified Date of the object/part. UTC Date in string format
|
|
43
|
+
*/
|
|
44
|
+
MatchModifiedSince?: string | null
|
|
45
|
+
/**
|
|
46
|
+
* Modified Date of the object/part to exclude UTC Date in string format
|
|
47
|
+
*/
|
|
48
|
+
MatchUnmodifiedSince?: string | null
|
|
49
|
+
/**
|
|
50
|
+
* true or false Object range to match
|
|
51
|
+
*/
|
|
52
|
+
MatchRange?: boolean
|
|
53
|
+
Start?: number
|
|
54
|
+
End?: number
|
|
55
|
+
Encryption?: Encryption
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class CopySourceOptions {
|
|
59
|
+
public readonly Bucket: string
|
|
60
|
+
public readonly Object: string
|
|
61
|
+
public readonly VersionID: string
|
|
62
|
+
public MatchETag: string
|
|
63
|
+
private readonly NoMatchETag: string
|
|
64
|
+
private readonly MatchModifiedSince: string | null
|
|
65
|
+
private readonly MatchUnmodifiedSince: string | null
|
|
66
|
+
public readonly MatchRange: boolean
|
|
67
|
+
public readonly Start: number
|
|
68
|
+
public readonly End: number
|
|
69
|
+
private readonly Encryption?: Encryption
|
|
70
|
+
|
|
71
|
+
constructor({
|
|
72
|
+
Bucket,
|
|
73
|
+
Object,
|
|
74
|
+
VersionID = '',
|
|
75
|
+
MatchETag = '',
|
|
76
|
+
NoMatchETag = '',
|
|
77
|
+
MatchModifiedSince = null,
|
|
78
|
+
MatchUnmodifiedSince = null,
|
|
79
|
+
MatchRange = false,
|
|
80
|
+
Start = 0,
|
|
81
|
+
End = 0,
|
|
82
|
+
Encryption = undefined,
|
|
83
|
+
}: ICopySourceOptions) {
|
|
84
|
+
this.Bucket = Bucket
|
|
85
|
+
this.Object = Object
|
|
86
|
+
this.VersionID = VersionID
|
|
87
|
+
this.MatchETag = MatchETag
|
|
88
|
+
this.NoMatchETag = NoMatchETag
|
|
89
|
+
this.MatchModifiedSince = MatchModifiedSince
|
|
90
|
+
this.MatchUnmodifiedSince = MatchUnmodifiedSince
|
|
91
|
+
this.MatchRange = MatchRange
|
|
92
|
+
this.Start = Start
|
|
93
|
+
this.End = End
|
|
94
|
+
this.Encryption = Encryption
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
validate() {
|
|
98
|
+
if (!isValidBucketName(this.Bucket)) {
|
|
99
|
+
throw new errors.InvalidBucketNameError('Invalid Source bucket name: ' + this.Bucket)
|
|
100
|
+
}
|
|
101
|
+
if (!isValidObjectName(this.Object)) {
|
|
102
|
+
throw new errors.InvalidObjectNameError(`Invalid Source object name: ${this.Object}`)
|
|
103
|
+
}
|
|
104
|
+
if ((this.MatchRange && this.Start !== -1 && this.End !== -1 && this.Start > this.End) || this.Start < 0) {
|
|
105
|
+
throw new errors.InvalidObjectNameError('Source start must be non-negative, and start must be at most end.')
|
|
106
|
+
} else if ((this.MatchRange && !isNumber(this.Start)) || !isNumber(this.End)) {
|
|
107
|
+
throw new errors.InvalidObjectNameError(
|
|
108
|
+
'MatchRange is specified. But Invalid Start and End values are specified.',
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return true
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
getHeaders(): RequestHeaders {
|
|
116
|
+
const headerOptions: RequestHeaders = {}
|
|
117
|
+
headerOptions['x-amz-copy-source'] = encodeURI(this.Bucket + '/' + this.Object)
|
|
118
|
+
|
|
119
|
+
if (!isEmpty(this.VersionID)) {
|
|
120
|
+
headerOptions['x-amz-copy-source'] = `${encodeURI(this.Bucket + '/' + this.Object)}?versionId=${this.VersionID}`
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (!isEmpty(this.MatchETag)) {
|
|
124
|
+
headerOptions['x-amz-copy-source-if-match'] = this.MatchETag
|
|
125
|
+
}
|
|
126
|
+
if (!isEmpty(this.NoMatchETag)) {
|
|
127
|
+
headerOptions['x-amz-copy-source-if-none-match'] = this.NoMatchETag
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!isEmpty(this.MatchModifiedSince)) {
|
|
131
|
+
headerOptions['x-amz-copy-source-if-modified-since'] = this.MatchModifiedSince
|
|
132
|
+
}
|
|
133
|
+
if (!isEmpty(this.MatchUnmodifiedSince)) {
|
|
134
|
+
headerOptions['x-amz-copy-source-if-unmodified-since'] = this.MatchUnmodifiedSince
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return headerOptions
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @deprecated use nodejs fs module
|
|
143
|
+
*/
|
|
144
|
+
export function removeDirAndFiles(dirPath: string, removeSelf = true) {
|
|
145
|
+
if (removeSelf) {
|
|
146
|
+
return fs.rmSync(dirPath, { recursive: true, force: true })
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
fs.readdirSync(dirPath).forEach((item) => {
|
|
150
|
+
fs.rmSync(path.join(dirPath, item), { recursive: true, force: true })
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface ICopyDestinationOptions {
|
|
155
|
+
/**
|
|
156
|
+
* Bucket name
|
|
157
|
+
*/
|
|
158
|
+
Bucket: string
|
|
159
|
+
/**
|
|
160
|
+
* Object Name for the destination (composed/copied) object defaults
|
|
161
|
+
*/
|
|
162
|
+
Object: string
|
|
163
|
+
/**
|
|
164
|
+
* Encryption configuration defaults to {}
|
|
165
|
+
* @default {}
|
|
166
|
+
*/
|
|
167
|
+
Encryption?: Encryption
|
|
168
|
+
UserMetadata?: ObjectMetaData
|
|
169
|
+
/**
|
|
170
|
+
* query-string encoded string or Record<string, string> Object
|
|
171
|
+
*/
|
|
172
|
+
UserTags?: Record<string, string> | string
|
|
173
|
+
LegalHold?: 'on' | 'off'
|
|
174
|
+
/**
|
|
175
|
+
* UTC Date String
|
|
176
|
+
*/
|
|
177
|
+
RetainUntilDate?: string
|
|
178
|
+
Mode?: RETENTION_MODES
|
|
179
|
+
MetadataDirective?: 'COPY' | 'REPLACE'
|
|
180
|
+
/**
|
|
181
|
+
* Extra headers for the target object
|
|
182
|
+
*/
|
|
183
|
+
Headers?: Record<string, string>
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export class CopyDestinationOptions {
|
|
187
|
+
public readonly Bucket: string
|
|
188
|
+
public readonly Object: string
|
|
189
|
+
private readonly Encryption?: Encryption
|
|
190
|
+
private readonly UserMetadata?: ObjectMetaData
|
|
191
|
+
private readonly UserTags?: Record<string, string> | string
|
|
192
|
+
private readonly LegalHold?: 'on' | 'off'
|
|
193
|
+
private readonly RetainUntilDate?: string
|
|
194
|
+
private readonly Mode?: RETENTION_MODES
|
|
195
|
+
private readonly MetadataDirective?: string
|
|
196
|
+
private readonly Headers?: Record<string, string>
|
|
197
|
+
|
|
198
|
+
constructor({
|
|
199
|
+
Bucket,
|
|
200
|
+
Object,
|
|
201
|
+
Encryption,
|
|
202
|
+
UserMetadata,
|
|
203
|
+
UserTags,
|
|
204
|
+
LegalHold,
|
|
205
|
+
RetainUntilDate,
|
|
206
|
+
Mode,
|
|
207
|
+
MetadataDirective,
|
|
208
|
+
Headers,
|
|
209
|
+
}: ICopyDestinationOptions) {
|
|
210
|
+
this.Bucket = Bucket
|
|
211
|
+
this.Object = Object
|
|
212
|
+
this.Encryption = Encryption ?? undefined // null input will become undefined, easy for runtime assert
|
|
213
|
+
this.UserMetadata = UserMetadata
|
|
214
|
+
this.UserTags = UserTags
|
|
215
|
+
this.LegalHold = LegalHold
|
|
216
|
+
this.Mode = Mode // retention mode
|
|
217
|
+
this.RetainUntilDate = RetainUntilDate
|
|
218
|
+
this.MetadataDirective = MetadataDirective
|
|
219
|
+
this.Headers = Headers
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
getHeaders(): RequestHeaders {
|
|
223
|
+
const replaceDirective = 'REPLACE'
|
|
224
|
+
const headerOptions: RequestHeaders = {}
|
|
225
|
+
|
|
226
|
+
const userTags = this.UserTags
|
|
227
|
+
if (!isEmpty(userTags)) {
|
|
228
|
+
headerOptions['X-Amz-Tagging-Directive'] = replaceDirective
|
|
229
|
+
headerOptions['X-Amz-Tagging'] = isObject(userTags)
|
|
230
|
+
? querystring.stringify(userTags)
|
|
231
|
+
: isString(userTags)
|
|
232
|
+
? userTags
|
|
233
|
+
: ''
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (this.Mode) {
|
|
237
|
+
headerOptions['X-Amz-Object-Lock-Mode'] = this.Mode // GOVERNANCE or COMPLIANCE
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (this.RetainUntilDate) {
|
|
241
|
+
headerOptions['X-Amz-Object-Lock-Retain-Until-Date'] = this.RetainUntilDate // needs to be UTC.
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (this.LegalHold) {
|
|
245
|
+
headerOptions['X-Amz-Object-Lock-Legal-Hold'] = this.LegalHold // ON or OFF
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (this.UserMetadata) {
|
|
249
|
+
for (const [key, value] of Object.entries(this.UserMetadata)) {
|
|
250
|
+
headerOptions[`X-Amz-Meta-${key}`] = value.toString()
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (this.MetadataDirective) {
|
|
255
|
+
headerOptions[`X-Amz-Metadata-Directive`] = this.MetadataDirective
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (this.Encryption) {
|
|
259
|
+
const encryptionHeaders = getEncryptionHeaders(this.Encryption)
|
|
260
|
+
for (const [key, value] of Object.entries(encryptionHeaders)) {
|
|
261
|
+
headerOptions[key] = value
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (this.Headers) {
|
|
265
|
+
for (const [key, value] of Object.entries(this.Headers)) {
|
|
266
|
+
headerOptions[key] = value
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return headerOptions
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
validate() {
|
|
274
|
+
if (!isValidBucketName(this.Bucket)) {
|
|
275
|
+
throw new errors.InvalidBucketNameError('Invalid Destination bucket name: ' + this.Bucket)
|
|
276
|
+
}
|
|
277
|
+
if (!isValidObjectName(this.Object)) {
|
|
278
|
+
throw new errors.InvalidObjectNameError(`Invalid Destination object name: ${this.Object}`)
|
|
279
|
+
}
|
|
280
|
+
if (!isEmpty(this.UserMetadata) && !isObject(this.UserMetadata)) {
|
|
281
|
+
throw new errors.InvalidObjectNameError(`Destination UserMetadata should be an object with key value pairs`)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!isEmpty(this.Mode) && ![RETENTION_MODES.GOVERNANCE, RETENTION_MODES.COMPLIANCE].includes(this.Mode)) {
|
|
285
|
+
throw new errors.InvalidObjectNameError(
|
|
286
|
+
`Invalid Mode specified for destination object it should be one of [GOVERNANCE,COMPLIANCE]`,
|
|
287
|
+
)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (this.Encryption !== undefined && isEmptyObject(this.Encryption)) {
|
|
291
|
+
throw new errors.InvalidObjectNameError(`Invalid Encryption configuration for destination object `)
|
|
292
|
+
}
|
|
293
|
+
return true
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* maybe this should be a generic type for Records, leave it for later refactor
|
|
299
|
+
*/
|
|
300
|
+
export class SelectResults {
|
|
301
|
+
private records?: unknown
|
|
302
|
+
private response?: unknown
|
|
303
|
+
private stats?: string
|
|
304
|
+
private progress?: unknown
|
|
305
|
+
|
|
306
|
+
constructor({
|
|
307
|
+
records, // parsed data as stream
|
|
308
|
+
response, // original response stream
|
|
309
|
+
stats, // stats as xml
|
|
310
|
+
progress, // stats as xml
|
|
311
|
+
}: {
|
|
312
|
+
records?: unknown
|
|
313
|
+
response?: unknown
|
|
314
|
+
stats?: string
|
|
315
|
+
progress?: unknown
|
|
316
|
+
}) {
|
|
317
|
+
this.records = records
|
|
318
|
+
this.response = response
|
|
319
|
+
this.stats = stats
|
|
320
|
+
this.progress = progress
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
setStats(stats: string) {
|
|
324
|
+
this.stats = stats
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
getStats() {
|
|
328
|
+
return this.stats
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
setProgress(progress: unknown) {
|
|
332
|
+
this.progress = progress
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
getProgress() {
|
|
336
|
+
return this.progress
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
setResponse(response: unknown) {
|
|
340
|
+
this.response = response
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
getResponse() {
|
|
344
|
+
return this.response
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
setRecords(records: unknown) {
|
|
348
|
+
this.records = records
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
getRecords(): unknown {
|
|
352
|
+
return this.records
|
|
353
|
+
}
|
|
354
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// promise helper for stdlib
|
|
2
|
+
|
|
3
|
+
import * as fs from 'node:fs'
|
|
4
|
+
import * as stream from 'node:stream'
|
|
5
|
+
import { promisify } from 'node:util'
|
|
6
|
+
|
|
7
|
+
// TODO: use "node:fs/promise" directly after we stop testing on nodejs 12
|
|
8
|
+
export { promises as fsp } from 'node:fs'
|
|
9
|
+
export const streamPromise = {
|
|
10
|
+
// node:stream/promises Added in: v15.0.0
|
|
11
|
+
pipeline: promisify(stream.pipeline),
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const fstat = promisify(fs.fstat)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
// Wrapper for an async function that supports callback style API.
|
|
4
|
+
// It will preserve 'this'.
|
|
5
|
+
export function callbackify(fn: (...args: any[]) => any) {
|
|
6
|
+
return function (this: any, ...args: any[]) {
|
|
7
|
+
const lastArg = args[args.length - 1]
|
|
8
|
+
|
|
9
|
+
if (typeof lastArg === 'function') {
|
|
10
|
+
const callback = args.pop()
|
|
11
|
+
return fn.apply(this, args).then(
|
|
12
|
+
(result: any) => callback(null, result),
|
|
13
|
+
(err: any) => callback(err),
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return fn.apply(this, args)
|
|
18
|
+
}
|
|
19
|
+
}
|