npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@raisindb/function-wasm

v0.5.8

Published

Write a RaisinDB server function as a WebAssembly component in TypeScript/JavaScript

Readme

@raisindb/function-wasm

Write a RaisinDB server function as a WebAssembly component in TypeScript/JavaScript, built with jco / ComponentizeJS.

The design goal is that a QuickJS function componentizes with zero source changes. This SDK therefore re-implements nothing: src/generated/api_wrapper.js is a byte-identical copy of the QuickJS runtime's own wrapper (regenerated by make gen-bindings, guarded by a freshness test), so the frozen per-method error conventions — throw vs null vs [] vs sentinel — are literally the same code running in both runtimes. All this SDK adds is the three globals that wrapper reaches for, mapped onto the WIT host.

npm i -D @raisindb/function-wasm @bytecodealliance/jco @bytecodealliance/componentize-js

Write a handler

// src/index.js
export async function handler(input) {
  const people = raisin.nodes.getChildren('content', '/people');
  console.log('greeting', input.name);
  return { greeting: `Hello, ${input.name}!`, people: people.length };
}

One module can carry many handlers, and one built artifact can back many raisin:Function nodes:

export async function handler(input) { /* entry_file: main.wasm */ }
export async function onOrder(input) { /* entry_file: main.wasm:on-order */ }

Build

npx raisin-wasm-build src/index.js --out main.wasm

which wraps:

jco componentize <generated entry> --wit <sdk>/wit -n function --bundle --disable http fetch-event -o main.wasm

Your module is never componentized directly. The WIT world exports exactly one function — handler: func(name: string, input: string) -> result<string, string> — so the build writes a small entry that imports your module, wraps it with createHandler, and imports @raisindb/function-wasm/host-wit (the only module that imports the unresolvable-in-Node specifier raisin:function/host).

name is the handler chosen by the Function node's entry_file suffix: main.wasm -> "default" -> your handler export; main.wasm:on-order -> "on-order" -> your onOrder (or 'on-order') export. An unknown name answers Err listing what the component registered — the host never validates the name, because the guest owns its handler namespace.

Expect an 8-12 MB artifact: a component embeds the whole StarlingMonkey JS engine. The server's default cap is 32 MiB, and one artifact can back N functions (entry_file: ../shared/main.wasm:on-order), which is how a package with twenty handlers still ships ten megabytes.

Test — natively, no wasm

import { expect, it } from 'vitest';
import { createMockHost } from '@raisindb/function-wasm/testing';
import { createHandler } from '@raisindb/function-wasm';
import * as fn from '../src/index.js';

it('greets', async () => {
  const mock = createMockHost({ context: { tenant_id: 't1' } });
  mock.expect('nodes_getChildren', () => [{ path: '/people/ada' }]);
  mock.install();

  const out = await createHandler(fn)('default', JSON.stringify({ name: 'Ada' }));

  expect(JSON.parse(out).greeting).toBe('Hello, Ada!');
  expect(mock.logs[0].message).toBe('greeting Ada');
});

vitest run in this package exercises the SDK the same way.

What is NOT available

The runtime is StarlingMonkey with http and fetch-event disabled, driven by a synchronous host — not Node, and not the QuickJS runtime's full environment.

| Missing | Use instead | |---|---| | fetch, Request, Response, Headers | raisin.http.request(...) — the only egress the host polices | | setTimeout / setInterval / any timer-based wait | nothing: there is no scheduler after the export returns | | Resource.resize / toImage / getPageCount, and getBinary on a processed resource | raisin.assets.*, or keep that function in JavaScript. These need the server's per-execution temp files; calling one throws by name rather than undefined is not a function | | require, node:* builtins, the filesystem | there are zero preopens; the component links no wasi:sockets and no wasi:http | | dynamic import() of a module not present at build time | everything is snapshotted at componentize time | | host imports that are asynchronous | every WIT host import is synchronous (Component Model async is not enabled) |

async/await in your handler does work: ComponentizeJS runs the event loop to resolution around the export call. What does not work is code that waits on something no one will ever resolve — a timer, a socket, an unresolved promise: the component simply returns.

console.* is forwarded to the host log (ExecutionResult.logs and the SSE log stream). Date.now() and Math.random() work (clocks and random stay enabled).

Layout

| path | what | |---|---| | src/index.js | public entry — createHandler, installShim, setHost | | src/entry.js | the name router behind the single WIT export | | src/shim.js | __raisin_call, __raisin_internal, console, raisin.context | | src/host.js | the host holder — what makes native tests possible | | src/host-wit.js | the only module importing raisin:function/host | | src/testing.js | the mock host | | src/generated/* | generated — make gen-bindings, never hand-edited | | wit/raisin-function.wit | generated copy of the contract | | bin/raisin-wasm-build.js | the jco wrapper |

--bundle is not optional here: it makes the toolchain resolve the SDK through Node's own algorithm (symlinked / file: installs included) instead of the guest's flat virtual filesystem.

Verified against jco 1.32.1 / componentize-js 0.22.0, by building examples/wasm-functions/wasm/demo/greet-ts (12.09 MiB, jco wit shows import raisin:function/[email protected] + export handler and no wasi:sockets / wasi:http):

  • the CLI flags above;
  • the error convention — an export returning result<_, string> returns the ok string and throws for the err arm, where the payload is e.payload if present, else e.message;
  • the host import specifier carries the WIT package version ('raisin:function/[email protected]'); without it componentization fails at Wizer time with Error loading module.