├── .gitignore ├── LICENSE ├── README.md ├── crypt.ts ├── deno.d.ts ├── errors.ts ├── example └── main.ts ├── ioutil.ts ├── tsconfig.json ├── ws.ts └── ws_test.ts /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Yusuke Sakurai 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 | deno-ws 2 | === 3 | An experimental websocket implementation for deno.ts 4 | 5 | NOTE: 2019/01/08 6 | 7 | 🎉deno-ws has been merged into https://github.com/denoland/deno_std 8 | Please use https://deno.land/x/net/ws.ts instead of this repository. This repository will be archived soon. 9 | 10 | ## Author 11 | 12 | [keroxp](https://github.com/keroxp) 13 | 14 | ## License 15 | 16 | MIT 17 | -------------------------------------------------------------------------------- /crypt.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * [js-sha1]{@link https://github.com/emn178/js-sha1} 3 | * 4 | * @version 0.6.0 5 | * @author Chen, Yi-Cyuan [emn178@gmail.com] 6 | * @copyright Chen, Yi-Cyuan 2014-2017 7 | * @license MIT 8 | */ 9 | /*jslint bitwise: true */ 10 | 11 | const HEX_CHARS = '0123456789abcdef'.split(''); 12 | const EXTRA = [-2147483648, 8388608, 32768, 128]; 13 | const SHIFT = [24, 16, 8, 0]; 14 | 15 | const blocks = []; 16 | 17 | export class Sha1 { 18 | blocks; 19 | block; 20 | start; 21 | bytes; 22 | hBytes; 23 | finalized; 24 | hashed; 25 | first; 26 | 27 | h0 = 0x67452301; 28 | h1 = 0xEFCDAB89; 29 | h2 = 0x98BADCFE; 30 | h3 = 0x10325476; 31 | h4 = 0xC3D2E1F0; 32 | lastByteIndex = 0; 33 | 34 | constructor(sharedMemory: boolean = false) { 35 | if (sharedMemory) { 36 | blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = 37 | blocks[4] = blocks[5] = blocks[6] = blocks[7] = 38 | blocks[8] = blocks[9] = blocks[10] = blocks[11] = 39 | blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; 40 | this.blocks = blocks; 41 | } else { 42 | this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 43 | } 44 | 45 | this.h0 = 0x67452301; 46 | this.h1 = 0xEFCDAB89; 47 | this.h2 = 0x98BADCFE; 48 | this.h3 = 0x10325476; 49 | this.h4 = 0xC3D2E1F0; 50 | 51 | this.block = this.start = this.bytes = this.hBytes = 0; 52 | this.finalized = this.hashed = false; 53 | this.first = true; 54 | } 55 | 56 | update(data: string | ArrayBuffer) { 57 | if (this.finalized) { 58 | return; 59 | } 60 | let message; 61 | let notString = typeof(data) !== 'string'; 62 | if (notString && data instanceof ArrayBuffer) { 63 | message = new Uint8Array(data); 64 | } else { 65 | message = data; 66 | } 67 | let code, index = 0, i, length = message.length || 0, blocks = this.blocks; 68 | 69 | while (index < length) { 70 | if (this.hashed) { 71 | this.hashed = false; 72 | blocks[0] = this.block; 73 | blocks[16] = blocks[1] = blocks[2] = blocks[3] = 74 | blocks[4] = blocks[5] = blocks[6] = blocks[7] = 75 | blocks[8] = blocks[9] = blocks[10] = blocks[11] = 76 | blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; 77 | } 78 | 79 | if (notString) { 80 | for (i = this.start; index < length && i < 64; ++index) { 81 | blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]; 82 | } 83 | } else { 84 | for (i = this.start; index < length && i < 64; ++index) { 85 | code = message.charCodeAt(index); 86 | if (code < 0x80) { 87 | blocks[i >> 2] |= code << SHIFT[i++ & 3]; 88 | } else if (code < 0x800) { 89 | blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; 90 | blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; 91 | } else if (code < 0xd800 || code >= 0xe000) { 92 | blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; 93 | blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; 94 | blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; 95 | } else { 96 | code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); 97 | blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; 98 | blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; 99 | blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; 100 | blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; 101 | } 102 | } 103 | } 104 | 105 | this.lastByteIndex = i; 106 | this.bytes += i - this.start; 107 | if (i >= 64) { 108 | this.block = blocks[16]; 109 | this.start = i - 64; 110 | this.hash(); 111 | this.hashed = true; 112 | } else { 113 | this.start = i; 114 | } 115 | } 116 | if (this.bytes > 4294967295) { 117 | this.hBytes += this.bytes / 4294967296 << 0; 118 | this.bytes = this.bytes % 4294967296; 119 | } 120 | return this; 121 | }; 122 | 123 | finalize() { 124 | if (this.finalized) { 125 | return; 126 | } 127 | this.finalized = true; 128 | let blocks = this.blocks, i = this.lastByteIndex; 129 | blocks[16] = this.block; 130 | blocks[i >> 2] |= EXTRA[i & 3]; 131 | this.block = blocks[16]; 132 | if (i >= 56) { 133 | if (!this.hashed) { 134 | this.hash(); 135 | } 136 | blocks[0] = this.block; 137 | blocks[16] = blocks[1] = blocks[2] = blocks[3] = 138 | blocks[4] = blocks[5] = blocks[6] = blocks[7] = 139 | blocks[8] = blocks[9] = blocks[10] = blocks[11] = 140 | blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; 141 | } 142 | blocks[14] = this.hBytes << 3 | this.bytes >>> 29; 143 | blocks[15] = this.bytes << 3; 144 | this.hash(); 145 | }; 146 | 147 | hash() { 148 | let a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4; 149 | let f, j, t, blocks = this.blocks; 150 | 151 | for (j = 16; j < 80; ++j) { 152 | t = blocks[j - 3] ^ blocks[j - 8] ^ blocks[j - 14] ^ blocks[j - 16]; 153 | blocks[j] = (t << 1) | (t >>> 31); 154 | } 155 | 156 | for (j = 0; j < 20; j += 5) { 157 | f = (b & c) | ((~b) & d); 158 | t = (a << 5) | (a >>> 27); 159 | e = t + f + e + 1518500249 + blocks[j] << 0; 160 | b = (b << 30) | (b >>> 2); 161 | 162 | f = (a & b) | ((~a) & c); 163 | t = (e << 5) | (e >>> 27); 164 | d = t + f + d + 1518500249 + blocks[j + 1] << 0; 165 | a = (a << 30) | (a >>> 2); 166 | 167 | f = (e & a) | ((~e) & b); 168 | t = (d << 5) | (d >>> 27); 169 | c = t + f + c + 1518500249 + blocks[j + 2] << 0; 170 | e = (e << 30) | (e >>> 2); 171 | 172 | f = (d & e) | ((~d) & a); 173 | t = (c << 5) | (c >>> 27); 174 | b = t + f + b + 1518500249 + blocks[j + 3] << 0; 175 | d = (d << 30) | (d >>> 2); 176 | 177 | f = (c & d) | ((~c) & e); 178 | t = (b << 5) | (b >>> 27); 179 | a = t + f + a + 1518500249 + blocks[j + 4] << 0; 180 | c = (c << 30) | (c >>> 2); 181 | } 182 | 183 | for (; j < 40; j += 5) { 184 | f = b ^ c ^ d; 185 | t = (a << 5) | (a >>> 27); 186 | e = t + f + e + 1859775393 + blocks[j] << 0; 187 | b = (b << 30) | (b >>> 2); 188 | 189 | f = a ^ b ^ c; 190 | t = (e << 5) | (e >>> 27); 191 | d = t + f + d + 1859775393 + blocks[j + 1] << 0; 192 | a = (a << 30) | (a >>> 2); 193 | 194 | f = e ^ a ^ b; 195 | t = (d << 5) | (d >>> 27); 196 | c = t + f + c + 1859775393 + blocks[j + 2] << 0; 197 | e = (e << 30) | (e >>> 2); 198 | 199 | f = d ^ e ^ a; 200 | t = (c << 5) | (c >>> 27); 201 | b = t + f + b + 1859775393 + blocks[j + 3] << 0; 202 | d = (d << 30) | (d >>> 2); 203 | 204 | f = c ^ d ^ e; 205 | t = (b << 5) | (b >>> 27); 206 | a = t + f + a + 1859775393 + blocks[j + 4] << 0; 207 | c = (c << 30) | (c >>> 2); 208 | } 209 | 210 | for (; j < 60; j += 5) { 211 | f = (b & c) | (b & d) | (c & d); 212 | t = (a << 5) | (a >>> 27); 213 | e = t + f + e - 1894007588 + blocks[j] << 0; 214 | b = (b << 30) | (b >>> 2); 215 | 216 | f = (a & b) | (a & c) | (b & c); 217 | t = (e << 5) | (e >>> 27); 218 | d = t + f + d - 1894007588 + blocks[j + 1] << 0; 219 | a = (a << 30) | (a >>> 2); 220 | 221 | f = (e & a) | (e & b) | (a & b); 222 | t = (d << 5) | (d >>> 27); 223 | c = t + f + c - 1894007588 + blocks[j + 2] << 0; 224 | e = (e << 30) | (e >>> 2); 225 | 226 | f = (d & e) | (d & a) | (e & a); 227 | t = (c << 5) | (c >>> 27); 228 | b = t + f + b - 1894007588 + blocks[j + 3] << 0; 229 | d = (d << 30) | (d >>> 2); 230 | 231 | f = (c & d) | (c & e) | (d & e); 232 | t = (b << 5) | (b >>> 27); 233 | a = t + f + a - 1894007588 + blocks[j + 4] << 0; 234 | c = (c << 30) | (c >>> 2); 235 | } 236 | 237 | for (; j < 80; j += 5) { 238 | f = b ^ c ^ d; 239 | t = (a << 5) | (a >>> 27); 240 | e = t + f + e - 899497514 + blocks[j] << 0; 241 | b = (b << 30) | (b >>> 2); 242 | 243 | f = a ^ b ^ c; 244 | t = (e << 5) | (e >>> 27); 245 | d = t + f + d - 899497514 + blocks[j + 1] << 0; 246 | a = (a << 30) | (a >>> 2); 247 | 248 | f = e ^ a ^ b; 249 | t = (d << 5) | (d >>> 27); 250 | c = t + f + c - 899497514 + blocks[j + 2] << 0; 251 | e = (e << 30) | (e >>> 2); 252 | 253 | f = d ^ e ^ a; 254 | t = (c << 5) | (c >>> 27); 255 | b = t + f + b - 899497514 + blocks[j + 3] << 0; 256 | d = (d << 30) | (d >>> 2); 257 | 258 | f = c ^ d ^ e; 259 | t = (b << 5) | (b >>> 27); 260 | a = t + f + a - 899497514 + blocks[j + 4] << 0; 261 | c = (c << 30) | (c >>> 2); 262 | } 263 | 264 | this.h0 = this.h0 + a << 0; 265 | this.h1 = this.h1 + b << 0; 266 | this.h2 = this.h2 + c << 0; 267 | this.h3 = this.h3 + d << 0; 268 | this.h4 = this.h4 + e << 0; 269 | }; 270 | 271 | hex() { 272 | this.finalize(); 273 | 274 | let h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4; 275 | 276 | return HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + 277 | HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + 278 | HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + 279 | HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + 280 | HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + 281 | HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + 282 | HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + 283 | HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + 284 | HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + 285 | HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + 286 | HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + 287 | HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + 288 | HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] + 289 | HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + 290 | HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + 291 | HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + 292 | HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] + 293 | HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] + 294 | HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] + 295 | HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F]; 296 | }; 297 | 298 | toString() { 299 | return this.hex(); 300 | }; 301 | 302 | digest() { 303 | this.finalize(); 304 | 305 | let h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4; 306 | 307 | return [ 308 | (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF, 309 | (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF, 310 | (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF, 311 | (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF, 312 | (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF 313 | ]; 314 | }; 315 | 316 | array() { 317 | return this.digest(); 318 | }; 319 | 320 | arrayBuffer() { 321 | this.finalize(); 322 | 323 | let buffer = new ArrayBuffer(20); 324 | let dataView = new DataView(buffer); 325 | dataView.setUint32(0, this.h0); 326 | dataView.setUint32(4, this.h1); 327 | dataView.setUint32(8, this.h2); 328 | dataView.setUint32(12, this.h3); 329 | dataView.setUint32(16, this.h4); 330 | return buffer; 331 | } 332 | } 333 | -------------------------------------------------------------------------------- /deno.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018 the Deno authors. All rights reserved. MIT license. 2 | 3 | /// 4 | /// 5 | 6 | declare module "deno" { 7 | /** Exit the Deno process with optional exit code. */ 8 | export function exit(exitCode?: number): never; 9 | /** Returns a snapshot of the environment variables at invocation. Mutating a 10 | * property in the object will set that variable in the environment for 11 | * the process. The environment object will only accept `string`s or `number`s 12 | * as values. 13 | * 14 | * import { env } from "deno"; 15 | * 16 | * const myEnv = env(); 17 | * console.log(myEnv.SHELL); 18 | * myEnv.TEST_VAR = "HELLO"; 19 | * const newEnv = env(); 20 | * console.log(myEnv.TEST_VAR == newEnv.TEST_VAR); 21 | */ 22 | export function env(): { 23 | [index: string]: string; 24 | }; 25 | /** 26 | * cwd() Return a string representing the current working directory. 27 | * If the current directory can be reached via multiple paths 28 | * (due to symbolic links), cwd() may return 29 | * any one of them. 30 | * throws NotFound exception if directory not available 31 | */ 32 | export function cwd(): string; 33 | /** 34 | * chdir() Change the current working directory to path. 35 | * throws NotFound exception if directory not available 36 | */ 37 | export function chdir(directory: string): void; 38 | export interface ReadResult { 39 | nread: number; 40 | eof: boolean; 41 | } 42 | export interface Reader { 43 | /** Reads up to p.byteLength bytes into `p`. It resolves to the number 44 | * of bytes read (`0` <= `n` <= `p.byteLength`) and any error encountered. 45 | * Even if `read()` returns `n` < `p.byteLength`, it may use all of `p` as 46 | * scratch space during the call. If some data is available but not 47 | * `p.byteLength` bytes, `read()` conventionally returns what is available 48 | * instead of waiting for more. 49 | * 50 | * When `read()` encounters an error or end-of-file condition after 51 | * successfully reading `n` > `0` bytes, it returns the number of bytes read. 52 | * It may return the (non-nil) error from the same call or return the error 53 | * (and `n` == `0`) from a subsequent call. An instance of this general case 54 | * is that a `Reader` returning a non-zero number of bytes at the end of the 55 | * input stream may return either `err` == `EOF` or `err` == `null`. The next 56 | * `read()` should return `0`, `EOF`. 57 | * 58 | * Callers should always process the `n` > `0` bytes returned before 59 | * considering the `EOF`. Doing so correctly handles I/O errors that happen 60 | * after reading some bytes and also both of the allowed `EOF` behaviors. 61 | * 62 | * Implementations of `read()` are discouraged from returning a zero byte 63 | * count with a `null` error, except when `p.byteLength` == `0`. Callers 64 | * should treat a return of `0` and `null` as indicating that nothing 65 | * happened; in particular it does not indicate `EOF`. 66 | * 67 | * Implementations must not retain `p`. 68 | */ 69 | read(p: Uint8Array): Promise; 70 | } 71 | export interface Writer { 72 | /** Writes `p.byteLength` bytes from `p` to the underlying data 73 | * stream. It resolves to the number of bytes written from `p` (`0` <= `n` <= 74 | * `p.byteLength`) and any error encountered that caused the write to stop 75 | * early. `write()` must return a non-null error if it returns `n` < 76 | * `p.byteLength`. write() must not modify the slice data, even temporarily. 77 | * 78 | * Implementations must not retain `p`. 79 | */ 80 | write(p: Uint8Array): Promise; 81 | } 82 | export interface Closer { 83 | close(): void; 84 | } 85 | export interface Seeker { 86 | /** Seek sets the offset for the next `read()` or `write()` to offset, 87 | * interpreted according to `whence`: `SeekStart` means relative to the start 88 | * of the file, `SeekCurrent` means relative to the current offset, and 89 | * `SeekEnd` means relative to the end. Seek returns the new offset relative 90 | * to the start of the file and an error, if any. 91 | * 92 | * Seeking to an offset before the start of the file is an error. Seeking to 93 | * any positive offset is legal, but the behavior of subsequent I/O operations 94 | * on the underlying object is implementation-dependent. 95 | */ 96 | seek(offset: number, whence: number): Promise; 97 | } 98 | export interface ReadCloser extends Reader, Closer {} 99 | export interface WriteCloser extends Writer, Closer {} 100 | export interface ReadSeeker extends Reader, Seeker {} 101 | export interface WriteSeeker extends Writer, Seeker {} 102 | export interface ReadWriteCloser extends Reader, Writer, Closer {} 103 | export interface ReadWriteSeeker extends Reader, Writer, Seeker {} 104 | /** Copies from `src` to `dst` until either `EOF` is reached on `src` 105 | * or an error occurs. It returns the number of bytes copied and the first 106 | * error encountered while copying, if any. 107 | * 108 | * Because `copy()` is defined to read from `src` until `EOF`, it does not 109 | * treat an `EOF` from `read()` as an error to be reported. 110 | */ 111 | export function copy(dst: Writer, src: Reader): Promise; 112 | /** Turns `r` into async iterator. 113 | * 114 | * for await (const chunk of readerIterator(reader)) { 115 | * console.log(chunk) 116 | * } 117 | */ 118 | export function toAsyncIterator(r: Reader): AsyncIterableIterator; 119 | /** The Deno abstraction for reading and writing files. */ 120 | export class File implements Reader, Writer, Closer { 121 | readonly rid: number; 122 | constructor(rid: number); 123 | write(p: Uint8Array): Promise; 124 | read(p: Uint8Array): Promise; 125 | close(): void; 126 | } 127 | /** An instance of `File` for stdin. */ 128 | export const stdin: File; 129 | /** An instance of `File` for stdout. */ 130 | export const stdout: File; 131 | /** An instance of `File` for stderr. */ 132 | export const stderr: File; 133 | export type OpenMode = 134 | | "r" 135 | /** Read-write. Start at beginning of file. */ 136 | | "r+" 137 | /** Write-only. Opens and truncates existing file or creates new one for 138 | * writing only. 139 | */ 140 | | "w" 141 | /** Read-write. Opens and truncates existing file or creates new one for 142 | * writing and reading. 143 | */ 144 | | "w+" 145 | /** Write-only. Opens existing file or creates new one. Each write appends 146 | * content to the end of file. 147 | */ 148 | | "a" 149 | /** Read-write. Behaves like "a" and allows to read from file. */ 150 | | "a+" 151 | /** Write-only. Exclusive create - creates new file only if one doesn't exist 152 | * already. 153 | */ 154 | | "x" 155 | /** Read-write. Behaves like `x` and allows to read from file. */ 156 | | "x+"; 157 | /** A factory function for creating instances of `File` associated with the 158 | * supplied file name. 159 | */ 160 | function create(filename: string): Promise; 161 | /** Open a file and return an instance of the `File` object. 162 | * 163 | * import * as deno from "deno"; 164 | * (async () => { 165 | * const file = await deno.open("/foo/bar.txt"); 166 | * })(); 167 | */ 168 | export function open(filename: string, mode?: OpenMode): Promise; 169 | /** Read from a file ID into an array buffer. 170 | * 171 | * Resolves with the `ReadResult` for the operation. 172 | */ 173 | export function read(rid: number, p: Uint8Array): Promise; 174 | /** Write to the file ID the contents of the array buffer. 175 | * 176 | * Resolves with the number of bytes written. 177 | */ 178 | export function write(rid: number, p: Uint8Array): Promise; 179 | /** Close the file ID. */ 180 | export function close(rid: number): void; 181 | /** A Buffer is a variable-sized buffer of bytes with read() and write() 182 | * methods. Based on https://golang.org/pkg/bytes/#Buffer 183 | */ 184 | export class Buffer implements Reader, Writer { 185 | private buf; 186 | private off; 187 | constructor(ab?: ArrayBuffer); 188 | /** bytes() returns a slice holding the unread portion of the buffer. 189 | * The slice is valid for use only until the next buffer modification (that 190 | * is, only until the next call to a method like read(), write(), reset(), or 191 | * truncate()). The slice aliases the buffer content at least until the next 192 | * buffer modification, so immediate changes to the slice will affect the 193 | * result of future reads. 194 | */ 195 | bytes(): Uint8Array; 196 | /** toString() returns the contents of the unread portion of the buffer 197 | * as a string. Warning - if multibyte characters are present when data is 198 | * flowing through the buffer, this method may result in incorrect strings 199 | * due to a character being split. 200 | */ 201 | toString(): string; 202 | /** empty() returns whether the unread portion of the buffer is empty. */ 203 | empty(): boolean; 204 | /** length is a getter that returns the number of bytes of the unread 205 | * portion of the buffer 206 | */ 207 | readonly length: number; 208 | /** Returns the capacity of the buffer's underlying byte slice, that is, 209 | * the total space allocated for the buffer's data. 210 | */ 211 | readonly capacity: number; 212 | /** truncate() discards all but the first n unread bytes from the buffer but 213 | * continues to use the same allocated storage. It throws if n is negative or 214 | * greater than the length of the buffer. 215 | */ 216 | truncate(n: number): void; 217 | /** reset() resets the buffer to be empty, but it retains the underlying 218 | * storage for use by future writes. reset() is the same as truncate(0) 219 | */ 220 | reset(): void; 221 | /** _tryGrowByReslice() is a version of grow for the fast-case 222 | * where the internal buffer only needs to be resliced. It returns the index 223 | * where bytes should be written and whether it succeeded. 224 | * It returns -1 if a reslice was not needed. 225 | */ 226 | private _tryGrowByReslice; 227 | private _reslice; 228 | /** read() reads the next len(p) bytes from the buffer or until the buffer 229 | * is drained. The return value n is the number of bytes read. If the 230 | * buffer has no data to return, eof in the response will be true. 231 | */ 232 | read(p: Uint8Array): Promise; 233 | write(p: Uint8Array): Promise; 234 | /** _grow() grows the buffer to guarantee space for n more bytes. 235 | * It returns the index where bytes should be written. 236 | * If the buffer can't grow it will throw with ErrTooLarge. 237 | */ 238 | private _grow; 239 | /** grow() grows the buffer's capacity, if necessary, to guarantee space for 240 | * another n bytes. After grow(n), at least n bytes can be written to the 241 | * buffer without another allocation. If n is negative, grow() will panic. If 242 | * the buffer can't grow it will throw ErrTooLarge. 243 | * Based on https://golang.org/pkg/bytes/#Buffer.Grow 244 | */ 245 | grow(n: number): void; 246 | /** readFrom() reads data from r until EOF and appends it to the buffer, 247 | * growing the buffer as needed. It returns the number of bytes read. If the 248 | * buffer becomes too large, readFrom will panic with ErrTooLarge. 249 | * Based on https://golang.org/pkg/bytes/#Buffer.ReadFrom 250 | */ 251 | readFrom(r: Reader): Promise; 252 | } 253 | /** Read `r` until EOF and return the content as `Uint8Array`. 254 | */ 255 | export function readAll(r: Reader): Promise; 256 | /** Creates a new directory with the specified path and permission 257 | * synchronously. 258 | * 259 | * import { mkdirSync } from "deno"; 260 | * mkdirSync("new_dir"); 261 | */ 262 | export function mkdirSync(path: string, mode?: number): void; 263 | /** Creates a new directory with the specified path and permission. 264 | * 265 | * import { mkdir } from "deno"; 266 | * await mkdir("new_dir"); 267 | */ 268 | export function mkdir(path: string, mode?: number): Promise; 269 | interface MakeTempDirOptions { 270 | dir?: string; 271 | prefix?: string; 272 | suffix?: string; 273 | } 274 | /** makeTempDirSync is the synchronous version of `makeTempDir`. 275 | * 276 | * import { makeTempDirSync } from "deno"; 277 | * const tempDirName0 = makeTempDirSync(); 278 | * const tempDirName1 = makeTempDirSync({ prefix: 'my_temp' }); 279 | */ 280 | export function makeTempDirSync(options?: MakeTempDirOptions): string; 281 | /** makeTempDir creates a new temporary directory in the directory `dir`, its 282 | * name beginning with `prefix` and ending with `suffix`. 283 | * It returns the full path to the newly created directory. 284 | * If `dir` is unspecified, tempDir uses the default directory for temporary 285 | * files. Multiple programs calling tempDir simultaneously will not choose the 286 | * same directory. It is the caller's responsibility to remove the directory 287 | * when no longer needed. 288 | * 289 | * import { makeTempDir } from "deno"; 290 | * const tempDirName0 = await makeTempDir(); 291 | * const tempDirName1 = await makeTempDir({ prefix: 'my_temp' }); 292 | */ 293 | export function makeTempDir(options?: MakeTempDirOptions): Promise; 294 | /** Changes the permission of a specific file/directory of specified path 295 | * synchronously. 296 | * 297 | * import { chmodSync } from "deno"; 298 | * chmodSync("/path/to/file", 0o666); 299 | */ 300 | export function chmodSync(path: string, mode: number): void; 301 | /** Changes the permission of a specific file/directory of specified path. 302 | * 303 | * import { chmod } from "deno"; 304 | * await chmod("/path/to/file", 0o666); 305 | */ 306 | export function chmod(path: string, mode: number): Promise; 307 | /** Removes the named file or (empty) directory synchronously. Would throw 308 | * error if permission denied, not found, or directory not empty. 309 | * 310 | * import { removeSync } from "deno"; 311 | * removeSync("/path/to/empty_dir/or/file"); 312 | */ 313 | export function removeSync(path: string): void; 314 | /** Removes the named file or (empty) directory. Would throw error if 315 | * permission denied, not found, or directory not empty. 316 | * 317 | * import { remove } from "deno"; 318 | * await remove("/path/to/empty_dir/or/file"); 319 | */ 320 | export function remove(path: string): Promise; 321 | /** Recursively removes the named file or directory synchronously. Would throw 322 | * error if permission denied or not found. 323 | * 324 | * import { removeAllSync } from "deno"; 325 | * removeAllSync("/path/to/dir/or/file"); 326 | */ 327 | export function removeAllSync(path: string): void; 328 | /** Recursively removes the named file or directory. Would throw error if 329 | * permission denied or not found. 330 | * 331 | * import { removeAll } from "deno"; 332 | * await removeAll("/path/to/dir/or/file"); 333 | */ 334 | export function removeAll(path: string): Promise; 335 | /** Synchronously renames (moves) `oldpath` to `newpath`. If `newpath` already 336 | * exists and is not a directory, `renameSync()` replaces it. OS-specific 337 | * restrictions may apply when `oldpath` and `newpath` are in different 338 | * directories. 339 | * 340 | * import { renameSync } from "deno"; 341 | * renameSync("old/path", "new/path"); 342 | */ 343 | export function renameSync(oldpath: string, newpath: string): void; 344 | /** Renames (moves) `oldpath` to `newpath`. If `newpath` already exists and is 345 | * not a directory, `rename()` replaces it. OS-specific restrictions may apply 346 | * when `oldpath` and `newpath` are in different directories. 347 | * 348 | * import { rename } from "deno"; 349 | * await rename("old/path", "new/path"); 350 | */ 351 | export function rename(oldpath: string, newpath: string): Promise; 352 | /** Read the entire contents of a file synchronously. 353 | * 354 | * import { readFileSync } from "deno"; 355 | * const decoder = new TextDecoder("utf-8"); 356 | * const data = readFileSync("hello.txt"); 357 | * console.log(decoder.decode(data)); 358 | */ 359 | export function readFileSync(filename: string): Uint8Array; 360 | /** Read the entire contents of a file. 361 | * 362 | * import { readFile } from "deno"; 363 | * const decoder = new TextDecoder("utf-8"); 364 | * const data = await readFile("hello.txt"); 365 | * console.log(decoder.decode(data)); 366 | */ 367 | export function readFile(filename: string): Promise; 368 | /** A FileInfo describes a file and is returned by `stat`, `lstat`, 369 | * `statSync`, `lstatSync`. 370 | */ 371 | export interface FileInfo { 372 | /** The size of the file, in bytes. */ 373 | len: number; 374 | /** The last modification time of the file. This corresponds to the `mtime` 375 | * field from `stat` on Unix and `ftLastWriteTime` on Windows. This may not 376 | * be available on all platforms. 377 | */ 378 | modified: number | null; 379 | /** The last access time of the file. This corresponds to the `atime` 380 | * field from `stat` on Unix and `ftLastAccessTime` on Windows. This may not 381 | * be available on all platforms. 382 | */ 383 | accessed: number | null; 384 | /** The last access time of the file. This corresponds to the `birthtime` 385 | * field from `stat` on Unix and `ftCreationTime` on Windows. This may not 386 | * be available on all platforms. 387 | */ 388 | created: number | null; 389 | /** The underlying raw st_mode bits that contain the standard Unix permissions 390 | * for this file/directory. TODO Match behavior with Go on windows for mode. 391 | */ 392 | mode: number | null; 393 | /** Returns the file or directory name. */ 394 | name: string | null; 395 | /** Returns the file or directory path. */ 396 | path: string | null; 397 | /** Returns whether this is info for a regular file. This result is mutually 398 | * exclusive to `FileInfo.isDirectory` and `FileInfo.isSymlink`. 399 | */ 400 | isFile(): boolean; 401 | /** Returns whether this is info for a regular directory. This result is 402 | * mutually exclusive to `FileInfo.isFile` and `FileInfo.isSymlink`. 403 | */ 404 | isDirectory(): boolean; 405 | /** Returns whether this is info for a symlink. This result is 406 | * mutually exclusive to `FileInfo.isFile` and `FileInfo.isDirectory`. 407 | */ 408 | isSymlink(): boolean; 409 | } 410 | /** Reads the directory given by path and returns a list of file info 411 | * synchronously. 412 | * 413 | * import { readDirSync } from "deno"; 414 | * const files = readDirSync("/"); 415 | */ 416 | export function readDirSync(path: string): FileInfo[]; 417 | /** Reads the directory given by path and returns a list of file info. 418 | * 419 | * import { readDir } from "deno"; 420 | * const files = await readDir("/"); 421 | */ 422 | export function readDir(path: string): Promise; 423 | /** Copies the contents of a file to another by name synchronously. 424 | * Creates a new file if target does not exists, and if target exists, 425 | * overwrites original content of the target file. 426 | * 427 | * It would also copy the permission of the original file 428 | * to the destination. 429 | * 430 | * import { copyFileSync } from "deno"; 431 | * copyFileSync("from.txt", "to.txt"); 432 | */ 433 | export function copyFileSync(from: string, to: string): void; 434 | /** Copies the contents of a file to another by name. 435 | * 436 | * Creates a new file if target does not exists, and if target exists, 437 | * overwrites original content of the target file. 438 | * 439 | * It would also copy the permission of the original file 440 | * to the destination. 441 | * 442 | * import { copyFile } from "deno"; 443 | * await copyFile("from.txt", "to.txt"); 444 | */ 445 | export function copyFile(from: string, to: string): Promise; 446 | /** Returns the destination of the named symbolic link synchronously. 447 | * 448 | * import { readlinkSync } from "deno"; 449 | * const targetPath = readlinkSync("symlink/path"); 450 | */ 451 | export function readlinkSync(name: string): string; 452 | /** Returns the destination of the named symbolic link. 453 | * 454 | * import { readlink } from "deno"; 455 | * const targetPath = await readlink("symlink/path"); 456 | */ 457 | export function readlink(name: string): Promise; 458 | /** Queries the file system for information on the path provided. If the given 459 | * path is a symlink information about the symlink will be returned. 460 | * 461 | * import { lstat } from "deno"; 462 | * const fileInfo = await lstat("hello.txt"); 463 | * assert(fileInfo.isFile()); 464 | */ 465 | export function lstat(filename: string): Promise; 466 | /** Queries the file system for information on the path provided synchronously. 467 | * If the given path is a symlink information about the symlink will be 468 | * returned. 469 | * 470 | * import { lstatSync } from "deno"; 471 | * const fileInfo = lstatSync("hello.txt"); 472 | * assert(fileInfo.isFile()); 473 | */ 474 | export function lstatSync(filename: string): FileInfo; 475 | /** Queries the file system for information on the path provided. `stat` Will 476 | * always follow symlinks. 477 | * 478 | * import { stat } from "deno"; 479 | * const fileInfo = await stat("hello.txt"); 480 | * assert(fileInfo.isFile()); 481 | */ 482 | export function stat(filename: string): Promise; 483 | /** Queries the file system for information on the path provided synchronously. 484 | * `statSync` Will always follow symlinks. 485 | * 486 | * import { statSync } from "deno"; 487 | * const fileInfo = statSync("hello.txt"); 488 | * assert(fileInfo.isFile()); 489 | */ 490 | export function statSync(filename: string): FileInfo; 491 | /** Synchronously creates `newname` as a symbolic link to `oldname`. The type 492 | * argument can be set to `dir` or `file` and is only available on Windows 493 | * (ignored on other platforms). 494 | * 495 | * import { symlinkSync } from "deno"; 496 | * symlinkSync("old/name", "new/name"); 497 | */ 498 | export function symlinkSync( 499 | oldname: string, 500 | newname: string, 501 | type?: string 502 | ): void; 503 | /** Creates `newname` as a symbolic link to `oldname`. The type argument can be 504 | * set to `dir` or `file` and is only available on Windows (ignored on other 505 | * platforms). 506 | * 507 | * import { symlink } from "deno"; 508 | * await symlink("old/name", "new/name"); 509 | */ 510 | export function symlink( 511 | oldname: string, 512 | newname: string, 513 | type?: string 514 | ): Promise; 515 | /** Write a new file, with given filename and data synchronously. 516 | * 517 | * import { writeFileSync } from "deno"; 518 | * 519 | * const encoder = new TextEncoder("utf-8"); 520 | * const data = encoder.encode("Hello world\n"); 521 | * writeFileSync("hello.txt", data); 522 | */ 523 | export function writeFileSync( 524 | filename: string, 525 | data: Uint8Array, 526 | perm?: number 527 | ): void; 528 | /** Write a new file, with given filename and data. 529 | * 530 | * import { writeFile } from "deno"; 531 | * 532 | * const encoder = new TextEncoder("utf-8"); 533 | * const data = encoder.encode("Hello world\n"); 534 | * await writeFile("hello.txt", data); 535 | */ 536 | export function writeFile( 537 | filename: string, 538 | data: Uint8Array, 539 | perm?: number 540 | ): Promise; 541 | export enum ErrorKind { 542 | NoError = 0, 543 | NotFound = 1, 544 | PermissionDenied = 2, 545 | ConnectionRefused = 3, 546 | ConnectionReset = 4, 547 | ConnectionAborted = 5, 548 | NotConnected = 6, 549 | AddrInUse = 7, 550 | AddrNotAvailable = 8, 551 | BrokenPipe = 9, 552 | AlreadyExists = 10, 553 | WouldBlock = 11, 554 | InvalidInput = 12, 555 | InvalidData = 13, 556 | TimedOut = 14, 557 | Interrupted = 15, 558 | WriteZero = 16, 559 | Other = 17, 560 | UnexpectedEof = 18, 561 | BadResource = 19, 562 | CommandFailed = 20, 563 | EmptyHost = 21, 564 | IdnaError = 22, 565 | InvalidPort = 23, 566 | InvalidIpv4Address = 24, 567 | InvalidIpv6Address = 25, 568 | InvalidDomainCharacter = 26, 569 | RelativeUrlWithoutBase = 27, 570 | RelativeUrlWithCannotBeABaseBase = 28, 571 | SetHostOnCannotBeABaseUrl = 29, 572 | Overflow = 30, 573 | HttpUser = 31, 574 | HttpClosed = 32, 575 | HttpCanceled = 33, 576 | HttpParse = 34, 577 | HttpOther = 35, 578 | TooLarge = 36, 579 | InvalidUri = 37 580 | } 581 | /** A Deno specific error. The `kind` property is set to a specific error code 582 | * which can be used to in application logic. 583 | * 584 | * import { DenoError, ErrorKind } from "deno"; 585 | * try { 586 | * somethingThatMightThrow(); 587 | * } catch (e) { 588 | * if (e instanceof DenoError && e.kind === ErrorKind.Overflow) { 589 | * console.error("Overflow error!"); 590 | * } 591 | * } 592 | */ 593 | export class DenoError extends Error { 594 | readonly kind: T; 595 | constructor(kind: T, msg: string); 596 | } 597 | type MessageCallback = (msg: Uint8Array) => void; 598 | type PromiseRejectEvent = 599 | | "RejectWithNoHandler" 600 | | "HandlerAddedAfterReject" 601 | | "ResolveAfterResolved" 602 | | "RejectAfterResolved"; 603 | interface Libdeno { 604 | recv(cb: MessageCallback): void; 605 | send(control: ArrayBufferView, data?: ArrayBufferView): null | Uint8Array; 606 | print(x: string, isErr?: boolean): void; 607 | shared: ArrayBuffer; 608 | setGlobalErrorHandler: ( 609 | handler: ( 610 | message: string, 611 | source: string, 612 | line: number, 613 | col: number, 614 | error: Error 615 | ) => void 616 | ) => void; 617 | setPromiseRejectHandler: ( 618 | handler: ( 619 | error: Error | string, 620 | event: PromiseRejectEvent, 621 | promise: Promise 622 | ) => void 623 | ) => void; 624 | setPromiseErrorExaminer: (handler: () => boolean) => void; 625 | } 626 | export const libdeno: Libdeno; 627 | export {}; 628 | interface Platform { 629 | /** The operating system CPU architecture. */ 630 | arch: "x64"; 631 | /** The operating system platform. */ 632 | os: "mac" | "win" | "linux"; 633 | } 634 | export const platform: Platform; 635 | /** Truncates or extends the specified file synchronously, updating the size of 636 | * this file to become size. 637 | * 638 | * import { truncateSync } from "deno"; 639 | * 640 | * truncateSync("hello.txt", 10); 641 | */ 642 | export function truncateSync(name: string, len?: number): void; 643 | /** 644 | * Truncates or extends the specified file, updating the size of this file to 645 | * become size. 646 | * 647 | * import { truncate } from "deno"; 648 | * 649 | * await truncate("hello.txt", 10); 650 | */ 651 | export function truncate(name: string, len?: number): Promise; 652 | type Network = "tcp"; 653 | type Addr = string; 654 | /** A Listener is a generic network listener for stream-oriented protocols. */ 655 | export interface Listener { 656 | /** Waits for and resolves to the next connection to the `Listener`. */ 657 | accept(): Promise; 658 | /** Close closes the listener. Any pending accept promises will be rejected 659 | * with errors. 660 | */ 661 | close(): void; 662 | /** Return the address of the `Listener`. */ 663 | addr(): Addr; 664 | } 665 | export interface Conn extends Reader, Writer, Closer { 666 | /** The local address of the connection. */ 667 | localAddr: string; 668 | /** The remote address of the connection. */ 669 | remoteAddr: string; 670 | /** Shuts down (`shutdown(2)`) the reading side of the TCP connection. Most 671 | * callers should just use `close()`. 672 | */ 673 | closeRead(): void; 674 | /** Shuts down (`shutdown(2)`) the writing side of the TCP connection. Most 675 | * callers should just use `close()`. 676 | */ 677 | closeWrite(): void; 678 | } 679 | /** Listen announces on the local network address. 680 | * 681 | * The network must be `tcp`, `tcp4`, `tcp6`, `unix` or `unixpacket`. 682 | * 683 | * For TCP networks, if the host in the address parameter is empty or a literal 684 | * unspecified IP address, `listen()` listens on all available unicast and 685 | * anycast IP addresses of the local system. To only use IPv4, use network 686 | * `tcp4`. The address can use a host name, but this is not recommended, 687 | * because it will create a listener for at most one of the host's IP 688 | * addresses. If the port in the address parameter is empty or `0`, as in 689 | * `127.0.0.1:` or `[::1]:0`, a port number is automatically chosen. The 690 | * `addr()` method of `Listener` can be used to discover the chosen port. 691 | * 692 | * See `dial()` for a description of the network and address parameters. 693 | */ 694 | export function listen(network: Network, address: string): Listener; 695 | /** Dial connects to the address on the named network. 696 | * 697 | * Supported networks are only `tcp` currently. 698 | * 699 | * TODO: `tcp4` (IPv4-only), `tcp6` (IPv6-only), `udp`, `udp4` (IPv4-only), 700 | * `udp6` (IPv6-only), `ip`, `ip4` (IPv4-only), `ip6` (IPv6-only), `unix`, 701 | * `unixgram` and `unixpacket`. 702 | * 703 | * For TCP and UDP networks, the address has the form `host:port`. The host must 704 | * be a literal IP address, or a host name that can be resolved to IP addresses. 705 | * The port must be a literal port number or a service name. If the host is a 706 | * literal IPv6 address it must be enclosed in square brackets, as in 707 | * `[2001:db8::1]:80` or `[fe80::1%zone]:80`. The zone specifies the scope of 708 | * the literal IPv6 address as defined in RFC 4007. The functions JoinHostPort 709 | * and SplitHostPort manipulate a pair of host and port in this form. When using 710 | * TCP, and the host resolves to multiple IP addresses, Dial will try each IP 711 | * address in order until one succeeds. 712 | * 713 | * Examples: 714 | * 715 | * dial("tcp", "golang.org:http") 716 | * dial("tcp", "192.0.2.1:http") 717 | * dial("tcp", "198.51.100.1:80") 718 | * dial("udp", "[2001:db8::1]:domain") 719 | * dial("udp", "[fe80::1%lo0]:53") 720 | * dial("tcp", ":80") 721 | */ 722 | export function dial(network: Network, address: string): Promise; 723 | /** **RESERVED** */ 724 | export function connect(network: Network, address: string): Promise; 725 | interface Metrics { 726 | opsDispatched: number; 727 | opsCompleted: number; 728 | bytesSentControl: number; 729 | bytesSentData: number; 730 | bytesReceived: number; 731 | } 732 | /** Receive metrics from the privileged side of Deno. */ 733 | export function metrics(): Metrics; 734 | export {}; 735 | type ResourceMap = { 736 | [rid: number]: string; 737 | }; 738 | /** Returns a map of open _file like_ resource ids along with their string 739 | * representation. 740 | */ 741 | export function resources(): ResourceMap; 742 | /** How to handle subsubprocess stdio. 743 | * 744 | * "inherit" The default if unspecified. The child inherits from the 745 | * corresponding parent descriptor. 746 | * 747 | * "piped" A new pipe should be arranged to connect the parent and child 748 | * subprocesses. 749 | * 750 | * "null" This stream will be ignored. This is the equivalent of attaching the 751 | * stream to /dev/null. 752 | */ 753 | type ProcessStdio = "inherit" | "piped" | "null"; 754 | export interface RunOptions { 755 | args: string[]; 756 | cwd?: string; 757 | stdout?: ProcessStdio; 758 | stderr?: ProcessStdio; 759 | stdin?: ProcessStdio; 760 | } 761 | export class Process { 762 | readonly rid: number; 763 | readonly pid: number; 764 | readonly stdin?: WriteCloser; 765 | readonly stdout?: ReadCloser; 766 | readonly stderr?: ReadCloser; 767 | status(): Promise; 768 | /** Buffer the stdout and return it as Uint8Array after EOF. 769 | * You must have set stdout to "piped" in when creating the process. 770 | * This calls close() on stdout after its done. 771 | */ 772 | output(): Promise; 773 | close(): void; 774 | } 775 | export interface ProcessStatus { 776 | success: boolean; 777 | code?: number; 778 | signal?: number; 779 | } 780 | export function run(opt: RunOptions): Process; 781 | type ConsoleOptions = Partial<{ 782 | showHidden: boolean; 783 | depth: number; 784 | colors: boolean; 785 | }>; 786 | /** TODO Do not expose this from "deno" namespace. */ 787 | export function stringifyArgs(args: any[], options?: ConsoleOptions): string; 788 | type PrintFunc = (x: string, isErr?: boolean) => void; 789 | /** TODO Do not expose this from "deno". */ 790 | export class Console { 791 | private printFunc; 792 | constructor(printFunc: PrintFunc); 793 | /** Writes the arguments to stdout */ 794 | log: (...args: any[]) => void; 795 | /** Writes the arguments to stdout */ 796 | debug: (...args: any[]) => void; 797 | /** Writes the arguments to stdout */ 798 | info: (...args: any[]) => void; 799 | /** Writes the properties of the supplied `obj` to stdout */ 800 | dir: ( 801 | obj: any, 802 | options?: Partial<{ 803 | showHidden: boolean; 804 | depth: number; 805 | colors: boolean; 806 | }> 807 | ) => void; 808 | /** Writes the arguments to stdout */ 809 | warn: (...args: any[]) => void; 810 | /** Writes the arguments to stdout */ 811 | error: (...args: any[]) => void; 812 | /** Writes an error message to stdout if the assertion is `false`. If the 813 | * assertion is `true`, nothing happens. 814 | * 815 | * ref: https://console.spec.whatwg.org/#assert 816 | */ 817 | assert: (condition?: boolean, ...args: any[]) => void; 818 | count: (label?: string) => void; 819 | countReset: (label?: string) => void; 820 | time: (label?: string) => void; 821 | timeLog: (label?: string, ...args: any[]) => void; 822 | timeEnd: (label?: string) => void; 823 | } 824 | /** 825 | * inspect() converts input into string that has the same format 826 | * as printed by console.log(...); 827 | */ 828 | export function inspect( 829 | value: any, // tslint:disable-line:no-any 830 | options?: ConsoleOptions 831 | ): string; 832 | export {}; 833 | /*! **************************************************************************** 834 | Copyright (c) Microsoft Corporation. All rights reserved. 835 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 836 | this file except in compliance with the License. You may obtain a copy of the 837 | License at http://www.apache.org/licenses/LICENSE-2.0 838 | 839 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 840 | ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 841 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 842 | MERCHANTABLITY OR NON-INFRINGEMENT. 843 | 844 | See the Apache Version 2.0 License for specific language governing permissions 845 | and limitations under the License. 846 | *******************************************************************************/ 847 | type BufferSource = ArrayBufferView | ArrayBuffer; 848 | type HeadersInit = Headers | Array<[string, string]> | Record; 849 | type URLSearchParamsInit = string | string[][] | Record; 850 | type BodyInit = 851 | | Blob 852 | | BufferSource 853 | | FormData 854 | | URLSearchParams 855 | | ReadableStream 856 | | string; 857 | type RequestInfo = Request | string; 858 | type ReferrerPolicy = 859 | | "" 860 | | "no-referrer" 861 | | "no-referrer-when-downgrade" 862 | | "origin-only" 863 | | "origin-when-cross-origin" 864 | | "unsafe-url"; 865 | type BlobPart = BufferSource | Blob | string; 866 | type FormDataEntryValue = DomFile | string; 867 | type EventListenerOrEventListenerObject = EventListener | EventListenerObject; 868 | interface DomIterable { 869 | keys(): IterableIterator; 870 | values(): IterableIterator; 871 | entries(): IterableIterator<[K, V]>; 872 | [Symbol.iterator](): IterableIterator<[K, V]>; 873 | forEach( 874 | callback: (value: V, key: K, parent: this) => void, 875 | thisArg?: any 876 | ): void; 877 | } 878 | interface Element {} 879 | interface HTMLFormElement {} 880 | type EndingType = "transparent" | "native"; 881 | interface BlobPropertyBag { 882 | type?: string; 883 | ending?: EndingType; 884 | } 885 | interface AbortSignalEventMap { 886 | abort: ProgressEvent; 887 | } 888 | interface EventTarget { 889 | addEventListener( 890 | type: string, 891 | listener: EventListenerOrEventListenerObject | null, 892 | options?: boolean | AddEventListenerOptions 893 | ): void; 894 | dispatchEvent(evt: Event): boolean; 895 | removeEventListener( 896 | type: string, 897 | listener?: EventListenerOrEventListenerObject | null, 898 | options?: EventListenerOptions | boolean 899 | ): void; 900 | } 901 | interface ProgressEventInit extends EventInit { 902 | lengthComputable?: boolean; 903 | loaded?: number; 904 | total?: number; 905 | } 906 | interface URLSearchParams { 907 | /** 908 | * Appends a specified key/value pair as a new search parameter. 909 | */ 910 | append(name: string, value: string): void; 911 | /** 912 | * Deletes the given search parameter, and its associated value, 913 | * from the list of all search parameters. 914 | */ 915 | delete(name: string): void; 916 | /** 917 | * Returns the first value associated to the given search parameter. 918 | */ 919 | get(name: string): string | null; 920 | /** 921 | * Returns all the values association with a given search parameter. 922 | */ 923 | getAll(name: string): string[]; 924 | /** 925 | * Returns a Boolean indicating if such a search parameter exists. 926 | */ 927 | has(name: string): boolean; 928 | /** 929 | * Sets the value associated to a given search parameter to the given value. 930 | * If there were several values, delete the others. 931 | */ 932 | set(name: string, value: string): void; 933 | /** 934 | * Sort all key/value pairs contained in this object in place 935 | * and return undefined. The sort order is according to Unicode 936 | * code points of the keys. 937 | */ 938 | sort(): void; 939 | /** 940 | * Returns a query string suitable for use in a URL. 941 | */ 942 | toString(): string; 943 | /** 944 | * Iterates over each name-value pair in the query 945 | * and invokes the given function. 946 | */ 947 | forEach( 948 | callbackfn: (value: string, key: string, parent: URLSearchParams) => void, 949 | thisArg?: any 950 | ): void; 951 | } 952 | interface EventListener { 953 | (evt: Event): void; 954 | } 955 | interface EventInit { 956 | bubbles?: boolean; 957 | cancelable?: boolean; 958 | composed?: boolean; 959 | } 960 | interface Event { 961 | readonly bubbles: boolean; 962 | cancelBubble: boolean; 963 | readonly cancelable: boolean; 964 | readonly composed: boolean; 965 | readonly currentTarget: EventTarget | null; 966 | readonly defaultPrevented: boolean; 967 | readonly eventPhase: number; 968 | readonly isTrusted: boolean; 969 | returnValue: boolean; 970 | readonly srcElement: Element | null; 971 | readonly target: EventTarget | null; 972 | readonly timeStamp: number; 973 | readonly type: string; 974 | deepPath(): EventTarget[]; 975 | initEvent(type: string, bubbles?: boolean, cancelable?: boolean): void; 976 | preventDefault(): void; 977 | stopImmediatePropagation(): void; 978 | stopPropagation(): void; 979 | readonly AT_TARGET: number; 980 | readonly BUBBLING_PHASE: number; 981 | readonly CAPTURING_PHASE: number; 982 | readonly NONE: number; 983 | } 984 | interface DomFile extends Blob { 985 | readonly lastModified: number; 986 | readonly name: string; 987 | } 988 | interface FilePropertyBag extends BlobPropertyBag { 989 | lastModified?: number; 990 | } 991 | interface ProgressEvent extends Event { 992 | readonly lengthComputable: boolean; 993 | readonly loaded: number; 994 | readonly total: number; 995 | } 996 | interface EventListenerOptions { 997 | capture?: boolean; 998 | } 999 | interface AddEventListenerOptions extends EventListenerOptions { 1000 | once?: boolean; 1001 | passive?: boolean; 1002 | } 1003 | interface AbortSignal extends EventTarget { 1004 | readonly aborted: boolean; 1005 | onabort: ((this: AbortSignal, ev: ProgressEvent) => any) | null; 1006 | addEventListener( 1007 | type: K, 1008 | listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, 1009 | options?: boolean | AddEventListenerOptions 1010 | ): void; 1011 | addEventListener( 1012 | type: string, 1013 | listener: EventListenerOrEventListenerObject, 1014 | options?: boolean | AddEventListenerOptions 1015 | ): void; 1016 | removeEventListener( 1017 | type: K, 1018 | listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, 1019 | options?: boolean | EventListenerOptions 1020 | ): void; 1021 | removeEventListener( 1022 | type: string, 1023 | listener: EventListenerOrEventListenerObject, 1024 | options?: boolean | EventListenerOptions 1025 | ): void; 1026 | } 1027 | interface ReadableStream { 1028 | readonly locked: boolean; 1029 | cancel(): Promise; 1030 | getReader(): ReadableStreamReader; 1031 | } 1032 | interface EventListenerObject { 1033 | handleEvent(evt: Event): void; 1034 | } 1035 | interface ReadableStreamReader { 1036 | cancel(): Promise; 1037 | read(): Promise; 1038 | releaseLock(): void; 1039 | } 1040 | interface FormData extends DomIterable { 1041 | append(name: string, value: string | Blob, fileName?: string): void; 1042 | delete(name: string): void; 1043 | get(name: string): FormDataEntryValue | null; 1044 | getAll(name: string): FormDataEntryValue[]; 1045 | has(name: string): boolean; 1046 | set(name: string, value: string | Blob, fileName?: string): void; 1047 | } 1048 | interface FormDataConstructor { 1049 | new (): FormData; 1050 | prototype: FormData; 1051 | } 1052 | /** A blob object represents a file-like object of immutable, raw data. */ 1053 | interface Blob { 1054 | /** The size, in bytes, of the data contained in the `Blob` object. */ 1055 | readonly size: number; 1056 | /** A string indicating the media type of the data contained in the `Blob`. 1057 | * If the type is unknown, this string is empty. 1058 | */ 1059 | readonly type: string; 1060 | /** Returns a new `Blob` object containing the data in the specified range of 1061 | * bytes of the source `Blob`. 1062 | */ 1063 | slice(start?: number, end?: number, contentType?: string): Blob; 1064 | } 1065 | interface Body { 1066 | /** A simple getter used to expose a `ReadableStream` of the body contents. */ 1067 | readonly body: ReadableStream | null; 1068 | /** Stores a `Boolean` that declares whether the body has been used in a 1069 | * response yet. 1070 | */ 1071 | readonly bodyUsed: boolean; 1072 | /** Takes a `Response` stream and reads it to completion. It returns a promise 1073 | * that resolves with an `ArrayBuffer`. 1074 | */ 1075 | arrayBuffer(): Promise; 1076 | /** Takes a `Response` stream and reads it to completion. It returns a promise 1077 | * that resolves with a `Blob`. 1078 | */ 1079 | blob(): Promise; 1080 | /** Takes a `Response` stream and reads it to completion. It returns a promise 1081 | * that resolves with a `FormData` object. 1082 | */ 1083 | formData(): Promise; 1084 | /** Takes a `Response` stream and reads it to completion. It returns a promise 1085 | * that resolves with the result of parsing the body text as JSON. 1086 | */ 1087 | json(): Promise; 1088 | /** Takes a `Response` stream and reads it to completion. It returns a promise 1089 | * that resolves with a `USVString` (text). 1090 | */ 1091 | text(): Promise; 1092 | } 1093 | interface Headers extends DomIterable { 1094 | /** Appends a new value onto an existing header inside a `Headers` object, or 1095 | * adds the header if it does not already exist. 1096 | */ 1097 | append(name: string, value: string): void; 1098 | /** Deletes a header from a `Headers` object. */ 1099 | delete(name: string): void; 1100 | /** Returns an iterator allowing to go through all key/value pairs 1101 | * contained in this Headers object. The both the key and value of each pairs 1102 | * are ByteString objects. 1103 | */ 1104 | entries(): IterableIterator<[string, string]>; 1105 | /** Returns a `ByteString` sequence of all the values of a header within a 1106 | * `Headers` object with a given name. 1107 | */ 1108 | get(name: string): string | null; 1109 | /** Returns a boolean stating whether a `Headers` object contains a certain 1110 | * header. 1111 | */ 1112 | has(name: string): boolean; 1113 | /** Returns an iterator allowing to go through all keys contained in 1114 | * this Headers object. The keys are ByteString objects. 1115 | */ 1116 | keys(): IterableIterator; 1117 | /** Sets a new value for an existing header inside a Headers object, or adds 1118 | * the header if it does not already exist. 1119 | */ 1120 | set(name: string, value: string): void; 1121 | /** Returns an iterator allowing to go through all values contained in 1122 | * this Headers object. The values are ByteString objects. 1123 | */ 1124 | values(): IterableIterator; 1125 | forEach( 1126 | callbackfn: (value: string, key: string, parent: this) => void, 1127 | thisArg?: any 1128 | ): void; 1129 | /** The Symbol.iterator well-known symbol specifies the default 1130 | * iterator for this Headers object 1131 | */ 1132 | [Symbol.iterator](): IterableIterator<[string, string]>; 1133 | } 1134 | interface HeadersConstructor { 1135 | new (init?: HeadersInit): Headers; 1136 | prototype: Headers; 1137 | } 1138 | type RequestCache = 1139 | | "default" 1140 | | "no-store" 1141 | | "reload" 1142 | | "no-cache" 1143 | | "force-cache" 1144 | | "only-if-cached"; 1145 | type RequestCredentials = "omit" | "same-origin" | "include"; 1146 | type RequestDestination = 1147 | | "" 1148 | | "audio" 1149 | | "audioworklet" 1150 | | "document" 1151 | | "embed" 1152 | | "font" 1153 | | "image" 1154 | | "manifest" 1155 | | "object" 1156 | | "paintworklet" 1157 | | "report" 1158 | | "script" 1159 | | "sharedworker" 1160 | | "style" 1161 | | "track" 1162 | | "video" 1163 | | "worker" 1164 | | "xslt"; 1165 | type RequestMode = "navigate" | "same-origin" | "no-cors" | "cors"; 1166 | type RequestRedirect = "follow" | "error" | "manual"; 1167 | type ResponseType = 1168 | | "basic" 1169 | | "cors" 1170 | | "default" 1171 | | "error" 1172 | | "opaque" 1173 | | "opaqueredirect"; 1174 | interface RequestInit { 1175 | body?: BodyInit | null; 1176 | cache?: RequestCache; 1177 | credentials?: RequestCredentials; 1178 | headers?: HeadersInit; 1179 | integrity?: string; 1180 | keepalive?: boolean; 1181 | method?: string; 1182 | mode?: RequestMode; 1183 | redirect?: RequestRedirect; 1184 | referrer?: string; 1185 | referrerPolicy?: ReferrerPolicy; 1186 | signal?: AbortSignal | null; 1187 | window?: any; 1188 | } 1189 | interface ResponseInit { 1190 | headers?: HeadersInit; 1191 | status?: number; 1192 | statusText?: string; 1193 | } 1194 | interface Request extends Body { 1195 | /** Returns the cache mode associated with request, which is a string 1196 | * indicating how the the request will interact with the browser's cache when 1197 | * fetching. 1198 | */ 1199 | readonly cache: RequestCache; 1200 | /** Returns the credentials mode associated with request, which is a string 1201 | * indicating whether credentials will be sent with the request always, never, 1202 | * or only when sent to a same-origin URL. 1203 | */ 1204 | readonly credentials: RequestCredentials; 1205 | /** Returns the kind of resource requested by request, (e.g., `document` or 1206 | * `script`). 1207 | */ 1208 | readonly destination: RequestDestination; 1209 | /** Returns a Headers object consisting of the headers associated with 1210 | * request. 1211 | * 1212 | * Note that headers added in the network layer by the user agent 1213 | * will not be accounted for in this object, (e.g., the `Host` header). 1214 | */ 1215 | readonly headers: Headers; 1216 | /** Returns request's subresource integrity metadata, which is a cryptographic 1217 | * hash of the resource being fetched. Its value consists of multiple hashes 1218 | * separated by whitespace. [SRI] 1219 | */ 1220 | readonly integrity: string; 1221 | /** Returns a boolean indicating whether or not request is for a history 1222 | * navigation (a.k.a. back-forward navigation). 1223 | */ 1224 | readonly isHistoryNavigation: boolean; 1225 | /** Returns a boolean indicating whether or not request is for a reload 1226 | * navigation. 1227 | */ 1228 | readonly isReloadNavigation: boolean; 1229 | /** Returns a boolean indicating whether or not request can outlive the global 1230 | * in which it was created. 1231 | */ 1232 | readonly keepalive: boolean; 1233 | /** Returns request's HTTP method, which is `GET` by default. */ 1234 | readonly method: string; 1235 | /** Returns the mode associated with request, which is a string indicating 1236 | * whether the request will use CORS, or will be restricted to same-origin 1237 | * URLs. 1238 | */ 1239 | readonly mode: RequestMode; 1240 | /** Returns the redirect mode associated with request, which is a string 1241 | * indicating how redirects for the request will be handled during fetching. 1242 | * 1243 | * A request will follow redirects by default. 1244 | */ 1245 | readonly redirect: RequestRedirect; 1246 | /** Returns the referrer of request. Its value can be a same-origin URL if 1247 | * explicitly set in init, the empty string to indicate no referrer, and 1248 | * `about:client` when defaulting to the global's default. 1249 | * 1250 | * This is used during fetching to determine the value of the `Referer` 1251 | * header of the request being made. 1252 | */ 1253 | readonly referrer: string; 1254 | /** Returns the referrer policy associated with request. This is used during 1255 | * fetching to compute the value of the request's referrer. 1256 | */ 1257 | readonly referrerPolicy: ReferrerPolicy; 1258 | /** Returns the signal associated with request, which is an AbortSignal object 1259 | * indicating whether or not request has been aborted, and its abort event 1260 | * handler. 1261 | */ 1262 | readonly signal: AbortSignal; 1263 | /** Returns the URL of request as a string. */ 1264 | readonly url: string; 1265 | clone(): Request; 1266 | } 1267 | interface Response extends Body { 1268 | /** Contains the `Headers` object associated with the response. */ 1269 | readonly headers: Headers; 1270 | /** Contains a boolean stating whether the response was successful (status in 1271 | * the range 200-299) or not. 1272 | */ 1273 | readonly ok: boolean; 1274 | /** Indicates whether or not the response is the result of a redirect; that 1275 | * is, its URL list has more than one entry. 1276 | */ 1277 | readonly redirected: boolean; 1278 | /** Contains the status code of the response (e.g., `200` for a success). */ 1279 | readonly status: number; 1280 | /** Contains the status message corresponding to the status code (e.g., `OK` 1281 | * for `200`). 1282 | */ 1283 | readonly statusText: string; 1284 | readonly trailer: Promise; 1285 | /** Contains the type of the response (e.g., `basic`, `cors`). */ 1286 | readonly type: ResponseType; 1287 | /** Contains the URL of the response. */ 1288 | readonly url: string; 1289 | /** Creates a clone of a `Response` object. */ 1290 | clone(): Response; 1291 | } 1292 | export {}; 1293 | type Constructor = new (...args: any[]) => T; 1294 | /** Mixes in a DOM iterable methods into a base class, assumes that there is 1295 | * a private data iterable that is part of the base class, located at 1296 | * `[dataSymbol]`. 1297 | * TODO Don't expose DomIterableMixin from "deno" namespace. 1298 | */ 1299 | export function DomIterableMixin( 1300 | Base: TBase, 1301 | dataSymbol: symbol 1302 | ): TBase & Constructor>; 1303 | export {}; 1304 | type TypedArray = Uint8Array | Float32Array | Int32Array; 1305 | interface CallSite { 1306 | /** Value of `this` */ 1307 | getThis(): any; 1308 | /** Type of `this` as a string. 1309 | * 1310 | * This is the name of the function stored in the constructor field of 1311 | * `this`, if available. Otherwise the object's `[[Class]]` internal 1312 | * property. 1313 | */ 1314 | getTypeName(): string | null; 1315 | /** Current function. */ 1316 | getFunction(): Function | undefined; 1317 | /** Name of the current function, typically its name property. 1318 | * 1319 | * If a name property is not available an attempt will be made to try 1320 | * to infer a name from the function's context. 1321 | */ 1322 | getFunctionName(): string | null; 1323 | /** Name of the property (of `this` or one of its prototypes) that holds 1324 | * the current function. 1325 | */ 1326 | getMethodName(): string | null; 1327 | /** Name of the script (if this function was defined in a script). */ 1328 | getFileName(): string | null; 1329 | /** Get the script name or source URL for the source map. */ 1330 | getScriptNameOrSourceURL(): string; 1331 | /** Current line number (if this function was defined in a script). */ 1332 | getLineNumber(): number | null; 1333 | /** Current column number (if this function was defined in a script). */ 1334 | getColumnNumber(): number | null; 1335 | /** A call site object representing the location where eval was called (if 1336 | * this function was created using a call to `eval`) 1337 | */ 1338 | getEvalOrigin(): string | undefined; 1339 | /** Is this a top level invocation, that is, is `this` the global object? */ 1340 | isToplevel(): boolean; 1341 | /** Does this call take place in code defined by a call to `eval`? */ 1342 | isEval(): boolean; 1343 | /** Is this call in native V8 code? */ 1344 | isNative(): boolean; 1345 | /** Is this a constructor call? */ 1346 | isConstructor(): boolean; 1347 | } 1348 | interface StartOfSourceMap { 1349 | file?: string; 1350 | sourceRoot?: string; 1351 | } 1352 | interface RawSourceMap extends StartOfSourceMap { 1353 | version: string; 1354 | sources: string[]; 1355 | names: string[]; 1356 | sourcesContent?: string[]; 1357 | mappings: string; 1358 | } 1359 | global { 1360 | interface ErrorConstructor { 1361 | /** Create `.stack` property on a target object */ 1362 | captureStackTrace(targetObject: object, constructorOpt?: Function): void; 1363 | /** 1364 | * Optional override for formatting stack traces 1365 | * 1366 | * @see https://github.com/v8/v8/wiki/Stack%20Trace%20API#customizing-stack-traces 1367 | */ 1368 | prepareStackTrace?: (err: Error, stackTraces: CallSite[]) => any; 1369 | stackTraceLimit: number; 1370 | } 1371 | } 1372 | interface Deferred { 1373 | promise: Promise; 1374 | resolve: Function; 1375 | reject: Function; 1376 | } 1377 | /** Create a wrapper around a promise that could be resolved externally. 1378 | * TODO Do not expose this from "deno" namespace. 1379 | */ 1380 | export function deferred(): Deferred; 1381 | function isTypedArray(x: unknown): x is TypedArray; 1382 | export const args: string[]; 1383 | } 1384 | 1385 | declare interface Window { 1386 | window: Window; 1387 | atob: typeof textEncoding.atob; 1388 | btoa: typeof textEncoding.btoa; 1389 | fetch: typeof fetchTypes.fetch; 1390 | clearTimeout: typeof timers.clearTimer; 1391 | clearInterval: typeof timers.clearTimer; 1392 | console: consoleTypes.Console; 1393 | setTimeout: typeof timers.setTimeout; 1394 | setInterval: typeof timers.setInterval; 1395 | Blob: typeof blob.DenoBlob; 1396 | URL: typeof url.URL; 1397 | URLSearchParams: typeof urlSearchParams.URLSearchParams; 1398 | Headers: domTypes.HeadersConstructor; 1399 | FormData: domTypes.FormDataConstructor; 1400 | TextEncoder: typeof textEncoding.TextEncoder; 1401 | TextDecoder: typeof textEncoding.TextDecoder; 1402 | } 1403 | 1404 | declare const window: Window; 1405 | declare const atob: typeof textEncoding.atob; 1406 | declare const btoa: typeof textEncoding.btoa; 1407 | declare const fetch: typeof fetchTypes.fetch; 1408 | declare const clearTimeout: typeof timers.clearTimer; 1409 | declare const clearInterval: typeof timers.clearTimer; 1410 | declare const console: consoleTypes.Console; 1411 | declare const setTimeout: typeof timers.setTimeout; 1412 | declare const setInterval: typeof timers.setInterval; 1413 | declare const Blob: typeof blob.DenoBlob; 1414 | declare const URL: typeof url.URL; 1415 | declare const URLSearchParams: typeof urlSearchParams.URLSearchParams; 1416 | declare const Headers: domTypes.HeadersConstructor; 1417 | declare const FormData: domTypes.FormDataConstructor; 1418 | declare const TextEncoder: typeof textEncoding.TextEncoder; 1419 | declare const TextDecoder: typeof textEncoding.TextDecoder; 1420 | 1421 | declare type Blob = blob.DenoBlob; 1422 | declare type URL = url.URL; 1423 | declare type URLSearchParams = urlSearchParams.URLSearchParams; 1424 | declare type Headers = domTypes.Headers; 1425 | declare type FormData = domTypes.FormData; 1426 | declare type TextEncoder = textEncoding.TextEncoder; 1427 | declare type TextDecoder = textEncoding.TextDecoder; 1428 | 1429 | declare namespace domTypes { 1430 | type BufferSource = ArrayBufferView | ArrayBuffer; 1431 | type HeadersInit = Headers | Array<[string, string]> | Record; 1432 | type URLSearchParamsInit = string | string[][] | Record; 1433 | type BodyInit = 1434 | | Blob 1435 | | BufferSource 1436 | | FormData 1437 | | URLSearchParams 1438 | | ReadableStream 1439 | | string; 1440 | type RequestInfo = Request | string; 1441 | type ReferrerPolicy = 1442 | | "" 1443 | | "no-referrer" 1444 | | "no-referrer-when-downgrade" 1445 | | "origin-only" 1446 | | "origin-when-cross-origin" 1447 | | "unsafe-url"; 1448 | type BlobPart = BufferSource | Blob | string; 1449 | type FormDataEntryValue = DomFile | string; 1450 | type EventListenerOrEventListenerObject = EventListener | EventListenerObject; 1451 | interface DomIterable { 1452 | keys(): IterableIterator; 1453 | values(): IterableIterator; 1454 | entries(): IterableIterator<[K, V]>; 1455 | [Symbol.iterator](): IterableIterator<[K, V]>; 1456 | forEach( 1457 | callback: (value: V, key: K, parent: this) => void, 1458 | thisArg?: any 1459 | ): void; 1460 | } 1461 | interface Element {} 1462 | interface HTMLFormElement {} 1463 | type EndingType = "transparent" | "native"; 1464 | interface BlobPropertyBag { 1465 | type?: string; 1466 | ending?: EndingType; 1467 | } 1468 | interface AbortSignalEventMap { 1469 | abort: ProgressEvent; 1470 | } 1471 | interface EventTarget { 1472 | addEventListener( 1473 | type: string, 1474 | listener: EventListenerOrEventListenerObject | null, 1475 | options?: boolean | AddEventListenerOptions 1476 | ): void; 1477 | dispatchEvent(evt: Event): boolean; 1478 | removeEventListener( 1479 | type: string, 1480 | listener?: EventListenerOrEventListenerObject | null, 1481 | options?: EventListenerOptions | boolean 1482 | ): void; 1483 | } 1484 | interface ProgressEventInit extends EventInit { 1485 | lengthComputable?: boolean; 1486 | loaded?: number; 1487 | total?: number; 1488 | } 1489 | interface URLSearchParams { 1490 | /** 1491 | * Appends a specified key/value pair as a new search parameter. 1492 | */ 1493 | append(name: string, value: string): void; 1494 | /** 1495 | * Deletes the given search parameter, and its associated value, 1496 | * from the list of all search parameters. 1497 | */ 1498 | delete(name: string): void; 1499 | /** 1500 | * Returns the first value associated to the given search parameter. 1501 | */ 1502 | get(name: string): string | null; 1503 | /** 1504 | * Returns all the values association with a given search parameter. 1505 | */ 1506 | getAll(name: string): string[]; 1507 | /** 1508 | * Returns a Boolean indicating if such a search parameter exists. 1509 | */ 1510 | has(name: string): boolean; 1511 | /** 1512 | * Sets the value associated to a given search parameter to the given value. 1513 | * If there were several values, delete the others. 1514 | */ 1515 | set(name: string, value: string): void; 1516 | /** 1517 | * Sort all key/value pairs contained in this object in place 1518 | * and return undefined. The sort order is according to Unicode 1519 | * code points of the keys. 1520 | */ 1521 | sort(): void; 1522 | /** 1523 | * Returns a query string suitable for use in a URL. 1524 | */ 1525 | toString(): string; 1526 | /** 1527 | * Iterates over each name-value pair in the query 1528 | * and invokes the given function. 1529 | */ 1530 | forEach( 1531 | callbackfn: (value: string, key: string, parent: URLSearchParams) => void, 1532 | thisArg?: any 1533 | ): void; 1534 | } 1535 | interface EventListener { 1536 | (evt: Event): void; 1537 | } 1538 | interface EventInit { 1539 | bubbles?: boolean; 1540 | cancelable?: boolean; 1541 | composed?: boolean; 1542 | } 1543 | interface Event { 1544 | readonly bubbles: boolean; 1545 | cancelBubble: boolean; 1546 | readonly cancelable: boolean; 1547 | readonly composed: boolean; 1548 | readonly currentTarget: EventTarget | null; 1549 | readonly defaultPrevented: boolean; 1550 | readonly eventPhase: number; 1551 | readonly isTrusted: boolean; 1552 | returnValue: boolean; 1553 | readonly srcElement: Element | null; 1554 | readonly target: EventTarget | null; 1555 | readonly timeStamp: number; 1556 | readonly type: string; 1557 | deepPath(): EventTarget[]; 1558 | initEvent(type: string, bubbles?: boolean, cancelable?: boolean): void; 1559 | preventDefault(): void; 1560 | stopImmediatePropagation(): void; 1561 | stopPropagation(): void; 1562 | readonly AT_TARGET: number; 1563 | readonly BUBBLING_PHASE: number; 1564 | readonly CAPTURING_PHASE: number; 1565 | readonly NONE: number; 1566 | } 1567 | interface DomFile extends Blob { 1568 | readonly lastModified: number; 1569 | readonly name: string; 1570 | } 1571 | interface FilePropertyBag extends BlobPropertyBag { 1572 | lastModified?: number; 1573 | } 1574 | interface ProgressEvent extends Event { 1575 | readonly lengthComputable: boolean; 1576 | readonly loaded: number; 1577 | readonly total: number; 1578 | } 1579 | interface EventListenerOptions { 1580 | capture?: boolean; 1581 | } 1582 | interface AddEventListenerOptions extends EventListenerOptions { 1583 | once?: boolean; 1584 | passive?: boolean; 1585 | } 1586 | interface AbortSignal extends EventTarget { 1587 | readonly aborted: boolean; 1588 | onabort: ((this: AbortSignal, ev: ProgressEvent) => any) | null; 1589 | addEventListener( 1590 | type: K, 1591 | listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, 1592 | options?: boolean | AddEventListenerOptions 1593 | ): void; 1594 | addEventListener( 1595 | type: string, 1596 | listener: EventListenerOrEventListenerObject, 1597 | options?: boolean | AddEventListenerOptions 1598 | ): void; 1599 | removeEventListener( 1600 | type: K, 1601 | listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, 1602 | options?: boolean | EventListenerOptions 1603 | ): void; 1604 | removeEventListener( 1605 | type: string, 1606 | listener: EventListenerOrEventListenerObject, 1607 | options?: boolean | EventListenerOptions 1608 | ): void; 1609 | } 1610 | interface ReadableStream { 1611 | readonly locked: boolean; 1612 | cancel(): Promise; 1613 | getReader(): ReadableStreamReader; 1614 | } 1615 | interface EventListenerObject { 1616 | handleEvent(evt: Event): void; 1617 | } 1618 | interface ReadableStreamReader { 1619 | cancel(): Promise; 1620 | read(): Promise; 1621 | releaseLock(): void; 1622 | } 1623 | interface FormData extends DomIterable { 1624 | append(name: string, value: string | Blob, fileName?: string): void; 1625 | delete(name: string): void; 1626 | get(name: string): FormDataEntryValue | null; 1627 | getAll(name: string): FormDataEntryValue[]; 1628 | has(name: string): boolean; 1629 | set(name: string, value: string | Blob, fileName?: string): void; 1630 | } 1631 | interface FormDataConstructor { 1632 | new (): FormData; 1633 | prototype: FormData; 1634 | } 1635 | /** A blob object represents a file-like object of immutable, raw data. */ 1636 | interface Blob { 1637 | /** The size, in bytes, of the data contained in the `Blob` object. */ 1638 | readonly size: number; 1639 | /** A string indicating the media type of the data contained in the `Blob`. 1640 | * If the type is unknown, this string is empty. 1641 | */ 1642 | readonly type: string; 1643 | /** Returns a new `Blob` object containing the data in the specified range of 1644 | * bytes of the source `Blob`. 1645 | */ 1646 | slice(start?: number, end?: number, contentType?: string): Blob; 1647 | } 1648 | interface Body { 1649 | /** A simple getter used to expose a `ReadableStream` of the body contents. */ 1650 | readonly body: ReadableStream | null; 1651 | /** Stores a `Boolean` that declares whether the body has been used in a 1652 | * response yet. 1653 | */ 1654 | readonly bodyUsed: boolean; 1655 | /** Takes a `Response` stream and reads it to completion. It returns a promise 1656 | * that resolves with an `ArrayBuffer`. 1657 | */ 1658 | arrayBuffer(): Promise; 1659 | /** Takes a `Response` stream and reads it to completion. It returns a promise 1660 | * that resolves with a `Blob`. 1661 | */ 1662 | blob(): Promise; 1663 | /** Takes a `Response` stream and reads it to completion. It returns a promise 1664 | * that resolves with a `FormData` object. 1665 | */ 1666 | formData(): Promise; 1667 | /** Takes a `Response` stream and reads it to completion. It returns a promise 1668 | * that resolves with the result of parsing the body text as JSON. 1669 | */ 1670 | json(): Promise; 1671 | /** Takes a `Response` stream and reads it to completion. It returns a promise 1672 | * that resolves with a `USVString` (text). 1673 | */ 1674 | text(): Promise; 1675 | } 1676 | interface Headers extends DomIterable { 1677 | /** Appends a new value onto an existing header inside a `Headers` object, or 1678 | * adds the header if it does not already exist. 1679 | */ 1680 | append(name: string, value: string): void; 1681 | /** Deletes a header from a `Headers` object. */ 1682 | delete(name: string): void; 1683 | /** Returns an iterator allowing to go through all key/value pairs 1684 | * contained in this Headers object. The both the key and value of each pairs 1685 | * are ByteString objects. 1686 | */ 1687 | entries(): IterableIterator<[string, string]>; 1688 | /** Returns a `ByteString` sequence of all the values of a header within a 1689 | * `Headers` object with a given name. 1690 | */ 1691 | get(name: string): string | null; 1692 | /** Returns a boolean stating whether a `Headers` object contains a certain 1693 | * header. 1694 | */ 1695 | has(name: string): boolean; 1696 | /** Returns an iterator allowing to go through all keys contained in 1697 | * this Headers object. The keys are ByteString objects. 1698 | */ 1699 | keys(): IterableIterator; 1700 | /** Sets a new value for an existing header inside a Headers object, or adds 1701 | * the header if it does not already exist. 1702 | */ 1703 | set(name: string, value: string): void; 1704 | /** Returns an iterator allowing to go through all values contained in 1705 | * this Headers object. The values are ByteString objects. 1706 | */ 1707 | values(): IterableIterator; 1708 | forEach( 1709 | callbackfn: (value: string, key: string, parent: this) => void, 1710 | thisArg?: any 1711 | ): void; 1712 | /** The Symbol.iterator well-known symbol specifies the default 1713 | * iterator for this Headers object 1714 | */ 1715 | [Symbol.iterator](): IterableIterator<[string, string]>; 1716 | } 1717 | interface HeadersConstructor { 1718 | new (init?: HeadersInit): Headers; 1719 | prototype: Headers; 1720 | } 1721 | type RequestCache = 1722 | | "default" 1723 | | "no-store" 1724 | | "reload" 1725 | | "no-cache" 1726 | | "force-cache" 1727 | | "only-if-cached"; 1728 | type RequestCredentials = "omit" | "same-origin" | "include"; 1729 | type RequestDestination = 1730 | | "" 1731 | | "audio" 1732 | | "audioworklet" 1733 | | "document" 1734 | | "embed" 1735 | | "font" 1736 | | "image" 1737 | | "manifest" 1738 | | "object" 1739 | | "paintworklet" 1740 | | "report" 1741 | | "script" 1742 | | "sharedworker" 1743 | | "style" 1744 | | "track" 1745 | | "video" 1746 | | "worker" 1747 | | "xslt"; 1748 | type RequestMode = "navigate" | "same-origin" | "no-cors" | "cors"; 1749 | type RequestRedirect = "follow" | "error" | "manual"; 1750 | type ResponseType = 1751 | | "basic" 1752 | | "cors" 1753 | | "default" 1754 | | "error" 1755 | | "opaque" 1756 | | "opaqueredirect"; 1757 | interface RequestInit { 1758 | body?: BodyInit | null; 1759 | cache?: RequestCache; 1760 | credentials?: RequestCredentials; 1761 | headers?: HeadersInit; 1762 | integrity?: string; 1763 | keepalive?: boolean; 1764 | method?: string; 1765 | mode?: RequestMode; 1766 | redirect?: RequestRedirect; 1767 | referrer?: string; 1768 | referrerPolicy?: ReferrerPolicy; 1769 | signal?: AbortSignal | null; 1770 | window?: any; 1771 | } 1772 | interface ResponseInit { 1773 | headers?: HeadersInit; 1774 | status?: number; 1775 | statusText?: string; 1776 | } 1777 | interface Request extends Body { 1778 | /** Returns the cache mode associated with request, which is a string 1779 | * indicating how the the request will interact with the browser's cache when 1780 | * fetching. 1781 | */ 1782 | readonly cache: RequestCache; 1783 | /** Returns the credentials mode associated with request, which is a string 1784 | * indicating whether credentials will be sent with the request always, never, 1785 | * or only when sent to a same-origin URL. 1786 | */ 1787 | readonly credentials: RequestCredentials; 1788 | /** Returns the kind of resource requested by request, (e.g., `document` or 1789 | * `script`). 1790 | */ 1791 | readonly destination: RequestDestination; 1792 | /** Returns a Headers object consisting of the headers associated with 1793 | * request. 1794 | * 1795 | * Note that headers added in the network layer by the user agent 1796 | * will not be accounted for in this object, (e.g., the `Host` header). 1797 | */ 1798 | readonly headers: Headers; 1799 | /** Returns request's subresource integrity metadata, which is a cryptographic 1800 | * hash of the resource being fetched. Its value consists of multiple hashes 1801 | * separated by whitespace. [SRI] 1802 | */ 1803 | readonly integrity: string; 1804 | /** Returns a boolean indicating whether or not request is for a history 1805 | * navigation (a.k.a. back-forward navigation). 1806 | */ 1807 | readonly isHistoryNavigation: boolean; 1808 | /** Returns a boolean indicating whether or not request is for a reload 1809 | * navigation. 1810 | */ 1811 | readonly isReloadNavigation: boolean; 1812 | /** Returns a boolean indicating whether or not request can outlive the global 1813 | * in which it was created. 1814 | */ 1815 | readonly keepalive: boolean; 1816 | /** Returns request's HTTP method, which is `GET` by default. */ 1817 | readonly method: string; 1818 | /** Returns the mode associated with request, which is a string indicating 1819 | * whether the request will use CORS, or will be restricted to same-origin 1820 | * URLs. 1821 | */ 1822 | readonly mode: RequestMode; 1823 | /** Returns the redirect mode associated with request, which is a string 1824 | * indicating how redirects for the request will be handled during fetching. 1825 | * 1826 | * A request will follow redirects by default. 1827 | */ 1828 | readonly redirect: RequestRedirect; 1829 | /** Returns the referrer of request. Its value can be a same-origin URL if 1830 | * explicitly set in init, the empty string to indicate no referrer, and 1831 | * `about:client` when defaulting to the global's default. 1832 | * 1833 | * This is used during fetching to determine the value of the `Referer` 1834 | * header of the request being made. 1835 | */ 1836 | readonly referrer: string; 1837 | /** Returns the referrer policy associated with request. This is used during 1838 | * fetching to compute the value of the request's referrer. 1839 | */ 1840 | readonly referrerPolicy: ReferrerPolicy; 1841 | /** Returns the signal associated with request, which is an AbortSignal object 1842 | * indicating whether or not request has been aborted, and its abort event 1843 | * handler. 1844 | */ 1845 | readonly signal: AbortSignal; 1846 | /** Returns the URL of request as a string. */ 1847 | readonly url: string; 1848 | clone(): Request; 1849 | } 1850 | interface Response extends Body { 1851 | /** Contains the `Headers` object associated with the response. */ 1852 | readonly headers: Headers; 1853 | /** Contains a boolean stating whether the response was successful (status in 1854 | * the range 200-299) or not. 1855 | */ 1856 | readonly ok: boolean; 1857 | /** Indicates whether or not the response is the result of a redirect; that 1858 | * is, its URL list has more than one entry. 1859 | */ 1860 | readonly redirected: boolean; 1861 | /** Contains the status code of the response (e.g., `200` for a success). */ 1862 | readonly status: number; 1863 | /** Contains the status message corresponding to the status code (e.g., `OK` 1864 | * for `200`). 1865 | */ 1866 | readonly statusText: string; 1867 | readonly trailer: Promise; 1868 | /** Contains the type of the response (e.g., `basic`, `cors`). */ 1869 | readonly type: ResponseType; 1870 | /** Contains the URL of the response. */ 1871 | readonly url: string; 1872 | /** Creates a clone of a `Response` object. */ 1873 | clone(): Response; 1874 | } 1875 | } 1876 | 1877 | declare namespace blob { 1878 | const bytesSymbol: unique symbol; 1879 | export class DenoBlob implements domTypes.Blob { 1880 | private readonly [bytesSymbol]; 1881 | readonly size: number; 1882 | readonly type: string; 1883 | /** A blob object represents a file-like object of immutable, raw data. */ 1884 | constructor( 1885 | blobParts?: domTypes.BlobPart[], 1886 | options?: domTypes.BlobPropertyBag 1887 | ); 1888 | slice(start?: number, end?: number, contentType?: string): DenoBlob; 1889 | } 1890 | } 1891 | 1892 | declare namespace consoleTypes { 1893 | type ConsoleOptions = Partial<{ 1894 | showHidden: boolean; 1895 | depth: number; 1896 | colors: boolean; 1897 | }>; 1898 | /** TODO Do not expose this from "deno" namespace. */ 1899 | export function stringifyArgs(args: any[], options?: ConsoleOptions): string; 1900 | type PrintFunc = (x: string, isErr?: boolean) => void; 1901 | /** TODO Do not expose this from "deno". */ 1902 | export class Console { 1903 | private printFunc; 1904 | constructor(printFunc: PrintFunc); 1905 | /** Writes the arguments to stdout */ 1906 | log: (...args: any[]) => void; 1907 | /** Writes the arguments to stdout */ 1908 | debug: (...args: any[]) => void; 1909 | /** Writes the arguments to stdout */ 1910 | info: (...args: any[]) => void; 1911 | /** Writes the properties of the supplied `obj` to stdout */ 1912 | dir: ( 1913 | obj: any, 1914 | options?: Partial<{ 1915 | showHidden: boolean; 1916 | depth: number; 1917 | colors: boolean; 1918 | }> 1919 | ) => void; 1920 | /** Writes the arguments to stdout */ 1921 | warn: (...args: any[]) => void; 1922 | /** Writes the arguments to stdout */ 1923 | error: (...args: any[]) => void; 1924 | /** Writes an error message to stdout if the assertion is `false`. If the 1925 | * assertion is `true`, nothing happens. 1926 | * 1927 | * ref: https://console.spec.whatwg.org/#assert 1928 | */ 1929 | assert: (condition?: boolean, ...args: any[]) => void; 1930 | count: (label?: string) => void; 1931 | countReset: (label?: string) => void; 1932 | time: (label?: string) => void; 1933 | timeLog: (label?: string, ...args: any[]) => void; 1934 | timeEnd: (label?: string) => void; 1935 | } 1936 | /** 1937 | * inspect() converts input into string that has the same format 1938 | * as printed by console.log(...); 1939 | */ 1940 | export function inspect( 1941 | value: any, // tslint:disable-line:no-any 1942 | options?: ConsoleOptions 1943 | ): string; 1944 | } 1945 | 1946 | declare namespace io { 1947 | export interface ReadResult { 1948 | nread: number; 1949 | eof: boolean; 1950 | } 1951 | export interface Reader { 1952 | /** Reads up to p.byteLength bytes into `p`. It resolves to the number 1953 | * of bytes read (`0` <= `n` <= `p.byteLength`) and any error encountered. 1954 | * Even if `read()` returns `n` < `p.byteLength`, it may use all of `p` as 1955 | * scratch space during the call. If some data is available but not 1956 | * `p.byteLength` bytes, `read()` conventionally returns what is available 1957 | * instead of waiting for more. 1958 | * 1959 | * When `read()` encounters an error or end-of-file condition after 1960 | * successfully reading `n` > `0` bytes, it returns the number of bytes read. 1961 | * It may return the (non-nil) error from the same call or return the error 1962 | * (and `n` == `0`) from a subsequent call. An instance of this general case 1963 | * is that a `Reader` returning a non-zero number of bytes at the end of the 1964 | * input stream may return either `err` == `EOF` or `err` == `null`. The next 1965 | * `read()` should return `0`, `EOF`. 1966 | * 1967 | * Callers should always process the `n` > `0` bytes returned before 1968 | * considering the `EOF`. Doing so correctly handles I/O errors that happen 1969 | * after reading some bytes and also both of the allowed `EOF` behaviors. 1970 | * 1971 | * Implementations of `read()` are discouraged from returning a zero byte 1972 | * count with a `null` error, except when `p.byteLength` == `0`. Callers 1973 | * should treat a return of `0` and `null` as indicating that nothing 1974 | * happened; in particular it does not indicate `EOF`. 1975 | * 1976 | * Implementations must not retain `p`. 1977 | */ 1978 | read(p: Uint8Array): Promise; 1979 | } 1980 | export interface Writer { 1981 | /** Writes `p.byteLength` bytes from `p` to the underlying data 1982 | * stream. It resolves to the number of bytes written from `p` (`0` <= `n` <= 1983 | * `p.byteLength`) and any error encountered that caused the write to stop 1984 | * early. `write()` must return a non-null error if it returns `n` < 1985 | * `p.byteLength`. write() must not modify the slice data, even temporarily. 1986 | * 1987 | * Implementations must not retain `p`. 1988 | */ 1989 | write(p: Uint8Array): Promise; 1990 | } 1991 | export interface Closer { 1992 | close(): void; 1993 | } 1994 | export interface Seeker { 1995 | /** Seek sets the offset for the next `read()` or `write()` to offset, 1996 | * interpreted according to `whence`: `SeekStart` means relative to the start 1997 | * of the file, `SeekCurrent` means relative to the current offset, and 1998 | * `SeekEnd` means relative to the end. Seek returns the new offset relative 1999 | * to the start of the file and an error, if any. 2000 | * 2001 | * Seeking to an offset before the start of the file is an error. Seeking to 2002 | * any positive offset is legal, but the behavior of subsequent I/O operations 2003 | * on the underlying object is implementation-dependent. 2004 | */ 2005 | seek(offset: number, whence: number): Promise; 2006 | } 2007 | export interface ReadCloser extends Reader, Closer {} 2008 | export interface WriteCloser extends Writer, Closer {} 2009 | export interface ReadSeeker extends Reader, Seeker {} 2010 | export interface WriteSeeker extends Writer, Seeker {} 2011 | export interface ReadWriteCloser extends Reader, Writer, Closer {} 2012 | export interface ReadWriteSeeker extends Reader, Writer, Seeker {} 2013 | /** Copies from `src` to `dst` until either `EOF` is reached on `src` 2014 | * or an error occurs. It returns the number of bytes copied and the first 2015 | * error encountered while copying, if any. 2016 | * 2017 | * Because `copy()` is defined to read from `src` until `EOF`, it does not 2018 | * treat an `EOF` from `read()` as an error to be reported. 2019 | */ 2020 | export function copy(dst: Writer, src: Reader): Promise; 2021 | /** Turns `r` into async iterator. 2022 | * 2023 | * for await (const chunk of readerIterator(reader)) { 2024 | * console.log(chunk) 2025 | * } 2026 | */ 2027 | export function toAsyncIterator(r: Reader): AsyncIterableIterator; 2028 | } 2029 | 2030 | declare namespace fetchTypes { 2031 | class Body implements domTypes.Body, domTypes.ReadableStream, io.ReadCloser { 2032 | private rid; 2033 | readonly contentType: string; 2034 | bodyUsed: boolean; 2035 | private _bodyPromise; 2036 | private _data; 2037 | readonly locked: boolean; 2038 | readonly body: null | Body; 2039 | constructor(rid: number, contentType: string); 2040 | private _bodyBuffer; 2041 | arrayBuffer(): Promise; 2042 | blob(): Promise; 2043 | formData(): Promise; 2044 | json(): Promise; 2045 | text(): Promise; 2046 | read(p: Uint8Array): Promise; 2047 | close(): void; 2048 | cancel(): Promise; 2049 | getReader(): domTypes.ReadableStreamReader; 2050 | } 2051 | class Response implements domTypes.Response { 2052 | readonly status: number; 2053 | readonly url: string; 2054 | statusText: string; 2055 | readonly type = "basic"; 2056 | redirected: boolean; 2057 | headers: domTypes.Headers; 2058 | readonly trailer: Promise; 2059 | bodyUsed: boolean; 2060 | readonly body: Body; 2061 | constructor( 2062 | status: number, 2063 | headersList: Array<[string, string]>, 2064 | rid: number, 2065 | body_?: null | Body 2066 | ); 2067 | arrayBuffer(): Promise; 2068 | blob(): Promise; 2069 | formData(): Promise; 2070 | json(): Promise; 2071 | text(): Promise; 2072 | readonly ok: boolean; 2073 | clone(): domTypes.Response; 2074 | } 2075 | /** Fetch a resource from the network. */ 2076 | export function fetch( 2077 | input: domTypes.Request | string, 2078 | init?: domTypes.RequestInit 2079 | ): Promise; 2080 | } 2081 | 2082 | declare namespace textEncoding { 2083 | export function atob(s: string): string; 2084 | /** Creates a base-64 ASCII string from the input string. */ 2085 | export function btoa(s: string): string; 2086 | export interface TextDecodeOptions { 2087 | stream?: false; 2088 | } 2089 | export interface TextDecoderOptions { 2090 | fatal?: boolean; 2091 | ignoreBOM?: false; 2092 | } 2093 | export class TextDecoder { 2094 | private _encoding; 2095 | /** Returns encoding's name, lowercased. */ 2096 | readonly encoding: string; 2097 | /** Returns `true` if error mode is "fatal", and `false` otherwise. */ 2098 | readonly fatal: boolean; 2099 | /** Returns `true` if ignore BOM flag is set, and `false` otherwise. */ 2100 | readonly ignoreBOM = false; 2101 | constructor(label?: string, options?: TextDecoderOptions); 2102 | /** Returns the result of running encoding's decoder. */ 2103 | decode(input?: domTypes.BufferSource, options?: TextDecodeOptions): string; 2104 | } 2105 | export class TextEncoder { 2106 | /** Returns "utf-8". */ 2107 | readonly encoding = "utf-8"; 2108 | /** Returns the result of running UTF-8's encoder. */ 2109 | encode(input?: string): Uint8Array; 2110 | } 2111 | } 2112 | 2113 | declare namespace timers { 2114 | export type Args = any[]; 2115 | /** Sets a timer which executes a function once after the timer expires. */ 2116 | export function setTimeout( 2117 | cb: (...args: Args) => void, 2118 | delay: number, 2119 | ...args: Args 2120 | ): number; 2121 | /** Repeatedly calls a function , with a fixed time delay between each call. */ 2122 | export function setInterval( 2123 | cb: (...args: Args) => void, 2124 | delay: number, 2125 | ...args: Args 2126 | ): number; 2127 | /** Clears a previously set timer by id. */ 2128 | export function clearTimer(id: number): void; 2129 | } 2130 | 2131 | declare namespace urlSearchParams { 2132 | export class URLSearchParams { 2133 | private params; 2134 | constructor(init?: string | string[][] | Record); 2135 | /** Appends a specified key/value pair as a new search parameter. 2136 | * 2137 | * searchParams.append('name', 'first'); 2138 | * searchParams.append('name', 'second'); 2139 | */ 2140 | append(name: string, value: string): void; 2141 | /** Deletes the given search parameter and its associated value, 2142 | * from the list of all search parameters. 2143 | * 2144 | * searchParams.delete('name'); 2145 | */ 2146 | delete(name: string): void; 2147 | /** Returns all the values associated with a given search parameter 2148 | * as an array. 2149 | * 2150 | * searchParams.getAll('name'); 2151 | */ 2152 | getAll(name: string): string[]; 2153 | /** Returns the first value associated to the given search parameter. 2154 | * 2155 | * searchParams.get('name'); 2156 | */ 2157 | get(name: string): string | null; 2158 | /** Returns a Boolean that indicates whether a parameter with the 2159 | * specified name exists. 2160 | * 2161 | * searchParams.has('name'); 2162 | */ 2163 | has(name: string): boolean; 2164 | /** Sets the value associated with a given search parameter to the 2165 | * given value. If there were several matching values, this method 2166 | * deletes the others. If the search parameter doesn't exist, this 2167 | * method creates it. 2168 | * 2169 | * searchParams.set('name', 'value'); 2170 | */ 2171 | set(name: string, value: string): void; 2172 | /** Sort all key/value pairs contained in this object in place and 2173 | * return undefined. The sort order is according to Unicode code 2174 | * points of the keys. 2175 | * 2176 | * searchParams.sort(); 2177 | */ 2178 | sort(): void; 2179 | /** Calls a function for each element contained in this object in 2180 | * place and return undefined. Optionally accepts an object to use 2181 | * as this when executing callback as second argument. 2182 | * 2183 | * searchParams.forEach((value, key, parent) => { 2184 | * console.log(value, key, parent); 2185 | * }); 2186 | * 2187 | */ 2188 | forEach( 2189 | callbackfn: (value: string, key: string, parent: URLSearchParams) => void, 2190 | thisArg?: any 2191 | ): void; 2192 | /** Returns an iterator allowing to go through all keys contained 2193 | * in this object. 2194 | * 2195 | * for (const key of searchParams.keys()) { 2196 | * console.log(key); 2197 | * } 2198 | */ 2199 | keys(): Iterable; 2200 | /** Returns an iterator allowing to go through all values contained 2201 | * in this object. 2202 | * 2203 | * for (const value of searchParams.values()) { 2204 | * console.log(value); 2205 | * } 2206 | */ 2207 | values(): Iterable; 2208 | /** Returns an iterator allowing to go through all key/value 2209 | * pairs contained in this object. 2210 | * 2211 | * for (const [key, value] of searchParams.entries()) { 2212 | * console.log(key, value); 2213 | * } 2214 | */ 2215 | entries(): Iterable<[string, string]>; 2216 | /** Returns an iterator allowing to go through all key/value 2217 | * pairs contained in this object. 2218 | * 2219 | * for (const [key, value] of searchParams[Symbol.iterator]()) { 2220 | * console.log(key, value); 2221 | * } 2222 | */ 2223 | [Symbol.iterator](): Iterable<[string, string]>; 2224 | /** Returns a query string suitable for use in a URL. 2225 | * 2226 | * searchParams.toString(); 2227 | */ 2228 | toString(): string; 2229 | } 2230 | } 2231 | 2232 | declare namespace url { 2233 | export class URL { 2234 | private _parts; 2235 | private _searchParams; 2236 | private _updateSearchParams; 2237 | hash: string; 2238 | host: string; 2239 | hostname: string; 2240 | href: string; 2241 | readonly origin: string; 2242 | password: string; 2243 | pathname: string; 2244 | port: string; 2245 | protocol: string; 2246 | search: string; 2247 | username: string; 2248 | readonly searchParams: urlSearchParams.URLSearchParams; 2249 | constructor(url: string, base?: string | URL); 2250 | toString(): string; 2251 | toJSON(): string; 2252 | } 2253 | } 2254 | 2255 | -------------------------------------------------------------------------------- /errors.ts: -------------------------------------------------------------------------------- 1 | export class SocketClosedError extends Error {} -------------------------------------------------------------------------------- /example/main.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Yusuke Sakurai. All rights reserved. MIT license. 2 | import {serve} from "https://deno.land/x/net/http.ts"; 3 | import {acceptWebSocket, isWebSocketCloseEvent, isWebSocketPingEvent} from "../ws.ts"; 4 | 5 | async function main() { 6 | console.log("websocket server is running on 0.0.0.0:8080"); 7 | for await (const req of serve("0.0.0.0:8080")) { 8 | if (req.url === "/ws") { 9 | (async () => { 10 | const sock = await acceptWebSocket(req); 11 | console.log("socket connected!"); 12 | for await (const ev of sock.receive()) { 13 | if (typeof ev === "string") { 14 | // text message 15 | console.log("ws:Text", ev); 16 | await sock.send(ev); 17 | } else if (ev instanceof Uint8Array) { 18 | // binary message 19 | console.log("ws:Binary", ev); 20 | } else if (isWebSocketPingEvent(ev)) { 21 | const [_, body] = ev; 22 | // ping 23 | console.log("ws:Ping", body); 24 | } else if (isWebSocketCloseEvent(ev)) { 25 | // close 26 | const {code, reason} = ev; 27 | console.log("ws:Close", code, reason); 28 | } 29 | } 30 | })(); 31 | } 32 | } 33 | } 34 | 35 | main(); -------------------------------------------------------------------------------- /ioutil.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Yusuke Sakurai. All rights reserved. MIT license. 2 | import {BufReader} from "https://deno.land/x/net/bufio.ts"; 3 | 4 | export async function readShort(buf: BufReader) { 5 | const [high, low] = [ 6 | await buf.readByte(), 7 | await buf.readByte() 8 | ]; 9 | return (high << 8) | low; 10 | } 11 | 12 | export async function readInt(buf: BufReader) { 13 | const [high, low] = [ 14 | await readShort(buf), 15 | await readShort(buf) 16 | ]; 17 | return (high << 16) | low 18 | } 19 | 20 | export async function readLong(buf: BufReader) { 21 | const [high, low] = [ 22 | await readInt(buf), 23 | await readInt(buf) 24 | ]; 25 | return (high << 32) | low 26 | } 27 | 28 | export function sliceLongToBytes(d: number, dest = new Array(8)): number[] { 29 | let mask = 0xff; 30 | let shift = 58; 31 | for (let i = 0; i < 8; i++) { 32 | dest[i] = (d >>> shift) & mask; 33 | shift -= 8; 34 | mask >>>= 8; 35 | } 36 | return dest; 37 | } 38 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "baseUrl": ".", 5 | "paths": { 6 | "deno": ["./deno.d.ts"], 7 | "http://*": [ 8 | "../../.deno/deps/https/*" 9 | ], 10 | "https://*": [ 11 | "../../.deno/deps/https/*" 12 | ] 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /ws.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Yusuke Sakurai. All rights reserved. MIT license. 2 | import {Buffer, Writer, Conn} from "deno" 3 | import {ServerRequest} from "https://deno.land/x/net/http.ts"; 4 | import {BufReader, BufWriter} from "https://deno.land/x/net/bufio.ts"; 5 | import {readLong, readShort, sliceLongToBytes} from "./ioutil.ts"; 6 | import {Sha1} from "./crypt.ts"; 7 | import {SocketClosedError} from "./errors.ts"; 8 | 9 | export const OpCodeContinue = 0x0; 10 | export const OpCodeTextFrame = 0x1; 11 | export const OpCodeBinaryFrame = 0x2; 12 | export const OpCodeClose = 0x8; 13 | export const OpcodePing = 0x9; 14 | export const OpcodePong = 0xA; 15 | 16 | 17 | export type WebSocketEvent = string | Uint8Array | WebSocketCloseEvent | WebSocketPingEvent | WebSocketPongEvent; 18 | 19 | export type WebSocketCloseEvent = { 20 | code: number 21 | reason?: string 22 | }; 23 | 24 | export function isWebSocketCloseEvent(a): a is WebSocketCloseEvent { 25 | return a && typeof a["code"] === "number" 26 | } 27 | 28 | export type WebSocketPingEvent = ["ping", Uint8Array] 29 | 30 | export function isWebSocketPingEvent(a): a is WebSocketPingEvent { 31 | return Array.isArray(a) && a[0] === "ping" && a[1] instanceof Uint8Array; 32 | } 33 | 34 | export type WebSocketPongEvent = ["pong", Uint8Array] 35 | 36 | export function isWebSocketPongEvent(a): a is WebSocketPongEvent { 37 | return Array.isArray(a) && a[0] === "pong" && a[1] instanceof Uint8Array; 38 | } 39 | 40 | export type WebSocketFrame = { 41 | isLastFrame: boolean, 42 | opcode: number, 43 | mask?: Uint8Array, 44 | payload: Uint8Array 45 | } 46 | 47 | export type WebSocket = { 48 | readonly isClosed: boolean 49 | receive(): AsyncIterableIterator 50 | send(data: string | Uint8Array): Promise 51 | ping(data?: string | Uint8Array): Promise 52 | close(code: number, reason?: string): Promise 53 | } 54 | 55 | class WebSocketImpl implements WebSocket { 56 | encoder = new TextEncoder(); 57 | constructor(private conn: Conn, private mask?: Uint8Array) { 58 | } 59 | 60 | async* receive(): AsyncIterableIterator { 61 | let frames: WebSocketFrame[] = []; 62 | let payloadsLength = 0; 63 | for await (const frame of receiveFrame(this.conn)) { 64 | unmask(frame.payload, frame.mask); 65 | switch (frame.opcode) { 66 | case OpCodeTextFrame: 67 | case OpCodeBinaryFrame: 68 | case OpCodeContinue: 69 | frames.push(frame); 70 | payloadsLength += frame.payload.length; 71 | if (frame.isLastFrame) { 72 | const concat = new Uint8Array(payloadsLength); 73 | let offs = 0; 74 | for (const frame of frames) { 75 | concat.set(frame.payload, offs); 76 | offs += frame.payload.length; 77 | } 78 | if (frames[0].opcode === OpCodeTextFrame) { 79 | // text 80 | yield new Buffer(concat).toString() 81 | } else { 82 | // binary 83 | yield concat 84 | } 85 | frames = []; 86 | payloadsLength = 0; 87 | } 88 | break; 89 | case OpCodeClose: 90 | const code = (frame.payload[0] << 16) | frame.payload[1]; 91 | const reason = new Buffer(frame.payload.subarray(2, frame.payload.length)).toString(); 92 | this._isClosed = true; 93 | yield {code, reason}; 94 | return; 95 | case OpcodePing: 96 | yield ["ping", frame.payload] as WebSocketPingEvent; 97 | break; 98 | case OpcodePong: 99 | yield ["pong", frame.payload] as WebSocketPongEvent; 100 | break; 101 | } 102 | } 103 | } 104 | 105 | async send(data: string | Uint8Array): Promise { 106 | if (this.isClosed) { 107 | throw new SocketClosedError("socket has been closed") 108 | } 109 | const opcode = typeof data === "string" ? OpCodeTextFrame : OpCodeBinaryFrame; 110 | const payload = typeof data === "string" ? this.encoder.encode(data) : data; 111 | const isLastFrame = true; 112 | await writeFrame({ 113 | isLastFrame, 114 | opcode, 115 | payload, 116 | mask: this.mask, 117 | }, this.conn); 118 | } 119 | 120 | async ping(data: string | Uint8Array): Promise { 121 | const payload = typeof data === "string" ? this.encoder.encode(data) : data; 122 | await writeFrame({ 123 | isLastFrame: true, 124 | opcode: OpCodeClose, 125 | mask: this.mask, 126 | payload 127 | }, this.conn) 128 | } 129 | 130 | private _isClosed = false; 131 | get isClosed() { 132 | return this._isClosed; 133 | } 134 | 135 | async close(code: number, reason?: string): Promise { 136 | try { 137 | const header = [ 138 | (code >>> 8), (code & 0x00ff) 139 | ]; 140 | let payload: Uint8Array; 141 | if (reason) { 142 | const reasonBytes = this.encoder.encode(reason); 143 | payload = new Uint8Array(2 + reasonBytes.byteLength); 144 | payload.set(header); 145 | payload.set(reasonBytes, 2); 146 | } else { 147 | payload = new Uint8Array(header); 148 | } 149 | await writeFrame({ 150 | isLastFrame: true, 151 | opcode: OpCodeClose, 152 | mask: this.mask, 153 | payload 154 | }, this.conn); 155 | } catch (e) { 156 | throw e; 157 | } finally { 158 | this.ensureSocketClosed(); 159 | } 160 | } 161 | 162 | private ensureSocketClosed(): Error { 163 | if (this.isClosed) return; 164 | try { 165 | this.conn.close() 166 | } catch (e) { 167 | console.error(e); 168 | } finally { 169 | this._isClosed = true; 170 | } 171 | } 172 | } 173 | 174 | 175 | export async function* receiveFrame(conn: Conn): AsyncIterableIterator { 176 | let receiving = true; 177 | const reader = new BufReader(conn); 178 | while (receiving) { 179 | const frame = await readFrame(reader); 180 | switch (frame.opcode) { 181 | case OpCodeTextFrame: 182 | case OpCodeBinaryFrame: 183 | case OpCodeContinue: 184 | yield frame; 185 | break; 186 | case OpCodeClose: 187 | await writeFrame({ 188 | isLastFrame: true, 189 | opcode: OpCodeClose, 190 | payload: frame.payload, 191 | }, conn); 192 | conn.close(); 193 | yield frame; 194 | receiving = false; 195 | break; 196 | case OpcodePing: 197 | await writeFrame({ 198 | isLastFrame: true, 199 | opcode: OpcodePong, 200 | payload: frame.payload 201 | }, conn); 202 | yield frame; 203 | break; 204 | case OpcodePong: 205 | yield frame; 206 | break; 207 | } 208 | } 209 | } 210 | 211 | export async function writeFrame(frame: WebSocketFrame, writer: Writer) { 212 | let payloadLength = frame.payload.byteLength; 213 | let header: Uint8Array; 214 | const hasMask = (frame.mask ? 1 : 0) << 7; 215 | if (payloadLength < 126) { 216 | header = new Uint8Array([ 217 | (0b1000 << 4) | frame.opcode, 218 | (hasMask | payloadLength) 219 | ]); 220 | } else if (payloadLength < 0xffff) { 221 | header = new Uint8Array([ 222 | (0b1000 << 4) | frame.opcode, 223 | (hasMask | 0b01111110), 224 | payloadLength >>> 8, 225 | (payloadLength & 0x00ff) 226 | ]); 227 | } else { 228 | header = new Uint8Array([ 229 | (0b1000 << 4) | frame.opcode, 230 | (hasMask | 0b01111111), 231 | ...sliceLongToBytes(payloadLength) 232 | ]); 233 | } 234 | if (frame.mask) { 235 | unmask(frame.payload, frame.mask); 236 | } 237 | const bytes = new Uint8Array(header.length + payloadLength); 238 | bytes.set(header, 0); 239 | bytes.set(frame.payload, header.length); 240 | const w = new BufWriter(writer); 241 | await w.write(bytes); 242 | await w.flush(); 243 | } 244 | 245 | export function unmask(payload: Uint8Array, mask: Uint8Array) { 246 | if (mask) { 247 | for (let i = 0; i < payload.length; i++) { 248 | payload[i] ^= mask[i % 4]; 249 | } 250 | } 251 | } 252 | 253 | export function acceptable(req: ServerRequest): boolean { 254 | return req.headers.get("upgrade") === "websocket" 255 | && req.headers.has("sec-websocket-key") 256 | } 257 | 258 | export async function acceptWebSocket(req: ServerRequest): Promise { 259 | if (acceptable(req)) { 260 | const sock = new WebSocketImpl(req.conn); 261 | const secKey = req.headers.get("sec-websocket-key"); 262 | const secAccept = createSecAccept(secKey); 263 | await req.respond({ 264 | status: 101, 265 | headers: new Headers({ 266 | "Upgrade": "websocket", 267 | "Connection": "Upgrade", 268 | "Sec-WebSocket-Accept": secAccept, 269 | }) 270 | }); 271 | return sock; 272 | } 273 | throw new Error("request is not acceptable"); 274 | } 275 | 276 | const kGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 277 | 278 | export function createSecAccept(nonce: string) { 279 | const sha1 = new Sha1(); 280 | sha1.update(nonce + kGUID); 281 | const bytes = sha1.digest(); 282 | const hash = bytes.reduce((data, byte) => data + String.fromCharCode(byte), ""); 283 | return btoa(hash); 284 | } 285 | 286 | export async function readFrame(buf: BufReader): Promise { 287 | let b = await buf.readByte(); 288 | let isLastFrame = false; 289 | switch (b >>> 4) { 290 | case 0b1000: 291 | isLastFrame = true; 292 | break; 293 | case 0b0000: 294 | isLastFrame = false; 295 | break; 296 | default: 297 | throw new Error("invalid signature"); 298 | } 299 | const opcode = b & 0x0f; 300 | // has_mask & payload 301 | b = await buf.readByte(); 302 | const hasMask = b >>> 7; 303 | let payloadLength = b & 0b01111111; 304 | if (payloadLength === 126) { 305 | payloadLength = await readShort(buf); 306 | } else if (payloadLength === 127) { 307 | payloadLength = await readLong(buf); 308 | } 309 | // mask 310 | let mask; 311 | if (hasMask) { 312 | mask = new Uint8Array(4); 313 | await buf.readFull(mask); 314 | } 315 | // payload 316 | const payload = new Uint8Array(payloadLength); 317 | await buf.readFull(payload); 318 | return { 319 | isLastFrame, opcode, mask, payload 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /ws_test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Yusuke Sakurai. All rights reserved. MIT license. 2 | import {Buffer} from "deno"; 3 | import {BufReader} from "https://deno.land/x/net/bufio.ts" 4 | import { 5 | test, 6 | assert, 7 | assertEqual 8 | } from "https://deno.land/x/testing/testing.ts"; 9 | import { 10 | createSecAccept, 11 | OpCodeBinaryFrame, 12 | OpCodeContinue, 13 | OpcodePing, 14 | OpcodePong, 15 | OpCodeTextFrame, 16 | readFrame, 17 | unmask 18 | } from "./ws.ts"; 19 | 20 | test(async function testReadFrame() { 21 | // unmasked single text frame with payload "Hello" 22 | const buf = new BufReader(new Buffer(new Uint8Array([ 23 | 0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f 24 | ]))); 25 | const frame = await readFrame(buf); 26 | assertEqual(frame.opcode, OpCodeTextFrame); 27 | assertEqual(frame.mask, undefined); 28 | assertEqual(new Buffer(frame.payload).toString(), "Hello"); 29 | assertEqual(frame.isLastFrame, true); 30 | }); 31 | 32 | test(async function testReadFrame2() { 33 | //a masked single text frame with payload "Hello" 34 | const buf = new BufReader(new Buffer(new Uint8Array([ 35 | 0x81, 0x85, 0x37, 0xfa, 0x21, 0x3d, 0x7f, 0x9f, 0x4d, 0x51, 0x58 36 | ]))); 37 | const frame = await readFrame(buf); 38 | console.dir(frame); 39 | assertEqual(frame.opcode, OpCodeTextFrame); 40 | unmask(frame.payload, frame.mask); 41 | assertEqual(new Buffer(frame.payload).toString(), "Hello"); 42 | assertEqual(frame.isLastFrame, true); 43 | }); 44 | 45 | test(async function f() { 46 | const buf1 = new BufReader(new Buffer(new Uint8Array([ 47 | 0x01, 0x03, 0x48, 0x65, 0x6c 48 | ]))); 49 | const buf2 = new BufReader(new Buffer(new Uint8Array([ 50 | 0x80, 0x02, 0x6c, 0x6f 51 | ]))); 52 | const [f1, f2] = await Promise.all([ 53 | readFrame(buf1), readFrame(buf2) 54 | ]); 55 | assertEqual(f1.isLastFrame, false); 56 | assertEqual(f1.mask, undefined); 57 | assertEqual(f1.opcode, OpCodeTextFrame); 58 | assertEqual(new Buffer(f1.payload).toString(), "Hel"); 59 | 60 | assertEqual(f2.isLastFrame, true); 61 | assertEqual(f2.mask, undefined); 62 | assertEqual(f2.opcode, OpCodeContinue); 63 | assertEqual(new Buffer(f2.payload).toString(), "lo") 64 | }); 65 | 66 | test(async function f2() { 67 | // unmasked ping with payload "Hello" 68 | const buf = new BufReader(new Buffer(new Uint8Array([ 69 | 0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 70 | ]))); 71 | const ping = await readFrame(buf); 72 | assertEqual(ping.opcode, OpcodePing); 73 | assertEqual(new Buffer(ping.payload).toString(), "Hello") 74 | 75 | const buf2 = new BufReader(new Buffer(new Uint8Array([ 76 | 0x8a, 0x85, 0x37, 0xfa, 0x21, 0x3d, 0x7f, 0x9f, 0x4d, 0x51, 0x58 77 | ]))); 78 | const pong = await readFrame(buf2); 79 | assertEqual(pong.opcode, OpcodePong); 80 | assert(pong.mask !== undefined); 81 | unmask(pong.payload, pong.mask); 82 | assertEqual(new Buffer(pong.payload).toString(), "Hello") 83 | }); 84 | 85 | test(async function f3() { 86 | let a = [0x82, 0x7E, 0x01, 0x00]; 87 | for (let i = 0; i < 256; i++) { 88 | a.push(i); 89 | } 90 | const buf = new BufReader(new Buffer(new Uint8Array(a))); 91 | const bin = await readFrame(buf); 92 | assertEqual(bin.opcode, OpCodeBinaryFrame); 93 | assertEqual(bin.isLastFrame, true); 94 | assertEqual(bin.mask, undefined); 95 | assertEqual(bin.payload.length, 256); 96 | }); 97 | 98 | test(async function f4() { 99 | let a = [0x82, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00]; 100 | for (let i = 0; i < 0xffff; i++) { 101 | a.push(i); 102 | } 103 | const buf = new BufReader(new Buffer(new Uint8Array(a))); 104 | const bin = await readFrame(buf); 105 | assertEqual(bin.opcode, OpCodeBinaryFrame); 106 | assertEqual(bin.isLastFrame, true); 107 | assertEqual(bin.mask, undefined); 108 | assertEqual(bin.payload.length, 0xffff + 1); 109 | }); 110 | 111 | test(async function testCreateSecAccept() { 112 | const nonce = "dGhlIHNhbXBsZSBub25jZQ=="; 113 | const d = createSecAccept(nonce); 114 | assertEqual(d, "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="); 115 | }); --------------------------------------------------------------------------------