import { FormItem, EditorLanguage, FormComponentType, InputDataType, Plugin, PluginResponseType, PluginType } from '../../types/index.js'; import { PUBLIC_INTEGRATIONS_LOGO_URL } from './constants.js'; const KinesisPluginVersions = { V1: '0.0.1' }; // some constants to share with the UI export const KINESIS_MODULE_NAME = 'KinesisPlugin'; export const OPERATION_TYPE_NAME = 'operationType'; export const OPERATION_TYPE_PUT = 'OPERATION_TYPE_PUT'; export const OPERATION_TYPE_GET = 'OPERATION_TYPE_GET'; const MESSAGES_PLACEHOLDER = `[ { "id": 123, "company": "Superblocks!" }, { "id": 456, "value": { "koala": "bear" } } ]`; const makeDropdownItem = (value: string, displayName?: string, subText?: string) => { return { key: value, value: value, displayName: displayName ?? value, subText: subText ?? '' }; }; type DisplayInfo = { displayName: string; description: string }; const KINESIS_ACTIONS_AND_DISPLAY_NAMES: Record = { OPERATION_TYPE_PUT: { displayName: 'Put', description: 'Put a number of records onto a Kinesis stream' }, OPERATION_TYPE_GET: { displayName: 'Get', description: 'Stream records in from a Kinesis stream' } }; const KINESIS_STREAM_IDENTIFIERS_AND_DISPLAY_NAMES: Record = { STREAM_IDENTIFIER_STREAM_NAME: 'Stream name', STREAM_IDENTIFIER_STREAM_ARN: 'Stream ARN' }; // descriptions from here: https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html const KINESIS_SHARD_ITERATOR_TYPES_AND_DISPLAY_NAMES: Record = { SHARD_ITERATOR_TYPE_LATEST: { displayName: 'Latest', description: 'Start reading just after the most recent record in the shard, so that you always read the most recent data in the shard' }, SHARD_ITERATOR_TYPE_TRIM_HORIZON: { displayName: 'Trim Horizon', description: 'Start reading at the last untrimmed record in the shard in the system, which is the oldest data record in the shard' }, SHARD_ITERATOR_TYPE_AT_TIMESTAMP: { displayName: 'Timestamp', description: 'Start reading from the position denoted by a specific time stamp' }, SHARD_ITERATOR_TYPE_AT_SEQUENCE_NUMBER: { displayName: 'At sequence number', description: 'Start reading from the position denoted by a specific sequence number' }, SHARD_ITERATOR_TYPE_AFTER_SEQUENCE_NUMBER: { displayName: 'After sequence number', description: 'Start reading right after the position denoted by a specific sequence number' } }; const BASE_STREAM_IDENTIFIER = { label: 'Stream identifier', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.DROPDOWN, rules: [{ required: true }], initialValue: 'STREAM_IDENTIFIER_STREAM_NAME', options: Object.entries(KINESIS_STREAM_IDENTIFIERS_AND_DISPLAY_NAMES).map(([value, displayName]) => makeDropdownItem(value, displayName)), tooltip: { markdownText: 'Identify the stream to use' } }; const BASE_STREAM_ARN = { label: 'ARN', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.DYNAMIC_INPUT_TEXT, rules: [{ required: true }], placeholder: 'arn:aws:kinesis:us-east-1:123456789012:stream/my_stream', tooltip: { markdownText: 'The ARN of the stream to use' } }; const BASE_STREAM_NAME = { label: 'Name', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.DYNAMIC_INPUT_TEXT, rules: [{ required: true }], placeholder: 'my_stream', tooltip: { markdownText: 'The name of the stream to use' } }; export const KinesisPlugin: Plugin = { id: 'kinesis', name: 'Amazon Kinesis', moduleName: KINESIS_MODULE_NAME, modulePath: 'plugins/kinesis/KinesisPlugin', iconLocation: `${PUBLIC_INTEGRATIONS_LOGO_URL}/kinesis.png`, // TODO(docs-v2): no kinesis page exists in docs-v2; add one or remove this line docsUrl: undefined, type: PluginType.API, responseType: PluginResponseType.JSON, hasRawRequest: false, hasMetadata: true, isStreamable: true, datasourceTemplate: { sections: [ { name: 'main', items: [ { label: 'Display name', name: 'name', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.INPUT_TEXT, placeholder: 'Amazon Kinesis Prod', rules: [{ required: true, message: 'Display name is required' }] }, { label: 'Region', name: 'connection.awsConfig.region', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.INPUT_TEXT, placeholder: 'us-east-1', rules: [{ required: true, message: 'Region is required' }] }, { label: 'Access key ID', name: 'connection.awsConfig.auth.accessKeyId', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.INPUT_TEXT, rules: [{ required: true, message: 'Access key ID is required' }] }, { label: 'Secret key', name: 'connection.awsConfig.auth.secretKey', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.INPUT_TEXT, dataType: InputDataType.PASSWORD, rules: [{ required: true, message: 'Secret key is required' }] }, { label: 'Endpoint (optional)', name: 'connection.awsConfig.endpoint', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.INPUT_TEXT, placeholder: 'kinesis.us-east-1.amazonaws.com:4566', tooltip: { markdownText: 'Specify the data stream endpoint to connect to. [Read more](https://docs.aws.amazon.com/general/latest/gr/ak.html)' } } ] } ] }, actionTemplate: { sections: [ { name: 'actionSelect', items: [ { label: 'Action', name: 'operationType', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.DROPDOWN, rules: [{ required: true }], // logic in the front-end will choose the right default based on // the context. we should bring that in the form. initialValue: 'OPERATION_TYPE_PUT', options: Object.entries(KINESIS_ACTIONS_AND_DISPLAY_NAMES).map(([value, displayInfo]) => makeDropdownItem(value, displayInfo.displayName, displayInfo.description) ) } ] }, { name: 'streamIdentifier', items: [ // PUT { name: 'put.streamIdentifierType', display: { show: { operationType: ['OPERATION_TYPE_PUT'] } }, ...BASE_STREAM_IDENTIFIER } as FormItem, { name: 'put.streamName', display: { show: { operationType: ['OPERATION_TYPE_PUT'], 'put.streamIdentifierType': ['STREAM_IDENTIFIER_STREAM_NAME'] } }, ...BASE_STREAM_NAME } as FormItem, { name: 'put.streamArn', display: { show: { operationType: ['OPERATION_TYPE_PUT'], 'put.streamIdentifierType': ['STREAM_IDENTIFIER_STREAM_ARN'] } }, ...BASE_STREAM_ARN } as FormItem, // GET { name: 'get.streamIdentifierType', display: { show: { operationType: ['OPERATION_TYPE_GET'] } }, ...BASE_STREAM_IDENTIFIER } as FormItem, { name: 'get.streamName', display: { show: { operationType: ['OPERATION_TYPE_GET'], 'get.streamIdentifierType': ['STREAM_IDENTIFIER_STREAM_NAME'] } }, ...BASE_STREAM_NAME } as FormItem, { name: 'get.streamArn', display: { show: { operationType: ['OPERATION_TYPE_GET'], 'get.streamIdentifierType': ['STREAM_IDENTIFIER_STREAM_ARN'] } }, ...BASE_STREAM_ARN } as FormItem ] }, { name: 'main', items: [ // put { label: 'Partition Key', name: 'put.partitionKey', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.DYNAMIC_INPUT_TEXT, rules: [{ required: true, message: 'Partition key is required' }], display: { show: { operationType: ['OPERATION_TYPE_PUT'] } }, tooltip: { markdownText: 'Used to group data by shard within a stream' } }, { label: 'Messages', name: 'put.data', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.CODE_EDITOR, rules: [{ required: true, message: 'Messages are required' }], language: EditorLanguage.JSON, tooltip: { markdownText: 'A JSON array of messages to put' }, placeholder: MESSAGES_PLACEHOLDER, display: { show: { operationType: ['OPERATION_TYPE_PUT'] } } }, // get { label: 'Shard ID', name: 'get.shardId', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.DYNAMIC_INPUT_TEXT, rules: [{ required: true, message: 'Shard ID is required' }], placeholder: 'shardId-000000000001', display: { show: { operationType: ['OPERATION_TYPE_GET'] } }, tooltip: { markdownText: 'The shard ID to use when getting data' } }, { label: 'Shard iterator type', name: 'get.shardIteratorType', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.DROPDOWN, display: { show: { operationType: ['OPERATION_TYPE_GET'] } }, rules: [{ required: true }], initialValue: 'SHARD_ITERATOR_TYPE_LATEST', options: Object.entries(KINESIS_SHARD_ITERATOR_TYPES_AND_DISPLAY_NAMES).map(([value, displayInfo]) => makeDropdownItem(value, displayInfo.displayName, displayInfo.description) ), tooltip: { markdownText: 'Identify the point you would like to get from' } }, { label: 'Starting sequence number', name: 'get.startingSequenceNumber', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.DYNAMIC_INPUT_TEXT, rules: [{ required: true, message: 'Starting sequence number is required' }], display: { show: { operationType: ['OPERATION_TYPE_GET'], 'get.shardIteratorType': ['SHARD_ITERATOR_TYPE_AT_SEQUENCE_NUMBER', 'SHARD_ITERATOR_TYPE_AFTER_SEQUENCE_NUMBER'] } }, tooltip: { // https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html markdownText: 'The sequence number of the data record in the shard from which to start reading' } }, { label: 'Timestamp', name: 'get.timestamp', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.DYNAMIC_INPUT_TEXT, rules: [{ required: true, message: 'Timestamp is required' }], display: { show: { operationType: ['OPERATION_TYPE_GET'], 'get.shardIteratorType': ['SHARD_ITERATOR_TYPE_AT_TIMESTAMP'] } }, tooltip: { // https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html markdownText: 'The ISO-formatted timestamp of the data record from which to start reading' } }, { label: 'Limit', name: 'get.limit', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.DYNAMIC_INPUT_TEXT, rules: [{ required: true, message: 'Limit is required' }], dataType: InputDataType.NUMBER, initialValue: 10, display: { show: { operationType: ['OPERATION_TYPE_GET'] } }, tooltip: { markdownText: 'The maximum number of messages to get in each polling cycle' } }, { label: 'Polling cooldown ms', name: 'get.pollingCooldownMs', startVersion: KinesisPluginVersions.V1, componentType: FormComponentType.DYNAMIC_INPUT_TEXT, rules: [{ required: true, message: 'Polling cooldown ms is required' }], dataType: InputDataType.NUMBER, initialValue: 1000, display: { show: { operationType: ['OPERATION_TYPE_GET'] } }, tooltip: { markdownText: 'The amount of time in milliseconds to wait between each polling cycle' } } ] } ] } };