Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion application-templates/javascript/event/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,16 @@ CTP_CLIENT_ID=
CTP_CLIENT_SECRET=
CTP_PROJECT_KEY=
CTP_SCOPE=
CTP_REGION=
CTP_REGION=
PORT=

# Subscription destination configuration
# Options: "GoogleCloudPubSub" or "SNS"
CONNECT_SUBSCRIPTION_DESTINATION=

# GCP Pub/Sub configuration (required if CONNECT_SUBSCRIPTION_DESTINATION=GoogleCloudPubSub)
CONNECT_GCP_TOPIC_NAME=
CONNECT_GCP_PROJECT_ID=

# AWS SNS configuration (required if CONNECT_SUBSCRIPTION_DESTINATION=SNS)
CONNECT_AWS_TOPIC_ARN=
128 changes: 91 additions & 37 deletions application-templates/javascript/event/src/connector/actions.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,101 @@
import { assertNonNullable } from '../utils/assert.utils.js';

const CUSTOMER_CREATE_SUBSCRIPTION_KEY =
'myconnector-customerCreateSubscription';

export async function createGcpPubSubCustomerCreateSubscription(
apiRoot,
topicName,
projectId
) {
const destination = {
type: 'GoogleCloudPubSub',
topic: topicName,
projectId,
};
await createSubscription(apiRoot, destination);
}

export async function createAzureServiceBusCustomerCreateSubscription(
apiRoot,
connectionString
) {
const destination = {
type: 'AzureServiceBus',
connectionString: connectionString,
};
await createSubscription(apiRoot, destination);
}

async function createSubscription(apiRoot, destination) {
await deleteCustomerCreateSubscription(apiRoot);
await apiRoot
export async function createCustomerCreateSubscription(apiRoot, config) {
// Delete existing subscription first (inline deletion)
const {
body: { results: subscriptions },
} = await apiRoot
.subscriptions()
.post({
body: {
key: CUSTOMER_CREATE_SUBSCRIPTION_KEY,
destination,
messages: [
{
resourceTypeId: 'customer',
types: ['CustomerCreated'],
},
],
.get({
queryArgs: {
where: `key = "${CUSTOMER_CREATE_SUBSCRIPTION_KEY}"`,
},
})
.execute();

if (subscriptions.length > 0) {
const subscription = subscriptions[0];
await apiRoot
.subscriptions()
.withKey({ key: CUSTOMER_CREATE_SUBSCRIPTION_KEY })
.delete({
queryArgs: {
version: subscription.version,
},
})
.execute();
}

// Google Cloud Pub/Sub subscription
if (config.connectSubscriptionDestination === 'GoogleCloudPubSub') {
assertNonNullable(
config.connectGcpTopicName,
'GCP Topic Name must be provided for GoogleCloudPubSub destination'
);
assertNonNullable(
config.connectGcpProjectId,
'GCP Project ID must be provided for GoogleCloudPubSub destination'
);

await apiRoot
.subscriptions()
.post({
body: {
key: CUSTOMER_CREATE_SUBSCRIPTION_KEY,
destination: {
type: 'GoogleCloudPubSub',
topic: config.connectGcpTopicName,
projectId: config.connectGcpProjectId,
},
messages: [
{
resourceTypeId: 'customer',
types: ['CustomerCreated'],
},
],
},
})
.execute();

return;
}

// AWS SNS subscription
if (config.connectSubscriptionDestination === 'SNS') {
assertNonNullable(
config.connectAwsTopicArn,
'AWS Topic ARN must be provided for SNS destination'
);

await apiRoot
.subscriptions()
.post({
body: {
key: CUSTOMER_CREATE_SUBSCRIPTION_KEY,
destination: {
type: 'SNS',
topicArn: config.connectAwsTopicArn,
authenticationMode: 'IAM',
},
messages: [
{
resourceTypeId: 'customer',
types: ['CustomerCreated'],
},
],
},
})
.execute();

return;
}

throw new Error(
`Unknown subscription destination type: ${config.connectSubscriptionDestination}`
);
}

export async function deleteCustomerCreateSubscription(apiRoot) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,52 +1,17 @@
import dotenv from 'dotenv';
dotenv.config();

import { createApiRoot } from '../client/create.client.js';
import { assertError, assertString } from '../utils/assert.utils.js';
import {
createGcpPubSubCustomerCreateSubscription,
createAzureServiceBusCustomerCreateSubscription,
} from './actions.js';

const CONNECT_GCP_TOPIC_NAME_KEY = 'CONNECT_GCP_TOPIC_NAME';
const CONNECT_GCP_PROJECT_ID_KEY = 'CONNECT_GCP_PROJECT_ID';
const CONNECT_PROVIDER_KEY = 'CONNECT_PROVIDER';
const CONNECT_AZURE_CONNECTION_STRING_KEY = 'CONNECT_AZURE_CONNECTION_STRING';
import { assertError } from '../utils/assert.utils.js';
import { createCustomerCreateSubscription } from './actions.js';
import { readConfiguration } from '../utils/config.utils.js';

async function postDeploy(properties) {
const connectProvider = properties.get(CONNECT_PROVIDER_KEY);
assertString(connectProvider, CONNECT_PROVIDER_KEY);
async function postDeploy(config) {
const apiRoot = createApiRoot();

switch (connectProvider) {
case 'AZURE': {
const connectionString = properties.get(
CONNECT_AZURE_CONNECTION_STRING_KEY
);
assertString(connectionString, CONNECT_AZURE_CONNECTION_STRING_KEY);
await createAzureServiceBusCustomerCreateSubscription(
apiRoot,
connectionString
);
break;
}
default: {
const topicName = properties.get(CONNECT_GCP_TOPIC_NAME_KEY);
const projectId = properties.get(CONNECT_GCP_PROJECT_ID_KEY);
assertString(topicName, CONNECT_GCP_TOPIC_NAME_KEY);
assertString(projectId, CONNECT_GCP_PROJECT_ID_KEY);
await createGcpPubSubCustomerCreateSubscription(
apiRoot,
topicName,
projectId
);
}
}
await createCustomerCreateSubscription(apiRoot, config);
}

async function run() {
try {
const properties = new Map(Object.entries(process.env));
await postDeploy(properties);
const config = readConfiguration();
await postDeploy(config);
} catch (error) {
assertError(error);
process.stderr.write(`Post-deploy failed: ${error.message}\n`);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import dotenv from 'dotenv';
dotenv.config();

import { createApiRoot } from '../client/create.client.js';
import { assertError } from '../utils/assert.utils.js';
import { deleteCustomerCreateSubscription } from './actions.js';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ export function assertError(value, message) {
export function assertString(value, message) {
assert(typeof value === 'string', message ?? 'Invalid string value');
}

export function assertNonNullable(value, message) {
assert(
value !== null && value !== undefined,
message ?? 'Value is null or undefined'
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ export const readConfiguration = () => {
projectKey: process.env.CTP_PROJECT_KEY,
scope: process.env.CTP_SCOPE,
region: process.env.CTP_REGION,
port: process.env.PORT,
connectSubscriptionDestination:
process.env.CONNECT_SUBSCRIPTION_DESTINATION,
connectGcpTopicName: process.env.CONNECT_GCP_TOPIC_NAME,
connectGcpProjectId: process.env.CONNECT_GCP_PROJECT_ID,
connectAwsTopicArn: process.env.CONNECT_AWS_TOPIC_ARN,
};

const validationErrors = getValidateMessages(envValidators, envVars);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const envValidators = [
referencedBy: 'environmentVariables',
}),

optional(standardString)(
standardString(
['scope'],
{
code: 'InvalidScope',
Expand All @@ -50,6 +50,56 @@ const envValidators = [
message: 'Not a valid region.',
referencedBy: 'environmentVariables',
}),

standardString(
['port'],
{
code: 'InvalidPort',
message: 'Port should be a valid string.',
referencedBy: 'environmentVariables',
},
{ min: 1, max: undefined }
),

optional(standardString)(
['connectSubscriptionDestination'],
{
code: 'InvalidSubscriptionDestination',
message: 'Subscription destination should be a valid string.',
referencedBy: 'environmentVariables',
},
{ min: 2, max: undefined }
),

optional(standardString)(
['connectGcpTopicName'],
{
code: 'InvalidGcpTopicName',
message: 'GCP Topic Name should be a valid string.',
referencedBy: 'environmentVariables',
},
{ min: 2, max: undefined }
),

optional(standardString)(
['connectGcpProjectId'],
{
code: 'InvalidGcpProjectId',
message: 'GCP Project ID should be a valid string.',
referencedBy: 'environmentVariables',
},
{ min: 2, max: undefined }
),

optional(standardString)(
['connectAwsTopicArn'],
{
code: 'InvalidAwsTopicArn',
message: 'AWS Topic ARN should be a valid string.',
referencedBy: 'environmentVariables',
},
{ min: 2, max: undefined }
),
];

export default envValidators;
14 changes: 13 additions & 1 deletion application-templates/typescript/event/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,16 @@ CTP_CLIENT_ID=
CTP_CLIENT_SECRET=
CTP_PROJECT_KEY=
CTP_SCOPE=
CTP_REGION=
CTP_REGION=
PORT=

# Subscription destination configuration
# Options: "GoogleCloudPubSub" or "SNS"
CONNECT_SUBSCRIPTION_DESTINATION=

# GCP Pub/Sub configuration (required if CONNECT_SUBSCRIPTION_DESTINATION=GoogleCloudPubSub)
CONNECT_GCP_TOPIC_NAME=
CONNECT_GCP_PROJECT_ID=

# AWS SNS configuration (required if CONNECT_SUBSCRIPTION_DESTINATION=SNS)
CONNECT_AWS_TOPIC_ARN=
Loading
Loading