Skip to content

Commit 1e26380

Browse files
committed
chore(storage): update s3 serde to accomodate stricter types
1 parent b75a5fa commit 1e26380

File tree

5 files changed

+31
-8
lines changed

5 files changed

+31
-8
lines changed

packages/storage/src/providers/s3/apis/internal/list.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export const list = async (
8686
ContinuationToken: options?.listAll ? undefined : options?.nextToken,
8787
Delimiter: getDelimiter(options),
8888
ExpectedBucketOwner: options?.expectedBucketOwner,
89-
EncodingType: 'url',
89+
EncodingType: 'url' as const,
9090
};
9191
logger.debug(`listing items from "${listParams.Prefix}"`);
9292

packages/storage/src/providers/s3/utils/client/s3data/deleteObject.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ import {
2323
validateS3RequiredParameter,
2424
} from '../utils';
2525
import { validateObjectUrl } from '../../validateObjectUrl';
26+
import { deserializeStringTag } from '../utils/deserializeHelpers';
2627

2728
import type {
2829
DeleteObjectCommandInput,
2930
DeleteObjectCommandOutput,
31+
RequestPayer,
3032
} from './types';
3133
import { defaultConfig, parseXmlError } from './base';
3234

@@ -73,7 +75,10 @@ const deleteObjectDeserializer = async (
7375
const content = map(response.headers, {
7476
DeleteMarker: ['x-amz-delete-marker', deserializeBoolean],
7577
VersionId: 'x-amz-version-id',
76-
RequestCharged: 'x-amz-request-charged',
78+
RequestCharged: [
79+
'x-amz-request-charged',
80+
deserializeStringTag<RequestPayer>,
81+
],
7782
});
7883

7984
return {

packages/storage/src/providers/s3/utils/client/s3data/listObjectsV2.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@ import {
2525
s3TransferHandler,
2626
} from '../utils';
2727
import { IntegrityError } from '../../../../../errors/IntegrityError';
28+
import { deserializeStringTag } from '../utils/deserializeHelpers';
2829

2930
import type {
31+
ChecksumAlgorithm,
3032
ListObjectsV2CommandInput,
3133
ListObjectsV2CommandOutput,
34+
StorageClass,
3235
} from './types';
3336
import { defaultConfig, parseXmlError } from './base';
3437

@@ -83,7 +86,7 @@ const listObjectsV2Deserializer = async (
8386
],
8487
ContinuationToken: 'ContinuationToken',
8588
Delimiter: 'Delimiter',
86-
EncodingType: 'EncodingType',
89+
EncodingType: ['EncodingType', deserializeStringTag<'url'>],
8790
IsTruncated: ['IsTruncated', deserializeBoolean],
8891
KeyCount: ['KeyCount', deserializeNumber],
8992
MaxKeys: ['MaxKeys', deserializeNumber],
@@ -124,12 +127,12 @@ const deserializeObject = (output: any) =>
124127
value => emptyArrayGuard(value, deserializeChecksumAlgorithmList),
125128
],
126129
Size: ['Size', deserializeNumber],
127-
StorageClass: 'StorageClass',
130+
StorageClass: ['StorageClass', deserializeStringTag<StorageClass>],
128131
Owner: ['Owner', deserializeOwner],
129132
});
130133

131134
const deserializeChecksumAlgorithmList = (output: any[]) =>
132-
output.map(entry => String(entry));
135+
output.map(deserializeStringTag<ChecksumAlgorithm>);
133136

134137
const deserializeOwner = (output: any) =>
135138
map(output, { DisplayName: 'DisplayName', ID: 'ID' });

packages/storage/src/providers/s3/utils/client/s3data/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4255,7 +4255,7 @@ export interface PutObjectCommandInput extends Omit<PutObjectRequest, 'Body'> {
42554255
/**
42564256
* For *`PutObjectRequest["Body"]`*, see {@link PutObjectRequest.Body}.
42574257
*/
4258-
Body?: string | Blob | ArrayBuffer | ArrayBufferView;
4258+
Body?: string | Blob | ArrayBuffer | ArrayBufferView;
42594259
}
42604260
/**
42614261
* @public

packages/storage/src/providers/s3/utils/client/utils/deserializeHelpers.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ export const deserializeTimestamp = (value: string): Date | undefined => {
112112
* Create a function deserializing a string to an enum value. If the string is not a valid enum value, it throws a
113113
* StorageError.
114114
*
115+
* This utility is ONLY preferred if the enum value is critical. Since the enum values are hard-coded, new enum values
116+
* returned from service would break the library.
117+
*
115118
* @example
116119
* ```typescript
117120
* const deserializeStringEnum = createStringEnumDeserializer(['a', 'b', 'c'] as const, 'FieldName');
@@ -130,7 +133,7 @@ export const createStringEnumDeserializer = <T extends readonly string[]>(
130133
) => {
131134
const deserializeStringEnum = (
132135
value: any,
133-
): T extends (infer E)[] ? E : never => {
136+
): T extends readonly (infer E)[] ? E : never => {
134137
const parsedEnumValue = value
135138
? (enumValues.find(enumValue => enumValue === value) as any)
136139
: undefined;
@@ -149,6 +152,18 @@ export const createStringEnumDeserializer = <T extends readonly string[]>(
149152
return deserializeStringEnum;
150153
};
151154

155+
/**
156+
* Deserializes a string if a string tag type. The function simply cast the parsed string into a given string tag type.
157+
* It does NOT validate whether the string value against the string tag. This behavior is the same to AWS SDK parsing
158+
* logic of string tag types.
159+
*
160+
* If you need to verify the string value, you must use {@link createStringEnumDeserializer} instead.
161+
*
162+
* @internal
163+
*/
164+
export const deserializeStringTag = <T extends string>(value: any): T =>
165+
String(value) as T;
166+
152167
/**
153168
* Function that makes sure the deserializer receives non-empty array.
154169
*
@@ -173,7 +188,7 @@ export const emptyArrayGuard = <T extends any[]>(
173188
*/
174189
export const deserializeMetadata = (
175190
headers: Headers,
176-
): Record<string, string> => {
191+
): Record<string, string> | undefined => {
177192
const objectMetadataHeaderPrefix = 'x-amz-meta-';
178193
const deserialized = Object.keys(headers)
179194
.filter(header => header.startsWith(objectMetadataHeaderPrefix))

0 commit comments

Comments
 (0)