Skip to content

Commit

Permalink
feat(http): basic support
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Feb 10, 2024
1 parent 4885102 commit ce0d4b3
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 1 deletion.
49 changes: 49 additions & 0 deletions packages/http/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "@cordisjs/plugin-http",
"description": "Axios-style HTTP client service for Cordis",
"version": "0.1.0",
"main": "lib/index.mjs",
"types": "lib/index.d.ts",
"exports": {
".": {
"require": "./lib/index.cjs",
"import": "./lib/index.mjs",
"types": "./lib/index.d.ts"
},
"./package.json": "./package.json"
},
"files": [
"lib",
"src"
],
"author": "Shigma <[email protected]>",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/cordiverse/cordis.git",
"directory": "packages/http"
},
"bugs": {
"url": "https://github.com/cordiverse/cordis/issues"
},
"homepage": "https://github.com/cordiverse/cordis",
"keywords": [
"cordis",
"http",
"fetch",
"request",
"service",
"plugin"
],
"devDependencies": {
"cordis": "^3.9.2"
},
"peerDependencies": {
"cordis": "^3.9.2"
},
"dependencies": {
"cosmokit": "^1.5.2",
"unws": "^0.2.4",
"ws": "^8.16.0"
}
}
3 changes: 3 additions & 0 deletions packages/http/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @cordisjs/plugin-http

Axios-style HTTP client service for Cordis.
144 changes: 144 additions & 0 deletions packages/http/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { Context } from 'cordis'
import { Dict } from 'cosmokit'
import { WebSocket } from 'unws'
import { ClientOptions } from 'ws'

declare module 'cordis' {
interface Context {
http: HTTP
}
}

interface HTTP {
[Context.current]: Context
<T>(url: string | URL, config?: HTTP.Config): Promise<HTTP.Response<T>>
<T>(method: HTTP.Method, url: string | URL, config?: HTTP.Config): Promise<HTTP.Response<T>>
get<T>(url: string, config?: HTTP.Config): Promise<T>
delete<T>(url: string, config?: HTTP.Config): Promise<T>
head(url: string, config?: HTTP.Config): Promise<Dict>
patch<T>(url: string, data?: any, config?: HTTP.Config): Promise<T>
post<T>(url: string, data?: any, config?: HTTP.Config): Promise<T>
put<T>(url: string, data?: any, config?: HTTP.Config): Promise<T>
/** @deprecated use `ctx.http()` instead */
axios<T>(url: string, config?: HTTP.Config): Promise<HTTP.Response<T>>
ws(url: string, config?: HTTP.Config): Promise<WebSocket>
}

const _Error = Error

namespace HTTP {
export type Method =
| 'get' | 'GET'
| 'delete' | 'DELETE'
| 'head' | 'HEAD'
| 'options' | 'OPTIONS'
| 'post' | 'POST'
| 'put' | 'PUT'
| 'patch' | 'PATCH'
| 'purge' | 'PURGE'
| 'link' | 'LINK'
| 'unlink' | 'UNLINK'

export type ResponseType =
| 'arraybuffer'
| 'json'
| 'text'
| 'stream'

export interface Config {
method?: Method
params?: Dict
data?: any
headers?: Dict
timeout?: number
proxyAgent?: string
responseType?: ResponseType
}

export class Error extends _Error {
response?: Response
}

export interface Response<T = any> {
data: T
status: number
statusText: string
headers: Dict
}
}

export function apply(ctx: Context) {
ctx.provide('http')

const http = async function http(this: Context, ...args: any[]) {
let method: HTTP.Method | undefined
if (typeof args[1] === 'string' || args[1] instanceof URL) {
method = args.shift()
}
const response = await fetch(args[0], {
method,
...args[1],
})
const data = await response.json()
return {
data,
status: response.status,
statusText: response.statusText,
headers: Object.fromEntries(response.headers),
}
} as HTTP

for (const method of ['GET', 'DELETE'] as const) {
http[method.toLowerCase()] = async function (this: HTTP, url: string, config?: HTTP.Config) {
const caller = this[Context.current]
const response = await caller.http(url, {
method,
...config,
})
return response.data
}
}

for (const method of ['PATCH', 'POST', 'PUT'] as const) {
http[method.toLowerCase()] = async function (this: HTTP, url: string, data?: any, config?: HTTP.Config) {
const caller = this[Context.current]
const response = await caller.http(url, {
method,
data,
...config,
})
return response.data
}
}

http.head = async function (this: HTTP, url: string, config?: HTTP.Config) {
const caller = this[Context.current]
const response = await caller.http(url, {
method: 'HEAD',
...config,
})
return response.headers
}

http.ws = async function (this: HTTP, url: string, config?: HTTP.Config) {
// const caller = this[Context.current]
return new WebSocket(url, 'Server' in WebSocket ? {
// agent: caller.agent(config?.proxyAgent),
handshakeTimeout: config?.timeout,
headers: {
...config?.headers,
},
} as ClientOptions as never : undefined)
}

http.axios = async function (this: HTTP, url: string, config?: HTTP.Config) {
const caller = this[Context.current]
caller.emit('internal/warning', 'ctx.http.axios() is deprecated, use ctx.http() instead')
return caller.http(url, config)
}

ctx.http = http
ctx.on('dispose', () => {
ctx.http = null as never
})
}
10 changes: 10 additions & 0 deletions packages/http/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib",
},
"include": [
"src",
],
}
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@cordisjs/loader": ["packages/core/src"],
"@cordisjs/plugin-http-*": ["packages/*/src"],
"@cordisjs/plugin-*": ["packages/*/src"],
"@cordisjs/*": ["packages/*/src"],
},
},
Expand Down

0 comments on commit ce0d4b3

Please sign in to comment.