Skip to content

Commit

Permalink
feat(contract)!: rewrite and more tests (#51)
Browse files Browse the repository at this point in the history

BREAKING CHANGE: `.tags` -> `.tag`
  • Loading branch information
unnoq authored Dec 13, 2024
1 parent e8d4b28 commit 4555a17
Show file tree
Hide file tree
Showing 45 changed files with 1,107 additions and 781 deletions.
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

0 comments on commit 4555a17

Please sign in to comment.