+
{props.children}
);
diff --git a/apps/web/app/admin/_components/admin-sidebar.tsx b/apps/web/app/admin/_components/admin-sidebar.tsx
new file mode 100644
index 000000000..de651a9d4
--- /dev/null
+++ b/apps/web/app/admin/_components/admin-sidebar.tsx
@@ -0,0 +1,35 @@
+import { Home, Users } from 'lucide-react';
+
+import {
+ Sidebar,
+ SidebarContent,
+ SidebarGroup,
+ SidebarItem,
+} from '@kit/ui/sidebar';
+
+import { AppLogo } from '~/components/app-logo';
+
+export function AdminSidebar() {
+ return (
+
+
+
+
+
+
+
+ }>
+ Home
+
+
+ }
+ >
+ Accounts
+
+
+
+
+ );
+}
diff --git a/apps/web/app/admin/accounts/[account]/page.tsx b/apps/web/app/admin/accounts/[account]/page.tsx
new file mode 100644
index 000000000..e69de29bb
diff --git a/apps/web/app/admin/accounts/page.tsx b/apps/web/app/admin/accounts/page.tsx
new file mode 100644
index 000000000..9129598de
--- /dev/null
+++ b/apps/web/app/admin/accounts/page.tsx
@@ -0,0 +1,10 @@
+import { PageBody, PageHeader } from '@kit/ui/page';
+
+export default function AccountsPage() {
+ return (
+ <>
+
+ ;
+ >
+ );
+}
diff --git a/apps/web/app/admin/layout.tsx b/apps/web/app/admin/layout.tsx
new file mode 100644
index 000000000..7a858e9c4
--- /dev/null
+++ b/apps/web/app/admin/layout.tsx
@@ -0,0 +1,7 @@
+import { Page } from '@kit/ui/page';
+
+import { AdminSidebar } from '~/admin/_components/admin-sidebar';
+
+export default function AdminLayout(props: React.PropsWithChildren) {
+ return }>{props.children};
+}
diff --git a/apps/web/app/admin/page.tsx b/apps/web/app/admin/page.tsx
new file mode 100644
index 000000000..146377d9e
--- /dev/null
+++ b/apps/web/app/admin/page.tsx
@@ -0,0 +1,11 @@
+import { PageBody, PageHeader } from '@kit/ui/page';
+
+export default function AdminPage() {
+ return (
+ <>
+
+
+
+ >
+ );
+}
diff --git a/apps/web/app/join/_lib/server/join-team.service.ts b/apps/web/app/join/_lib/server/join-team.service.ts
new file mode 100644
index 000000000..a77ebc08a
--- /dev/null
+++ b/apps/web/app/join/_lib/server/join-team.service.ts
@@ -0,0 +1,47 @@
+import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
+
+export class JoinTeamService {
+ async isCurrentUserAlreadyInAccount(accountId: string) {
+ const client = getSupabaseServerComponentClient();
+
+ const { data } = await client
+ .from('accounts')
+ .select('id')
+ .eq('id', accountId)
+ .maybeSingle();
+
+ return !!data?.id;
+ }
+
+ async getInviteDataFromInviteToken(token: string) {
+ // we use an admin client to be able to read the pending membership
+ // without having to be logged in
+ const adminClient = getSupabaseServerComponentClient({ admin: true });
+
+ const { data: invitation, error } = await adminClient
+ .from('invitations')
+ .select<
+ string,
+ {
+ id: string;
+ account: {
+ id: string;
+ name: string;
+ slug: string;
+ picture_url: string;
+ };
+ }
+ >(
+ 'id, expires_at, account: account_id !inner (id, name, slug, picture_url)',
+ )
+ .eq('invite_token', token)
+ .gte('expires_at', new Date().toISOString())
+ .single();
+
+ if (!invitation ?? error) {
+ return null;
+ }
+
+ return invitation;
+ }
+}
diff --git a/apps/web/app/join/page.tsx b/apps/web/app/join/page.tsx
index a16aca495..879c1071a 100644
--- a/apps/web/app/join/page.tsx
+++ b/apps/web/app/join/page.tsx
@@ -3,7 +3,6 @@ import { notFound, redirect } from 'next/navigation';
import { ArrowLeft } from 'lucide-react';
-import { Logger } from '@kit/shared/logger';
import { requireUser } from '@kit/supabase/require-user';
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
import { AcceptInvitationContainer } from '@kit/team-accounts/components';
@@ -15,6 +14,8 @@ import pathsConfig from '~/config/paths.config';
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
import { withI18n } from '~/lib/i18n/with-i18n';
+import { JoinTeamService } from './_lib/server/join-team.service';
+
interface Context {
searchParams: {
invite_token: string;
@@ -47,19 +48,23 @@ async function JoinTeamAccountPage({ searchParams }: Context) {
redirect(pathsConfig.auth.signUp + '?invite_token=' + token);
}
+ const service = new JoinTeamService();
+
// the user is logged in, we can now check if the token is valid
- const invitation = await getInviteDataFromInviteToken(token);
+ const invitation = await service.getInviteDataFromInviteToken(token);
if (!invitation) {
return ;
}
// we need to verify the user isn't already in the account
- const isInAccount = await isCurrentUserAlreadyInAccount(
+ const isInAccount = await service.isCurrentUserAlreadyInAccount(
invitation.account.id,
);
if (isInAccount) {
+ const { Logger } = await import('@kit/shared/logger');
+
Logger.warn(
{
name: 'join-team-account',
@@ -97,56 +102,6 @@ async function JoinTeamAccountPage({ searchParams }: Context) {
export default withI18n(JoinTeamAccountPage);
-/**
- * Verifies that the current user is not already in the account by
- * reading the document from the `accounts` table. If the user can read it
- * it means they are already in the account.
- * @param accountId
- */
-async function isCurrentUserAlreadyInAccount(accountId: string) {
- const client = getSupabaseServerComponentClient();
-
- const { data } = await client
- .from('accounts')
- .select('id')
- .eq('id', accountId)
- .maybeSingle();
-
- return !!data?.id;
-}
-
-async function getInviteDataFromInviteToken(token: string) {
- // we use an admin client to be able to read the pending membership
- // without having to be logged in
- const adminClient = getSupabaseServerComponentClient({ admin: true });
-
- const { data: invitation, error } = await adminClient
- .from('invitations')
- .select<
- string,
- {
- id: string;
- account: {
- id: string;
- name: string;
- slug: string;
- picture_url: string;
- };
- }
- >(
- 'id, expires_at, account: account_id !inner (id, name, slug, picture_url)',
- )
- .eq('invite_token', token)
- .gte('expires_at', new Date().toISOString())
- .single();
-
- if (!invitation ?? error) {
- return null;
- }
-
- return invitation;
-}
-
function InviteNotFoundOrExpired() {
return (
diff --git a/apps/web/instrumentation.ts b/apps/web/instrumentation.ts
index a1dfadbb7..ca20f6ef0 100644
--- a/apps/web/instrumentation.ts
+++ b/apps/web/instrumentation.ts
@@ -1,7 +1,9 @@
import { registerInstrumentation } from '@kit/monitoring';
-export async function register() {
- // Register monitoring instrumentation based on the
- // MONITORING_INSTRUMENTATION_PROVIDER environment variable.
- await registerInstrumentation();
+export function register() {
+ if (process.env.NEXT_RUNTIME !== 'nodejs') {
+ // Register monitoring instrumentation based on the
+ // MONITORING_INSTRUMENTATION_PROVIDER environment variable.
+ return registerInstrumentation();
+ }
}
diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs
index 910641b88..edf006881 100644
--- a/apps/web/next.config.mjs
+++ b/apps/web/next.config.mjs
@@ -23,6 +23,7 @@ const INTERNAL_PACKAGES = [
/** @type {import('next').NextConfig} */
const config = {
reactStrictMode: true,
+ swcMinify: true,
/** Enables hot reloading for local packages without a build step */
transpilePackages: INTERNAL_PACKAGES,
pageExtensions: ['ts', 'tsx'],
diff --git a/packages/cms/wordpress/package.json b/packages/cms/wordpress/package.json
index 60fc579e4..2dc702777 100644
--- a/packages/cms/wordpress/package.json
+++ b/packages/cms/wordpress/package.json
@@ -7,7 +7,6 @@
"format": "prettier --check \"**/*.{ts,tsx}\"",
"lint": "eslint .",
"typecheck": "tsc --noEmit",
- "build": "contentlayer build",
"start": "docker compose up"
},
"prettier": "@kit/prettier-config",
diff --git a/packages/monitoring/baselime/src/index.ts b/packages/monitoring/baselime/src/index.ts
index e1bc23d25..590437486 100644
--- a/packages/monitoring/baselime/src/index.ts
+++ b/packages/monitoring/baselime/src/index.ts
@@ -1,9 +1,3 @@
-import {
- BaselimeSDK,
- BetterHttpInstrumentation,
- VercelPlugin,
-} from '@baselime/node-opentelemetry';
-
const INSTRUMENTATION_SERVICE_NAME = process.env.INSTRUMENTATION_SERVICE_NAME;
if (!INSTRUMENTATION_SERVICE_NAME) {
@@ -18,7 +12,11 @@ if (!INSTRUMENTATION_SERVICE_NAME) {
*
* Please set the MONITORING_INSTRUMENTATION_PROVIDER environment variable to 'baselime' to register Baselime instrumentation.
*/
-export function registerBaselimeInstrumentation() {
+export async function registerBaselimeInstrumentation() {
+ const { BaselimeSDK, BetterHttpInstrumentation, VercelPlugin } = await import(
+ '@baselime/node-opentelemetry'
+ );
+
const sdk = new BaselimeSDK({
serverless: true,
service: INSTRUMENTATION_SERVICE_NAME,
diff --git a/packages/monitoring/sentry/src/index.ts b/packages/monitoring/sentry/src/index.ts
index cc9c91ced..67385ced0 100644
--- a/packages/monitoring/sentry/src/index.ts
+++ b/packages/monitoring/sentry/src/index.ts
@@ -1,11 +1,3 @@
-import { Resource } from '@opentelemetry/resources';
-import { NodeSDK } from '@opentelemetry/sdk-node';
-import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
-import {
- SentryPropagator,
- SentrySpanProcessor,
-} from '@sentry/opentelemetry-node';
-
const INSTRUMENTATION_SERVICE_NAME = process.env.INSTRUMENTATION_SERVICE_NAME;
if (!INSTRUMENTATION_SERVICE_NAME) {
@@ -20,7 +12,18 @@ if (!INSTRUMENTATION_SERVICE_NAME) {
*
* Please set the MONITORING_INSTRUMENTATION_PROVIDER environment variable to 'sentry' to register Sentry instrumentation.
*/
-export function registerSentryInstrumentation() {
+export async function registerSentryInstrumentation() {
+ const { Resource } = await import('@opentelemetry/resources');
+ const { NodeSDK } = await import('@opentelemetry/sdk-node');
+
+ const { SEMRESATTRS_SERVICE_NAME } = await import(
+ '@opentelemetry/semantic-conventions'
+ );
+
+ const { SentrySpanProcessor, SentryPropagator } = await import(
+ '@sentry/opentelemetry-node'
+ );
+
const sdk = new NodeSDK({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: INSTRUMENTATION_SERVICE_NAME,
diff --git a/packages/monitoring/src/instrumentation.ts b/packages/monitoring/src/instrumentation.ts
index aa6abd654..70e228ac4 100644
--- a/packages/monitoring/src/instrumentation.ts
+++ b/packages/monitoring/src/instrumentation.ts
@@ -17,7 +17,6 @@ const DEFAULT_INSTRUMENTATION_PROVIDER = process.env
* Please set the MONITORING_INSTRUMENTATION_PROVIDER environment variable to register the monitoring instrumentation provider.
*/
export async function registerInstrumentation() {
- // Only run instrumentation in Node.js environment
if (
process.env.NEXT_RUNTIME !== 'nodejs' ||
!DEFAULT_INSTRUMENTATION_PROVIDER
@@ -39,6 +38,8 @@ export async function registerInstrumentation() {
}
default:
- throw new Error(`Unknown instrumentation provider`);
+ throw new Error(
+ `Unknown instrumentation provider: ${DEFAULT_INSTRUMENTATION_PROVIDER as string}`,
+ );
}
}
diff --git a/packages/shared/src/logger/index.ts b/packages/shared/src/logger/index.ts
index 0323c4dca..e6610e16b 100644
--- a/packages/shared/src/logger/index.ts
+++ b/packages/shared/src/logger/index.ts
@@ -1,12 +1,14 @@
import { Logger as LoggerInstance } from './logger';
+const LOGGER = process.env.LOGGER ?? 'pino';
+
/*
* Logger
* By default, the logger is set to use Pino. To change the logger, update the import statement below.
* to your desired logger implementation.
*/
async function getLogger(): Promise {
- switch (process.env.LOGGER ?? 'pino') {
+ switch (LOGGER) {
case 'pino': {
const { Logger: PinoLogger } = await import('./impl/pino');