feat: MSK, MSK CONNECT and SES
This commit is contained in:
@@ -58,7 +58,13 @@ export const apiEndpointKeys = {
|
||||
updateCloudFormationTerminationProtection: "clouds.services.resources.iac.termination-protection.update",
|
||||
createSqsLambdaEventSourceMapping: "clouds.services.resources.serverless.sqs-event-source-mapping.create",
|
||||
listSqsLambdaEventSourceMappings: "clouds.services.resources.serverless.sqs-event-source-mappings.list",
|
||||
deleteSqsLambdaEventSourceMapping: "clouds.services.resources.serverless.sqs-event-source-mapping.delete",
|
||||
deleteSqsLambdaEventSourceMapping: "clouds.services.resources.serverless.sqs-event-source-mapping.delete",
|
||||
putKinesisRecord: "clouds.services.resources.kinesis.record.put",
|
||||
listKinesisRecords: "clouds.services.resources.kinesis.records.list",
|
||||
createLambdaEventSourceMapping: "clouds.services.resources.serverless.event-source-mapping.create",
|
||||
listLambdaEventSourceMappings: "clouds.services.resources.serverless.event-source-mappings.list",
|
||||
updateLambdaEventSourceMapping: "clouds.services.resources.serverless.event-source-mapping.update",
|
||||
deleteLambdaEventSourceMapping: "clouds.services.resources.serverless.event-source-mapping.delete",
|
||||
startWorkflowExecution: "clouds.services.resources.workflows.execution.start",
|
||||
listWorkflowExecutions: "clouds.services.resources.workflows.executions.list",
|
||||
describeWorkflowExecution: "clouds.services.resources.workflows.execution.describe",
|
||||
@@ -219,6 +225,7 @@ export const apiEndpointKeys = {
|
||||
reboot: "aws.ec2.instances.reboot",
|
||||
terminate: "aws.ec2.instances.terminate",
|
||||
tags: "aws.ec2.instances.tags",
|
||||
securityGroups: "aws.ec2.instances.securityGroups",
|
||||
createImage: "aws.ec2.instances.create-image",
|
||||
console: "aws.ec2.instances.console",
|
||||
},
|
||||
@@ -547,6 +554,12 @@ export const endpointRegistry: EndpointRegistry = new Map([
|
||||
method: "DELETE",
|
||||
},
|
||||
],
|
||||
[apiEndpointKeys.clouds.resources.putKinesisRecord, {path: "/clouds/:cloud/services/kinesis/resources/:id/records", method: "POST"}],
|
||||
[apiEndpointKeys.clouds.resources.listKinesisRecords, {path: "/clouds/:cloud/services/kinesis/resources/:id/records", method: "GET"}],
|
||||
[apiEndpointKeys.clouds.resources.createLambdaEventSourceMapping, {path: "/clouds/:cloud/services/serverless/event-source-mappings", method: "POST"}],
|
||||
[apiEndpointKeys.clouds.resources.listLambdaEventSourceMappings, {path: "/clouds/:cloud/services/serverless/event-source-mappings", method: "GET"}],
|
||||
[apiEndpointKeys.clouds.resources.updateLambdaEventSourceMapping, {path: "/clouds/:cloud/services/serverless/event-source-mappings/:mappingId", method: "PATCH"}],
|
||||
[apiEndpointKeys.clouds.resources.deleteLambdaEventSourceMapping, {path: "/clouds/:cloud/services/serverless/event-source-mappings/:mappingId", method: "DELETE"}],
|
||||
[
|
||||
apiEndpointKeys.clouds.resources.startWorkflowExecution,
|
||||
{ path: "/clouds/:cloud/services/workflows/resources/:id/executions", method: "POST" },
|
||||
@@ -1113,6 +1126,7 @@ export const endpointRegistry: EndpointRegistry = new Map([
|
||||
[apiEndpointKeys.aws.ec2.instances.reboot, { path: "/ec2/instances/:instanceId/reboot", method: "POST" }],
|
||||
[apiEndpointKeys.aws.ec2.instances.terminate,{ path: "/ec2/instances/:instanceId/terminate", method: "POST" }],
|
||||
[apiEndpointKeys.aws.ec2.instances.tags, { path: "/ec2/instances/:instanceId/tags", method: "PUT" }],
|
||||
[apiEndpointKeys.aws.ec2.instances.securityGroups, { path: "/ec2/instances/:instanceId/security-groups", method: "PUT" }],
|
||||
[apiEndpointKeys.aws.ec2.instances.createImage, { path: "/ec2/instances/:instanceId/image", method: "POST" }],
|
||||
[apiEndpointKeys.aws.ec2.instances.console, { path: "/ec2/instances/:instanceId/console", method: "GET" }],
|
||||
[apiEndpointKeys.aws.ec2.amis.list, { path: "/ec2/amis", method: "GET" }],
|
||||
|
||||
@@ -75,6 +75,14 @@ export type Ec2Instance = {
|
||||
securityGroups: Ec2SecurityGroupRef[];
|
||||
networkInterfaces: Ec2NetworkInterface[];
|
||||
tags: Ec2Tag[];
|
||||
connection?: Ec2InstanceConnection;
|
||||
};
|
||||
|
||||
export type Ec2InstanceConnection = {
|
||||
sshHost?: string;
|
||||
sshPort?: number;
|
||||
containerId?: string;
|
||||
containerStatus: 'running' | 'stopped' | 'unavailable';
|
||||
};
|
||||
|
||||
export type Ec2KeyPair = {
|
||||
@@ -327,6 +335,14 @@ export async function updateEc2InstanceTags(
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateEc2InstanceSecurityGroups(instanceId: string, groupIds: string[]): Promise<void> {
|
||||
await apiClient.call(
|
||||
apiEndpointKeys.aws.ec2.instances.securityGroups,
|
||||
{ body: JSON.stringify({ groupIds }), headers: { "content-type": "application/json" } },
|
||||
{ instanceId },
|
||||
);
|
||||
}
|
||||
|
||||
export async function createEc2Ami(instanceId: string, input: CreateAmiInput): Promise<{ imageId: string }> {
|
||||
const res = await apiClient.call<{ imageId: string }>(
|
||||
apiEndpointKeys.aws.ec2.instances.createImage,
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest'
|
||||
import {deleteFlatItem, listFlatItems, putFlatItem} from './cloudProxyClient'
|
||||
|
||||
describe('generic flat-item requests for security-group ingress', () => {
|
||||
const fetchMock = vi.fn<typeof fetch>()
|
||||
|
||||
beforeEach(() => {
|
||||
fetchMock.mockImplementation(async (_url, init) => {
|
||||
const body = init?.method === 'GET'
|
||||
? {items: [], nextCursor: null}
|
||||
: {id: 'rule-id', collectionId: null, timestamp: null, body: {}, metadata: {}}
|
||||
return new Response(JSON.stringify(body), {status: 200, headers: {'Content-Type': 'application/json'}})
|
||||
})
|
||||
vi.stubGlobal('fetch', fetchMock)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals()
|
||||
fetchMock.mockReset()
|
||||
})
|
||||
|
||||
it('lists, adds, and deletes through the networking child-item SPI', async () => {
|
||||
const permission = {protocol: 'tcp', fromPort: 443, toPort: 443, cidr: '0.0.0.0/0'}
|
||||
|
||||
await listFlatItems('aws', 'networking', 'sg-web')
|
||||
await putFlatItem('aws', 'networking', 'sg-web', permission)
|
||||
await deleteFlatItem('aws', 'networking', 'sg-web', 'rule/id')
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledTimes(3)
|
||||
expect(String(fetchMock.mock.calls[0][0])).toContain('/api/clouds/aws/services/networking/resources/sg-web/items')
|
||||
expect(fetchMock.mock.calls[0][1]?.method).toBe('GET')
|
||||
expect(String(fetchMock.mock.calls[1][0])).toContain('/api/clouds/aws/services/networking/resources/sg-web/items')
|
||||
expect(fetchMock.mock.calls[1][1]?.method).toBe('POST')
|
||||
expect(JSON.parse(String(fetchMock.mock.calls[1][1]?.body))).toEqual(permission)
|
||||
expect(String(fetchMock.mock.calls[2][0])).toContain('/api/clouds/aws/services/networking/resources/sg-web/items/rule%2Fid')
|
||||
expect(fetchMock.mock.calls[2][1]?.method).toBe('DELETE')
|
||||
})
|
||||
})
|
||||
@@ -521,6 +521,39 @@ export interface SqsLambdaEventSourceMappingOverview {
|
||||
stateTransitionReason: string | null;
|
||||
}
|
||||
|
||||
export interface KinesisRecord {sequenceNumber: string; partitionKey: string | null; data: string; approximateArrivalTimestamp: string | null}
|
||||
export interface LambdaEventSourceMappingOverview {id: string; uuid: string; functionName: string | null; functionArn: string | null; eventSourceArn: string; batchSize: number | null; startingPosition: string | null; state: string | null; stateTransitionReason: string | null}
|
||||
export interface CreateLambdaEventSourceMappingInput {functionName: string; eventSourceArn: string; batchSize?: number; startingPosition?: "TRIM_HORIZON" | "LATEST"}
|
||||
|
||||
export async function putKinesisRecord(cloud: CloudProvider, streamName: string, input: {partitionKey: string; data: string}): Promise<{sequenceNumber: string; shardId: string}> {
|
||||
const res = await apiClient.call<{sequenceNumber: string; shardId: string}, typeof input>(apiEndpointKeys.clouds.resources.putKinesisRecord, requestOptions(cloud, "kinesis", {body: input}), {cloud, id: streamName})
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function listKinesisRecords(cloud: CloudProvider, streamName: string, signal?: AbortSignal): Promise<KinesisRecord[]> {
|
||||
const res = await apiClient.call<KinesisRecord[]>(apiEndpointKeys.clouds.resources.listKinesisRecords, requestOptions(cloud, "kinesis", {signal}), {cloud, id: streamName})
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function createLambdaEventSourceMapping(cloud: CloudProvider, input: CreateLambdaEventSourceMappingInput): Promise<LambdaEventSourceMappingOverview> {
|
||||
const res = await apiClient.call<LambdaEventSourceMappingOverview, CreateLambdaEventSourceMappingInput>(apiEndpointKeys.clouds.resources.createLambdaEventSourceMapping, requestOptions(cloud, "serverless", {body: input}), {cloud})
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function listLambdaEventSourceMappings(cloud: CloudProvider, filter: {functionName?: string; eventSourceArn?: string}, signal?: AbortSignal): Promise<LambdaEventSourceMappingOverview[]> {
|
||||
const res = await apiClient.call<LambdaEventSourceMappingOverview[]>(apiEndpointKeys.clouds.resources.listLambdaEventSourceMappings, requestOptions(cloud, "serverless", {signal, params: filter}), {cloud})
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function updateLambdaEventSourceMapping(cloud: CloudProvider, mappingId: string, input: {batchSize?: number; enabled?: boolean}): Promise<LambdaEventSourceMappingOverview> {
|
||||
const res = await apiClient.call<LambdaEventSourceMappingOverview, typeof input>(apiEndpointKeys.clouds.resources.updateLambdaEventSourceMapping, requestOptions(cloud, "serverless", {body: input}), {cloud, mappingId})
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function deleteLambdaEventSourceMapping(cloud: CloudProvider, mappingId: string): Promise<void> {
|
||||
await apiClient.call<void>(apiEndpointKeys.clouds.resources.deleteLambdaEventSourceMapping, requestOptions(cloud, "serverless"), {cloud, mappingId})
|
||||
}
|
||||
|
||||
export async function createApiGatewayLambdaRoute(
|
||||
cloud: CloudProvider,
|
||||
apiId: string,
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import {apiClient} from "@/api/api";
|
||||
|
||||
export interface MskCluster { ClusterArn?: string; ClusterName?: string; State?: string; KafkaVersion?: string; NumberOfBrokerNodes?: number; }
|
||||
export interface CreateMskClusterInput { clusterName: string; kafkaVersion: string; numberOfBrokerNodes: number; brokerNodeGroupInfo: {clientSubnets: string[]}; }
|
||||
export interface MskTopic { name: string; partitionCount: number; }
|
||||
export interface MskMessage { partition: number; offset: string; timestamp: string; key?: string; value?: string; headers: Record<string, string>; }
|
||||
export interface MskConsumerGroupLag { topic: string; totalLag: number; partitions: Array<{partition: number; currentOffset: string; endOffset: string; lag: number}>; }
|
||||
|
||||
function clusterPath(clusterArn: string): string { return `/msk/clusters/${encodeURIComponent(clusterArn)}`; }
|
||||
|
||||
export async function listMskClusters(signal?: AbortSignal): Promise<MskCluster[]> { return (await apiClient.get<MskCluster[]>("/msk/clusters", {signal})).data; }
|
||||
export async function createMskCluster(input: CreateMskClusterInput): Promise<MskCluster> { return (await apiClient.post<MskCluster, CreateMskClusterInput>("/msk/clusters", input)).data; }
|
||||
export async function deleteMskCluster(clusterArn: string): Promise<void> { await apiClient.delete(clusterPath(clusterArn)); }
|
||||
export async function getMskBootstrapBrokers(clusterArn: string): Promise<string> { return (await apiClient.get<{bootstrapBrokers: string}>(`${clusterPath(clusterArn)}/bootstrap-brokers`)).data.bootstrapBrokers; }
|
||||
export async function listMskTopics(clusterArn: string, signal?: AbortSignal): Promise<MskTopic[]> { return (await apiClient.get<MskTopic[]>(`${clusterPath(clusterArn)}/topics`, {signal})).data; }
|
||||
export async function createMskTopic(clusterArn: string, input: {topic: string; numPartitions?: number; replicationFactor?: number; configEntries?: Array<{name: string; value: string}>}): Promise<void> { await apiClient.post(`${clusterPath(clusterArn)}/topics`, input); }
|
||||
export async function deleteMskTopic(clusterArn: string, topic: string): Promise<void> { await apiClient.delete(`${clusterPath(clusterArn)}/topics/${encodeURIComponent(topic)}`); }
|
||||
export async function produceMskMessage(clusterArn: string, topic: string, input: {key?: string; value: string; headers?: Record<string, string>}): Promise<Array<{topicName: string; partition: number; baseOffset?: string}>> { return (await apiClient.post<Array<{topicName: string; partition: number; baseOffset?: string}>, typeof input>(`${clusterPath(clusterArn)}/topics/${encodeURIComponent(topic)}/messages`, input)).data; }
|
||||
export async function peekMskMessages(clusterArn: string, topic: string, limit: number): Promise<MskMessage[]> { return (await apiClient.get<MskMessage[]>(`${clusterPath(clusterArn)}/topics/${encodeURIComponent(topic)}/messages`, {params: {limit}})).data; }
|
||||
export async function getMskConsumerGroupLag(clusterArn: string, groupId: string, topic?: string): Promise<MskConsumerGroupLag[]> { return (await apiClient.get<MskConsumerGroupLag[]>(`${clusterPath(clusterArn)}/consumer-groups/${encodeURIComponent(groupId)}/lag`, {params: {topic}})).data; }
|
||||
@@ -0,0 +1,128 @@
|
||||
import {apiClient} from "@/api/api";
|
||||
|
||||
export interface CustomPlugin {
|
||||
customPluginArn?: string;
|
||||
name?: string;
|
||||
revision?: number;
|
||||
customPluginState?: string;
|
||||
}
|
||||
|
||||
export interface ConnectorSummary {
|
||||
connectorArn?: string;
|
||||
connectorName?: string;
|
||||
connectorState?: string;
|
||||
}
|
||||
|
||||
export interface ConnectorDescription extends ConnectorSummary {
|
||||
currentVersion?: string;
|
||||
stateDescription?: string;
|
||||
connectorConfiguration?: Record<string, string>;
|
||||
capacity?: {provisionedCapacity?: {mcuCount?: number; workerCount?: number}};
|
||||
kafkaCluster?: {apacheKafkaCluster?: {bootstrapServers?: string}};
|
||||
kafkaConnectVersion?: string;
|
||||
plugins?: Array<{customPlugin?: {customPluginArn?: string; revision?: number}}>;
|
||||
logDelivery?: {workerLogDelivery?: {cloudWatchLogs?: {enabled?: boolean; logGroup?: string}}};
|
||||
}
|
||||
|
||||
export interface S3SinkConnectorInput {
|
||||
connectorName: string;
|
||||
connectorDescription?: string;
|
||||
bootstrapServers: string;
|
||||
kafkaConnectVersion: string;
|
||||
serviceExecutionRoleArn: string;
|
||||
customPluginArn: string;
|
||||
customPluginRevision: number;
|
||||
workerCount: number;
|
||||
mcuCount: number;
|
||||
topics: string;
|
||||
keyConverter: "string" | "json";
|
||||
valueConverter: "string" | "json";
|
||||
s3Bucket: string;
|
||||
s3Region: string;
|
||||
flushSize: string;
|
||||
rotateIntervalMs: string;
|
||||
logGroup?: string;
|
||||
}
|
||||
|
||||
export interface UpdateS3SinkConnectorInput extends Omit<S3SinkConnectorInput, "connectorName" | "connectorDescription" | "bootstrapServers" | "kafkaConnectVersion" | "serviceExecutionRoleArn" | "customPluginArn" | "customPluginRevision" | "logGroup"> {
|
||||
currentVersion: string;
|
||||
}
|
||||
|
||||
const basePath = "/msk-connect";
|
||||
|
||||
export async function listCustomPlugins(signal?: AbortSignal): Promise<CustomPlugin[]> {
|
||||
return (await apiClient.get<CustomPlugin[]>(`${basePath}/custom-plugins`, {signal})).data;
|
||||
}
|
||||
|
||||
export async function registerCustomPlugin(input: {name: string; bucket: string; fileKey: string; objectVersion?: string; description?: string}): Promise<CustomPlugin> {
|
||||
return (await apiClient.post<CustomPlugin, object>(`${basePath}/custom-plugins`, {
|
||||
name: input.name,
|
||||
contentType: "JAR",
|
||||
description: input.description || undefined,
|
||||
location: {s3Location: {bucketArn: `arn:aws:s3:::${input.bucket}`, fileKey: input.fileKey, objectVersion: input.objectVersion || undefined}},
|
||||
})).data;
|
||||
}
|
||||
|
||||
export async function deleteCustomPlugin(customPluginArn: string): Promise<void> {
|
||||
await apiClient.delete(`${basePath}/custom-plugins/${encodeURIComponent(customPluginArn)}`);
|
||||
}
|
||||
|
||||
export async function listConnectors(signal?: AbortSignal): Promise<ConnectorSummary[]> {
|
||||
return (await apiClient.get<ConnectorSummary[]>(`${basePath}/connectors`, {signal})).data;
|
||||
}
|
||||
|
||||
export async function describeConnector(connectorArn: string, signal?: AbortSignal): Promise<ConnectorDescription> {
|
||||
return (await apiClient.get<ConnectorDescription>(`${basePath}/connectors/${encodeURIComponent(connectorArn)}`, {signal})).data;
|
||||
}
|
||||
|
||||
export async function createS3SinkConnector(input: S3SinkConnectorInput): Promise<ConnectorSummary> {
|
||||
return (await apiClient.post<ConnectorSummary, object>(`${basePath}/connectors`, connectorRequest(input), {timeout: 60_000})).data;
|
||||
}
|
||||
|
||||
export async function updateS3SinkConnector(connectorArn: string, input: UpdateS3SinkConnectorInput): Promise<ConnectorSummary> {
|
||||
return (await apiClient.patch<ConnectorSummary, object>(`${basePath}/connectors/${encodeURIComponent(connectorArn)}`, {
|
||||
currentVersion: input.currentVersion,
|
||||
capacity: {provisionedCapacity: {workerCount: input.workerCount, mcuCount: input.mcuCount}},
|
||||
connectorConfiguration: sinkConfiguration(input),
|
||||
})).data;
|
||||
}
|
||||
|
||||
export async function deleteConnector(connectorArn: string): Promise<void> {
|
||||
await apiClient.delete(`${basePath}/connectors/${encodeURIComponent(connectorArn)}`);
|
||||
}
|
||||
|
||||
function connectorRequest(input: S3SinkConnectorInput): object {
|
||||
return {
|
||||
connectorName: input.connectorName,
|
||||
connectorDescription: input.connectorDescription || undefined,
|
||||
capacity: {provisionedCapacity: {workerCount: input.workerCount, mcuCount: input.mcuCount}},
|
||||
connectorConfiguration: sinkConfiguration(input),
|
||||
kafkaCluster: {apacheKafkaCluster: {bootstrapServers: input.bootstrapServers}},
|
||||
kafkaClusterClientAuthentication: {authenticationType: "NONE"},
|
||||
kafkaClusterEncryptionInTransit: {encryptionType: "PLAINTEXT"},
|
||||
kafkaConnectVersion: input.kafkaConnectVersion,
|
||||
plugins: [{customPlugin: {customPluginArn: input.customPluginArn, revision: input.customPluginRevision}}],
|
||||
serviceExecutionRoleArn: input.serviceExecutionRoleArn,
|
||||
logDelivery: input.logGroup ? {workerLogDelivery: {cloudWatchLogs: {enabled: true, logGroup: input.logGroup}}} : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
function sinkConfiguration(input: Pick<S3SinkConnectorInput, "topics" | "keyConverter" | "valueConverter" | "s3Bucket" | "s3Region" | "flushSize" | "rotateIntervalMs">): Record<string, string> {
|
||||
return {
|
||||
"connector.class": "io.confluent.connect.s3.S3SinkConnector",
|
||||
"tasks.max": "1",
|
||||
topics: input.topics,
|
||||
"key.converter": converterClass(input.keyConverter),
|
||||
"value.converter": converterClass(input.valueConverter),
|
||||
"key.converter.schemas.enable": "false",
|
||||
"value.converter.schemas.enable": "false",
|
||||
"s3.bucket.name": input.s3Bucket,
|
||||
"s3.region": input.s3Region,
|
||||
"flush.size": input.flushSize,
|
||||
"rotate.interval.ms": input.rotateIntervalMs,
|
||||
};
|
||||
}
|
||||
|
||||
function converterClass(value: "string" | "json"): string {
|
||||
return value === "json" ? "org.apache.kafka.connect.json.JsonConverter" : "org.apache.kafka.connect.storage.StringConverter";
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import {apiClient} from '@/api/api'
|
||||
|
||||
export interface SesIdentity {IdentityName: string; IdentityType?: string; VerifiedForSendingStatus?: boolean}
|
||||
export interface SesTemplate {TemplateName: string; CreatedTimestamp?: string}
|
||||
export interface SesConfigurationSet {ConfigurationSetName: string; LastFreshStart?: string}
|
||||
export interface SesEventDestination {EventDestinationName?: string; Enabled?: boolean; MatchingEventTypes?: string[]; SnsDestination?: {TopicArn?: string}; EventBridgeDestination?: {EventBusArn?: string}; CloudWatchDestination?: {DimensionConfigurations?: Array<{DimensionName: string; DimensionValueSource: string; DefaultDimensionValue?: string}>}}
|
||||
export interface SesTopic {TopicArn?: string}
|
||||
export interface SesEventBus {Name?: string; Arn?: string}
|
||||
|
||||
export async function listSesIdentities(): Promise<SesIdentity[]> { return (await apiClient.get<SesIdentity[]>('/ses/identities')).data }
|
||||
export async function createSesIdentity(emailIdentity: string): Promise<void> { await apiClient.post('/ses/identities', {EmailIdentity: emailIdentity}) }
|
||||
export async function deleteSesIdentity(identity: string): Promise<void> { await apiClient.delete(`/ses/identities/${encodeURIComponent(identity)}`) }
|
||||
export async function sendSesSimple(input: unknown): Promise<void> { await apiClient.post('/ses/emails/simple', input) }
|
||||
export async function sendSesRaw(input: unknown): Promise<void> { await apiClient.post('/ses/emails/raw', input) }
|
||||
export async function sendSesTemplate(input: unknown): Promise<void> { await apiClient.post('/ses/emails/template', input) }
|
||||
export async function listSesSuppressions(): Promise<Array<{EmailAddress?: string; Reason?: string; LastUpdateTime?: string}>> { return (await apiClient.get<Array<{EmailAddress?: string; Reason?: string; LastUpdateTime?: string}>>('/ses/suppressions')).data }
|
||||
export async function putSesSuppression(emailAddress: string, reason: 'BOUNCE' | 'COMPLAINT'): Promise<void> { await apiClient.post('/ses/suppressions', {EmailAddress: emailAddress, Reason: reason}) }
|
||||
export async function deleteSesSuppression(emailAddress: string): Promise<void> { await apiClient.delete(`/ses/suppressions/${encodeURIComponent(emailAddress)}`) }
|
||||
export async function listSesTemplates(): Promise<SesTemplate[]> { return (await apiClient.get<SesTemplate[]>('/ses/templates')).data }
|
||||
export async function getSesTemplate(templateName: string): Promise<{TemplateContent?: {Subject?: string; Html?: string; Text?: string}}> { return (await apiClient.get<{TemplateContent?: {Subject?: string; Html?: string; Text?: string}}>(`/ses/templates/${encodeURIComponent(templateName)}`)).data }
|
||||
export async function saveSesTemplate(templateName: string, templateContent: {Subject: string; Html?: string; Text?: string}, existing: boolean): Promise<void> { if (existing) await apiClient.put(`/ses/templates/${encodeURIComponent(templateName)}`, {TemplateContent: templateContent}); else await apiClient.post('/ses/templates', {TemplateName: templateName, TemplateContent: templateContent}) }
|
||||
export async function deleteSesTemplate(templateName: string): Promise<void> { await apiClient.delete(`/ses/templates/${encodeURIComponent(templateName)}`) }
|
||||
export async function renderSesTemplate(templateName: string, templateData: string): Promise<string> { return (await apiClient.post<{RenderedTemplate: string}, {TemplateName: string; TemplateData: string}>('/ses/templates/test-render', {TemplateName: templateName, TemplateData: templateData})).data.RenderedTemplate }
|
||||
export async function listSesConfigurationSets(): Promise<SesConfigurationSet[]> { return (await apiClient.get<SesConfigurationSet[]>('/ses/configuration-sets')).data }
|
||||
export async function createSesConfigurationSet(configurationSetName: string): Promise<void> { await apiClient.post('/ses/configuration-sets', {ConfigurationSetName: configurationSetName}) }
|
||||
export async function deleteSesConfigurationSet(name: string): Promise<void> { await apiClient.delete(`/ses/configuration-sets/${encodeURIComponent(name)}`) }
|
||||
export async function listSesEventDestinations(name: string): Promise<SesEventDestination[]> { return (await apiClient.get<SesEventDestination[]>(`/ses/configuration-sets/${encodeURIComponent(name)}/event-destinations`)).data }
|
||||
export async function createSesEventDestination(name: string, input: unknown): Promise<void> { await apiClient.post(`/ses/configuration-sets/${encodeURIComponent(name)}/event-destinations`, input) }
|
||||
export async function deleteSesEventDestination(name: string, destination: string): Promise<void> { await apiClient.delete(`/ses/configuration-sets/${encodeURIComponent(name)}/event-destinations/${encodeURIComponent(destination)}`) }
|
||||
export async function listSesTopics(): Promise<SesTopic[]> { return (await apiClient.get<SesTopic[]>('/ses/inventory/sns-topics')).data }
|
||||
export async function listSesEventBuses(): Promise<SesEventBus[]> { return (await apiClient.get<SesEventBus[]>('/ses/inventory/event-buses')).data }
|
||||
Reference in New Issue
Block a user