Skip to content

Commit

Permalink
feat: add initial modules
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Nov 18, 2020
1 parent fbb085d commit ce62be1
Show file tree
Hide file tree
Showing 26 changed files with 658 additions and 5 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
dist
lib
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
node_modules
*.log*
dist
lib
57 changes: 54 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,68 @@ And then SSR<sup>2</sup> moved browser code to server

And then Workers<sup>3</sup> moved browser/server code to workers

Workers are neither NodeJS with `process` or browser with `window` yet expected to run code that had to work both of them :}
Workers are neither NodeJS with `process` or browser with `window`

Yet expected to run code that had to work both of them :}

**[1]** Single Page Applications
**[2]** Server Side Rendering
**[3]** https://workers.cloudflare.com


## What is un?

Un is a preset of polyfills and small utilities to make it easier doing SSR and serving API inside workers.
un is a framework of modules, shims and presets that work perfectly with any Javascript environemnt
including Browsers, Workers, NodeJS or pure JavaScript.

You still need a bundler like [rollup.js](https://rollupjs.org) and un will disapear as soon as is bundled.

The goal is that final bundle works consistent regardless of running context yet not adding excessive polyfills.

## Install

Install un as `devDependen:

```bash
yarn add --dev un
# or
npm i -D @nuxt/un
```

You can import modules from `un/lib/`

## Shims

- [process](./src/shims/process.ts)

## NodeJS

### `http`

- [IncomingMessage](./src/node/http/request.ts)
- [ServerResponse](./src/node/http/request.ts)
- [METHODS](./src/node/http/consts.ts)
- [STATUS_CODES](./src/node/http/consts.ts)

### `net`

- [Socket](./src/node/net/socket.ts)

### `stream`

- [Readable](./src/node/stream/readable.ts)
- [Writable](./src/node/stream/writable.ts)

## Mocks

- [generic](./src/mock/empty.ts): Exports a proxy that can act as a recursive function, calss, object or array
- [empty](./src/mock/empty.ts): Exports `{}`
- [noop](./src/mock/noop.ts): Exports `() => {}`

## Packages

- [depd](./src/npm/depd.ts)
- [mime-db](./src/npm/mime-db.ts)
- [mime](./src/npm/mime.ts)

## License

Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
"repository": "nuxt-contrib/un",
"license": "MIT",
"sideEffects": false,
"types": "lib/*.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "true",
"build": "tsc src",
"lint": "eslint --ext ts .",
"release": "yarn build && standard-version && npm publish && git push --follow-tags"
},
Expand All @@ -19,5 +20,8 @@
"eslint": "latest",
"standard-version": "latest",
"typescript": "latest"
},
"dependencies": {
"mime": "^2.4.6"
}
}
1 change: 1 addition & 0 deletions src/mock/empty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default {}
25 changes: 25 additions & 0 deletions src/mock/generic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
function getProxy (name: string, overrides: any = {}): any {
const fn = function () { }
fn.prototype.name = name
const props: any = {}
return new Proxy(fn, {
get (_target, prop) {
if (prop === 'caller') { return null }
if (prop === '__createMock__') { return getProxy }
if (prop in overrides) { return overrides[prop] }
// @ts-ignore
return (props[prop] = props[prop] || getProxy(`${name}.${prop.toString()}`))
},
apply (_target, _this, _args) {
return getProxy(`${name}()`)
},
construct (_target, _args, _newT) {
return getProxy(`[${name}]`) as Object
},
enumerate (_target) {
return []
}
})
}

export default getProxy('mock')
1 change: 1 addition & 0 deletions src/mock/noop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => {}
80 changes: 80 additions & 0 deletions src/node/http/consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
export const METHODS = [
'ACL', 'BIND', 'CHECKOUT',
'CONNECT', 'COPY', 'DELETE',
'GET', 'HEAD', 'LINK',
'LOCK', 'M-SEARCH', 'MERGE',
'MKACTIVITY', 'MKCALENDAR', 'MKCOL',
'MOVE', 'NOTIFY', 'OPTIONS',
'PATCH', 'POST', 'PRI',
'PROPFIND', 'PROPPATCH', 'PURGE',
'PUT', 'REBIND', 'REPORT',
'SEARCH', 'SOURCE', 'SUBSCRIBE',
'TRACE', 'UNBIND', 'UNLINK',
'UNLOCK', 'UNSUBSCRIBE'
]

export const STATUS_CODES = {
100: 'Continue',
101: 'Switching Protocols',
102: 'Processing',
103: 'Early Hints',
200: 'OK',
201: 'Created',
202: 'Accepted',
203: 'Non-Authoritative Information',
204: 'No Content',
205: 'Reset Content',
206: 'Partial Content',
207: 'Multi-Status',
208: 'Already Reported',
226: 'IM Used',
300: 'Multiple Choices',
301: 'Moved Permanently',
302: 'Found',
303: 'See Other',
304: 'Not Modified',
305: 'Use Proxy',
307: 'Temporary Redirect',
308: 'Permanent Redirect',
400: 'Bad Request',
401: 'Unauthorized',
402: 'Payment Required',
403: 'Forbidden',
404: 'Not Found',
405: 'Method Not Allowed',
406: 'Not Acceptable',
407: 'Proxy Authentication Required',
408: 'Request Timeout',
409: 'Conflict',
410: 'Gone',
411: 'Length Required',
412: 'Precondition Failed',
413: 'Payload Too Large',
414: 'URI Too Long',
415: 'Unsupported Media Type',
416: 'Range Not Satisfiable',
417: 'Expectation Failed',
418: "I'm a Teapot",
421: 'Misdirected Request',
422: 'Unprocessable Entity',
423: 'Locked',
424: 'Failed Dependency',
425: 'Too Early',
426: 'Upgrade Required',
428: 'Precondition Required',
429: 'Too Many Requests',
431: 'Request Header Fields Too Large',
451: 'Unavailable For Legal Reasons',
500: 'Internal Server Error',
501: 'Not Implemented',
502: 'Bad Gateway',
503: 'Service Unavailable',
504: 'Gateway Timeout',
505: 'HTTP Version Not Supported',
506: 'Variant Also Negotiates',
507: 'Insufficient Storage',
508: 'Loop Detected',
509: 'Bandwidth Limit Exceeded',
510: 'Not Extended',
511: 'Network Authentication Required'
}
3 changes: 3 additions & 0 deletions src/node/http/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './consts'
export * from './request'
export * from './response'
42 changes: 42 additions & 0 deletions src/node/http/request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type http from 'http'
import { Socket } from 'src/node/net/socket'
import { Readable } from 'src/node/stream/readable'
import { rawHeaders } from 'src/utils'

// Docs: https://nodejs.org/api/http.html#http_class_http_incomingmessage
// Implementation: https://github.com/nodejs/node/blob/master/lib/_http_incoming.js

export class IncomingMessage extends Readable implements http.IncomingMessage {
public aborted: boolean = false;
public httpVersion: string = '1.1'
public httpVersionMajor: number = 1
public httpVersionMinor: number = 1
public complete: boolean = true
public connection: Socket
public socket: Socket
public headers: http.IncomingHttpHeaders = {}
public trailers = {}
public method: string = 'GET'
public url: string = '/'
public statusCode: number = 200
public statusMessage: string = ''

readable: boolean = false

constructor (socket?: Socket) {
super()
this.socket = this.connection = socket || new Socket()
}

get rawHeaders () {
return rawHeaders(this.headers)
}

get rawTrailers () {
return []
}

setTimeout (_msecs: number, _callback?: () => void) {
return this
}
}
111 changes: 111 additions & 0 deletions src/node/http/response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import type http from 'http'
import type { Socket } from 'net'
import { Callback, HeadersObject } from 'src/types'
import { Writable } from 'src/node/stream/writable'

// Docs: https://nodejs.org/api/http.html#http_class_http_serverresponse
// Implementation: https://github.com/nodejs/node/blob/master/lib/_http_outgoing.js

export class ServerResponse extends Writable implements http.ServerResponse {
statusCode: number = 200;
statusMessage: string = '';
upgrading: boolean = false;
chunkedEncoding: boolean = false;
shouldKeepAlive: boolean = false;
useChunkedEncodingByDefault: boolean = false;
sendDate: boolean = false;
finished: boolean = false;
headersSent: boolean = false;
connection: Socket | null = null;
socket: Socket | null = null;
req: http.IncomingMessage

_headers: HeadersObject = {}

constructor (req: http.IncomingMessage) {
super()
this.req = req
}

assignSocket (socket: Socket): void {
// @ts-ignore
socket._httpMessage = this
// socket.on('close', onServerResponseClose)
this.socket = socket
this.connection = socket
this.emit('socket', socket)
this._flush()
}

_flush () {
this.flushHeaders()
}

detachSocket (_socket: Socket): void {
}

writeContinue (_callback?: Callback): void {
}

writeHead (statusCode: number,
arg1?: string | http.OutgoingHttpHeaders | http.OutgoingHttpHeader[],
arg2?: http.OutgoingHttpHeaders | http.OutgoingHttpHeader[]) {
if (statusCode) {
this.statusCode = statusCode
}
if (typeof arg1 === 'string') {
this.statusMessage = arg1
arg1 = undefined
}
const headers = arg2 || arg1
if (headers) {
if (Array.isArray(headers)) {
// TODO: OutgoingHttpHeader[]
} else {
for (const key in headers) {
// @ts-ignore
this.setHeader(key, headers[key])
}
}
}
this.headersSent = true
return this
}

writeProcessing (): void {
}

setTimeout (_msecs: number, _callback?: Callback): this {
return this
}

setHeader (name: string, value: number | string | ReadonlyArray<string>): void {
this._headers[name.toLowerCase()] = value + ''
}

getHeader (name: string): number | string | string[] | undefined {
return this._headers[name.toLowerCase()]
}

getHeaders (): http.OutgoingHttpHeaders {
return this._headers
}

getHeaderNames (): string[] {
return Object.keys(this._headers)
}

hasHeader (name: string): boolean {
return name.toLowerCase() in this._headers
}

removeHeader (name: string): void {
delete this._headers[name.toLowerCase()]
}

addTrailers (_headers: http.OutgoingHttpHeaders | ReadonlyArray<[string, string]>): void {
}

flushHeaders (): void {
}
}
3 changes: 3 additions & 0 deletions src/node/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './http'
export * from './net'
export * from './stream'
1 change: 1 addition & 0 deletions src/node/net/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './socket'
Loading

0 comments on commit ce62be1

Please sign in to comment.