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
1 change: 1 addition & 0 deletions .changepacks/changepack_log_TrNXrNzW_2CG0ILlaaUW3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"changes":{"packages/generator/package.json":"Patch"},"note":"Fix gen issue","date":"2025-12-04T13:14:14.424512200Z"}
1 change: 1 addition & 0 deletions .changepacks/changepack_log_c5-e3qOi7k21VRnLuw095.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"changes":{"packages/core/package.json":"Patch","packages/react-query/package.json":"Patch","packages/fetch/package.json":"Patch"},"note":"Fix query typing issue","date":"2025-12-04T13:14:26.431881700Z"}
7 changes: 4 additions & 3 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"dependencies": {
"@devup-api/fetch": "workspace:*",
"@devup-api/next-plugin": "workspace:*",
"@devup-api/react-query": "workspace:*",
"@devup-ui/react": "^1",
"next": "^16.0.4",
"react": "^19.2.0",
Expand Down Expand Up @@ -88,15 +89,15 @@
},
"packages/core": {
"name": "@devup-api/core",
"version": "0.1.5",
"version": "0.1.6",
"devDependencies": {
"@types/node": "^24.10",
"typescript": "^5.9",
},
},
"packages/fetch": {
"name": "@devup-api/fetch",
"version": "0.1.5",
"version": "0.1.7",
"dependencies": {
"@devup-api/core": "workspace:*",
},
Expand Down Expand Up @@ -139,7 +140,7 @@
},
"packages/react-query": {
"name": "@devup-api/react-query",
"version": "0.0.0",
"version": "0.1.0",
"dependencies": {
"@devup-api/fetch": "workspace:*",
"@tanstack/react-query": ">=5.90",
Expand Down
37 changes: 34 additions & 3 deletions examples/next/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,46 @@
'use client'

import { createApi } from '@devup-api/fetch'
import { createQueryClient } from '@devup-api/react-query'
import { Box, Text } from '@devup-ui/react'
import { useEffect } from 'react'

const api = createApi('https://api.example.com')
const api2 = createApi('https://api.example2.com', undefined, 'openapi2.json')
const api = createApi({
baseUrl: 'https://api.example.com',
})
const api2 = createApi({
baseUrl: 'https://api.example2.com',
serverName: 'openapi2.json',
})

const queryClient = createQueryClient(api)

export default function Home() {
const { data, isLoading, error } = queryClient.useQuery('GET', 'getUsers', {
// params: { id: 1 },
query: {
name: 'John Doe',
},
})

console.info(data, isLoading, error)

const {
data: data2,
error: error2,
mutateAsync,
} = queryClient.useMutation('GET', '/users/{id}', {})
mutateAsync({
params: { id: 1 },
query: {
name: 'John Doe',
},
})

console.info(data2, error2)

useEffect(() => {
api2.get('getUsers2', {}).then((res) => {
api2.get('getUsers2').then((res) => {
console.log(res)
})
api.get('getUsers', {}).then((res) => {
Expand Down
1 change: 1 addition & 0 deletions examples/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"react-dom": "^19.2.0",
"@devup-api/next-plugin": "workspace:*",
"@devup-api/fetch": "workspace:*",
"@devup-api/react-query": "workspace:*",
"@devup-ui/react": "^1"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
"lint": "biome check",
"lint:fix": "biome check --write",
"prepare": "husky",
"build": "bun run -F @devup-api/core build && bun run -F @devup-api/utils build && bun run -F @devup-api/generator build && bun run -F @devup-api/fetch build && bun run -F @devup-api/webpack-plugin build && bun run -F @devup-api/vite-plugin build && bun run -F @devup-api/next-plugin build && bun run -F @devup-api/rsbuild-plugin build",
"publish": "bun publish --cwd packages/core && bun publish --cwd packages/utils && bun publish --cwd packages/generator && bun publish --cwd packages/fetch && bun publish --cwd packages/webpack-plugin && bun publish --cwd packages/vite-plugin && bun publish --cwd packages/next-plugin && bun publish --cwd packages/rsbuild-plugin"
"build": "bun run -F @devup-api/core build && bun run -F @devup-api/utils build && bun run -F @devup-api/generator build && bun run -F @devup-api/fetch build && bun run -F @devup-api/webpack-plugin build && bun run -F @devup-api/vite-plugin build && bun run -F @devup-api/next-plugin build && bun run -F @devup-api/rsbuild-plugin build && bun run -F @devup-api/react-query build",
"publish": "bun publish --cwd packages/core && bun publish --cwd packages/utils && bun publish --cwd packages/generator && bun publish --cwd packages/fetch && bun publish --cwd packages/webpack-plugin && bun publish --cwd packages/vite-plugin && bun publish --cwd packages/next-plugin && bun publish --cwd packages/rsbuild-plugin && bun publish --cwd packages/react-query"
},
"workspaces": [
"packages/*",
Expand Down
10 changes: 9 additions & 1 deletion packages/core/src/additional.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { DevupApiServers } from './api-struct'
import type { Middleware } from './middleware'

export type Additional<
Expand All @@ -7,7 +8,14 @@ export type Additional<

export type RequiredOptions<T extends object> = keyof T extends undefined
? never
: T
: 'params' extends keyof T
? T
: 'query' extends keyof T
? T
: 'body' extends keyof T
? T
: never
export type IsCold = keyof DevupApiServers extends never ? true : false
export type DevupApiRequestInit = Omit<RequestInit, 'body'> & {
body?: object | RequestInit['body']
params?: Record<string, string | number | boolean | null | undefined>
Expand Down
42 changes: 31 additions & 11 deletions packages/core/src/api-struct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,48 @@ export interface DevupRequestComponentStruct {}
// biome-ignore lint/suspicious/noEmptyInterface: empty interface
export interface DevupResponseComponentStruct {}

export type DevupApiStruct = DevupGetApiStruct &
DevupPostApiStruct &
DevupPutApiStruct &
DevupDeleteApiStruct &
DevupPatchApiStruct
export type DevupGetApiStructScope<O extends string> = ConditionalScope<
DevupGetApiStruct,
O
>
export type DevupPostApiStructScope<O extends string> = ConditionalScope<
DevupPostApiStruct,
O
>
export type DevupPutApiStructScope<O extends string> = ConditionalScope<
DevupPutApiStruct,
O
>
export type DevupDeleteApiStructScope<O extends string> = ConditionalScope<
DevupDeleteApiStruct,
O
>
export type DevupPatchApiStructScope<O extends string> = ConditionalScope<
DevupPatchApiStruct,
O
>

export type DevupGetApiStructKey<O extends string> = ConditionalKeys<
ConditionalScope<DevupGetApiStruct, O>
DevupGetApiStructScope<O>
>
export type DevupPostApiStructKey<O extends string> = ConditionalKeys<
ConditionalScope<DevupPostApiStruct, O>
DevupPostApiStructScope<O>
>
export type DevupPutApiStructKey<O extends string> = ConditionalKeys<
ConditionalScope<DevupPutApiStruct, O>
DevupPutApiStructScope<O>
>
export type DevupDeleteApiStructKey<O extends string> = ConditionalKeys<
ConditionalScope<DevupDeleteApiStruct, O>
DevupDeleteApiStructScope<O>
>
export type DevupPatchApiStructKey<O extends string> = ConditionalKeys<
ConditionalScope<DevupPatchApiStruct, O>
DevupPatchApiStructScope<O>
>
export type DevupApiStructScope<O extends string> = DevupGetApiStructScope<O> &
DevupPostApiStructScope<O> &
DevupPutApiStructScope<O> &
DevupDeleteApiStructScope<O> &
DevupPatchApiStructScope<O>

export type DevupApiStructKey<O extends string> = ConditionalKeys<
ConditionalScope<DevupApiStruct, O>
DevupApiStructScope<O>
>
6 changes: 3 additions & 3 deletions packages/core/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ export interface MiddlewareCallbackParams {
}

type MiddlewareOnRequest = (
params: MiddlewareCallbackParams,
params: Readonly<MiddlewareCallbackParams>,
) => PromiseOr<undefined | Request | Response>
type MiddlewareOnResponse = (
params: MiddlewareCallbackParams & { response: Response },
params: Readonly<MiddlewareCallbackParams & { response: Response }>,
) => PromiseOr<undefined | Error | Response>
type MiddlewareOnError = (
params: MiddlewareCallbackParams & { error: unknown },
params: Readonly<MiddlewareCallbackParams & { error: unknown }>,
) => PromiseOr<undefined | Error | Response>

export type Middleware =
Expand Down
22 changes: 22 additions & 0 deletions packages/fetch/src/__tests__/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,28 @@ test('request does not serialize non-plain object body', async () => {
}
})

test('request serializes plain object body to JSON with custom headers', async () => {
const api = new DevupApi('https://api.example.com', undefined, 'openapi.json')
const mockFetch = globalThis.fetch as unknown as ReturnType<typeof mock>

await api.post(
'/test' as never,
{
body: { name: 'test', value: 123 },
} as never,
)

expect(mockFetch).toHaveBeenCalledTimes(1)
const call = mockFetch.mock.calls[0]
expect(call).toBeDefined()
if (call) {
const request = call[0] as Request
const body = await request.text()
expect(body).toBe(JSON.stringify({ name: 'test', value: 123 }))
expect(request.headers.get('Content-Type')).toBe('application/json')
}
})

test('request merges defaultOptions with request options', async () => {
const api = new DevupApi(
'https://api.example.com',
Expand Down
Loading