Deno
Deno provides an API to run JavaScript/TypeScript in non-browser environment with more access to system resources, but still within a sandbox.
API and Permissions
All Deno permissions must be explicitly declared in package.json
.
DenoCommand
works similarly to a regular shell Command. It can be created with shell.createDenoCommand
.
The returned DenoCommand
object has execute
and spawn
methods (just like regular Command
).
To run a Deno command, you need one of the the following scoped permissions:
shell:deno:execute
shell:deno:spawn
Read sample code for more details.
RPC Library Style API
If you’re looking to run Deno as a library for resource-intensive tasks or those requiring system access, the Deno API offers a solution. You can execute Deno scripts using
shell.createDenoCommand
, passing input throughargv
andstdin
, and retrieving results viastdout
andstderr
. This approach essentially treats Deno like a CLI, as illustrated in an example (Transform Image with Sharp) provided below. However, using a CLI is not always ideal for those who prefer calling scripts directly like a typical library. The@kksh/api
solves this by offering an abstraction in RPC style, allowing Deno scripts to be invoked as libraries rather than CLIs.
The shell API provides a function siganture createDenoRpcChannel
that creates a Deno RPC API.
Then you can call the remote API functions directly.
- Since this is a bidirectional IPC channel, you can pass
LocalAPI
andRemoteAPI
generics to define the API.LocalAPI
is what you want to expose to the other side of the channel, andRemoteAPI
is what you want to call from the other side.
args
areargv
like regular commandsconfig
is the same as config inshell.createDenoCommand
, used for configuring deno permissions and other options.localAPIImplementation
is the implementation of the API you want to expose, pass{}
if you don’t want to expose any API.
Suppose we want to build a math library in Deno and call it from extension running in web worker or iframe.
Here is how the library will be written in Deno. Just provide an API object.
Deno Script
I recommend use a separate subdirectory for Deno scripts to avoid confusion with regular extension code. I will use deno-src
in this example.
This will create a import map in deno.json
Kunkun’s API package for Deno is on JSR, https://jsr.io/@kunkun/api
Note: the scope is @kunkun
rather than @kksh
. This is because @kunkun
scope was taken on npm registry.
expose
function is provided by @kunkun/api/runtime/deno
to expose the API object to its parent process.
expose()
is a wrapper function for building a bidirectional RPC channel. It returns the RPCChannel
object,
which can be used to call API exposed from the other side of the channel.
Manual Channel Configuration
You shouldn’t need to worry about how the channel is created, but here is how it’s done manually.
It’s based on @hk/comlink-stdio
package, see https://jsr.io/@hk/comlink-stdio
Extension Code
In main extension code, use shell.createDenoRpcChannel
to start running a Deno script and get the API object.
Sample Code
Transform Image with Sharp
In this sample, we will transform an image with sharp, which is not runnable in browser.
Suppose we have a template worker extension project with the following structure:
Directorysrc
- deno-script.ts
- index.ts
- …
index.ts
is the entrypoint to the extension command, deno-script.ts
is a script that will be executed by Deno.
The deno script above is very simple, it takes in an input image path and output image path, then apply blur and resize and save to output path.
To run this sample directly with deno
:
In the command above, we need to grant fine-grained permissions to Deno. It’s not a good idea to run Deno with all permissions.
Use Deno API
In the following sample code, we will use shell.createDenoCommand
to create a Deno command with permission settings.
See https://docs.api.kunkun.sh/interfaces/ui.DenoRunConfig for options you can pass to shell.createDenoCommand
.
The above TypeScript code sets CWD to the desktop directory, but you don’t have to. You can always just compute the absolute path for the input and output file.
$EXTENSION
was used to refer to the directory of the extension. It will be translated to the real path of your extension root at runtime.
$DESKTOP
is also a path alias that will be translated to the real path of your desktop at runtime.
You can find other path aliases in file system API.
Permissions in package.json
To ensure that an extension operates within a restricted scope, it must declare the necessary permissions in the package.json
file.
This step prevents the extension from executing any code beyond the predefined limits.
path
is the path to the deno script to execute.
The rest of the permissions are from Deno permissions.
net
env
read
write
run
ffi
sys
They are string[]
or "*"
, when set to "*"
, it allows all.
For example, setting "read": "*"
allows setting allowAllRead
to true in shell.createDenoCommand
, and will be translated to --allow-read
in the code execution.
Setting "read": ["$DESKTOP"]
allows you to set allowRead: ["$DESKTOP"]
in shell.createDenoCommand
, and will be translated to --allow-read=/Users/user/Desktop
in the code execution.