@openfluke/portal
v0.3.0
Published
Paragon Orchestrated Runtime for Isomorphic Technologies Across Layers — isomorphic Go/WASM loader for browser, Bun, and Node.
Maintainers
Readme
@openfluke/portal
Paragon Orchestrated Runtime for Isomorphic Technologies Across Layers
@openfluke/portal is an isomorphic loader for Go-compiled WebAssembly (Paragon). It works seamlessly in Bun/Node.js backends and browser frontends (Vite/React/Ionic), exposing the same API across layers. Portal bundles wasm_exec.js (from the Go runtime) and your compiled paragon.wasm, so you can import { initPortal } and immediately construct neural networks in either environment.
Installation
# Add to your project
bun add @openfluke/portal
# or
npm install @openfluke/portalUsage
Backend (Bun / Node.js)
Create a quick test script index.ts:
import { initPortal } from "@openfluke/portal";
const main = async () => {
console.log("⚙️ initPortal()…");
const portal = await initPortal();
const configs = [
{
name: "Alpha",
layers: [{ Width: 1, Height: 1 }, { Width: 2, Height: 1 }, { Width: 3, Height: 1 }],
activations: ["linear", "relu", "softmax"],
},
{
name: "Beta",
layers: [{ Width: 1, Height: 1 }, { Width: 4, Height: 1 }, { Width: 3, Height: 1 }],
activations: ["linear", "tanh", "softmax"],
},
{
name: "Gamma",
layers: [{ Width: 1, Height: 1 }, { Width: 3, Height: 1 }, { Width: 3, Height: 1 }],
activations: ["linear", "sigmoid", "softmax"],
},
];
for (const cfg of configs) {
const nn = portal.NewNetworkFloat32(
JSON.stringify(cfg.layers),
JSON.stringify(cfg.activations),
JSON.stringify([true, true, true])
);
nn.PerturbWeights(JSON.stringify([0.1, Date.now() % 1000]));
const input = JSON.stringify([[[Math.random()]]]);
nn.Forward(input);
console.log(cfg.name, "→", nn.ExtractOutput());
}
};
main();Run it:
bun run index.tsFrontend (React / Vite / Ionic)
Use the same API inside a React component. Example: run 3 networks with pulses of random data:
import React, { useEffect, useState } from "react";
import { initPortal } from "@openfluke/portal";
export default function PortalDemo() {
const [portal, setPortal] = useState<any>(null);
const [output, setOutput] = useState<string>("Loading…");
useEffect(() => {
(async () => {
const api = await initPortal();
setPortal(api);
const nn = api.NewNetworkFloat32(
JSON.stringify([{ Width: 1, Height: 1 }, { Width: 2, Height: 1 }, { Width: 3, Height: 1 }]),
JSON.stringify(["linear", "relu", "softmax"]),
JSON.stringify([true, true, true])
);
nn.PerturbWeights(JSON.stringify([0.1, Date.now() % 1000]));
nn.Forward(JSON.stringify([[[Math.random()]]]));
setOutput(nn.ExtractOutput());
})();
}, []);
return (
<div>
<h1>Portal Demo</h1>
<pre>{output}</pre>
</div>
);
}When you run bun dev with Vite/Ionic, the WASM is auto-loaded from the package’s dist folder. No manual <script> tags required.
Development (Local Linking)
If you are developing Portal itself:
bun i
bun run clean && bun run build
bun linkThen in another project:
bun add @openfluke/portal@link:portalIf running in frontend change vite.config.ts
/// <reference types="vitest" />
import legacy from '@vitejs/plugin-legacy'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
legacy()
],
optimizeDeps: {
exclude: ['@openfluke/portal'] // Prevents pre-bundling; allows relative asset imports (?raw/?url) and import.meta.url to resolve to actual dist/ files
},
assetsInclude: ['**/*.wasm'], // Treats .wasm as static assets (emits correctly in builds)
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/setupTests.ts',
}
})License
Apache-2.0 © 2025 OpenFluke
