Compare commits

..
15 changed files with 2084 additions and 2087 deletions
@@ -81,7 +81,7 @@ services:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?err}
- POSTGRES_DB=${POSTGRES_DB:?err}
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER}']
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
interval: 10s
timeout: 5s
retries: 5
+1 -1
View File
@@ -7,7 +7,7 @@ services:
volumes:
- documenso_database:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER}']
test: ['CMD-SHELL', 'pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB']
interval: 10s
timeout: 5s
retries: 5
+1 -1
View File
@@ -8,7 +8,7 @@ services:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?err}
- POSTGRES_DB=${POSTGRES_DB:?err}
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER}']
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
interval: 10s
timeout: 5s
retries: 5
+1 -1
View File
@@ -8,7 +8,7 @@ services:
- POSTGRES_PASSWORD=password
- POSTGRES_DB=documenso
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U documenso']
test: ['CMD-SHELL', 'pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB']
interval: 1s
timeout: 5s
retries: 5
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+22 -24
View File
@@ -10,7 +10,7 @@ const CONTENT_TYPE_MULTIPART = 'multipart/form-data';
const getUrlEncodedBody = async (req: Request) => {
const params = new URLSearchParams(await req.text());
const data: Record<string, unknown> = {};
const data: Record<string, string[]> = {};
for (const key of params.keys()) {
data[key] = params.getAll(key);
@@ -22,18 +22,20 @@ const getUrlEncodedBody = async (req: Request) => {
const getMultipartBody = async (req: Request) => {
const formData = await req.formData();
const data: Record<string, unknown> = {};
const data: Record<string, FormDataEntryValue | FormDataEntryValue[]> = {};
for (const [key, value] of formData.entries()) {
// !: Handles cases where our generated SDKs send key[] syntax for arrays.
const normalizedKey = key.endsWith('[]') ? key.slice(0, -2) : key;
if (data[normalizedKey] === undefined) {
const existing = data[normalizedKey];
if (existing === undefined) {
data[normalizedKey] = value;
} else if (Array.isArray(data[normalizedKey])) {
data[normalizedKey].push(value);
} else if (Array.isArray(existing)) {
existing.push(value);
} else {
data[normalizedKey] = [data[normalizedKey], value];
data[normalizedKey] = [existing, value];
}
}
@@ -138,8 +140,10 @@ const createRequestProxy = async (req: Request, url?: string) => {
}
default:
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
return (target as unknown as Record<string | number | symbol, unknown>)[prop];
// SAFETY: Every property this trap does not special-case is forwarded from the
// original Request, so `prop` can only be a key the caller reads off a Request.
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return target[prop as keyof Request];
}
},
});
@@ -160,23 +164,25 @@ export const createOpenApiFetchHandler = async <TRouter extends OpenApiRouter>(
const url = new URL(opts.req.url.replace(opts.endpoint, ''));
const req: Request = await createRequestProxy(opts.req, url.toString());
// The handler is typed against Node HTTP req/res, but only reads properties our request
// proxy and mock response provide, so we declare it against the fetch-based types we pass.
// @ts-expect-error Inherited from original fetch handler in `trpc-to-openapi`
const openApiHttpHandler = createOpenApiNodeHttpHandler(opts);
const openApiHttpHandler: (req: Request, res: ServerResponse) => void = createOpenApiNodeHttpHandler(opts);
return new Promise<Response>((resolve) => {
let statusCode: number;
// Create a mock ServerResponse object that bridges Node HTTP APIs with Fetch API Response.
// This allows the Node HTTP handler to work with Fetch API Request objects.
// SAFETY: The Node HTTP handler only calls setHeader/statusCode/end on the response,
// which this mock implements to bridge Node HTTP APIs with a Fetch API Response.
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const res = {
setHeader: (key: string, value: string | readonly string[]) => {
if (typeof value === 'string') {
resHeaders.set(key, value);
} else {
setHeader: (key: string, value: string | string[]) => {
if (Array.isArray(value)) {
for (const v of value) {
resHeaders.append(key, v);
}
} else {
resHeaders.set(key, value);
}
},
get statusCode() {
@@ -195,14 +201,6 @@ export const createOpenApiFetchHandler = async <TRouter extends OpenApiRouter>(
},
} as ServerResponse;
// Type assertions are necessary here for interop between Fetch API Request/Response
// and Node HTTP IncomingMessage/ServerResponse types.
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const nodeReq = req as unknown as Parameters<typeof openApiHttpHandler>[0];
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const nodeRes = res as unknown as Parameters<typeof openApiHttpHandler>[1];
void openApiHttpHandler(nodeReq, nodeRes);
void openApiHttpHandler(req, res);
});
};
+2 -3
View File
@@ -5,7 +5,6 @@ import {
BRANDING_LOGO_MAX_SIZE_MB,
} from '@documenso/lib/constants/branding';
import { megabytesToBytes } from '@documenso/lib/universal/unit-convertions';
import type { ZodRawShape } from 'zod';
import z from 'zod';
import { zfd } from 'zod-form-data';
@@ -49,10 +48,10 @@ export const zfdBrandingImageFile = () => {
* an error. This provides the same functionality as `zfd.formData()` but
* can be considered somewhat safer.
*/
export const zodFormData = <T extends ZodRawShape>(schema: T) => {
export const zodFormData = <T extends Parameters<typeof z.object>[0]>(schema: T) => {
return z.preprocess((data) => {
if (data instanceof FormData) {
const formData: Record<string, unknown> = {};
const formData: Record<string, FormDataEntryValue | FormDataEntryValue[]> = {};
for (const key of data.keys()) {
const values = data.getAll(key);