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

fsa1-wasm

v0.3.3

Published

FSA1 in the browser: unpack an .xlsx to an in-memory file tree, render it, check it, evaluate formulas against it, and pack it back -- with no backend and no filesystem.

Readme

fsa1-wasm

FSA1 in the browser. Unpack an .xlsx into an in-memory file tree — tabs are folders, cells are files — then render, check, evaluate and pack it back. No backend, no filesystem.

fsa1.sh — what it is, and why, with worked examples.

import init, { xlsx_to_html } from "fsa1-wasm";

await init();                                     // fetches the .wasm beside this module
const html = xlsx_to_html(new Uint8Array(bytes)); // xlsx -> tree -> a standalone document

Under a bundler that hands you the asset URL, pass it as an object — a bare argument is the deprecated form and warns:

import wasmUrl from "fsa1-wasm/fsa1_wasm_bg.wasm?url";
await init({ module_or_path: wasmUrl });

The payload is ~3.5 MB (~1.4 MB over the wire), so most hosts want it lazily.

A refusal crosses as a thrown Error whose name is a RefusalKind — the vocabulary fsa1-cli maps to exit codes — carrying the located findings as its message. The union is exported, so a switch over it is checkable.

A Session holds wasm memory. Call free() when you are done with it — from a component's unmount hook, not on every render.

API

/**
 * What `Session.render_fragment` hands back: the grid, for a page a host supplies itself.
 *
 * `markup` CARRIES `<style>` and `<script>` elements of its own -- a sidecar's layer rides in one,
 * a figure's Vega runtime and mount script in others -- so mount it with
 * `document.createRange().createContextualFragment(markup)`. `innerHTML` inserts those scripts
 * inert, and no figure ever draws.
 */
export interface RenderedFragment {
    /** The cascade, for a `<style>` in `<head>`: the `@layer` order THIS view computes. */
    styles: string;
    /** The body to mount, `<style>`, `<script>` and all. */
    markup: string;
    /** The formula bar's only listener, for a `<script>` after the markup. Without it the bar
     *  renders spans that never fill. */
    script: string;
    /** Advisories about the answer: an empty tab, or a figure whose spec would not expand. */
    notes: string[];
}



/** Every `name` an `Error` thrown by this module carries. */
export type RefusalKind = "invalid-arguments" | "validation" | "conflict" | "not-found" | "io";



export class Session {
    private constructor();
    free(): void;
    [Symbol.dispose](): void;
    check(target: string): string[];
    check_table(target: string): string;
    eval(target: string, formula: string): any;
    pack_xlsx(): Uint8Array;
    render_ascii(target: string): string;
    /**
     * The four keys `RenderedFragment` spells in `fsa1_wasm.d.ts`.
     */
    render_fragment(target: string): any;
    render_html(target: string): string;
    tabs(): string[];
    tree(): any;
    tree_ascii(target: string, full: boolean): string;
    warnings(): string[];
}

export function load_tree(entries: any): Session;

export function unpack_xlsx(bytes: Uint8Array, strict: boolean, decomposition?: string | null): Session;

export function xlsx_to_html(bytes: Uint8Array, target?: string | null): string;

export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;

export interface InitOutput {
    readonly memory: WebAssembly.Memory;
    readonly __wbg_session_free: (a: number, b: number) => void;
    readonly load_tree: (a: any) => [number, number, number];
    readonly session_check: (a: number, b: number, c: number) => [number, number, number, number];
    readonly session_check_table: (a: number, b: number, c: number) => [number, number, number, number];
    readonly session_eval: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
    readonly session_pack_xlsx: (a: number) => [number, number, number, number];
    readonly session_render_ascii: (a: number, b: number, c: number) => [number, number, number, number];
    readonly session_render_fragment: (a: number, b: number, c: number) => [number, number, number];
    readonly session_render_html: (a: number, b: number, c: number) => [number, number, number, number];
    readonly session_tabs: (a: number) => [number, number];
    readonly session_tree: (a: number) => [number, number, number];
    readonly session_tree_ascii: (a: number, b: number, c: number, d: number) => [number, number, number, number];
    readonly session_warnings: (a: number) => [number, number];
    readonly unpack_xlsx: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
    readonly xlsx_to_html: (a: number, b: number, c: number, d: number) => [number, number, number, number];
    readonly __wbindgen_malloc: (a: number, b: number) => number;
    readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
    readonly __wbindgen_exn_store: (a: number) => void;
    readonly __externref_table_alloc: () => number;
    readonly __wbindgen_externrefs: WebAssembly.Table;
    readonly __externref_table_dealloc: (a: number) => void;
    readonly __externref_drop_slice: (a: number, b: number) => void;
    readonly __wbindgen_free: (a: number, b: number, c: number) => void;
    readonly __wbindgen_start: () => void;
}

export type SyncInitInput = BufferSource | WebAssembly.Module;

/**
 * Instantiates the given `module`, which can either be bytes or
 * a precompiled `WebAssembly.Module`.
 *
 * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
 *
 * @returns {InitOutput}
 */
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;

/**
 * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
 * for everything else, calls `WebAssembly.instantiate` directly.
 *
 * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
 *
 * @returns {Promise<InitOutput>}
 */
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;

MIT. Built from https://github.com/fredrikolis/FSA1