blob: f8b98fbbd95fe18032cabb1d786ccb4f7380b425 [file] [view] [edit]
# DartPad Worker Protocol
The `bin/shared_worker.dart` program is intended to run as a [SharedWorker][1]
in the browser. The client can communicate with the worker over the
[MessagePort][2] created when connecting to the [SharedWorker][1]. This document
describes the protocol for communication over this port.
In the description below the _worker_ is `bin/shared_worker.dart` and _client_
is the web page that connected to the [SharedWorker][1].
**Concepts:**
* _Session_, when a client connects to the worker, a session is created.
Sessions do share the same file-system and thread. But are otherwise
independent, and should be using differnet parts of the virtual file-system.
* _Workspace_, a workspace is a folder and associated resources for
running language-servers and compiling source code.
* _Language-server_, a process running within a workspace that provides a
language-server-protocol server for Dart.
* _Hot-reload compiler_, a process running with a workspace that faciliates
incremental compilation of a single entry-point.
## JSON-RPC 2.0
Communication with the worker uses [JSON-RPC 2.0][3]. Communication over the
[MessagePort][2] takes place using raw JSON objects (utilizing the browser's
structured clone algorithm), not JSON-encoded strings.
The following sections outline which methods are offered by the worker...
[JSON-RPC 2.0][3] requests are usually on the form:
```js
{
"jsonrpc": "2.0",
"method": "<name-of-method>",
"params": {
// parameters for the method
},
"id": 42 // unique ID per request, omitted for notifications!
}
```
If the `id` property is omitted, then the message is said to be a _notification_
and no response will be sent. For _requests_ the `id` must be unique and must
be used by the client to find the matching _response_ for the _request_.
Response objects are usually on the form:
```js
{
"jsonrpc": "2.0",
"result": {
// result values from the method
},
"id": 42 // ID from the request
}
```
If an error occured when handling a _request_, then an error will be returned.
Errors will never be returned for _notifications_, since notifications don't
carry an `id` property, they never produce a _response_ or an _error_.
Errors are usually on the form:
```js
{
"jsonrpc": "2.0",
"error": {
"code": 1000, // Integer error code (negative numbers are reserved)
"message": "<human readable message>",
"data": {
// Arbitrary data associated from the error handler.
}
},
"id": 42 // ID from the request
}
```
When sending requests and notifications is possible to batch multiple messages
into a single message by sending an array of requests and notifications.
For further details about JSON-RPC 2.0, refer to the [specification][3].
## Server Methods and Notifications
Methods are prefixed based on what objects they operate on. Thus, all methods
prefixed `workspace/` require a `workspaceId` parameter.
| **Method Prefix** | **Required identifiers** |
| :--- | :--- |
| `workspace/` | `workspaceId` |
| `workspace/languageServer/` | `workspaceId` and `languageServerId` |
| `workspace/hotReloadCompiler/` | `workspaceId` and `hotReloadCompilerId` |
### Method `createWorkspace`
Creates workspace with a dedicated `workspaceFolder`.
**Params:**
```js
{} // No parameters!
```
**Result:**
```js
{
// The workspaceId is a unique number identifying the workspace created
"workspaceId": 42,
// Folder on the shared file-system dedicated to this workspace
"workspaceFolder": "file:///workspace/pad_42/",
}
```
### Method `workspace/dispose`
Deletes the workspace and all associated resources.
**Params:**
```js
{
"workspaceId": 42,
}
```
**Result:**
```js
{} // empty result
```
### Method `workspace/writeFileFromText`
Write a `text` string to a file as UTF-8.
Parent directories will be automatically created.
**Params:**
```js
{
"workspaceId": 42,
// URI of the file that you want to write.
// Can be absolute file:// or relative to workspaceFolder
"uri": "bin/hello.dart",
// Text that should be written to the file.
// This will be written as UTF-8.
"text": "void main() => print('hello world');",
}
```
**Result:**
```js
{} // empty result
```
### Method `workspace/writeFileFromBytes`
**Params:**
```js
{
"workspaceId": 42,
"uri": "bin/hello.dart",
// Bytes that should be written to the file as base64
"base64": "<base64-encoded bytes>",
}
```
**Result:**
```js
{} // empty result
```
### Method `workspace/readFileAsText`
**Params:**
```js
{
"workspaceId": 42,
"uri": "bin/hello.dart",
}
```
**Result:**
```js
{
"text": "<contents of the file as UTF-8>"
}
```
### Method `workspace/readFileAsBytes`
**Params:**
```js
{
"workspaceId": 42,
"uri": "bin/hello.dart",
}
```
**Result:**
```js
{
"base64": "<bytes from the file encoded as base64>"
}
```
### Method `workspace/deleteFileSystemEntity`
**Params:**
```js
{
"workspaceId": 42,
// URI of the file or folder that you want to delete.
"uri": "bin/hello.dart",
}
```
**Result:**
```js
{} // empty result
```
### Method `workspace/stat`
Get information about a file or folder.
**Params:**
```js
{
"workspaceId": 42,
"uri": "bin/hello.dart",
}
```
**Result:**
```js
{
// Type of the entity: "file", "folder" or "other"
"type": "file" | "folder" | "other",
// Size in bytes (only for files)
"size": 1024
}
```
### Method `workspace/createFolder`
**Params:**
```js
{
"workspaceId": 42,
"uri": "lib",
}
```
**Result:**
```js
{} // empty result
```
### Method `workspace/listDirectory`
**Params:**
```js
{
"workspaceId": 42,
"uri": "lib",
// Whether to list recursively (default: false)
"recursive": true,
// Whether to ignore hidden files (starting with .) (default: false)
"ignoreHidden": true
}
```
**Result:**
```js
{
// List of entries. Paths are relative to the uri listed.
"entries": [
{"path": "main.dart", "type": "file"},
{"path": "src", "type": "folder"}
]
}
```
### Method `workspace/importTarArchive`
Import a tar archive (uncompressed) into the workspace.
**Params:**
```js
{
"workspaceId": 42,
// Path where to extract the archive.
"uri": ".",
// Base64 encoded tar archive.
"base64": "<base64-encoded-tar>"
}
```
**Result:**
```js
{} // empty result
```
### Method `workspace/exportTarArchive`
Export a directory as a tar archive (uncompressed).
**Params:**
```js
{
"workspaceId": 42,
// Directory to export.
"uri": "."
}
```
**Result:**
```js
{
// Base64 encoded tar archive.
"base64": "<base64-encoded-tar>"
}
```
### Method `workspace/pub`
Runs `pub` in the specified directory.
**Params:**
```js
{
"workspaceId": 42,
// Directory to run pub in.
"uri": ".",
// Command to run.
"command": "get" | "add" | "downgrade" | "outdated" | "upgrade" | "remove" | "unpack",
// Arguments to pass to the pub command (optional)
"args": ["--dry-run"]
}
```
**Result:**
```js
{
"log": "<output from pub get>",
}
```
### Method `workspace/startHotReloadCompiler`
Start a hot-reload compiler for `uri`.
**Params:**
```js
{
"workspaceId": 42,
"uri": "bin/hello.dart",
}
```
**Result:**
```js
{
// identifier for the hot-reload compiler just started
"hotReloadCompilerId": 67,
}
```
### Method `workspace/hotReloadCompiler/compile`
Run the hot-reload compiler for the `uri` it was started with.
Returns `code` and `compiledLibraryUris`, which must be supplied to the
hot-reload method as `librariesToReload` when hot-reloading.
**Params:**
```js
{
"workspaceId": 42,
"hotReloadCompilerId": 67,
}
```
**Result:**
```js
{
// Code is `null` if compilation failed!
"code": "<javascript code>" || null,
"compiledLibraryUris": ["package:myapp/myapp.dart", ...],
"log": "<log lines>",
}
```
### Method `workspace/hotReloadCompiler/close`
Close the hot-reload compiler, releasing resources (memory) held.
**Params:**
```js
{
"workspaceId": 42,
"hotReloadCompilerId": 67,
}
```
**Result:**
```js
{} // empty result
```
### Method `workspace/startLanguageServer`
Start a language-server.
**Params:**
```js
{
"workspaceId": 42,
}
```
**Result:**
```js
{
"languageServerId": 36, // identifier for the language-server just started
}
```
### Method `workspace/languageServer/message`
Sends an LSP message to a running language server.
**Params:**
```js
{
"workspaceId": 42,
"languageServerId": 36,
"message": {
// JSON-RPC 2.0 message for the language-server
"jsonrpc": "2.0",
"method": "...",
"params": {...},
"id": ...,
},
}
```
**Result:**
```js
{} // empty result
```
### Method `workspace/languageServer/stop`
**Params:**
```js
{
"workspaceId": 42,
"languageServerId": 36,
}
```
**Result:**
```js
{} // empty result
```
## Client Notifications
### Notification `workspace/languageServer/message`
Sent by the worker when the language server produces a message.
**Params:**
```js
{
"workspaceId": 42,
"languageServerId": 36,
"message": {
// JSON-RPC 2.0 message from the language-server
}
}
```
### Notification `workspace/languageServer/exited`
Sent by the worker when a language server process terminates.
**Params:**
```js
{
"workspaceId": 42,
"languageServerId": 36
}
```
## Error codes
Errors returned by the worker use the following codes.
<!-- BEGIN GENERATED ERROR CODE TABLE -->
| Code | Name | Description |
| :--- | :--- | :--- |
| 2001 | `workspaceNotFound` | The provided `workspaceId` does not exist. |
| 4001 | `fileNotFound` | The requested file or directory does not exist. |
| 4002 | `fileWriteConflict` | Could not write file (e.g. parent is a file). |
| 4003 | `fileDeletionFailed` | Could not delete the requested entity. |
| 5001 | `languageServerNotFound` | The `languageServerId` does not exist in this workspace. |
| 6001 | `compilationFailed` | Failed to compile code, usually due to an issue in the code being compiled. |
| 6020 | `packageConfigNotFound` | Unable to find `.dart_tool/package_config.json` in any parent directory. |
| 6100 | `hotReloadCompilerNotFound` | The `hotReloadCompilerId` does not exist in this workspace. |
| 6101 | `hotReloadRejected` | The hot reload request was rejected by the compiler. |
| 7001 | `pubCommandFailed` | The pub command failed to execute successfully. |
| 7064 | `pubUsage` | The command was used incorrectly. |
| 7065 | `pubData` | The input data was incorrect. |
| 7066 | `pubNoInput` | An input file did not exist or was unreadable. |
| 7067 | `pubNoUser` | The user specified did not exist. |
| 7068 | `pubNoHost` | The host specified did not exist. |
| 7069 | `pubUnavailable` | A service is unavailable. |
| 7070 | `pubSoftware` | An internal software error has been detected. |
| 7071 | `pubOs` | An operating system error has been detected. |
| 7072 | `pubOsFile` | Some system file did not exist or was unreadable. |
| 7073 | `pubCantCreate` | A user-specified output file cannot be created. |
| 7074 | `pubIo` | An error occurred while doing I/O on some file. |
| 7075 | `pubTempFail` | Temporary failure, indicating something that is not really an error. |
| 7076 | `pubProtocol` | The remote system returned something invalid during a protocol exchange. |
| 7077 | `pubNoPerm` | The user did not have sufficient permissions. |
| 7078 | `pubConfig` | Something was unconfigured or mis-configured. |
| 8001 | `moduleLoaderNotAvailable` | The DDC module loader is has not been loaded into the sandbox. |
| 8002 | `flutterLoaderNotAvailable` | The flutter loader has not been loaded into the sandbox. |
| 8100 | `moduleLoadingFailed` | Failed to load module into the sandbox. |
| 8200 | `executionFailed` | Error happened when running `main()` from user-code. |
| 8300 | `hotRestartFailed` | Hot-restart failed. |
| 8400 | `hotReloadFailed` | Hot-reload failed. |
<!-- END GENERATED ERROR CODE TABLE -->
[1]: https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker
[2]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort
[3]: https://www.jsonrpc.org/specification