Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a0e515d
wip
chrisdickinson Oct 20, 2023
e14d0f8
fix(build): ubuntu base64 requires flag for single-line output
chrisdickinson Oct 26, 2023
a86b31b
feat: add bun support
chrisdickinson Oct 26, 2023
a3c5354
fix: remove paths with ":"; windows does not support them
chrisdickinson Oct 27, 2023
6a07590
fix(build): do not install bun on windows
chrisdickinson Oct 27, 2023
ed07db7
fix(build): just-install npm pkg does not work on windows; use gh action
chrisdickinson Oct 27, 2023
23d2ff6
fix(build): use lts node version (>=20)
chrisdickinson Oct 27, 2023
e4b9e8d
fix(ci): remove install/build steps
chrisdickinson Oct 27, 2023
fd00386
fix(build): remove shasum call from build
chrisdickinson Oct 27, 2023
1a370d5
rename "offMainThread" -> "runInWorker"
chrisdickinson Oct 27, 2023
fe5ade3
fix: add formatting, lint examples, skip tests if WebAssembly is not …
chrisdickinson Oct 27, 2023
8cc03d3
wip: gate bun test for windows
chrisdickinson Oct 27, 2023
8abff83
doc: improve typedocs; rename features->capabilities
chrisdickinson Oct 27, 2023
499277a
feat: implement PluginOutput + extism var get/set
chrisdickinson Oct 30, 2023
452d285
feat: implement basic http calls
chrisdickinson Oct 31, 2023
4ad57e2
fix: remove old check for runtime module
chrisdickinson Oct 31, 2023
e358ee4
fix: lint & format
chrisdickinson Oct 31, 2023
78f13e2
fix(test): add test for host fn calls that span many SAB pages
chrisdickinson Nov 2, 2023
e007466
fix: return {async, value} from AtomicsWaitAsync polyfill in firefox
chrisdickinson Nov 2, 2023
5327535
feat: add Plugin#reset; implement allowedHosts
chrisdickinson Nov 7, 2023
bf80714
fix: correct race condition on certain block offsets
chrisdickinson Nov 7, 2023
40d0583
feat: alias createPlugin as newPlugin for folks coming from other ext…
chrisdickinson Nov 7, 2023
faf9ebb
fix: s/DYLIBSO_ENV/EXTISM_ENV/g
chrisdickinson Nov 8, 2023
7354013
fix: support node v18
chrisdickinson Nov 8, 2023
a31aa1b
fix: update readme
chrisdickinson Nov 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .eslintrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
env:
browser: true
es2021: true
node: true
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended']
parser: '@typescript-eslint/parser'
root: true
ignorePatterns: ["oldsrc/", "tests/mod.test.ts", "tests/index.test.ts"]
rules:
no-constant-condition: 'off'
no-unused-vars: 'off'
'@typescript-eslint/no-unused-vars':
- 'error'
- argsIgnorePattern: '_.*'
varsIgnorePattern: '_.*'
'@typescript-eslint/no-explicit-any': 'off'
31 changes: 15 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,19 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: Setup Node.js environment
uses: actions/setup-node@v3.8.1

- name: Setup Deno
uses: denoland/setup-deno@v1.1.2

- name: NPM install
run: npm ci

- name: Build
run: npm run build

- name: Node Test
- uses: extractions/setup-just@v1

- uses: actions/setup-node@v3.8.1
with:
node-version: lts/*
check-latest: true

- uses: denoland/setup-deno@v1.1.2

- uses: oven-sh/setup-bun@v1
if: ${{ matrix.os != 'windows-latest' }}
with:
bun-version: latest

- name: Test
run: npm run test

- name: Deno Test
run: deno test -A ./tests/mod.test.ts
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# test artifacts
tests/artifacts

# generated docs
docs/

# Logs
logs
*.log
Expand Down
6 changes: 3 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"deno.lint": true,
"deno.unstable": true,
"deno.enablePaths": [
"./src/deno/mod.ts",
"./src/mod.ts",
"./examples/deno.ts",
"./tests/mod.test.ts"
"./src/mod.test.ts"
]
}
}
115 changes: 115 additions & 0 deletions DEVELOPING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Developing

## The build process

The Extism SDK targets several platforms:

- Deno
- Node ECMAScript Modules ("ESM")
- Node CommonJS Modules ("CJS")
- Browser ECMAScript Modules

The source of this library is written as valid TypeScript, which may be
consumed and run directly by Deno. The latter three platforms are treated as
compile targets. There are two other compile targets:

- The source of the [Worker](https://mdn.io/worker), compiled for the browser.
- The source of the [Worker](https://mdn.io/worker), compiled for node.
- Tests

For compiled targets, the worker is compiled to a single artifact with an entry
point starting at `src/worker.ts`, base64-encoded, and included in the
resulting artifact.

Builds are orchestrated by the `justfile` and `esbuild`: each build target recipe accepts
incoming `esbuild` flags as an array of JSON data and prepends its own configuration.
This allows dependent recipes to override earlier flags. An annotated example:

```
build_worker_browser out='worker/browser' args='[]': # <-- we accept args and an out dir
#!/bin/bash
config="$(<<<'{{ args }}' jq -cM '
[{
"format": "esm",
"alias": {
"js-sdk:capabilities": "./src/polyfills/browser-capabilities.ts",
"node:worker_threads": "./src/polyfills/worker-node-worker_threads.ts",
"js-sdk:fs": "./src/polyfills/browser-fs.ts",
"js-sdk:wasi": "./src/polyfills/browser-wasi.ts",
}
}] + . # <--- add this recipe's flags to the incoming flags.
')"
just build_worker {{ out }} "$config"
```

There is a `_build` recipe that all other build targets depend on, at
varying degrees of indirection. This `_build` fixes all Deno-style `.ts`
import statements, invokes `esbuild`, and emits TypeScript declarations
via `tsc`.

### Polyfills

We use `esbuild` to compile to these targets. This allows us to abstract
differences at module boundaries and replace them as-needed. For example: each
of Node, Deno, and the Browser have different WASI libraries with slightly different
interfaces. We define a **virtual module**, `js-sdk:wasi`, and implement it by:

1. Modifying `deno.json`; adding a mapping from `js-sdk:wasi` to `./src/polyfills/deno-wasi.ts`.
2. Adding a `types/js-sdk:wasi/index.d.ts` file.
3. Modifying the esbuild `alias` added by `build_worker`, `build_worker_node`,
`build_node_cjs`, `build_node_esm`, and `build_browser`.
- Node overrides are set to `./src/polyfills/node-wasi.ts`.
- Browser overrides are set to `./src/polyfills/browser-wasi.ts`.

In this manner, differences between the platforms are hidden and the core of
the library can be written in "mutually intelligble" TypeScript.

One notable exception to this rule: Deno implements Node polyfills; for
complicated imports, like `node:worker_threads`, we instead only polyfill the
browser. The browser polyfill is split into `host:node:worker_threads.ts` and
`worker-node-worker_threads.ts`: these polyfill just enough of the Node worker
thread API over the top of builtin workers to make them adhere to the same
interface.

### Testing

Tests are co-located with source code, using the `*.test.ts` pattern. Tests
are run in three forms:

- Interpreted, via `deno test -A`
- Compiled, via `node --test`
- And via playwright, which polyfills `node:test` using `tape` and runs tests
across firefox, webkit, and chromium.

The `assert` API is polyfilled in browser using
[`rollup-plugin-polyfill-node`](https://npm.im/rollup-plugin-polyfill-node).
This polyfill doesn't track Node's APIs very closely, so it's best to stick to
simple assertions (`assert.equal`.)

## The Extism runtime, shared memory, and worker threads

This SDK defaults to running on background threads in contexts where that is
feasible. Host functions require this library to share memory between the main
and worker threads, however. The rules on transferring buffers are as follows:

- ArrayBuffers may be transferred asynchronously between main and worker threads. Once
transferred they may no longer be accessed on the sending thread.
- SharedArrayBuffers may be sent _only_ from the main thread. (All browsers allow
the creation of SharedArrayBuffers off of the main thread, but Chromium disallows
_sending_ those SharedArrayBuffers to the main thread from the worker.)
- Browser environments disallow using `TextDecoder` against typed arrays backed by
SharedArrayBuffers. The Extism library handles this transparently by copying out
of shared memory.

These rules make navigating memory sharing fairly tricky compared to other SDK platforms.
As a result, the JS SDK includes its own extism runtime, which:

- Reserves 16 bits of address space for "page id" information, leaving 48 bits per "page"
of allocated memory.
- Creates sharedarraybuffers on the worker thread and shares them with the worker thread on
`call()`.
- Worker-originated pages are transferred up to the main thread and copied into sharedarraybuffers
whenever the worker transfers control to the main thread (whether returning from a `call()` or
calling a `hostfn`.)
- When new pages are created during the execution of a `hostfn`, they will be
_copied down_ to the worker thread using a 64KiB scratch space.
32 changes: 0 additions & 32 deletions Makefile

This file was deleted.

Loading