├── .github
├── FUNDING.yml
└── workflows
│ └── main.yml
├── .gitignore
├── LICENSE
├── README.md
├── mod.ts
└── mod_test.ts
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | ko_fi: v1rtl
4 | liberapay: v1rtl
5 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | # Controls when the action will run. Triggers the workflow on push or pull request
4 | # events but only for the master branch
5 | on:
6 | push:
7 | branches: [master]
8 | pull_request:
9 | branches: [master]
10 |
11 | jobs:
12 | test:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v2
16 | - uses: denoland/setup-deno@v1
17 | with:
18 | deno-version: v1.x
19 | - name: Run tests
20 | run: deno test -A --coverage=coverage
21 | - name: Create coverage report
22 | run: deno coverage ./coverage --lcov > coverage.lcov
23 | - name: Coveralls
24 | uses: coverallsapp/github-action@master
25 | with:
26 | github-token: ${{ secrets.GITHUB_TOKEN }}
27 | path-to-lcov: ./coverage.lcov
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | coverage
2 | coverage.*
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Deno libraries
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # node-http
4 |
5 | [![GitHub Workflow Status][gh-actions-img]][github-actions] [![Coverage][cov-badge]][cov]
6 |
7 |
8 |
9 | > ⚠️ **DEPRECATED!** Use [std/http](https://deno.land/std/node/http.ts) instead.
10 |
11 | Node.js-like HTTP server for Deno. Makes porting web things from Node (a little bit) easier.
12 |
13 | ## Example
14 |
15 | ```js
16 | import { createServer } from 'https://deno.land/x/node_http/mod.ts'
17 |
18 | const s = createServer((req) => req.respond({ body: 'Hello' }))
19 |
20 | s.on('error', (err) => console.log(err))
21 |
22 | s.on('listening', () => console.log(s.address()))
23 |
24 | await s.listen({ port: 3000 })
25 | ```
26 |
27 | [docs-badge]: https://img.shields.io/github/v/release/deno-libs/node_http?color=yellow&label=Docs&logo=deno&style=for-the-badge
28 | [docs]: https://doc.deno.land/https/deno.land/x/node_http/mod.ts
29 | [gh-actions-img]: https://img.shields.io/github/workflow/status/deno-libs/node-http/CI?style=for-the-badge
30 | [github-actions]: https://github.com/deno-libs/node-http/actions
31 | [cov]: https://coveralls.io/github/deno-libs/node-http
32 | [cov-badge]: https://img.shields.io/coveralls/github/deno-libs/node-http?style=for-the-badge
33 |
--------------------------------------------------------------------------------
/mod.ts:
--------------------------------------------------------------------------------
1 | import * as http from 'https://deno.land/std@0.106.0/http/server.ts'
2 | import { EventEmitter } from 'https://deno.land/x/event@2.0.0/mod.ts'
3 |
4 | import { getFreePort } from 'https://deno.land/x/free_port@v1.2.0/mod.ts'
5 |
6 | type Events = {
7 | error: [Error]
8 | listening: []
9 | request: [http.ServerRequest]
10 | close: []
11 | }
12 |
13 | export type ServerHandler = (req: http.ServerRequest) => void | Promise
14 |
15 | /**
16 | * Ported from `net.AddressInfo`
17 | */
18 | export type AddressInfo = {
19 | family: string
20 | address: string
21 | port: number
22 | }
23 |
24 | export class Server extends EventEmitter {
25 | #server?: http.Server
26 | handler?: ServerHandler
27 |
28 | constructor(handler?: ServerHandler) {
29 | super()
30 | this.handler = handler
31 | }
32 |
33 | async listen(addr?: string | http.HTTPOptions) {
34 | if (!addr) addr = { port: await getFreePort(3000) }
35 |
36 | try {
37 | this.#server = http.serve(addr)
38 | } catch (e) {
39 | await this.emit('error', e)
40 | throw e
41 | }
42 |
43 | this.emit('listening')
44 |
45 | try {
46 | for await (const req of this.#server!) {
47 | await this.emit('request', req)
48 | await this.handler?.(req)
49 | }
50 | } catch (e) {
51 | await this.emit('error', e)
52 | throw e
53 | }
54 |
55 | return this.#server
56 | }
57 | address(): string | AddressInfo {
58 | const unixAddr = this.#server?.listener.addr as Deno.UnixAddr
59 | const netAddr = this.#server?.listener.addr as Deno.NetAddr
60 |
61 | if (unixAddr?.path) return unixAddr.path
62 | else return { family: 'IPv4', address: netAddr.hostname, port: netAddr.port }
63 | }
64 | close() {
65 | this.#server?.close()
66 | this.emit('close')
67 | }
68 | }
69 |
70 | export const createServer = (handler?: ServerHandler) => new Server(handler)
71 |
--------------------------------------------------------------------------------
/mod_test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it, run } from 'https://deno.land/x/tincan@0.2.1/mod.ts'
2 | import { createServer } from './mod.ts'
3 | import { makeFetch } from 'https://deno.land/x/superfetch@0.0.9/mod.ts'
4 |
5 | describe('node_http', () => {
6 | it('should start the server', async () => {
7 | const s = createServer((req) => req.respond({ body: 'Hello' }))
8 |
9 | const fetch = makeFetch(s.handler!)
10 |
11 | await fetch('/').expect('Hello')
12 | })
13 | describe('events', () => {
14 | it('should trigger "listening" event', async () => {
15 | const s = createServer()
16 |
17 | s.on('listening', () => {
18 | expect(s.address()).toEqual({ family: 'IPv4', address: '0.0.0.0', port: 8080 })
19 | s.close()
20 | })
21 |
22 | await s.listen({ port: 8080 })
23 | })
24 | it('should trigger "request" event', async () => {
25 | const s = createServer()
26 |
27 | s.on('request', (req) => {
28 | expect(req.url).toBe('/')
29 | req.respond({ body: 'hello' })
30 | })
31 |
32 | const fetch = makeFetch(s)
33 |
34 | await fetch('/').expect('hello')
35 | })
36 | })
37 | })
38 |
39 | run()
40 |
--------------------------------------------------------------------------------