* - Replaced Supabase local environment variables - Updates packages - Force Zod v3 if peer deps require Zod v4 - Updated Dev Tool * Use correct field for pnpm overrides * Fix inaccuracies in the Agents files; fix type casting in `useForm` * Updated lock file * Be more specific when intercepting POST request in flaky e2e test
229 lines
5.6 KiB
TypeScript
229 lines
5.6 KiB
TypeScript
import { EnvMode } from '@/app/variables/lib/types';
|
|
|
|
import { getVariable } from '../variables/lib/env-scanner';
|
|
|
|
export function createConnectivityService(mode: EnvMode) {
|
|
return new ConnectivityService(mode);
|
|
}
|
|
|
|
class ConnectivityService {
|
|
constructor(private mode: EnvMode = 'development') {}
|
|
|
|
async checkSupabaseConnectivity() {
|
|
const url = await getVariable('NEXT_PUBLIC_SUPABASE_URL', this.mode);
|
|
|
|
if (!url) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: 'No Supabase URL found in environment variables',
|
|
};
|
|
}
|
|
|
|
const anonKey =
|
|
(await getVariable('NEXT_PUBLIC_SUPABASE_ANON_KEY', this.mode)) ||
|
|
(await getVariable('NEXT_PUBLIC_SUPABASE_PUBLIC_KEY', this.mode));
|
|
|
|
if (!anonKey) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: 'No Supabase Anon Key found in environment variables',
|
|
};
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`${url}/auth/v1/health`, {
|
|
headers: {
|
|
apikey: anonKey,
|
|
Authorization: `Bearer ${anonKey}`,
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
return {
|
|
status: 'error' as const,
|
|
message:
|
|
'Failed to connect to Supabase. The Supabase Anon Key or URL is not valid.',
|
|
};
|
|
}
|
|
|
|
return {
|
|
status: 'success' as const,
|
|
message: 'Connected to Supabase',
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: `Failed to connect to Supabase. ${error}`,
|
|
};
|
|
}
|
|
}
|
|
|
|
async checkSupabaseAdminConnectivity() {
|
|
const url = await getVariable('NEXT_PUBLIC_SUPABASE_URL', this.mode);
|
|
|
|
if (!url) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: 'No Supabase URL found in environment variables',
|
|
};
|
|
}
|
|
|
|
const endpoint = `${url}/rest/v1/accounts`;
|
|
|
|
const apikey =
|
|
(await getVariable('NEXT_PUBLIC_SUPABASE_ANON_KEY', this.mode)) ||
|
|
(await getVariable('NEXT_PUBLIC_SUPABASE_PUBLIC_KEY', this.mode));
|
|
|
|
if (!apikey) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: 'No Supabase Anon Key found in environment variables',
|
|
};
|
|
}
|
|
|
|
const adminKey =
|
|
(await getVariable('SUPABASE_SERVICE_ROLE_KEY', this.mode)) ||
|
|
(await getVariable('SUPABASE_SECRET_KEY', this.mode));
|
|
|
|
if (!adminKey) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: 'No Supabase Service Role Key found in environment variables',
|
|
};
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(endpoint, {
|
|
headers: {
|
|
apikey: adminKey,
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
return {
|
|
status: 'error' as const,
|
|
message:
|
|
'Failed to connect to Supabase Admin. The Supabase Service Role Key is not valid.',
|
|
};
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.length === 0) {
|
|
return {
|
|
status: 'error' as const,
|
|
message:
|
|
'No accounts found in Supabase Admin. The data may not be seeded. Please run `pnpm run supabase:web:reset` to reset the database.',
|
|
};
|
|
}
|
|
|
|
return {
|
|
status: 'success' as const,
|
|
message: 'Connected to Supabase Admin',
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: `Failed to connect to Supabase Admin. ${error}`,
|
|
};
|
|
}
|
|
}
|
|
|
|
async checkStripeWebhookEndpoints() {
|
|
const secretKey = await getVariable('STRIPE_SECRET_KEY', this.mode);
|
|
|
|
if (!secretKey) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: 'No Stripe Secret Key found in environment variables',
|
|
};
|
|
}
|
|
|
|
const webhooksSecret = await getVariable(
|
|
'STRIPE_WEBHOOK_SECRET',
|
|
this.mode,
|
|
);
|
|
|
|
if (!webhooksSecret) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: 'No Webhooks secret found in environment variables',
|
|
};
|
|
}
|
|
|
|
const url = `https://api.stripe.com`;
|
|
|
|
const request = await fetch(`${url}/v1/webhook_endpoints`, {
|
|
headers: {
|
|
Authorization: `Bearer ${secretKey}`,
|
|
},
|
|
});
|
|
|
|
if (!request.ok) {
|
|
return {
|
|
status: 'error' as const,
|
|
message:
|
|
'Failed to connect to Stripe. The Stripe Webhook Secret is not valid.',
|
|
};
|
|
}
|
|
|
|
const webhooksResponse = await request.json();
|
|
const webhooks = webhooksResponse.data ?? [];
|
|
|
|
if (webhooks.length === 0) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: 'No webhooks found in Stripe',
|
|
};
|
|
}
|
|
|
|
const allWebhooksShareTheSameSecret = webhooks.every(
|
|
(webhook: { secret: string }) => webhook.secret === webhooksSecret,
|
|
);
|
|
|
|
if (!allWebhooksShareTheSameSecret) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: 'All webhooks do not share the same secret',
|
|
};
|
|
}
|
|
|
|
return {
|
|
status: 'success' as const,
|
|
message: 'All webhooks share the same Webhooks secret',
|
|
};
|
|
}
|
|
|
|
async checkStripeConnected() {
|
|
const secretKey = await getVariable('STRIPE_SECRET_KEY', this.mode);
|
|
|
|
if (!secretKey) {
|
|
return {
|
|
status: 'error' as const,
|
|
message: 'No Stripe Secret Key found in environment variables',
|
|
};
|
|
}
|
|
|
|
const url = `https://api.stripe.com`;
|
|
|
|
const request = await fetch(`${url}/v1/prices`, {
|
|
headers: {
|
|
Authorization: `Bearer ${secretKey}`,
|
|
},
|
|
});
|
|
|
|
if (!request.ok) {
|
|
return {
|
|
status: 'error' as const,
|
|
message:
|
|
'Failed to connect to Stripe. The Stripe Secret Key is not valid.',
|
|
};
|
|
}
|
|
|
|
return {
|
|
status: 'success' as const,
|
|
message: 'Connected to Stripe',
|
|
};
|
|
}
|
|
}
|