@hanzo/s3 0.6.3 → 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.
Files changed (119) hide show
  1. package/LICENSE +202 -0
  2. package/MAINTAINERS.md +62 -0
  3. package/README.md +262 -0
  4. package/README_zh_CN.md +192 -0
  5. package/dist/esm/AssumeRoleProvider.d.mts +86 -0
  6. package/dist/esm/AssumeRoleProvider.mjs +183 -0
  7. package/dist/esm/CredentialProvider.d.mts +22 -0
  8. package/dist/esm/CredentialProvider.mjs +48 -0
  9. package/dist/esm/Credentials.d.mts +22 -0
  10. package/dist/esm/Credentials.mjs +38 -0
  11. package/dist/esm/IamAwsProvider.d.mts +27 -0
  12. package/dist/esm/IamAwsProvider.mjs +189 -0
  13. package/dist/esm/errors.d.mts +82 -0
  14. package/dist/esm/errors.mjs +117 -0
  15. package/dist/esm/helpers.d.mts +156 -0
  16. package/dist/esm/helpers.mjs +218 -0
  17. package/dist/esm/internal/async.d.mts +9 -0
  18. package/dist/esm/internal/async.mjs +14 -0
  19. package/dist/esm/internal/callbackify.d.mts +1 -0
  20. package/dist/esm/internal/callbackify.mjs +15 -0
  21. package/dist/esm/internal/client.d.mts +394 -0
  22. package/dist/esm/internal/client.mjs +3007 -0
  23. package/dist/esm/internal/copy-conditions.d.mts +10 -0
  24. package/dist/esm/internal/copy-conditions.mjs +25 -0
  25. package/dist/esm/internal/extensions.d.mts +18 -0
  26. package/dist/esm/internal/extensions.mjs +114 -0
  27. package/dist/esm/internal/helper.d.mts +177 -0
  28. package/dist/esm/internal/helper.mjs +552 -0
  29. package/dist/esm/internal/join-host-port.d.mts +11 -0
  30. package/dist/esm/internal/join-host-port.mjs +23 -0
  31. package/dist/esm/internal/post-policy.d.mts +17 -0
  32. package/dist/esm/internal/post-policy.mjs +98 -0
  33. package/dist/esm/internal/request.d.mts +11 -0
  34. package/dist/esm/internal/request.mjs +75 -0
  35. package/dist/esm/internal/response.d.mts +8 -0
  36. package/dist/esm/internal/response.mjs +16 -0
  37. package/dist/esm/internal/s3-endpoints.d.mts +38 -0
  38. package/dist/esm/internal/s3-endpoints.mjs +68 -0
  39. package/dist/esm/internal/type.d.mts +482 -0
  40. package/dist/esm/internal/type.mjs +30 -0
  41. package/dist/esm/internal/xml-parser.d.mts +93 -0
  42. package/dist/esm/internal/xml-parser.mjs +819 -0
  43. package/dist/esm/notification.d.mts +58 -0
  44. package/dist/esm/notification.mjs +209 -0
  45. package/dist/esm/s3.d.mts +40 -0
  46. package/dist/esm/s3.mjs +86 -0
  47. package/dist/esm/signing.d.mts +5 -0
  48. package/dist/esm/signing.mjs +258 -0
  49. package/dist/main/AssumeRoleProvider.d.ts +86 -0
  50. package/dist/main/AssumeRoleProvider.js +191 -0
  51. package/dist/main/CredentialProvider.d.ts +22 -0
  52. package/dist/main/CredentialProvider.js +55 -0
  53. package/dist/main/Credentials.d.ts +22 -0
  54. package/dist/main/Credentials.js +45 -0
  55. package/dist/main/IamAwsProvider.d.ts +27 -0
  56. package/dist/main/IamAwsProvider.js +198 -0
  57. package/dist/main/errors.d.ts +82 -0
  58. package/dist/main/errors.js +138 -0
  59. package/dist/main/helpers.d.ts +156 -0
  60. package/dist/main/helpers.js +233 -0
  61. package/dist/main/internal/async.d.ts +9 -0
  62. package/dist/main/internal/async.js +24 -0
  63. package/dist/main/internal/callbackify.d.ts +1 -0
  64. package/dist/main/internal/callbackify.js +21 -0
  65. package/dist/main/internal/client.d.ts +394 -0
  66. package/dist/main/internal/client.js +3014 -0
  67. package/dist/main/internal/copy-conditions.d.ts +10 -0
  68. package/dist/main/internal/copy-conditions.js +31 -0
  69. package/dist/main/internal/extensions.d.ts +18 -0
  70. package/dist/main/internal/extensions.js +122 -0
  71. package/dist/main/internal/helper.d.ts +177 -0
  72. package/dist/main/internal/helper.js +608 -0
  73. package/dist/main/internal/join-host-port.d.ts +11 -0
  74. package/dist/main/internal/join-host-port.js +29 -0
  75. package/dist/main/internal/post-policy.d.ts +17 -0
  76. package/dist/main/internal/post-policy.js +107 -0
  77. package/dist/main/internal/request.d.ts +11 -0
  78. package/dist/main/internal/request.js +83 -0
  79. package/dist/main/internal/response.d.ts +8 -0
  80. package/dist/main/internal/response.js +24 -0
  81. package/dist/main/internal/s3-endpoints.d.ts +38 -0
  82. package/dist/main/internal/s3-endpoints.js +73 -0
  83. package/dist/main/internal/type.d.ts +482 -0
  84. package/dist/main/internal/type.js +42 -0
  85. package/dist/main/internal/xml-parser.d.ts +93 -0
  86. package/dist/main/internal/xml-parser.js +849 -0
  87. package/dist/main/notification.d.ts +58 -0
  88. package/dist/main/notification.js +230 -0
  89. package/dist/main/s3.d.ts +40 -0
  90. package/dist/main/s3.js +117 -0
  91. package/dist/main/signing.d.ts +5 -0
  92. package/dist/main/signing.js +269 -0
  93. package/package.json +146 -39
  94. package/src/AssumeRoleProvider.ts +262 -0
  95. package/src/CredentialProvider.ts +54 -0
  96. package/src/Credentials.ts +44 -0
  97. package/src/IamAwsProvider.ts +234 -0
  98. package/src/errors.ts +120 -0
  99. package/src/helpers.ts +354 -0
  100. package/src/internal/async.ts +14 -0
  101. package/src/internal/callbackify.ts +19 -0
  102. package/src/internal/client.ts +3412 -0
  103. package/src/internal/copy-conditions.ts +30 -0
  104. package/src/internal/extensions.ts +140 -0
  105. package/src/internal/helper.ts +606 -0
  106. package/src/internal/join-host-port.ts +23 -0
  107. package/src/internal/post-policy.ts +99 -0
  108. package/src/internal/request.ts +102 -0
  109. package/src/internal/response.ts +26 -0
  110. package/src/internal/s3-endpoints.ts +70 -0
  111. package/src/internal/type.ts +577 -0
  112. package/src/internal/xml-parser.ts +871 -0
  113. package/src/notification.ts +254 -0
  114. package/src/s3.ts +155 -0
  115. package/src/signing.ts +325 -0
  116. package/lib/index.js +0 -450
  117. package/lib/index.js.map +0 -7
  118. package/lib/perfTest.js +0 -91
  119. 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
+ }