2018-06-15 07:33:23 -04:00
|
|
|
# Deno Roadmap
|
|
|
|
|
|
|
|
API and Feature requests should be submitted as PRs to this document.
|
|
|
|
|
2018-06-29 08:14:26 -04:00
|
|
|
## Target Use Cases
|
|
|
|
|
|
|
|
### Low-level, fast memory efficient sockets
|
|
|
|
|
|
|
|
Example, non-final API for piping a socket to stdout:
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
function nonblockingpipe(fd) {
|
|
|
|
let buf = new Uint8Array(1024); // Fixed 1k buffer.
|
|
|
|
for (;;) {
|
|
|
|
let code = await deno.pollNB(fd, deno.POLL_RD | deno.POLL_WR);
|
|
|
|
switch (code) {
|
|
|
|
case "READABLE":
|
|
|
|
let [nread, err] = deno.readNB(fd, buf, buf.byteSize);
|
|
|
|
if (err === "EAGAIN") continue;
|
|
|
|
if (err != null) break;
|
|
|
|
await deno.stdout.write(buf.slice(0, nread));
|
|
|
|
break;
|
|
|
|
case "ERROR":
|
|
|
|
throw Error("blah");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### List deps
|
|
|
|
|
|
|
|
```
|
|
|
|
% deno --list-deps http://gist.com/blah.js
|
|
|
|
http://gist.com/blah.js
|
|
|
|
http://gist.com/dep.js
|
2018-08-02 19:13:02 -04:00
|
|
|
https://github.com/denoland/deno/master/testing.js
|
2018-06-29 08:14:26 -04:00
|
|
|
%
|
|
|
|
```
|
|
|
|
|
|
|
|
## Security Model
|
|
|
|
|
|
|
|
* We want to be secure by default; user should be able to run untrusted code,
|
|
|
|
like the web.
|
|
|
|
* Threat model:
|
|
|
|
* Modifiying/deleting local files
|
|
|
|
* Leaking private information
|
2018-07-03 15:18:42 -04:00
|
|
|
* Disallowed default:
|
|
|
|
* Network access
|
|
|
|
* Local write access
|
|
|
|
* Non-JS extensions
|
|
|
|
* Subprocesses
|
|
|
|
* Env access
|
|
|
|
* Allowed default:
|
2018-06-29 08:14:26 -04:00
|
|
|
* Local read access.
|
|
|
|
* argv, stdout, stderr, stdin access always allowed.
|
2018-07-03 15:18:42 -04:00
|
|
|
* Maybe: temp dir write access. (But what if they create symlinks there?)
|
2018-06-29 08:14:26 -04:00
|
|
|
* The user gets prompted when the software tries to do something it doesn't have
|
|
|
|
the privilege for.
|
|
|
|
* Have an option to get a stack trace when access is requested.
|
|
|
|
* Worried that granting access per file will give a false sense of security due
|
|
|
|
to monkey patching techniques. Access should be granted per program (js
|
|
|
|
context).
|
|
|
|
|
2018-07-03 15:18:42 -04:00
|
|
|
Example security prompts. Options are: YES, NO, PRINT STACK
|
|
|
|
```
|
|
|
|
Program requests write access to "~/.ssh/id_rsa". Grant? [yNs]
|
|
|
|
http://gist.github.com/asdfasd.js requests network access to "www.facebook.com". Grant? [yNs]
|
|
|
|
Program requests access to environment variables. Grant? [yNs]
|
|
|
|
Program requests to spawn `rm -rf /`. Grant? [yNs]
|
|
|
|
```
|
2018-06-29 08:14:26 -04:00
|
|
|
|
|
|
|
* cli flags to grant access ahead of time --allow-all --allow-write --allow-net
|
|
|
|
--allow-env --allow-exec
|
|
|
|
* in version two we will add ability to give finer grain access
|
|
|
|
--allow-net=facebook.com
|
|
|
|
|
2018-06-15 07:33:23 -04:00
|
|
|
## Milestone 1: Rust rewrite / V8 snapshot
|
|
|
|
|
|
|
|
ETA: July 2018.
|
|
|
|
|
|
|
|
Go is a garbage collected language and we are worried that combining it with
|
2018-06-24 13:53:59 -04:00
|
|
|
V8's GC will lead to difficult contention problems down the road.
|
2018-06-15 07:33:23 -04:00
|
|
|
|
|
|
|
The V8Worker2 binding/concept is being ported to a new C++ library called
|
|
|
|
libdeno. libdeno will include the entire JS runtime as a V8 snapshot. It still
|
|
|
|
follows the message passing paradigm. Rust will be bound to this library to
|
|
|
|
implement the privileged part of Deno. See deno2/README.md for more details.
|
|
|
|
|
|
|
|
V8 Snapshots allow Deno to avoid recompiling the TypeScript compiler at
|
|
|
|
startup. This is already working.
|
|
|
|
|
|
|
|
When the rewrite is at feature parity with the Go prototype, we will release
|
|
|
|
binaries for people to try.
|
|
|
|
|
2018-06-29 08:14:26 -04:00
|
|
|
## libdeno C API.
|
|
|
|
|
|
|
|
Deno's privileged side will primarily be programmed in Rust. However there
|
|
|
|
will be a small C API that wraps V8 to 1) define the low-level message passing
|
|
|
|
semantics 2) provide a low-level test target 3) provide an ANSI C API binding
|
|
|
|
interface for Rust. V8 plus this C API is called libdeno and the important bits
|
|
|
|
of the API is specified here:
|
|
|
|
|
|
|
|
```c
|
|
|
|
// Data that gets transmitted.
|
|
|
|
typedef struct {
|
|
|
|
const char* data;
|
|
|
|
size_t len;
|
|
|
|
} deno_buf;
|
|
|
|
|
2018-07-06 16:26:34 -04:00
|
|
|
typedef void (*deno_sub_cb)(Deno* d, deno_buf bufs[], size_t nbufs)
|
2018-06-29 08:14:26 -04:00
|
|
|
void deno_set_callback(Deno* deno, deno_sub_cb cb);
|
|
|
|
|
|
|
|
// Executes javascript source code.
|
|
|
|
// Get error text with deno_last_exception().
|
|
|
|
// 0 = success, non-zero = failure.
|
|
|
|
// TODO(ry) Currently the return code has opposite semantics.
|
|
|
|
int deno_execute(Deno* d, const char* js_filename, const char* js_source);
|
|
|
|
|
|
|
|
// This call doesn't go into JS. This is thread-safe.
|
|
|
|
// TODO(ry) Currently this is called deno_pub. It should be renamed.
|
|
|
|
// deno_append is the desired name.
|
|
|
|
void deno_append(deno_buf buf);
|
|
|
|
|
|
|
|
// Should only be called at most once during the deno_sub_cb.
|
|
|
|
void deno_set_response(Deno* deno, deno_buf bufs[], size_t nbufs);
|
|
|
|
|
|
|
|
const char* deno_last_exception(Deno* d);
|
|
|
|
```
|
2018-06-15 07:33:23 -04:00
|
|
|
|
|
|
|
## TypeScript API.
|
|
|
|
|
|
|
|
|
|
|
|
There are three layers of API to consider:
|
|
|
|
* L1: the low-level message passing API exported by libdeno (L1),
|
2018-08-03 11:21:04 -04:00
|
|
|
* L2: the flatbuffer messages used internally (L2),
|
2018-06-15 07:33:23 -04:00
|
|
|
* L3: the final "deno" namespace exported to users (L3).
|
|
|
|
|
|
|
|
### L1
|
|
|
|
|
2018-06-29 08:14:26 -04:00
|
|
|
```typescript
|
2018-07-06 16:26:34 -04:00
|
|
|
function send(...ab: ArrayBuffer[]): ArrayBuffer[] | null;
|
2018-06-15 07:33:23 -04:00
|
|
|
```
|
2018-06-29 08:14:26 -04:00
|
|
|
Used to make calls outside of V8. Send an ArrayBuffer and synchronously receive
|
2018-07-06 16:26:34 -04:00
|
|
|
an ArrayBuffer back.
|
2018-06-15 07:33:23 -04:00
|
|
|
|
2018-06-29 08:14:26 -04:00
|
|
|
```typescript
|
|
|
|
function poll(): ArrayBuffer[];
|
2018-06-15 07:33:23 -04:00
|
|
|
```
|
2018-06-29 08:14:26 -04:00
|
|
|
Poll for new asynchronous events from the privileged side. This will be done
|
|
|
|
as the main event loop.
|
2018-06-15 07:33:23 -04:00
|
|
|
|
2018-06-29 08:14:26 -04:00
|
|
|
```typescript
|
2018-06-15 07:33:23 -04:00
|
|
|
function print(x: string): void;
|
|
|
|
```
|
2018-06-29 08:14:26 -04:00
|
|
|
A way to print to stdout. Although this could be easily implemented thru
|
|
|
|
`send()` this is an important debugging tool to avoid intermediate
|
|
|
|
infrastructure.
|
|
|
|
|
|
|
|
|
|
|
|
The current implementation is out of sync with this document:
|
2018-08-02 19:13:02 -04:00
|
|
|
https://github.com/denoland/deno/blob/master/js/deno.d.ts
|
2018-06-29 08:14:26 -04:00
|
|
|
|
|
|
|
#### L1 Examples
|
|
|
|
|
|
|
|
The main event loop of Deno should look something like this:
|
|
|
|
```js
|
|
|
|
function main() {
|
|
|
|
// Setup...
|
|
|
|
while (true) {
|
|
|
|
const messages = deno.poll();
|
|
|
|
processMessages(messages);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
2018-06-15 07:33:23 -04:00
|
|
|
|
|
|
|
|
|
|
|
### L2
|
|
|
|
|
2018-08-03 11:21:04 -04:00
|
|
|
https://github.com/denoland/deno/blob/master/src/msg.fbs
|
2018-06-15 07:33:23 -04:00
|
|
|
|
|
|
|
### L3
|
|
|
|
|
|
|
|
With in Deno this is the high-level user facing API. However, the intention
|
|
|
|
is to expose functionality as simply as possible. There should be little or
|
|
|
|
no "ergonomics" APIs. (For example, `deno.readFileSync` only deals with
|
|
|
|
ArrayBuffers and does not have an encoding parameter to return strings.)
|
|
|
|
The intention is to make very easy to extend and link in external modules
|
|
|
|
which can then add this functionality.
|
|
|
|
|
|
|
|
Deno does not aim to be API compatible with Node in any respect. Deno will
|
|
|
|
export a single flat namespace "deno" under which all core functions are
|
|
|
|
defined. We leave it up to users to wrap Deno's namespace to provide some
|
|
|
|
compatibility with Node.
|
|
|
|
|
|
|
|
*Top-level await*: This will be put off until at least deno2 Milestone1 is
|
|
|
|
complete. One of the major problems is that top-level await calls are not
|
|
|
|
syntactically valid TypeScript.
|
|
|
|
|
|
|
|
Functions exported under Deno namespace:
|
|
|
|
```ts
|
|
|
|
deno.readFileSync(filename: string): ArrayBuffer;
|
|
|
|
deno.writeFileSync(filename: string, data: Uint8Array, perm: number): void;
|
|
|
|
```
|
|
|
|
|
|
|
|
Timers:
|
|
|
|
```ts
|
|
|
|
setTimeout(cb: TimerCallback, delay: number, ...args: any[]): number;
|
|
|
|
setInterval(cb: TimerCallbac, duration: number, ...args: any[]): number;
|
|
|
|
clearTimeout(timerId: number);
|
|
|
|
clearInterval(timerId: number);
|
|
|
|
```
|
|
|
|
|
|
|
|
Console:
|
|
|
|
```ts
|
|
|
|
declare var console: {
|
|
|
|
log(...args: any[]): void;
|
|
|
|
error(...args: any[]): void;
|
|
|
|
assert(assertion: boolean, ...msg: any[]): void;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
URL:
|
|
|
|
```ts
|
|
|
|
URL(url: string, base?: string): URL;
|
|
|
|
```
|
|
|
|
|
|
|
|
Text encoding:
|
|
|
|
```ts
|
|
|
|
declare var TextEncoder: {
|
|
|
|
new (utfLabel?: string, options?: TextEncoderOptions): TextEncoder;
|
|
|
|
(utfLabel?: string, options?: TextEncoderOptions): TextEncoder;
|
|
|
|
encoding: string;
|
|
|
|
};
|
|
|
|
|
|
|
|
declare var TextDecoder: {
|
|
|
|
new (label?: string, options?: TextDecoderOptions): TextDecoder;
|
|
|
|
(label?: string, options?: TextDecoderOptions): TextDecoder;
|
|
|
|
encoding: string;
|
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
Fetch API:
|
|
|
|
```ts
|
|
|
|
fetch(input?: Request | string, init?: RequestInit): Promise<Response>;
|
|
|
|
```
|