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
1 change: 1 addition & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"dev": "bun run --hot src/server.ts",
"build": "tsc",
"start": "bun run src/server.ts",
"worker:sequences": "bun run src/workers/sequence-worker.ts",
"check-types": "tsc --noEmit && tsc --noEmit -p test/tsconfig.json",
"lint": "eslint .",
"test": "TZ=UTC vitest run",
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/config/env.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const rawEnv = {
RESEND_FROM_EMAIL: process.env.RESEND_FROM_EMAIL,
GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
SEQUENCE_LIVE_SEND_ENABLED: process.env.SEQUENCE_LIVE_SEND_ENABLED,
GROQ_API_KEY: process.env.GROQ_API_KEY,
};

const parsedEnv = apiEnvSchema.safeParse(rawEnv);
Expand Down
213 changes: 213 additions & 0 deletions apps/api/src/controllers/sequences.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import type { Context } from "hono";
import type {
ConnectGmailInput,
CreateSequenceInput,
EnrollPeopleInput,
GenerateEmailContentInput,
ListEnrollmentsQuery,
ListSequencesQuery,
UpdateSequenceInput,
UpdateSequenceStepInput,
} from "@workspace/validators/schemas/sequence";
import { STATUS_CODES } from "@/constants/status-codes.js";
import { sendSuccess } from "@/lib/api-response.js";
import { getSessionWorkspaceId } from "@/lib/workspace.js";
import {
archiveSequence,
completeSequenceTask,
confirmUnsubscribe,
connectGmail,
createSequence,
deleteSequence,
disconnectGmail,
enrollPeople,
generateSequenceEmailContent,
getSequence,
getSequenceDashboard,
listGmailIntegrations,
listSequenceActivity,
listSequenceEnrollments,
listSequences,
pauseEnrollment,
previewUnsubscribe,
publishSequence,
resumeEnrollment,
updateSequence,
updateSequenceStep,
} from "@/services/sequence.service.js";

export async function listSequencesController(c: Context, query: ListSequencesQuery) {
return sendSuccess(c, await listSequences(getSessionWorkspaceId(c), query), STATUS_CODES.OK);
}

export async function createSequenceController(c: Context, input: CreateSequenceInput) {
const workspaceId = getSessionWorkspaceId(c);
const user = c.get("user");
return sendSuccess(c, { sequence: await createSequence(workspaceId, user.id, input) }, STATUS_CODES.CREATED);
}

export async function getSequenceController(c: Context, sequenceId: string) {
return sendSuccess(c, await getSequence(getSessionWorkspaceId(c), sequenceId), STATUS_CODES.OK);
}

export async function updateSequenceController(
c: Context,
sequenceId: string,
input: UpdateSequenceInput,
) {
return sendSuccess(
c,
await updateSequence(getSessionWorkspaceId(c), sequenceId, input),
STATUS_CODES.OK,
);
}

export async function updateSequenceStepController(
c: Context,
sequenceId: string,
stepId: string,
input: UpdateSequenceStepInput,
) {
return sendSuccess(
c,
{ step: await updateSequenceStep(getSessionWorkspaceId(c), sequenceId, stepId, input) },
STATUS_CODES.OK,
);
}

export async function publishSequenceController(c: Context, sequenceId: string) {
const workspaceId = getSessionWorkspaceId(c);
const user = c.get("user");
return sendSuccess(
c,
{ version: await publishSequence(workspaceId, sequenceId, user.id) },
STATUS_CODES.OK,
);
}

export async function archiveSequenceController(c: Context, sequenceId: string) {
return sendSuccess(
c,
{ sequence: await archiveSequence(getSessionWorkspaceId(c), sequenceId) },
STATUS_CODES.OK,
);
}

export async function deleteSequenceController(c: Context, sequenceId: string) {
return sendSuccess(
c,
{ sequence: await deleteSequence(getSessionWorkspaceId(c), sequenceId) },
STATUS_CODES.OK,
);
}

export async function enrollPeopleController(
c: Context,
sequenceId: string,
input: EnrollPeopleInput,
) {
const workspaceId = getSessionWorkspaceId(c);
const user = c.get("user");
return sendSuccess(
c,
{ enrollments: await enrollPeople(workspaceId, sequenceId, user.id, input) },
STATUS_CODES.CREATED,
);
}

export async function listSequenceEnrollmentsController(
c: Context,
sequenceId: string,
query: ListEnrollmentsQuery,
) {
return sendSuccess(
c,
{ enrollments: await listSequenceEnrollments(getSessionWorkspaceId(c), sequenceId, query) },
STATUS_CODES.OK,
);
}

export async function listSequenceActivityController(c: Context, sequenceId: string) {
return sendSuccess(
c,
{ activity: await listSequenceActivity(getSessionWorkspaceId(c), sequenceId) },
STATUS_CODES.OK,
);
}

export async function pauseEnrollmentController(c: Context, enrollmentId: string) {
return sendSuccess(
c,
{ enrollment: await pauseEnrollment(getSessionWorkspaceId(c), enrollmentId) },
STATUS_CODES.OK,
);
}

export async function resumeEnrollmentController(c: Context, enrollmentId: string) {
return sendSuccess(
c,
{ enrollment: await resumeEnrollment(getSessionWorkspaceId(c), enrollmentId) },
STATUS_CODES.OK,
);
}

export async function completeSequenceTaskController(c: Context, taskId: string) {
return sendSuccess(
c,
{ task: await completeSequenceTask(getSessionWorkspaceId(c), taskId) },
STATUS_CODES.OK,
);
}

export async function getSequenceDashboardController(c: Context) {
return sendSuccess(c, await getSequenceDashboard(getSessionWorkspaceId(c)), STATUS_CODES.OK);
}

export async function listGmailIntegrationsController(c: Context) {
const user = c.get("user");
return sendSuccess(
c,
{ gmailIntegrations: await listGmailIntegrations(getSessionWorkspaceId(c), user.id) },
STATUS_CODES.OK,
);
}

export async function connectGmailController(c: Context, input: ConnectGmailInput) {
const user = c.get("user");
return sendSuccess(
c,
{ gmailIntegration: await connectGmail(getSessionWorkspaceId(c), user.id, input) },
STATUS_CODES.CREATED,
);
}

export async function disconnectGmailController(c: Context, gmailIntegrationId: string) {
const user = c.get("user");
return sendSuccess(
c,
{
gmailIntegration: await disconnectGmail(
getSessionWorkspaceId(c),
user.id,
gmailIntegrationId,
),
},
STATUS_CODES.OK,
);
}

export async function generateEmailContentController(c: Context, input: GenerateEmailContentInput) {
return sendSuccess(
c,
{ email: await generateSequenceEmailContent(input.prompt) },
STATUS_CODES.OK,
);
}

export async function previewUnsubscribeController(c: Context, token: string) {
return sendSuccess(c, await previewUnsubscribe(token), STATUS_CODES.OK);
}

export async function confirmUnsubscribeController(c: Context, token: string) {
return sendSuccess(c, await confirmUnsubscribe(token), STATUS_CODES.OK);
}
Loading
Loading