Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
unnoq committed Dec 28, 2024
1 parent 9588d75 commit f387b10
Show file tree
Hide file tree
Showing 19 changed files with 609 additions and 1,186 deletions.
6 changes: 5 additions & 1 deletion packages/openapi/src/fetch/openapi-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { ConditionalFetchHandler, FetchOptions } from '@orpc/server/fetch'
import type { PublicInputBuilderSimple } from './input-builder-simple'
import { type Context, createProcedureClient, ORPCError, type Router, type WithSignal } from '@orpc/server'
import { executeWithHooks, type Hooks, ORPC_HANDLER_HEADER, trim } from '@orpc/shared'
import { JSONSerializer, type PublicJSONSerializer } from '../json-serializer'
import { InputBuilderFull, type PublicInputBuilderFull } from './input-builder-full'
import { InputBuilderSimple } from './input-builder-simple'
import { OpenAPIPayloadCodec, type PublicOpenAPIPayloadCodec } from './openapi-payload-codec'
Expand All @@ -11,6 +12,7 @@ import { CompositeSchemaCoercer, type SchemaCoercer } from './schema-coercer'
export type OpenAPIHandlerOptions<T extends Context> =
& Hooks<Request, Response, T, WithSignal>
& {
jsonSerializer?: PublicJSONSerializer
procedureMatcher?: PublicOpenAPIProcedureMatcher
payloadCodec?: PublicOpenAPIPayloadCodec
inputBuilderSimple?: PublicInputBuilderSimple
Expand All @@ -30,8 +32,10 @@ export class OpenAPIHandler<T extends Context> implements ConditionalFetchHandle
router: Router<T, any>,
private readonly options?: NoInfer<OpenAPIHandlerOptions<T>>,
) {
const jsonSerializer = options?.jsonSerializer ?? new JSONSerializer()

this.procedureMatcher = options?.procedureMatcher ?? new OpenAPIProcedureMatcher(hono, router)
this.payloadCodec = options?.payloadCodec ?? new OpenAPIPayloadCodec()
this.payloadCodec = options?.payloadCodec ?? new OpenAPIPayloadCodec(jsonSerializer)
this.inputBuilderSimple = options?.inputBuilderSimple ?? new InputBuilderSimple()
this.inputBuilderFull = options?.inputBuilderFull ?? new InputBuilderFull()
this.compositeSchemaCoercer = new CompositeSchemaCoercer(options?.schemaCoercers ?? [])
Expand Down
3 changes: 2 additions & 1 deletion packages/openapi/src/fetch/openapi-payload-codec.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { JSONSerializer } from '../json-serializer'
import { OpenAPIPayloadCodec } from './openapi-payload-codec'

describe('openAPIPayloadCodec', () => {
const codec = new OpenAPIPayloadCodec()
const codec = new OpenAPIPayloadCodec(new JSONSerializer())

describe('encode', () => {
it('should encode JSON data when accept header is application/json', async () => {
Expand Down
38 changes: 5 additions & 33 deletions packages/openapi/src/fetch/openapi-payload-codec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import type { PublicJSONSerializer } from '../json-serializer'
import { ORPCError } from '@orpc/server'
import { findDeepMatches, isPlainObject } from '@orpc/shared'
import { findDeepMatches } from '@orpc/shared'
import cd from 'content-disposition'
import { safeParse } from 'fast-content-type-parse'
import wcmatch from 'wildcard-match'
import * as BracketNotation from './bracket-notation'

export class OpenAPIPayloadCodec {
constructor(private readonly jsonSerializer: PublicJSONSerializer) {}

encode(payload: unknown, accept?: string): { body: FormData | Blob | string | undefined, headers?: Headers } {
const typeMatchers = (
accept?.split(',').map(safeParse) ?? [{ type: '*/*' }]
Expand All @@ -30,7 +33,7 @@ export class OpenAPIPayloadCodec {
}
}

const handledPayload = this.serialize(payload)
const handledPayload = this.jsonSerializer.serialize(payload)
const hasBlobs = findDeepMatches(v => v instanceof Blob, handledPayload).values.length > 0

const isExpectedMultipartFormData = typeMatchers.some(isMatch =>
Expand Down Expand Up @@ -141,37 +144,6 @@ export class OpenAPIPayloadCodec {
}
}

serialize(payload: unknown): unknown {
if (payload instanceof Set)
return this.serialize([...payload])
if (payload instanceof Map)
return this.serialize([...payload.entries()])
if (Array.isArray(payload)) {
return payload.map(v => (v === undefined ? 'undefined' : this.serialize(v)))
}
if (Number.isNaN(payload))
return 'NaN'
if (typeof payload === 'bigint')
return payload.toString()
if (payload instanceof Date && Number.isNaN(payload.getTime())) {
return 'Invalid Date'
}
if (payload instanceof RegExp)
return payload.toString()
if (payload instanceof URL)
return payload.toString()
if (!isPlainObject(payload))
return payload
return Object.keys(payload).reduce(
(carry, key) => {
const val = payload[key]
carry[key] = this.serialize(val)
return carry
},
{} as Record<string, unknown>,
)
}

async decode(re: Request | Response | Headers | URLSearchParams | FormData): Promise<unknown> {
if (
re instanceof Headers
Expand Down
Loading

0 comments on commit f387b10

Please sign in to comment.