Skip to content

Commit 613932c

Browse files
authored
refactor: migrate CopyConditions PostPolicy to TypeScript (#1141)
1 parent 43bef25 commit 613932c

File tree

4 files changed

+138
-163
lines changed

4 files changed

+138
-163
lines changed

src/internal/copy-conditions.ts

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
export class CopyConditions {
2+
public modified = ''
3+
public unmodified = ''
4+
public matchETag = ''
5+
public matchETagExcept = ''
6+
7+
setModified(date: Date): void {
8+
if (!(date instanceof Date)) {
9+
throw new TypeError('date must be of type Date')
10+
}
11+
12+
this.modified = date.toUTCString()
13+
}
14+
15+
setUnmodified(date: Date): void {
16+
if (!(date instanceof Date)) {
17+
throw new TypeError('date must be of type Date')
18+
}
19+
20+
this.unmodified = date.toUTCString()
21+
}
22+
23+
setMatchETag(etag: string): void {
24+
this.matchETag = etag
25+
}
26+
27+
setMatchETagExcept(etag: string): void {
28+
this.matchETagExcept = etag
29+
}
30+
}

src/internal/post-policy.ts

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Build PostPolicy object that can be signed by presignedPostPolicy
2+
import * as errors from '../errors.ts'
3+
import { isObject, isValidBucketName, isValidObjectName, isValidPrefix } from './helper.ts'
4+
import type { ObjectMetaData } from './type.ts'
5+
6+
export class PostPolicy {
7+
public policy: { conditions: (string | number)[][]; expiration?: string } = {
8+
conditions: [],
9+
}
10+
public formData: Record<string, string> = {}
11+
12+
// set expiration date
13+
setExpires(date: Date) {
14+
if (!date) {
15+
throw new errors.InvalidDateError('Invalid date: cannot be null')
16+
}
17+
this.policy.expiration = date.toISOString()
18+
}
19+
20+
// set object name
21+
setKey(objectName: string) {
22+
if (!isValidObjectName(objectName)) {
23+
throw new errors.InvalidObjectNameError(`Invalid object name : ${objectName}`)
24+
}
25+
this.policy.conditions.push(['eq', '$key', objectName])
26+
this.formData.key = objectName
27+
}
28+
29+
// set object name prefix, i.e policy allows any keys with this prefix
30+
setKeyStartsWith(prefix: string) {
31+
if (!isValidPrefix(prefix)) {
32+
throw new errors.InvalidPrefixError(`Invalid prefix : ${prefix}`)
33+
}
34+
this.policy.conditions.push(['starts-with', '$key', prefix])
35+
this.formData.key = prefix
36+
}
37+
38+
// set bucket name
39+
setBucket(bucketName: string) {
40+
if (!isValidBucketName(bucketName)) {
41+
throw new errors.InvalidBucketNameError(`Invalid bucket name : ${bucketName}`)
42+
}
43+
this.policy.conditions.push(['eq', '$bucket', bucketName])
44+
this.formData.bucket = bucketName
45+
}
46+
47+
// set Content-Type
48+
setContentType(type: string) {
49+
if (!type) {
50+
throw new Error('content-type cannot be null')
51+
}
52+
this.policy.conditions.push(['eq', '$Content-Type', type])
53+
this.formData['Content-Type'] = type
54+
}
55+
56+
// set Content-Type prefix, i.e image/ allows any image
57+
setContentTypeStartsWith(prefix: string) {
58+
if (!prefix) {
59+
throw new Error('content-type cannot be null')
60+
}
61+
this.policy.conditions.push(['starts-with', '$Content-Type', prefix])
62+
this.formData['Content-Type'] = prefix
63+
}
64+
65+
// set Content-Disposition
66+
setContentDisposition(value: string) {
67+
if (!value) {
68+
throw new Error('content-disposition cannot be null')
69+
}
70+
this.policy.conditions.push(['eq', '$Content-Disposition', value])
71+
this.formData['Content-Disposition'] = value
72+
}
73+
74+
// set minimum/maximum length of what Content-Length can be.
75+
setContentLengthRange(min: number, max: number) {
76+
if (min > max) {
77+
throw new Error('min cannot be more than max')
78+
}
79+
if (min < 0) {
80+
throw new Error('min should be > 0')
81+
}
82+
if (max < 0) {
83+
throw new Error('max should be > 0')
84+
}
85+
this.policy.conditions.push(['content-length-range', min, max])
86+
}
87+
88+
// set user defined metadata
89+
setUserMetaData(metaData: ObjectMetaData) {
90+
if (!isObject(metaData)) {
91+
throw new TypeError('metadata should be of type "object"')
92+
}
93+
Object.entries(metaData).forEach(([key, value]) => {
94+
const amzMetaDataKey = `x-amz-meta-${key}`
95+
this.policy.conditions.push(['eq', `$${amzMetaDataKey}`, value])
96+
this.formData[amzMetaDataKey] = value.toString()
97+
})
98+
}
99+
}

src/minio.d.ts

+3-30
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ import type {
1111
RETENTION_MODES,
1212
RETENTION_VALIDITY_UNITS,
1313
} from './helpers.ts'
14+
import { CopyConditions } from './internal/copy-conditions.ts'
15+
import { PostPolicy } from './internal/post-policy.ts'
1416
import type { Region } from './internal/s3-endpoints.ts'
1517
import type { Transport } from './internal/type.ts'
1618

1719
export * from './helpers.ts'
1820
export type { Region } from './internal/s3-endpoints.ts'
21+
export { CopyConditions, PostPolicy }
1922

2023
// Exports only from typings
2124
export type NotificationEvent =
@@ -663,36 +666,6 @@ export class Client {
663666
}
664667
}
665668

666-
export declare class CopyConditions {
667-
setModified(date: Date): void
668-
669-
setUnmodified(date: Date): void
670-
671-
setMatchETag(etag: string): void
672-
673-
setMatchETagExcept(etag: string): void
674-
}
675-
676-
export declare class PostPolicy {
677-
setExpires(date: Date): void
678-
679-
setKey(objectName: string): void
680-
681-
setKeyStartsWith(prefix: string): void
682-
683-
setBucket(bucketName: string): void
684-
685-
setContentType(type: string): void
686-
687-
setContentTypeStartsWith(prefix: string): void
688-
689-
setContentLengthRange(min: number, max: number): void
690-
691-
setContentDisposition(disposition: string): void
692-
693-
setUserMetaData(metadata: Record<string, string>): void
694-
}
695-
696669
export declare class NotificationPoller extends EventEmitter {
697670
stop(): void
698671

src/minio.js

+6-133
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { CredentialProvider } from './CredentialProvider.ts'
3333
import * as errors from './errors.ts'
3434
import { extensions } from './extensions.js'
3535
import { CopyDestinationOptions, CopySourceOptions, DEFAULT_REGION } from './helpers.ts'
36+
import { CopyConditions } from './internal/copy-conditions.ts'
3637
import {
3738
calculateEvenSplits,
3839
extractMetadata,
@@ -66,6 +67,7 @@ import {
6667
uriEscape,
6768
uriResourceEscape,
6869
} from './internal/helper.ts'
70+
import { PostPolicy } from './internal/post-policy.ts'
6971
import { getS3Endpoint } from './internal/s3-endpoints.ts'
7072
import { LEGAL_HOLD_STATUS, RETENTION_MODES, RETENTION_VALIDITY_UNITS } from './internal/type.ts'
7173
import { NotificationConfig, NotificationPoller } from './notification.js'
@@ -74,11 +76,13 @@ import { promisify } from './promisify.js'
7476
import { postPresignSignatureV4, presignSignatureV4, signV4 } from './signing.ts'
7577
import * as transformers from './transformers.js'
7678
import { parseSelectObjectContentResponse } from './xml-parsers.js'
77-
// will be replaced by bundler
78-
const Package = { version: process.env.MINIO_JS_PACKAGE_VERSION || 'development' }
7979

8080
export * from './helpers.ts'
8181
export * from './notification.js'
82+
export { CopyConditions, PostPolicy }
83+
84+
// will be replaced by bundler
85+
const Package = { version: process.env.MINIO_JS_PACKAGE_VERSION || 'development' }
8286

8387
export class Client {
8488
constructor(params) {
@@ -3848,134 +3852,3 @@ Client.prototype.setObjectLegalHold = promisify(Client.prototype.setObjectLegalH
38483852
Client.prototype.getObjectLegalHold = promisify(Client.prototype.getObjectLegalHold)
38493853
Client.prototype.composeObject = promisify(Client.prototype.composeObject)
38503854
Client.prototype.selectObjectContent = promisify(Client.prototype.selectObjectContent)
3851-
3852-
export class CopyConditions {
3853-
constructor() {
3854-
this.modified = ''
3855-
this.unmodified = ''
3856-
this.matchETag = ''
3857-
this.matchETagExcept = ''
3858-
}
3859-
3860-
setModified(date) {
3861-
if (!(date instanceof Date)) {
3862-
throw new TypeError('date must be of type Date')
3863-
}
3864-
3865-
this.modified = date.toUTCString()
3866-
}
3867-
3868-
setUnmodified(date) {
3869-
if (!(date instanceof Date)) {
3870-
throw new TypeError('date must be of type Date')
3871-
}
3872-
3873-
this.unmodified = date.toUTCString()
3874-
}
3875-
3876-
setMatchETag(etag) {
3877-
this.matchETag = etag
3878-
}
3879-
3880-
setMatchETagExcept(etag) {
3881-
this.matchETagExcept = etag
3882-
}
3883-
}
3884-
3885-
// Build PostPolicy object that can be signed by presignedPostPolicy
3886-
export class PostPolicy {
3887-
constructor() {
3888-
this.policy = {
3889-
conditions: [],
3890-
}
3891-
this.formData = {}
3892-
}
3893-
3894-
// set expiration date
3895-
setExpires(date) {
3896-
if (!date) {
3897-
throw new errors.InvalidDateError('Invalid date : cannot be null')
3898-
}
3899-
this.policy.expiration = date.toISOString()
3900-
}
3901-
3902-
// set object name
3903-
setKey(objectName) {
3904-
if (!isValidObjectName(objectName)) {
3905-
throw new errors.InvalidObjectNameError(`Invalid object name : ${objectName}`)
3906-
}
3907-
this.policy.conditions.push(['eq', '$key', objectName])
3908-
this.formData.key = objectName
3909-
}
3910-
3911-
// set object name prefix, i.e policy allows any keys with this prefix
3912-
setKeyStartsWith(prefix) {
3913-
if (!isValidPrefix(prefix)) {
3914-
throw new errors.InvalidPrefixError(`Invalid prefix : ${prefix}`)
3915-
}
3916-
this.policy.conditions.push(['starts-with', '$key', prefix])
3917-
this.formData.key = prefix
3918-
}
3919-
3920-
// set bucket name
3921-
setBucket(bucketName) {
3922-
if (!isValidBucketName(bucketName)) {
3923-
throw new errors.InvalidBucketNameError(`Invalid bucket name : ${bucketName}`)
3924-
}
3925-
this.policy.conditions.push(['eq', '$bucket', bucketName])
3926-
this.formData.bucket = bucketName
3927-
}
3928-
3929-
// set Content-Type
3930-
setContentType(type) {
3931-
if (!type) {
3932-
throw new Error('content-type cannot be null')
3933-
}
3934-
this.policy.conditions.push(['eq', '$Content-Type', type])
3935-
this.formData['Content-Type'] = type
3936-
}
3937-
3938-
// set Content-Type prefix, i.e image/ allows any image
3939-
setContentTypeStartsWith(prefix) {
3940-
if (!prefix) {
3941-
throw new Error('content-type cannot be null')
3942-
}
3943-
this.policy.conditions.push(['starts-with', '$Content-Type', prefix])
3944-
this.formData['Content-Type'] = prefix
3945-
}
3946-
3947-
// set Content-Disposition
3948-
setContentDisposition(value) {
3949-
if (!value) {
3950-
throw new Error('content-disposition cannot be null')
3951-
}
3952-
this.policy.conditions.push(['eq', '$Content-Disposition', value])
3953-
this.formData['Content-Disposition'] = value
3954-
}
3955-
3956-
// set minimum/maximum length of what Content-Length can be.
3957-
setContentLengthRange(min, max) {
3958-
if (min > max) {
3959-
throw new Error('min cannot be more than max')
3960-
}
3961-
if (min < 0) {
3962-
throw new Error('min should be > 0')
3963-
}
3964-
if (max < 0) {
3965-
throw new Error('max should be > 0')
3966-
}
3967-
this.policy.conditions.push(['content-length-range', min, max])
3968-
}
3969-
3970-
// set user defined metadata
3971-
setUserMetaData(metaData) {
3972-
if (!isObject(metaData)) {
3973-
throw new TypeError('metadata should be of type "object"')
3974-
}
3975-
Object.entries(metaData).forEach(([key, value]) => {
3976-
const amzMetaDataKey = `x-amz-meta-${key}`
3977-
this.policy.conditions.push(['eq', `$${amzMetaDataKey}`, value])
3978-
this.formData[amzMetaDataKey] = value
3979-
})
3980-
}
3981-
}

0 commit comments

Comments
 (0)