Skip to content

Commit 22a090f

Browse files
committed
chore: merge main into release for new releases
2 parents 7613502 + fdbfc74 commit 22a090f

20 files changed

Lines changed: 554 additions & 141 deletions

File tree

.github/workflows/trigger-api-tasks-deploy-main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ jobs:
3131
- name: Build Integration Platform package
3232
working-directory: ./packages/integration-platform
3333
run: bun run build
34+
- name: Build Email package
35+
working-directory: ./packages/email
36+
run: bun run build
3437
- name: Build DB package
3538
working-directory: ./packages/db
3639
run: bun run build

.github/workflows/trigger-api-tasks-deploy-release.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ jobs:
3535
working-directory: ./packages/integration-platform
3636
run: bun run build
3737

38+
- name: Build Email package
39+
working-directory: ./packages/email
40+
run: bun run build
41+
3842
- name: Build DB package
3943
working-directory: ./packages/db
4044
run: bun run build

apps/api/emailExtension.ts

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import type {
2+
BuildContext,
3+
BuildExtension,
4+
BuildManifest,
5+
} from '@trigger.dev/build';
6+
import type { Plugin } from 'esbuild';
7+
import { existsSync } from 'node:fs';
8+
import { cp, mkdir } from 'node:fs/promises';
9+
import { resolve } from 'node:path';
10+
11+
const PACKAGE_NAME = '@trycompai/email';
12+
13+
/**
14+
* Custom Trigger.dev build extension for @trycompai/email workspace package.
15+
*
16+
* Since @trycompai/email is a workspace package (not published to npm),
17+
* we need to:
18+
* 1. Add an esbuild plugin to resolve the import path during build
19+
* 2. Copy the built dist files into the trigger.dev deployment
20+
*/
21+
export function emailExtension(): EmailExtension {
22+
return new EmailExtension();
23+
}
24+
25+
class EmailExtension implements BuildExtension {
26+
public readonly name = 'EmailExtension';
27+
private _packagePath: string | undefined;
28+
29+
async onBuildStart(context: BuildContext) {
30+
if (context.target === 'dev') {
31+
return;
32+
}
33+
34+
this._packagePath = this.findPackageRoot(context.workingDir);
35+
36+
if (!this._packagePath) {
37+
throw new Error(
38+
[
39+
`EmailExtension could not find ${PACKAGE_NAME}.`,
40+
'Make sure the package is built (run `bun run build` in packages/email).',
41+
].join('\n'),
42+
);
43+
}
44+
45+
context.logger.debug(`Found email package at ${this._packagePath}`);
46+
47+
const packagePath = this._packagePath;
48+
const resolvePlugin: Plugin = {
49+
name: 'resolve-email',
50+
setup(build) {
51+
build.onResolve({ filter: /^@trycompai\/email$/ }, () => {
52+
return {
53+
path: resolve(packagePath, 'dist/index.js'),
54+
};
55+
});
56+
57+
build.onResolve(
58+
{ filter: /^@trycompai\/email\// },
59+
(args) => {
60+
const subpath = args.path.replace(`${PACKAGE_NAME}/`, '');
61+
return {
62+
path: resolve(packagePath, 'dist', `${subpath}/index.js`),
63+
};
64+
},
65+
);
66+
},
67+
};
68+
69+
context.registerPlugin(resolvePlugin);
70+
}
71+
72+
async onBuildComplete(context: BuildContext, manifest: BuildManifest) {
73+
if (context.target === 'dev') {
74+
return;
75+
}
76+
77+
const packagePath = this._packagePath;
78+
if (!packagePath) {
79+
return;
80+
}
81+
82+
const packageDistPath = resolve(packagePath, 'dist');
83+
84+
const destPath = resolve(
85+
manifest.outputPath,
86+
'node_modules/@trycompai/email',
87+
);
88+
const destDistPath = resolve(destPath, 'dist');
89+
90+
await mkdir(destDistPath, { recursive: true });
91+
92+
await cp(packageDistPath, destDistPath, { recursive: true });
93+
94+
const packageJsonPath = resolve(packagePath, 'package.json');
95+
if (existsSync(packageJsonPath)) {
96+
await cp(packageJsonPath, resolve(destPath, 'package.json'));
97+
}
98+
99+
context.logger.log(
100+
'Copied @trycompai/email to deployment bundle',
101+
);
102+
}
103+
104+
private findPackageRoot(workingDir: string): string | undefined {
105+
const candidates = [
106+
resolve(workingDir, '../../packages/email'),
107+
resolve(workingDir, '../packages/email'),
108+
];
109+
110+
for (const candidate of candidates) {
111+
if (
112+
existsSync(candidate) &&
113+
existsSync(resolve(candidate, 'dist/index.js'))
114+
) {
115+
return candidate;
116+
}
117+
}
118+
119+
return undefined;
120+
}
121+
}

apps/api/trigger.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { PrismaInstrumentation } from '@prisma/instrumentation';
22
import { syncVercelEnvVars } from '@trigger.dev/build/extensions/core';
33
import { defineConfig } from '@trigger.dev/sdk';
44
import { prismaExtension } from './customPrismaExtension';
5+
import { emailExtension } from './emailExtension';
56
import { integrationPlatformExtension } from './integrationPlatformExtension';
67

78
export default defineConfig({
@@ -16,6 +17,7 @@ export default defineConfig({
1617
dbPackageVersion: '^1.3.15', // Version of @trycompai/db package with compiled JS
1718
}),
1819
integrationPlatformExtension(),
20+
emailExtension(),
1921
syncVercelEnvVars(),
2022
],
2123
},
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use server';
2+
3+
import { db } from '@db';
4+
import { revalidatePath, revalidateTag } from 'next/cache';
5+
import { headers } from 'next/headers';
6+
import { authActionClient } from '../safe-action';
7+
import { organizationDeviceAgentStepSchema } from '../schema';
8+
9+
export const updateOrganizationDeviceAgentStepAction = authActionClient
10+
.inputSchema(organizationDeviceAgentStepSchema)
11+
.metadata({
12+
name: 'update-organization-device-agent-step',
13+
track: {
14+
event: 'update-organization-device-agent-step',
15+
channel: 'server',
16+
},
17+
})
18+
.action(async ({ parsedInput, ctx }) => {
19+
const { deviceAgentStepEnabled } = parsedInput;
20+
const { activeOrganizationId } = ctx.session;
21+
22+
if (!activeOrganizationId) {
23+
throw new Error('No active organization');
24+
}
25+
26+
try {
27+
await db.organization.update({
28+
where: { id: activeOrganizationId },
29+
data: { deviceAgentStepEnabled },
30+
});
31+
32+
const headersList = await headers();
33+
let path = headersList.get('x-pathname') || headersList.get('referer') || '';
34+
path = path.replace(/\/[a-z]{2}\//, '/');
35+
36+
revalidatePath(path);
37+
revalidateTag(`organization_${activeOrganizationId}`, 'max');
38+
39+
return {
40+
success: true,
41+
};
42+
} catch (error) {
43+
console.error(error);
44+
throw new Error('Failed to update device agent step setting');
45+
}
46+
});
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use server';
2+
3+
import { db } from '@db';
4+
import { revalidatePath, revalidateTag } from 'next/cache';
5+
import { headers } from 'next/headers';
6+
import { authActionClient } from '../safe-action';
7+
import { organizationSecurityTrainingStepSchema } from '../schema';
8+
9+
export const updateOrganizationSecurityTrainingStepAction = authActionClient
10+
.inputSchema(organizationSecurityTrainingStepSchema)
11+
.metadata({
12+
name: 'update-organization-security-training-step',
13+
track: {
14+
event: 'update-organization-security-training-step',
15+
channel: 'server',
16+
},
17+
})
18+
.action(async ({ parsedInput, ctx }) => {
19+
const { securityTrainingStepEnabled } = parsedInput;
20+
const { activeOrganizationId } = ctx.session;
21+
22+
if (!activeOrganizationId) {
23+
throw new Error('No active organization');
24+
}
25+
26+
try {
27+
await db.organization.update({
28+
where: { id: activeOrganizationId },
29+
data: { securityTrainingStepEnabled },
30+
});
31+
32+
const headersList = await headers();
33+
let path = headersList.get('x-pathname') || headersList.get('referer') || '';
34+
path = path.replace(/\/[a-z]{2}\//, '/');
35+
36+
revalidatePath(path);
37+
revalidateTag(`organization_${activeOrganizationId}`, 'max');
38+
39+
return {
40+
success: true,
41+
};
42+
} catch (error) {
43+
console.error(error);
44+
throw new Error('Failed to update security training step setting');
45+
}
46+
});

apps/app/src/actions/schema.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ export const organizationEvidenceApprovalSchema = z.object({
6969
evidenceApprovalEnabled: z.boolean(),
7070
});
7171

72+
export const organizationDeviceAgentStepSchema = z.object({
73+
deviceAgentStepEnabled: z.boolean(),
74+
});
75+
76+
export const organizationSecurityTrainingStepSchema = z.object({
77+
securityTrainingStepEnabled: z.boolean(),
78+
});
79+
7280
// Risks
7381
export const createRiskSchema = z.object({
7482
title: z

0 commit comments

Comments
 (0)