diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml
index e534fcf..57e7735 100644
--- a/.github/workflows/deploy.yaml
+++ b/.github/workflows/deploy.yaml
@@ -33,6 +33,10 @@ jobs:
exit 1
fi
+ fossa:
+ needs: [validate_branch_name]
+ uses: ./.github/workflows/fossa.yaml
+
code_validation:
needs: [validate_branch_name]
uses: ./.github/workflows/code-validation.yaml
diff --git a/.github/workflows/fossa.yaml b/.github/workflows/fossa.yaml
new file mode 100644
index 0000000..ada2984
--- /dev/null
+++ b/.github/workflows/fossa.yaml
@@ -0,0 +1,28 @@
+name: Fossa Compliance Check
+
+on:
+ workflow_call:
+
+jobs:
+ fossa:
+ runs-on: [self-hosted, ubuntu-22-04, regular]
+
+ if: github.actor != 'dependabot[bot]'
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
+ - name: Install FOSSA CLI
+ run: |
+ curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install-latest.sh | bash
+
+ - name: Run FOSSA Analysis
+ env:
+ FOSSA_API_KEY: ${{ secrets.FOSSA_PUB_API_KEY }}
+ run: fossa analyze
+
+ - name: Run FOSSA Test
+ env:
+ FOSSA_API_KEY: ${{ secrets.FOSSA_PUB_API_KEY }}
+ run: fossa test
diff --git a/.gitmodules b/.gitmodules
index 2d7a6f1..69745e6 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,9 +1,6 @@
-[submodule "fastedge-runtime/spidermonkey/gecko-dev"]
- path = fastedge-runtime/spidermonkey/gecko-dev
- url = https://github.com/bytecodealliance/gecko-dev.git
-[submodule "fastedge-runtime/cbindings/wit-interface/wit"]
- path = fastedge-runtime/cbindings/wit-interface/wit
- url = https://github.com/G-Core/FastEdge-wit.git
[submodule "runtime/StarlingMonkey"]
path = runtime/StarlingMonkey
url = https://github.com/bytecodealliance/StarlingMonkey.git
+[submodule "runtime/FastEdge-wit"]
+ path = runtime/FastEdge-wit
+ url = https://github.com/G-Core/FastEdge-wit.git
diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs
index 490122b..ac78366 100644
--- a/docs/astro.config.mjs
+++ b/docs/astro.config.mjs
@@ -8,6 +8,7 @@ export default defineConfig({
integrations: [
starlight({
title: '@gcoredev/fastedge-sdk-js',
+ customCss: ['./src/styles/custom.css'],
social: {
github: 'https://github.com/G-Core/FastEdge-sdk-js',
},
@@ -47,7 +48,72 @@ export default defineConfig({
{
label: 'Reference',
collapsed: true,
- autogenerate: { directory: 'reference' },
+ items: [
+ {
+ label: 'Overview',
+ link: `${import.meta.env.BASE_URL}reference/overview/`,
+ },
+ {
+ label: 'FastEdge::env',
+ link: `${import.meta.env.BASE_URL}reference/fastedge/env/`,
+ },
+ {
+ label: 'FastEdge::secret',
+ collapsed: true,
+ items: [
+ {
+ label: 'getSecret',
+ link: `${import.meta.env.BASE_URL}reference/fastedge/secret/get-secret/`,
+ },
+ {
+ label: 'getSecretEffectiveAt',
+ link: `${
+ import.meta.env.BASE_URL
+ }reference/fastedge/secret/get-secret-effective-at/`,
+ },
+ ],
+ },
+ {
+ label: 'FastEdge::kv',
+ collapsed: true,
+ items: [
+ {
+ label: 'KvStore.open()',
+ link: `${import.meta.env.BASE_URL}reference/fastedge/kv/open/`,
+ },
+ {
+ label: 'KV Instance',
+ collapsed: true,
+ items: [
+ {
+ label: 'get / scan',
+ link: `${import.meta.env.BASE_URL}reference/fastedge/kv/key-value/`,
+ },
+ {
+ label: 'zrange / zscan',
+ link: `${import.meta.env.BASE_URL}reference/fastedge/kv/zset/`,
+ },
+ {
+ label: 'bfExists',
+ link: `${import.meta.env.BASE_URL}reference/fastedge/kv/bloom-filter/`,
+ },
+ ],
+ },
+ ],
+ },
+ {
+ label: 'Headers',
+ link: `${import.meta.env.BASE_URL}reference/headers/`,
+ },
+ {
+ label: 'Request',
+ link: `${import.meta.env.BASE_URL}reference/request/`,
+ },
+ {
+ label: 'Response',
+ link: `${import.meta.env.BASE_URL}reference/response/`,
+ },
+ ],
},
{
label: 'Migrating',
diff --git a/docs/examples/kv-store.js b/docs/examples/kv-store.js
new file mode 100644
index 0000000..aff2b18
--- /dev/null
+++ b/docs/examples/kv-store.js
@@ -0,0 +1,15 @@
+import { KvStore } from 'fastedge::kv';
+
+async function eventHandler(event) {
+ try {
+ const myStore = KvStore.open('kv-store-name-as-defined-on-app');
+ const value = myStore.get('key');
+ return new Response(`The KV Store responded with: ${value}`);
+ } catch (error) {
+ return Response.json({ error: error.message }, { status: 500 });
+ }
+}
+
+addEventListener('fetch', (event) => {
+ event.respondWith(eventHandler(event));
+});
diff --git a/docs/src/content/docs/examples/kv-store.mdx b/docs/src/content/docs/examples/kv-store.mdx
new file mode 100644
index 0000000..8a01a8f
--- /dev/null
+++ b/docs/src/content/docs/examples/kv-store.mdx
@@ -0,0 +1,12 @@
+---
+title: Key-value Store
+description: An example using KV Store.
+prev:
+ link: /FastEdge-sdk-js/examples/main-examples/
+ label: Back to examples
+---
+
+import { Code } from '@astrojs/starlight/components';
+import importedCode from '/examples/kv-store.js?raw';
+
+
diff --git a/docs/src/content/docs/examples/main-examples.mdx b/docs/src/content/docs/examples/main-examples.mdx
index f57a563..2883cdf 100644
--- a/docs/src/content/docs/examples/main-examples.mdx
+++ b/docs/src/content/docs/examples/main-examples.mdx
@@ -30,4 +30,8 @@ More examples will be added to the examples-repo as we build out more functional
title='Environment variables and secrets'
href='/FastEdge-sdk-js/examples/variables-and-secrets/'
/>
+
diff --git a/docs/src/content/docs/reference/fastedge-env.md b/docs/src/content/docs/reference/fastedge/env/index.md
similarity index 100%
rename from docs/src/content/docs/reference/fastedge-env.md
rename to docs/src/content/docs/reference/fastedge/env/index.md
diff --git a/docs/src/content/docs/reference/fastedge/kv/bloom-filter.md b/docs/src/content/docs/reference/fastedge/kv/bloom-filter.md
new file mode 100644
index 0000000..f3bd575
--- /dev/null
+++ b/docs/src/content/docs/reference/fastedge/kv/bloom-filter.md
@@ -0,0 +1,48 @@
+---
+title: Bloom Filter accessors
+description: How to access Bloom Filter values from a FastEdge Kv Instance.
+---
+
+To access Bloom Filter values in a KV Store. First create a `KV Instance` using `KvStore.open()`
+
+This instance will then provide the `bfExists` method you can use to verify if a value exists.
+
+## zrangeByScore
+
+```js
+import { KvStore } from 'fastedge::kv';
+
+async function eventHandler(event) {
+ try {
+ const myStore = KvStore.open('kv-store-name-as-defined-on-app');
+ const hasItem = myStore.bfExists('key', 'value');
+ return new Response(`The KV Store responded with: ${hasItem}`);
+ } catch (error) {
+ return Response.json({ error: error.message }, { status: 500 });
+ }
+}
+
+addEventListener('fetch', (event) => {
+ event.respondWith(eventHandler(event));
+});
+```
+
+```js title="SYNTAX"
+storeInstance.bfExists(key, value);
+```
+
+##### Parameters
+
+- `key` (required)
+
+ A string containing the key you want to retrieve the values from.
+
+- `value` (required)
+
+ A string representing the value you want to check for existence.
+
+
+##### Return Value
+
+`boolean`. It returns `true` if the Bloom Filter contains the value.
+
diff --git a/docs/src/content/docs/reference/fastedge/kv/key-value.md b/docs/src/content/docs/reference/fastedge/kv/key-value.md
new file mode 100644
index 0000000..5421fa3
--- /dev/null
+++ b/docs/src/content/docs/reference/fastedge/kv/key-value.md
@@ -0,0 +1,80 @@
+---
+title: Key-value accessors
+description: How to access Key-value pairs from a FastEdge Kv Instance.
+---
+
+To access key-value pairs in a KV Store. First create a `KV Instance` using `KvStore.open()`
+
+This instance will then provide the `get` and `scan` methods you can use to access key-value pairs.
+
+## get
+
+```js
+import { KvStore } from 'fastedge::kv';
+
+async function eventHandler(event) {
+ try {
+ const myStore = KvStore.open('kv-store-name-as-defined-on-app');
+ const value = myStore.get('key');
+ return new Response(`The KV Store responded with: ${value}`);
+ } catch (error) {
+ return Response.json({ error: error.message }, { status: 500 });
+ }
+}
+
+addEventListener('fetch', (event) => {
+ event.respondWith(eventHandler(event));
+});
+```
+
+```js title="SYNTAX"
+storeInstance.get(key);
+```
+
+##### Parameters
+
+- `key` (required)
+
+ A string containing the key you want to retrieve the value of.
+
+##### Return Value
+
+An `ArrayBuffer` of the value for the given key. If the key does not exist, null is returned.
+
+## scan
+
+```js
+import { KvStore } from 'fastedge::kv';
+
+async function eventHandler(event) {
+ try {
+ const myStore = KvStore.open('kv-store-name-as-defined-on-app');
+ const results = myStore.scan('pre*');
+ return new Response(`The KV Store responded with: ${results.join(', ')}`);
+ } catch (error) {
+ return Response.json({ error: error.message }, { status: 500 });
+ }
+}
+
+addEventListener('fetch', (event) => {
+ event.respondWith(eventHandler(event));
+});
+```
+
+```js title="SYNTAX"
+storeInstance.scan(pattern);
+```
+
+##### Parameters
+
+- `pattern` (required)
+
+ A string containing the prefix pattern match.
+
+**Note**: This is a prefix match, it must contain the wildcard `*`. In the given example it matches
+all keys that start with `pre`
+
+##### Return Value
+
+An `Array` of all the keys that match the given pattern. If no `matches` are found it
+returns an empty array.
diff --git a/docs/src/content/docs/reference/fastedge/kv/open.md b/docs/src/content/docs/reference/fastedge/kv/open.md
new file mode 100644
index 0000000..8fb3e90
--- /dev/null
+++ b/docs/src/content/docs/reference/fastedge/kv/open.md
@@ -0,0 +1,46 @@
+---
+title: KV Stores
+description: How to use FastEdge Key-Value Stores.
+---
+
+### KV Store Open
+
+How to access Key-value Stores within FastEdge.
+
+```js
+import { KvStore } from 'fastedge::kv';
+
+async function eventHandler(event) {
+ try {
+ const myStore = KvStore.open('kv-store-name-as-defined-on-app');
+ const value = myStore.get('key');
+ return new Response(`The KV Store responded with: ${value}`);
+ } catch (error) {
+ return Response.json({ error: error.message }, { status: 500 });
+ }
+}
+
+addEventListener('fetch', (event) => {
+ event.respondWith(eventHandler(event));
+});
+```
+
+```js title="SYNTAX"
+KvStore.open(kvStoreName);
+```
+
+##### Parameters
+
+- `kvStoreName` (required)
+
+ A string containing the name of the store you want to open.
+
+##### Return Value
+
+A `KV Instance` that lets you interact with the store. It provides:
+
+- get
+- scan
+- zrangeByScore
+- zscan
+- bfExists
diff --git a/docs/src/content/docs/reference/fastedge/kv/zset.md b/docs/src/content/docs/reference/fastedge/kv/zset.md
new file mode 100644
index 0000000..7a8ac00
--- /dev/null
+++ b/docs/src/content/docs/reference/fastedge/kv/zset.md
@@ -0,0 +1,94 @@
+---
+title: Sorted Set accessors
+description: How to access Sorted Set values from a FastEdge Kv Instance.
+---
+
+To access Sorted Set values in a KV Store. First create a `KV Instance` using `KvStore.open()`
+
+This instance will then provide the `zrangeByScore` and `zscan` methods you can use to access Sorted
+Set values.
+
+## zrangeByScore
+
+```js
+import { KvStore } from 'fastedge::kv';
+
+async function eventHandler(event) {
+ try {
+ const myStore = KvStore.open('kv-store-name-as-defined-on-app');
+ const results = myStore.zrangeByScore('key', 0, 10);
+ return new Response(`The KV Store responded with: ${JSON.stringify(results)}`);
+ } catch (error) {
+ return Response.json({ error: error.message }, { status: 500 });
+ }
+}
+
+addEventListener('fetch', (event) => {
+ event.respondWith(eventHandler(event));
+});
+```
+
+```js title="SYNTAX"
+storeInstance.zrangeByScore(key, min, max);
+```
+
+##### Parameters
+
+- `key` (required)
+
+ A string containing the key you want to retrieve the values from.
+
+- `min` (required)
+
+ A number representing the min-score for which to return values for.
+
+- `max` (required)
+
+ A number representing the max-score for which to return values for.
+
+##### Return Value
+
+An `Array<[ArrayBuffer, number]>`. It returns a list of tuples, containing the value in an
+ArrayBuffer and the score as a number.
+
+## zscan
+
+```js
+import { KvStore } from 'fastedge::kv';
+
+async function eventHandler(event) {
+ try {
+ const myStore = KvStore.open('kv-store-name-as-defined-on-app');
+ const results = myStore.zscan('pre*');
+ return new Response(`The KV Store responded with: ${JSON.stringify(results)}`);
+ } catch (error) {
+ return Response.json({ error: error.message }, { status: 500 });
+ }
+}
+
+addEventListener('fetch', (event) => {
+ event.respondWith(eventHandler(event));
+});
+```
+
+```js title="SYNTAX"
+storeInstance.zscan(key, pattern);
+```
+
+##### Parameters
+
+- `key` (required)
+
+ A string containing the key you want to retrieve the values from.
+
+- `pattern` (required)
+
+ A string containing the prefix pattern match.
+
+**Note**: This is a prefix match, it must contain the wildcard `*`. In the given example it matches
+all values that start with `pre`
+
+##### Return Value
+
+An `Array<[ArrayBuffer, number]>`. It returns a list of tuples, containing the value in an
+ArrayBuffer and the score as a number.
diff --git a/docs/src/content/docs/reference/fastedge::secret/getSecretEffectiveAt.md b/docs/src/content/docs/reference/fastedge/secret/get-secret-effective-at.md
similarity index 100%
rename from docs/src/content/docs/reference/fastedge::secret/getSecretEffectiveAt.md
rename to docs/src/content/docs/reference/fastedge/secret/get-secret-effective-at.md
diff --git a/docs/src/content/docs/reference/fastedge::secret/getSecret.md b/docs/src/content/docs/reference/fastedge/secret/get-secret.md
similarity index 100%
rename from docs/src/content/docs/reference/fastedge::secret/getSecret.md
rename to docs/src/content/docs/reference/fastedge/secret/get-secret.md
diff --git a/docs/src/styles/custom.css b/docs/src/styles/custom.css
new file mode 100644
index 0000000..3ff056e
--- /dev/null
+++ b/docs/src/styles/custom.css
@@ -0,0 +1,7 @@
+/* Custom styles for specific Starlight sidebar items */
+
+/* Target only nested details (sub-sections) */
+.sidebar-content details details > summary > div > span {
+ font-weight: normal !important;
+ font-size: var(--sl-text-sm) !important;
+}
diff --git a/package-lock.json b/package-lock.json
index d69e00d..3aa22ab 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,7 +10,7 @@
"license": "Apache-2.0",
"dependencies": {
"@bytecodealliance/jco": "^1.2.4",
- "@bytecodealliance/wizer": "^3.0.1",
+ "@bytecodealliance/wizer": "^10.0.0",
"acorn": "^8.8.2",
"acorn-walk": "^8.2.0",
"arg": "^5.0.2",
@@ -23,6 +23,7 @@
"regexpu-core": "^5.3.2"
},
"bin": {
+ "fastedge-assets": "bin/fastedge-assets.js",
"fastedge-build": "bin/fastedge-build.js",
"fastedge-init": "bin/fastedge-init.js"
},
@@ -1913,122 +1914,6 @@
"componentize-js": "src/cli.js"
}
},
- "node_modules/@bytecodealliance/componentize-js/node_modules/@bytecodealliance/wizer": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer/-/wizer-10.0.0.tgz",
- "integrity": "sha512-ziWmovyu1jQl9TsKlfC2bwuUZwxVPFHlX4fOqTzxhgS76jITIo45nzODEwPgU+jjmOr8F3YX2V2wAChC5NKujg==",
- "license": "Apache-2.0",
- "bin": {
- "wizer": "wizer.js"
- },
- "engines": {
- "node": ">=16"
- },
- "optionalDependencies": {
- "@bytecodealliance/wizer-darwin-arm64": "10.0.0",
- "@bytecodealliance/wizer-darwin-x64": "10.0.0",
- "@bytecodealliance/wizer-linux-arm64": "10.0.0",
- "@bytecodealliance/wizer-linux-s390x": "10.0.0",
- "@bytecodealliance/wizer-linux-x64": "10.0.0",
- "@bytecodealliance/wizer-win32-x64": "10.0.0"
- }
- },
- "node_modules/@bytecodealliance/componentize-js/node_modules/@bytecodealliance/wizer-darwin-arm64": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-arm64/-/wizer-darwin-arm64-10.0.0.tgz",
- "integrity": "sha512-dhZTWel+xccGTKSJtI9A7oM4yyP20FWflsT+AoqkOqkCY7kCNrj4tmMtZ6GXZFRDkrPY5+EnOh62sfShEibAMA==",
- "cpu": [
- "arm64"
- ],
- "license": "Apache-2.0",
- "optional": true,
- "os": [
- "darwin"
- ],
- "bin": {
- "wizer-darwin-arm64": "wizer"
- }
- },
- "node_modules/@bytecodealliance/componentize-js/node_modules/@bytecodealliance/wizer-darwin-x64": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-x64/-/wizer-darwin-x64-10.0.0.tgz",
- "integrity": "sha512-r/LUIZw6Q3Hf4htd46mD+EBxfwjBkxVIrTM1r+B2pTCddoBYQnKVdVsI4UFyy7NoBxzEg8F8BwmTNoSLmFRjpw==",
- "cpu": [
- "x64"
- ],
- "license": "Apache-2.0",
- "optional": true,
- "os": [
- "darwin"
- ],
- "bin": {
- "wizer-darwin-x64": "wizer"
- }
- },
- "node_modules/@bytecodealliance/componentize-js/node_modules/@bytecodealliance/wizer-linux-arm64": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-arm64/-/wizer-linux-arm64-10.0.0.tgz",
- "integrity": "sha512-pGSfFWXzeTqHm6z1PtVaEn+7Fm3QGC8YnHrzBV4sQDVS3N1NwmuHZAc8kslmlFPNdu61ycEvdOsSgCny8JPQvg==",
- "cpu": [
- "arm64"
- ],
- "license": "Apache-2.0",
- "optional": true,
- "os": [
- "linux"
- ],
- "bin": {
- "wizer-linux-arm64": "wizer"
- }
- },
- "node_modules/@bytecodealliance/componentize-js/node_modules/@bytecodealliance/wizer-linux-s390x": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-s390x/-/wizer-linux-s390x-10.0.0.tgz",
- "integrity": "sha512-O8vHxRTAdb1lUnVXMIMTcp/9q4pq1D4iIKigJCipg2JN15taV9uFAWh0fO88wylXwuSlO7dOE1AwQl54fMKXQg==",
- "cpu": [
- "s390x"
- ],
- "license": "Apache-2.0",
- "optional": true,
- "os": [
- "linux"
- ],
- "bin": {
- "wizer-linux-s390x": "wizer"
- }
- },
- "node_modules/@bytecodealliance/componentize-js/node_modules/@bytecodealliance/wizer-linux-x64": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-x64/-/wizer-linux-x64-10.0.0.tgz",
- "integrity": "sha512-fJtM1sy43FBMnp+xpapFX6U1YdTBKA/1T4CYfG/qeE8jn0SXk2EuiYoY/EnC2uyNy9hjTrvfdYO5n4MXW0EIdQ==",
- "cpu": [
- "x64"
- ],
- "license": "Apache-2.0",
- "optional": true,
- "os": [
- "linux"
- ],
- "bin": {
- "wizer-linux-x64": "wizer"
- }
- },
- "node_modules/@bytecodealliance/componentize-js/node_modules/@bytecodealliance/wizer-win32-x64": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-win32-x64/-/wizer-win32-x64-10.0.0.tgz",
- "integrity": "sha512-55BPLfGT7iT7gH5M69NpTM16QknJZ7OxJ0z73VOEoeGA9CT8QPKMRzFKsPIvLs+W8G28fdudFA94nElrdkp3Kg==",
- "cpu": [
- "x64"
- ],
- "license": "Apache-2.0",
- "optional": true,
- "os": [
- "win32"
- ],
- "bin": {
- "wizer-win32-x64": "wizer"
- }
- },
"node_modules/@bytecodealliance/jco": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/@bytecodealliance/jco/-/jco-1.15.0.tgz",
@@ -2069,9 +1954,9 @@
}
},
"node_modules/@bytecodealliance/wizer": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer/-/wizer-3.0.1.tgz",
- "integrity": "sha512-f0NBiBHCNBkbFHTPRbA7aKf/t4KyNhi2KvSqw3QzCgi8wFF/uLZ0dhejj93rbiKO/iwWbmU7v9K3SVkW81mcjQ==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer/-/wizer-10.0.0.tgz",
+ "integrity": "sha512-ziWmovyu1jQl9TsKlfC2bwuUZwxVPFHlX4fOqTzxhgS76jITIo45nzODEwPgU+jjmOr8F3YX2V2wAChC5NKujg==",
"license": "Apache-2.0",
"bin": {
"wizer": "wizer.js"
@@ -2080,18 +1965,18 @@
"node": ">=16"
},
"optionalDependencies": {
- "@bytecodealliance/wizer-darwin-arm64": "3.0.1",
- "@bytecodealliance/wizer-darwin-x64": "3.0.1",
- "@bytecodealliance/wizer-linux-arm64": "3.0.1",
- "@bytecodealliance/wizer-linux-s390x": "3.0.1",
- "@bytecodealliance/wizer-linux-x64": "3.0.1",
- "@bytecodealliance/wizer-win32-x64": "3.0.1"
+ "@bytecodealliance/wizer-darwin-arm64": "10.0.0",
+ "@bytecodealliance/wizer-darwin-x64": "10.0.0",
+ "@bytecodealliance/wizer-linux-arm64": "10.0.0",
+ "@bytecodealliance/wizer-linux-s390x": "10.0.0",
+ "@bytecodealliance/wizer-linux-x64": "10.0.0",
+ "@bytecodealliance/wizer-win32-x64": "10.0.0"
}
},
"node_modules/@bytecodealliance/wizer-darwin-arm64": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-arm64/-/wizer-darwin-arm64-3.0.1.tgz",
- "integrity": "sha512-/8KYSajyhO9koAE3qQhYfC6belZheJw9X3XqW7hrizTpj6n4z4OJFhhqwJmiYFUUsPtC7OxcXMFFPbTuSQPBcw==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-arm64/-/wizer-darwin-arm64-10.0.0.tgz",
+ "integrity": "sha512-dhZTWel+xccGTKSJtI9A7oM4yyP20FWflsT+AoqkOqkCY7kCNrj4tmMtZ6GXZFRDkrPY5+EnOh62sfShEibAMA==",
"cpu": [
"arm64"
],
@@ -2105,9 +1990,9 @@
}
},
"node_modules/@bytecodealliance/wizer-darwin-x64": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-x64/-/wizer-darwin-x64-3.0.1.tgz",
- "integrity": "sha512-bMReultN/r+W/BRXV0F+28U5dZwbQT/ZO0k4icZlhUhrv5/wpQJix7Z/ZvBnVQ+/JHb0QDUpFk2/zCtgkRXP6Q==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-darwin-x64/-/wizer-darwin-x64-10.0.0.tgz",
+ "integrity": "sha512-r/LUIZw6Q3Hf4htd46mD+EBxfwjBkxVIrTM1r+B2pTCddoBYQnKVdVsI4UFyy7NoBxzEg8F8BwmTNoSLmFRjpw==",
"cpu": [
"x64"
],
@@ -2121,9 +2006,9 @@
}
},
"node_modules/@bytecodealliance/wizer-linux-arm64": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-arm64/-/wizer-linux-arm64-3.0.1.tgz",
- "integrity": "sha512-35ZhAeYxWK3bTqqgwysbBWlGlrlMNKNng3ZITQV2PAtafpE7aCeqywl7VAS4lLRG5eTb7wxNgN7zf8d3wiIFTQ==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-arm64/-/wizer-linux-arm64-10.0.0.tgz",
+ "integrity": "sha512-pGSfFWXzeTqHm6z1PtVaEn+7Fm3QGC8YnHrzBV4sQDVS3N1NwmuHZAc8kslmlFPNdu61ycEvdOsSgCny8JPQvg==",
"cpu": [
"arm64"
],
@@ -2137,9 +2022,9 @@
}
},
"node_modules/@bytecodealliance/wizer-linux-s390x": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-s390x/-/wizer-linux-s390x-3.0.1.tgz",
- "integrity": "sha512-Smvy9mguEMtX0lupDLTPshXUzAHeOhgscr1bhGNjeCCLD1sd8rIjBvWV19Wtra0BL1zTuU2EPOHjR/4k8WoyDg==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-s390x/-/wizer-linux-s390x-10.0.0.tgz",
+ "integrity": "sha512-O8vHxRTAdb1lUnVXMIMTcp/9q4pq1D4iIKigJCipg2JN15taV9uFAWh0fO88wylXwuSlO7dOE1AwQl54fMKXQg==",
"cpu": [
"s390x"
],
@@ -2153,9 +2038,9 @@
}
},
"node_modules/@bytecodealliance/wizer-linux-x64": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-x64/-/wizer-linux-x64-3.0.1.tgz",
- "integrity": "sha512-uUue78xl7iwndsGgTsagHLTLyLBVHhwzuywiwHt1xw8y0X0O8REKRLBoB7+LdM+pttDPdFtKJgbTFL4UPAA7Yw==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-linux-x64/-/wizer-linux-x64-10.0.0.tgz",
+ "integrity": "sha512-fJtM1sy43FBMnp+xpapFX6U1YdTBKA/1T4CYfG/qeE8jn0SXk2EuiYoY/EnC2uyNy9hjTrvfdYO5n4MXW0EIdQ==",
"cpu": [
"x64"
],
@@ -2169,9 +2054,9 @@
}
},
"node_modules/@bytecodealliance/wizer-win32-x64": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-win32-x64/-/wizer-win32-x64-3.0.1.tgz",
- "integrity": "sha512-ycd38sx1UTZpHZwh8IfH/4N3n0OQUB8awxkUSLXf9PolEd088YbxoPB3noHy4E+L2oYN7KZMrg9517pX0z2RhQ==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@bytecodealliance/wizer-win32-x64/-/wizer-win32-x64-10.0.0.tgz",
+ "integrity": "sha512-55BPLfGT7iT7gH5M69NpTM16QknJZ7OxJ0z73VOEoeGA9CT8QPKMRzFKsPIvLs+W8G28fdudFA94nElrdkp3Kg==",
"cpu": [
"x64"
],
diff --git a/package.json b/package.json
index 212985b..d75fb08 100644
--- a/package.json
+++ b/package.json
@@ -43,8 +43,8 @@
"build:types": "tsc -p ./tsconfig.build.json",
"typecheck": "tsc -p ./tsconfig.typecheck.json ",
"generate:wit-world": "npm-run-all -s wit:merge wit:bindings",
- "wit:merge": "./runtime/fastedge/host-api/scripts/merge-wit-bindings.js",
- "wit:bindings": "./runtime/fastedge/host-api/scripts/create-wit-bindings.sh",
+ "wit:merge": "./runtime/fastedge/scripts/merge-wit-bindings.js",
+ "wit:bindings": "./runtime/fastedge/scripts/create-wit-bindings.sh",
"lint": "npx eslint -c ./config/eslint/repo/.eslintrc.cjs .",
"semantic-release": "semantic-release",
"test:solo": "NODE_ENV=test jest -c ./config/jest/jest.config.js --",
@@ -85,7 +85,7 @@
},
"dependencies": {
"@bytecodealliance/jco": "^1.2.4",
- "@bytecodealliance/wizer": "^3.0.1",
+ "@bytecodealliance/wizer": "^10.0.0",
"acorn": "^8.8.2",
"acorn-walk": "^8.2.0",
"arg": "^5.0.2",
diff --git a/runtime/FastEdge-wit b/runtime/FastEdge-wit
new file mode 160000
index 0000000..561aa99
--- /dev/null
+++ b/runtime/FastEdge-wit
@@ -0,0 +1 @@
+Subproject commit 561aa99135425fb2a7a01feb989614fcbd083a50
diff --git a/runtime/fastedge/CMakeLists.txt b/runtime/fastedge/CMakeLists.txt
index 5a77d04..484ad36 100644
--- a/runtime/fastedge/CMakeLists.txt
+++ b/runtime/fastedge/CMakeLists.txt
@@ -4,6 +4,7 @@ include("../StarlingMonkey/cmake/add_as_subproject.cmake")
# add_builtin(fastedge::runtime SRC handler.cpp)
add_builtin(fastedge::fastedge SRC builtins/fastedge.cpp)
+add_builtin(fastedge::kv_store SRC builtins/kv-store.cpp)
project(fastedge)
diff --git a/runtime/fastedge/builtins/fastedge.cpp b/runtime/fastedge/builtins/fastedge.cpp
index eda1125..9ac67ff 100644
--- a/runtime/fastedge/builtins/fastedge.cpp
+++ b/runtime/fastedge/builtins/fastedge.cpp
@@ -194,7 +194,6 @@ bool install(api::Engine *engine) {
return false;
}
-
// Ensure that the fastedge objects are not garbage collected and modules are defined
// fastedge:env
RootedValue get_env_val(engine->cx());
diff --git a/runtime/fastedge/builtins/kv-store.cpp b/runtime/fastedge/builtins/kv-store.cpp
new file mode 100644
index 0000000..b99ddf6
--- /dev/null
+++ b/runtime/fastedge/builtins/kv-store.cpp
@@ -0,0 +1,469 @@
+#include "kv-store.h"
+#include
+
+using fastedge::kv_store::KvStore;
+
+namespace {
+api::Engine *ENGINE;
+}
+
+namespace fastedge::kv_store {
+
+// JSClassOps for KvStore instances
+static const JSClassOps kv_store_class_ops = {
+ .finalize = KvStore::finalize,
+};
+
+// JSClass definition for KvStore instances
+const JSClass KvStore::class_ = {
+ "KvStore",
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_FOREGROUND_FINALIZE,
+ &kv_store_class_ops
+};
+
+// Static methods for the KvStore constructor
+const JSFunctionSpec KvStore::static_methods[] = {
+ JS_FN("open", KvStore::open, 1, JSPROP_ENUMERATE),
+ JS_FS_END
+};
+
+// Instance methods for KvStore objects
+const JSFunctionSpec KvStore::methods[] = {
+ JS_FN("get", KvStore::get, 1, JSPROP_ENUMERATE),
+ JS_FN("scan", KvStore::scan, 1, JSPROP_ENUMERATE),
+ JS_FN("zrangeByScore", KvStore::zrange_by_score, 3, JSPROP_ENUMERATE),
+ JS_FN("zscan", KvStore::zscan, 2, JSPROP_ENUMERATE),
+ JS_FN("bfExists", KvStore::bf_exists, 2, JSPROP_ENUMERATE),
+ JS_FS_END
+};
+
+KvStore* KvStore::get_instance(JSContext *cx, JSObject *obj) {
+ return static_cast(JS::GetReservedSlot(obj, 0).toPrivate());
+}
+
+void KvStore::finalize(JS::GCContext *gcx, JSObject *obj) {
+ KvStore* store = static_cast(JS::GetReservedSlot(obj, 0).toPrivate());
+ if (store) {
+ delete store;
+ }
+}
+
+bool KvStore::open(JSContext *cx, unsigned argc, JS::Value *vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+ if (!args.requireAtLeast(cx, "KvStore.open", 1)) {
+ return false;
+ }
+
+ // Convert the store name to string
+ JS::RootedString store_name_str(cx, JS::ToString(cx, args[0]));
+ if (!store_name_str) {
+ return false;
+ }
+
+ JS::UniqueChars store_name = JS_EncodeStringToUTF8(cx, store_name_str);
+ if (!store_name) {
+ return false;
+ }
+
+ // Call the host API to open the store
+ auto result = host_api::kv_store_open(store_name.get());
+
+ // THROW ERRORS...
+ if (!result.is_ok()) {
+ // Handle error cases
+ auto error = result.unwrap_err();
+ switch (error.tag) {
+ case host_api::KvStoreErrorTag::NO_SUCH_STORE:
+ JS_ReportErrorUTF8(cx, "No such store: %s", store_name.get());
+ break;
+ case host_api::KvStoreErrorTag::ACCESS_DENIED:
+ JS_ReportErrorUTF8(cx, "Access denied to store: %s", store_name.get());
+ break;
+ case host_api::KvStoreErrorTag::INTERNAL_ERROR:
+ JS_ReportErrorUTF8(cx, "Internal error opening store: %s", store_name.get());
+ break;
+ case host_api::KvStoreErrorTag::OTHER:
+ JS_ReportErrorUTF8(cx, "Error opening store %s: %s", store_name.get(), error.val.other.ptr);
+ break;
+ }
+ return false;
+ }
+
+ int32_t store_handle = result.unwrap();
+
+ // Create a new KvStore instance
+ JS::RootedObject store_obj(cx, JS_NewObjectWithGivenProto(cx, &KvStore::class_, nullptr));
+ if (!store_obj) {
+ return false;
+ }
+
+ // Create the C++ instance and store it in the JS object
+ KvStore* store_instance = new KvStore(store_handle);
+ JS::SetReservedSlot(store_obj, 0, JS::PrivateValue(store_instance));
+
+ // Define the instance methods
+ if (!JS_DefineFunctions(cx, store_obj, KvStore::methods)) {
+ delete store_instance;
+ return false;
+ }
+
+ args.rval().setObject(*store_obj);
+ return true;
+}
+
+bool KvStore::get(JSContext *cx, unsigned argc, JS::Value *vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+ if (!args.requireAtLeast(cx, "get", 1)) {
+ return false;
+ }
+
+ // Get the KvStore instance
+ JS::RootedObject this_obj(cx, &args.thisv().toObject());
+ KvStore* store = get_instance(cx, this_obj);
+ if (!store) {
+ JS_ReportErrorUTF8(cx, "Invalid KvStore instance");
+ return false;
+ }
+
+ // Convert the key to string
+ JS::RootedString key_str(cx, JS::ToString(cx, args[0]));
+ if (!key_str) {
+ return false;
+ }
+
+ JS::UniqueChars key = JS_EncodeStringToUTF8(cx, key_str);
+ if (!key) {
+ return false;
+ }
+
+ // Call the host API
+ auto result = host_api::kv_store_get(store->store_handle_, key.get());
+
+ if (!result.is_ok()) {
+ // Handle error
+ JS_ReportErrorUTF8(cx, "Error getting key: %s", key.get());
+ return false;
+ }
+
+ auto value_option = result.unwrap();
+ if (!value_option.is_some()) {
+ args.rval().setNull();
+ return true;
+ }
+
+ auto value = value_option.unwrap();
+
+ // Convert the value (list) to a Uint8Array
+ JS::RootedObject byte_array(cx, JS_NewUint8Array(cx, value.len));
+ if (!byte_array) {
+ return false;
+ }
+
+ {
+ JS::AutoCheckCannotGC noGC(cx);
+ bool is_shared;
+ void *array_buffer = JS_GetArrayBufferViewData(byte_array, &is_shared, noGC);
+ memcpy(array_buffer, value.ptr, value.len);
+ }
+
+ args.rval().setObject(*byte_array);
+ return true;
+}
+
+bool KvStore::scan(JSContext *cx, unsigned argc, JS::Value *vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+ if (!args.requireAtLeast(cx, "scan", 1)) {
+ return false;
+ }
+
+ JS::RootedObject this_obj(cx, &args.thisv().toObject());
+ KvStore* store = get_instance(cx, this_obj);
+ if (!store) {
+ JS_ReportErrorUTF8(cx, "Invalid KvStore instance");
+ return false;
+ }
+
+ JS::RootedString pattern_str(cx, JS::ToString(cx, args[0]));
+ if (!pattern_str) {
+ return false;
+ }
+
+ JS::UniqueChars pattern = JS_EncodeStringToUTF8(cx, pattern_str);
+ if (!pattern) {
+ return false;
+ }
+
+ auto result = host_api::kv_store_scan(store->store_handle_, pattern.get());
+
+ if (!result.is_ok()) {
+ JS_ReportErrorUTF8(cx, "Error scanning with pattern: %s (Only prefix matching is supported. e.g. 'foo*')", pattern.get());
+ return false;
+ }
+
+ auto keys = result.unwrap();
+
+ // Create a JavaScript array
+ JS::RootedObject keys_array(cx, JS::NewArrayObject(cx, keys.len));
+ if (!keys_array) {
+ return false;
+ }
+
+ for (size_t i = 0; i < keys.len; i++) {
+ JS::RootedString key_str(cx, JS_NewStringCopyUTF8N(cx,
+ JS::UTF8Chars(keys.ptr[i].begin(), keys.ptr[i].size())));
+ if (!key_str) {
+ return false;
+ }
+
+ JS::RootedValue key_val(cx, JS::StringValue(key_str));
+ if (!JS_SetElement(cx, keys_array, i, key_val)) {
+ return false;
+ }
+ }
+
+ args.rval().setObject(*keys_array);
+ return true;
+}
+
+bool KvStore::zrange_by_score(JSContext *cx, unsigned argc, JS::Value *vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+ if (!args.requireAtLeast(cx, "zrangeByScore", 3)) {
+ return false;
+ }
+
+ JS::RootedObject this_obj(cx, &args.thisv().toObject());
+ KvStore* store = get_instance(cx, this_obj);
+ if (!store) {
+ JS_ReportErrorUTF8(cx, "Invalid KvStore instance");
+ return false;
+ }
+
+ // Convert arguments
+ JS::RootedString key_str(cx, JS::ToString(cx, args[0]));
+ if (!key_str) {
+ return false;
+ }
+
+ JS::UniqueChars key = JS_EncodeStringToUTF8(cx, key_str);
+ if (!key) {
+ return false;
+ }
+
+ double min, max;
+ if (!JS::ToNumber(cx, args[1], &min) || !JS::ToNumber(cx, args[2], &max)) {
+ return false;
+ }
+
+ auto result = host_api::kv_store_zrange_by_score(store->store_handle_, key.get(), min, max);
+
+ if (!result.is_ok()) {
+ JS_ReportErrorUTF8(cx, "Error in zrangeByScore for key: %s", key.get());
+ return false;
+ }
+
+ auto tuples = result.unwrap();
+
+ // Create array of [value, score] tuples
+ JS::RootedObject tuples_array(cx, JS::NewArrayObject(cx, tuples.len));
+ if (!tuples_array) {
+ return false;
+ }
+
+ for (size_t i = 0; i < tuples.len; i++) {
+ // Create the value Uint8Array
+ JS::RootedObject byte_array(cx, JS_NewUint8Array(cx, tuples.ptr[i].f0.len));
+ if (!byte_array) {
+ return false;
+ }
+
+ {
+ JS::AutoCheckCannotGC noGC(cx);
+ bool is_shared;
+ void *array_buffer = JS_GetArrayBufferViewData(byte_array, &is_shared, noGC);
+ memcpy(array_buffer, tuples.ptr[i].f0.ptr, tuples.ptr[i].f0.len);
+ }
+
+ // Create tuple [value, score]
+ JS::RootedObject tuple(cx, JS::NewArrayObject(cx, 2));
+ if (!tuple) {
+ return false;
+ }
+
+ JS::RootedValue value_val(cx, JS::ObjectValue(*byte_array));
+ JS::RootedValue score_val(cx, JS::DoubleValue(tuples.ptr[i].f1));
+
+ if (!JS_SetElement(cx, tuple, 0, value_val) ||
+ !JS_SetElement(cx, tuple, 1, score_val)) {
+ return false;
+ }
+
+ JS::RootedValue tuple_val(cx, JS::ObjectValue(*tuple));
+ if (!JS_SetElement(cx, tuples_array, i, tuple_val)) {
+ return false;
+ }
+ }
+
+ args.rval().setObject(*tuples_array);
+ return true;
+}
+
+bool KvStore::zscan(JSContext *cx, unsigned argc, JS::Value *vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+ if (!args.requireAtLeast(cx, "zscan", 2)) {
+ return false;
+ }
+
+ JS::RootedObject this_obj(cx, &args.thisv().toObject());
+ KvStore* store = get_instance(cx, this_obj);
+ if (!store) {
+ JS_ReportErrorUTF8(cx, "Invalid KvStore instance");
+ return false;
+ }
+
+ JS::RootedString key_str(cx, JS::ToString(cx, args[0]));
+ if (!key_str) {
+ return false;
+ }
+
+ JS::UniqueChars key = JS_EncodeStringToUTF8(cx, key_str);
+ if (!key) {
+ return false;
+ }
+
+ JS::RootedString pattern_str(cx, JS::ToString(cx, args[1]));
+ if (!pattern_str) {
+ return false;
+ }
+
+ JS::UniqueChars pattern = JS_EncodeStringToUTF8(cx, pattern_str);
+ if (!pattern) {
+ return false;
+ }
+
+ auto result = host_api::kv_store_zscan(store->store_handle_, key.get(), pattern.get());
+
+ if (!result.is_ok()) {
+ JS_ReportErrorUTF8(cx, "Error in zscan for key: %s", key.get());
+ return false;
+ }
+
+ auto tuples = result.unwrap();
+
+ // Create array of [value, score] tuples
+ JS::RootedObject tuples_array(cx, JS::NewArrayObject(cx, tuples.len));
+ if (!tuples_array) {
+ return false;
+ }
+
+ for (size_t i = 0; i < tuples.len; i++) {
+ // Create the value Uint8Array
+ JS::RootedObject byte_array(cx, JS_NewUint8Array(cx, tuples.ptr[i].f0.len));
+ if (!byte_array) {
+ return false;
+ }
+
+ {
+ JS::AutoCheckCannotGC noGC(cx);
+ bool is_shared;
+ void *array_buffer = JS_GetArrayBufferViewData(byte_array, &is_shared, noGC);
+ memcpy(array_buffer, tuples.ptr[i].f0.ptr, tuples.ptr[i].f0.len);
+ }
+
+ // Create tuple [value, score]
+ JS::RootedObject tuple(cx, JS::NewArrayObject(cx, 2));
+ if (!tuple) {
+ return false;
+ }
+
+ JS::RootedValue value_val(cx, JS::ObjectValue(*byte_array));
+ JS::RootedValue score_val(cx, JS::DoubleValue(tuples.ptr[i].f1));
+
+ if (!JS_SetElement(cx, tuple, 0, value_val) ||
+ !JS_SetElement(cx, tuple, 1, score_val)) {
+ return false;
+ }
+
+ JS::RootedValue tuple_val(cx, JS::ObjectValue(*tuple));
+ if (!JS_SetElement(cx, tuples_array, i, tuple_val)) {
+ return false;
+ }
+ }
+
+ args.rval().setObject(*tuples_array);
+ return true;
+}
+
+bool KvStore::bf_exists(JSContext *cx, unsigned argc, JS::Value *vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+ if (!args.requireAtLeast(cx, "bfExists", 2)) {
+ return false;
+ }
+
+ JS::RootedObject this_obj(cx, &args.thisv().toObject());
+ KvStore* store = get_instance(cx, this_obj);
+ if (!store) {
+ JS_ReportErrorUTF8(cx, "Invalid KvStore instance");
+ return false;
+ }
+
+ JS::RootedString key_str(cx, JS::ToString(cx, args[0]));
+ if (!key_str) {
+ return false;
+ }
+
+ JS::UniqueChars key = JS_EncodeStringToUTF8(cx, key_str);
+ if (!key) {
+ return false;
+ }
+
+ JS::RootedString item_str(cx, JS::ToString(cx, args[1]));
+ if (!item_str) {
+ return false;
+ }
+
+ JS::UniqueChars item = JS_EncodeStringToUTF8(cx, item_str);
+ if (!item) {
+ return false;
+ }
+
+ auto result = host_api::kv_store_bf_exists(store->store_handle_, key.get(), item.get());
+
+ if (!result.is_ok()) {
+ JS_ReportErrorUTF8(cx, "Error checking bloom filter for key: %s", key.get());
+ return false;
+ }
+
+ args.rval().setBoolean(result.unwrap());
+ return true;
+}
+
+bool install(api::Engine *engine) {
+ ENGINE = engine;
+
+ // Create the KvStore constructor function
+ JS::RootedObject kv_store_ctor(engine->cx(),
+ JS_NewObject(engine->cx(), &KvStore::class_));
+ if (!kv_store_ctor) {
+ return false;
+ }
+
+ // Add static methods to the constructor
+ if (!JS_DefineFunctions(engine->cx(), kv_store_ctor, KvStore::static_methods)) {
+ return false;
+ }
+
+ // Define KvStore on the global object
+ if (!JS_DefineProperty(engine->cx(), engine->global(), "KvStore", kv_store_ctor, 0)) {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace fastedge::kv_store
diff --git a/runtime/fastedge/builtins/kv-store.h b/runtime/fastedge/builtins/kv-store.h
new file mode 100644
index 0000000..586a776
--- /dev/null
+++ b/runtime/fastedge/builtins/kv-store.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "builtin.h"
+#include "../host-api/include/fastedge_host_api.h"
+
+namespace fastedge::kv_store {
+
+class KvStore : public builtins::BuiltinNoConstructor {
+public:
+ static constexpr const char *class_name = "KvStore";
+
+ static bool open(JSContext *cx, unsigned argc, JS::Value *vp);
+ static bool get(JSContext *cx, unsigned argc, JS::Value *vp);
+ static bool scan(JSContext *cx, unsigned argc, JS::Value *vp);
+ static bool zrange_by_score(JSContext *cx, unsigned argc, JS::Value *vp);
+ static bool zscan(JSContext *cx, unsigned argc, JS::Value *vp);
+ static bool bf_exists(JSContext *cx, unsigned argc, JS::Value *vp);
+
+ static void finalize(JS::GCContext *gcx, JSObject *obj);
+
+ static const JSClass class_;
+ static const JSFunctionSpec static_methods[];
+ static const JSFunctionSpec methods[];
+
+private:
+ int32_t store_handle_;
+
+ explicit KvStore(int32_t handle) : store_handle_(handle) {}
+
+ static KvStore* get_instance(JSContext *cx, JSObject *obj);
+};
+
+} // namespace fastedge::kv_store
diff --git a/runtime/fastedge/host-api/bindings/bindings.c b/runtime/fastedge/host-api/bindings/bindings.c
index 306b45c..1113ad0 100644
--- a/runtime/fastedge/host-api/bindings/bindings.c
+++ b/runtime/fastedge/host-api/bindings/bindings.c
@@ -16,6 +16,26 @@ extern void __wasm_import_gcore_fastedge_secret_get(uint8_t *, size_t, uint8_t *
__attribute__((__import_module__("gcore:fastedge/secret"), __import_name__("get-effective-at")))
extern void __wasm_import_gcore_fastedge_secret_get_effective_at(uint8_t *, size_t, int32_t, uint8_t *);
+// Imported Functions from `gcore:fastedge/key-value`
+
+__attribute__((__import_module__("gcore:fastedge/key-value"), __import_name__("[static]store.open")))
+extern void __wasm_import_gcore_fastedge_key_value_static_store_open(uint8_t *, size_t, uint8_t *);
+
+__attribute__((__import_module__("gcore:fastedge/key-value"), __import_name__("[method]store.get")))
+extern void __wasm_import_gcore_fastedge_key_value_method_store_get(int32_t, uint8_t *, size_t, uint8_t *);
+
+__attribute__((__import_module__("gcore:fastedge/key-value"), __import_name__("[method]store.scan")))
+extern void __wasm_import_gcore_fastedge_key_value_method_store_scan(int32_t, uint8_t *, size_t, uint8_t *);
+
+__attribute__((__import_module__("gcore:fastedge/key-value"), __import_name__("[method]store.zrange-by-score")))
+extern void __wasm_import_gcore_fastedge_key_value_method_store_zrange_by_score(int32_t, uint8_t *, size_t, double, double, uint8_t *);
+
+__attribute__((__import_module__("gcore:fastedge/key-value"), __import_name__("[method]store.zscan")))
+extern void __wasm_import_gcore_fastedge_key_value_method_store_zscan(int32_t, uint8_t *, size_t, uint8_t *, size_t, uint8_t *);
+
+__attribute__((__import_module__("gcore:fastedge/key-value"), __import_name__("[method]store.bf-exists")))
+extern void __wasm_import_gcore_fastedge_key_value_method_store_bf_exists(int32_t, uint8_t *, size_t, uint8_t *, size_t, uint8_t *);
+
// Imported Functions from `wasi:cli/environment@0.2.3`
__attribute__((__import_module__("wasi:cli/environment@0.2.3"), __import_name__("get-environment")))
@@ -632,22 +652,57 @@ void gcore_fastedge_secret_result_option_string_error_free(gcore_fastedge_secret
}
}
-void bindings_tuple2_string_string_free(bindings_tuple2_string_string_t *ptr) {
- bindings_string_free(&ptr->f0);
- bindings_string_free(&ptr->f1);
-}
-
-void bindings_list_tuple2_string_string_free(bindings_list_tuple2_string_string_t *ptr) {
+void gcore_fastedge_key_value_value_free(gcore_fastedge_key_value_value_t *ptr) {
size_t list_len = ptr->len;
if (list_len > 0) {
- bindings_tuple2_string_string_t *list_ptr = ptr->ptr;
+ uint8_t *list_ptr = ptr->ptr;
for (size_t i = 0; i < list_len; i++) {
- bindings_tuple2_string_string_free(&list_ptr[i]);
}
free(list_ptr);
}
}
+__attribute__((__import_module__("gcore:fastedge/key-value"), __import_name__("[resource-drop]store")))
+extern void __wasm_import_gcore_fastedge_key_value_store_drop(int32_t handle);
+
+void gcore_fastedge_key_value_store_drop_own(gcore_fastedge_key_value_own_store_t handle) {
+ __wasm_import_gcore_fastedge_key_value_store_drop(handle.__handle);
+}
+
+gcore_fastedge_key_value_borrow_store_t gcore_fastedge_key_value_borrow_store(gcore_fastedge_key_value_own_store_t arg) {
+ return (gcore_fastedge_key_value_borrow_store_t) { arg.__handle };
+}
+
+void gcore_fastedge_key_value_error_free(gcore_fastedge_key_value_error_t *ptr) {
+ switch ((int32_t) ptr->tag) {
+ case 3: {
+ bindings_string_free(&ptr->val.other);
+ break;
+ }
+ }
+}
+
+void gcore_fastedge_key_value_result_own_store_error_free(gcore_fastedge_key_value_result_own_store_error_t *ptr) {
+ if (!ptr->is_err) {
+ } else {
+ gcore_fastedge_key_value_error_free(&ptr->val.err);
+ }
+}
+
+void bindings_option_value_free(bindings_option_value_t *ptr) {
+ if (ptr->is_some) {
+ gcore_fastedge_key_value_value_free(&ptr->val);
+ }
+}
+
+void gcore_fastedge_key_value_result_option_value_error_free(gcore_fastedge_key_value_result_option_value_error_t *ptr) {
+ if (!ptr->is_err) {
+ bindings_option_value_free(&ptr->val.ok);
+ } else {
+ gcore_fastedge_key_value_error_free(&ptr->val.err);
+ }
+}
+
void bindings_list_string_free(bindings_list_string_t *ptr) {
size_t list_len = ptr->len;
if (list_len > 0) {
@@ -659,6 +714,60 @@ void bindings_list_string_free(bindings_list_string_t *ptr) {
}
}
+void gcore_fastedge_key_value_result_list_string_error_free(gcore_fastedge_key_value_result_list_string_error_t *ptr) {
+ if (!ptr->is_err) {
+ bindings_list_string_free(&ptr->val.ok);
+ } else {
+ gcore_fastedge_key_value_error_free(&ptr->val.err);
+ }
+}
+
+void bindings_tuple2_value_f64_free(bindings_tuple2_value_f64_t *ptr) {
+ gcore_fastedge_key_value_value_free(&ptr->f0);
+}
+
+void bindings_list_tuple2_value_f64_free(bindings_list_tuple2_value_f64_t *ptr) {
+ size_t list_len = ptr->len;
+ if (list_len > 0) {
+ bindings_tuple2_value_f64_t *list_ptr = ptr->ptr;
+ for (size_t i = 0; i < list_len; i++) {
+ bindings_tuple2_value_f64_free(&list_ptr[i]);
+ }
+ free(list_ptr);
+ }
+}
+
+void gcore_fastedge_key_value_result_list_tuple2_value_f64_error_free(gcore_fastedge_key_value_result_list_tuple2_value_f64_error_t *ptr) {
+ if (!ptr->is_err) {
+ bindings_list_tuple2_value_f64_free(&ptr->val.ok);
+ } else {
+ gcore_fastedge_key_value_error_free(&ptr->val.err);
+ }
+}
+
+void gcore_fastedge_key_value_result_bool_error_free(gcore_fastedge_key_value_result_bool_error_t *ptr) {
+ if (!ptr->is_err) {
+ } else {
+ gcore_fastedge_key_value_error_free(&ptr->val.err);
+ }
+}
+
+void bindings_tuple2_string_string_free(bindings_tuple2_string_string_t *ptr) {
+ bindings_string_free(&ptr->f0);
+ bindings_string_free(&ptr->f1);
+}
+
+void bindings_list_tuple2_string_string_free(bindings_list_tuple2_string_string_t *ptr) {
+ size_t list_len = ptr->len;
+ if (list_len > 0) {
+ bindings_tuple2_string_string_t *list_ptr = ptr->ptr;
+ for (size_t i = 0; i < list_len; i++) {
+ bindings_tuple2_string_string_free(&list_ptr[i]);
+ }
+ free(list_ptr);
+ }
+}
+
void wasi_cli_exit_result_void_void_free(wasi_cli_exit_result_void_void_t *ptr) {
if (!ptr->is_err) {
}
@@ -1793,6 +1902,289 @@ bool gcore_fastedge_secret_get_effective_at(bindings_string_t *key, uint32_t at,
}
}
+bool gcore_fastedge_key_value_static_store_open(bindings_string_t *name, gcore_fastedge_key_value_own_store_t *ret, gcore_fastedge_key_value_error_t *err) {
+ __attribute__((__aligned__(4)))
+ uint8_t ret_area[16];
+ uint8_t *ptr = (uint8_t *) &ret_area;
+ __wasm_import_gcore_fastedge_key_value_static_store_open((uint8_t *) (*name).ptr, (*name).len, ptr);
+ gcore_fastedge_key_value_result_own_store_error_t result;
+ switch ((int32_t) *((uint8_t*) (ptr + 0))) {
+ case 0: {
+ result.is_err = false;
+ result.val.ok = (gcore_fastedge_key_value_own_store_t) { *((int32_t*) (ptr + 4)) };
+ break;
+ }
+ case 1: {
+ result.is_err = true;
+ gcore_fastedge_key_value_error_t variant;
+ variant.tag = (int32_t) *((uint8_t*) (ptr + 4));
+ switch ((int32_t) variant.tag) {
+ case 0: {
+ break;
+ }
+ case 1: {
+ break;
+ }
+ case 2: {
+ break;
+ }
+ case 3: {
+ variant.val.other = (bindings_string_t) { (uint8_t*)(*((uint8_t **) (ptr + 8))), (*((size_t*) (ptr + 12))) };
+ break;
+ }
+ }
+
+ result.val.err = variant;
+ break;
+ }
+ }
+ if (!result.is_err) {
+ *ret = result.val.ok;
+ return 1;
+ } else {
+ *err = result.val.err;
+ return 0;
+ }
+}
+
+bool gcore_fastedge_key_value_method_store_get(gcore_fastedge_key_value_borrow_store_t self, bindings_string_t *key, bindings_option_value_t *ret, gcore_fastedge_key_value_error_t *err) {
+ __attribute__((__aligned__(4)))
+ uint8_t ret_area[16];
+ uint8_t *ptr = (uint8_t *) &ret_area;
+ __wasm_import_gcore_fastedge_key_value_method_store_get((self).__handle, (uint8_t *) (*key).ptr, (*key).len, ptr);
+ gcore_fastedge_key_value_result_option_value_error_t result;
+ switch ((int32_t) *((uint8_t*) (ptr + 0))) {
+ case 0: {
+ result.is_err = false;
+ bindings_option_value_t option;
+ switch ((int32_t) *((uint8_t*) (ptr + 4))) {
+ case 0: {
+ option.is_some = false;
+ break;
+ }
+ case 1: {
+ option.is_some = true;
+ option.val = (gcore_fastedge_key_value_value_t) { (uint8_t*)(*((uint8_t **) (ptr + 8))), (*((size_t*) (ptr + 12))) };
+ break;
+ }
+ }
+
+ result.val.ok = option;
+ break;
+ }
+ case 1: {
+ result.is_err = true;
+ gcore_fastedge_key_value_error_t variant;
+ variant.tag = (int32_t) *((uint8_t*) (ptr + 4));
+ switch ((int32_t) variant.tag) {
+ case 0: {
+ break;
+ }
+ case 1: {
+ break;
+ }
+ case 2: {
+ break;
+ }
+ case 3: {
+ variant.val.other = (bindings_string_t) { (uint8_t*)(*((uint8_t **) (ptr + 8))), (*((size_t*) (ptr + 12))) };
+ break;
+ }
+ }
+
+ result.val.err = variant;
+ break;
+ }
+ }
+ if (!result.is_err) {
+ *ret = result.val.ok;
+ return 1;
+ } else {
+ *err = result.val.err;
+ return 0;
+ }
+}
+
+bool gcore_fastedge_key_value_method_store_scan(gcore_fastedge_key_value_borrow_store_t self, bindings_string_t *pattern, bindings_list_string_t *ret, gcore_fastedge_key_value_error_t *err) {
+ __attribute__((__aligned__(4)))
+ uint8_t ret_area[16];
+ uint8_t *ptr = (uint8_t *) &ret_area;
+ __wasm_import_gcore_fastedge_key_value_method_store_scan((self).__handle, (uint8_t *) (*pattern).ptr, (*pattern).len, ptr);
+ gcore_fastedge_key_value_result_list_string_error_t result;
+ switch ((int32_t) *((uint8_t*) (ptr + 0))) {
+ case 0: {
+ result.is_err = false;
+ result.val.ok = (bindings_list_string_t) { (bindings_string_t*)(*((uint8_t **) (ptr + 4))), (*((size_t*) (ptr + 8))) };
+ break;
+ }
+ case 1: {
+ result.is_err = true;
+ gcore_fastedge_key_value_error_t variant;
+ variant.tag = (int32_t) *((uint8_t*) (ptr + 4));
+ switch ((int32_t) variant.tag) {
+ case 0: {
+ break;
+ }
+ case 1: {
+ break;
+ }
+ case 2: {
+ break;
+ }
+ case 3: {
+ variant.val.other = (bindings_string_t) { (uint8_t*)(*((uint8_t **) (ptr + 8))), (*((size_t*) (ptr + 12))) };
+ break;
+ }
+ }
+
+ result.val.err = variant;
+ break;
+ }
+ }
+ if (!result.is_err) {
+ *ret = result.val.ok;
+ return 1;
+ } else {
+ *err = result.val.err;
+ return 0;
+ }
+}
+
+bool gcore_fastedge_key_value_method_store_zrange_by_score(gcore_fastedge_key_value_borrow_store_t self, bindings_string_t *key, double min, double max, bindings_list_tuple2_value_f64_t *ret, gcore_fastedge_key_value_error_t *err) {
+ __attribute__((__aligned__(4)))
+ uint8_t ret_area[16];
+ uint8_t *ptr = (uint8_t *) &ret_area;
+ __wasm_import_gcore_fastedge_key_value_method_store_zrange_by_score((self).__handle, (uint8_t *) (*key).ptr, (*key).len, min, max, ptr);
+ gcore_fastedge_key_value_result_list_tuple2_value_f64_error_t result;
+ switch ((int32_t) *((uint8_t*) (ptr + 0))) {
+ case 0: {
+ result.is_err = false;
+ result.val.ok = (bindings_list_tuple2_value_f64_t) { (bindings_tuple2_value_f64_t*)(*((uint8_t **) (ptr + 4))), (*((size_t*) (ptr + 8))) };
+ break;
+ }
+ case 1: {
+ result.is_err = true;
+ gcore_fastedge_key_value_error_t variant;
+ variant.tag = (int32_t) *((uint8_t*) (ptr + 4));
+ switch ((int32_t) variant.tag) {
+ case 0: {
+ break;
+ }
+ case 1: {
+ break;
+ }
+ case 2: {
+ break;
+ }
+ case 3: {
+ variant.val.other = (bindings_string_t) { (uint8_t*)(*((uint8_t **) (ptr + 8))), (*((size_t*) (ptr + 12))) };
+ break;
+ }
+ }
+
+ result.val.err = variant;
+ break;
+ }
+ }
+ if (!result.is_err) {
+ *ret = result.val.ok;
+ return 1;
+ } else {
+ *err = result.val.err;
+ return 0;
+ }
+}
+
+bool gcore_fastedge_key_value_method_store_zscan(gcore_fastedge_key_value_borrow_store_t self, bindings_string_t *key, bindings_string_t *pattern, bindings_list_tuple2_value_f64_t *ret, gcore_fastedge_key_value_error_t *err) {
+ __attribute__((__aligned__(4)))
+ uint8_t ret_area[16];
+ uint8_t *ptr = (uint8_t *) &ret_area;
+ __wasm_import_gcore_fastedge_key_value_method_store_zscan((self).__handle, (uint8_t *) (*key).ptr, (*key).len, (uint8_t *) (*pattern).ptr, (*pattern).len, ptr);
+ gcore_fastedge_key_value_result_list_tuple2_value_f64_error_t result;
+ switch ((int32_t) *((uint8_t*) (ptr + 0))) {
+ case 0: {
+ result.is_err = false;
+ result.val.ok = (bindings_list_tuple2_value_f64_t) { (bindings_tuple2_value_f64_t*)(*((uint8_t **) (ptr + 4))), (*((size_t*) (ptr + 8))) };
+ break;
+ }
+ case 1: {
+ result.is_err = true;
+ gcore_fastedge_key_value_error_t variant;
+ variant.tag = (int32_t) *((uint8_t*) (ptr + 4));
+ switch ((int32_t) variant.tag) {
+ case 0: {
+ break;
+ }
+ case 1: {
+ break;
+ }
+ case 2: {
+ break;
+ }
+ case 3: {
+ variant.val.other = (bindings_string_t) { (uint8_t*)(*((uint8_t **) (ptr + 8))), (*((size_t*) (ptr + 12))) };
+ break;
+ }
+ }
+
+ result.val.err = variant;
+ break;
+ }
+ }
+ if (!result.is_err) {
+ *ret = result.val.ok;
+ return 1;
+ } else {
+ *err = result.val.err;
+ return 0;
+ }
+}
+
+bool gcore_fastedge_key_value_method_store_bf_exists(gcore_fastedge_key_value_borrow_store_t self, bindings_string_t *key, bindings_string_t *item, bool *ret, gcore_fastedge_key_value_error_t *err) {
+ __attribute__((__aligned__(4)))
+ uint8_t ret_area[16];
+ uint8_t *ptr = (uint8_t *) &ret_area;
+ __wasm_import_gcore_fastedge_key_value_method_store_bf_exists((self).__handle, (uint8_t *) (*key).ptr, (*key).len, (uint8_t *) (*item).ptr, (*item).len, ptr);
+ gcore_fastedge_key_value_result_bool_error_t result;
+ switch ((int32_t) *((uint8_t*) (ptr + 0))) {
+ case 0: {
+ result.is_err = false;
+ result.val.ok = (int32_t) *((uint8_t*) (ptr + 4));
+ break;
+ }
+ case 1: {
+ result.is_err = true;
+ gcore_fastedge_key_value_error_t variant;
+ variant.tag = (int32_t) *((uint8_t*) (ptr + 4));
+ switch ((int32_t) variant.tag) {
+ case 0: {
+ break;
+ }
+ case 1: {
+ break;
+ }
+ case 2: {
+ break;
+ }
+ case 3: {
+ variant.val.other = (bindings_string_t) { (uint8_t*)(*((uint8_t **) (ptr + 8))), (*((size_t*) (ptr + 12))) };
+ break;
+ }
+ }
+
+ result.val.err = variant;
+ break;
+ }
+ }
+ if (!result.is_err) {
+ *ret = result.val.ok;
+ return 1;
+ } else {
+ *err = result.val.err;
+ return 0;
+ }
+}
+
void wasi_cli_environment_get_environment(bindings_list_tuple2_string_string_t *ret) {
__attribute__((__aligned__(4)))
uint8_t ret_area[8];
diff --git a/runtime/fastedge/host-api/bindings/bindings.h b/runtime/fastedge/host-api/bindings/bindings.h
index 4250bc5..fc430f8 100644
--- a/runtime/fastedge/host-api/bindings/bindings.h
+++ b/runtime/fastedge/host-api/bindings/bindings.h
@@ -42,6 +42,97 @@ typedef struct {
} val;
} gcore_fastedge_secret_result_option_string_error_t;
+typedef struct gcore_fastedge_key_value_value_t {
+ uint8_t *ptr;
+ size_t len;
+} gcore_fastedge_key_value_value_t;
+
+typedef struct gcore_fastedge_key_value_own_store_t {
+ int32_t __handle;
+} gcore_fastedge_key_value_own_store_t;
+
+typedef struct gcore_fastedge_key_value_borrow_store_t {
+ int32_t __handle;
+} gcore_fastedge_key_value_borrow_store_t;
+
+// The set of errors which may be raised by functions in this interface
+typedef struct gcore_fastedge_key_value_error_t {
+ uint8_t tag;
+ union {
+ bindings_string_t other;
+ } val;
+} gcore_fastedge_key_value_error_t;
+
+// The host does not recognize the store label requested.
+#define GCORE_FASTEDGE_KEY_VALUE_ERROR_NO_SUCH_STORE 0
+// The requesting component does not have access to the specified store
+// (which may or may not exist).
+#define GCORE_FASTEDGE_KEY_VALUE_ERROR_ACCESS_DENIED 1
+// Some unexpected internal error has occurred.
+#define GCORE_FASTEDGE_KEY_VALUE_ERROR_INTERNAL_ERROR 2
+// Some implementation-specific error has occurred (e.g. I/O)
+#define GCORE_FASTEDGE_KEY_VALUE_ERROR_OTHER 3
+
+typedef struct {
+ bool is_err;
+ union {
+ gcore_fastedge_key_value_own_store_t ok;
+ gcore_fastedge_key_value_error_t err;
+ } val;
+} gcore_fastedge_key_value_result_own_store_error_t;
+
+typedef struct {
+ bool is_some;
+ gcore_fastedge_key_value_value_t val;
+} bindings_option_value_t;
+
+typedef struct {
+ bool is_err;
+ union {
+ bindings_option_value_t ok;
+ gcore_fastedge_key_value_error_t err;
+ } val;
+} gcore_fastedge_key_value_result_option_value_error_t;
+
+typedef struct {
+ bindings_string_t *ptr;
+ size_t len;
+} bindings_list_string_t;
+
+typedef struct {
+ bool is_err;
+ union {
+ bindings_list_string_t ok;
+ gcore_fastedge_key_value_error_t err;
+ } val;
+} gcore_fastedge_key_value_result_list_string_error_t;
+
+typedef struct {
+ gcore_fastedge_key_value_value_t f0;
+ double f1;
+} bindings_tuple2_value_f64_t;
+
+typedef struct {
+ bindings_tuple2_value_f64_t *ptr;
+ size_t len;
+} bindings_list_tuple2_value_f64_t;
+
+typedef struct {
+ bool is_err;
+ union {
+ bindings_list_tuple2_value_f64_t ok;
+ gcore_fastedge_key_value_error_t err;
+ } val;
+} gcore_fastedge_key_value_result_list_tuple2_value_f64_error_t;
+
+typedef struct {
+ bool is_err;
+ union {
+ bool ok;
+ gcore_fastedge_key_value_error_t err;
+ } val;
+} gcore_fastedge_key_value_result_bool_error_t;
+
typedef struct {
bindings_string_t f0;
bindings_string_t f1;
@@ -52,11 +143,6 @@ typedef struct {
size_t len;
} bindings_list_tuple2_string_string_t;
-typedef struct {
- bindings_string_t *ptr;
- size_t len;
-} bindings_list_string_t;
-
typedef struct {
bool is_err;
} wasi_cli_exit_result_void_void_t;
@@ -1317,13 +1403,44 @@ typedef wasi_http_types_own_response_outparam_t exports_wasi_http_incoming_handl
extern bool gcore_fastedge_dictionary_get(bindings_string_t *name, bindings_string_t *ret);
// Imported Functions from `gcore:fastedge/secret`
-// Get the secret associated with the specified `key` efective at current timestamp.
+// Get the secret associated with the specified `key` effective at current timestamp.
// Returns `ok(none)` if the key does not exist.
extern bool gcore_fastedge_secret_get(bindings_string_t *key, bindings_option_string_t *ret, gcore_fastedge_secret_error_t *err);
// Get the secret associated with the specified `key` effective `at` given timestamp in seconds.
// Returns `ok(none)` if the key does not exist.
extern bool gcore_fastedge_secret_get_effective_at(bindings_string_t *key, uint32_t at, bindings_option_string_t *ret, gcore_fastedge_secret_error_t *err);
+// Imported Functions from `gcore:fastedge/key-value`
+// Open the store with the specified name.
+//
+// `error::no-such-store` will be raised if the `name` is not recognized.
+extern bool gcore_fastedge_key_value_static_store_open(bindings_string_t *name, gcore_fastedge_key_value_own_store_t *ret, gcore_fastedge_key_value_error_t *err);
+// Get the value associated with the specified `key`
+//
+// Returns `ok(none)` if the key does not exist.
+extern bool gcore_fastedge_key_value_method_store_get(gcore_fastedge_key_value_borrow_store_t self, bindings_string_t *key, bindings_option_value_t *ret, gcore_fastedge_key_value_error_t *err);
+// Interface to scan over keys in the store.
+// It matches glob-style pattern filter on each element from the retrieved collection.
+//
+// Returns an array of elements as a list of keys.
+extern bool gcore_fastedge_key_value_method_store_scan(gcore_fastedge_key_value_borrow_store_t self, bindings_string_t *pattern, bindings_list_string_t *ret, gcore_fastedge_key_value_error_t *err);
+// Get all the elements with score from the sorted set at `key` with a f64 score between min and max
+// (including elements with score equal to min or max). The elements are considered to be ordered from low to high
+// scores.
+//
+// Returns empty `Vec` if the key does not exist or if no elements have scores between min and max.
+extern bool gcore_fastedge_key_value_method_store_zrange_by_score(gcore_fastedge_key_value_borrow_store_t self, bindings_string_t *key, double min, double max, bindings_list_tuple2_value_f64_t *ret, gcore_fastedge_key_value_error_t *err);
+// Interface to scan through a sorted set by key
+// It matches glob-style pattern filter on each elements from the retrieved collection.
+//
+// Returns an array of elements as a list of value of the Sorted Set.
+extern bool gcore_fastedge_key_value_method_store_zscan(gcore_fastedge_key_value_borrow_store_t self, bindings_string_t *key, bindings_string_t *pattern, bindings_list_tuple2_value_f64_t *ret, gcore_fastedge_key_value_error_t *err);
+// Determines whether a given item was added to a Bloom filter.
+//
+// Returns one of these replies: 'true' means that, with high probability, item was already added to the filter,
+// and 'false' means that key does not exist or that item had not been added to the filter.
+extern bool gcore_fastedge_key_value_method_store_bf_exists(gcore_fastedge_key_value_borrow_store_t self, bindings_string_t *key, bindings_string_t *item, bool *ret, gcore_fastedge_key_value_error_t *err);
+
// Imported Functions from `wasi:cli/environment@0.2.3`
// Get the POSIX-style environment variables.
//
@@ -1842,12 +1959,36 @@ void gcore_fastedge_secret_error_free(gcore_fastedge_secret_error_t *ptr);
void gcore_fastedge_secret_result_option_string_error_free(gcore_fastedge_secret_result_option_string_error_t *ptr);
-void bindings_tuple2_string_string_free(bindings_tuple2_string_string_t *ptr);
+void gcore_fastedge_key_value_value_free(gcore_fastedge_key_value_value_t *ptr);
-void bindings_list_tuple2_string_string_free(bindings_list_tuple2_string_string_t *ptr);
+extern void gcore_fastedge_key_value_store_drop_own(gcore_fastedge_key_value_own_store_t handle);
+
+extern gcore_fastedge_key_value_borrow_store_t gcore_fastedge_key_value_borrow_store(gcore_fastedge_key_value_own_store_t handle);
+
+void gcore_fastedge_key_value_error_free(gcore_fastedge_key_value_error_t *ptr);
+
+void gcore_fastedge_key_value_result_own_store_error_free(gcore_fastedge_key_value_result_own_store_error_t *ptr);
+
+void bindings_option_value_free(bindings_option_value_t *ptr);
+
+void gcore_fastedge_key_value_result_option_value_error_free(gcore_fastedge_key_value_result_option_value_error_t *ptr);
void bindings_list_string_free(bindings_list_string_t *ptr);
+void gcore_fastedge_key_value_result_list_string_error_free(gcore_fastedge_key_value_result_list_string_error_t *ptr);
+
+void bindings_tuple2_value_f64_free(bindings_tuple2_value_f64_t *ptr);
+
+void bindings_list_tuple2_value_f64_free(bindings_list_tuple2_value_f64_t *ptr);
+
+void gcore_fastedge_key_value_result_list_tuple2_value_f64_error_free(gcore_fastedge_key_value_result_list_tuple2_value_f64_error_t *ptr);
+
+void gcore_fastedge_key_value_result_bool_error_free(gcore_fastedge_key_value_result_bool_error_t *ptr);
+
+void bindings_tuple2_string_string_free(bindings_tuple2_string_string_t *ptr);
+
+void bindings_list_tuple2_string_string_free(bindings_list_tuple2_string_string_t *ptr);
+
void wasi_cli_exit_result_void_void_free(wasi_cli_exit_result_void_void_t *ptr);
extern void wasi_io_error_error_drop_own(wasi_io_error_own_error_t handle);
diff --git a/runtime/fastedge/host-api/bindings/bindings_component_type.o b/runtime/fastedge/host-api/bindings/bindings_component_type.o
index 3217439..ff505ff 100644
Binary files a/runtime/fastedge/host-api/bindings/bindings_component_type.o and b/runtime/fastedge/host-api/bindings/bindings_component_type.o differ
diff --git a/runtime/fastedge/host-api/deps/fastedge/key-value.wit b/runtime/fastedge/host-api/deps/fastedge/key-value.wit
new file mode 100644
index 0000000..6d94782
--- /dev/null
+++ b/runtime/fastedge/host-api/deps/fastedge/key-value.wit
@@ -0,0 +1,54 @@
+interface key-value {
+ type value = list;
+ type list-result = list;
+ type zlist-result = list>;
+
+ /// FastEdge key-value persistent store resource
+ resource store {
+ /// Open the store with the specified name.
+ ///
+ /// `error::no-such-store` will be raised if the `name` is not recognized.
+ open: static func(name: string) -> result;
+
+ /// Get the value associated with the specified `key`
+ ///
+ /// Returns `ok(none)` if the key does not exist.
+ get: func(key: string) -> result