Skip to content

Commit bd6cf41

Browse files
committed
improvement(types): enforce outside just hooks dir and update CI checks
1 parent 49c1201 commit bd6cf41

92 files changed

Lines changed: 1679 additions & 1210 deletions

File tree

Some content is hidden

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

apps/sim/app/(auth)/login/login-form.tsx

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {
1515
ModalDescription,
1616
ModalHeader,
1717
} from '@/components/emcn'
18+
import { requestJson } from '@/lib/api/client/request'
19+
import { forgetPasswordContract } from '@/lib/api/contracts'
1820
import { client } from '@/lib/auth/auth-client'
1921
import { getEnv, isFalsy, isTruthy } from '@/lib/core/config/env'
2022
import { validateCallbackUrl } from '@/lib/core/security/input-validation'
@@ -282,20 +284,16 @@ export default function LoginPage({
282284
setIsSubmittingReset(true)
283285
setResetStatus({ type: null, message: '' })
284286

285-
const response = await fetch('/api/auth/forget-password', {
286-
method: 'POST',
287-
headers: {
288-
'Content-Type': 'application/json',
289-
},
290-
body: JSON.stringify({
291-
email: forgotPasswordEmail,
292-
redirectTo: `${getBaseUrl()}/reset-password`,
293-
}),
294-
})
295-
296-
if (!response.ok) {
297-
const errorData = await response.json()
298-
let errorMessage = errorData.message || 'Failed to request password reset'
287+
try {
288+
await requestJson(forgetPasswordContract, {
289+
body: {
290+
email: forgotPasswordEmail,
291+
redirectTo: `${getBaseUrl()}/reset-password`,
292+
},
293+
})
294+
} catch (requestError) {
295+
let errorMessage =
296+
requestError instanceof Error ? requestError.message : 'Failed to request password reset'
299297

300298
if (
301299
errorMessage.includes('Invalid body parameters') ||

apps/sim/app/(auth)/oauth/consent/page.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export default function OAuthConsentPage() {
4444
return
4545
}
4646

47+
// boundary-raw-fetch: better-auth catch-all OAuth client lookup, no app-level contract
4748
fetch(`/api/auth/oauth2/client/${encodeURIComponent(clientId)}`, { credentials: 'include' })
4849
.then(async (res) => {
4950
if (!res.ok) return
@@ -65,6 +66,7 @@ export default function OAuthConsentPage() {
6566

6667
setSubmitting(true)
6768
try {
69+
// boundary-raw-fetch: better-auth catch-all OAuth consent submission, no app-level contract
6870
const res = await fetch('/api/auth/oauth2/consent', {
6971
method: 'POST',
7072
headers: { 'Content-Type': 'application/json' },
@@ -100,6 +102,7 @@ export default function OAuthConsentPage() {
100102
const handleSwitchAccount = useCallback(async () => {
101103
if (!consentCode) return
102104

105+
// boundary-raw-fetch: route handler not yet contract-backed (uses safeParse, not parseRequest)
103106
const res = await fetch(`/api/auth/oauth2/authorize-params?consent_code=${consentCode}`, {
104107
credentials: 'include',
105108
})

apps/sim/app/(auth)/reset-password/reset-password-content.tsx

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { Suspense, useState } from 'react'
44
import { createLogger } from '@sim/logger'
55
import Link from 'next/link'
66
import { useRouter, useSearchParams } from 'next/navigation'
7+
import { requestJson } from '@/lib/api/client/request'
8+
import { resetPasswordContract } from '@/lib/api/contracts'
79
import { SetNewPasswordForm } from '@/app/(auth)/reset-password/reset-password-form'
810

911
const logger = createLogger('ResetPasswordPage')
@@ -27,26 +29,18 @@ function ResetPasswordContent() {
2729
: null
2830

2931
const handleResetPassword = async (password: string) => {
32+
if (!token) return
3033
try {
3134
setIsSubmitting(true)
3235
setStatusMessage({ type: null, text: '' })
3336

34-
const response = await fetch('/api/auth/reset-password', {
35-
method: 'POST',
36-
headers: {
37-
'Content-Type': 'application/json',
38-
},
39-
body: JSON.stringify({
37+
await requestJson(resetPasswordContract, {
38+
body: {
4039
token,
4140
newPassword: password,
42-
}),
41+
},
4342
})
4443

45-
if (!response.ok) {
46-
const errorData = await response.json()
47-
throw new Error(errorData.message || 'Failed to reset password')
48-
}
49-
5044
setStatusMessage({
5145
type: 'success',
5246
text: 'Password reset successful! Redirecting to login...',

apps/sim/app/(landing)/components/auth-modal/auth-modal.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const SOCIAL_BTN =
4949

5050
function fetchProviderStatus(): Promise<ProviderStatus> {
5151
if (fetchPromise) return fetchPromise
52+
// boundary-raw-fetch: /api/auth/providers route has no parseRequest contract (zero-input GET, no boundary contract exists)
5253
fetchPromise = fetch('/api/auth/providers')
5354
.then((r) => {
5455
if (!r.ok) throw new Error(`HTTP ${r.status}`)

apps/sim/app/(landing)/components/contact/contact-form.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ interface SubmitContactRequestInput extends ContactRequestPayload {
6060
}
6161

6262
async function submitContactRequest(payload: SubmitContactRequestInput) {
63+
// boundary-raw-fetch: payload includes turnstile captcha + honeypot fields not in submitContactContract body
6364
const response = await fetch('/api/contact', {
6465
method: 'POST',
6566
headers: { 'Content-Type': 'application/json' },

apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ import {
1414
Textarea,
1515
} from '@/components/emcn'
1616
import { Check } from '@/components/emcn/icons'
17+
import { requestJson } from '@/lib/api/client/request'
1718
import {
1819
DEMO_REQUEST_COMPANY_SIZE_OPTIONS,
1920
type DemoRequestPayload,
2021
demoRequestSchema,
22+
submitDemoRequestContract,
2123
} from '@/lib/api/contracts/demo-requests'
2224
import { flattenFieldErrors } from '@/lib/api/contracts/primitives'
2325
import { captureClientEvent } from '@/lib/posthog/client'
@@ -56,22 +58,7 @@ const LANDING_INPUT =
5658
'h-[32px] rounded-[5px] border border-[var(--border-1)] bg-[var(--surface-5)] px-2.5 font-[430] font-season text-[13.5px] text-[var(--text-primary)] transition-colors placeholder:text-[var(--text-muted)] outline-none'
5759

5860
async function submitDemoRequest(payload: DemoRequestPayload) {
59-
const response = await fetch('/api/demo-requests', {
60-
method: 'POST',
61-
headers: { 'Content-Type': 'application/json' },
62-
body: JSON.stringify(payload),
63-
})
64-
65-
const result = (await response.json().catch(() => null)) as {
66-
error?: string
67-
message?: string
68-
} | null
69-
70-
if (!response.ok) {
71-
throw new Error(result?.error || 'Failed to submit demo request')
72-
}
73-
74-
return result
61+
return requestJson(submitDemoRequestContract, { body: payload })
7562
}
7663

7764
export function DemoRequestModal({ children, theme = 'dark' }: DemoRequestModalProps) {

apps/sim/app/(landing)/integrations/components/request-integration-modal.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
ModalHeader,
1313
Textarea,
1414
} from '@/components/emcn'
15+
import { requestJson } from '@/lib/api/client/request'
16+
import { integrationRequestContract } from '@/lib/api/contracts/common'
1517

1618
type SubmitStatus = 'idle' | 'submitting' | 'success' | 'error'
1719

@@ -46,18 +48,14 @@ export function RequestIntegrationModal() {
4648
setStatus('submitting')
4749

4850
try {
49-
const res = await fetch('/api/help/integration-request', {
50-
method: 'POST',
51-
headers: { 'Content-Type': 'application/json' },
52-
body: JSON.stringify({
51+
await requestJson(integrationRequestContract, {
52+
body: {
5353
integrationName: integrationName.trim(),
5454
email: email.trim(),
5555
useCase: useCase.trim() || undefined,
56-
}),
56+
},
5757
})
5858

59-
if (!res.ok) throw new Error('Request failed')
60-
6159
setStatus('success')
6260
setTimeout(() => setOpen(false), 1500)
6361
} catch {

apps/sim/app/_shell/providers/session-provider.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export function SessionProvider({ children }: { children: React.ReactNode }) {
9292
}
9393

9494
try {
95+
// boundary-raw-fetch: GET route handler not yet contract-backed (no GET contract for /api/organizations)
9596
const response = await fetch('/api/organizations')
9697
if (!response.ok) {
9798
return

apps/sim/app/api/auth/sso/providers/route.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { db, member, ssoProvider } from '@sim/db'
22
import { createLogger } from '@sim/logger'
33
import { and, eq } from 'drizzle-orm'
44
import { type NextRequest, NextResponse } from 'next/server'
5-
import { ssoProvidersQuerySchema } from '@/lib/api/contracts/auth'
5+
import { listSsoProvidersContract } from '@/lib/api/contracts/auth'
6+
import { parseRequest } from '@/lib/api/server'
67
import { getSession } from '@/lib/auth'
78
import { REDACTED_MARKER } from '@/lib/core/security/redaction'
89
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
@@ -12,11 +13,9 @@ const logger = createLogger('SSOProvidersRoute')
1213
export const GET = withRouteHandler(async (request: NextRequest) => {
1314
try {
1415
const session = await getSession()
15-
const { searchParams } = new URL(request.url)
16-
const query = ssoProvidersQuerySchema.parse({
17-
organizationId: searchParams.get('organizationId') || undefined,
18-
})
19-
const { organizationId } = query
16+
const parsed = await parseRequest(listSsoProvidersContract, request, undefined)
17+
if (!parsed.success) return parsed.response
18+
const { organizationId } = parsed.data.query
2019

2120
let providers
2221
if (session?.user?.id) {

apps/sim/app/api/templates/[id]/og-image/route.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { templates } from '@sim/db/schema'
33
import { createLogger } from '@sim/logger'
44
import { eq } from 'drizzle-orm'
55
import { type NextRequest, NextResponse } from 'next/server'
6-
import { updateTemplateOgImageBodySchema } from '@/lib/api/contracts/templates'
7-
import { parseJsonBody } from '@/lib/api/server'
6+
import { updateTemplateOgImageContract } from '@/lib/api/contracts/templates'
7+
import { parseRequest } from '@/lib/api/server'
88
import { getSession } from '@/lib/auth'
99
import { generateRequestId } from '@/lib/core/utils/request'
1010
import { getBaseUrl } from '@/lib/core/utils/urls'
@@ -21,9 +21,9 @@ const logger = createLogger('TemplateOGImageAPI')
2121
* Accepts base64-encoded image data in the request body.
2222
*/
2323
export const PUT = withRouteHandler(
24-
async (request: NextRequest, { params }: { params: Promise<{ id: string }> }) => {
24+
async (request: NextRequest, context: { params: Promise<{ id: string }> }) => {
2525
const requestId = generateRequestId()
26-
const { id } = await params
26+
const { id } = await context.params
2727

2828
try {
2929
const session = await getSession()
@@ -42,14 +42,9 @@ export const PUT = withRouteHandler(
4242
return NextResponse.json({ error }, { status: status || 403 })
4343
}
4444

45-
const parsedBody = await parseJsonBody(request)
46-
const bodyResult = parsedBody.success
47-
? updateTemplateOgImageBodySchema.safeParse(parsedBody.data)
48-
: null
49-
const body = bodyResult?.success
50-
? bodyResult.data
51-
: ({ imageData: undefined } as { imageData?: string })
52-
const { imageData } = body
45+
const parsed = await parseRequest(updateTemplateOgImageContract, request, context)
46+
if (!parsed.success) return parsed.response
47+
const { imageData } = parsed.data.body
5348

5449
if (!imageData || typeof imageData !== 'string') {
5550
return NextResponse.json(

0 commit comments

Comments
 (0)