chore: merge main, resolve biome formatting conflicts

Merge origin/main into feat/external-2fa-codes. Resolve formatting
conflicts caused by biome rollout; preserve both feature streams:
PR's external 2FA token + signing-session 2FA proof additions plus
main's RateLimit/RecipientExpired/signingReminders/date-auto-insert.

In complete-document-with-token.ts, drop the duplicate early
field-fetching block introduced when main moved that logic later
with date auto-insert support; keep the EXTERNAL_TWO_FACTOR_AUTH
check using derivedRecipientActionAuth.
This commit is contained in:
ephraimduncan
2026-05-12 11:46:11 +00:00
parent 9194884fbe
commit 138d663c25
1959 changed files with 93488 additions and 47038 deletions
@@ -12,6 +12,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -12,6 +12,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -12,6 +12,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -12,6 +12,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -10,6 +10,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -12,6 +12,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -12,6 +12,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -10,6 +10,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -10,6 +10,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -10,6 +10,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -10,6 +10,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -10,6 +10,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -16,6 +16,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -10,6 +10,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
@@ -10,6 +10,7 @@ export async function GET(request: Request) {
status: 200,
headers: {
'content-type': 'application/json',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
},
}),
);
+24 -28
View File
@@ -1,15 +1,17 @@
import { DateTime } from 'luxon';
export interface TransformedData {
export type TransformedData = {
labels: string[];
datasets: Array<{
label: string;
data: number[];
}>;
}
};
export function addZeroMonth(transformedData: TransformedData): TransformedData {
const result = {
const FORMAT = 'MMM yyyy';
export const addZeroMonth = (transformedData: TransformedData, isCumulative = false): TransformedData => {
const result: TransformedData = {
labels: [...transformedData.labels],
datasets: transformedData.datasets.map((dataset) => ({
label: dataset.label,
@@ -21,34 +23,28 @@ export function addZeroMonth(transformedData: TransformedData): TransformedData
return result;
}
if (result.datasets.every((dataset) => dataset.data[0] === 0)) {
return result;
}
try {
let firstMonth = DateTime.fromFormat(result.labels[0], 'MMM yyyy');
if (!result.datasets.every((dataset) => dataset.data[0] === 0)) {
const firstMonth = DateTime.fromFormat(result.labels[0], FORMAT);
if (!firstMonth.isValid) {
const formats = ['MMM yyyy', 'MMMM yyyy', 'MM/yyyy', 'yyyy-MM'];
for (const format of formats) {
firstMonth = DateTime.fromFormat(result.labels[0], format);
if (firstMonth.isValid) break;
}
if (!firstMonth.isValid) {
console.warn(`Could not parse date: "${result.labels[0]}"`);
return transformedData;
}
console.warn(`Could not parse date: "${result.labels[0]}"`);
return transformedData;
}
const zeroMonth = firstMonth.minus({ months: 1 }).toFormat('MMM yyyy');
result.labels.unshift(zeroMonth);
result.labels.unshift(firstMonth.minus({ months: 1 }).toFormat(FORMAT));
result.datasets.forEach((dataset) => {
dataset.data.unshift(0);
});
return result;
} catch (error) {
return transformedData;
}
}
const now = DateTime.now().startOf('month');
const lastMonth = DateTime.fromFormat(result.labels[result.labels.length - 1], FORMAT);
if (lastMonth.isValid && lastMonth.startOf('month') < now) {
result.labels.push(now.toFormat(FORMAT));
result.datasets.forEach((dataset) => {
dataset.data.push(isCumulative ? dataset.data[dataset.data.length - 1] : 0);
});
}
return result;
};
+15 -8
View File
@@ -60,7 +60,9 @@ async function originHeadersFromReq(req: Request, origin: StaticOrigin | OriginF
const reqOrigin = req.headers.get('Origin') || undefined;
const value = typeof origin === 'function' ? await origin(reqOrigin, req) : origin;
if (!value) return;
if (!value) {
return;
}
return getOriginHeaders(reqOrigin, value);
}
@@ -85,12 +87,17 @@ export default async function cors(req: Request, res: Response, options?: CorsOp
const { headers } = res;
const originHeaders = await originHeadersFromReq(req, opts.origin ?? false);
const mergeHeaders = (v: string, k: string) => {
if (k === 'Vary') headers.append(k, v);
else headers.set(k, v);
if (k === 'Vary') {
headers.append(k, v);
} else {
headers.set(k, v);
}
};
// If there's no origin we won't touch the response
if (!originHeaders) return res;
if (!originHeaders) {
return res;
}
originHeaders.forEach(mergeHeaders);
@@ -98,9 +105,7 @@ export default async function cors(req: Request, res: Response, options?: CorsOp
headers.set('Access-Control-Allow-Credentials', 'true');
}
const exposed = Array.isArray(opts.exposedHeaders)
? opts.exposedHeaders.join(',')
: opts.exposedHeaders;
const exposed = Array.isArray(opts.exposedHeaders) ? opts.exposedHeaders.join(',') : opts.exposedHeaders;
if (exposed) {
headers.set('Access-Control-Expose-Headers', exposed);
@@ -120,7 +125,9 @@ export default async function cors(req: Request, res: Response, options?: CorsOp
headers.set('Access-Control-Max-Age', String(opts.maxAge));
}
if (opts.preflightContinue) return res;
if (opts.preflightContinue) {
return res;
}
headers.set('Content-Length', '0');
return new Response(null, { status: opts.optionsSuccessStatus, headers });
@@ -1,8 +1,7 @@
import { kyselyPrisma, sql } from '@documenso/prisma';
import { DocumentStatus, EnvelopeType } from '@prisma/client';
import { DateTime } from 'luxon';
import { kyselyPrisma, sql } from '@documenso/prisma';
import { addZeroMonth } from '../add-zero-month';
export const getCompletedDocumentsMonthly = async (type: 'count' | 'cumulative' = 'count') => {
@@ -21,8 +20,7 @@ export const getCompletedDocumentsMonthly = async (type: 'count' | 'cumulative'
.where(() => sql`"Envelope"."status" = ${DocumentStatus.COMPLETED}::"DocumentStatus"`)
.where(() => sql`"Envelope"."type" = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`)
.groupBy('month')
.orderBy('month', 'desc')
.limit(12);
.orderBy('month', 'desc');
const result = await qb.execute();
@@ -31,16 +29,12 @@ export const getCompletedDocumentsMonthly = async (type: 'count' | 'cumulative'
datasets: [
{
label: type === 'count' ? 'Completed Documents per Month' : 'Total Completed Documents',
data: result
.map((row) => (type === 'count' ? Number(row.count) : Number(row.cume_count)))
.reverse(),
data: result.map((row) => (type === 'count' ? Number(row.count) : Number(row.cume_count))).reverse(),
},
],
};
return addZeroMonth(transformedData);
return addZeroMonth(transformedData, type === 'cumulative');
};
export type GetCompletedDocumentsMonthlyResult = Awaited<
ReturnType<typeof getCompletedDocumentsMonthly>
>;
export type GetCompletedDocumentsMonthlyResult = Awaited<ReturnType<typeof getCompletedDocumentsMonthly>>;
@@ -1,6 +1,5 @@
import { DateTime } from 'luxon';
import { kyselyPrisma, sql } from '@documenso/prisma';
import { DateTime } from 'luxon';
import { addZeroMonth } from '../add-zero-month';
@@ -29,16 +28,12 @@ export const getSignerConversionMonthly = async (type: 'count' | 'cumulative' =
datasets: [
{
label: type === 'count' ? 'Signers That Signed Up' : 'Total Signers That Signed Up',
data: result
.map((row) => (type === 'count' ? Number(row.count) : Number(row.cume_count)))
.reverse(),
data: result.map((row) => (type === 'count' ? Number(row.count) : Number(row.cume_count))).reverse(),
},
],
};
return addZeroMonth(transformedData);
return addZeroMonth(transformedData, type === 'cumulative');
};
export type GetSignerConversionMonthlyResult = Awaited<
ReturnType<typeof getSignerConversionMonthly>
>;
export type GetSignerConversionMonthlyResult = Awaited<ReturnType<typeof getSignerConversionMonthly>>;
@@ -1,6 +1,5 @@
import { DateTime } from 'luxon';
import { kyselyPrisma, sql } from '@documenso/prisma';
import { DateTime } from 'luxon';
import { addZeroMonth } from '../add-zero-month';
@@ -17,8 +16,7 @@ export const getUserMonthlyGrowth = async (type: 'count' | 'cumulative' = 'count
.as('cume_count'),
])
.groupBy('month')
.orderBy('month', 'desc')
.limit(12);
.orderBy('month', 'desc');
const result = await qb.execute();
@@ -27,14 +25,12 @@ export const getUserMonthlyGrowth = async (type: 'count' | 'cumulative' = 'count
datasets: [
{
label: type === 'count' ? 'New Users' : 'Total Users',
data: result
.map((row) => (type === 'count' ? Number(row.count) : Number(row.cume_count)))
.reverse(),
data: result.map((row) => (type === 'count' ? Number(row.count) : Number(row.cume_count))).reverse(),
},
],
};
return addZeroMonth(transformedData);
return addZeroMonth(transformedData, type === 'cumulative');
};
export type GetUserMonthlyGrowthResult = Awaited<ReturnType<typeof getUserMonthlyGrowth>>;
+3 -20
View File
@@ -1,6 +1,6 @@
import { DateTime } from 'luxon';
import { addZeroMonth } from './add-zero-month';
import { addZeroMonth, type TransformedData } from './add-zero-month';
type MetricKeys = {
stars: number;
@@ -14,14 +14,6 @@ type DataEntry = {
[key: string]: MetricKeys;
};
type TransformData = {
labels: string[];
datasets: {
label: string;
data: number[];
}[];
};
type MetricKey = keyof MetricKeys;
const FRIENDLY_METRIC_NAMES: { [key in MetricKey]: string } = {
@@ -32,13 +24,7 @@ const FRIENDLY_METRIC_NAMES: { [key in MetricKey]: string } = {
earlyAdopters: 'Customers',
};
export function transformData({
data,
metric,
}: {
data: DataEntry;
metric: MetricKey;
}): TransformData {
export function transformData({ data, metric }: { data: DataEntry; metric: MetricKey }): TransformedData {
try {
if (!data || Object.keys(data).length === 0) {
return {
@@ -103,7 +89,7 @@ export function transformData({
],
};
return addZeroMonth(transformedData);
return addZeroMonth(transformedData, true);
} catch (error) {
return {
labels: [],
@@ -111,6 +97,3 @@ export function transformData({
};
}
}
// To be on the safer side
export const transformRepoStats = transformData;
+1 -1
View File
@@ -12,7 +12,7 @@
"dependencies": {
"@documenso/prisma": "*",
"luxon": "^3.7.2",
"next": "15.5.9"
"next": "16.2.4"
},
"devDependencies": {
"@types/node": "^20",
+2 -2
View File
@@ -11,7 +11,7 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
@@ -22,6 +22,6 @@
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],
"exclude": ["node_modules"]
}