Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions packages/client/src/procedure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

import type { Caller } from '@orpc/server'
import type { Promisable } from '@orpc/shared'
import { ORPC_HEADER, ORPC_HEADER_VALUE } from '@orpc/contract'
import { trim } from '@orpc/shared'
import { ORPC_PROTOCOL_HEADER, ORPC_PROTOCOL_VALUE, trim } from '@orpc/shared'
import { ORPCError } from '@orpc/shared/error'
import { ORPCDeserializer, ORPCSerializer } from '@orpc/transformer'

Expand Down Expand Up @@ -43,21 +42,27 @@ export function createProcedureClient<TInput, TOutput>(

const fetch_ = options.fetch ?? fetch
const url = `${trim(options.baseURL, '/')}/${options.path.map(encodeURIComponent).join('/')}`
let headers = await options.headers?.(input)
headers = headers instanceof Headers ? headers : new Headers(headers)

const { body, headers: headers_ } = serializer.serialize(input)
const headers = new Headers({
[ORPC_PROTOCOL_HEADER]: ORPC_PROTOCOL_VALUE,
})

for (const [key, value] of headers_.entries()) {
let customHeaders = await options.headers?.(input)
customHeaders = customHeaders instanceof Headers ? customHeaders : new Headers(customHeaders)
for (const [key, value] of customHeaders.entries()) {
headers.append(key, value)
}

headers.set(ORPC_HEADER, ORPC_HEADER_VALUE)
const serialized = serializer.serialize(input)

for (const [key, value] of serialized.headers.entries()) {
headers.append(key, value)
}

const response = await fetch_(url, {
method: 'POST',
headers,
body,
body: serialized.body,
signal: callerOptions?.signal,
})

Expand Down
5 changes: 5 additions & 0 deletions packages/contract/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,10 @@
"dependencies": {
"@orpc/shared": "workspace:*",
"@standard-schema/spec": "1.0.0-beta.4"
},
"devDependencies": {
"arktype": "2.0.0-rc.26",
"valibot": "1.0.0-beta.9",
"zod": "3.24.1"
}
}
110 changes: 110 additions & 0 deletions packages/contract/src/builder.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import type { DecoratedContractProcedure } from './procedure-decorated'
import type { ContractRouterBuilder } from './router-builder'
import { z } from 'zod'
import { ContractBuilder } from './builder'
import { ContractProcedure } from './procedure'

const builder = new ContractBuilder()

describe('to ContractRouterBuilder', () => {
it('prefix', () => {
expectTypeOf(builder.prefix('/prefix')).toEqualTypeOf<
ContractRouterBuilder
>()

// @ts-expect-error - invalid prefix
builder.prefix(1)
// @ts-expect-error - invalid prefix
builder.prefix('')
})

it('tags', () => {
expectTypeOf(builder.tag('tag1', 'tag2')).toEqualTypeOf<
ContractRouterBuilder
>()

// @ts-expect-error - invalid tag
builder.tag(1)
// @ts-expect-error - invalid tag
builder.tag({})
})
})

describe('to DecoratedContractProcedure', () => {
it('route', () => {
expectTypeOf(builder.route({ method: 'GET', path: '/path' })).toEqualTypeOf<
DecoratedContractProcedure<undefined, undefined>
>()

expectTypeOf(builder.route({ })).toEqualTypeOf<
DecoratedContractProcedure<undefined, undefined>
>()

// @ts-expect-error - invalid method
builder.route({ method: 'HE' })
// @ts-expect-error - invalid path
builder.route({ method: 'GET', path: '' })
})

const schema = z.object({
value: z.string(),
})

it('input', () => {
expectTypeOf(builder.input(schema)).toEqualTypeOf<
DecoratedContractProcedure<typeof schema, undefined>
>()

expectTypeOf(builder.input(schema, { value: 'example' })).toEqualTypeOf<
DecoratedContractProcedure<typeof schema, undefined>
>()

// @ts-expect-error - invalid schema
builder.input({})

// @ts-expect-error - invalid example
builder.input(schema, { })
})

it('output', () => {
expectTypeOf(builder.output(schema)).toEqualTypeOf<
DecoratedContractProcedure<undefined, typeof schema>
>()

expectTypeOf(builder.output(schema, { value: 'example' })).toEqualTypeOf<
DecoratedContractProcedure<undefined, typeof schema>
>()

// @ts-expect-error - invalid schema
builder.output({})

// @ts-expect-error - invalid example
builder.output(schema, {})
})
})

describe('to router', () => {
const router = {
a: {
b: {
c: new ContractProcedure({ InputSchema: undefined, OutputSchema: undefined }),
},
},
}

const emptyRouter = {

}

const invalidRouter = {
a: 1,
}

it('router', () => {
expectTypeOf(builder.router(router)).toEqualTypeOf<typeof router>()
expectTypeOf(builder.router(emptyRouter)).toEqualTypeOf<typeof emptyRouter>()

// @ts-expect-error - invalid router
builder.router(invalidRouter)
})
})
Loading