Compare commits

..

78 Commits

Author SHA1 Message Date
Steve Manuel
ce67aecf61 ci: add multiple version test strategy for java sdk 2023-01-10 09:14:37 -07:00
dependabot[bot]
9f0e2413e3 chore(deps): Update base64 requirement from 0.20.0-alpha to 0.21.0 (#204)
Updates the requirements on
[base64](https://github.com/marshallpierce/rust-base64) to permit the
latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md">base64's
changelog</a>.</em></p>
<blockquote>
<h1>0.21.0</h1>
<p>(not yet released)</p>
<h2>Migration</h2>
<h3>Functions</h3>
<table>
<thead>
<tr>
<th>&lt; 0.20 function</th>
<th>0.21 equivalent</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>encode()</code></td>
<td><code>engine::general_purpose::STANDARD.encode()</code> or
<code>prelude::BASE64_STANDARD.encode()</code></td>
</tr>
<tr>
<td><code>encode_config()</code></td>
<td><code>engine.encode()</code></td>
</tr>
<tr>
<td><code>encode_config_buf()</code></td>
<td><code>engine.encode_string()</code></td>
</tr>
<tr>
<td><code>encode_config_slice()</code></td>
<td><code>engine.encode_slice()</code></td>
</tr>
<tr>
<td><code>decode()</code></td>
<td><code>engine::general_purpose::STANDARD.decode()</code> or
<code>prelude::BASE64_STANDARD.decode()</code></td>
</tr>
<tr>
<td><code>decode_config()</code></td>
<td><code>engine.decode()</code></td>
</tr>
<tr>
<td><code>decode_config_buf()</code></td>
<td><code>engine.decode_vec()</code></td>
</tr>
<tr>
<td><code>decode_config_slice()</code></td>
<td><code>engine.decode_slice()</code></td>
</tr>
</tbody>
</table>
<p>The short-lived 0.20 functions were the 0.13 functions with
<code>config</code> replaced with <code>engine</code>.</p>
<h3>Padding</h3>
<p>If applicable, use the preset engines <code>engine::STANDARD</code>,
<code>engine::STANDARD_NO_PAD</code>, <code>engine::URL_SAFE</code>,
or <code>engine::URL_SAFE_NO_PAD</code>.
The <code>NO_PAD</code> ones require that padding is absent when
decoding, and the others require that
canonical padding is present .</p>
<p>If you need the &lt; 0.20 behavior that did not care about padding,
or want to recreate &lt; 0.20.0's predefined <code>Config</code>s
precisely, see the following table.</p>
<table>
<thead>
<tr>
<th>0.13.1 Config</th>
<th>0.20.0+ alphabet</th>
<th><code>encode_padding</code></th>
<th><code>decode_padding_mode</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>STANDARD</td>
<td>STANDARD</td>
<td>true</td>
<td>Indifferent</td>
</tr>
<tr>
<td>STANDARD_NO_PAD</td>
<td>STANDARD</td>
<td>false</td>
<td>Indifferent</td>
</tr>
<tr>
<td>URL_SAFE</td>
<td>URL_SAFE</td>
<td>true</td>
<td>Indifferent</td>
</tr>
<tr>
<td>URL_SAFE_NO_PAD</td>
<td>URL_SAFE</td>
<td>false</td>
<td>Indifferent</td>
</tr>
</tbody>
</table>
<h1>0.21.0-rc.1</h1>
<ul>
<li>Restore the ability to decode into a slice of precisely the correct
length with <code>Engine.decode_slice_unchecked</code>.</li>
<li>Add <code>Engine</code> as a <code>pub use</code> in
<code>prelude</code>.</li>
</ul>
<h1>0.21.0-beta.2</h1>
<h2>Breaking changes</h2>
<ul>
<li>Re-exports of preconfigured engines in <code>engine</code> are
removed in favor of <code>base64::prelude::...</code> that are better
suited to those who wish to <code>use</code> the entire path to a
name.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="d7fb31c4ad"><code>d7fb31c</code></a>
v0.21.0</li>
<li><a
href="83503761e9"><code>8350376</code></a>
Merge pull request <a
href="https://github-redirect.dependabot.com/marshallpierce/rust-base64/issues/207">#207</a>
from marshallpierce/mp/api-rework</li>
<li><a
href="726f7841b7"><code>726f784</code></a>
v0.21.0-rc.1</li>
<li><a
href="b29ab0196d"><code>b29ab01</code></a>
Add <code>Engine</code> in <code>prelude</code></li>
<li><a
href="64bbcc02df"><code>64bbcc0</code></a>
Remove no longer needed test helpers</li>
<li><a
href="0f981bd04f"><code>0f981bd</code></a>
Add decode_slice_unchecked to restore ability to decode into a precisely
size...</li>
<li><a
href="a51e822ae9"><code>a51e822</code></a>
v0.21.0-beta.2</li>
<li><a
href="936569a658"><code>936569a</code></a>
Move re-exports from <code>engine</code> to <code>prelude</code></li>
<li><a
href="53e1091e1b"><code>53e1091</code></a>
Fix release notes typo</li>
<li><a
href="b03eb5a84d"><code>b03eb5a</code></a>
v0.21.0-beta.1</li>
<li>Additional commits viewable in <a
href="https://github.com/marshallpierce/rust-base64/compare/v0.20.0-alpha.1...v0.21.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-09 08:59:38 -06:00
dependabot[bot]
5b9e1c1ff6 chore(deps-dev): Bump prettier from 2.8.1 to 2.8.2 in /node (#205)
Bumps [prettier](https://github.com/prettier/prettier) from 2.8.1 to
2.8.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/releases">prettier's
releases</a>.</em></p>
<blockquote>
<h2>2.8.2</h2>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#282">Changelog</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's
changelog</a>.</em></p>
<blockquote>
<h1>2.8.2</h1>
<p><a
href="https://github.com/prettier/prettier/compare/2.8.1...2.8.2">diff</a></p>
<h4>Don't lowercase link references (<a
href="https://github-redirect.dependabot.com/prettier/prettier/pull/13155">#13155</a>
by <a
href="https://github.com/DerekNonGeneric"><code>@​DerekNonGeneric</code></a>
&amp; <a
href="https://github.com/fisker"><code>@​fisker</code></a>)</h4>
<!-- raw HTML omitted -->
<pre lang="markdown"><code>&lt;!-- Input --&gt;
We now don't strictly follow the release notes format suggested by [Keep
a Changelog].
<p>&lt;!-- Prettier 2.8.1 --&gt;
We now don't strictly follow the release notes format suggested by <a
href="https://example.com/">Keep a Changelog</a>.</p>
<p>&lt;!--
^^^^^^^^^^^^^^^^^^ lowercased
--&gt;</p>
<p>&lt;!-- Prettier 2.8.2 --&gt;
&lt;Same as input&gt;
</code></pre></p>
<h4>Preserve self-closing tags (<a
href="https://github-redirect.dependabot.com/prettier/prettier/pull/13691">#13691</a>
by <a
href="https://github.com/dcyriller"><code>@​dcyriller</code></a>)</h4>
<!-- raw HTML omitted -->
<pre lang="hbs"><code>{{! Input }}
&lt;div /&gt;
&lt;div&gt;&lt;/div&gt;
&lt;custom-component /&gt;
&lt;custom-component&gt;&lt;/custom-component&gt;
&lt;i /&gt;
&lt;i&gt;&lt;/i&gt;
&lt;Component /&gt;
&lt;Component&gt;&lt;/Component&gt;
<p>{{! Prettier 2.8.1 }}
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;custom-component&gt;&lt;/custom-component&gt;
&lt;custom-component&gt;&lt;/custom-component&gt;
&lt;i&gt;&lt;/i&gt;
&lt;i&gt;&lt;/i&gt;
&lt;Component /&gt;
&lt;Component /&gt;</p>
<p>{{! Prettier 2.8.2 }}
&lt;/tr&gt;&lt;/table&gt;
</code></pre></p>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ac88438d65"><code>ac88438</code></a>
Release 2.8.2</li>
<li><a
href="aaf919014f"><code>aaf9190</code></a>
Fix comments after directive (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/14081">#14081</a>)</li>
<li><a
href="9e09a78cf5"><code>9e09a78</code></a>
Stop inserting space in LESS property access (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/14103">#14103</a>)</li>
<li><a
href="0c5d4f3458"><code>0c5d4f3</code></a>
Fix removing commas from function arguments in maps (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/14089">#14089</a>)</li>
<li><a
href="b77d912c0c"><code>b77d912</code></a>
ember / glimmer: Preserve self-closing tags (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/13691">#13691</a>)</li>
<li><a
href="cf36209a27"><code>cf36209</code></a>
Handlebars: Add tests for <code>{{! prettier-ignore}}</code> (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/13693">#13693</a>)</li>
<li><a
href="f8e1ad806c"><code>f8e1ad8</code></a>
Add parens to head of <code>ExpressionStatement</code> instead of whole
statement (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/14077">#14077</a>)</li>
<li><a
href="8034bada96"><code>8034bad</code></a>
Build(deps): Bump json5 from 2.2.0 to 2.2.3 in /scripts/release (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/14104">#14104</a>)</li>
<li><a
href="31d40104f4"><code>31d4010</code></a>
Build(deps): Bump json5 from 2.2.1 to 2.2.3 in /website (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/14101">#14101</a>)</li>
<li><a
href="41cee0636e"><code>41cee06</code></a>
Do not change case of property name if inside a variable declaration in
LESS ...</li>
<li>Additional commits viewable in <a
href="https://github.com/prettier/prettier/compare/2.8.1...2.8.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=prettier&package-manager=npm_and_yarn&previous-version=2.8.1&new-version=2.8.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-09 08:59:17 -06:00
dependabot[bot]
ef8004b38d chore(deps-dev): Bump typedoc from 0.23.22 to 0.23.24 in /node (#206)
Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.23.22 to
0.23.24.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/TypeStrong/TypeDoc/releases">typedoc's
releases</a>.</em></p>
<blockquote>
<h2>v0.23.24</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Fixed an issue where signature comments were preferred over property
comments for indirectly created function-properties, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2135">#2135</a>.</li>
<li>Fixed symlink handling when expanding entry points, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2130">#2130</a>.</li>
</ul>
<h3>Thanks!</h3>
<ul>
<li><a
href="https://github.com/boneskull"><code>@​boneskull</code></a></li>
</ul>
<h2>v0.23.23</h2>
<h3>Features</h3>
<ul>
<li>Added <code>ts.Signature</code> to emitted
<code>EVENT_CREATE_SIGNATURE</code> event, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2002">#2002</a>.</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Links to members hidden by filter settings now temporarily override
the filter, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2092">#2092</a>.</li>
<li>If <code>src/</code> and <code>src/x</code> are specified as entry
points, <code>src/</code> will no longer be ignored, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2121">#2121</a>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/TypeStrong/typedoc/blob/master/CHANGELOG.md">typedoc's
changelog</a>.</em></p>
<blockquote>
<h2>v0.23.24 (2023-01-07)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Fixed an issue where signature comments were preferred over property
comments for indirectly created function-properties, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2135">#2135</a>.</li>
<li>Fixed symlink handling when expanding entry points, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2130">#2130</a>.</li>
</ul>
<h3>Thanks!</h3>
<ul>
<li><a
href="https://github.com/boneskull"><code>@​boneskull</code></a></li>
</ul>
<h2>v0.23.23 (2022-12-18)</h2>
<h3>Features</h3>
<ul>
<li>Added <code>ts.Signature</code> to emitted
<code>EVENT_CREATE_SIGNATURE</code> event, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2002">#2002</a>.</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Links to members hidden by filter settings now temporarily override
the filter, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2092">#2092</a>.</li>
<li>If <code>src/</code> and <code>src/x</code> are specified as entry
points, <code>src/</code> will no longer be ignored, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2121">#2121</a>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="0340ef4553"><code>0340ef4</code></a>
Update changelog for release</li>
<li><a
href="05e65f2bfe"><code>05e65f2</code></a>
Bump version to 0.23.24</li>
<li><a
href="0cb16a8b8c"><code>0cb16a8</code></a>
Shiki :/</li>
<li><a
href="7cf8b3cfd9"><code>7cf8b3c</code></a>
Upgrade deps</li>
<li><a
href="cc93e0996d"><code>cc93e09</code></a>
Update changelog</li>
<li><a
href="26480e7c19"><code>26480e7</code></a>
Merge pull request <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2134">#2134</a>
from boneskull/boneskull/issue2130</li>
<li><a
href="6c1b4ac811"><code>6c1b4ac</code></a>
fix(test): glob root match test matches against platform-normalized
path</li>
<li><a
href="fd7a896be5"><code>fd7a896</code></a>
fix: allow traversal of symlinks in glob</li>
<li><a
href="81ccecfa4f"><code>81ccecf</code></a>
Fix <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2135">#2135</a></li>
<li><a
href="2d60647225"><code>2d60647</code></a>
Merge pull request <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2133">#2133</a>
from boneskull/boneskull/tooltweak</li>
<li>Additional commits viewable in <a
href="https://github.com/TypeStrong/TypeDoc/compare/v0.23.22...v0.23.24">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=typedoc&package-manager=npm_and_yarn&previous-version=0.23.22&new-version=0.23.24)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-09 08:59:07 -06:00
zach
9a6b4997dc feat: add EXTISM_DEBUG env variable to enable debug info (#201) 2023-01-06 14:06:11 -08:00
Benjamin Eckel
87a403b7f3 Fix: Fixes Runtime problem with ESM module (#199)
Takes new version of the wasi shim and ensures that both CJS and ESM
distributions can be built.


Already published as 0.2.2

Co-authored-by: Steve Manuel <steve@dylib.so>
2023-01-04 18:01:48 -06:00
Benjamin Eckel
908edf2918 feat: WASI support for browser runtime (#196)
closes #160

Goal is not to expose all the WASI functionality, but to just write
minimum code to allow PDK targets that require WASI (e.g. tinygo
compiled plugins) to work in the browser. We can follow up with allowing
the user more control over the WASI environment.
2023-01-04 14:42:18 -06:00
zach
7d34595dd7 feat(zig): import extism.h directly instead of hand-written bindings (#197) 2023-01-04 10:57:08 -08:00
dependabot[bot]
e3a427b0cc chore(deps-dev): Update minitest requirement from ~> 5.16.3 to ~> 5.17.0 in /ruby (#190)
Updates the requirements on
[minitest](https://github.com/seattlerb/minitest) to permit the latest
version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/minitest/minitest/blob/master/History.rdoc">minitest's
changelog</a>.</em></p>
<blockquote>
<p>=== 5.17.0 / 2022-12-31</p>
<ul>
<li>
<p>1 minor enhancement:</p>
<ul>
<li>Refactor setup hooks into a SETUP_METHODS constant. (MSP-Greg)</li>
</ul>
</li>
<li>
<p>3 bug fixes:</p>
<ul>
<li>Fix kwargs for Mock calls to delegator. (blowmage)</li>
<li>Fix kwargs for expectations. (bobmazanec, blowmage)</li>
<li>Remove check for .b method. (tenderlove)</li>
</ul>
</li>
</ul>
<p>=== 5.16.3 / 2022-08-17</p>
<ul>
<li>
<p>2 bug fixes:</p>
<ul>
<li>Fixed exception sanitization by removing TypeError restriction on
rescue.</li>
<li>Use A instead of deprecated TESTOPTS in rake test:slow.
(davidstosik)</li>
</ul>
</li>
</ul>
<p>=== 5.16.2 / 2022-07-03</p>
<ul>
<li>
<p>4 bug fixes:</p>
<ul>
<li>Added MT_KWARGS_HACK kludge for stub to deal with ruby 2.7 kwargs
nastiness. (tsugimoto)</li>
<li>In #expect, pop Hash class from args if $MT_KWARGS_HACK.
(casperisfine)</li>
<li>In above scenario, set expected kwargs (as Objects) based on actual
kwargs.</li>
<li>Nuke ivars if exception fails to marshal twice (eg better_errors).
(irphilli)</li>
</ul>
</li>
</ul>
<p>=== 5.16.1 / 2022-06-20</p>
<ul>
<li>
<p>2 bug fixes:</p>
<ul>
<li>Apparently adding real kwarg support to mocks/stubs broke some code.
Fixed.
<ul>
<li>Use <code>MT_KWARGS_HACK=1</code> to activate the kludgy kwargs
support w/ caveats.</li>
</ul>
</li>
<li>Clarified some doco wrt the block on #stub.</li>
</ul>
</li>
</ul>
<p>=== 5.16.0 / 2022-06-14</p>
<ul>
<li>
<p>2 major enhancements:</p>
<ul>
<li>Added Minitest::TestTask.</li>
<li>Dropping ruby 2.2 - 2.5. 2.6 is DTM soon too.</li>
</ul>
</li>
<li>
<p>11 minor enhancements:</p>
<ul>
<li>Added --show-skips option to show skips at end of run but not
require --verbose. (MSP-Greg)</li>
<li>Added Minitest.seed, the random seed used by the run.</li>
<li>Calling <code>srand Minitest.seed</code> before all shuffles to
ensure determinism.</li>
<li>Extended #stub to handle kwargs for both block and call args.
(SampsonCrowley)</li>
<li>Extended Mock#__call to display kwargs.</li>
</ul>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="abdde9d03b"><code>abdde9d</code></a>
prepped for release</li>
<li><a
href="c0be030603"><code>c0be030</code></a>
- Fix kwargs for Mock calls to delegator. (blowmage)</li>
<li><a
href="87604fca4d"><code>87604fc</code></a>
- Fix kwargs for expectations. (bobmazanec, blowmage)</li>
<li><a
href="0b816d303b"><code>0b816d3</code></a>
Add EOL date to rails matrix</li>
<li><a
href="2f7ed237f1"><code>2f7ed23</code></a>
cleaned up rails version</li>
<li><a
href="ae54abfb23"><code>ae54abf</code></a>
Updated README for rails/ruby compatibilty matrix</li>
<li><a
href="4f31487068"><code>4f31487</code></a>
Fixed race condition causing flaky tests. (XrXr)</li>
<li><a
href="dcdd882fbe"><code>dcdd882</code></a>
get rake dcov back to 100%</li>
<li><a
href="3a77687e8b"><code>3a77687</code></a>
+ Refactor setup hooks into a SETUP_METHODS constant. (MSP-Greg)</li>
<li><a
href="b5565c0c7a"><code>b5565c0</code></a>
- Remove check for .b method. (tenderlove)</li>
<li>See full diff in <a
href="https://github.com/seattlerb/minitest/compare/v5.16.3...v5.17.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-03 13:52:02 -06:00
dependabot[bot]
0782d79278 chore(deps-dev): Bump @types/node from 18.11.17 to 18.11.18 in /node (#191)
Bumps
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
from 18.11.17 to 18.11.18.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/node&package-manager=npm_and_yarn&previous-version=18.11.17&new-version=18.11.18)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-03 13:51:49 -06:00
dependabot[bot]
472ad42048 chore(deps-dev): Bump @types/jest from 29.2.4 to 29.2.5 in /node (#192)
Bumps
[@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest)
from 29.2.4 to 29.2.5.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/jest&package-manager=npm_and_yarn&previous-version=29.2.4&new-version=29.2.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-03 13:51:38 -06:00
Steve Manuel
ed6110e6ec chore: add zig to graphic and readme support 2023-01-02 17:25:48 -07:00
dependabot[bot]
527bcdfbcf chore(deps): Bump json5 from 2.2.1 to 2.2.3 in /node (#194)
Bumps [json5](https://github.com/json5/json5) from 2.2.1 to 2.2.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/json5/json5/releases">json5's
releases</a>.</em></p>
<blockquote>
<h2>v2.2.3</h2>
<ul>
<li>Fix: json5@2.2.3 is now the 'latest' release according to npm
instead of v1.0.2. (<a
href="https://github-redirect.dependabot.com/json5/json5/issues/299">#299</a>)</li>
</ul>
<h2>v2.2.2</h2>
<ul>
<li>Fix: Properties with the name <code>__proto__</code> are added to
objects and arrays.
(<a
href="https://github-redirect.dependabot.com/json5/json5/issues/199">#199</a>)
This also fixes a prototype pollution vulnerability reported by
Jonathan Gregson! (<a
href="https://github-redirect.dependabot.com/json5/json5/issues/295">#295</a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/json5/json5/blob/main/CHANGELOG.md">json5's
changelog</a>.</em></p>
<blockquote>
<h3>v2.2.3 [<a
href="https://github.com/json5/json5/tree/v2.2.3">code</a>, <a
href="https://github.com/json5/json5/compare/v2.2.2...v2.2.3">diff</a>]</h3>
<ul>
<li>Fix: json5@2.2.3 is now the 'latest' release according to npm
instead of
v1.0.2. (<a
href="https://github-redirect.dependabot.com/json5/json5/issues/299">#299</a>)</li>
</ul>
<h3>v2.2.2 [<a
href="https://github.com/json5/json5/tree/v2.2.2">code</a>, <a
href="https://github.com/json5/json5/compare/v2.2.1...v2.2.2">diff</a>]</h3>
<ul>
<li>Fix: Properties with the name <code>__proto__</code> are added to
objects and arrays.
(<a
href="https://github-redirect.dependabot.com/json5/json5/issues/199">#199</a>)
This also fixes a prototype pollution vulnerability reported by
Jonathan Gregson! (<a
href="https://github-redirect.dependabot.com/json5/json5/issues/295">#295</a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="c3a7524277"><code>c3a7524</code></a>
2.2.3</li>
<li><a
href="94fd06d82e"><code>94fd06d</code></a>
docs: update CHANGELOG for v2.2.3</li>
<li><a
href="3b8cebf0c4"><code>3b8cebf</code></a>
docs(security): use GitHub security advisories</li>
<li><a
href="f0fd9e194d"><code>f0fd9e1</code></a>
docs: publish a security policy</li>
<li><a
href="6a91a05fff"><code>6a91a05</code></a>
docs(template): bug -&gt; bug report</li>
<li><a
href="14f8cb186e"><code>14f8cb1</code></a>
2.2.2</li>
<li><a
href="10cc7ca916"><code>10cc7ca</code></a>
docs: update CHANGELOG for v2.2.2</li>
<li><a
href="7774c10979"><code>7774c10</code></a>
fix: add <strong>proto</strong> to objects and arrays</li>
<li><a
href="edde30abd8"><code>edde30a</code></a>
Readme: slight tweak to intro</li>
<li><a
href="97286f8bd5"><code>97286f8</code></a>
Improve example in readme</li>
<li>Additional commits viewable in <a
href="https://github.com/json5/json5/compare/v2.2.1...v2.2.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=json5&package-manager=npm_and_yarn&previous-version=2.2.1&new-version=2.2.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/extism/extism/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 14:49:07 -08:00
dependabot[bot]
765a1c55d5 chore(deps): Bump json5 from 2.2.1 to 2.2.3 in /browser (#193)
Bumps [json5](https://github.com/json5/json5) from 2.2.1 to 2.2.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/json5/json5/releases">json5's
releases</a>.</em></p>
<blockquote>
<h2>v2.2.3</h2>
<ul>
<li>Fix: json5@2.2.3 is now the 'latest' release according to npm
instead of v1.0.2. (<a
href="https://github-redirect.dependabot.com/json5/json5/issues/299">#299</a>)</li>
</ul>
<h2>v2.2.2</h2>
<ul>
<li>Fix: Properties with the name <code>__proto__</code> are added to
objects and arrays.
(<a
href="https://github-redirect.dependabot.com/json5/json5/issues/199">#199</a>)
This also fixes a prototype pollution vulnerability reported by
Jonathan Gregson! (<a
href="https://github-redirect.dependabot.com/json5/json5/issues/295">#295</a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/json5/json5/blob/main/CHANGELOG.md">json5's
changelog</a>.</em></p>
<blockquote>
<h3>v2.2.3 [<a
href="https://github.com/json5/json5/tree/v2.2.3">code</a>, <a
href="https://github.com/json5/json5/compare/v2.2.2...v2.2.3">diff</a>]</h3>
<ul>
<li>Fix: json5@2.2.3 is now the 'latest' release according to npm
instead of
v1.0.2. (<a
href="https://github-redirect.dependabot.com/json5/json5/issues/299">#299</a>)</li>
</ul>
<h3>v2.2.2 [<a
href="https://github.com/json5/json5/tree/v2.2.2">code</a>, <a
href="https://github.com/json5/json5/compare/v2.2.1...v2.2.2">diff</a>]</h3>
<ul>
<li>Fix: Properties with the name <code>__proto__</code> are added to
objects and arrays.
(<a
href="https://github-redirect.dependabot.com/json5/json5/issues/199">#199</a>)
This also fixes a prototype pollution vulnerability reported by
Jonathan Gregson! (<a
href="https://github-redirect.dependabot.com/json5/json5/issues/295">#295</a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="c3a7524277"><code>c3a7524</code></a>
2.2.3</li>
<li><a
href="94fd06d82e"><code>94fd06d</code></a>
docs: update CHANGELOG for v2.2.3</li>
<li><a
href="3b8cebf0c4"><code>3b8cebf</code></a>
docs(security): use GitHub security advisories</li>
<li><a
href="f0fd9e194d"><code>f0fd9e1</code></a>
docs: publish a security policy</li>
<li><a
href="6a91a05fff"><code>6a91a05</code></a>
docs(template): bug -&gt; bug report</li>
<li><a
href="14f8cb186e"><code>14f8cb1</code></a>
2.2.2</li>
<li><a
href="10cc7ca916"><code>10cc7ca</code></a>
docs: update CHANGELOG for v2.2.2</li>
<li><a
href="7774c10979"><code>7774c10</code></a>
fix: add <strong>proto</strong> to objects and arrays</li>
<li><a
href="edde30abd8"><code>edde30a</code></a>
Readme: slight tweak to intro</li>
<li><a
href="97286f8bd5"><code>97286f8</code></a>
Improve example in readme</li>
<li>Additional commits viewable in <a
href="https://github.com/json5/json5/compare/v2.2.1...v2.2.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=json5&package-manager=npm_and_yarn&previous-version=2.2.1&new-version=2.2.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/extism/extism/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 14:48:52 -08:00
Doğu Us
6f534336f3 feat(zig-sdk): Create Zig Host Sdk (#186) 2023-01-02 15:30:34 -07:00
zach
5c9aa4c90a fix(elixir): use local Rust extism package from extism_nif for local development (#180) 2022-12-28 11:40:17 -06:00
dependabot[bot]
a98b39a10f chore(deps-dev): Bump @types/node from 18.11.13 to 18.11.17 in /node (#174)
Bumps
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
from 18.11.13 to 18.11.17.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/node&package-manager=npm_and_yarn&previous-version=18.11.13&new-version=18.11.17)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-24 23:07:01 -06:00
zach
8c2255eafa chore: update to wasmtime 4.0.0 (#181) 2022-12-22 10:43:49 -08:00
zach
094f51ba2b refactor(ocaml): Cleanup code, split out extism-manifest package, prepare to release with next runtime release (#182) 2022-12-22 10:43:24 -08:00
Steve Manuel
c2b1b78cc1 Update README.md 2022-12-20 14:35:53 -07:00
Thomas Darimont
322812ede2 refactor(java-sdk): Revise API usage (#177)
(cherry picked from commit 766090a1aa8340598c643ca01dded16b15c26ba5)
2022-12-19 17:48:45 -06:00
zach
9ccef562a9 ci: use glob for paths (#178) 2022-12-19 15:09:57 -08:00
Benjamin Eckel
bc2b044770 fix(java-sdk): Bad xml 2022-12-19 15:55:28 -06:00
Benjamin Eckel
374191f420 release(java-sdk): Bump version to 0.1.0 2022-12-19 15:39:12 -06:00
zach
ba69d9fcc8 chore: move each language to separate workflow (#176)
- Moves each language into a separate workflow
- Only runs CI for languages when they're changed (or when the runtime
is changed)
2022-12-19 12:38:50 -08:00
Benjamin Eckel
6cbde1acfc docs(java-sdk): Update readme (#175) 2022-12-19 11:42:08 -06:00
Benjamin Eckel
f34fa8bed2 feat(java-sdk): Create Java Host SDK (#122)
Closes #117

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
Co-authored-by: Thomas Darimont <thomas.darimont@googlemail.com>
2022-12-19 10:55:40 -06:00
zach
dd0c5757da chore: update OCaml version to latest release (#171) 2022-12-16 11:19:19 -08:00
zach
34feb4b942 fix(haskell): update encoding of Extism.Manifest.HTTPRequest (#170) 2022-12-15 17:44:22 -08:00
zach
34b5942dd5 fix: use timeouts for language-specific runtime initialization/finalization calls (#169)
After adding the timer code plugins written in Haskell fail with a
timeout when trying to call `hs_init` - this PR fixes the runtime
initialization and updates those functions to respect the configured
timeout.
2022-12-15 16:43:19 -08:00
Benjamin Eckel
d681dcd9f1 chore(dotnet-sdk): Update Sample file, use the one from the docs (#164) 2022-12-15 14:52:53 -08:00
zach
4622f32a69 feat: add timeout_ms field to SDKs (#165) 2022-12-14 17:48:05 -08:00
zach
0c4b985ed7 feat: Add option to set timeout for plugin (#163)
- Adds `Manifest::timeout_ms` field to specify the plugin timeout in
milliseconds
- Sets a 30 second default timeout

Co-authored-by: Steve Manuel <steve@dylib.so>
2022-12-13 15:58:52 -08:00
Steve Manuel
5dfe7162b4 chore: include .net in readme list of sdk support 2022-12-13 12:35:28 -05:00
Steve Manuel
e0f8e54504 chore: update readme language support graphic 2022-12-13 12:33:21 -05:00
Benjamin Eckel
a236e59d3c docs: Add link to Haskell PDK instructions (#162) 2022-12-13 10:28:11 -06:00
dependabot[bot]
77c1d55791 chore(deps-dev): Bump @types/jest from 29.2.3 to 29.2.4 in /node (#155)
Bumps
[@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest)
from 29.2.3 to 29.2.4.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/jest&package-manager=npm_and_yarn&previous-version=29.2.3&new-version=29.2.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-13 11:15:54 -05:00
Benjamin Eckel
ab36decbe7 fix(dotnet-sdk): Missed native version bump 2022-12-12 16:47:10 -06:00
Benjamin Eckel
0343bbbefe chore(dotnet-sdk): Release 0.2.0 (#161) 2022-12-12 16:42:53 -06:00
Benjamin Eckel
95ccafb02b ci(dotnet-sdk): Package dotnet lib with native dll (#152)
Fix release for native windows nuget package
2022-12-12 11:08:10 -06:00
Benjamin Eckel
c8308c3cdf docs(dotnet-sdk): RC-2 version to test 2022-12-12 11:06:54 -06:00
dependabot[bot]
aedb5b9c24 chore(deps-dev): Bump typedoc from 0.23.21 to 0.23.22 in /node (#156)
[//]: # (dependabot-start)
⚠️  **Dependabot is rebasing this PR** ⚠️ 

Rebasing might not happen immediately, so don't worry if this takes some
time.

Note: if you make any changes to this PR yourself, they will take
precedence over the rebase.

---

[//]: # (dependabot-end)

Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.23.21 to
0.23.22.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/TypeStrong/TypeDoc/releases">typedoc's
releases</a>.</em></p>
<blockquote>
<h2>v0.23.22</h2>
<h3>Features</h3>
<ul>
<li>Add support for defining the kind sort order, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2109">#2109</a>.</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Normalize all file paths on Windows, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2113">#2113</a>.</li>
<li>Fix <code>@link</code> tags within lists, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2103">#2103</a>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/TypeStrong/typedoc/blob/master/CHANGELOG.md">typedoc's
changelog</a>.</em></p>
<blockquote>
<h2>v0.23.22 (2022-12-11)</h2>
<h3>Features</h3>
<ul>
<li>Add support for defining the kind sort order, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2109">#2109</a>.</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Normalize all file paths on Windows, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2113">#2113</a>.</li>
<li>Fix <code>@link</code> tags within lists, <a
href="https://github-redirect.dependabot.com/TypeStrong/TypeDoc/issues/2103">#2103</a>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ff5cb55a08"><code>ff5cb55</code></a>
Update changelog for release</li>
<li><a
href="678bf5e4dd"><code>678bf5e</code></a>
Bump version to 0.23.22</li>
<li><a
href="84c26e65d8"><code>84c26e6</code></a>
Fix <code>@link</code> tags within lists</li>
<li><a
href="5edf2290e7"><code>5edf229</code></a>
Add support for defining the kind sort order</li>
<li><a
href="36c95c0432"><code>36c95c0</code></a>
Normalize all paths on Windows</li>
<li>See full diff in <a
href="https://github.com/TypeStrong/TypeDoc/compare/v0.23.21...v0.23.22">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=typedoc&package-manager=npm_and_yarn&previous-version=0.23.21&new-version=0.23.22)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-12 10:38:07 -06:00
dependabot[bot]
f34cc8f6ca chore(deps-dev): Bump typescript from 4.9.3 to 4.9.4 in /node (#157)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.9.3
to 4.9.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/Microsoft/TypeScript/releases">typescript's
releases</a>.</em></p>
<blockquote>
<h2>TypeScript 4.9.4</h2>
<p>For release notes, check out the <a
href="https://devblogs.microsoft.com/typescript/announcing-typescript-4-9">release
announcement</a>.</p>
<p>For the complete list of fixed issues, check out the</p>
<ul>
<li><a
href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+milestone%3A%22TypeScript+4.9.4%22+is%3Aclosed+">fixed
issues query for Typescript v4.9.4</a>.</li>
</ul>
<p>Downloads are available on:</p>
<ul>
<li><a href="https://www.npmjs.com/package/typescript">npm</a></li>
<li><a
href="https://www.nuget.org/packages/Microsoft.TypeScript.MSBuild">NuGet
package</a></li>
</ul>
<h2>Changes:</h2>
<ul>
<li>e2868216f637e875a74c675845625eb15dcfe9a2 Bump version to 4.9.4 and
LKG.</li>
<li>eb5419fc8d980859b98553586dfb5f40d811a745 Cherry-pick <a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51704">#51704</a>
to release 4.9 (<a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51712">#51712</a>)</li>
<li>b4d382b9b12460adf2da4cc0d1429cf19f8dc8be Cherry-pick changes for
narrowing to tagged literal types.</li>
<li>e7a02f43fce47e1a39259ada5460bcc33c8e98b5 Port of <a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51626">#51626</a>
and <a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51689">#51689</a>
to release-4.9 (<a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51627">#51627</a>)</li>
<li>1727912f0437a7f367d90040fc4b0b4f3efd017a Cherry-pick fix around
<code>visitEachChild</code> to release-4.9. (<a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51544">#51544</a>)</li>
</ul>
<p>This list of changes was <a
href="https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_release?releaseId=117&amp;_a=release-summary">auto
generated</a>.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e2868216f6"><code>e286821</code></a>
Bump version to 4.9.4 and LKG.</li>
<li><a
href="eb5419fc8d"><code>eb5419f</code></a>
Cherry-pick <a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51704">#51704</a>
to release 4.9 (<a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51712">#51712</a>)</li>
<li><a
href="b4d382b9b1"><code>b4d382b</code></a>
Cherry-pick changes for narrowing to tagged literal types.</li>
<li><a
href="e7a02f43fc"><code>e7a02f4</code></a>
Port of <a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51626">#51626</a>
and <a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51689">#51689</a>
to release-4.9 (<a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51627">#51627</a>)</li>
<li><a
href="1727912f04"><code>1727912</code></a>
Cherry-pick fix around <code>visitEachChild</code> to release-4.9. (<a
href="https://github-redirect.dependabot.com/Microsoft/TypeScript/issues/51544">#51544</a>)</li>
<li>See full diff in <a
href="https://github.com/Microsoft/TypeScript/compare/v4.9.3...v4.9.4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=typescript&package-manager=npm_and_yarn&previous-version=4.9.3&new-version=4.9.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-12 10:37:45 -06:00
dependabot[bot]
dc2d015573 chore(deps-dev): Bump @types/node from 18.11.10 to 18.11.13 in /node (#158)
[//]: # (dependabot-start)
⚠️  **Dependabot is rebasing this PR** ⚠️ 

Rebasing might not happen immediately, so don't worry if this takes some
time.

Note: if you make any changes to this PR yourself, they will take
precedence over the rebase.

---

[//]: # (dependabot-end)

Bumps
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
from 18.11.10 to 18.11.13.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/node&package-manager=npm_and_yarn&previous-version=18.11.10&new-version=18.11.13)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-12 10:37:26 -06:00
dependabot[bot]
6a7b595c08 chore(deps-dev): Bump prettier from 2.8.0 to 2.8.1 in /node (#159)
Bumps [prettier](https://github.com/prettier/prettier) from 2.8.0 to
2.8.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/releases">prettier's
releases</a>.</em></p>
<blockquote>
<h2>2.8.1</h2>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#281">Changelog</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's
changelog</a>.</em></p>
<blockquote>
<h1>2.8.1</h1>
<p><a
href="https://github.com/prettier/prettier/compare/2.8.0...2.8.1">diff</a></p>
<h4>Fix SCSS map in arguments (<a
href="https://github-redirect.dependabot.com/prettier/prettier/pull/9184">#9184</a>
by <a
href="https://github.com/agamkrbit"><code>@​agamkrbit</code></a>)</h4>
<!-- raw HTML omitted -->
<pre lang="scss"><code>// Input
$display-breakpoints: map-deep-merge(
  (
    &quot;print-only&quot;: &quot;only print&quot;,
    &quot;screen-only&quot;: &quot;only screen&quot;,
&quot;xs-only&quot;: &quot;only screen and (max-width:
#{map-get($grid-breakpoints, &quot;sm&quot;)-1})&quot;,
  ),
  $display-breakpoints
);
<p>// Prettier 2.8.0
$display-breakpoints: map-deep-merge(
(
&quot;print-only&quot;: &quot;only print&quot;,
&quot;screen-only&quot;: &quot;only screen&quot;,
&quot;xs-only&quot;: &quot;only screen and (max-width:
#{map-get($grid-breakpoints, &quot; sm
&quot;)-1})&quot;,
),
$display-breakpoints
);</p>
<p>// Prettier 2.8.1
$display-breakpoints: map-deep-merge(
(
&quot;print-only&quot;: &quot;only print&quot;,
&quot;screen-only&quot;: &quot;only screen&quot;,
&quot;xs-only&quot;: &quot;only screen and (max-width:
#{map-get($grid-breakpoints, &quot;sm&quot;)-1})&quot;,
),
$display-breakpoints
);
</code></pre></p>
<h4>Support auto accessors syntax (<a
href="https://github-redirect.dependabot.com/prettier/prettier/pull/13919">#13919</a>
by <a
href="https://github.com/sosukesuzuki"><code>@​sosukesuzuki</code></a>)</h4>
<p>Support for <a
href="https://devblogs.microsoft.com/typescript/announcing-typescript-4-9/#auto-accessors-in-classes">Auto
Accessors Syntax</a> landed in TypeScript 4.9.</p>
<p>(Doesn't work well with <code>babel-ts</code> parser)</p>
<!-- raw HTML omitted -->
<pre lang="tsx"><code>class Foo {
  accessor foo: number = 3;
&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="cd1df1a184"><code>cd1df1a</code></a>
Release 2.8.1</li>
<li><a
href="5541a63d76"><code>5541a63</code></a>
Remove version validation</li>
<li><a
href="1cf760a184"><code>1cf760a</code></a>
Support decorator auto accessors syntax (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/13919">#13919</a>)</li>
<li><a
href="aa34209820"><code>aa34209</code></a>
test: format instantiation expr in logical expr (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/13897">#13897</a>)</li>
<li><a
href="957b4f20e8"><code>957b4f2</code></a>
Build(deps): Bump decode-uri-component from 0.2.0 to 0.2.2 in /website
(<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/13933">#13933</a>)</li>
<li><a
href="e4240aeaf0"><code>e4240ae</code></a>
Add tests for keyword class property (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/13927">#13927</a>)</li>
<li><a
href="655a161d0f"><code>655a161</code></a>
Add tests for multiple comments (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/13890">#13890</a>)</li>
<li><a
href="4a1e32a9de"><code>4a1e32a</code></a>
Fixed scss function arguments on different lines in maps <a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/9128">#9128</a>
(<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/9184">#9184</a>)</li>
<li><a
href="38806fe666"><code>38806fe</code></a>
Migrate from probot/no-response to lee-dohm/no-response (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/13891">#13891</a>)</li>
<li><a
href="a60bee2e2d"><code>a60bee2</code></a>
Add '--single-attribute-per-line' option to Playground (<a
href="https://github-redirect.dependabot.com/prettier/prettier/issues/13587">#13587</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/prettier/prettier/compare/2.8.0...2.8.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=prettier&package-manager=npm_and_yarn&previous-version=2.8.0&new-version=2.8.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-12 10:37:04 -06:00
zach
a68823e71c fix: remove old/duplicate Haskell runtime initialization code (#154) 2022-12-10 20:10:34 -08:00
zach
9a1d99a6e7 fix: order of arguments to Func::new 2022-12-09 19:39:15 -08:00
zach
f2a9851867 fix: order of arguments to Function::new 2022-12-09 19:35:15 -08:00
zach
124787127c feat: Add ability to register host functions with the runtime from the Rust SDK (#148)
- Adds the ability to initialize plugins with additional functions
created by the host (only supported by the Rust SDK right now)
- Adds `PluginBuilder` to the Rust SDK to make it easier to configure all the options

## Hello, world

The following example uses `println` from the host to print to stdout
from inside the plugin.

Host:
```rust
use extism::*;

fn main() -> Result<(), Error> {
    let context = Context::new();
    let manifest = Manifest::new([std::path::PathBuf::from("code.wasm")]);
    let say_hello = Function::new("say_hello", [ValType::I64], [], |caller, input, _out| {
        let internal = caller.data();
        let r = internal.memory().get_str(input[0].unwrap_i64() as usize)?;
        println!("Hello, {r}!");
        Ok(())
    });
    let mut plugin = PluginBuilder::new(manifest)
        .with_function(say_hello)
        .with_wasi(true)
        .build(&context)?;
    plugin.call("test", b"world").unwrap();
    Ok(())
}
```

Plugin:
```rust
use extism_pdk::*;

extern "C" {
    fn say_hello(offs: u64);
}

#[plugin_fn]
pub fn test(input: String) -> FnResult<()> {
    let memory = Memory::from_bytes(&input);
    unsafe {
        say_hello(memory.offset);
    }
    Ok(())
}

```
2022-12-09 16:08:50 -08:00
Muhammad Azeez
c3ffb25891 feat: Implement .NET Host SDK (#119)
I am working on a .NET host for extism. My plan is to do the following:
 - [x] Implement a proof of concept to make sure things are possible
- [x] Write docs for the C# API so that the users get a nice IDE
experience
 - [x] Create a github action to publish the NuGet packages
    - [x] Edit `ci.yml` to include .NET Sdk
- [x] Create `release-dotnet.yml` to release `Extism.Sdk` nuget package
- [x] Maybe Create `release-dotnet-native.yml` to release
`Extism.runtime.win` nuget package
 - [x] Test on Linux (Help needed)
 - [x] Test on Mac (Help needed)
 - [x] Expose all of the Extism functions
 - [x] Write automated tests
- [x] ~Edit README show that the there is a .NET SDK~. Probably we
should not do this until we have a docs page.
 - [x] ~Use the `Extism.runtime.win-x64` package in the sample project~

Out of scope for this PR:
 - Json Serialization/Desererialization support

Co-authored-by: Alistair Evans <alistairjevans@gmail.com>
Co-authored-by: Benjamin Eckel <bhelx@simst.im>
Co-authored-by: Benjamin Eckel <bhelx@users.noreply.github.com>
2022-12-08 12:42:27 -06:00
zach
e473d2cb7e refactor(haskell): cleanup haskell SDK to prepare for release (#138)
- Switches from `stack` to `cabal`
- Cleanup SDK code
- Adds release action (still waiting on Hackage upload approval)

Co-authored-by: Steve Manuel <steve@dylib.so>
2022-12-08 10:07:56 -08:00
zach
5a5b538855 fix(ci): don’t install Python dev dependencies on CI (#149) 2022-12-07 18:45:50 -08:00
zach
acb06b9898 feat: Add support for allowed_paths manifest key in SDKs (#144)
The Haskell SDK is updated here:
https://github.com/extism/extism/pull/138
2022-12-07 07:52:23 -08:00
zach
1973024816 fix: disallow all hosts if allowed_hosts is empty (#143) 2022-12-06 08:29:08 -08:00
zach
d4febd7228 fix: use Dir::open_ambient_dir instead of Dir::from_std_file (#140)
`Dir::from_std_file` works on Linux, but does not work as expected on
Windows
2022-12-06 08:28:51 -08:00
zach
bb2697193a feat: add allowed_paths to specify preopened directories in WASI (#137)
Adds ability to make local files available to plugins. Using the Rust
SDK:

```rust
let wasm = include_bytes!("code.wasm");
let mut context = Context::new();
let manifest = Manifest::new(vec![Wasm::data(wasm)]).with_allowed_path("/path/on/disk", "/plugin/path");
let plugin = Plugin::new_with_manifest(&mut context, &manifest, false)?;
...
```
2022-12-05 18:01:25 -08:00
zach
fee7348cee fix: Reinstantiate after call to _start (#135)
After a closer reading of:
https://github.com/WebAssembly/WASI/blob/main/legacy/application-abi.md
it looks likes `_start` is expected to be called at most once. This PR
automatically reinstantiates a plugin after a call to `_start` so it can
be used again.

CI caught a bug with the `extism_version` output which is fixed here:
https://github.com/extism/extism/pull/139
2022-12-05 16:18:30 -08:00
zach
9cf54d5f1f feat: Improve usability of manifest types (#124)
- Adds some helper functions for creating a manifest, mostly helpful for
the Rust SDK
- Renames `ManifestWasm` to `Wasm`
- Renames `ManifestMemory` to `MemoryOptions`
- `ManifestWasm` and `ManifestMemory` have been marked as deprecated
- Adds an alias from `MemoryOptions::max_pages` to `MemoryOptions::max`
in serde specification

Co-authored-by: Steve Manuel <steve@dylib.so>
2022-12-05 15:09:50 -08:00
zach
a3c6b9ee6a fix: add null byte to end of version string (#139) 2022-12-05 14:38:11 -08:00
dependabot[bot]
732b886fd5 chore(deps-dev): Bump @types/node from 18.11.9 to 18.11.10 in /node (#130)
Bumps
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
from 18.11.9 to 18.11.10.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/node&package-manager=npm_and_yarn&previous-version=18.11.9&new-version=18.11.10)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-04 19:53:46 -06:00
dependabot[bot]
bd8ca71275 chore(deps-dev): Bump @types/ffi-napi from 4.0.6 to 4.0.7 in /node (#131)
Bumps
[@types/ffi-napi](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ffi-napi)
from 4.0.6 to 4.0.7.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/ffi-napi">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/ffi-napi&package-manager=npm_and_yarn&previous-version=4.0.6&new-version=4.0.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-04 19:53:36 -06:00
zach
37ee7d67b6 fix: update crate name to extism_runtime in logging registration function (#123)
This bug exists because we didn't change the crate name in the logging
registration function, so all of our logs from `extism_runtime` were
being filtered out.
2022-12-02 14:04:54 -08:00
Steve Manuel
6b5f7999b7 fix: removes the stdout print of extism.h in php sdk (#112) 2022-11-30 16:30:06 -08:00
Benjamin Eckel
de24fffc7c fix(elixir-sdk): remove compiled nif from package, update readme (#111) 2022-11-30 16:38:51 -06:00
Benjamin Eckel
37b8e5bd12 release: v0.1.0 (#110) 2022-11-30 14:52:46 -06:00
Benjamin Eckel
c6b8429c67 chore: Add Makefile for browser runtime (#103)
I accidentally published without building. this should help make sure
releases are valid
2022-11-30 13:20:23 -06:00
Benjamin Eckel
ad114f44d2 fix(ruby-sdk): Add FFI gem as dependency (#106) 2022-11-30 13:19:54 -06:00
Benjamin Eckel
45180ad473 docs(node-sdk): Fix example to use CJS imports (#107) 2022-11-30 13:19:45 -06:00
Benjamin Eckel
9546dac689 docs(elixir-sdk): Reduce elixir min version (#108)
I've tested it in at least as low as 1.12. It just prints out a warning
so should be fine if someone wants to use it on an older version.
2022-11-30 13:19:28 -06:00
zach
197e934258 Fix elixir bindings (#109) 2022-11-30 10:42:43 -08:00
Benjamin Eckel
339556597b chore(python-sdk): Put placeholder readme in python dir (#104) 2022-11-29 12:39:01 -06:00
Benjamin Eckel
64927d9bcd fix(rust-sdk): Fix dep versions (#102) 2022-11-29 12:17:49 -06:00
Benjamin Eckel
86f1117ad5 chore: Fix bad publish, bump to 0.0.2 2022-11-29 11:52:55 -06:00
Benjamin Eckel
34be80a7ad chore: Fix elixir release workflow (#77) 2022-11-29 11:47:30 -06:00
Benjamin Eckel
3e6a0071e9 fix: Fix the release action (#101) 2022-11-29 10:33:26 -06:00
Benjamin Eckel
d17b693c4b release: Bump to 0.0.1 (#97) 2022-11-29 09:48:40 -06:00
zach
18fceec8f8 Cleanup Haskell SDK, split out manifest sublibrary (#99) 2022-11-28 21:03:13 -08:00
Benjamin Eckel
f5cf4f184e chore: fix ruby release publish (#78) 2022-11-28 19:31:26 -06:00
154 changed files with 6032 additions and 2500 deletions

View File

@@ -7,12 +7,24 @@ runs:
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Download libextism
uses: actions/download-artifact@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
name: libextism-${{ matrix.os }}
toolchain: stable
override: true
- name: Cache Rust environment
uses: Swatinem/rust-cache@v1
- name: Cache libextism
id: cache-libextism
uses: actions/cache@v3
with:
path: target/**
key: ${{ runner.os }}-libextism-${{ hashFiles('runtime/**') }}-${{ hashFiles('manifest/**') }}-${{ hashFiles('libextism/**') }}
- name: Build
if: steps.cache-libextism.outputs.cache-hit != 'true'
shell: bash
run: cargo build --release -p libextism
- name: Install extism shared library
shell: bash
run: |
sudo cp libextism.* /usr/local/lib
sudo cp runtime/extism.h /usr/local/include
sudo make install

36
.github/workflows/browser-ci.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-node.yml
- manifest/**
- runtime/**
- libextism/**
- browser/**
workflow_dispatch:
name: Browser CI
jobs:
node:
name: Browser
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Node env
uses: actions/setup-node@v3
with:
node-version: 18
- name: Test Browser Runtime
run: |
cd browser
npm i
npm run test

39
.github/workflows/ci-cpp.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-cpp.yml
- manifest/**
- runtime/**
- libextism/**
- cpp/**
workflow_dispatch:
name: C++ CI
jobs:
cpp:
name: C++
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Install C++ SDK deps
if: ${{ matrix.os == 'macos-latest' }}
run: |
brew install jsoncpp googletest pkg-config
- name: Install C++ SDK deps
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
sudo apt-get install g++ libjsoncpp-dev libgtest-dev pkg-config
- name: Run C++ tests
run: |
cd cpp
LD_LIBRARY_PATH=/usr/local/lib make example
LD_LIBRARY_PATH=/usr/local/lib make test

34
.github/workflows/ci-dotnet.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-dotnet.yml
- manifest/**
- runtime/**
- libextism/**
- dotnet/**
workflow_dispatch:
name: .NET CI
jobs:
dotnet:
name: .NET
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: 7.x
- name: Test .NET Sdk
run: |
cd dotnet
LD_LIBRARY_PATH=/usr/local/lib dotnet test ./Extism.sln

41
.github/workflows/ci-elixir.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-elixir.yml
- manifest/**
- runtime/**
- rust/**
- elixir/**
workflow_dispatch:
name: Elixir CI
jobs:
elixir:
name: Elixir
runs-on: ${{ matrix.os }}
env:
MIX_ENV: test
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Elixir Host SDK
if: ${{ runner.os != 'macOS' }}
uses: erlef/setup-beam@v1
with:
experimental-otp: true
otp-version: '25.0.4'
elixir-version: '1.14.0'
- name: Test Elixir Host SDK
if: ${{ runner.os != 'macOS' }}
run: |
cd elixir
LD_LIBRARY_PATH=/usr/local/lib mix do deps.get, test

39
.github/workflows/ci-go.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-go.yml
- manifest/**
- runtime/**
- libextism/**
- extism.go
- extism_test.go
- go.mod
- libextism.pc
- go/**
workflow_dispatch:
name: Go CI
jobs:
go:
name: Go
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Go env
uses: actions/setup-go@v3
- name: Test Go Host SDK
run: |
go version
cd go
LD_LIBRARY_PATH=/usr/local/lib go run main.go
LD_LIBRARY_PATH=/usr/local/lib go test

47
.github/workflows/ci-haskell.yml vendored Normal file
View File

@@ -0,0 +1,47 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-haskell.yml
- manifest/**
- runtime/**
- libextism/**
- haskell/**
workflow_dispatch:
name: Haskell CI
jobs:
haskell:
name: Haskell
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Haskell env
uses: haskell/actions/setup@v2
with:
enable-stack: false
- name: Cache Haskell
id: cache-haskell
uses: actions/cache@v3
with:
path: ./haskell/dist-newstyle
key: ${{ runner.os }}-haskell-${{ hashFiles('haskell/**') }}
- name: Build Haskell Host SDK
if: steps.cache-haskell.outputs.cache-hit != 'true'
run: |
cd haskell
cabal update
LD_LIBRARY_PATH=/usr/local/lib cabal build
- name: Test Haskell SDK
run: |
cd haskell
cabal update
LD_LIBRARY_PATH=/usr/local/lib cabal test

42
.github/workflows/ci-java.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-java.yml
- manifest/**
- runtime/**
- libextism/**
- java/**
workflow_dispatch:
name: Java CI
jobs:
java:
name: Java
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
version: [8, 11, 17]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Set up Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '${{ matrix.version }}'
- name: Test Java
run: |
cd java
cat pom.xml | sed 's/<java.version>17/<java.version>${{ matrix.version }}/' > updated.xml
mv updated.xml pom.xml
mvn --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn verify
#- name: Examine logs
# if: success() || failure()
# run: |
# cat /tmp/extism.log

38
.github/workflows/ci-node.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-node.yml
- manifest/**
- runtime/**
- libextism/**
- node/**
workflow_dispatch:
name: Node CI
jobs:
node:
name: Node
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Node env
uses: actions/setup-node@v3
with:
node-version: 18
- name: Test Node Host SDK
run: |
cd node
npm i
LD_LIBRARY_PATH=/usr/local/lib npm run build
LD_LIBRARY_PATH=/usr/local/lib npm run example
LD_LIBRARY_PATH=/usr/local/lib npm run test

50
.github/workflows/ci-ocaml.yml vendored Normal file
View File

@@ -0,0 +1,50 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-ocaml.yml
- manifest/**
- runtime/**
- libextism/**
- ocaml/**
- dune-project
- extism.opam
workflow_dispatch:
name: OCaml CI
jobs:
ocaml:
name: OCaml
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup OCaml env
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: ocaml-base-compiler.5.0.0
- name: Cache OCaml
id: cache-ocaml
uses: actions/cache@v3
with:
path: _build
key: ${{ runner.os }}-ocaml-${{ hashFiles('ocaml/**.ml') }}-${{ hashFiles('dune-project') }}
- name: Build OCaml Host SDK
if: steps.cache-ocaml.outputs.cache-hit != 'true'
run: |
opam install -y --deps-only .
cd ocaml
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune build
- name: Test OCaml Host SDK
run: |
opam install -y --deps-only .
cd ocaml
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune exec ./bin/main.exe ../wasm/code.wasm count_vowels -- --input "qwertyuiop"
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune runtest

42
.github/workflows/ci-php.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-php.yml
- manifest/**
- runtime/**
- libextism/**
- php/**
- composer.json
- composer.lock
workflow_dispatch:
name: PHP CI
jobs:
php:
name: PHP
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup PHP env
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
extensions: ffi
tools: composer
env:
fail-fast: true
- name: Test PHP SDK
run: |
cd php/example
composer install
php index.php

40
.github/workflows/ci-python.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-python.yml
- manifest/**
- runtime/**
- libextism/**
- python/**
workflow_dispatch:
name: Python CI
jobs:
python:
name: Python
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Python env
uses: actions/setup-python@v4
with:
python-version: "3.9"
check-latest: true
- name: Install Poetry
uses: snok/install-poetry@v1
- name: Test Python Host SDK
run: |
cd python
cp ../README.md .
poetry install --no-dev
poetry run python example.py
poetry run python -m unittest discover

38
.github/workflows/ci-ruby.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-ruby.yml
- manifest/**
- runtime/**
- libextism/**
- ruby/**
workflow_dispatch:
name: Ruby CI
jobs:
ruby:
name: Ruby
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Ruby env
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.0"
- name: Test Ruby Host SDK
run: |
cd ruby
bundle install
ruby example.rb
rake test

105
.github/workflows/ci-rust.yml vendored Normal file
View File

@@ -0,0 +1,105 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-rust.yml
- manifest/**
- runtime/**
- rust/**
- libextism/**
workflow_dispatch:
name: Rust CI
env:
RUNTIME_CRATE: extism-runtime
LIBEXTISM_CRATE: libextism
RUST_SDK_CRATE: extism
jobs:
lib:
name: Extism runtime lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Cache Rust environment
uses: Swatinem/rust-cache@v1
- name: Cache libextism
id: cache-libextism
uses: actions/cache@v3
with:
path: target/release/libextism.*
key: ${{ runner.os }}-libextism-${{ hashFiles('runtime/**') }}-${{ hashFiles('manifest/**') }}
- name: Cache target
id: cache-target
uses: actions/cache@v3
with:
path: target/**
key: ${{ runner.os }}-target-${{ env.GITHUB_SHA }}
- name: Build
if: steps.cache-libextism.outputs.cache-hit != 'true'
shell: bash
run: cargo build --release -p ${{ env.LIBEXTISM_CRATE }}
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: libextism-${{ matrix.os }}
path: |
target/release/libextism.*
lint_and_test:
name: Extism runtime lint and test
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Cache Rust environment
uses: Swatinem/rust-cache@v1
- name: Cache target
id: cache-target
uses: actions/cache@v3
with:
path: target/**
key: ${{ runner.os }}-target-${{ env.GITHUB_SHA }}
- name: Format
run: cargo fmt --check -p ${{ env.RUNTIME_CRATE }}
- name: Lint
run: cargo clippy --release --all-features --no-deps -p ${{ env.RUNTIME_CRATE }}
- name: Test
run: cargo test --all-features --release -p ${{ env.RUNTIME_CRATE }}
rust:
name: Rust
needs: lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Test Rust Host SDK
run: LD_LIBRARY_PATH=/usr/local/lib cargo test --release -p ${{ env.RUST_SDK_CRATE }}

34
.github/workflows/ci-zig.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
on:
pull_request:
paths:
- .github/actions/extism/**
- .github/workflows/ci-zig.yml
- manifest/**
- runtime/**
- libextism/**
- zig/**
workflow_dispatch:
name: Zig CI
jobs:
zig:
name: Zig
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Zig env
uses: goto-bus-stop/setup-zig@v2
- name: Test Zig Host SDK
run: |
zig version
cd zig
LD_LIBRARY_PATH=/usr/local/lib zig build test

View File

@@ -2,361 +2,7 @@ on: [pull_request, workflow_dispatch]
name: CI
env:
RUNTIME_CRATE: extism-runtime
LIBEXTISM_CRATE: libextism
RUST_SDK_CRATE: extism
jobs:
lib:
name: Extism runtime lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Cache Rust environment
uses: Swatinem/rust-cache@v1
- name: Cache libextism
id: cache-libextism
uses: actions/cache@v3
with:
path: target/release/libextism.*
key: ${{ runner.os }}-libextism-${{ hashFiles('runtime/**') }}-${{ hashFiles('manifest/**') }}
- name: Cache target
id: cache-target
uses: actions/cache@v3
with:
path: target/**
key: ${{ runner.os }}-target-${{ env.GITHUB_SHA }}
- name: Build
if: steps.cache-libextism.outputs.cache-hit != 'true'
shell: bash
run: cargo build --release -p ${{ env.LIBEXTISM_CRATE }}
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: libextism-${{ matrix.os }}
path: |
target/release/libextism.*
lint_and_test:
name: Extism runtime lint and test
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Cache Rust environment
uses: Swatinem/rust-cache@v1
- name: Cache target
id: cache-target
uses: actions/cache@v3
with:
path: target/**
key: ${{ runner.os }}-target-${{ env.GITHUB_SHA }}
- name: Format
run: cargo fmt --check -p ${{ env.RUNTIME_CRATE }}
- name: Lint
run: cargo clippy --release --all-features --no-deps -p ${{ env.RUNTIME_CRATE }}
- name: Test
run: cargo test --all-features --release -p ${{ env.RUNTIME_CRATE }}
rust:
name: Rust
needs: lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Test Rust Host SDK
run: LD_LIBRARY_PATH=/usr/local/lib cargo test --release -p ${{ env.RUST_SDK_CRATE }}
elixir:
name: Elixir
needs: lib
runs-on: ${{ matrix.os }}
env:
MIX_ENV: test
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Elixir Host SDK
if: ${{ runner.os != 'macOS' }}
uses: erlef/setup-beam@v1
with:
experimental-otp: true
otp-version: '25.0.4'
elixir-version: '1.14.0'
- name: Test Elixir Host SDK
if: ${{ runner.os != 'macOS' }}
run: |
cd elixir
LD_LIBRARY_PATH=/usr/local/lib mix do deps.get, test
go:
name: Go
needs: lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Go env
uses: actions/setup-go@v3
- name: Test Go Host SDK
run: |
go version
cd go
LD_LIBRARY_PATH=/usr/local/lib go run main.go
LD_LIBRARY_PATH=/usr/local/lib go test
python:
name: Python
needs: lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Python env
uses: actions/setup-python@v4
with:
python-version: "3.9"
check-latest: true
- name: Install Poetry
uses: snok/install-poetry@v1
- name: Test Python Host SDK
run: |
cd python
cp ../README.md .
poetry install
poetry run python example.py
poetry run python -m unittest discover
ruby:
name: Ruby
needs: lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Ruby env
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.0"
- name: Test Ruby Host SDK
run: |
cd ruby
bundle install
ruby example.rb
rake test
node:
name: Node
needs: lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Node env
uses: actions/setup-node@v3
with:
node-version: 18
- name: Test Node Host SDK
run: |
cd node
npm i
LD_LIBRARY_PATH=/usr/local/lib npm run build
LD_LIBRARY_PATH=/usr/local/lib npm run example
LD_LIBRARY_PATH=/usr/local/lib npm run test
- name: Test Browser Runtime
run: |
cd browser
npm i
npm run test
ocaml:
name: OCaml
needs: lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup OCaml env
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: ocaml-base-compiler.5.0.0~beta1
- name: Cache OCaml
id: cache-ocaml
uses: actions/cache@v3
with:
path: _build
key: ${{ runner.os }}-ocaml-${{ hashFiles('ocaml/lib/**') }}-${{ hashFiles('ocaml/bin/**') }}-${{ hashFiles('dune-project') }}
- name: Build OCaml Host SDK
if: steps.cache-ocaml.outputs.cache-hit != 'true'
run: |
opam install -y --deps-only .
cd ocaml
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune build
- name: Test OCaml Host SDK
run: |
opam install -y --deps-only .
cd ocaml
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune exec ./bin/main.exe
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune runtest
haskell:
name: Haskell
needs: lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup Haskell env
uses: haskell/actions/setup@v2
with:
enable-stack: true
stack-version: "latest"
- name: Cache Haskell
id: cache-haskell
uses: actions/cache@v3
with:
path: .stack-work
key: ${{ runner.os }}-haskell-${{ hashFiles('haskell/**') }}
- name: Build Haskell Host SDK
if: steps.cache-haskell.outputs.cache-hit != 'true'
run: |
cd haskell
LD_LIBRARY_PATH=/usr/local/lib stack build
- name: Test Haskell SDK
run: |
cd haskell
LD_LIBRARY_PATH=/usr/local/lib stack test
php:
name: PHP
needs: lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Setup PHP env
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
extensions: ffi
tools: composer
env:
fail-fast: true
- name: Test PHP SDK
run: |
cd php/example
composer install
php index.php
cpp:
name: C++
needs: lib
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust:
- stable
steps:
- name: Checkout sources
uses: actions/checkout@v3
- uses: ./.github/actions/extism
- name: Install C++ SDK deps
if: ${{ matrix.os == 'macos-latest' }}
run: |
brew install jsoncpp googletest pkg-config
- name: Install C++ SDK deps
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
sudo apt-get install g++ libjsoncpp-dev libgtest-dev pkg-config
- name: Run C++ tests
run: |
cd cpp
LD_LIBRARY_PATH=/usr/local/lib make example
LD_LIBRARY_PATH=/usr/local/lib make test
sdk_api_coverage:
name: SDK API Coverage Report
runs-on: ubuntu-latest
@@ -376,3 +22,4 @@ jobs:
id: coverage
run: |
python scripts/sdk_coverage.py

View File

@@ -0,0 +1,29 @@
on:
workflow_dispatch:
name: Release .NET Native NuGet Packages
jobs:
release-runtimes:
name: release-dotnet-native
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: 7.x
- uses: dawidd6/action-download-artifact@v2
with:
workflow: release.yml
name: release-artifacts
- name: Extract Archive
run: |
tar -xvzf libextism-x86_64-pc-windows-msvc-v*.tar.gz --directory dotnet/nuget/runtimes
mv dotnet/nuget/runtimes/extism.dll dotnet/nuget/runtimes/win-x64.dll
- name: Publish win-x64
run: |
cd dotnet/nuget
dotnet pack -o dist
dotnet nuget push --source https://api.nuget.org/v3/index.json ./dist/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }}

32
.github/workflows/release-dotnet.yaml vendored Normal file
View File

@@ -0,0 +1,32 @@
on:
workflow_dispatch:
name: Release .NET SDK
jobs:
release-sdks:
name: release-dotnet
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install extism shared library
shell: bash
run: |
mkdir -p /home/runner/.local/bin/
export PATH="/home/runner/.local/bin/:$PATH"
curl https://raw.githubusercontent.com/extism/cli/main/install.sh | sh
extism --sudo --prefix /usr/local install
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: 7.x
- name: Test .NET Sdk
run: |
cd dotnet
LD_LIBRARY_PATH=/usr/local/lib dotnet test ./Extism.sln
- name: Publish .NET Sdk
run: |
cd dotnet/src/Extism.Sdk/
dotnet pack -c Release
dotnet nuget push --source https://api.nuget.org/v3/index.json ./bin/Release/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }}

View File

@@ -10,7 +10,13 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install extism shared library
shell: bash
run: |
mkdir -p /home/runner/.local/bin/
export PATH="/home/runner/.local/bin/:$PATH"
curl https://raw.githubusercontent.com/extism/cli/main/install.sh | sh
extism --sudo --prefix /usr/local install
- name: Setup Elixir Host SDK
uses: erlef/setup-beam@v1
with:

17
.github/workflows/release-haskell.yaml vendored Normal file
View File

@@ -0,0 +1,17 @@
on:
workflow_dispatch:
name: Release Rust SDK
jobs:
release-sdks:
name: release-rust
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: cachix/haskell-release-action@v1
with:
- hackage-token: "${{ secrets.HACKAGE_TOKEN }}"
- work-dir: ./haskell

22
.github/workflows/release-java.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Publish package to the Maven Central Repository
on:
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'adopt'
- name: Publish package
env:
JRELEASER_NEXUS2_USERNAME: ${{ secrets.JRELEASER_NEXUS2_USERNAME }}
JRELEASER_NEXUS2_PASSWORD: ${{ secrets.JRELEASER_NEXUS2_PASSWORD }}
JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }}
JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }}
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.JRELEASER_GPG_PUBLIC_KEY }}
JRELEASER_GITHUB_TOKEN: "dummy"
run: mvn -Prelease clean jreleaser:prepare deploy jreleaser:deploy -DaltDeploymentRepository=local::default::file:./target/staging-deploy

View File

@@ -23,9 +23,8 @@ jobs:
run: |
cd python
cp ../LICENSE .
cp ../README.md .
make clean
make prepare
poetry install --no-dev
poetry build
- name: Release Python Host SDK

View File

@@ -21,5 +21,5 @@ jobs:
RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_TOKEN }}
run: |
cd ruby
make publish
make publish RUBYGEMS_API_KEY=$RUBYGEMS_API_KEY

View File

@@ -7,7 +7,7 @@ name: Release
env:
RUNTIME_MANIFEST: runtime/Cargo.toml
RUNTIME_CRATE: extism-runtime
RUNTIME_CRATE: libextism
RUSTFLAGS: -C target-feature=-crt-static
ARTIFACT_DIR: release-artifacts

9
.gitignore vendored
View File

@@ -27,9 +27,12 @@ ruby/tmp/
ruby/Gemfile.lock
rust/target
rust/test.log
ocaml/duniverse
ocaml/_build
duniverse
_build
php/Extism.php
dist-newstyle
.stack-work
vendor
vendor
zig/zig-*
zig/example-out/
zig/*.log

1
.ocamlformat Normal file
View File

@@ -0,0 +1 @@
version = 0.24.1

View File

@@ -3,8 +3,6 @@ members = [
"manifest",
"runtime",
"rust",
"libextism"
]
exclude = [
"libextism",
"elixir/native/extism_nif"
]

View File

@@ -27,6 +27,9 @@ lint:
build:
cargo build --release $(FEATURE_FLAGS) --manifest-path libextism/Cargo.toml
debug:
RUSTFLAGS=-g $(MAKE) build
install:
install runtime/extism.h $(DEST)/include
install target/release/libextism.$(SOEXT) $(DEST)/lib

View File

@@ -10,16 +10,21 @@ The universal plug-in system. Run WebAssembly extensions inside your app. Use id
[Ruby](https://extism.org/docs/integrate-into-your-codebase/ruby-host-sdk), [Python](https://extism.org/docs/integrate-into-your-codebase/python-host-sdk),
[Node](https://extism.org/docs/integrate-into-your-codebase/node-host-sdk), [Rust](https://extism.org/docs/integrate-into-your-codebase/rust-host-sdk),
[C](https://extism.org/docs/integrate-into-your-codebase/c-host-sdk), [C++](https://extism.org/docs/integrate-into-your-codebase/cpp-host-sdk),
[OCaml](https://extism.org/docs/integrate-into-your-codebase/ocaml-host-sdk), [Haskell](https://extism.org/docs/integrate-into-your-codebase/haskell-host-sdk), [PHP](https://extism.org/docs/integrate-into-your-codebase/php-host-sdk), [Elixir/Erlang](https://extism.org/docs/integrate-into-your-codebase/elixir-or-erlang-host-sdk) &amp; more (others coming soon).
[OCaml](https://extism.org/docs/integrate-into-your-codebase/ocaml-host-sdk),
[Haskell](https://extism.org/docs/integrate-into-your-codebase/haskell-host-sdk),
[PHP](https://extism.org/docs/integrate-into-your-codebase/php-host-sdk),
[Elixir/Erlang](https://extism.org/docs/integrate-into-your-codebase/elixir-or-erlang-host-sdk),
[.NET](https://extism.org/docs/integrate-into-your-codebase/dotnet-host-sdk),
[Java](https://extism.org/docs/integrate-into-your-codebase/java-host-sdk),
[Zig](https://extism.org/docs/integrate-into-your-codebase/zig-host-sdk) &amp; more (others coming soon).
Plug-in development kits (PDK) for plug-in authors supported in [Rust](https://github.com/extism/rust-pdk), [AssemblyScript](https://github.com/extism/assemblyscript-pdk), [Go](https://github.com/extism/go-pdk), [C/C++](https://github.com/extism/c-pdk).
Plug-in development kits (PDK) for plug-in authors supported in [Rust](https://github.com/extism/rust-pdk), [AssemblyScript](https://github.com/extism/assemblyscript-pdk), [Go](https://github.com/extism/go-pdk), [C/C++](https://github.com/extism/c-pdk), [Haskell](https://github.com/extism/haskell-pdk), and [Zig](https://github.com/extism/zig-pdk).
<p align="center">
<img style="width: 70%;" src="https://user-images.githubusercontent.com/7517515/200043015-ddfe5833-0252-43a8-bc9e-5b3f829c37d1.png" alt="Extism embedded SDK language support"/>
<img style="width: 70%;" src="https://user-images.githubusercontent.com/7517515/210286900-39b144fd-1b26-4dd0-b7a9-2b5755bc174d.png" alt="Extism embedded SDK language support"/>
</p>
Add a flexible, secure, and _bLaZiNg FaSt_ plug-in system to your project. Server, desktop, mobile, web, database -- you name it. Enable users to write and execute safe extensions to your software in **3 easy steps:**
### 1. Import

28
browser/Makefile Normal file
View File

@@ -0,0 +1,28 @@
.PHONY: test
prepare:
npm install
build:
npm run build
test: prepare
npm run test
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

View File

@@ -1,12 +1,12 @@
const { build } = require("esbuild");
const { dependencies, peerDependencies } = require('./package.json')
const { peerDependencies } = require('./package.json')
const sharedConfig = {
entryPoints: ["src/index.ts"],
bundle: true,
minify: false,
drop: [], // preseve debugger statements
external: Object.keys(dependencies || {}).concat(Object.keys(peerDependencies || {})),
external: Object.keys(peerDependencies || {}),
};
build({

View File

@@ -104,7 +104,7 @@
async loadFunctions(url) {
let plugin = await this.extismContext.newPlugin({ "wasm": [ { "path": url } ] })
let functions = await plugin.getExportedFunctions()
let functions = Object.keys(await plugin.getExports())
console.log("funcs ", functions)
this.setState({functions})
}

1040
browser/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@extism/runtime-browser",
"version": "0.0.1-rc.12",
"version": "0.2.2",
"description": "Extism runtime in the browser",
"scripts": {
"build": "node build.js && tsc --emitDeclarationOnly --outDir dist",
@@ -17,7 +17,7 @@
],
"module": "dist/index.esm.js",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"typings": "dist/src/index.d.ts",
"author": "The Extism Authors <oss@extism.org>",
"license": "BSD-3-Clause",
"devDependencies": {
@@ -30,5 +30,8 @@
"tslint-config-prettier": "^1.18.0",
"typedoc": "^0.23.20",
"typescript": "^4.8.4"
},
"dependencies": {
"@bjorn3/browser_wasi_shim": "^0.2.1"
}
}

View File

@@ -12,7 +12,7 @@ describe('', () => {
const ctx = new ExtismContext();
const plugin = await ctx.newPlugin({ wasm: [{ data: data }] });
const functions = await plugin.getExports();
expect(Object.keys(functions).filter(x => !x.startsWith("__") && x !== "memory")).toEqual(['count_vowels']);
expect(Object.keys(functions).filter((x) => !x.startsWith('__') && x !== 'memory')).toEqual(['count_vowels']);
let output = await plugin.call('count_vowels', 'this is a test');
expect(parse(output)).toEqual({ count: 4 });
output = await plugin.call('count_vowels', 'this is a test again');

View File

@@ -1,5 +1,7 @@
import Allocator from './allocator';
import { PluginConfig } from './manifest';
//@ts-ignore TODO add types to this library
import { WASI, File } from "@bjorn3/browser_wasi_shim";
export default class ExtismPlugin {
moduleData: ArrayBuffer;
@@ -61,7 +63,19 @@ export default class ExtismPlugin {
return this.module;
}
const environment = this.makeEnv();
this.module = await WebAssembly.instantiate(this.moduleData, { env: environment });
const args: Array<string> = [];
const envVars: Array<string> = [];
let fds = [
new File([]), // stdin
new File([]), // stdout
new File([]), // stderr
];
let wasi = new WASI(args, envVars, fds);
let env = {
wasi_snapshot_preview1: wasi.wasiImport,
env: environment
};
this.module = await WebAssembly.instantiate(this.moduleData, env);
return this.module;
}

View File

@@ -6,7 +6,8 @@
"forceConsistentCasingInFileNames": true,
"declaration": true,
"strict": true,
"skipLibCheck": true
"skipLibCheck": true,
"allowJs": true
},
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}

View File

@@ -21,6 +21,7 @@ uint8_t *read_file(const char *filename, size_t *len) {
uint8_t *data = malloc(length);
if (data == NULL) {
fclose(fp);
return NULL;
}

View File

@@ -34,8 +34,7 @@
},
"files": [
"php/src/Context.php",
"php/src/Plugin.php",
"php/src/extism.h"
"php/src/Plugin.php"
]
},
"autoload-dev": {

View File

@@ -53,6 +53,10 @@ public:
Config config;
std::vector<Wasm> wasm;
std::vector<std::string> allowed_hosts;
std::map<std::string, std::string> allowed_paths;
uint64_t timeout_ms;
Manifest() : timeout_ms(30000) {}
static Manifest path(std::string s, std::string hash = std::string()) {
Manifest m;
@@ -94,6 +98,16 @@ public:
doc["allowed_hosts"] = h;
}
if (!this->allowed_paths.empty()) {
Json::Value h;
for (auto k : this->allowed_paths) {
h[k.first] = k.second;
}
doc["allowed_paths"] = h;
}
doc["timeout_ms"] = Json::Value(this->timeout_ms);
Json::FastWriter writer;
return writer.write(doc);
}
@@ -115,6 +129,15 @@ public:
void allow_host(std::string host) { this->allowed_hosts.push_back(host); }
void allow_path(std::string src, std::string dest = std::string()) {
if (dest.empty()) {
dest = src;
}
this->allowed_paths[src] = dest;
}
void set_timeout_ms(uint64_t ms) { this->timeout_ms = ms; }
void set_config(std::string k, std::string v) { this->config[k] = v; }
};
@@ -266,6 +289,7 @@ public:
class Context {
public:
std::shared_ptr<ExtismContext> pointer;
Context() {
this->pointer = std::shared_ptr<ExtismContext>(extism_context_new(),
extism_context_free);

479
dotnet/.gitignore vendored Normal file
View File

@@ -0,0 +1,479 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET
project.lock.json
project.fragment.lock.json
artifacts/
# Tye
.tye/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
##
## Visual studio for Mac
##
# globs
Makefile.in
*.userprefs
*.usertasks
config.make
config.status
aclocal.m4
install-sh
autom4te.cache/
*.tar.gz
tarballs/
test-results/
# Mac bundle stuff
*.dmg
*.app
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
nuget/runtimes/win-x64.dll

37
dotnet/Extism.sln Normal file
View File

@@ -0,0 +1,37 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33110.190
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.Sdk", "src\Extism.Sdk\Extism.Sdk.csproj", "{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.Sdk.Tests", "test\Extism.Sdk\Extism.Sdk.Tests.csproj", "{DB440D61-C781-4C59-9223-9A79CC9FB4E7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.Sdk.Sample", "samples\Extism.Sdk.Sample\Extism.Sdk.Sample.csproj", "{2232E572-E8BA-46A1-AF31-E4168960DB75}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Release|Any CPU.Build.0 = Release|Any CPU
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Release|Any CPU.Build.0 = Release|Any CPU
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2B6BF267-F2A5-4CB5-8DFD-F11CC8787E6B}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<NoBuild>true</NoBuild>
<IncludeBuildOutput>false</IncludeBuildOutput>
</PropertyGroup>
<PropertyGroup>
<PackageId>Extism.runtime.win-x64</PackageId>
<Version>0.2.0</Version>
<Authors>Extism Contributors</Authors>
<Description>Internal implementation package for Extism to work on Windows x64</Description>
<Tags>extism, wasm, plugin</Tags>
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
</PropertyGroup>
<ItemGroup>
<Content Include="runtimes/win-x64.dll"
CopyToOutputDirectory="Always"
Pack="true"
PackagePath="runtimes\win-x64\native\extism.dll" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1 @@
win-x64.dll

View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Include="..\..\..\wasm\code.wasm" Link="code.wasm">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Extism.Sdk\Extism.Sdk.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,11 @@
using Extism.Sdk.Native;
using System.Text;
var context = new Context();
var wasm = await File.ReadAllBytesAsync("./code.wasm");
using var plugin = context.CreatePlugin(wasm, withWasi: true);
var output = Encoding.UTF8.GetString(
plugin.CallFunction("count_vowels", Encoding.UTF8.GetBytes("Hello World!"))
);
Console.WriteLine(output); // prints {"count": 3}

View File

@@ -0,0 +1,5 @@
## Example 1
This example shows how you can use the library in the most basic way.
It loads up the sample wasm plugin and lets you to pass inputs to it and show the ouput.
**Please note that on Windows you have to manually copy the `extism.dll` file to the ouput directory.**

View File

@@ -0,0 +1,24 @@
<!-- Recommended practices for publishing nuget packages from: https://devblogs.microsoft.com/dotnet/producing-packages-with-source-link/ -->
<Project>
<PropertyGroup>
<!-- Publish the repository URL in the built .nupkg (in the NuSpec <Repository> element) -->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<!-- Embed source files that are not tracked by the source control manager in the PDB -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<!-- Recommended: Embed symbols containing Source Link in the main file (exe/dll) -->
<DebugType>embedded</DebugType>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,184 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
namespace Extism.Sdk.Native;
/// <summary>
/// Represents an Extism context through which you can load <see cref="Plugin"/>s.
/// </summary>
public class Context : IDisposable
{
private const int DisposedMarker = 1;
private int _disposed;
/// <summary>
/// Initialize a new Extism Context.
/// </summary>
public Context()
{
NativeHandle = LibExtism.extism_context_new();
}
/// <summary>
/// Native pointer to the Extism Context.
/// </summary>
internal IntPtr NativeHandle { get; }
/// <summary>
/// Loads an Extism <see cref="Plugin"/>.
/// </summary>
/// <param name="wasm">A WASM module (wat or wasm) or a JSON encoded manifest.</param>
/// <param name="withWasi">Enable/Disable WASI.</param>
public Plugin CreatePlugin(ReadOnlySpan<byte> wasm, bool withWasi)
{
CheckNotDisposed();
unsafe
{
fixed (byte* wasmPtr = wasm)
{
var plugin = LibExtism.extism_plugin_new(NativeHandle, wasmPtr, wasm.Length, withWasi);
return new Plugin(this, plugin);
}
}
}
/// <summary>
/// Remove all plugins from this <see cref="Context"/>'s registry.
/// </summary>
public void Reset()
{
CheckNotDisposed();
LibExtism.extism_context_reset(NativeHandle);
}
/// <summary>
/// Get this this <see cref="Context"/>'s last error.
/// </summary>
/// <returns></returns>
internal string? GetError()
{
CheckNotDisposed();
var result = LibExtism.extism_error(NativeHandle, -1);
return Marshal.PtrToStringUTF8(result);
}
/// <summary>
/// Frees all resources held by this Context.
/// </summary>
public void Dispose()
{
if (Interlocked.Exchange(ref _disposed, DisposedMarker) == DisposedMarker)
{
// Already disposed.
return;
}
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Throw an appropriate exception if the plugin has been disposed.
/// </summary>
/// <exception cref="ObjectDisposedException"></exception>
protected void CheckNotDisposed()
{
Interlocked.MemoryBarrier();
if (_disposed == DisposedMarker)
{
ThrowDisposedException();
}
}
[DoesNotReturn]
private static void ThrowDisposedException()
{
throw new ObjectDisposedException(nameof(Context));
}
/// <summary>
/// Frees all resources held by this Context.
/// </summary>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free up any managed resources here
}
// Free up unmanaged resources
LibExtism.extism_context_free(NativeHandle);
}
/// <summary>
/// Destructs the current Context and frees all resources used by it.
/// </summary>
~Context()
{
Dispose(false);
}
/// <summary>
/// Get the Extism version string.
/// </summary>
public static string GetExtismVersion()
{
var pointer = LibExtism.extism_version();
return Marshal.PtrToStringUTF8(pointer);
}
/// <summary>
/// Set Extism's log file and level. This is applied for all <see cref="Context"/>s.
/// </summary>
/// <param name="logPath">Log file; can be 'stdout' or 'stderr' to write logs to the console.</param>
/// <param name="level">The log level to write at.</param>
public static bool SetExtismLogFile(string logPath, LogLevel level)
{
var logLevel = level switch
{
LogLevel.Error => LibExtism.LogLevels.Error,
LogLevel.Warning => LibExtism.LogLevels.Warn,
LogLevel.Info => LibExtism.LogLevels.Info,
LogLevel.Debug => LibExtism.LogLevels.Debug,
LogLevel.Trace => LibExtism.LogLevels.Trace,
_ => throw new NotImplementedException(),
};
return LibExtism.extism_log_file(logPath, logLevel);
}
}
/// <summary>
/// Extism Log Levels
/// </summary>
public enum LogLevel
{
/// <summary>
/// Designates very serious errors.
/// </summary>
Error,
/// <summary>
/// Designates hazardous situations.
/// </summary>
Warning,
/// <summary>
/// Designates useful information.
/// </summary>
Info,
/// <summary>
/// Designates lower priority information.
/// </summary>
Debug,
/// <summary>
/// Designates very low priority, often extremely verbose, information.
/// </summary>
Trace
}

View File

@@ -0,0 +1,40 @@
namespace Extism.Sdk.Native;
using System;
/// <summary>
/// Represents errors that occur during calling Extism functions.
/// </summary>
public class ExtismException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="ExtismException"/> class.
/// </summary>
public ExtismException()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExtismException"/> class with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error .</param>
public ExtismException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExtismException"/> class
/// with a specified error message and a reference to the inner exception
/// that is the cause of this exception.
/// </summary>
/// <param name="message">The message that describes the error .</param>
/// <param name="innerException">
/// The exception that is the cause of the current exception, or a null reference
/// (Nothing in Visual Basic) if no inner exception is specified.
/// </param>
public ExtismException(string message, Exception innerException)
: base(message, innerException)
{
}
}

View File

@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<LangVersion>10</LangVersion>
</PropertyGroup>
<PropertyGroup>
<PackageId>Extism.Sdk</PackageId>
<Version>0.2.0</Version>
<Authors>Extism Contributors</Authors>
<Description>Extism SDK that allows hosting Extism plugins in .NET apps.</Description>
<Tags>extism, wasm, plugin</Tags>
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,170 @@
using System.Runtime.InteropServices;
namespace Extism.Sdk.Native;
/// <summary>
/// Functions exposed by the native Extism library.
/// </summary>
internal static class LibExtism
{
/// <summary>
/// Create a new context.
/// </summary>
/// <returns>A pointer to the newly created context.</returns>
[DllImport("extism")]
public static extern IntPtr extism_context_new();
/// <summary>
/// Remove a context from the registry and free associated memory.
/// </summary>
/// <param name="context"></param>
[DllImport("extism")]
public static extern void extism_context_free(IntPtr context);
/// <summary>
/// Load a WASM plugin.
/// </summary>
/// <param name="context">Pointer to the context the plugin will be associated with.</param>
/// <param name="wasm">A WASM module (wat or wasm) or a JSON encoded manifest.</param>
/// <param name="wasmSize">The length of the `wasm` parameter.</param>
/// <param name="withWasi">Enables/disables WASI.</param>
/// <returns></returns>
[DllImport("extism")]
unsafe public static extern IntPtr extism_plugin_new(IntPtr context, byte* wasm, int wasmSize, bool withWasi);
/// <summary>
/// Update a plugin, keeping the existing ID.
/// Similar to <see cref="extism_plugin_new"/> but takes an `plugin` argument to specify which plugin to update.
/// Memory for this plugin will be reset upon update.
/// </summary>
/// <param name="context">Pointer to the context the plugin is associated with.</param>
/// <param name="plugin">Pointer to the plugin you want to update.</param>
/// <param name="wasm">A WASM module (wat or wasm) or a JSON encoded manifest.</param>
/// <param name="wasmLength">The length of the `wasm` parameter.</param>
/// <param name="withWasi">Enables/disables WASI.</param>
/// <returns></returns>
[DllImport("extism")]
unsafe public static extern bool extism_plugin_update(IntPtr context, IntPtr plugin, byte* wasm, int wasmLength, bool withWasi);
/// <summary>
/// Remove a plugin from the registry and free associated memory.
/// </summary>
/// <param name="context">Pointer to the context the plugin is associated with.</param>
/// <param name="plugin">Pointer to the plugin you want to free.</param>
[DllImport("extism")]
public static extern void extism_plugin_free(IntPtr context, IntPtr plugin);
/// <summary>
/// Remove all plugins from the registry.
/// </summary>
/// <param name="context"></param>
[DllImport("extism")]
public static extern void extism_context_reset(IntPtr context);
/// <summary>
/// Update plugin config values, this will merge with the existing values.
/// </summary>
/// <param name="context">Pointer to the context the plugin is associated with.</param>
/// <param name="plugin">Pointer to the plugin you want to update the configurations for.</param>
/// <param name="json">The configuration JSON encoded in UTF8.</param>
/// <param name="jsonLength">The length of the `json` parameter.</param>
/// <returns></returns>
[DllImport("extism")]
unsafe public static extern bool extism_plugin_config(IntPtr context, IntPtr plugin, byte* json, int jsonLength);
/// <summary>
/// Returns true if funcName exists.
/// </summary>
/// <param name="context"></param>
/// <param name="plugin"></param>
/// <param name="funcName"></param>
/// <returns></returns>
[DllImport("extism")]
public static extern bool extism_plugin_function_exists(IntPtr context, IntPtr plugin, string funcName);
/// <summary>
/// Call a function.
/// </summary>
/// <param name="context"></param>
/// <param name="plugin"></param>
/// <param name="funcName">The function to call.</param>
/// <param name="data">Input data.</param>
/// <param name="dataLen">The length of the `data` parameter.</param>
/// <returns></returns>
[DllImport("extism")]
unsafe public static extern int extism_plugin_call(IntPtr context, IntPtr plugin, string funcName, byte* data, int dataLen);
/// <summary>
/// Get the error associated with a Context or Plugin, if plugin is -1 then the context error will be returned.
/// </summary>
/// <param name="context"></param>
/// <param name="plugin">A plugin pointer, or -1 for the context error.</param>
/// <returns></returns>
[DllImport("extism")]
public static extern IntPtr extism_error(IntPtr context, nint plugin);
/// <summary>
/// Get the length of a plugin's output data.
/// </summary>
/// <param name="context"></param>
/// <param name="plugin"></param>
/// <returns></returns>
[DllImport("extism")]
public static extern long extism_plugin_output_length(IntPtr context, IntPtr plugin);
/// <summary>
/// Get the plugin's output data.
/// </summary>
/// <param name="context"></param>
/// <param name="plugin"></param>
/// <returns></returns>
[DllImport("extism")]
public static extern IntPtr extism_plugin_output_data(IntPtr context, IntPtr plugin);
/// <summary>
/// Set log file and level.
/// </summary>
/// <param name="filename"></param>
/// <param name="logLevel"></param>
/// <returns></returns>
[DllImport("extism")]
public static extern bool extism_log_file(string filename, string logLevel);
/// <summary>
/// Get the Extism version string.
/// </summary>
/// <returns></returns>
[DllImport("extism", EntryPoint = "extism_version")]
public static extern IntPtr extism_version();
/// <summary>
/// Extism Log Levels
/// </summary>
public static class LogLevels
{
/// <summary>
/// Designates very serious errors.
/// </summary>
public const string Error = "Error";
/// <summary>
/// Designates hazardous situations.
/// </summary>
public const string Warn = "Warn";
/// <summary>
/// Designates useful information.
/// </summary>
public const string Info = "Info";
/// <summary>
/// Designates lower priority information.
/// </summary>
public const string Debug = "Debug";
/// <summary>
/// Designates very low priority, often extremely verbose, information.
/// </summary>
public const string Trace = "Trace";
}
}

View File

@@ -0,0 +1,189 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
namespace Extism.Sdk.Native;
/// <summary>
/// Represents a WASM Extism plugin.
/// </summary>
public class Plugin : IDisposable
{
private const int DisposedMarker = 1;
private readonly Context _context;
private int _disposed;
internal Plugin(Context context, IntPtr handle)
{
_context = context;
NativeHandle = handle;
}
/// <summary>
/// A pointer to the native Plugin struct.
/// </summary>
internal IntPtr NativeHandle { get; }
/// <summary>
/// Update a plugin, keeping the existing ID.
/// </summary>
/// <param name="wasm">The plugin WASM bytes.</param>
/// <param name="withWasi">Enable/Disable WASI.</param>
unsafe public bool Update(ReadOnlySpan<byte> wasm, bool withWasi)
{
CheckNotDisposed();
fixed (byte* wasmPtr = wasm)
{
return LibExtism.extism_plugin_update(_context.NativeHandle, NativeHandle, wasmPtr, wasm.Length, withWasi);
}
}
/// <summary>
/// Update plugin config values, this will merge with the existing values.
/// </summary>
/// <param name="json">The configuration JSON encoded in UTF8.</param>
unsafe public bool SetConfig(ReadOnlySpan<byte> json)
{
CheckNotDisposed();
fixed (byte* jsonPtr = json)
{
return LibExtism.extism_plugin_config(_context.NativeHandle, NativeHandle, jsonPtr, json.Length);
}
}
/// <summary>
/// Checks if a specific function exists in the current plugin.
/// </summary>
public bool FunctionExists(string name)
{
CheckNotDisposed();
return LibExtism.extism_plugin_function_exists(_context.NativeHandle, NativeHandle, name);
}
/// <summary>
/// Calls a function in the current plugin and returns a status.
/// If the status represents an error, call <see cref="GetError"/> to get the error.
/// Othewise, call <see cref="OutputData"/> to get the function's output data.
/// </summary>
/// <param name="functionName">Name of the function in the plugin to invoke.</param>
/// <param name="data">A buffer to provide as input to the function.</param>
/// <returns>The exit code of the function.</returns>
/// <exception cref="ExtismException"></exception>
unsafe public ReadOnlySpan<byte> CallFunction(string functionName, ReadOnlySpan<byte> data)
{
CheckNotDisposed();
fixed (byte* dataPtr = data)
{
int response = LibExtism.extism_plugin_call(_context.NativeHandle, NativeHandle, functionName, dataPtr, data.Length);
if (response == 0) {
return OutputData();
} else {
var errorMsg = GetError();
if (errorMsg != null) {
throw new ExtismException(errorMsg);
} else {
throw new ExtismException("Call to Extism failed");
}
}
}
}
/// <summary>
/// Get the length of a plugin's output data.
/// </summary>
/// <returns></returns>
internal int OutputLength()
{
CheckNotDisposed();
return (int)LibExtism.extism_plugin_output_length(_context.NativeHandle, NativeHandle);
}
/// <summary>
/// Get the plugin's output data.
/// </summary>
internal ReadOnlySpan<byte> OutputData()
{
CheckNotDisposed();
var length = OutputLength();
unsafe
{
var ptr = LibExtism.extism_plugin_output_data(_context.NativeHandle, NativeHandle).ToPointer();
return new Span<byte>(ptr, length);
}
}
/// <summary>
/// Get the error associated with the current plugin.
/// </summary>
/// <returns></returns>
internal string? GetError()
{
CheckNotDisposed();
var result = LibExtism.extism_error(_context.NativeHandle, NativeHandle);
return Marshal.PtrToStringUTF8(result);
}
/// <summary>
/// Frees all resources held by this Plugin.
/// </summary>
public void Dispose()
{
if (Interlocked.Exchange(ref _disposed, DisposedMarker) == DisposedMarker)
{
// Already disposed.
return;
}
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Throw an appropriate exception if the plugin has been disposed.
/// </summary>
/// <exception cref="ObjectDisposedException"></exception>
protected void CheckNotDisposed()
{
Interlocked.MemoryBarrier();
if (_disposed == DisposedMarker)
{
ThrowDisposedException();
}
}
[DoesNotReturn]
private static void ThrowDisposedException()
{
throw new ObjectDisposedException(nameof(Plugin));
}
/// <summary>
/// Frees all resources held by this Plugin.
/// </summary>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free up any managed resources here
}
// Free up unmanaged resources
LibExtism.extism_plugin_free(_context.NativeHandle, NativeHandle);
}
/// <summary>
/// Destructs the current Plugin and frees all resources used by it.
/// </summary>
~Plugin()
{
Dispose(false);
}
}

View File

@@ -0,0 +1,2 @@
## Extism.Sdk
Extism SDK that allows hosting Extism plugins in .NET apps.

View File

@@ -0,0 +1,24 @@
using Extism.Sdk.Native;
using System.Reflection;
using System.Text;
using Xunit;
namespace Extism.Sdk.Tests;
public class BasicTests
{
[Fact]
public void CountHelloWorldVowels()
{
using var context = new Context();
var binDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
var wasm = File.ReadAllBytes(Path.Combine(binDirectory, "code.wasm"));
using var plugin = context.CreatePlugin(wasm, withWasi: true);
var response = plugin.CallFunction("count_vowels", Encoding.UTF8.GetBytes("Hello World"));
Assert.Equal("{\"count\": 3}", Encoding.UTF8.GetString(response));
}
}

View File

@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\wasm\code.wasm" Link="code.wasm">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Extism.Sdk\Extism.Sdk.csproj" />
</ItemGroup>
</Project>

View File

@@ -19,6 +19,28 @@
(name extism)
(synopsis "Extism bindings")
(description "Bindings to Extism, the universal plugin system")
(depends ocaml dune ctypes-foreign bigstringaf ppx_yojson_conv base64 ppx_inline_test)
(depends
(ocaml (>= 4.14.1))
(dune (>= 3.2))
(ctypes-foreign (>= 0.18.0))
(bigstringaf (>= 0.9.0))
(ppx_yojson_conv (>= 0.15.0))
extism-manifest
(ppx_inline_test (>= 0.15.0))
(cmdliner (>= 1.1.1))
)
(tags
(topics wasm plugin)))
(package
(name extism-manifest)
(synopsis "Extism manifest bindings")
(description "Bindings to Extism, the universal plugin system")
(depends
(ocaml (>= 4.14.1))
(dune (>= 3.2))
(ppx_yojson_conv (>= 0.15.0))
(base64 (>= 3.5.0))
)
(tags
(topics wasm plugin)))

View File

@@ -13,7 +13,7 @@ You can find this package on [hex.pm](https://hex.pm/packages/extism).
```elixir
def deps do
[
{:extism, "~> 0.0.1-rc.6"}
{:extism, "~> 0.1.0"}
]
end
```
@@ -70,4 +70,4 @@ The key method to know here is [Extism.Plugin#call](Extism.Plugin.html#call/3) w
```elixir
{:ok, plugin} = Extism.Context.new_plugin(ctx, manifest, false)
{:ok, output} = Extism.Plugin.call(plugin, "count_vowels", "this is a test")
```
```

View File

@@ -4,8 +4,8 @@ defmodule Extism.MixProject do
def project do
[
app: :extism,
version: "0.0.1-rc.6",
elixir: "~> 1.14",
version: "0.1.0",
elixir: "~> 1.12",
start_permanent: Mix.env() == :prod,
deps: deps(),
package: package(),
@@ -43,7 +43,7 @@ defmodule Extism.MixProject do
licenses: ["BSD-3-Clause"],
description: "Extism Host SDK for Elixir and Erlang",
name: "extism",
files: ~w(lib native priv .formatter.exs mix.exs README.md LICENSE),
files: ~w(lib native .formatter.exs mix.exs README.md LICENSE),
links: %{"GitHub" => "https://github.com/extism/extism"}
]
end

View File

@@ -1,6 +1,6 @@
[package]
name = "extism_nif"
version = "0.0.1-rc.6"
version = "0.1.0"
edition = "2021"
authors = ["Benjamin Eckel <bhelx@simst.im>"]
@@ -11,5 +11,5 @@ crate-type = ["cdylib"]
[dependencies]
rustler = "0.26.0"
extism = { version = "0.0.1-rc.6" }
extism = { version = "0.1.0", path = "../../../rust" }
log = "0.4"

View File

@@ -1,10 +1,10 @@
use rustler::{Atom, Env, Term, ResourceArc};
use extism::{Plugin, Context};
use std::str;
use extism::{Context, Plugin};
use rustler::{Atom, Env, ResourceArc, Term};
use std::mem;
use std::path::Path;
use std::str;
use std::str::FromStr;
use std::sync::RwLock;
use std::mem;
mod atoms {
rustler::atoms! {
@@ -15,9 +15,12 @@ mod atoms {
}
struct ExtismContext {
ctx: RwLock<Context>
ctx: RwLock<Context>,
}
unsafe impl Sync for ExtismContext {}
unsafe impl Send for ExtismContext {}
fn load(env: Env, _: Term) -> bool {
rustler::resource!(ExtismContext, env);
true
@@ -27,15 +30,16 @@ fn to_rustler_error(extism_error: extism::Error) -> rustler::Error {
match extism_error {
extism::Error::UnableToLoadPlugin(msg) => rustler::Error::Term(Box::new(msg)),
extism::Error::Message(msg) => rustler::Error::Term(Box::new(msg)),
extism::Error::Json(json_err) => rustler::Error::Term(Box::new(json_err.to_string()))
extism::Error::Json(json_err) => rustler::Error::Term(Box::new(json_err.to_string())),
extism::Error::Runtime(e) => rustler::Error::Term(Box::new(e.to_string())),
}
}
#[rustler::nif]
fn context_new() -> ResourceArc<ExtismContext> {
ResourceArc::new(
ExtismContext { ctx: RwLock::new(Context::new()) }
)
ResourceArc::new(ExtismContext {
ctx: RwLock::new(Context::new()),
})
}
#[rustler::nif]
@@ -51,7 +55,11 @@ fn context_free(ctx: ResourceArc<ExtismContext>) {
}
#[rustler::nif]
fn plugin_new_with_manifest(ctx: ResourceArc<ExtismContext>, manifest_payload: String, wasi: bool) -> Result<i32, rustler::Error> {
fn plugin_new_with_manifest(
ctx: ResourceArc<ExtismContext>,
manifest_payload: String,
wasi: bool,
) -> Result<i32, rustler::Error> {
let context = &ctx.ctx.write().unwrap();
let result = match Plugin::new(context, manifest_payload, wasi) {
Err(e) => Err(to_rustler_error(e)),
@@ -67,17 +75,22 @@ fn plugin_new_with_manifest(ctx: ResourceArc<ExtismContext>, manifest_payload: S
}
#[rustler::nif]
fn plugin_call(ctx: ResourceArc<ExtismContext>, plugin_id: i32, name: String, input: String) -> Result<String, rustler::Error> {
fn plugin_call(
ctx: ResourceArc<ExtismContext>,
plugin_id: i32,
name: String,
input: String,
) -> Result<String, rustler::Error> {
let context = &ctx.ctx.read().unwrap();
let plugin = unsafe { Plugin::from_id(plugin_id, context) };
let mut plugin = unsafe { Plugin::from_id(plugin_id, context) };
let result = match plugin.call(name, input) {
Err(e) => Err(to_rustler_error(e)),
Ok(result) => {
match str::from_utf8(&result) {
Ok(output) => Ok(output.to_string()),
Err(_e) => Err(rustler::Error::Term(Box::new("Could not read output from plugin")))
}
}
Ok(result) => match str::from_utf8(&result) {
Ok(output) => Ok(output.to_string()),
Err(_e) => Err(rustler::Error::Term(Box::new(
"Could not read output from plugin",
))),
},
};
// this forget should be safe because the context will clean up
// all it's plugins when it is dropped
@@ -86,14 +99,17 @@ fn plugin_call(ctx: ResourceArc<ExtismContext>, plugin_id: i32, name: String, in
}
#[rustler::nif]
fn plugin_update_manifest(ctx: ResourceArc<ExtismContext>, plugin_id: i32, manifest_payload: String, wasi: bool) -> Result<(), rustler::Error> {
fn plugin_update_manifest(
ctx: ResourceArc<ExtismContext>,
plugin_id: i32,
manifest_payload: String,
wasi: bool,
) -> Result<(), rustler::Error> {
let context = &ctx.ctx.read().unwrap();
let mut plugin = unsafe { Plugin::from_id(plugin_id, context) };
let result = match plugin.update(manifest_payload, wasi) {
Ok(()) => {
Ok(())
},
Err(e) => Err(to_rustler_error(e))
Ok(()) => Ok(()),
Err(e) => Err(to_rustler_error(e)),
};
// this forget should be safe because the context will clean up
// all it's plugins when it is dropped
@@ -113,19 +129,28 @@ fn plugin_free(ctx: ResourceArc<ExtismContext>, plugin_id: i32) -> Result<(), ru
fn set_log_file(filename: String, log_level: String) -> Result<Atom, rustler::Error> {
let path = Path::new(&filename);
match log::Level::from_str(&log_level) {
Err(_e) => Err(rustler::Error::Term(Box::new(format!("{} not a valid log level", log_level)))),
Err(_e) => Err(rustler::Error::Term(Box::new(format!(
"{} not a valid log level",
log_level
)))),
Ok(level) => {
if extism::set_log_file(path, Some(level)) {
Ok(atoms::ok())
} else {
Err(rustler::Error::Term(Box::new("Did not set log file, received false from the API.")))
Err(rustler::Error::Term(Box::new(
"Did not set log file, received false from the API.",
)))
}
}
}
}
#[rustler::nif]
fn plugin_has_function(ctx: ResourceArc<ExtismContext>, plugin_id: i32, function_name: String) -> Result<bool, rustler::Error> {
fn plugin_has_function(
ctx: ResourceArc<ExtismContext>,
plugin_id: i32,
function_name: String,
) -> Result<bool, rustler::Error> {
let context = &ctx.ctx.read().unwrap();
let plugin = unsafe { Plugin::from_id(plugin_id, context) };
let has_function = plugin.has_function(function_name);

33
extism-manifest.opam Normal file
View File

@@ -0,0 +1,33 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
synopsis: "Extism manifest bindings"
description: "Bindings to Extism, the universal plugin system"
maintainer: ["Extism Authors <oss@extism.org>"]
authors: ["Extism Authors <oss@extism.org>"]
license: "BSD-3-Clause"
tags: ["topics" "wasm" "plugin"]
homepage: "https://github.com/extism/extism"
doc: "https://github.com/extism/extism"
bug-reports: "https://github.com/extism/extism/issues"
depends: [
"ocaml" {>= "4.14.1"}
"dune" {>= "3.2" & >= "3.2"}
"ppx_yojson_conv" {>= "0.15.0"}
"base64" {>= "3.5.0"}
"odoc" {with-doc}
]
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/extism/extism.git"

View File

@@ -53,11 +53,11 @@ type WasmFile struct {
}
type WasmUrl struct {
Url string `json:"url"`
Hash string `json:"hash,omitempty"`
Header map[string]string `json:"header,omitempty"`
Name string `json:"name,omitempty"`
Method string `json:"method,omitempty"`
Url string `json:"url"`
Hash string `json:"hash,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
Name string `json:"name,omitempty"`
Method string `json:"method,omitempty"`
}
type Wasm interface{}
@@ -65,10 +65,12 @@ type Wasm interface{}
type Manifest struct {
Wasm []Wasm `json:"wasm"`
Memory struct {
Max uint32 `json:"max,omitempty"`
MaxPages uint32 `json:"max_pages,omitempty"`
} `json:"memory,omitempty"`
Config map[string]string `json:"config,omitempty"`
AllowedHosts []string `json:"allowed_hosts,omitempty"`
AllowedPaths map[string]string `json:"allowed_paths,omitempty"`
Timeout uint `json:"timeout_ms,omitempty"`
}
func makePointer(data []byte) unsafe.Pointer {

View File

@@ -10,13 +10,14 @@ homepage: "https://github.com/extism/extism"
doc: "https://github.com/extism/extism"
bug-reports: "https://github.com/extism/extism/issues"
depends: [
"ocaml"
"dune" {>= "3.2"}
"ctypes-foreign"
"bigstringaf"
"ppx_yojson_conv"
"base64"
"ppx_inline_test"
"ocaml" {>= "4.14.1"}
"dune" {>= "3.2" & >= "3.2"}
"ctypes-foreign" {>= "0.18.0"}
"bigstringaf" {>= "0.9.0"}
"ppx_yojson_conv" {>= "0.15.0"}
"extism-manifest"
"ppx_inline_test" {>= "0.15.0"}
"cmdliner" {>= "1.1.1"}
"odoc" {with-doc}
]
build: [

View File

@@ -1,23 +1,16 @@
module Main where
import System.Exit (exitFailure, exitSuccess)
import qualified Data.ByteString as B
import Extism
import Extism.Manifest
import Extism.Manifest(manifest, wasmFile)
try f (Right x) = f x
try f (Left (ErrorMessage msg)) = do
_ <- putStrLn msg
exitFailure
handlePlugin plugin = do
res <- Extism.call plugin "count_vowels" (Extism.toByteString "this is a test")
try (\bs -> do
_ <- putStrLn (Extism.fromByteString bs)
_ <- Extism.free plugin
exitSuccess) res
unwrap (Right x) = x
unwrap (Left (ExtismError msg)) = do
error msg
main = do
context <- Extism.newContext ()
plugin <- Extism.pluginFromManifest context (manifest [wasmFile "../wasm/code.wasm"]) False
try handlePlugin plugin
let m = manifest [wasmFile "../wasm/code.wasm"]
context <- Extism.newContext
plugin <- unwrap <$> Extism.pluginFromManifest context m False
res <- unwrap <$> Extism.call plugin "count_vowels" (Extism.toByteString "this is a test")
putStrLn (Extism.fromByteString res)
Extism.free plugin

30
haskell/Makefile Normal file
View File

@@ -0,0 +1,30 @@
.PHONY: test
prepare:
cabal update
build: prepare
cabal build
test: prepare
cabal test
clean:
cabal clean
publish: clean prepare
cabal sdist
# TODO: upload
format:
# TODO
lint:
cabal check
hlint src manifest
docs:
# TODO
show-docs: docs
# TODO

1
haskell/cabal.project Normal file
View File

@@ -0,0 +1 @@
packages: extism.cabal manifest/extism-manifest.cabal

View File

@@ -1,54 +1,45 @@
cabal-version: 2.4
cabal-version: 3.0
name: extism
version: 0.0.1.0
-- A short (one-line) description of the package.
synopsis: Extism bindings
-- A longer description of the package.
description: Bindings to Extism, the universal plugin system
-- A URL where users can report bugs.
bug-reports: https://github.com/extism/extism
-- The license under which the package is released.
license: BSD-3-Clause
author: Extism authors
version: 0.0.1
license: BSD-3-Clause
maintainer: oss@extism.org
-- A copyright notice.
-- copyright:
category: Plugins, WebAssembly
author: Extism authors
bug-reports: https://github.com/extism/extism
synopsis: Extism bindings
description: Bindings to Extism, the universal plugin system
category: Plugins, WebAssembly
extra-source-files: CHANGELOG.md
library
exposed-modules: Extism Extism.Manifest
exposed-modules: Extism
reexported-modules: Extism.Manifest
hs-source-dirs: src
other-modules: Extism.Bindings
default-language: Haskell2010
extra-libraries: extism
extra-lib-dirs: /usr/local/lib
build-depends:
base >= 4.16.1 && < 4.18.0,
bytestring >= 0.11.3 && < 0.12,
json >= 0.10 && < 0.11,
extism-manifest >= 0.0.0 && < 0.1.0
-- Modules included in this library but not exported.
other-modules:
test-suite extism-example
type: exitcode-stdio-1.0
main-is: Example.hs
default-language: Haskell2010
build-depends:
base,
extism,
bytestring
-- LANGUAGE extensions used by modules in this package.
-- other-extensions:
build-depends:
base ^>=4.16.1.0
, bytestring
, base64-bytestring
, json
hs-source-dirs: src
default-language: Haskell2010
extra-libraries: extism
extra-lib-dirs: /usr/local/lib
Test-Suite extism-example
type: exitcode-stdio-1.0
main-is: Example.hs
build-depends: base, extism, bytestring
default-language: Haskell2010
Test-Suite extism-test
type: exitcode-stdio-1.0
main-is: Test.hs
test-suite extism-test
type: exitcode-stdio-1.0
main-is: Test.hs
hs-source-dirs: test
build-depends: base, extism, bytestring, HUnit
default-language: Haskell2010
build-depends:
base,
extism,
bytestring,
HUnit

View File

@@ -0,0 +1,5 @@
# Revision history for extism-manifest
## 0.1.0.0 -- YYYY-mm-dd
* First version. Released on an unsuspecting world.

View File

@@ -0,0 +1,58 @@
module Extism.JSON (
module Extism.JSON,
module Text.JSON
) where
import Text.JSON
import qualified Data.ByteString as B
import Data.ByteString.Internal (c2w, w2c)
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Char8 as BS (unpack)
data Nullable a = Null | NotNull a
makeArray x = JSArray [showJSON a | a <- x]
isNull JSNull = True
isNull _ = False
filterNulls obj = [(a, b) | (a, b) <- obj, not (isNull b)]
object x = makeObj $ filterNulls x
objectWithNulls x = makeObj x
nonNull x = NotNull x
null' = Null
(.=) a b = (a, showJSON b)
toNullable (Just x) = NotNull x
toNullable Nothing = Null
fromNullable (NotNull x) = Just x
fromNullable Null = Nothing
mapNullable f Null = Null
mapNullable f (NotNull x) = NotNull (f x)
(.?) (JSObject a) k =
case valFromObj k a of
Ok x -> NotNull x
Error _ -> Null
(.?) _ _ = Null
(.??) a k = toNullable $ lookup k a
find :: JSON a => String -> JSValue -> Nullable a
find k obj = obj .? k
update :: JSON a => String -> a -> JSValue -> JSValue
update k v (JSObject obj) = object $ (fromJSObject obj) ++ [k .= v]
instance JSON a => JSON (Nullable a) where
showJSON (NotNull x) = showJSON x
showJSON Null = JSNull
readJSON JSNull = Ok Null
readJSON x = readJSON x
newtype Base64 = Base64 B.ByteString
instance JSON Base64 where
showJSON (Base64 bs) = showJSON (BS.unpack $ B64.encode bs)
readJSON (JSString s) =
let toByteString x = B.pack (Prelude.map c2w x) in
case B64.decode (toByteString (fromJSString s)) of
Left msg -> Error msg
Right d -> Ok (Base64 d)

View File

@@ -0,0 +1,247 @@
module Extism.Manifest where
import Extism.JSON
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BS (unpack)
-- | Memory options
newtype Memory = Memory
{
memoryMaxPages :: Nullable Int
}
instance JSON Memory where
showJSON (Memory max) =
object [
"max_pages" .= max
]
readJSON obj =
let max = obj .? "max_pages" in
Ok (Memory max)
-- | HTTP request
data HTTPRequest = HTTPRequest
{
url :: String
, headers :: Nullable [(String, String)]
, method :: Nullable String
}
makeKV x =
object [(k, showJSON v) | (k, v) <- x]
requestObj (HTTPRequest url headers method) =
[
"url" .= url,
"headers" .= mapNullable makeKV headers,
"method" .= method
]
instance JSON HTTPRequest where
showJSON req = object $ requestObj req
readJSON x =
let url = x .? "url" in
let headers = x .? "headers" in
let method = x .? "method" in
case url of
Null -> Error "Missing 'url' field"
NotNull url -> Ok (HTTPRequest url headers method)
-- | WASM from file
data WasmFile = WasmFile
{
filePath :: String
, fileName :: Nullable String
, fileHash :: Nullable String
}
instance JSON WasmFile where
showJSON (WasmFile path name hash) =
object [
"path" .= path,
"name" .= name,
"hash" .= hash
]
readJSON x =
let path = x .? "url" in
let name = x .? "name" in
let hash = x .? "hash" in
case path of
Null -> Error "Missing 'path' field"
NotNull path -> Ok (WasmFile path name hash)
-- | WASM from raw bytes
data WasmData = WasmData
{
dataBytes :: Base64
, dataName :: Nullable String
, dataHash :: Nullable String
}
instance JSON WasmData where
showJSON (WasmData bytes name hash) =
object [
"data" .= bytes,
"name" .= name,
"hash" .= hash
]
readJSON x =
let d = x .? "data" in
let name = x .? "name" in
let hash = x .? "hash" in
case d of
Null -> Error "Missing 'path' field"
NotNull d ->
case readJSON d of
Error msg -> Error msg
Ok d' -> Ok (WasmData d' name hash)
-- | WASM from a URL
data WasmURL = WasmURL
{
req :: HTTPRequest
, urlName :: Nullable String
, urlHash :: Nullable String
}
instance JSON WasmURL where
showJSON (WasmURL req name hash) =
object (
"name" .= name :
"hash" .= hash :
requestObj req)
readJSON x =
let req = x .? "req" in
let name = x .? "name" in
let hash = x .? "hash" in
case fromNullable req of
Nothing -> Error "Missing 'req' field"
Just req -> Ok (WasmURL req name hash)
-- | Specifies where to get WASM module data
data Wasm = File WasmFile | Data WasmData | URL WasmURL
instance JSON Wasm where
showJSON x =
case x of
File f -> showJSON f
Data d -> showJSON d
URL u -> showJSON u
readJSON x =
let file = (readJSON x :: Result WasmFile) in
case file of
Ok x -> Ok (File x)
Error _ ->
let data' = (readJSON x :: Result WasmData) in
case data' of
Ok x -> Ok (Data x)
Error _ ->
let url = (readJSON x :: Result WasmURL) in
case url of
Ok x -> Ok (URL x)
Error _ -> Error "JSON does not match any of the Wasm types"
wasmFile :: String -> Wasm
wasmFile path =
File WasmFile { filePath = path, fileName = null', fileHash = null'}
wasmURL :: String -> String -> Wasm
wasmURL method url =
let r = HTTPRequest { url = url, headers = null', method = nonNull method } in
URL WasmURL { req = r, urlName = null', urlHash = null' }
wasmData :: B.ByteString -> Wasm
wasmData d =
Data WasmData { dataBytes = Base64 d, dataName = null', dataHash = null' }
withName :: Wasm -> String -> Wasm
withName (Data d) name = Data d { dataName = nonNull name }
withName (URL url) name = URL url { urlName = nonNull name }
withName (File f) name = File f { fileName = nonNull name }
withHash :: Wasm -> String -> Wasm
withHash (Data d) hash = Data d { dataHash = nonNull hash }
withHash (URL url) hash = URL url { urlHash = nonNull hash }
withHash (File f) hash = File f { fileHash = nonNull hash }
-- | The 'Manifest' type is used to provide WASM data and configuration to the
-- | Extism runtime
data Manifest = Manifest
{
wasm :: [Wasm]
, memory :: Nullable Memory
, config :: Nullable [(String, String)]
, allowedHosts :: Nullable [String]
, allowedPaths :: Nullable [(String, String)]
, timeout :: Nullable Int
}
instance JSON Manifest where
showJSON (Manifest wasm memory config hosts paths timeout) =
let w = makeArray wasm in
object [
"wasm" .= w,
"memory" .= memory,
"config" .= mapNullable makeKV config,
"allowed_hosts" .= hosts,
"allowed_paths" .= mapNullable makeKV paths,
"timeout_ms" .= timeout
]
readJSON x =
let wasm = x .? "wasm" in
let memory = x .? "memory" in
let config = x .? "config" in
let hosts = x .? "allowed_hosts" in
let paths = x .? "allowed_paths" in
let timeout = x .? "timeout_ms" in
case fromNullable wasm of
Nothing -> Error "Missing 'wasm' field"
Just wasm -> Ok (Manifest wasm memory config hosts paths timeout)
-- | Create a new 'Manifest' from a list of 'Wasm'
manifest :: [Wasm] -> Manifest
manifest wasm =
Manifest {
wasm = wasm,
memory = null',
config = null',
allowedHosts = null',
allowedPaths = null',
timeout = null'
}
-- | Update the config values
withConfig :: Manifest -> [(String, String)] -> Manifest
withConfig m config =
m { config = nonNull config }
-- | Update allowed hosts for `extism_http_request`
withHosts :: Manifest -> [String] -> Manifest
withHosts m hosts =
m { allowedHosts = nonNull hosts }
-- | Update allowed paths
withPaths :: Manifest -> [(String, String)] -> Manifest
withPaths m p =
m { allowedPaths = nonNull p }
-- | Update plugin timeout (in milliseconds)
withTimeout :: Manifest -> Int -> Manifest
withTimeout m t =
m { timeout = nonNull t }
toString :: (JSON a) => a -> String
toString v =
encode (showJSON v)

View File

@@ -0,0 +1,21 @@
cabal-version: 3.0
name: extism-manifest
version: 0.0.1
license: BSD-3-Clause
maintainer: oss@extism.org
author: Extism authors
bug-reports: https://github.com/extism/extism
synopsis: Extism manifest bindings
description: Bindings to Extism WebAssembly manifest
category: Plugins, WebAssembly
extra-source-files: CHANGELOG.md
library
exposed-modules: Extism.Manifest Extism.JSON
hs-source-dirs: .
default-language: Haskell2010
build-depends:
base >= 4.16.1 && < 4.18.0,
bytestring >= 0.11.3 && < 0.12,
json >= 0.10 && < 0.11,
base64-bytestring >= 1.2.1 && < 1.3,

View File

@@ -1,84 +1,68 @@
{-# LANGUAGE ForeignFunctionInterface #-}
module Extism (module Extism, module Extism.Manifest) where
import GHC.Int
import GHC.Word
import Foreign.C.Types
import Foreign.Ptr
import Data.Int
import Data.Word
import Control.Monad (void)
import Foreign.ForeignPtr
import Foreign.C.String
import Control.Monad (void)
import Foreign.Ptr
import Data.ByteString as B
import Data.ByteString.Internal (c2w, w2c)
import Data.ByteString.Unsafe (unsafeUseAsCString)
import Data.Bifunctor (second)
import Text.JSON (JSON, toJSObject, toJSString, encode, JSValue(JSNull, JSString))
import Text.JSON (encode, toJSObject, showJSON)
import Extism.Manifest (Manifest, toString)
import Extism.Bindings
newtype ExtismContext = ExtismContext () deriving Show
foreign import ccall unsafe "extism.h extism_context_new" extism_context_new :: IO (Ptr ExtismContext)
foreign import ccall unsafe "extism.h &extism_context_free" extism_context_free :: FunPtr (Ptr ExtismContext -> IO ())
foreign import ccall unsafe "extism.h extism_plugin_new" extism_plugin_new :: Ptr ExtismContext -> Ptr Word8 -> Word64 -> CBool -> IO Int32
foreign import ccall unsafe "extism.h extism_plugin_update" extism_plugin_update :: Ptr ExtismContext -> Int32 -> Ptr Word8 -> Word64 -> CBool -> IO CBool
foreign import ccall unsafe "extism.h extism_plugin_call" extism_plugin_call :: Ptr ExtismContext -> Int32 -> CString -> Ptr Word8 -> Word64 -> IO Int32
foreign import ccall unsafe "extism.h extism_plugin_function_exists" extism_plugin_function_exists :: Ptr ExtismContext -> Int32 -> CString -> IO CBool
foreign import ccall unsafe "extism.h extism_error" extism_error :: Ptr ExtismContext -> Int32 -> IO CString
foreign import ccall unsafe "extism.h extism_plugin_output_length" extism_plugin_output_length :: Ptr ExtismContext -> Int32 -> IO Word64
foreign import ccall unsafe "extism.h extism_plugin_output_data" extism_plugin_output_data :: Ptr ExtismContext -> Int32 -> IO (Ptr Word8)
foreign import ccall unsafe "extism.h extism_log_file" extism_log_file :: CString -> CString -> IO CBool
foreign import ccall unsafe "extism.h extism_plugin_config" extism_plugin_config :: Ptr ExtismContext -> Int32 -> Ptr Word8 -> Int64 -> IO CBool
foreign import ccall unsafe "extism.h extism_plugin_free" extism_plugin_free :: Ptr ExtismContext -> Int32 -> IO ()
foreign import ccall unsafe "extism.h extism_context_reset" extism_context_reset :: Ptr ExtismContext -> IO ()
foreign import ccall unsafe "extism.h extism_version" extism_version :: IO CString
-- Context manages plugins
-- | Context for managing plugins
newtype Context = Context (ForeignPtr ExtismContext)
-- Plugins can be used to call WASM function
-- | Plugins can be used to call WASM function
data Plugin = Plugin Context Int32
-- Log level
-- | Log level
data LogLevel = Error | Warn | Info | Debug | Trace deriving (Show)
-- Extism error
newtype Error = ErrorMessage String deriving Show
-- | Extism error
newtype Error = ExtismError String deriving Show
-- Helper function to convert a string to a bytestring
-- | Result type
type Result a = Either Error a
-- | Helper function to convert a 'String' to a 'ByteString'
toByteString :: String -> ByteString
toByteString x = B.pack (Prelude.map c2w x)
-- Helper function to convert a bytestring to a string
-- | Helper function to convert a 'ByteString' to a 'String'
fromByteString :: ByteString -> String
fromByteString bs = Prelude.map w2c $ B.unpack bs
-- Get the Extism version string
-- | Get the Extism version string
extismVersion :: () -> IO String
extismVersion () = do
v <- extism_version
peekCString v
-- Remove all registered plugins in a Context
-- | Remove all registered plugins in a 'Context'
reset :: Context -> IO ()
reset (Context ctx) =
withForeignPtr ctx extism_context_reset
-- Create a new context
newContext :: () -> IO Context
newContext () = do
-- | Create a new 'Context'
newContext :: IO Context
newContext = do
ptr <- extism_context_new
fptr <- newForeignPtr extism_context_free ptr
return (Context fptr)
-- Execute a function with a new context that is destroyed when it returns
-- | Execute a function with a new 'Context' that is destroyed when it returns
withContext :: (Context -> IO a) -> IO a
withContext f = do
ctx <- newContext ()
ctx <- newContext
f ctx
-- Create a plugin from a WASM module, `useWasi` determines if WASI should
-- be linked
plugin :: Context -> B.ByteString -> Bool -> IO (Either Error Plugin)
-- | Create a 'Plugin' from a WASM module, `useWasi` determines if WASI should
-- | be linked
plugin :: Context -> B.ByteString -> Bool -> IO (Result Plugin)
plugin c wasm useWasi =
let length = fromIntegral (B.length wasm) in
let wasi = fromInteger (if useWasi then 1 else 0) in
@@ -90,18 +74,18 @@ plugin c wasm useWasi =
if p < 0 then do
err <- extism_error ctx (-1)
e <- peekCString err
return $ Left (ErrorMessage e)
return $ Left (ExtismError e)
else
return $ Right (Plugin c p))
-- Create a plugin from a Manifest
pluginFromManifest :: Context -> Manifest -> Bool -> IO (Either Error Plugin)
-- | Create a 'Plugin' from a 'Manifest'
pluginFromManifest :: Context -> Manifest -> Bool -> IO (Result Plugin)
pluginFromManifest ctx manifest useWasi =
let wasm = toByteString $ toString manifest in
plugin ctx wasm useWasi
-- Update a plugin with a new WASM module
update :: Plugin -> B.ByteString -> Bool -> IO (Either Error ())
-- | Update a 'Plugin' with a new WASM module
update :: Plugin -> B.ByteString -> Bool -> IO (Result ())
update (Plugin (Context ctx) id) wasm useWasi =
let length = fromIntegral (B.length wasm) in
let wasi = fromInteger (if useWasi then 1 else 0) in
@@ -112,30 +96,27 @@ update (Plugin (Context ctx) id) wasm useWasi =
if b <= 0 then do
err <- extism_error ctx (-1)
e <- peekCString err
return $ Left (ErrorMessage e)
return $ Left (ExtismError e)
else
return (Right ()))
-- Update a plugin with a new Manifest
updateManifest :: Plugin -> Manifest -> Bool -> IO (Either Error ())
-- | Update a 'Plugin' with a new 'Manifest'
updateManifest :: Plugin -> Manifest -> Bool -> IO (Result ())
updateManifest plugin manifest useWasi =
let wasm = toByteString $ toString manifest in
update plugin wasm useWasi
-- Check if a plugin is value
-- | Check if a 'Plugin' is valid
isValid :: Plugin -> Bool
isValid (Plugin _ p) = p >= 0
convertMaybeString Nothing = JSNull
convertMaybeString (Just s) = JSString (toJSString s)
-- Set configuration values for a plugin
-- | Set configuration values for a plugin
setConfig :: Plugin -> [(String, Maybe String)] -> IO Bool
setConfig (Plugin (Context ctx) plugin) x =
if plugin < 0
then return False
else
let obj = toJSObject [(k, convertMaybeString v) | (k, v) <- x] in
let obj = toJSObject [(k, showJSON v) | (k, v) <- x] in
let bs = toByteString (encode obj) in
let length = fromIntegral (B.length bs) in
unsafeUseAsCString bs (\s -> do
@@ -149,7 +130,7 @@ levelStr Warn = "warn"
levelStr Trace = "trace"
levelStr Info = "info"
-- Set the log file and level, this is a global configuration
-- | Set the log file and level, this is a global configuration
setLogFile :: String -> LogLevel -> IO Bool
setLogFile filename level =
let s = levelStr level in
@@ -158,15 +139,15 @@ setLogFile filename level =
b <- extism_log_file f l
return $ b /= 0))
-- Check if a function exists in the given plugin
-- | Check if a function exists in the given plugin
functionExists :: Plugin -> String -> IO Bool
functionExists (Plugin (Context ctx) plugin) name = do
withForeignPtr ctx (\ctx -> do
b <- withCString name (extism_plugin_function_exists ctx plugin)
if b == 1 then return True else return False)
--- Call a function provided by the given plugin
call :: Plugin -> String -> B.ByteString -> IO (Either Error B.ByteString)
--- | Call a function provided by the given plugin
call :: Plugin -> String -> B.ByteString -> IO (Result B.ByteString)
call (Plugin (Context ctx) plugin) name input =
let length = fromIntegral (B.length input) in
do
@@ -177,16 +158,17 @@ call (Plugin (Context ctx) plugin) name input =
err <- extism_error ctx plugin
if err /= nullPtr
then do e <- peekCString err
return $ Left (ErrorMessage e)
return $ Left (ExtismError e)
else if rc == 0
then do
length <- extism_plugin_output_length ctx plugin
ptr <- extism_plugin_output_data ctx plugin
buf <- packCStringLen (castPtr ptr, fromIntegral length)
return $ Right buf
else return $ Left (ErrorMessage "Call failed"))
else return $ Left (ExtismError "Call failed"))
-- Free a plugin
-- | Free a 'Plugin', this will automatically be called for every plugin
-- | associated with a 'Context' when that 'Context' is freed
free :: Plugin -> IO ()
free (Plugin (Context ctx) plugin) =
withForeignPtr ctx (`extism_plugin_free` plugin)

View File

@@ -0,0 +1,26 @@
{-# LANGUAGE ForeignFunctionInterface #-}
module Extism.Bindings where
import Foreign.C.Types
import Foreign.Ptr
import Foreign.C.String
import Data.Int
import Data.Word
newtype ExtismContext = ExtismContext () deriving Show
foreign import ccall unsafe "extism.h extism_context_new" extism_context_new :: IO (Ptr ExtismContext)
foreign import ccall unsafe "extism.h &extism_context_free" extism_context_free :: FunPtr (Ptr ExtismContext -> IO ())
foreign import ccall unsafe "extism.h extism_plugin_new" extism_plugin_new :: Ptr ExtismContext -> Ptr Word8 -> Word64 -> CBool -> IO Int32
foreign import ccall unsafe "extism.h extism_plugin_update" extism_plugin_update :: Ptr ExtismContext -> Int32 -> Ptr Word8 -> Word64 -> CBool -> IO CBool
foreign import ccall unsafe "extism.h extism_plugin_call" extism_plugin_call :: Ptr ExtismContext -> Int32 -> CString -> Ptr Word8 -> Word64 -> IO Int32
foreign import ccall unsafe "extism.h extism_plugin_function_exists" extism_plugin_function_exists :: Ptr ExtismContext -> Int32 -> CString -> IO CBool
foreign import ccall unsafe "extism.h extism_error" extism_error :: Ptr ExtismContext -> Int32 -> IO CString
foreign import ccall unsafe "extism.h extism_plugin_output_length" extism_plugin_output_length :: Ptr ExtismContext -> Int32 -> IO Word64
foreign import ccall unsafe "extism.h extism_plugin_output_data" extism_plugin_output_data :: Ptr ExtismContext -> Int32 -> IO (Ptr Word8)
foreign import ccall unsafe "extism.h extism_log_file" extism_log_file :: CString -> CString -> IO CBool
foreign import ccall unsafe "extism.h extism_plugin_config" extism_plugin_config :: Ptr ExtismContext -> Int32 -> Ptr Word8 -> Int64 -> IO CBool
foreign import ccall unsafe "extism.h extism_plugin_free" extism_plugin_free :: Ptr ExtismContext -> Int32 -> IO ()
foreign import ccall unsafe "extism.h extism_context_reset" extism_context_reset :: Ptr ExtismContext -> IO ()
foreign import ccall unsafe "extism.h extism_version" extism_version :: IO CString

View File

@@ -1,183 +0,0 @@
module Extism.Manifest where
import Text.JSON
(
JSValue(JSNull, JSString, JSArray),
toJSString, showJSON, makeObj, encode
)
import qualified Data.ByteString as B
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Char8 as BS (unpack)
valueOrNull f Nothing = JSNull
valueOrNull f (Just x) = f x
makeString s = JSString (toJSString s)
stringOrNull = valueOrNull makeString
makeArray f [] = JSNull
makeArray f x = JSArray [f a | a <- x]
filterNulls obj = [(a, b) | (a, b) <- obj, not (isNull b)]
mapObj f x = makeObj (filterNulls [(a, f b) | (a, b) <- x])
isNull JSNull = True
isNull _ = False
newtype Memory = Memory
{
memoryMax :: Maybe Int
}
class JSONValue a where
toJSONValue :: a -> JSValue
instance JSONValue Memory where
toJSONValue x =
case memoryMax x of
Nothing -> makeObj []
Just max -> makeObj [("max", showJSON max)]
data HttpRequest = HttpRequest
{
url :: String
, header :: [(String, String)]
, method :: Maybe String
}
requestObj x =
let meth = stringOrNull $ method x in
let h = mapObj makeString $ header x in
filterNulls [
("url", makeString $ url x),
("header", h),
("method", meth)
]
instance JSONValue HttpRequest where
toJSONValue x =
makeObj $ requestObj x
data WasmFile = WasmFile
{
filePath :: String
, fileName :: Maybe String
, fileHash :: Maybe String
}
instance JSONValue WasmFile where
toJSONValue x =
let path = makeString $ filePath x in
let name = stringOrNull $ fileName x in
let hash = stringOrNull $ fileHash x in
makeObj $ filterNulls [
("path", path),
("name", name),
("hash", hash)
]
data WasmCode = WasmCode
{
codeBytes :: B.ByteString
, codeName :: Maybe String
, codeHash :: Maybe String
}
instance JSONValue WasmCode where
toJSONValue x =
let bytes = makeString $ BS.unpack $ B64.encode $ codeBytes x in
let name = stringOrNull $ codeName x in
let hash = stringOrNull $ codeHash x in
makeObj $ filterNulls [
("data", bytes),
("name", name),
("hash", hash)
]
data WasmURL = WasmURL
{
req :: HttpRequest
, urlName :: Maybe String
, urlHash :: Maybe String
}
instance JSONValue WasmURL where
toJSONValue x =
let request = requestObj $ req x in
let name = stringOrNull $ urlName x in
let hash = stringOrNull $ urlHash x in
makeObj $ filterNulls $ ("name", name) : ("hash", hash) : request
data Wasm = File WasmFile | Code WasmCode | URL WasmURL
instance JSONValue Wasm where
toJSONValue x =
case x of
File f -> toJSONValue f
Code d -> toJSONValue d
URL u -> toJSONValue u
wasmFile :: String -> Wasm
wasmFile path =
File WasmFile { filePath = path, fileName = Nothing, fileHash = Nothing}
wasmURL :: String -> String -> Wasm
wasmURL method url =
let r = HttpRequest { url = url, header = [], method = Just method } in
URL WasmURL { req = r, urlName = Nothing, urlHash = Nothing }
wasmCode :: B.ByteString -> Wasm
wasmCode code =
Code WasmCode { codeBytes = code, codeName = Nothing, codeHash = Nothing }
withName :: Wasm -> String -> Wasm
withName (Code code) name = Code code { codeName = Just name }
withName (URL url) name = URL url { urlName = Just name }
withName (File f) name = File f { fileName = Just name }
withHash :: Wasm -> String -> Wasm
withHash (Code code) hash = Code code { codeHash = Just hash }
withHash (URL url) hash = URL url { urlHash = Just hash }
withHash (File f) hash = File f { fileHash = Just hash }
data Manifest = Manifest
{
wasm :: [Wasm]
, memory :: Maybe Memory
, config :: [(String, String)]
, allowed_hosts :: [String]
}
manifest :: [Wasm] -> Manifest
manifest wasm =
Manifest {
wasm = wasm,
memory = Nothing,
config = [],
allowed_hosts = []
}
withConfig :: Manifest -> [(String, String)] -> Manifest
withConfig m config =
m { config = config }
withHosts :: Manifest -> [String] -> Manifest
withHosts m hosts =
m { allowed_hosts = hosts }
instance JSONValue Manifest where
toJSONValue x =
let w = makeArray toJSONValue $ wasm x in
let mem = valueOrNull toJSONValue $ memory x in
let c = mapObj makeString $ config x in
let hosts = makeArray makeString $ allowed_hosts x in
makeObj $ filterNulls [
("wasm", w),
("memory", mem),
("config", c),
("allowed_hosts", hosts)
]
toString :: Manifest -> String
toString manifest =
encode (toJSONValue manifest)

View File

@@ -1,67 +0,0 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# resolver: lts-3.5
# resolver: nightly-2015-09-21
# resolver: ghc-7.10.2
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# resolver: ./custom-snapshot.yaml
# resolver: https://example.com/snapshots/2018-01-01.yaml
resolver:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2022/8/30.yaml
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the resolver.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:
#
# extra-deps:
# - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
#
# extra-deps: []
# Override default flag values for local packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=2.7"
#
# Override the architecture used by stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor

View File

@@ -1,13 +0,0 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files
packages: []
snapshots:
- completed:
size: 632828
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2022/8/30.yaml
sha256: 5b02c2ce430ac62843fb884126765628da2ca2280bb9de0c6635c723e32a9f6b
original:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2022/8/30.yaml

View File

@@ -3,18 +3,15 @@ import Extism
import Extism.Manifest
unwrap' (Right x) = return x
unwrap' (Left (ErrorMessage msg)) =
unwrap (Right x) = return x
unwrap (Left (ExtismError msg)) =
assertFailure msg
unwrap io = do
x <- io
unwrap' x
defaultManifest = manifest [wasmFile "test/code.wasm"]
initPlugin :: Context -> IO Plugin
initPlugin context =
unwrap (Extism.pluginFromManifest context defaultManifest False)
Extism.pluginFromManifest context defaultManifest False >>= unwrap
pluginFunctionExists = do
withContext (\ctx -> do
@@ -25,7 +22,7 @@ pluginFunctionExists = do
assertBool "function doesn't exist" (not exists'))
checkCallResult p = do
res <- unwrap (call p "count_vowels" (toByteString "this is a test"))
res <- call p "count_vowels" (toByteString "this is a test") >>= unwrap
assertEqual "count vowels output" "{\"count\": 4}" (fromByteString res)
pluginCall = do
@@ -45,7 +42,7 @@ pluginMultiple = do
pluginUpdate = do
withContext (\ctx -> do
p <- initPlugin ctx
unwrap (updateManifest p defaultManifest True)
updateManifest p defaultManifest True >>= unwrap
checkCallResult p)
pluginConfig = do
@@ -55,7 +52,7 @@ pluginConfig = do
assertBool "set config" b)
testSetLogFile = do
b <- setLogFile "stderr" Error
b <- setLogFile "stderr" Extism.Error
assertBool "set log file" b
t name f = TestLabel name (TestCase f)

190
java/pom.xml Normal file
View File

@@ -0,0 +1,190 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.extism.sdk</groupId>
<artifactId>extism</artifactId>
<packaging>jar</packaging>
<version>0.1.0</version>
<name>extism</name>
<url>https://github.com/extism/extism</url>
<description>Java-SDK for Extism to use webassembly from Java</description>
<licenses>
<license>
<name>BSD 3-Clause</name>
<url>https://opensource.org/licenses/BSD-3-Clause</url>
</license>
</licenses>
<organization>
<name>Dylibso, Inc.</name>
<url>https://dylib.so</url>
</organization>
<developers>
<developer>
<name>The Extism Authors</name>
<email>oss@extism.org</email>
<roles>
<role>Maintainer</role>
</roles>
<organization>Dylibso, Inc.</organization>
<organizationUrl>https://dylib.so</organizationUrl>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/extism/extism.git</connection>
<developerConnection>scm:git:ssh://git@github.com/extism/extism.git</developerConnection>
<url>https://github.com/extism/extism/java</url>
<tag>main</tag>
</scm>
<issueManagement>
<system>Github</system>
<url>https://github.com/extism/extism/issues</url>
</issueManagement>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- dependencies -->
<jna.version>5.12.1</jna.version>
<gson.version>2.10</gson.version>
<!-- testing -->
<junit-jupiter-engine.version>5.9.1</junit-jupiter-engine.version>
<assertj-core.version>3.23.1</assertj-core.version>
<!-- maven plugins -->
<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<!-- jreleaser -->
<jreleaser.git.root.search>true</jreleaser.git.root.search>
</properties>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<id>attach-javadoc</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-source</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jreleaser</groupId>
<artifactId>jreleaser-maven-plugin</artifactId>
<version>1.3.1</version>
<configuration>
<jreleaser>
<release>
<github>
<skipRelease>true</skipRelease>
</github>
</release>
<signing>
<active>ALWAYS</active>
<armored>true</armored>
</signing>
<deploy>
<maven>
<nexus2>
<maven-central>
<active>ALWAYS</active>
<url>https://s01.oss.sonatype.org/service/local</url>
<!--
<closeRepository>false</closeRepository>
<releaseRepository>false</releaseRepository>
-->
<stagingRepositories>target/staging-deploy</stagingRepositories>
</maven-central>
</nexus2>
</maven>
</deploy>
</jreleaser>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<jna.library.path>../target/release</jna.library.path>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>${jna.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter-engine.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>uk.org.webcompere</groupId>
<artifactId>model-assert</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

39
java/readme.md Normal file
View File

@@ -0,0 +1,39 @@
Extism Java-SDK
---
Java SDK for the [extism](https://extism.org/) WebAssembly Plugin-System.
# Build
To build the extism java-sdk run the following command:
```
mvn clean verify
```
# Usage
To use the extism java-sdk you need to add the `org.extism.sdk` dependency to your dependency management and ensure that
the native extism library is installed on your system. For installing the native library refer to the [extism documentation](https://extism.org/docs/install).
Instead of installing the native library on your system, you can also download the appropriate library for your platform
yourself.
To do that simply download the [extism release](https://github.com/extism/extism/releases) to a `folder` and run your java application with the system property `-Djna.library.path=/path/to/folder`.
## Maven
To use the extism java-sdk with maven you need to add the following dependency to your `pom.xml` file:
```xml
<dependency>
<groupId>org.extism.sdk</groupId>
<artifactId>extism</artifactId>
<version>0.1.0</version>
</dependency>
```
## Gradle
To use the extism java-sdk with maven you need to add the following dependency to your `build.gradle` file:
```
implementation 'org.extism.sdk:extism:0.1.0'
```

View File

@@ -0,0 +1,89 @@
package org.extism.sdk;
import com.sun.jna.Pointer;
import org.extism.sdk.manifest.Manifest;
/**
* Extism Context is used to store and manage plugins.
*/
public class Context implements AutoCloseable {
/**
* Holds a pointer to the native ExtismContext struct.
*/
private final Pointer contextPointer;
/**
* Creates a new context.
* <p>
* A Context is used to manage Plugins
* and make sure they are cleaned up when you are done with them.
*/
public Context() {
this.contextPointer = LibExtism.INSTANCE.extism_context_new();
}
/**
* Create a new plugin managed by this context.
*
* @param manifest The manifest for the plugin
* @param withWASI Set to true to enable WASI
* @return the plugin instance
*/
public Plugin newPlugin(Manifest manifest, boolean withWASI) {
return new Plugin(this, manifest, withWASI);
}
/**
* Frees the context *and* frees all its Plugins. Use {@link #reset()}, if you just want to
* free the plugins but keep the context. You should ensure this is called when you are done
* with the context.
*/
public void free() {
LibExtism.INSTANCE.extism_context_free(this.contextPointer);
}
/**
* Resets the context by freeing all its Plugins. Unlike {@link #free()}, it does not
* free the context itself.
*/
public void reset() {
LibExtism.INSTANCE.extism_context_reset(this.contextPointer);
}
/**
* Get the version string of the linked Extism Runtime.
*
* @return the version
*/
public String getVersion() {
return LibExtism.INSTANCE.extism_version();
}
/**
* Get the error associated with a context, if plugin is {@literal null} then the context error will be returned.
*
* @param plugin
* @return the error message
*/
protected String error(Plugin plugin) {
return LibExtism.INSTANCE.extism_error(this.contextPointer, plugin == null ? -1 : plugin.getIndex());
}
/**
* Return the raw pointer to this context.
*
* @return the pointer
*/
public Pointer getPointer() {
return this.contextPointer;
}
/**
* Calls {@link #free()} if used in the context of a TWR block.
*/
@Override
public void close() {
this.free();
}
}

View File

@@ -0,0 +1,76 @@
package org.extism.sdk;
import org.extism.sdk.manifest.Manifest;
import java.nio.file.Path;
import java.util.Objects;
/**
* Extism convenience functions.
*/
public class Extism {
/**
* Configure a log file with the given {@link Path} and configure the given {@link LogLevel}.
*
* @param path
* @param level
*
* @deprecated will be replaced with better logging API.
*/
@Deprecated(forRemoval = true)
public static void setLogFile(Path path, LogLevel level) {
Objects.requireNonNull(path, "path");
Objects.requireNonNull(level, "level");
var result = LibExtism.INSTANCE.extism_log_file(path.toString(), level.getLevel());
if (!result) {
var error = String.format("Could not set extism logger to %s with level %s", path, level);
throw new ExtismException(error);
}
}
/**
* Invokes the named {@code function} from the {@link Manifest} with the given {@code input}.
*
* @param manifest the manifest containing the function
* @param function the name of the function to call
* @param input the input as string
* @return the output as string
* @throws ExtismException if the call fails
*/
public static String invokeFunction(Manifest manifest, String function, String input) throws ExtismException {
try (var ctx = new Context()) {
try (var plugin = ctx.newPlugin(manifest, false)) {
return plugin.call(function, input);
}
}
}
/**
* Error levels for the Extism logging facility.
*
* @see Extism#setLogFile(Path, LogLevel)
*/
public enum LogLevel {
INFO("info"), //
DEBUG("debug"), //
WARN("warn"), //
TRACE("trace");
private final String level;
LogLevel(String level) {
this.level = level;
}
public String getLevel() {
return level;
}
}
}

View File

@@ -0,0 +1,18 @@
package org.extism.sdk;
/**
* Thrown when an exceptional condition has occurred.
*/
public class ExtismException extends RuntimeException {
public ExtismException() {
}
public ExtismException(String message) {
super(message);
}
public ExtismException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,143 @@
package org.extism.sdk;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
/**
* Wrapper around the Extism library.
*/
public interface LibExtism extends Library {
/**
* Holds the extism library instance.
* Resolves the extism library based on the resolution algorithm defined in {@link com.sun.jna.NativeLibrary}.
*/
LibExtism INSTANCE = Native.load("extism", LibExtism.class);
/**
* Create a new context
*/
Pointer extism_context_new();
/**
* Free a context
*/
void extism_context_free(Pointer contextPointer);
/**
* Remove all plugins from the registry.
*
* @param contextPointer
*/
void extism_context_reset(Pointer contextPointer);
/**
* Sets the logger to the given path with the given level of verbosity
*
* @param path The file path of the logger
* @param logLevel The level of the logger
* @return true if successful
*/
boolean extism_log_file(String path, String logLevel);
/**
* Returns the error associated with a @{@link Context} or @{@link Plugin}, if {@code pluginId} is {@literal -1} then the context error will be returned
*
* @param contextPointer
* @param pluginId
* @return
*/
String extism_error(Pointer contextPointer, int pluginId);
/**
* Create a new plugin.
*
* @param contextPointer pointer to the {@link Context}.
* @param wasm is a WASM module (wat or wasm) or a JSON encoded manifest
* @param wasmSize the length of the `wasm` parameter
* @param withWASI enables/disables WASI
* @return id of the plugin or {@literal -1} in case of error
*/
int extism_plugin_new(long contextPointer, byte[] wasm, long wasmSize, boolean withWASI);
/**
* Returns the Extism version string
*/
String extism_version();
/**
* Create a new plugin.
*
* @param contextPointer pointer to the {@link Context}.
* @param wasm is a WASM module (wat or wasm) or a JSON encoded manifest
* @param length the length of the `wasm` parameter
* @param withWASI enables/disables WASI
* @return id of the plugin or {@literal -1} in case of error
* @see #extism_plugin_new(long, byte[], long, boolean)
*/
int extism_plugin_new(Pointer contextPointer, byte[] wasm, int length, boolean withWASI);
/**
* Calls a function from the @{@link Plugin} at the given {@code pluginIndex}.
*
* @param contextPointer
* @param pluginIndex
* @param function_name is the function to call
* @param data is the data input data
* @param dataLength is the data input data length
* @return the result code of the plugin call. {@literal -1} in case of error, {@literal 0} otherwise.
*/
int extism_plugin_call(Pointer contextPointer, int pluginIndex, String function_name, byte[] data, int dataLength);
/**
* Returns the length of a plugin's output data.
*
* @param contextPointer
* @param pluginIndex
* @return the length of the output data in bytes.
*/
int extism_plugin_output_length(Pointer contextPointer, int pluginIndex);
/**
* Returns the plugin's output data.
*
* @param contextPointer
* @param pluginIndex
* @return
*/
Pointer extism_plugin_output_data(Pointer contextPointer, int pluginIndex);
/**
* Update a plugin, keeping the existing ID.
* Similar to {@link #extism_plugin_new(long, byte[], long, boolean)} but takes an {@code pluginIndex} argument to specify which plugin to update.
* Note: Memory for this plugin will be reset upon update.
*
* @param contextPointer
* @param pluginIndex
* @param wasm
* @param length
* @param withWASI
* @return {@literal true} if update was successful
*/
boolean extism_plugin_update(Pointer contextPointer, int pluginIndex, byte[] wasm, int length, boolean withWASI);
/**
* Remove a plugin from the registry and free associated memory.
*
* @param contextPointer
* @param pluginIndex
*/
void extism_plugin_free(Pointer contextPointer, int pluginIndex);
/**
* Update plugin config values, this will merge with the existing values.
*
* @param contextPointer
* @param pluginIndex
* @param json
* @param jsonLength
* @return {@literal true} if update was successful
*/
boolean extism_plugin_config(Pointer contextPointer, int pluginIndex, byte[] json, int jsonLength);
}

View File

@@ -0,0 +1,168 @@
package org.extism.sdk;
import com.sun.jna.Pointer;
import org.extism.sdk.manifest.Manifest;
import org.extism.sdk.support.JsonSerde;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
* Represents a Extism plugin.
*/
public class Plugin implements AutoCloseable {
/**
* Holds the Extism {@link Context} that the plugin belongs to.
*/
private final Context context;
/**
* Holds the index of the plugin
*/
private final int index;
/**
* Constructor for a Plugin. Only expose internally. Plugins should be created and
* managed from {@link org.extism.sdk.Context}.
*
* @param context The context to manage the plugin
* @param manifestBytes The manifest for the plugin
* @param withWASI Set to true to enable WASI
*/
public Plugin(Context context, byte[] manifestBytes, boolean withWASI) {
Objects.requireNonNull(context, "context");
Objects.requireNonNull(manifestBytes, "manifestBytes");
Pointer contextPointer = context.getPointer();
int index = LibExtism.INSTANCE.extism_plugin_new(contextPointer, manifestBytes, manifestBytes.length, withWASI);
if (index == -1) {
String error = context.error(this);
throw new ExtismException(error);
}
this.index= index;
this.context = context;
}
public Plugin(Context context, Manifest manifest, boolean withWASI) {
this(context, serialize(manifest), withWASI);
}
private static byte[] serialize(Manifest manifest) {
Objects.requireNonNull(manifest, "manifest");
return JsonSerde.toJson(manifest).getBytes(StandardCharsets.UTF_8);
}
/**
* Getter for the internal index pointer to this plugin.
*
* @return the plugin index
*/
public int getIndex() {
return index;
}
/**
* Invoke a function with the given name and input.
*
* @param functionName The name of the exported function to invoke
* @param inputData The raw bytes representing any input data
* @return A byte array representing the raw output data
* @throws ExtismException if the call fails
*/
public byte[] call(String functionName, byte[] inputData) {
Objects.requireNonNull(functionName, "functionName");
Pointer contextPointer = context.getPointer();
int inputDataLength = inputData == null ? 0 : inputData.length;
int exitCode = LibExtism.INSTANCE.extism_plugin_call(contextPointer, index, functionName, inputData, inputDataLength);
if (exitCode == -1) {
String error = context.error(this);
throw new ExtismException(error);
}
int length = LibExtism.INSTANCE.extism_plugin_output_length(contextPointer, index);
Pointer output = LibExtism.INSTANCE.extism_plugin_output_data(contextPointer, index);
return output.getByteArray(0, length);
}
/**
* Invoke a function with the given name and input.
*
* @param functionName The name of the exported function to invoke
* @param input The string representing the input data
* @return A string representing the output data
*/
public String call(String functionName, String input) {
Objects.requireNonNull(functionName, "functionName");
var inputBytes = input == null ? null : input.getBytes(StandardCharsets.UTF_8);
var outputBytes = call(functionName, inputBytes);
return new String(outputBytes, StandardCharsets.UTF_8);
}
/**
* Update the plugin code given manifest changes
*
* @param manifest The manifest for the plugin
* @param withWASI Set to true to enable WASI
* @return {@literal true} if update was successful
*/
public boolean update(Manifest manifest, boolean withWASI) {
return update(serialize(manifest), withWASI);
}
/**
* Update the plugin code given manifest changes
*
* @param manifestBytes The manifest for the plugin
* @param withWASI Set to true to enable WASI
* @return {@literal true} if update was successful
*/
public boolean update(byte[] manifestBytes, boolean withWASI) {
Objects.requireNonNull(manifestBytes, "manifestBytes");
return LibExtism.INSTANCE.extism_plugin_update(context.getPointer(), index, manifestBytes, manifestBytes.length, withWASI);
}
/**
* Frees a plugin from memory. Plugins will be automatically cleaned up
* if you free their parent Context using {@link org.extism.sdk.Context#free() free()} or {@link org.extism.sdk.Context#reset() reset()}
*/
public void free() {
LibExtism.INSTANCE.extism_plugin_free(context.getPointer(), index);
}
/**
* Update plugin config values, this will merge with the existing values.
*
* @param json
* @return
*/
public boolean updateConfig(String json) {
Objects.requireNonNull(json, "json");
return updateConfig(json.getBytes(StandardCharsets.UTF_8));
}
/**
* Update plugin config values, this will merge with the existing values.
*
* @param jsonBytes
* @return {@literal true} if update was successful
*/
public boolean updateConfig(byte[] jsonBytes) {
Objects.requireNonNull(jsonBytes, "jsonBytes");
return LibExtism.INSTANCE.extism_plugin_config(context.getPointer(), index, jsonBytes, jsonBytes.length);
}
/**
* Calls {@link #free()} if used in the context of a TWR block.
*/
@Override
public void close() {
free();
}
}

View File

@@ -0,0 +1,78 @@
package org.extism.sdk.manifest;
import com.google.gson.annotations.SerializedName;
import org.extism.sdk.wasm.WasmSource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class Manifest {
@SerializedName("wasm")
private final List<WasmSource> sources;
@SerializedName("memory")
private final MemoryOptions memoryOptions;
// FIXME remove this and related stuff if not supported in java-sdk
@SerializedName("allowed_hosts")
private final List<String> allowedHosts;
@SerializedName("config")
private final Map<String, String> config;
public Manifest() {
this(new ArrayList<>(), null, null, null);
}
public Manifest(WasmSource source) {
this(List.of(source));
}
public Manifest(List<WasmSource> sources) {
this(sources, null, null, null);
}
public Manifest(List<WasmSource> sources, MemoryOptions memoryOptions) {
this(sources, memoryOptions, null, null);
}
public Manifest(List<WasmSource> sources, MemoryOptions memoryOptions, Map<String, String> config) {
this(sources, memoryOptions, config, null);
}
public Manifest(List<WasmSource> sources, MemoryOptions memoryOptions, Map<String, String> config, List<String> allowedHosts) {
this.sources = sources;
this.memoryOptions = memoryOptions;
this.config = config;
this.allowedHosts = allowedHosts;
}
public void addSource(WasmSource source) {
this.sources.add(source);
}
public List<WasmSource> getSources() {
return Collections.unmodifiableList(sources);
}
public MemoryOptions getMemoryOptions() {
return memoryOptions;
}
public Map<String, String> getConfig() {
if (config == null || config.isEmpty()) {
return Collections.emptyMap();
}
return Collections.unmodifiableMap(config);
}
public List<String> getAllowedHosts() {
if (allowedHosts == null || allowedHosts.isEmpty()) {
return Collections.emptyList();
}
return Collections.unmodifiableList(allowedHosts);
}
}

View File

@@ -0,0 +1,8 @@
package org.extism.sdk.manifest;
import java.util.Map;
// FIXME remove this and related stuff if not supported in java-sdk
public record ManifestHttpRequest(String url, Map<String, String> header, String method) {
}

View File

@@ -0,0 +1,12 @@
package org.extism.sdk.manifest;
import com.google.gson.annotations.SerializedName;
/**
* Configures memory for the Wasm runtime.
* Memory is described in units of pages (64KB) and represent contiguous chunks of addressable memory.
*
* @param max Max number of pages.
*/
public record MemoryOptions(@SerializedName("max") Integer max) {
}

View File

@@ -0,0 +1,21 @@
package org.extism.sdk.support;
import java.security.MessageDigest;
public class Hashing {
public static String sha256HexDigest(byte[] input) {
try {
var messageDigest = MessageDigest.getInstance("SHA-256");
var messageDigestBytes = messageDigest.digest(input);
var hexString = new StringBuilder();
for (var b : messageDigestBytes) {
hexString.append(String.format("%02x", b));
}
return hexString.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,46 @@
package org.extism.sdk.support;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.extism.sdk.manifest.Manifest;
import java.lang.reflect.Type;
import java.util.Base64;
public class JsonSerde {
private static final Gson GSON;
static {
GSON = new GsonBuilder() //
.disableHtmlEscaping() //
// needed to convert the byte[] to a base64 encoded String
.registerTypeHierarchyAdapter(byte[].class, new ByteArrayToBase64TypeAdapter()) //
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) //
.setPrettyPrinting() //
.create();
}
public static String toJson(Manifest manifest) {
return GSON.toJson(manifest);
}
private static class ByteArrayToBase64TypeAdapter implements JsonSerializer<byte[]>, JsonDeserializer<byte[]> {
public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return Base64.getDecoder().decode(json.getAsString());
}
public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(Base64.getEncoder().withoutPadding().encodeToString(src));
}
}
}

View File

@@ -0,0 +1,11 @@
package org.extism.sdk.wasm;
/**
* WASM Source represented by raw bytes.
*
* @param name
* @param data the byte array representing the WASM code
* @param hash
*/
public record ByteArrayWasmSource(String name, byte[] data, String hash) implements WasmSource {
}

View File

@@ -0,0 +1,12 @@
package org.extism.sdk.wasm;
/**
* WASM Source represented by a file referenced by a path.
*
* @param name
* @param path
* @param hash
*/
public record PathWasmSource(String name, String path, String hash) implements WasmSource {
}

View File

@@ -0,0 +1,19 @@
package org.extism.sdk.wasm;
/**
* A named WASM source.
*/
public interface WasmSource {
/**
* Logical name of the WASM source
* @return
*/
String name();
/**
* Hash of the WASM source
* @return
*/
String hash();
}

View File

@@ -0,0 +1,46 @@
package org.extism.sdk.wasm;
import org.extism.sdk.ExtismException;
import org.extism.sdk.support.Hashing;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
/**
* Resolves {@link WasmSource} from {@link Path Path's} or raw bytes.
*/
public class WasmSourceResolver {
public PathWasmSource resolve(Path path) {
return resolve(null, path);
}
public PathWasmSource resolve(String name, Path path) {
Objects.requireNonNull(path, "path");
var wasmFile = path.toFile();
var hash = hash(path);
var wasmName = name == null ? wasmFile.getName() : name;
return new PathWasmSource(wasmName, wasmFile.getAbsolutePath(), hash);
}
public ByteArrayWasmSource resolve(String name, byte[] bytes) {
return new ByteArrayWasmSource(name, bytes, hash(bytes));
}
protected String hash(Path wasmFile) {
try {
return hash(Files.readAllBytes(wasmFile));
} catch (IOException ioe) {
throw new ExtismException("Could not compute hash from path: " + wasmFile, ioe);
}
}
protected String hash(byte[] bytes) {
return Hashing.sha256HexDigest(bytes);
}
}

View File

@@ -0,0 +1,23 @@
package org.extism.sdk;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class ContextTests {
@Test
public void shouldReturnVersionString() {
try (var ctx = new Context()) {
var version = ctx.getVersion();
assertThat(version).isNotNull();
}
}
@Test
public void shouldAllowResetOnEmptyContext() {
try (var ctx = new Context()) {
ctx.reset();
}
}
}

View File

@@ -0,0 +1,48 @@
package org.extism.sdk;
import org.extism.sdk.manifest.Manifest;
import org.extism.sdk.manifest.MemoryOptions;
import org.extism.sdk.support.JsonSerde;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.extism.sdk.TestWasmSources.CODE;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static uk.org.webcompere.modelassert.json.JsonAssertions.assertJson;
public class ManifestTests {
@Test
public void shouldSerializeManifestWithWasmSourceToJson() {
var manifest = new Manifest(CODE.pathWasmSource());
var json = JsonSerde.toJson(manifest);
assertNotNull(json);
assertJson(json).at("/wasm").isArray();
assertJson(json).at("/wasm").hasSize(1);
}
@Test
public void shouldSerializeManifestWithWasmSourceAndMemoryOptionsToJson() {
var manifest = new Manifest(List.of(CODE.pathWasmSource()), new MemoryOptions(4));
var json = JsonSerde.toJson(manifest);
assertNotNull(json);
assertJson(json).at("/wasm").isArray();
assertJson(json).at("/wasm").hasSize(1);
assertJson(json).at("/memory/max").isEqualTo(4);
}
@Test
public void codeWasmFromFileAndBytesShouldProduceTheSameHash() {
var byteHash = CODE.byteArrayWasmSource().hash();
var fileHash = CODE.pathWasmSource().hash();
assertThat(byteHash).isEqualTo(fileHash);
}
}

View File

@@ -0,0 +1,107 @@
package org.extism.sdk;
import org.extism.sdk.manifest.Manifest;
import org.extism.sdk.manifest.MemoryOptions;
import org.extism.sdk.wasm.WasmSourceResolver;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.extism.sdk.TestWasmSources.CODE;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class PluginTests {
// static {
// Extism.setLogFile(Paths.get("/tmp/extism.log"), Extism.LogLevel.TRACE);
// }
@Test
public void shouldInvokeFunctionWithMemoryOptions() {
//FIXME check whether memory options are effective
var manifest = new Manifest(List.of(CODE.pathWasmSource()), new MemoryOptions(0));
var output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
assertThat(output).isEqualTo("{\"count\": 3}");
}
@Test
public void shouldInvokeFunctionWithConfig() {
//FIXME check if config options are available in wasm call
var config = Map.of("key1", "value1");
var manifest = new Manifest(List.of(CODE.pathWasmSource()), null, config);
var output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
assertThat(output).isEqualTo("{\"count\": 3}");
}
@Test
public void shouldInvokeFunctionFromFileWasmSource() {
var manifest = new Manifest(CODE.pathWasmSource());
var output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
assertThat(output).isEqualTo("{\"count\": 3}");
}
// TODO This test breaks on CI with error:
// data did not match any variant of untagged enum Wasm at line 8 column 3
// @Test
// public void shouldInvokeFunctionFromByteArrayWasmSource() {
// var manifest = new Manifest(CODE.byteArrayWasmSource());
// var output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
// assertThat(output).isEqualTo("{\"count\": 3}");
// }
@Test
public void shouldFailToInvokeUnknownFunction() {
assertThrows(ExtismException.class, () -> {
var manifest = new Manifest(CODE.pathWasmSource());
Extism.invokeFunction(manifest, "unknown", "dummy");
}, "Function not found: unknown");
}
@Test
public void shouldAllowInvokeFunctionFromFileWasmSourceMultipleTimes() {
var wasmSource = CODE.pathWasmSource();
var manifest = new Manifest(wasmSource);
var output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
assertThat(output).isEqualTo("{\"count\": 3}");
output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
assertThat(output).isEqualTo("{\"count\": 3}");
}
@Test
public void shouldAllowInvokeFunctionFromFileWasmSourceApiUsageExample() {
var wasmSourceResolver = new WasmSourceResolver();
var manifest = new Manifest(wasmSourceResolver.resolve(CODE.getWasmFilePath()));
var functionName = "count_vowels";
var input = "Hello World";
try (var ctx = new Context()) {
try (var plugin = ctx.newPlugin(manifest, false)) {
var output = plugin.call(functionName, input);
assertThat(output).isEqualTo("{\"count\": 3}");
}
}
}
@Test
public void shouldAllowInvokeFunctionFromFileWasmSourceMultipleTimesByReusingContext() {
var manifest = new Manifest(CODE.pathWasmSource());
var functionName = "count_vowels";
var input = "Hello World";
try (var ctx = new Context()) {
try (var plugin = ctx.newPlugin(manifest, false)) {
var output = plugin.call(functionName, input);
assertThat(output).isEqualTo("{\"count\": 3}");
output = plugin.call(functionName, input);
assertThat(output).isEqualTo("{\"count\": 3}");
}
}
}
}

View File

@@ -0,0 +1,42 @@
package org.extism.sdk;
import org.extism.sdk.wasm.ByteArrayWasmSource;
import org.extism.sdk.wasm.PathWasmSource;
import org.extism.sdk.wasm.WasmSourceResolver;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
public enum TestWasmSources {
CODE {
public Path getWasmFilePath() {
return Paths.get(WASM_LOCATION, "code.wasm");
}
};
public static final String WASM_LOCATION = "src/test/resources";
public abstract Path getWasmFilePath();
public PathWasmSource pathWasmSource() {
return resolvePathWasmSource(getWasmFilePath());
}
public ByteArrayWasmSource byteArrayWasmSource() {
try {
var wasmBytes = Files.readAllBytes(getWasmFilePath());
return new WasmSourceResolver().resolve("wasm@" + Arrays.hashCode(wasmBytes), wasmBytes);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
public static PathWasmSource resolvePathWasmSource(Path path) {
return new WasmSourceResolver().resolve(path);
}
}

BIN
java/src/test/resources/code.wasm Executable file

Binary file not shown.

View File

@@ -5,6 +5,6 @@ libdir=${exec_prefix}/lib
Name: extism
Description: The Extism universal plug-in system.
Version: 0.0.1
Version: 0.1.0
Cflags: -I${includedir}
Libs: -L${libdir} -lextism

Some files were not shown because too many files have changed in this diff Show More