New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@thi.ng/wasm-api

Package Overview
Dependencies
Maintainers
1
Versions
146
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@thi.ng/wasm-api - npm Package Compare versions

Comparing version 0.5.0 to 0.6.0

codegen.d.ts

148

api.d.ts

@@ -1,3 +0,4 @@

import type { Fn, Fn2 } from "@thi.ng/api";
import type { FloatType, Fn, Fn2 } from "@thi.ng/api";
import type { WasmBridge } from "./bridge.js";
export declare const PKG_NAME = "@thi.ng/wasm-api";
export declare type BigIntArray = bigint[] | BigInt64Array | BigUint64Array;

@@ -63,9 +64,19 @@ /**

*
* @remarks
* In the supplied Zig bindings (/zig/core.zig) this is a no-op (currently).
*
* @param addr
* @param numBytes
*/
_wasm_free(addr: number): void;
_wasm_free(addr: number, numBytes: number): void;
}
export interface WasmMemViews {
i8: Int8Array;
u8: Uint8Array;
i16: Int16Array;
u16: Uint16Array;
i32: Int32Array;
u32: Uint32Array;
i64: BigInt64Array;
u64: BigUint64Array;
f32: Float32Array;
f64: Float64Array;
}
/**

@@ -104,2 +115,129 @@ * Core API of WASM imports defined by the {@link WasmBridge}. The same

}
export interface WasmTypeBase {
/**
* Base address in linear WASM memory.
*/
readonly __base: number;
/**
* Obtain as byte buffer
*/
readonly __bytes: Uint8Array;
}
export interface WasmType<T> {
readonly align: number;
readonly size: number;
instance: Fn<number, T>;
}
export declare type WasmTypeConstructor<T> = Fn<WasmMemViews, WasmType<T>>;
export declare type WasmInt = "i8" | "i16" | "i32" | "i64";
export declare type WasmUint = "u8" | "u16" | "u32" | "u64";
export declare type WasmFloat = FloatType;
export declare type WasmPrim = WasmInt | WasmUint | WasmFloat;
export declare type TypeColl = Record<string, TopLevelType>;
export interface TypeInfo {
/**
* Auto-computed size (in bytes)
*
* @internal
*/
__size?: number;
/**
* Auto-computed offset (in bytes) in parent struct
*
* @internal
*/
__offset?: number;
/**
* Auto-computed alignment (in bytes)
*
* @internal
*/
__align?: number;
}
export interface TopLevelType extends TypeInfo {
name: string;
doc?: string;
type: "struct" | "enum";
}
export interface Struct extends TopLevelType {
type: "struct";
fields: StructField[];
/**
* If true, struct fields will be re-ordered in descending order based on
* their {@link TypeInfo.__align} size.
*
* @defaultValue false
*/
auto?: boolean;
}
export interface StructField extends TypeInfo {
/**
* Field name (prefix: "__" is reserved)
*/
name: string;
/**
* Field docstring (can be multiline, will be formatted)
*/
doc?: string;
/**
* Field type tag/qualifier (note: `slice` & `vec` are only supported by
* Zig & TS)
*
* @defaultValue "scalar"
*/
tag?: "scalar" | "array" | "ptr" | "slice" | "vec";
/**
* Field base type. If not a {@link WasmPrim} or `opaque`, the value is
* interpreted as another type name in the {@link TypeColl}.
*
* TODO `opaque` currently unsupported.
*/
type: WasmPrim | "opaque" | string;
/**
* TODO currently unsupported!
*/
sentinel?: number;
/**
* Array or vector length
*/
len?: number;
/**
* TODO currently unsupported!
*/
default?: any;
}
export interface Enum extends TopLevelType {
type: "enum";
/**
* No u64 support, due to Typescript not supporting bigint enum values
*/
tag: Exclude<WasmUint, "u64">;
values: (string | EnumValue)[];
}
export interface EnumValue {
name: string;
value?: number;
doc?: string;
}
export interface ICodeGen {
/**
* Optional prelude source, to be prepended before any generated type defs.
*/
pre?: string;
/**
* Optional source code to be appended after any generated type defs.
*/
post?: string;
doc: (doc: string, indent: string, acc: string[], topLevel?: boolean) => void;
enum: (type: Enum, types: TypeColl, acc: string[]) => void;
struct: (type: Struct, types: TypeColl, acc: string[]) => void;
}
/**
* WASM usize type. Assuming wasm32 until wasm64 surfaces, then need an option.
*/
export declare const USIZE = "u32";
/**
* Byte size of {@link USIZE}.
*/
export declare const USIZE_SIZE = 4;
//# sourceMappingURL=api.d.ts.map

@@ -1,1 +0,9 @@

export {};
export const PKG_NAME = "@thi.ng/wasm-api";
/**
* WASM usize type. Assuming wasm32 until wasm64 surfaces, then need an option.
*/
export const USIZE = "u32";
/**
* Byte size of {@link USIZE}.
*/
export const USIZE_SIZE = 4;
/// <reference types="node" />
import type { NumericArray } from "@thi.ng/api";
import type { ILogger } from "@thi.ng/logger";
import type { BigIntArray, CoreAPI, IWasmAPI, WasmExports } from "./api.js";
import type { BigIntArray, CoreAPI, IWasmAPI, WasmExports, WasmMemViews } from "./api.js";
export declare const OutOfMemoryError: {

@@ -31,3 +31,3 @@ new (msg?: string | undefined): {

*/
export declare class WasmBridge<T extends WasmExports = WasmExports> {
export declare class WasmBridge<T extends WasmExports = WasmExports> implements WasmMemViews {
modules: Record<string, IWasmAPI<T>>;

@@ -49,3 +49,3 @@ logger: ILogger;

exports: T;
core: CoreAPI;
api: CoreAPI;
constructor(modules?: Record<string, IWasmAPI<T>>, logger?: ILogger);

@@ -100,3 +100,3 @@ /**

* // imports defined by the core API of the bridge itself
* core: { ... },
* wasmapi: { ... },
* // imports defined by the CustomAPI module

@@ -127,3 +127,4 @@ * custom: { ... }

* start address of the new memory block. If unsuccessful, throws an
* {@link OutOfMemoryError}.
* {@link OutOfMemoryError}. If `clear` is true, the allocated region will
* be zero-filled.
*

@@ -134,5 +135,15 @@ * @remarks

* @param numBytes
* @param clear
*/
allocate(numBytes: number): number;
free(addr: number): void;
allocate(numBytes: number, clear?: boolean): number;
/**
* Frees a previous allocated memory region using the exported WASM core API
* function {@link WasmExports._wasm_free} (implementation specific). The
* `numBytes` value must be the same as previously given to
* {@link WasmBridge.allocate}.
*
* @param addr
* @param numBytes
*/
free(addr: number, numBytes: number): void;
getI8(addr: number): number;

@@ -178,3 +189,26 @@ getU8(addr: number): number;

setF64Array(addr: number, buf: NumericArray): this;
/**
* Reads UTF-8 encoded string from given address and optional byte length.
* The default length is 0, which will be interpreted as a zero-terminated
* string. Returns string.
*
* @param addr
* @param len
*/
getString(addr: number, len?: number): string;
/**
* Encodes given string as UTF-8 and writes it to WASM memory starting at
* `addr`. By default the string will be zero-terminated and only `maxBytes`
* will be written. Returns the number of bytes written.
*
* @remarks
* An error will be thrown if the encoded string doesn't fully fit into the
* designated memory region (also note that there might need to be space for
* the additional sentinel/termination byte).
*
* @param str
* @param addr
* @param maxBytes
* @param terminate
*/
setString(str: string, addr: number, maxBytes: number, terminate?: boolean): number;

@@ -181,0 +215,0 @@ getElementById(addr: number, len?: number): HTMLElement;

@@ -31,3 +31,3 @@ import { defError } from "@thi.ng/errors/deferror";

const logA = (method) => (addr, len) => this.logger.debug(method(addr, len).join(", "));
this.core = {
this.api = {
printI8: logN,

@@ -140,3 +140,3 @@ printU8: logN,

* // imports defined by the core API of the bridge itself
* core: { ... },
* wasmapi: { ... },
* // imports defined by the CustomAPI module

@@ -156,3 +156,3 @@ * custom: { ... }

if (!this.imports) {
this.imports = { core: this.core };
this.imports = { wasmapi: this.api };
for (let id in this.modules) {

@@ -182,3 +182,4 @@ if (this.imports[id] !== undefined) {

* start address of the new memory block. If unsuccessful, throws an
* {@link OutOfMemoryError}.
* {@link OutOfMemoryError}. If `clear` is true, the allocated region will
* be zero-filled.
*

@@ -189,4 +190,5 @@ * @remarks

* @param numBytes
* @param clear
*/
allocate(numBytes) {
allocate(numBytes, clear = false) {
const addr = this.exports._wasm_allocate(numBytes);

@@ -197,7 +199,17 @@ if (!addr)

this.ensureMemory();
clear && this.u8.fill(0, addr, addr + numBytes);
return addr;
}
free(addr) {
this.logger.debug(`freeing memory @ 0x${U32(addr)}`);
this.exports._wasm_free(addr);
/**
* Frees a previous allocated memory region using the exported WASM core API
* function {@link WasmExports._wasm_free} (implementation specific). The
* `numBytes` value must be the same as previously given to
* {@link WasmBridge.allocate}.
*
* @param addr
* @param numBytes
*/
free(addr, numBytes) {
this.logger.debug(`freeing memory @ 0x${U32(addr)} .. 0x${U32(addr + numBytes - 1)}`);
this.exports._wasm_free(addr, numBytes);
}

@@ -352,5 +364,29 @@ getI8(addr) {

}
/**
* Reads UTF-8 encoded string from given address and optional byte length.
* The default length is 0, which will be interpreted as a zero-terminated
* string. Returns string.
*
* @param addr
* @param len
*/
getString(addr, len = 0) {
this.ensureMemory();
return this.utf8Decoder.decode(this.u8.subarray(addr, len > 0 ? addr + len : this.u8.indexOf(0, addr)));
}
/**
* Encodes given string as UTF-8 and writes it to WASM memory starting at
* `addr`. By default the string will be zero-terminated and only `maxBytes`
* will be written. Returns the number of bytes written.
*
* @remarks
* An error will be thrown if the encoded string doesn't fully fit into the
* designated memory region (also note that there might need to be space for
* the additional sentinel/termination byte).
*
* @param str
* @param addr
* @param maxBytes
* @param terminate
*/
setString(str, addr, maxBytes, terminate = true) {

@@ -357,0 +393,0 @@ maxBytes = Math.min(maxBytes, this.u8.length - addr);

# Change Log
- **Last updated**: 2022-08-08T22:36:17Z
- **Last updated**: 2022-08-15T15:40:55Z
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)

@@ -12,2 +12,36 @@

## [0.6.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.6.0) (2022-08-15)
#### 🚀 Features
- add C11 header/include file, update WasmBridge ([a67dc00](https://github.com/thi-ng/umbrella/commit/a67dc00))
- migrate headers/includes to /include
- rename "core" import section => "wasmapi"
- rename WasmBridge.core => WasmBridge.api
- update pkg file
- update codegens, add opts, fix alignments ([5c1fec5](https://github.com/thi-ng/umbrella/commit/5c1fec5))
- add global CodeGenOpts
- update generateTypes() to consider new opts
- add global USIZE type (for pointer sizes & codegens)
- add options for Zig codegen (extra debug helpers)
- simplify TS codegen
- fix sizeOf() for struct fields
- make prepareType() idempotent
- add bindings code generator framework ([17ee06f](https://github.com/thi-ng/umbrella/commit/17ee06f))
- add/update deps
- add preliminary codegens for Zig & TS
- add supporting types & utils
- add generateTypes() codegen facade fn
- update allocate/free() fns, update Zig core API ([8a55989](https://github.com/thi-ng/umbrella/commit/8a55989))
- add _wasm_free() Zig impl
- add printFmt() Zig fn
- update WasmBridge.allocate() (add clear option)
- update WasmBridge.free()
- ensure memory in WasmBridge.getString()
- add/update docstrings
#### ♻️ Refactoring
- extract WasmMemViews interface, update test WASM ([4c73e65](https://github.com/thi-ng/umbrella/commit/4c73e65))
## [0.5.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.5.0) (2022-08-08)

@@ -14,0 +48,0 @@

export * from "./api.js";
export * from "./bridge.js";
export * from "./codegen.js";
export * from "./object-index.js";
export * from "./codegen/typescript.js";
export * from "./codegen/zig.js";
export * from "./codegen/utils.js";
//# sourceMappingURL=index.d.ts.map
export * from "./api.js";
export * from "./bridge.js";
export * from "./codegen.js";
export * from "./object-index.js";
export * from "./codegen/typescript.js";
export * from "./codegen/zig.js";
export * from "./codegen/utils.js";

34

package.json
{
"name": "@thi.ng/wasm-api",
"version": "0.5.0",
"description": "Modular, extensible API bridge and generic glue code between JS & WebAssembly",
"version": "0.6.0",
"description": "Generic, modular, extensible API bridge, glue code and bindings code generator for hybrid JS & WebAssembly projects",
"type": "module",

@@ -35,9 +35,13 @@ "module": "./index.js",

"test": "testament test",
"test:build-zig": "zig build-lib -O ReleaseSmall -target wasm32-freestanding -dynamic --strip --pkg-begin wasmapi zig/core.zig --pkg-end test/custom.zig && wasm-dis -o custom.wast custom.wasm && cp custom.wasm test"
"test:build-zig": "zig build-lib -O ReleaseSmall -target wasm32-freestanding -dynamic --strip --pkg-begin wasmapi include/wasmapi.zig --pkg-end test/custom.zig && wasm-dis -o custom.wast custom.wasm && cp custom.wasm test"
},
"dependencies": {
"@thi.ng/api": "^8.3.9",
"@thi.ng/api": "^8.4.0",
"@thi.ng/binary": "^3.3.3",
"@thi.ng/checks": "^3.2.4",
"@thi.ng/compare": "^2.1.10",
"@thi.ng/defmulti": "^2.1.12",
"@thi.ng/errors": "^2.1.10",
"@thi.ng/hex": "^2.1.9",
"@thi.ng/idgen": "^2.1.10",
"@thi.ng/idgen": "^2.1.11",
"@thi.ng/logger": "^1.2.0"

@@ -55,2 +59,5 @@ },

"api",
"bindings",
"c",
"codegen",
"id",

@@ -78,3 +85,4 @@ "logger",

"*.d.ts",
"*.zig"
"codegen",
"include"
],

@@ -91,2 +99,14 @@ "exports": {

},
"./codegen": {
"default": "./codegen.js"
},
"./codegen/typescript": {
"default": "./codegen/typescript.js"
},
"./codegen/utils": {
"default": "./codegen/utils.js"
},
"./codegen/zig": {
"default": "./codegen/zig.js"
},
"./object-index": {

@@ -100,3 +120,3 @@ "default": "./object-index.js"

},
"gitHead": "e579cb171fc720cbf0b71d3a5f4adfacccdaf214\n"
"gitHead": "295e76c6f68ef34ba2117ff77612848e09f5c587\n"
}

@@ -15,2 +15,6 @@ <!-- This file is generated - DO NOT EDIT! -->

- [Object indices & handles](#object-indices--handles)
- [Data bindings & code generators](#data-bindings--code-generators)
- [Data type definitions](#data-type-definitions)
- [Code generation](#code-generation)
- [Example usage](#example-usage)
- [Status](#status)

@@ -20,2 +24,5 @@ - [Installation](#installation)

- [API](#api)
- [Basic usage example](#basic-usage-example)
- [Zig version](#zig-version)
- [C11 version](#c11-version)
- [Authors](#authors)

@@ -26,17 +33,28 @@ - [License](#license)

Modular, extensible API bridge and generic glue code between JS & WebAssembly.
Generic, modular, extensible API bridge, glue code and bindings code generator for hybrid JS & WebAssembly projects.
This package provides a small, generic and modular
This package provides a the following:
1. A small, generic and modular
[`WasmBridge`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html)
class as interop basis and a much reduced boilerplate for hybrid JS/WebAssembly
applications. At the moment only a minimal core API is provided (i.e. for debug
output, string, pointer, typed array accessors [8/16/32/64 bit (u)ints, 32/64
bit floats]), but in the future we aim to also supply support modules for DOM
manipulation, WebGL, WebGPU, WebAudio etc.
class as interop basis and much reduced boilerplate for hybrid JS/WebAssembly
applications.
2. A minimal core API for debug output, string, pointer, typed array accessors
(8/16/32/64 bit (u)ints, 32/64 bit floats). In the future we aim to also supply
support modules for DOM manipulation, WebGL, WebGPU, WebAudio etc.
3. Extensible shared datatype code generators for (currently)
[Zig](https://ziglang.org) & TypeScript. The latter also generates fully type
checked memory-mapped accessors of WASM-side data. In general, all languages
with a WebAssembly target are supported, however currently only bindings for
these few langs are included.
4. Include files for C11 and Zig, defining imports for the JS core API defined
by this package
In general, all languages with a WebAssembly target are supported, however
currently only bindings for [Zig](https://ziglang.org) are included.
### Custom API modules
The WasmBridge is extensible via custom defined API modules. Such API extensions
will consist of a collection of JS/TS functions & variables, their related
counterparts (import definitions) for the WASM target and (optionally) some
shared data types (bindings for which _can_ be generated by this package too).
On the JS side, custom API modules can be easily integrated via the [`IWasmAPI`

@@ -119,8 +137,8 @@ interface](https://docs.thi.ng/umbrella/wasm-api/interfaces/IWasmAPI.html). The

host, any JS native objects the WASM side might want to be working with must be
managed in JS. For this purpose the [`ObjectIndex`
managed manually in JS. For this purpose the [`ObjectIndex`
class](https://docs.thi.ng/umbrella/wasm-api/classes/ObjectIndex.html) can be
used by API modules to handle ID generation (incl. recycling, using
[@thi.ng/idgen](https://github.com/thi-ng/umbrella/tree/develop/packages/idgen))
& indexing of different types of JS objects/values. Only the numeric IDs will
then need to be exchanged with the WASM module...
and the indexing of different types of JS objects/values. Only the numeric IDs
(handles) will then need to be exchanged with the WASM module...

@@ -163,2 +181,25 @@ ```ts

### Data bindings & code generators
The package provides an extensible codegeneration framework to simplify the
bilateral design & exchange of data structures shared between the WASM & JS host
env. Currently, code generators for TypeScript & Zig are supplied (more are
planned). A CLI wrapper is worked on too.
#### Data type definitions
TODO
##### Struct
##### Enum
#### Code generation
TODO
#### Example usage
TODO
### Status

@@ -193,7 +234,15 @@

Package sizes (gzipped, pre-treeshake): ESM: 1.61 KB
Package sizes (gzipped, pre-treeshake): ESM: 3.98 KB
**IMPORTANT:** The package includes various code generators and supporting
functions which are NOT required during runtime. Hence the actual package size
in production will be MUCH smaller!
## Dependencies
- [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
- [@thi.ng/binary](https://github.com/thi-ng/umbrella/tree/develop/packages/binary)
- [@thi.ng/checks](https://github.com/thi-ng/umbrella/tree/develop/packages/checks)
- [@thi.ng/compare](https://github.com/thi-ng/umbrella/tree/develop/packages/compare)
- [@thi.ng/defmulti](https://github.com/thi-ng/umbrella/tree/develop/packages/defmulti)
- [@thi.ng/errors](https://github.com/thi-ng/umbrella/tree/develop/packages/errors)

@@ -208,2 +257,4 @@ - [@thi.ng/hex](https://github.com/thi-ng/umbrella/tree/develop/packages/hex)

## Basic usage example
```ts

@@ -233,2 +284,6 @@ import { WasmBridge, WasmExports } from "@thi.ng/wasm-api";

### Zig version
Requires [Zig](https://ziglang.org) to be installed:
```zig

@@ -240,3 +295,7 @@ //! Example Zig application (hello.zig)

const js = @import("wasmapi");
const std = @import("std");
// set custom memory allocator (here to disable)
pub const WASM_ALLOCATOR: ?std.mem.Allocator = null;
export fn start() void {

@@ -254,3 +313,3 @@ js.printStr("hello world!");

zig build-lib \
--pkg-begin wasmapi node_modules/@thi.ng/wasm-api/zig/core.zig --pkg-end \
--pkg-begin wasmapi node_modules/@thi.ng/wasm-api/include/wasmapi.zig --pkg-end \
-target wasm32-freestanding \

@@ -270,3 +329,4 @@ -O ReleaseSmall -dynamic --strip \

(type $none_=>_none (func))
(import "core" "_printStr" (func $fimport$0 (param i32 i32)))
(type $i32_=>_i32 (func (param i32) (result i32)))
(import "wasmapi" "_printStr" (func $fimport$0 (param i32 i32)))
(global $global$0 (mut i32) (i32.const 65536))

@@ -277,2 +337,4 @@ (memory $0 2)

(export "start" (func $0))
(export "_wasm_allocate" (func $1))
(export "_wasm_free" (func $2))
(func $0

@@ -284,5 +346,96 @@ (call $fimport$0

)
(func $1 (param $0 i32) (result i32)
(i32.const 0)
)
(func $2 (param $0 i32) (param $1 i32)
)
)
```
### C11 version
Requires [Emscripten](https://emscripten.org/) to be installed:
```c
#include <wasmapi.h>
void WASM_KEEP start() {
wasm_printStr0("hello world!");
}
```
Building the WASM module:
```bash
emcc -Os -Inode_modules/@thi.ng/wasm-api/include -DWASMAPI_NO_MALLOC \
-sERROR_ON_UNDEFINED_SYMBOLS=0 --no-entry \
-o hello.wasm hello.c
```
Resulting WASM:
```wasm
(module
(type $i32_=>_none (func (param i32)))
(type $none_=>_none (func))
(type $i32_=>_i32 (func (param i32) (result i32)))
(type $none_=>_i32 (func (result i32)))
(import "wasmapi" "_printStr0" (func $fimport$0 (param i32)))
(global $global$0 (mut i32) (i32.const 5243936))
(memory $0 256 256)
(data (i32.const 1024) "hello world!")
(table $0 2 2 funcref)
(elem (i32.const 1) $0)
(export "memory" (memory $0))
(export "_wasm_allocate" (func $1))
(export "_wasm_free" (func $2))
(export "start" (func $3))
(export "__indirect_function_table" (table $0))
(export "_initialize" (func $0))
(export "__errno_location" (func $7))
(export "stackSave" (func $4))
(export "stackRestore" (func $5))
(export "stackAlloc" (func $6))
(func $0
(nop)
)
(func $1 (param $0 i32) (result i32)
(i32.const 0)
)
(func $2 (param $0 i32)
(nop)
)
(func $3
(call $fimport$0
(i32.const 1024)
)
)
(func $4 (result i32)
(global.get $global$0)
)
(func $5 (param $0 i32)
(global.set $global$0
(local.get $0)
)
)
(func $6 (param $0 i32) (result i32)
(global.set $global$0
(local.tee $0
(i32.and
(i32.sub
(global.get $global$0)
(local.get $0)
)
(i32.const -16)
)
)
)
(local.get $0)
)
(func $7 (result i32)
(i32.const 1040)
)
)
```
## Authors

@@ -289,0 +442,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc