Skip to content

Instantly share code, notes, and snippets.

@KONFeature
Created December 23, 2023 20:56
Show Gist options
  • Save KONFeature/ade9d1dc1b3b323f5f3f8b6b8316ece8 to your computer and use it in GitHub Desktop.
Save KONFeature/ade9d1dc1b3b323f5f3f8b6b8316ece8 to your computer and use it in GitHub Desktop.
Simple SST event builder using typebox instead of zod (missing a few stuff, like metadata)
import {
EventBridgeClient,
PutEventsCommand,
PutEventsCommandOutput,
PutEventsRequestEntry,
} from "@aws-sdk/client-eventbridge";
import { Static, TSchema } from "@sinclair/typebox";
import { TypeCompiler } from "@sinclair/typebox/compiler";
import { EventBus } from "sst/node/event-bus";
import { useLoader } from "./loaderReplica";
/**
* PutEventsCommandOutput is used in return type of createEvent, in case the consumer of SST builds
* their project with declaration files, this is not portable. In order to allow TS to generate a
* declaration file without reference to @aws-sdk/client-eventbridge, we must re-export the type.
*
* More information here: https://github.com/microsoft/TypeScript/issues/47663#issuecomment-1519138189
*/
export { PutEventsCommandOutput };
const client = new EventBridgeClient({});
export function createTypeboxEventBuilder<
Bus extends keyof typeof EventBus,
>(props: {
bus: Bus;
}) {
return function createEvent<
Type extends string,
Shape extends TSchema,
Properties = Static<Shape>,
>(type: Type, properties: Shape) {
type Publish = (
properties: Properties
) => Promise<PutEventsCommandOutput>;
const propertiesCompiler = TypeCompiler.Compile(properties);
const publish = async (properties: any, metadata: any) => {
return await useLoader(
"sst.bus.publish",
async (input: PutEventsRequestEntry[]) => {
const size = 10;
const promises: Promise<any>[] = [];
for (let i = 0; i < input.length; i += size) {
const chunk = input.slice(i, i + size);
promises.push(
client.send(
new PutEventsCommand({
Entries: chunk,
})
)
);
}
const settled = await Promise.allSettled(promises);
const result = new Array<PutEventsCommandOutput>(
input.length
);
for (let i = 0; i < result.length; i++) {
const item = settled[Math.floor(i / 10)];
if (item.status === "rejected") {
result[i] = item.reason;
continue;
}
result[i] = item.value;
}
return result;
}
)({
EventBusName: EventBus[props.bus].eventBusName,
// COnfig.APP of SST not exposed
Source: process.env.SST_APP,
Detail: JSON.stringify({
properties: propertiesCompiler.Encode(properties),
metadata: (() => undefined)(),
}),
DetailType: type,
});
};
return {
publish: publish as Publish,
type,
shape: {
metadata: {},
properties: {} as Properties,
metadataFn: {} as any,
},
};
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment