Skip to content

Commit

Permalink
rename caller to client, and some improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
unnoq committed Dec 20, 2024
1 parent a04d95d commit 4e4b869
Show file tree
Hide file tree
Showing 26 changed files with 330 additions and 296 deletions.
4 changes: 2 additions & 2 deletions packages/next/src/action-form.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { ANY_LAZY_PROCEDURE, ANY_PROCEDURE, CreateProcedureCallerOptions } from '@orpc/server'
import { createProcedureCaller, loadProcedure, ORPCError } from '@orpc/server'
import { createProcedureClient, loadProcedure, ORPCError } from '@orpc/server'
import { OpenAPIDeserializer } from '@orpc/transformer'
import { forbidden, notFound, unauthorized } from 'next/navigation'

export type FormAction = (input: FormData) => Promise<void>

export function createFormAction<T extends ANY_PROCEDURE | ANY_LAZY_PROCEDURE>(opt: CreateProcedureCallerOptions<T>): FormAction {
const caller = createProcedureCaller(opt)
const caller = createProcedureClient(opt)

const formAction = async (input: FormData): Promise<void> => {
try {
Expand Down
4 changes: 2 additions & 2 deletions packages/next/src/action-safe.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { SchemaInput, SchemaOutput } from '@orpc/contract'
import type { ANY_LAZY_PROCEDURE, ANY_PROCEDURE, CreateProcedureCallerOptions, Lazy, Procedure, WELL_ORPC_ERROR_JSON } from '@orpc/server'
import { createProcedureCaller, ORPCError } from '@orpc/server'
import { createProcedureClient, ORPCError } from '@orpc/server'

export type SafeAction<T extends ANY_PROCEDURE | ANY_LAZY_PROCEDURE> = T extends
| Procedure<any, any, infer UInputSchema, infer UOutputSchema, infer UFuncOutput>
Expand All @@ -16,7 +16,7 @@ export type SafeAction<T extends ANY_PROCEDURE | ANY_LAZY_PROCEDURE> = T extends
: never

export function createSafeAction<T extends ANY_PROCEDURE | ANY_LAZY_PROCEDURE>(opt: CreateProcedureCallerOptions<T>): SafeAction<T> {
const caller = createProcedureCaller(opt)
const caller = createProcedureClient(opt)

const safeAction = async (...input: [any] | []) => {
try {
Expand Down
4 changes: 2 additions & 2 deletions packages/openapi/src/fetch/base-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { ANY_LAZY_PROCEDURE, ANY_PROCEDURE, Router } from '@orpc/server'
import type { FetchHandler } from '@orpc/server/fetch'
import type { Router as HonoRouter } from 'hono/router'
import type { EachContractLeafResultItem, EachLeafOptions } from '../utils'
import { createProcedureCaller, isLazy, isProcedure, LAZY_LOADER_SYMBOL, LAZY_ROUTER_PREFIX_SYMBOL, ORPCError } from '@orpc/server'
import { createProcedureClient, isLazy, isProcedure, LAZY_LOADER_SYMBOL, LAZY_ROUTER_PREFIX_SYMBOL, ORPCError } from '@orpc/server'
import { executeWithHooks, isPlainObject, mapValues, ORPC_PROTOCOL_HEADER, ORPC_PROTOCOL_VALUE, trim, value } from '@orpc/shared'
import { OpenAPIDeserializer, OpenAPISerializer, zodCoerce } from '@orpc/transformer'
import { eachContractProcedureLeaf, standardizeHTTPPath } from '../utils'
Expand Down Expand Up @@ -65,7 +65,7 @@ export function createOpenAPIHandler(createHonoRouter: () => Routing): FetchHand
const input = await deserializeInput(options.request, procedure)
const mergedInput = mergeParamsAndInput(params, input)

const caller = createProcedureCaller({
const caller = createProcedureClient({
context,
procedure,
path,
Expand Down
4 changes: 2 additions & 2 deletions packages/server/src/builder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ANY_CONTRACT_PROCEDURE, ContractRouter, HTTPPath, RouteOptions, Schema, SchemaInput, SchemaOutput } from '@orpc/contract'
import type { DecoratedLazy } from './lazy-decorated'
import type { FlattenLazy } from './lazy'
import type { Middleware } from './middleware'
import type { DecoratedMiddleware } from './middleware-decorated'
import type { Router } from './router'
Expand Down Expand Up @@ -137,7 +137,7 @@ export class Builder<TContext extends Context, TExtraContext extends Context> {

lazy<U extends Router<MergeContext<TContext, TExtraContext>, any>>(
loader: () => Promise<{ default: U }>,
): DecoratedLazy<AdaptedRouter<TContext, U>> {
): AdaptedRouter<TContext, FlattenLazy<U>> {
return new RouterBuilder<TContext, TExtraContext>(this['~orpc']).lazy(loader)
}

Expand Down
4 changes: 2 additions & 2 deletions packages/server/src/fetch/handle-request.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Procedure } from '../procedure'
import type { CallerOptions, WELL_CONTEXT } from '../types'
import type { WELL_CONTEXT, WithSignal } from '../types'
import { lazy } from '../lazy'
import { handleFetchRequest } from './handle-request'

Expand Down Expand Up @@ -64,7 +64,7 @@ describe('handleFetchRequest', () => {
expectTypeOf(output).toEqualTypeOf<Response>()
expectTypeOf(input).toEqualTypeOf<Request>()
expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
expectTypeOf(meta).toEqualTypeOf<CallerOptions>()
expectTypeOf(meta).toEqualTypeOf<WithSignal>()
},
})
})
Expand Down
12 changes: 6 additions & 6 deletions packages/server/src/fetch/orpc-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { ORPC_PROTOCOL_HEADER, ORPC_PROTOCOL_VALUE } from '@orpc/shared'
import { describe, expect, it, vi } from 'vitest'
import { lazy } from '../lazy'
import { Procedure } from '../procedure'
import { createProcedureCaller } from '../procedure-caller'
import { createProcedureClient } from '../procedure-client'
import { createORPCHandler } from './orpc-handler'

vi.mock('../procedure-caller', () => ({
createProcedureCaller: vi.fn(() => vi.fn()),
vi.mock('../procedure-client', () => ({
createProcedureClient: vi.fn(() => vi.fn()),
}))

describe('createORPCHandler', () => {
Expand Down Expand Up @@ -74,7 +74,7 @@ describe('createORPCHandler', () => {
const handler = createORPCHandler()

const caller = vi.fn().mockReturnValueOnce('__mocked__')
vi.mocked(createProcedureCaller).mockReturnValue(caller)
vi.mocked(createProcedureClient).mockReturnValue(caller)

const mockRequest = new Request('https://example.com/ping', {
headers: new Headers({ [ORPC_PROTOCOL_HEADER]: ORPC_PROTOCOL_VALUE }),
Expand Down Expand Up @@ -119,7 +119,7 @@ describe('createORPCHandler', () => {
it('should handle unexpected errors and return a 500 response', async () => {
const handler = createORPCHandler()

vi.mocked(createProcedureCaller).mockImplementationOnce(() => {
vi.mocked(createProcedureClient).mockImplementationOnce(() => {
throw new Error('Unexpected error')
})

Expand All @@ -146,7 +146,7 @@ describe('createORPCHandler', () => {
const handler = createORPCHandler()

const caller = vi.fn().mockReturnValueOnce('__mocked__')
vi.mocked(createProcedureCaller).mockReturnValue(caller)
vi.mocked(createProcedureClient).mockReturnValue(caller)

const mockRequest = new Request('https://example.com/ping', {
headers: new Headers({ [ORPC_PROTOCOL_HEADER]: ORPC_PROTOCOL_VALUE }),
Expand Down
4 changes: 2 additions & 2 deletions packages/server/src/fetch/orpc-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ORPCError } from '@orpc/shared/error'
import { ORPCDeserializer, ORPCSerializer } from '@orpc/transformer'
import { unlazy } from '../lazy'
import { isProcedure } from '../procedure'
import { createProcedureCaller } from '../procedure-caller'
import { createProcedureClient } from '../procedure-client'
import { type ANY_ROUTER, getRouterChild } from '../router'

const serializer = new ORPCSerializer()
Expand All @@ -31,7 +31,7 @@ export function createORPCHandler(): FetchHandler {

const input = await parseRequestInput(options.request)

const caller = createProcedureCaller({
const caller = createProcedureClient({
context,
procedure: match.procedure,
path: match.path,
Expand Down
8 changes: 3 additions & 5 deletions packages/server/src/fetch/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
/// <reference lib="dom" />

import type { HTTPPath } from '@orpc/contract'
import type { Hooks, Value } from '@orpc/shared'
import type { Router } from '../router'
import type { CallerOptions, Context } from '../types'
import type { Context, WithSignal } from '../types'

export type FetchHandlerOptions<T extends Context> =
{
Expand All @@ -27,8 +25,8 @@ export type FetchHandlerOptions<T extends Context> =
prefix?: HTTPPath
}
& NoInfer<(undefined extends T ? { context?: Value<T> } : { context: Value<T> })>
& CallerOptions
& Hooks<Request, Response, T, CallerOptions>
& WithSignal
& Hooks<Request, Response, T, WithSignal>

export type FetchHandler = <T extends Context>(
options: FetchHandlerOptions<T>
Expand Down
4 changes: 2 additions & 2 deletions packages/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ export * from './middleware'
export * from './middleware-decorated'
export * from './procedure'
export * from './procedure-builder'
export * from './procedure-caller'
export * from './procedure-client'
export * from './procedure-decorated'
export * from './procedure-implementer'
export * from './router'
export * from './router-builder'
export * from './router-caller'
export * from './router-client'
export * from './router-implementer'
export * from './types'
export * from './utils'
Expand Down
12 changes: 6 additions & 6 deletions packages/server/src/lazy-decorated.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ANY_PROCEDURE, ANY_ROUTER, Caller, DecoratedProcedure, Procedure, WELL_CONTEXT } from '.'
import type { ANY_PROCEDURE, ANY_ROUTER, DecoratedProcedure, Procedure, ProcedureClient, WELL_CONTEXT } from '.'
import type { Lazy } from './lazy'
import type { DecoratedLazy } from './lazy-decorated'
import { z } from 'zod'
Expand Down Expand Up @@ -42,7 +42,7 @@ describe('DecoratedLazy', () => {
expectTypeOf(decorated).toMatchTypeOf<Lazy<ANY_PROCEDURE>>()

expectTypeOf(decorated).toMatchTypeOf<
Caller<unknown, { val: number }>
ProcedureClient<unknown, { val: number }>
>()
})

Expand All @@ -53,19 +53,19 @@ describe('DecoratedLazy', () => {
expectTypeOf({ router: decorated }).toMatchTypeOf<ANY_ROUTER>()

expectTypeOf(decorated.ping).toMatchTypeOf<Lazy<ANY_PROCEDURE>>()
expectTypeOf(decorated.ping).toMatchTypeOf <Caller<unknown, { val: number }>>()
expectTypeOf(decorated.ping).toMatchTypeOf <ProcedureClient<unknown, { val: number }>>()

expectTypeOf(decorated.pong).toMatchTypeOf<Lazy<ANY_PROCEDURE>>()
expectTypeOf(decorated.pong).toMatchTypeOf<Caller<{ val: string }, unknown>>()
expectTypeOf(decorated.pong).toMatchTypeOf<ProcedureClient<{ val: string }, unknown>>()

expectTypeOf(decorated.nested).toMatchTypeOf<Lazy<ANY_ROUTER>>()
expectTypeOf({ router: decorated.nested }).toMatchTypeOf<ANY_ROUTER>()

expectTypeOf(decorated.nested.ping).toMatchTypeOf<Lazy<ANY_PROCEDURE>>()
expectTypeOf(decorated.nested.ping).toMatchTypeOf<Caller<unknown, { val: number }>>()
expectTypeOf(decorated.nested.ping).toMatchTypeOf<ProcedureClient<unknown, { val: number }>>()

expectTypeOf(decorated.nested.pong).toMatchTypeOf<Lazy<ANY_PROCEDURE>>()
expectTypeOf(decorated.nested.pong).toMatchTypeOf<Caller<{ val: string }, unknown>>()
expectTypeOf(decorated.nested.pong).toMatchTypeOf<ProcedureClient<{ val: string }, unknown>>()
})

it('flat lazy', () => {
Expand Down
20 changes: 10 additions & 10 deletions packages/server/src/lazy-decorated.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { z } from 'zod'
import { isLazy, lazy, unlazy } from './lazy'
import { decorateLazy } from './lazy-decorated'
import { Procedure } from './procedure'
import { createProcedureCaller } from './procedure-caller'
import { createProcedureClient } from './procedure-client'

vi.mock('./procedure-caller', () => ({
createProcedureCaller: vi.fn(() => vi.fn()),
Expand Down Expand Up @@ -62,19 +62,19 @@ describe('decorated lazy', () => {
const signal = controller.signal

const caller = vi.fn(() => '__mocked__')
vi.mocked(createProcedureCaller).mockReturnValue(caller as any)
vi.mocked(createProcedureClient).mockReturnValue(caller as any)

it('on root', async () => {
const decorated = decorateLazy(lazied) as any
expect(decorated).toBeInstanceOf(Function)

expect(createProcedureCaller).toHaveBeenCalledTimes(1)
expect(createProcedureCaller).toHaveBeenCalledWith({
expect(createProcedureClient).toHaveBeenCalledTimes(1)
expect(createProcedureClient).toHaveBeenCalledWith({
procedure: expect.any(Object),
context: undefined,
})
expect(vi.mocked(createProcedureCaller).mock.calls[0]![0].procedure).toSatisfy(isLazy)
const unwrapped = await unlazy(vi.mocked(createProcedureCaller).mock.calls[0]![0].procedure as any)
expect(vi.mocked(createProcedureClient).mock.calls[0]![0].procedure).toSatisfy(isLazy)
const unwrapped = await unlazy(vi.mocked(createProcedureClient).mock.calls[0]![0].procedure as any)
expect(unwrapped.default).toBe(router)

expect(await decorated({ val: '1' }, { signal })).toBe('__mocked__')
Expand All @@ -86,13 +86,13 @@ describe('decorated lazy', () => {
const decorated = decorateLazy(lazied).nested.ping as any
expect(decorated).toBeInstanceOf(Function)

expect(createProcedureCaller).toHaveBeenCalledTimes(3)
expect(createProcedureCaller).toHaveBeenNthCalledWith(3, {
expect(createProcedureClient).toHaveBeenCalledTimes(3)
expect(createProcedureClient).toHaveBeenNthCalledWith(3, {
procedure: expect.any(Object),
context: undefined,
})
expect(vi.mocked(createProcedureCaller).mock.calls[2]![0].procedure).toSatisfy(isLazy)
const unwrapped = await unlazy(vi.mocked(createProcedureCaller).mock.calls[2]![0].procedure as any)
expect(vi.mocked(createProcedureClient).mock.calls[2]![0].procedure).toSatisfy(isLazy)
const unwrapped = await unlazy(vi.mocked(createProcedureClient).mock.calls[2]![0].procedure as any)
expect(unwrapped.default).toBe(ping)

expect(await decorated({ val: '1' }, { signal })).toBe('__mocked__')
Expand Down
15 changes: 8 additions & 7 deletions packages/server/src/lazy-decorated.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { SchemaInput, SchemaOutput } from '@orpc/contract'
import type { Lazy } from './lazy'
import type { Procedure } from './procedure'
import type { Caller } from './types'
import type { ProcedureClient } from './procedure-client'
import { flatLazy } from './lazy'
import { createProcedureCaller } from './procedure-caller'
import { createLazyProcedureFormAnyLazy } from './lazy-utils'
import { createProcedureClient } from './procedure-client'
import { type ANY_ROUTER, getRouterChild } from './router'

export type DecoratedLazy<T> = T extends Lazy<infer U>
Expand All @@ -13,7 +14,7 @@ export type DecoratedLazy<T> = T extends Lazy<infer U>
& (
T extends Procedure<infer UContext, any, infer UInputSchema, infer UOutputSchema, infer UFuncOutput>
? undefined extends UContext
? Caller<SchemaInput<UInputSchema>, SchemaOutput<UOutputSchema, UFuncOutput>>
? ProcedureClient<SchemaInput<UInputSchema>, SchemaOutput<UOutputSchema, UFuncOutput>>
: unknown
: {
[K in keyof T]: T[K] extends object ? DecoratedLazy<T[K]> : never
Expand All @@ -23,14 +24,14 @@ export type DecoratedLazy<T> = T extends Lazy<infer U>
export function decorateLazy<T extends Lazy<ANY_ROUTER | undefined>>(lazied: T): DecoratedLazy<T> {
const flattenLazy = flatLazy(lazied)

const procedureCaller = createProcedureCaller({
procedure: flattenLazy,
const procedureProcedureClient = createProcedureClient({
procedure: createLazyProcedureFormAnyLazy(flattenLazy),
context: undefined,
})

Object.assign(procedureCaller, flattenLazy)
Object.assign(procedureProcedureClient, flattenLazy)

const recursive = new Proxy(procedureCaller, {
const recursive = new Proxy(procedureProcedureClient, {
get(target, key) {
if (typeof key !== 'string') {
return Reflect.get(target, key)
Expand Down
10 changes: 10 additions & 0 deletions packages/server/src/lazy-utils.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { Lazy } from './lazy'
import type { ANY_PROCEDURE } from './procedure'
import { lazy } from './lazy'
import { createLazyProcedureFormAnyLazy } from './lazy-utils'

it('createLazyProcedureFormAnyLazy return a Lazy<ANY_PROCEDURE>', async () => {
const lazyPing = lazy(() => Promise.resolve({ default: {} as unknown }))
const lazyProcedure = createLazyProcedureFormAnyLazy(lazyPing)
expectTypeOf(lazyProcedure).toEqualTypeOf<Lazy<ANY_PROCEDURE>>()
})
37 changes: 37 additions & 0 deletions packages/server/src/lazy-utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ContractProcedure } from '@orpc/contract'
import { isLazy, lazy, unlazy } from './lazy'
import { createLazyProcedureFormAnyLazy } from './lazy-utils'
import { Procedure } from './procedure'

describe('createLazyProcedureFormAnyLazy', () => {
const ping = new Procedure({
contract: new ContractProcedure({
InputSchema: undefined,
OutputSchema: undefined,
}),
func: vi.fn(),
})

it('return a Lazy<ANY_PROCEDURE>', async () => {
const lazyPing = lazy(() => Promise.resolve({ default: ping }))

const lazyProcedure = createLazyProcedureFormAnyLazy(lazyPing)

expect(lazyProcedure).toSatisfy(isLazy)
expect(unlazy(lazyProcedure)).resolves.toEqual({ default: ping })
})

it('throw un unlazy non-procedure', () => {
const lazyPing = lazy(() => Promise.resolve({ default: {} as unknown }))
const lazyProcedure = createLazyProcedureFormAnyLazy(lazyPing)

expect(unlazy(lazyProcedure)).rejects.toThrow('Expected a lazy<procedure> but got lazy<unknown>')
})

it('flat lazy', () => {
const lazyPing = lazy(() => Promise.resolve({ default: lazy(() => Promise.resolve({ default: ping })) }))
const lazyProcedure = createLazyProcedureFormAnyLazy(lazyPing)

expect(unlazy(lazyProcedure)).resolves.toEqual({ default: ping })
})
})
21 changes: 21 additions & 0 deletions packages/server/src/lazy-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Lazy } from './lazy'
import { flatLazy, lazy, unlazy } from './lazy'
import { type ANY_PROCEDURE, isProcedure } from './procedure'

export function createLazyProcedureFormAnyLazy(lazied: Lazy<any>): Lazy<ANY_PROCEDURE> {
const lazyProcedure = lazy(async () => {
const { default: maybeProcedure } = await unlazy(flatLazy(lazied))

if (!isProcedure(maybeProcedure)) {
throw new Error(`
Expected a lazy<procedure> but got lazy<unknown>.
This should be caught by TypeScript compilation.
Please report this issue if this makes you feel uncomfortable.
`)
}

return { default: maybeProcedure }
})

return lazyProcedure
}
2 changes: 1 addition & 1 deletion packages/server/src/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function isLazy(item: unknown): item is ANY_LAZY {
)
}

export function unlazy<T>(lazied: Lazyable<T>): Promise<{ default: T }> {
export function unlazy<T extends Lazyable<any>>(lazied: T): Promise<{ default: T extends Lazy<infer U> ? U : T }> {
return isLazy(lazied) ? lazied[LAZY_LOADER_SYMBOL]() : Promise.resolve({ default: lazied })
}

Expand Down
Loading

0 comments on commit 4e4b869

Please sign in to comment.