UNPKG

@aws-lambda-powertools/parser

Version:
256 lines (255 loc) 8.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.UserIdentity = exports.DynamoDBStreamChangeRecordBase = exports.DynamoDBStreamChangeRecord = exports.DynamoDBStreamRecord = exports.DynamoDBStreamSchema = exports.DynamoDBStreamToKinesisChangeRecord = exports.DynamoDBStreamToKinesisRecord = void 0; const unmarshallDynamoDB_1 = require("@aws-lambda-powertools/commons/utils/unmarshallDynamoDB"); const zod_1 = require("zod"); const DynamoDBStreamChangeRecordBase = zod_1.z.object({ ApproximateCreationDateTime: zod_1.z.number().optional(), Keys: zod_1.z.record(zod_1.z.string(), zod_1.z.record(zod_1.z.string(), zod_1.z.any())), NewImage: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(), OldImage: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(), SequenceNumber: zod_1.z.string(), SizeBytes: zod_1.z.number(), StreamViewType: zod_1.z.enum([ 'NEW_IMAGE', 'OLD_IMAGE', 'NEW_AND_OLD_IMAGES', 'KEYS_ONLY', ]), }); exports.DynamoDBStreamChangeRecordBase = DynamoDBStreamChangeRecordBase; const DynamoDBStreamToKinesisChangeRecord = DynamoDBStreamChangeRecordBase.omit({ SequenceNumber: true, StreamViewType: true, }); exports.DynamoDBStreamToKinesisChangeRecord = DynamoDBStreamToKinesisChangeRecord; const unmarshallDynamoDBTransform = (object, ctx) => { const result = { ...object }; const unmarshallAttributeValue = (imageName, image) => { try { // @ts-expect-error return (0, unmarshallDynamoDB_1.unmarshallDynamoDB)(image); } catch { ctx.addIssue({ code: 'custom', message: `Could not unmarshall ${imageName} in DynamoDB stream record`, fatal: true, path: [imageName], }); return zod_1.z.NEVER; } }; const unmarshalledKeys = unmarshallAttributeValue('Keys', object.Keys); if (unmarshalledKeys === zod_1.z.NEVER) return zod_1.z.NEVER; // @ts-expect-error - We are intentionally mutating the object result.Keys = unmarshalledKeys; if (object.NewImage) { const unmarshalled = unmarshallAttributeValue('NewImage', object.NewImage); if (unmarshalled === zod_1.z.NEVER) return zod_1.z.NEVER; result.NewImage = unmarshalled; } if (object.OldImage) { const unmarshalled = unmarshallAttributeValue('OldImage', object.OldImage); if (unmarshalled === zod_1.z.NEVER) return zod_1.z.NEVER; result.OldImage = unmarshalled; } return result; }; const DynamoDBStreamChangeRecord = DynamoDBStreamChangeRecordBase.transform(unmarshallDynamoDBTransform); exports.DynamoDBStreamChangeRecord = DynamoDBStreamChangeRecord; const UserIdentity = zod_1.z.object({ type: zod_1.z.enum(['Service']), principalId: zod_1.z.literal('dynamodb.amazonaws.com'), }); exports.UserIdentity = UserIdentity; const DynamoDBStreamRecord = zod_1.z.object({ eventID: zod_1.z.string(), eventName: zod_1.z.enum(['INSERT', 'MODIFY', 'REMOVE']), eventVersion: zod_1.z.string(), eventSource: zod_1.z.literal('aws:dynamodb'), awsRegion: zod_1.z.string(), eventSourceARN: zod_1.z.string(), dynamodb: DynamoDBStreamChangeRecord, userIdentity: UserIdentity.optional(), }); exports.DynamoDBStreamRecord = DynamoDBStreamRecord; /** * Zod schema for Amazon DynamoDB Stream event sent to an Amazon Kinesis Stream. * * This schema is best used in conjunction with the {@link KinesisEnvelope | `KinesisEnvelope`} when * you want to work with the DynamoDB stream event coming from an Amazon Kinesis Stream. * * By default, we unmarshall the `dynamodb.Keys`, `dynamodb.NewImage`, and `dynamodb.OldImage` fields * for you. * * If you want to extend the schema and provide your own Zod schema for any of these fields, * you can use the {@link DynamoDBMarshalled | `DynamoDBMarshalled`} helper. In that case, we won't unmarshall the other fields. * * To extend the schema, you can use the {@link DynamoDBStreamToKinesisRecord | `DynamoDBStreamToKinesisRecord`} child schema and the {@link DynamoDBMarshalled | `DynamoDBMarshalled`} * helper together. * * @example * ```ts * import { * DynamoDBStreamToKinesisRecord, * DynamoDBStreamToKinesisChangeRecord, * } from '@aws-lambda-powertools/parser/schemas/dynamodb'; * import { KinesisEnvelope } from '@aws-lambda-powertools/parser/envelopes/dynamodb'; * import { DynamoDBMarshalled } from '@aws-lambda-powertools/parser/helpers/dynamodb'; * * const CustomSchema = DynamoDBStreamToKinesisRecord.extend({ * dynamodb: DynamoDBStreamToKinesisChangeRecord.extend({ * NewImage: DynamoDBMarshalled( * z.object({ * id: z.string(), * attribute: z.number(), * stuff: z.array(z.string()), * }) * ), * // Add the lines below only if you want these keys to be unmarshalled * Keys: DynamoDBMarshalled(z.unknown()), * OldImage: DynamoDBMarshalled(z.unknown()), * }), * }); * * type CustomEvent = z.infer<typeof CustomSchema>; * ``` */ const DynamoDBStreamToKinesisRecord = DynamoDBStreamRecord.extend({ recordFormat: zod_1.z.literal('application/json'), tableName: zod_1.z.string(), userIdentity: UserIdentity.nullish(), dynamodb: DynamoDBStreamToKinesisChangeRecord.transform(unmarshallDynamoDBTransform), }).omit({ eventVersion: true, eventSourceARN: true, }); exports.DynamoDBStreamToKinesisRecord = DynamoDBStreamToKinesisRecord; /** * Zod schema for Amazon DynamoDB Stream event. * * @example * ```json * { * "Records":[{ * "eventID":"1", * "eventName":"INSERT", * "eventVersion":"1.0", * "eventSource":"aws:dynamodb", * "awsRegion":"us-east-1", * "dynamodb":{ * "Keys":{ * "Id":{ * "N":"101" * } * }, * "NewImage":{ * "Message":{ * "S":"New item!" * }, * "Id":{ * "N":"101" * } * }, * "SequenceNumber":"111", * "SizeBytes":26, * "StreamViewType":"NEW_AND_OLD_IMAGES" * }, * "eventSourceARN":"stream-ARN" * }, * { * "eventID":"2", * "eventName":"MODIFY", * "eventVersion":"1.0", * "eventSource":"aws:dynamodb", * "awsRegion":"us-east-1", * "dynamodb":{ * "Keys":{ * "Id":{ * "N":"101" * } * }, * "NewImage":{ * "Message":{ * "S":"This item has changed" * }, * "Id":{ * "N":"101" * } * }, * "OldImage":{ * "Message":{ * "S":"New item!" * }, * "Id":{ * "N":"101" * } * }, * "SequenceNumber":"222", * "SizeBytes":59, * "StreamViewType":"NEW_AND_OLD_IMAGES" * }, * "eventSourceARN":"stream-ARN" * }, * { * "eventID":"3", * "eventName":"REMOVE", * "eventVersion":"1.0", * "eventSource":"aws:dynamodb", * "awsRegion":"us-east-1", * "dynamodb":{ * "Keys":{ * "Id":{ * "N":"101" * } * }, * "OldImage":{ * "Message":{ * "S":"This item has changed" * }, * "Id":{ * "N":"101" * } * }, * "SequenceNumber":"333", * "SizeBytes":38, * "StreamViewType":"NEW_AND_OLD_IMAGES" * }, * "eventSourceARN":"stream-ARN" * }], * "window": { * "start": "2020-07-30T17:00:00Z", * "end": "2020-07-30T17:05:00Z" * }, * "state": { * "1": "state1" * }, * "shardId": "shard123456789", * "eventSourceARN": "stream-ARN", * "isFinalInvokeForWindow": false, * "isWindowTerminatedEarly": false * } * ``` * * @see {@link DynamoDBStreamEvent | DynamoDBStreamEvent} * @see {@link https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html} */ const DynamoDBStreamSchema = zod_1.z.object({ Records: zod_1.z.array(DynamoDBStreamRecord).nonempty(), window: zod_1.z .object({ start: zod_1.z.iso.datetime(), end: zod_1.z.iso.datetime(), }) .optional(), state: zod_1.z.record(zod_1.z.string(), zod_1.z.string()).optional(), shardId: zod_1.z.string().optional(), eventSourceARN: zod_1.z.string().optional(), isFinalInvokeForWindow: zod_1.z.boolean().optional(), isWindowTerminatedEarly: zod_1.z.boolean().optional(), }); exports.DynamoDBStreamSchema = DynamoDBStreamSchema;