diff --git a/.eslintrc.yaml b/.eslintrc.yaml new file mode 100644 index 0000000..31be2f8 --- /dev/null +++ b/.eslintrc.yaml @@ -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' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9250b4b..4c17809 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/.gitignore b/.gitignore index c6bba59..2bdeaf4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ +# test artifacts +tests/artifacts + +# generated docs +docs/ + # Logs logs *.log diff --git a/.vscode/settings.json b/.vscode/settings.json index 938a8f6..bfbab2b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" ] -} \ No newline at end of file +} diff --git a/DEVELOPING.md b/DEVELOPING.md new file mode 100644 index 0000000..cd5c7a1 --- /dev/null +++ b/DEVELOPING.md @@ -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. diff --git a/Makefile b/Makefile deleted file mode 100644 index dbb4807..0000000 --- a/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -.PHONY: test - -prepare: - npm install - -build: - npm run build - -test: prepare - npm run test - deno test -A .\tests\mod.test.ts - -clean: - echo "No clean implemented" - -publish: clean prepare build - npm publish - -format: - npx prettier --write src - -lint: - npx prettier --check src - -docs: - npx typedoc --out doc src - -show-docs: docs - open doc/index.html - -update-kernel: - node update-kernel.js \ No newline at end of file diff --git a/README.md b/README.md index 3109f36..7aef8bb 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,9 @@ > **Note**: This houses the 1.0 version of the JavaScript SDK and is a work in progress. Please use the [Node SDK](https://github.com/extism/extism/tree/main/node) or the [Browser SDK](https://github.com/extism/extism/tree/main/browser) in extism/extism until we hit 1.0. -This is a universal JavaScript SDK for Extism. We are aiming for it to work in all the major -JavaScript runtimes: +This is a universal JavaScript SDK for Extism. It works in all the major JavaScript runtimes: -* Browsers +* Browsers (Firefox, Chrome, WebKit) * Node * Deno * Bun @@ -21,6 +20,18 @@ npm install @extism/extism@1.0.0-rc1 --save > **Note**: Keep in mind we will possibly have breaking changes b/w rc versions until we hit 1.0. +## Compatibility + +- **Node.js**: `v18+` (with `--experimental-global-webcrypto`); `v20` with no additional flags +- **Deno**: `v1.36+` +- **Bun**: Tested on `v1.0.7`; Bun partially implements WASI. + +Browser tests are run using [playwright](https://playwright.dev)'s defaults. In +browsers, background thread support requires `SharedArrayBuffer` and `Atomic` +support. This is only available in +[`crossOriginIsolated`](https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated) +contexts. + ## Getting Started This guide should walk you through some of the concepts in Extism and this JS library. @@ -34,7 +45,7 @@ const createPlugin = require("@extism/extism") import createPlugin from '@extism/extism'; // Deno -import createPlugin from 'https://raw.githubusercontent.com/extism/js-sdk/main/src/deno/mod.ts'; +import createPlugin from 'https://raw.githubusercontent.com/extism/js-sdk/main/src/mod.ts'; ``` ## Creating A Plug-in @@ -44,49 +55,55 @@ The primary concept in Extism is the [plug-in](https://extism.org/docs/concepts/ Plug-in code can come from a file on disk, object storage or any number of places. Since you may not have one handy let's load a demo plug-in from the web: ```js -const wasm = { - url: 'https://github.com/extism/plugins/releases/latest/download/count_vowels.wasm' -} - -const plugin = await createPlugin(wasm, { - // NOTE: If you get an error like "TypeError: WebAssembly.instantiate(): Import #0 module="wasi_snapshot_preview1": module is not an object or function", then your plugin requires WASI support - useWasi: true, +const plugin = await createPlugin( + 'https://github.com/extism/plugins/releases/latest/download/count_vowels.wasm', + { useWasi: true } }); ``` ## Calling A Plug-in's Exports -This plug-in was written in Rust and it does one thing, it counts vowels in a string. As such, it exposes one "export" function: `count_vowels`. We can call exports using `ExtismPlugin.call`: +We're using a plug-in, `count_vowels`, which was compiled from Rust. +`count_vowels` plug-in does one thing: it counts vowels in a string. As such, +it exposes one "export" function: `count_vowels`. We can call exports using +`Plugin.call`: ```js -let out = await plugin.call("count_vowels", new TextEncoder().encode(input)); -console.log(new TextDecoder().decode(out.buffer)) +let out = await plugin.call("count_vowels", input); +console.log(out.text()) // => {"count": 3, "total": 3, "vowels": "aeiouAEIOU"} ``` -All exports have a simple interface of optional bytes in, and optional bytes out. This plug-in happens to take a string and return a JSON encoded string with a report of results. +All plug-in exports have a simple interface of optional bytes in, and optional +bytes out. This plug-in happens to take a string and return a JSON encoded +string with a report of results. ### Plug-in State -Plug-ins may be stateful or stateless. Plug-ins can maintain state b/w calls by the use of variables. Our count vowels plug-in remembers the total number of vowels it's ever counted in the "total" key in the result. You can see this by making subsequent calls to the export: +Plug-ins may be stateful or stateless. Plug-ins can maintain state between calls by +the use of variables. Our `count_vowels` plug-in remembers the total number of +vowels it's ever counted in the `total` key in the result. You can see this by +making subsequent calls to the export: ```js -let out = await plugin.call("count_vowels", new TextEncoder().encode("Hello, World!")); -console.log(new TextDecoder().decode(out.buffer)) - +let out = await plugin.call("count_vowels", "Hello, World!"); +console.log(out.text()) // => {"count": 3, "total": 9, "vowels": "aeiouAEIOU"} -out = await plugin.call("count_vowels", new TextEncoder().encode("Hello, World!")); -console.log(new TextDecoder().decode(out.buffer)) +out = await plugin.call("count_vowels", "Hello, World!"); +console.log(out.json()) // => {"count": 3, "total": 9, "vowels": "aeiouAEIOU"} ``` -These variables will persist until this plug-in is freed or you initialize a new one. +These variables will persist until you call `await plugin.reset()`. Variables +are not shared between plugin instances. ### Configuration -Plug-ins may optionally take a configuration object. This is a static way to configure the plug-in. Our count-vowels plugin takes an optional configuration to change out which characters are considered vowels. Example: +Plug-ins may optionally take a configuration object. This is a static way to +configure the plug-in. Our count-vowels plugin takes an optional configuration +to change out which characters are considered vowels. Example: ```js const wasm = { @@ -97,8 +114,8 @@ let plugin = await createPlugin(wasm, { useWasi: true, }); -let out = await plugin.call("count_vowels", new TextEncoder().encode("Yellow, World!")); -console.log(new TextDecoder().decode(out.buffer)) +let out = await plugin.call("count_vowels", "Yellow, World!"); +console.log(out.text()) // => {"count": 3, "total": 3, "vowels": "aeiouAEIOU"} plugin = await createPlugin(wasm, { @@ -106,20 +123,27 @@ plugin = await createPlugin(wasm, { config: { "vowels": "aeiouyAEIOUY" } }); -out = await plugin.call("count_vowels", new TextEncoder().encode("Yellow, World!")); -console.log(new TextDecoder().decode(out.buffer)) +out = await plugin.call("count_vowels", "Yellow, World!"); +console.log(out.text()) // => {"count": 4, "total": 4, "vowels": "aeiouAEIOUY"} ``` ### Host Functions -Let's extend our count-vowels example a little bit: Instead of storing the `total` in an ephemeral plug-in var, let's store it in a persistent key-value store! +Let's extend our count-vowels example a little bit: Instead of storing the +`total` in an ephemeral plug-in var, let's store it in a persistent key-value +store! -Wasm can't use our KV store on it's own. This is where [Host Functions](https://extism.org/docs/concepts/host-functions) come in. +Wasm can't use our KV store on it's own. This is where [Host +Functions](https://extism.org/docs/concepts/host-functions) come in. -[Host functions](https://extism.org/docs/concepts/host-functions) allow us to grant new capabilities to our plug-ins from our application. They are simply some JS functions you write which can be passed down and invoked from any language inside the plug-in. +[Host functions](https://extism.org/docs/concepts/host-functions) allow us to +grant new capabilities to our plug-ins from our application. They are simply +some JS functions you write which can be passed down and invoked from any +language inside the plug-in. -Let's load the manifest like usual but load up this `count_vowels_kvstore` plug-in: +Let's load the manifest like usual but load up this `count_vowels_kvstore` +plug-in: ```js const wasm = { @@ -127,7 +151,7 @@ const wasm = { } ``` -> *Note*: The source code for this is [here](https://github.com/extism/plugins/blob/main/count_vowels_kvstore/src/lib.rs) and is written in rust, but it could be written in any of our PDK languages. +> *Note*: The source code for this is [here](https://github.com/extism/plugins/blob/main/count_vowels_kvstore/src/lib.rs) and is written in Rust, but it could be written in any of our PDK languages. Unlike our previous plug-in, this plug-in expects you to provide host functions that satisfy our its import interface for a KV store. @@ -139,29 +163,35 @@ let kvStore = new Map(); const options = { useWasi: true, functions: { - "env": { + env: { // NOTE: the first argument is always a CurrentPlugin - "kv_read": function (cp: CurrentPlugin, offs: bigint) { - const key = cp.readString(offs); + kv_read(cp: CurrentPlugin, offs: bigint) { + const key = cp.read(offs).text(); let value = kvStore.get(key) ?? new Uint8Array([0, 0, 0, 0]); console.log(`Read ${new DataView(value.buffer).getUint32(0, true)} from key=${key}`); - return cp.writeBytes(value); + return cp.store(value); }, - "kv_write": function (cp: CurrentPlugin, kOffs: bigint, vOffs: bigint) { // this: CurrentPlugin - const key = cp.readString(kOffs); - const value = cp.readBytes(vOffs); - console.log(`Writing value=${new DataView(value.buffer).getUint32(0, true)} from key=${key}`); + kv_write(cp: CurrentPlugin, kOffs: bigint, vOffs: bigint) { + const key = cp.read(kOffs).text(); + + // Value is a PluginOutput, which subclasses DataView. Along + // with the `text()` and `json()` methods we've seen, we also + // get DataView methods, such as `getUint32`. + const value = cp.read(vOffs); + console.log(`Writing value=${new value.getUint32(0, true)} from key=${key}`); - kvStore.set(key, value); + kvStore.set(key, value.bytes()); } } } }; ``` -> *Note*: In order to write host functions you should get familiar with the methods on the `CurrentPlugin` type. `this` is bound to an instance of `CurrentPlugin`. +> *Note*: In order to write host functions you should get familiar with the +> methods on the `CurrentPlugin` type. -We need to pass these imports to the plug-in to create them. All imports of a plug-in must be satisfied for it to be initialized: +We need to pass these imports to the plug-in to create them. All imports of a +plug-in must be satisfied for it to be initialized: ```js const plugin = await createPlugin(wasm, options); @@ -170,14 +200,14 @@ const plugin = await createPlugin(wasm, options); Now we can invoke the event: ```js -let out = await plugin.call("count_vowels", new TextEncoder().encode("Hello World!")); -console.log(new TextDecoder().decode(out.buffer)) +let out = await plugin.call("count_vowels", "Hello World!"); +console.log(out.text()) // => Read from key=count-vowels" // => Writing value=3 from key=count-vowels" // => {"count": 3, "total": 3, "vowels": "aeiouAEIOU"} -out = await plugin.call("count_vowels", new TextEncoder().encode("Hello World!")); -console.log(new TextDecoder().decode(out.buffer)) +out = await plugin.call("count_vowels", "Hello World!"); +console.log(out.text()) // => Read from key=count-vowels" // => Writing value=6 from key=count-vowels" // => {"count": 3, "total": 6, "vowels": "aeiouAEIOU"} @@ -194,11 +224,3 @@ deno run -A ./examples/deno.ts ./wasm/config.wasm bun run ./examples/node.js wasm/config.wasm ``` - -## Update `extism-kernel.wasm`: - -We are shipping an embedded kernel in base64 form in plugin.ts. To update it, you can run: - -``` -make update-kernel -``` diff --git a/build.js b/build.js deleted file mode 100644 index 82d9817..0000000 --- a/build.js +++ /dev/null @@ -1,28 +0,0 @@ -const { build } = require("esbuild"); -const { peerDependencies } = require('./package.json') - -const sharedConfig = { - bundle: true, - minify: true, - drop: [], // preseve debugger statements - external: Object.keys(peerDependencies || {}), -}; - -// NodeJS CSJ -build({ - ...sharedConfig, - entryPoints: ["src/node/index.ts"], - platform: 'node', // for CJS - outfile: "dist/node/index.js", - external: [ './src/mod.ts', "sync-fetch", "child_process" ] -}); - -// Browser ESM -build({ - ...sharedConfig, - entryPoints: ["src/browser/index.ts"], - outfile: "dist/browser/index.mjs", - platform: 'neutral', - external: [ './src/mod.ts', "sync-fetch", "child_process" ], - format: "esm", -}); \ No newline at end of file diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..8e9f546 --- /dev/null +++ b/deno.json @@ -0,0 +1,9 @@ +{ + "imports": { + "js-sdk:worker-url": "./src/worker-url.ts", + "js-sdk:minimatch": "./src/polyfills/deno-minimatch.ts", + "js-sdk:capabilities": "./src/polyfills/deno-capabilities.ts", + "js-sdk:wasi": "./src/polyfills/deno-wasi.ts", + "js-sdk:fs": "./src/polyfills/node-fs.ts" + } +} diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..221205f --- /dev/null +++ b/deno.lock @@ -0,0 +1,99 @@ +{ + "version": "3", + "packages": { + "specifiers": { + "npm:@types/node": "npm:@types/node@18.16.19" + }, + "npm": { + "@types/node@18.16.19": { + "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", + "dependencies": {} + } + } + }, + "redirects": { + "https://deno.land/std/path/mod.ts": "https://deno.land/std@0.204.0/path/mod.ts" + }, + "remote": { + "https://deno.land/std@0.200.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", + "https://deno.land/std@0.200.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", + "https://deno.land/std@0.200.0/path/_relative.ts": "27bdeffb5311a47d85be26d37ad1969979359f7636c5cd9fcf05dcd0d5099dc5", + "https://deno.land/std@0.200.0/path/_resolve.ts": "7a3616f1093735ed327e758313b79c3c04ea921808ca5f19ddf240cb68d0adf6", + "https://deno.land/std@0.200.0/path/_util.ts": "4e191b1bac6b3bf0c31aab42e5ca2e01a86ab5a0d2e08b75acf8585047a86221", + "https://deno.land/std@0.200.0/path/relative.ts": "7db80c5035016174267da16321a742d76e875215c317859a383b12f413c6f5d6", + "https://deno.land/std@0.200.0/path/resolve.ts": "103b62207726a27f28177f397008545804ecb20aaf00623af1f622b18cd80b9f", + "https://deno.land/std@0.200.0/wasi/snapshot_preview1.ts": "25c18c35df4ba5755b059d3e178f3478ff210dc7fe7baef12e495cf2ed0a8b13", + "https://deno.land/std@0.204.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", + "https://deno.land/std@0.204.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", + "https://deno.land/std@0.204.0/path/_common/assert_path.ts": "061e4d093d4ba5aebceb2c4da3318bfe3289e868570e9d3a8e327d91c2958946", + "https://deno.land/std@0.204.0/path/_common/basename.ts": "0d978ff818f339cd3b1d09dc914881f4d15617432ae519c1b8fdc09ff8d3789a", + "https://deno.land/std@0.204.0/path/_common/common.ts": "9e4233b2eeb50f8b2ae10ecc2108f58583aea6fd3e8907827020282dc2b76143", + "https://deno.land/std@0.204.0/path/_common/constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", + "https://deno.land/std@0.204.0/path/_common/dirname.ts": "2ba7fb4cc9fafb0f38028f434179579ce61d4d9e51296fad22b701c3d3cd7397", + "https://deno.land/std@0.204.0/path/_common/format.ts": "11aa62e316dfbf22c126917f5e03ea5fe2ee707386555a8f513d27ad5756cf96", + "https://deno.land/std@0.204.0/path/_common/from_file_url.ts": "ef1bf3197d2efbf0297a2bdbf3a61d804b18f2bcce45548ae112313ec5be3c22", + "https://deno.land/std@0.204.0/path/_common/glob_to_reg_exp.ts": "5c3c2b79fc2294ec803d102bd9855c451c150021f452046312819fbb6d4dc156", + "https://deno.land/std@0.204.0/path/_common/is_glob.ts": "567dce5c6656bdedfc6b3ee6c0833e1e4db2b8dff6e62148e94a917f289c06ad", + "https://deno.land/std@0.204.0/path/_common/normalize.ts": "2ba7fb4cc9fafb0f38028f434179579ce61d4d9e51296fad22b701c3d3cd7397", + "https://deno.land/std@0.204.0/path/_common/normalize_string.ts": "88c472f28ae49525f9fe82de8c8816d93442d46a30d6bb5063b07ff8a89ff589", + "https://deno.land/std@0.204.0/path/_common/relative.ts": "1af19d787a2a84b8c534cc487424fe101f614982ae4851382c978ab2216186b4", + "https://deno.land/std@0.204.0/path/_common/strip_trailing_separators.ts": "7ffc7c287e97bdeeee31b155828686967f222cd73f9e5780bfe7dfb1b58c6c65", + "https://deno.land/std@0.204.0/path/_common/to_file_url.ts": "a8cdd1633bc9175b7eebd3613266d7c0b6ae0fb0cff24120b6092ac31662f9ae", + "https://deno.land/std@0.204.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", + "https://deno.land/std@0.204.0/path/_os.ts": "30b0c2875f360c9296dbe6b7f2d528f0f9c741cecad2e97f803f5219e91b40a2", + "https://deno.land/std@0.204.0/path/basename.ts": "04bb5ef3e86bba8a35603b8f3b69537112cdd19ce64b77f2522006da2977a5f3", + "https://deno.land/std@0.204.0/path/common.ts": "f4d061c7d0b95a65c2a1a52439edec393e906b40f1caf4604c389fae7caa80f5", + "https://deno.land/std@0.204.0/path/dirname.ts": "88a0a71c21debafc4da7a4cd44fd32e899462df458fbca152390887d41c40361", + "https://deno.land/std@0.204.0/path/extname.ts": "2da4e2490f3b48b7121d19fb4c91681a5e11bd6bd99df4f6f47d7a71bb6ecdf2", + "https://deno.land/std@0.204.0/path/format.ts": "3457530cc85d1b4bab175f9ae73998b34fd456c830d01883169af0681b8894fb", + "https://deno.land/std@0.204.0/path/from_file_url.ts": "e7fa233ea1dff9641e8d566153a24d95010110185a6f418dd2e32320926043f8", + "https://deno.land/std@0.204.0/path/glob.ts": "9c77cf47db1d786e2ebf66670824d03fd84ecc7c807cac24441eb9d5cb6a2986", + "https://deno.land/std@0.204.0/path/is_absolute.ts": "67232b41b860571c5b7537f4954c88d86ae2ba45e883ee37d3dec27b74909d13", + "https://deno.land/std@0.204.0/path/join.ts": "98d3d76c819af4a11a81d5ba2dbb319f1ce9d63fc2b615597d4bcfddd4a89a09", + "https://deno.land/std@0.204.0/path/mod.ts": "2d62a0a8b78a60e8e6f485d881bac6b61d58573b11cf585fb7c8fc50d9b20d80", + "https://deno.land/std@0.204.0/path/normalize.ts": "aa95be9a92c7bd4f9dc0ba51e942a1973e2b93d266cd74f5ca751c136d520b66", + "https://deno.land/std@0.204.0/path/parse.ts": "d87ff0deef3fb495bc0d862278ff96da5a06acf0625ca27769fc52ac0d3d6ece", + "https://deno.land/std@0.204.0/path/posix/_util.ts": "ecf49560fedd7dd376c6156cc5565cad97c1abe9824f4417adebc7acc36c93e5", + "https://deno.land/std@0.204.0/path/posix/basename.ts": "a630aeb8fd8e27356b1823b9dedd505e30085015407caa3396332752f6b8406a", + "https://deno.land/std@0.204.0/path/posix/common.ts": "e781d395dc76f6282e3f7dd8de13194abb8b04a82d109593141abc6e95755c8b", + "https://deno.land/std@0.204.0/path/posix/dirname.ts": "f48c9c42cc670803b505478b7ef162c7cfa9d8e751b59d278b2ec59470531472", + "https://deno.land/std@0.204.0/path/posix/extname.ts": "ee7f6571a9c0a37f9218fbf510c440d1685a7c13082c348d701396cc795e0be0", + "https://deno.land/std@0.204.0/path/posix/format.ts": "b94876f77e61bfe1f147d5ccb46a920636cd3cef8be43df330f0052b03875968", + "https://deno.land/std@0.204.0/path/posix/from_file_url.ts": "b97287a83e6407ac27bdf3ab621db3fccbf1c27df0a1b1f20e1e1b5acf38a379", + "https://deno.land/std@0.204.0/path/posix/glob.ts": "86c3f06d1c98303613c74650961c3e24bdb871cde2a97c3ae7f0f6d4abbef445", + "https://deno.land/std@0.204.0/path/posix/is_absolute.ts": "159900a3422d11069d48395568217eb7fc105ceda2683d03d9b7c0f0769e01b8", + "https://deno.land/std@0.204.0/path/posix/join.ts": "0c0d84bdc344876930126640011ec1b888e6facf74153ffad9ef26813aa2a076", + "https://deno.land/std@0.204.0/path/posix/mod.ts": "6bfa8a42d85345b12dbe8571028ca2c62d460b6ef968125e498602b43b6cf6b6", + "https://deno.land/std@0.204.0/path/posix/normalize.ts": "11de90a94ab7148cc46e5a288f7d732aade1d616bc8c862f5560fa18ff987b4b", + "https://deno.land/std@0.204.0/path/posix/parse.ts": "199208f373dd93a792e9c585352bfc73a6293411bed6da6d3bc4f4ef90b04c8e", + "https://deno.land/std@0.204.0/path/posix/relative.ts": "e2f230608b0f083e6deaa06e063943e5accb3320c28aef8d87528fbb7fe6504c", + "https://deno.land/std@0.204.0/path/posix/resolve.ts": "51579d83159d5c719518c9ae50812a63959bbcb7561d79acbdb2c3682236e285", + "https://deno.land/std@0.204.0/path/posix/separator.ts": "0b6573b5f3269a3164d8edc9cefc33a02dd51003731c561008c8bb60220ebac1", + "https://deno.land/std@0.204.0/path/posix/to_file_url.ts": "08d43ea839ee75e9b8b1538376cfe95911070a655cd312bc9a00f88ef14967b6", + "https://deno.land/std@0.204.0/path/posix/to_namespaced_path.ts": "c9228a0e74fd37e76622cd7b142b8416663a9b87db643302fa0926b5a5c83bdc", + "https://deno.land/std@0.204.0/path/relative.ts": "23d45ede8b7ac464a8299663a43488aad6b561414e7cbbe4790775590db6349c", + "https://deno.land/std@0.204.0/path/resolve.ts": "5b184efc87155a0af9fa305ff68a109e28de9aee81fc3e77cd01380f19daf867", + "https://deno.land/std@0.204.0/path/separator.ts": "40a3e9a4ad10bef23bc2cd6c610291b6c502a06237c2c4cd034a15ca78dedc1f", + "https://deno.land/std@0.204.0/path/to_file_url.ts": "edaafa089e0bce386e1b2d47afe7c72e379ff93b28a5829a5885e4b6c626d864", + "https://deno.land/std@0.204.0/path/to_namespaced_path.ts": "cf8734848aac3c7527d1689d2adf82132b1618eff3cc523a775068847416b22a", + "https://deno.land/std@0.204.0/path/windows/_util.ts": "f32b9444554c8863b9b4814025c700492a2b57ff2369d015360970a1b1099d54", + "https://deno.land/std@0.204.0/path/windows/basename.ts": "8a9dbf7353d50afbc5b221af36c02a72c2d1b2b5b9f7c65bf6a5a2a0baf88ad3", + "https://deno.land/std@0.204.0/path/windows/common.ts": "e781d395dc76f6282e3f7dd8de13194abb8b04a82d109593141abc6e95755c8b", + "https://deno.land/std@0.204.0/path/windows/dirname.ts": "5c2aa541384bf0bd9aca821275d2a8690e8238fa846198ef5c7515ce31a01a94", + "https://deno.land/std@0.204.0/path/windows/extname.ts": "07f4fa1b40d06a827446b3e3bcc8d619c5546b079b8ed0c77040bbef716c7614", + "https://deno.land/std@0.204.0/path/windows/format.ts": "343019130d78f172a5c49fdc7e64686a7faf41553268961e7b6c92a6d6548edf", + "https://deno.land/std@0.204.0/path/windows/from_file_url.ts": "d53335c12b0725893d768be3ac6bf0112cc5b639d2deb0171b35988493b46199", + "https://deno.land/std@0.204.0/path/windows/glob.ts": "0286fb89ecd21db5cbf3b6c79e2b87c889b03f1311e66fb769e6b905d4142332", + "https://deno.land/std@0.204.0/path/windows/is_absolute.ts": "245b56b5f355ede8664bd7f080c910a97e2169972d23075554ae14d73722c53c", + "https://deno.land/std@0.204.0/path/windows/join.ts": "e6600bf88edeeef4e2276e155b8de1d5dec0435fd526ba2dc4d37986b2882f16", + "https://deno.land/std@0.204.0/path/windows/mod.ts": "c3d1a36fbf9f6db1320bcb4fbda8de011d25461be3497105e15cbea1e3726198", + "https://deno.land/std@0.204.0/path/windows/normalize.ts": "9deebbf40c81ef540b7b945d4ccd7a6a2c5a5992f791e6d3377043031e164e69", + "https://deno.land/std@0.204.0/path/windows/parse.ts": "120faf778fe1f22056f33ded069b68e12447668fcfa19540c0129561428d3ae5", + "https://deno.land/std@0.204.0/path/windows/relative.ts": "026855cd2c36c8f28f1df3c6fbd8f2449a2aa21f48797a74700c5d872b86d649", + "https://deno.land/std@0.204.0/path/windows/resolve.ts": "5ff441ab18a2346abadf778121128ee71bda4d0898513d4639a6ca04edca366b", + "https://deno.land/std@0.204.0/path/windows/separator.ts": "ae21f27015f10510ed1ac4a0ba9c4c9c967cbdd9d9e776a3e4967553c397bd5d", + "https://deno.land/std@0.204.0/path/windows/to_file_url.ts": "8e9ea9e1ff364aa06fa72999204229952d0a279dbb876b7b838b2b2fea55cce3", + "https://deno.land/std@0.204.0/path/windows/to_namespaced_path.ts": "e0f4d4a5e77f28a5708c1a33ff24360f35637ba6d8f103d19661255ef7bfd50d", + "https://deno.land/x/minimatch@v3.0.4/index.js": "9325ef4ec1a7e979853cb8dad980d9ee9187cacfdb378599d29b3ae9f431b46d" + } +} diff --git a/examples/deno.ts b/examples/deno.ts old mode 100644 new mode 100755 index 5f061e7..3285199 --- a/examples/deno.ts +++ b/examples/deno.ts @@ -1,19 +1,19 @@ -import createPlugin from '../src/deno/mod.ts' +#!/usr/bin/env deno run -A +import createPlugin from '../src/mod.ts'; -const filename = Deno.args[0] || "wasm/hello.wasm"; -const funcname = Deno.args[1] || "run_test"; -const input = Deno.args[2] || "this is a test"; -const wasm = { - url: filename -} +const filename = Deno.args[0] || 'wasm/hello.wasm'; +const funcname = Deno.args[1] || 'run_test'; +const input = Deno.args[2] || 'this is a test'; -const plugin = await createPlugin(wasm, { - useWasi: true, - config: { - "thing": "testing" - } +const plugin = await createPlugin(filename, { + useWasi: true, + config: { + thing: 'testing', + }, }); const res = await plugin.call(funcname, new TextEncoder().encode(input)); const s = new TextDecoder().decode(res.buffer); -console.log(s) \ No newline at end of file +console.log(s); + +await plugin.close(); diff --git a/examples/index.html b/examples/index.html index dc27dff..73518ca 100644 --- a/examples/index.html +++ b/examples/index.html @@ -1,45 +1,43 @@ - -
- - + + +