feat: warm-up deps — ts-reset, web-vitals, RHF devtool, query-broadcast
Four low-risk adds before the Zod 4 / drizzle-zod headliner: - @total-typescript/ts-reset: tightens TS stdlib types globally (JSON.parse → unknown, fetch().json() → unknown, .filter(Boolean) narrows, Set literals respect typed Set targets). Caught 179 latent type errors; fixed all production sites (8 files) and added `any` cast escape hatch in test files (ESLint exemption scoped to tests/). - web-vitals + /api/v1/internal/vitals endpoint + WebVitalsReporter client component: establishes Core Web Vitals baseline (LCP/INP/CLS/ FCP/TTFB) via navigator.sendBeacon. Required before optimisation work. - @hookform/devtools + FormDevtool wrapper: dev-only RHF state inspector, lazy-loaded via next/dynamic so the chunk is excluded from prod bundles entirely. - @tanstack/query-broadcast-client-experimental: cross-tab cache sync via BroadcastChannel — wired in query-provider.tsx, 1-liner. Audit doc updated with sections 35 + 36 (PDF stack overhaul + comprehensive second-pass package sweep) covering ~20 package adoption candidates and 4-5 deprecation candidates. Verified: tsc clean, vitest 1293/1293 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -61,7 +61,7 @@ describe('Documenso recipient redirect — EMAIL_REDIRECT_TO', () => {
|
||||
]);
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledOnce();
|
||||
const callBody = JSON.parse(fetchMock.mock.calls[0]![1].body as string);
|
||||
const callBody = JSON.parse(fetchMock.mock.calls[0]![1].body as string) as any;
|
||||
expect(callBody.recipients).toHaveLength(2);
|
||||
for (const r of callBody.recipients) {
|
||||
expect(r.email).toBe(REDIRECT_TARGET);
|
||||
@@ -82,7 +82,7 @@ describe('Documenso recipient redirect — EMAIL_REDIRECT_TO', () => {
|
||||
});
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledOnce();
|
||||
const callBody = JSON.parse(fetchMock.mock.calls[0]![1].body as string);
|
||||
const callBody = JSON.parse(fetchMock.mock.calls[0]![1].body as string) as any;
|
||||
expect(callBody.formValues['client.primaryEmail']).toBe(REDIRECT_TARGET);
|
||||
expect(callBody.formValues['developer.email']).toBe(REDIRECT_TARGET);
|
||||
// Non-email field untouched
|
||||
@@ -99,7 +99,7 @@ describe('Documenso recipient redirect — EMAIL_REDIRECT_TO', () => {
|
||||
],
|
||||
});
|
||||
|
||||
const callBody = JSON.parse(fetchMock.mock.calls[0]![1].body as string);
|
||||
const callBody = JSON.parse(fetchMock.mock.calls[0]![1].body as string) as any;
|
||||
for (const r of callBody.recipients) {
|
||||
expect(r.email).toBe(REDIRECT_TARGET);
|
||||
expect(r.name).toMatch(/\(was: .+@realclient\.com\)/);
|
||||
@@ -134,7 +134,7 @@ describe('Documenso recipient redirect — EMAIL_REDIRECT_TO', () => {
|
||||
{ name: 'Alice', email: 'alice@realclient.com', role: 'SIGNER', signingOrder: 1 },
|
||||
]);
|
||||
|
||||
const callBody = JSON.parse(fetchMock.mock.calls[0]![1].body as string);
|
||||
const callBody = JSON.parse(fetchMock.mock.calls[0]![1].body as string) as any;
|
||||
expect(callBody.recipients[0].email).toBe('alice@realclient.com');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('encrypt / decrypt', () => {
|
||||
});
|
||||
|
||||
it('tampered data field throws on decrypt', () => {
|
||||
const stored = JSON.parse(encrypt('tamper me'));
|
||||
const stored = JSON.parse(encrypt('tamper me')) as any;
|
||||
// Flip the first hex byte of data
|
||||
const originalByte = stored.data.slice(0, 2);
|
||||
const flipped = originalByte === 'ff' ? '00' : 'ff';
|
||||
@@ -36,7 +36,7 @@ describe('encrypt / decrypt', () => {
|
||||
});
|
||||
|
||||
it('tampered auth tag throws on decrypt', () => {
|
||||
const stored = JSON.parse(encrypt('tamper tag'));
|
||||
const stored = JSON.parse(encrypt('tamper tag')) as any;
|
||||
const originalByte = stored.tag.slice(0, 2);
|
||||
const flipped = originalByte === 'ff' ? '00' : 'ff';
|
||||
stored.tag = flipped + stored.tag.slice(2);
|
||||
|
||||
@@ -60,7 +60,7 @@ describe('Error response security — AppError subclasses', () => {
|
||||
const error = new AppError(400, 'Bad request', 'BAD_REQUEST');
|
||||
const response = errorResponse(error);
|
||||
expect(response.status).toBe(400);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
expect(body.error).toBe('Bad request');
|
||||
expect(body.code).toBe('BAD_REQUEST');
|
||||
// Stack trace must never appear in the response body
|
||||
@@ -72,7 +72,7 @@ describe('Error response security — AppError subclasses', () => {
|
||||
const error = new NotFoundError('Client');
|
||||
const response = errorResponse(error);
|
||||
expect(response.status).toBe(404);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
// Message is now plain-text user-facing (no jargon, lowercased entity).
|
||||
expect(body.error).toBe("We couldn't find that client. It may have been removed.");
|
||||
expect(body.code).toBe('NOT_FOUND');
|
||||
@@ -83,7 +83,7 @@ describe('Error response security — AppError subclasses', () => {
|
||||
const error = new ForbiddenError();
|
||||
const response = errorResponse(error);
|
||||
expect(response.status).toBe(403);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
expect(body.code).toBe('FORBIDDEN');
|
||||
});
|
||||
|
||||
@@ -91,7 +91,7 @@ describe('Error response security — AppError subclasses', () => {
|
||||
const error = new RateLimitError(60);
|
||||
const response = errorResponse(error);
|
||||
expect(response.status).toBe(429);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
expect(body.retryAfter).toBe(60);
|
||||
expect(JSON.stringify(body)).not.toMatch(/stack|node_modules/i);
|
||||
});
|
||||
@@ -102,7 +102,7 @@ describe('Error response security — AppError subclasses', () => {
|
||||
]);
|
||||
const response = errorResponse(error);
|
||||
expect(response.status).toBe(400);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
expect(body.details).toHaveLength(1);
|
||||
expect(body.details[0].field).toBe('email');
|
||||
expect(JSON.stringify(body)).not.toContain('src/');
|
||||
@@ -115,7 +115,7 @@ describe('Error response security — unknown / native errors', () => {
|
||||
const error = new Error('SELECT * FROM users WHERE id = 1; DROP TABLE users;--');
|
||||
const response = errorResponse(error);
|
||||
expect(response.status).toBe(500);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
expect(body.error).toBe('Internal server error');
|
||||
expect(JSON.stringify(body)).not.toContain('SELECT');
|
||||
expect(JSON.stringify(body)).not.toContain('DROP TABLE');
|
||||
@@ -127,7 +127,7 @@ describe('Error response security — unknown / native errors', () => {
|
||||
);
|
||||
const response = errorResponse(error);
|
||||
expect(response.status).toBe(500);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
expect(body.error).toBe('Internal server error');
|
||||
expect(JSON.stringify(body)).not.toContain('G:\\');
|
||||
expect(JSON.stringify(body)).not.toContain('src\\lib');
|
||||
@@ -137,7 +137,7 @@ describe('Error response security — unknown / native errors', () => {
|
||||
const error = new Error('ENOENT: no such file at /app/node_modules/pg/lib/connection.js');
|
||||
const response = errorResponse(error);
|
||||
expect(response.status).toBe(500);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
expect(body.error).toBe('Internal server error');
|
||||
expect(JSON.stringify(body)).not.toContain('node_modules');
|
||||
expect(JSON.stringify(body)).not.toContain('ENOENT');
|
||||
@@ -147,7 +147,7 @@ describe('Error response security — unknown / native errors', () => {
|
||||
const error = new Error('relation "users" does not exist');
|
||||
const response = errorResponse(error);
|
||||
expect(response.status).toBe(500);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
expect(body.error).toBe('Internal server error');
|
||||
expect(JSON.stringify(body)).not.toContain('relation');
|
||||
expect(JSON.stringify(body)).not.toContain('"users"');
|
||||
@@ -156,14 +156,14 @@ describe('Error response security — unknown / native errors', () => {
|
||||
it('null thrown value returns generic 500', async () => {
|
||||
const response = errorResponse(null);
|
||||
expect(response.status).toBe(500);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
expect(body.error).toBe('Internal server error');
|
||||
});
|
||||
|
||||
it('string thrown returns generic 500', async () => {
|
||||
const response = errorResponse('something went wrong internally');
|
||||
expect(response.status).toBe(500);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
expect(body.error).toBe('Internal server error');
|
||||
// The raw string must not appear in the response
|
||||
expect(JSON.stringify(body)).not.toContain('something went wrong internally');
|
||||
@@ -184,7 +184,7 @@ describe('Error response security — ZodError', () => {
|
||||
]);
|
||||
const response = errorResponse(error);
|
||||
expect(response.status).toBe(400);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
expect(body.code).toBe('VALIDATION_ERROR');
|
||||
expect(body.details).toBeDefined();
|
||||
expect(Array.isArray(body.details)).toBe(true);
|
||||
@@ -203,7 +203,7 @@ describe('Error response security — ZodError', () => {
|
||||
},
|
||||
]);
|
||||
const response = errorResponse(error);
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
const bodyStr = JSON.stringify(body);
|
||||
expect(bodyStr).not.toContain('src/');
|
||||
expect(bodyStr).not.toContain('node_modules');
|
||||
@@ -222,7 +222,7 @@ describe('Error response security — response shape invariants', () => {
|
||||
new RateLimitError(30),
|
||||
];
|
||||
for (const err of errors) {
|
||||
const body = await errorResponse(err).json();
|
||||
const body = (await errorResponse(err).json()) as any;
|
||||
expect(typeof body.error).toBe('string');
|
||||
expect(body.error.length).toBeGreaterThan(0);
|
||||
// Stack must never appear
|
||||
@@ -232,7 +232,7 @@ describe('Error response security — response shape invariants', () => {
|
||||
|
||||
it('500 response body carries error + code (and requestId when in-flight)', async () => {
|
||||
const response = errorResponse(new Error('db connection refused'));
|
||||
const body = await response.json();
|
||||
const body = (await response.json()) as any;
|
||||
// Allowed keys for a 500 response. `code` is always present; `requestId`
|
||||
// and `message` only appear when an active request context is in scope.
|
||||
const allowed = new Set(['error', 'code', 'requestId', 'message']);
|
||||
|
||||
@@ -130,7 +130,7 @@ describe('placeFields v2 dispatch', () => {
|
||||
const [url, init] = fetchMock.mock.calls[0]!;
|
||||
expect(url).toBe('https://documenso.test/api/v2/envelope/field/create-many');
|
||||
expect((init as RequestInit).method).toBe('POST');
|
||||
const body = JSON.parse(String((init as RequestInit).body));
|
||||
const body = JSON.parse(String((init as RequestInit).body)) as any;
|
||||
expect(body.envelopeId).toBe('env-123');
|
||||
expect(body.fields[0]).toMatchObject({
|
||||
recipientId: 'rec-a',
|
||||
@@ -198,7 +198,7 @@ describe('placeFields v1 dispatch', () => {
|
||||
expect(fetchMock).toHaveBeenCalledTimes(2);
|
||||
const firstCall = fetchMock.mock.calls[0]!;
|
||||
expect(firstCall[0]).toBe('https://documenso.test/api/v1/documents/doc-123/fields');
|
||||
const firstBody = JSON.parse(String((firstCall[1] as RequestInit).body));
|
||||
const firstBody = JSON.parse(String((firstCall[1] as RequestInit).body)) as any;
|
||||
expect(firstBody).toMatchObject({
|
||||
recipientId: 42,
|
||||
type: 'SIGNATURE',
|
||||
@@ -227,7 +227,7 @@ describe('placeFields v1 dispatch', () => {
|
||||
],
|
||||
'port-1',
|
||||
);
|
||||
const body = JSON.parse(String((fetchMock.mock.calls[0]![1] as RequestInit).body));
|
||||
const body = JSON.parse(String((fetchMock.mock.calls[0]![1] as RequestInit).body)) as any;
|
||||
expect(body.recipientId).toBe(99);
|
||||
});
|
||||
|
||||
@@ -267,7 +267,7 @@ describe('placeDefaultSignatureFields integration', () => {
|
||||
'port-1',
|
||||
);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
const body = JSON.parse(String((fetchMock.mock.calls[0]![1] as RequestInit).body));
|
||||
const body = JSON.parse(String((fetchMock.mock.calls[0]![1] as RequestInit).body)) as any;
|
||||
expect(body.fields).toHaveLength(3);
|
||||
expect(body.fields.every((f: { type: string }) => f.type === 'SIGNATURE')).toBe(true);
|
||||
expect(body.fields.every((f: { pageNumber: number }) => f.pageNumber === 4)).toBe(true);
|
||||
@@ -293,7 +293,7 @@ describe('placeDefaultSignatureFields integration', () => {
|
||||
expect(fetchMock).toHaveBeenCalledTimes(2);
|
||||
for (const call of fetchMock.mock.calls) {
|
||||
expect(call[0]).toBe('https://documenso.test/api/v1/documents/doc-z/fields');
|
||||
const body = JSON.parse(String((call[1] as RequestInit).body));
|
||||
const body = JSON.parse(String((call[1] as RequestInit).body)) as any;
|
||||
expect(body.type).toBe('SIGNATURE');
|
||||
expect(body.pageNumber).toBe(1);
|
||||
// 88% of 842 = 741 (footer band)
|
||||
|
||||
@@ -63,7 +63,7 @@ describe('POST /api/public/website-inquiries — 503 when secret unset', () => {
|
||||
),
|
||||
);
|
||||
expect(res.status).toBe(503);
|
||||
const body = await res.json();
|
||||
const body = (await res.json()) as any;
|
||||
expect(body.error).toMatch(/not configured/i);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -175,7 +175,7 @@ describe('POST /api/public/website-inquiries — auth + capture', () => {
|
||||
),
|
||||
);
|
||||
expect(res.status).toBe(400);
|
||||
const body = await res.json();
|
||||
const body = (await res.json()) as any;
|
||||
expect(body.error).toMatch(/Unknown port/);
|
||||
});
|
||||
|
||||
@@ -193,7 +193,7 @@ describe('POST /api/public/website-inquiries — auth + capture', () => {
|
||||
),
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json();
|
||||
const body = (await res.json()) as any;
|
||||
expect(body).toEqual({ id: 'generated-row-id', deduped: false });
|
||||
|
||||
expect(state.inserted).toHaveLength(1);
|
||||
@@ -219,7 +219,7 @@ describe('POST /api/public/website-inquiries — auth + capture', () => {
|
||||
),
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json();
|
||||
const body = (await res.json()) as any;
|
||||
expect(body).toEqual({ id: 'existing-row-id', deduped: true });
|
||||
expect(state.inserted).toHaveLength(0);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user