Skip to content

Commit 6ee432a

Browse files
authored
Merge pull request #949 from trycompai/main
[comp] Production Deploy
2 parents c5fd895 + 1b460f3 commit 6ee432a

File tree

91 files changed

+3210
-5650
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+3210
-5650
lines changed

apps/app/package.json

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,26 @@
3030
"@prisma/instrumentation": "6.6.0",
3131
"@react-email/components": "^0.0.41",
3232
"@react-email/render": "^1.1.2",
33-
"@tailwindcss/postcss": "^4.1.10",
3433
"@tanstack/react-query": "^5.74.4",
3534
"@tanstack/react-table": "^8.21.3",
35+
"@tiptap/extension-character-count": "^2.14.0",
36+
"@tiptap/extension-code-block-lowlight": "^2.14.0",
37+
"@tiptap/extension-color": "^2.14.0",
38+
"@tiptap/extension-highlight": "^2.14.0",
39+
"@tiptap/extension-horizontal-rule": "^2.14.0",
40+
"@tiptap/extension-image": "^2.14.0",
41+
"@tiptap/extension-link": "^2.14.0",
42+
"@tiptap/extension-placeholder": "^2.14.0",
3643
"@tiptap/extension-table": "^2.11.7",
3744
"@tiptap/extension-table-cell": "^2.11.7",
3845
"@tiptap/extension-table-header": "^2.11.7",
3946
"@tiptap/extension-table-row": "^2.11.7",
47+
"@tiptap/extension-task-item": "^2.14.0",
48+
"@tiptap/extension-task-list": "^2.14.0",
49+
"@tiptap/extension-text-align": "^2.14.0",
50+
"@tiptap/extension-text-style": "^2.14.0",
51+
"@tiptap/extension-underline": "^2.14.0",
52+
"@tiptap/extension-youtube": "^2.14.0",
4053
"@tiptap/pm": "^2.11.7",
4154
"@tiptap/react": "^2.11.7",
4255
"@tiptap/starter-kit": "^2.11.7",
@@ -54,15 +67,13 @@
5467
"geist": "^1.3.1",
5568
"highlight.js": "^11.11.1",
5669
"immer": "^10.1.1",
57-
"languine": "^3.1.4",
70+
"lowlight": "^3.3.0",
5871
"marked": "^15.0.11",
5972
"motion": "^12.9.2",
60-
"next": "15.4.0-canary.83",
61-
"next-international": "^1.3.1",
73+
"next": "15.4.0-canary.85",
6274
"next-intl": "^3.26.5",
6375
"next-safe-action": "^8.0.3",
6476
"next-themes": "^0.4.4",
65-
"novel": "^1.0.2",
6677
"novu": "^2.6.6",
6778
"nuqs": "^2.4.3",
6879
"playwright-core": "^1.52.0",
@@ -90,11 +101,12 @@
90101
"zustand": "^5.0.3"
91102
},
92103
"devDependencies": {
104+
"@tailwindcss/postcss": "^4.1.10",
93105
"@trigger.dev/build": "3.3.17",
94106
"@types/d3": "^7.4.3",
95-
"@types/node": "^22.13.2",
107+
"@types/node": "^24.0.3",
96108
"eslint": "^9",
97-
"eslint-config-next": "15.4.0-canary.83",
109+
"eslint-config-next": "15.4.0-canary.85",
98110
"fleetctl": "^4.68.1",
99111
"postcss": "^8.5.4",
100112
"react": "^19.1.0",

apps/app/src/actions/organization/accept-invitation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { db } from '@comp/db';
44
import { revalidatePath, revalidateTag } from 'next/cache';
55
import { Resend } from 'resend';
66
import { z } from 'zod';
7-
import { authActionClient } from '../safe-action';
7+
import { authActionClientWithoutOrg } from '../safe-action';
88
import type { ActionResponse } from '../types';
99

1010
async function validateInviteCode(inviteCode: string, invitedEmail: string) {
@@ -31,7 +31,7 @@ const completeInvitationSchema = z.object({
3131
inviteCode: z.string(),
3232
});
3333

34-
export const completeInvitation = authActionClient
34+
export const completeInvitation = authActionClientWithoutOrg
3535
.metadata({
3636
name: 'complete-invitation',
3737
track: {

apps/app/src/actions/organization/create-organization-action.ts renamed to apps/app/src/actions/organization/initialize-organization-action.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import { organizationSchema } from '../schema';
1010
import { createStripeCustomer } from './lib/create-stripe-customer';
1111
import { initializeOrganization } from './lib/initialize-organization';
1212

13-
export const createOrganizationAction = authActionClient
13+
export const initializeOrganizationAction = authActionClient
1414
.inputSchema(organizationSchema)
1515
.metadata({
16-
name: 'create-organization',
16+
name: 'initialize-organization',
1717
track: {
18-
event: 'create-organization',
18+
event: 'initialize-organization',
1919
channel: 'server',
2020
},
2121
})

apps/app/src/actions/safe-action.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,89 @@ export const authWithOrgAccessClient = authActionClient.use(async ({ next, clien
253253
},
254254
});
255255
});
256+
257+
// New action client that requires auth but not an active organization
258+
export const authActionClientWithoutOrg = actionClientWithMeta
259+
.use(async ({ next, clientInput }) => {
260+
const response = await auth.api.getSession({
261+
headers: await headers(),
262+
});
263+
264+
const { session, user } = response ?? {};
265+
266+
if (!session) {
267+
throw new Error('Unauthorized');
268+
}
269+
270+
const result = await next({
271+
ctx: {
272+
user: user,
273+
session: session,
274+
},
275+
});
276+
277+
if (process.env.NODE_ENV === 'development') {
278+
logger('Input ->', JSON.stringify(clientInput, null, 2));
279+
logger('Result ->', JSON.stringify(result.data, null, 2));
280+
281+
// Also log validation errors if they exist
282+
if (result.validationErrors) {
283+
logger('Validation Errors ->', JSON.stringify(result.validationErrors, null, 2));
284+
}
285+
286+
return result;
287+
}
288+
289+
return result;
290+
})
291+
.use(async ({ next, metadata }) => {
292+
const headersList = await headers();
293+
let remaining: number | undefined;
294+
295+
if (ratelimit) {
296+
const { success, remaining: rateLimitRemaining } = await ratelimit.limit(
297+
`${headersList.get('x-forwarded-for')}-${metadata.name}`,
298+
);
299+
300+
if (!success) {
301+
throw new Error('Too many requests');
302+
}
303+
304+
remaining = rateLimitRemaining;
305+
}
306+
307+
return next({
308+
ctx: {
309+
ip: headersList.get('x-forwarded-for'),
310+
userAgent: headersList.get('user-agent'),
311+
ratelimit: {
312+
remaining: remaining ?? 0,
313+
},
314+
},
315+
});
316+
})
317+
.use(async ({ next, metadata, ctx }) => {
318+
const session = await auth.api.getSession({
319+
headers: await headers(),
320+
});
321+
322+
if (!session) {
323+
throw new Error('Unauthorized');
324+
}
325+
326+
if (metadata.track) {
327+
track(session.user.id, metadata.track.event, {
328+
channel: metadata.track.channel,
329+
email: session.user.email,
330+
name: session.user.name,
331+
// organizationId is optional here since there might not be one
332+
organizationId: session.session.activeOrganizationId || undefined,
333+
});
334+
}
335+
336+
return next({
337+
ctx: {
338+
user: session.user,
339+
},
340+
});
341+
});

apps/app/src/app/(app)/[orgId]/policies/[policyId]/components/PolicyPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Control, Member, Policy, User } from '@comp/db/types';
2-
import { JSONContent } from 'novel';
2+
import type { JSONContent } from '@tiptap/react';
33
import { Comments, CommentWithAuthor } from '../../../../../../components/comments/Comments';
44
import { AuditLogWithRelations } from '../data';
55
import { PolicyPageEditor } from '../editor/components/PolicyDetails';

apps/app/src/app/(app)/[orgId]/policies/[policyId]/components/RecentAuditLogs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export const RecentAuditLogs = ({ logs }: { logs: AuditLogWithRelations[] }) =>
197197
</div>
198198
</div>
199199
) : (
200-
<div className="flex flex-col items-center justify-center p-6 text-center">
200+
<div className="flex flex-col items-center justify-center py-12 px-6 text-center">
201201
<ActivityIcon className="text-muted-foreground mb-2 h-8 w-8" />
202202
<p className="text-sm font-medium">No recent activity</p>
203203
<p className="text-muted-foreground text-xs">
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { getOrganizations } from '@/data/getOrganizations';
2+
import { auth } from '@/utils/auth';
3+
import { db } from '@comp/db';
4+
import type { Organization } from '@comp/db/types';
5+
import { headers } from 'next/headers';
6+
import { notFound, redirect } from 'next/navigation';
7+
import { AcceptInvite } from '../../setup/components/accept-invite';
8+
import { SetupHeader } from '../../setup/components/SetupHeader';
9+
10+
interface InvitePageProps {
11+
params: Promise<{ code: string }>;
12+
}
13+
14+
export default async function InvitePage({ params }: InvitePageProps) {
15+
const { code } = await params;
16+
const session = await auth.api.getSession({
17+
headers: await headers(),
18+
});
19+
20+
if (!session) {
21+
// Redirect to auth with the invite code
22+
return redirect(`/auth?inviteCode=${code}`);
23+
}
24+
25+
// Fetch existing organizations
26+
let organizations: Organization[] = [];
27+
try {
28+
const result = await getOrganizations();
29+
organizations = result.organizations;
30+
} catch (error) {
31+
// If user has no organizations, continue with empty array
32+
console.error('Failed to fetch organizations:', error);
33+
}
34+
35+
// Check if this invitation exists and is valid for this user
36+
const invitation = await db.invitation.findFirst({
37+
where: {
38+
id: code,
39+
email: session.user.email,
40+
status: 'pending',
41+
},
42+
include: {
43+
organization: {
44+
select: {
45+
name: true,
46+
},
47+
},
48+
},
49+
});
50+
51+
if (!invitation) {
52+
// Either invitation doesn't exist, already accepted, or not for this user
53+
notFound();
54+
}
55+
56+
return (
57+
<div className="flex min-h-screen flex-col">
58+
<SetupHeader user={session.user} existingOrganizations={organizations} />
59+
<div className="flex flex-1 items-center justify-center p-4">
60+
<AcceptInvite
61+
inviteCode={invitation.id}
62+
organizationName={invitation.organization.name || ''}
63+
/>
64+
</div>
65+
</div>
66+
);
67+
}

apps/app/src/app/(app)/no-access/page.tsx

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,6 @@ export default async function NoAccess() {
3030
},
3131
});
3232

33-
const frameworks = await db.frameworkEditorFramework.findMany({
34-
select: {
35-
id: true,
36-
name: true,
37-
description: true,
38-
version: true,
39-
visible: true,
40-
},
41-
});
42-
4333
return (
4434
<div className="bg-foreground/05 flex h-screen flex-col items-center justify-center gap-4">
4535
<h1 className="text-2xl font-bold">Access Denied</h1>
@@ -54,11 +44,7 @@ export default async function NoAccess() {
5444
<p>Please select another organization or contact your organization administrator.</p>
5545
</div>
5646
<div>
57-
<OrganizationSwitcher
58-
organizations={organizations}
59-
organization={currentOrg}
60-
frameworks={frameworks}
61-
/>
47+
<OrganizationSwitcher organizations={organizations} organization={currentOrg} />
6248
</div>
6349
</div>
6450
);

0 commit comments

Comments
 (0)