FERS vanuit JavaScript gebruiken

De FERS-solver is gepubliceerd als WebAssembly-build van dezelfde Rust-rekenkern die de webapplicatie aandrijft. Hij draait in de browser of in Node, rekent zonder serverronde en vraagt in het gratis abonnement geen API-sleutel.

Installatie

Uit dezelfde rekenkern worden twee pakketten met een identieke API gepubliceerd — alleen de installatie en de bundlerinstelling verschillen. Neem -web voor alles wat door een bundler gaat en het pakket zonder achtervoegsel voor Node aan de serverzijde.

# Browser apps (Vite, Next.js, webpack):
npm install @ferscloud/fers-calculation-web

# Node.js / server-side:
npm install @ferscloud/fers-calculation

Beide pakketten dragen de versie van de rekenkern en gaan samen mee. Zet ze vast op dezelfde exacte versie in plaats van op een caret-bereik.

De bundler instellen

@ferscloud/fers-calculation-web is een WASM-ES-module die zich initialiseert via een top-level await. De meeste bundlers hebben daarvoor een eenmalige instelling nodig; het Node-pakket niet.

Vite

Voeg de plug-in toe en stel daarna een build-target in dat top-level await ondersteunt.

npm i -D vite-plugin-wasm

Vite-configuratie

// vite.config.ts
import wasm from "vite-plugin-wasm";

// The package initialises with a top-level await, so the build target
// has to be one that supports it. esnext needs no second plugin.
export default {
  plugins: [wasm()],
  build: { target: "esnext" },
};

Next.js en webpack

Transpileer het pakket en zet asynchrone WebAssembly aan. asyncFunction is nodig omdat de module zich met een top-level await initialiseert.

// next.config.js
module.exports = {
  transpilePackages: ["@ferscloud/fers-calculation-web"],
  webpack(config) {
    config.experiments = { ...config.experiments, asyncWebAssembly: true };
    config.output.environment = {
      ...config.output.environment,
      asyncFunction: true,
    };
    return config;
  },
};

De solver is synchroon en rekenintensief. Draai hem bij grote modellen in een Web Worker zodat de UI-thread responsief blijft.

Een model rekenen

Geen init()-aanroep en geen API-sleutel. Het gratis abonnement dekt elk model tot 100 staven.

import { calculate_from_json } from "@ferscloud/fers-calculation";

// No init() call needed — the nodejs and bundler builds initialise the
// WASM module automatically on import.
const res = JSON.parse(calculate_from_json(JSON.stringify(myModel)));

if (res.ok) {
  const data = res.result; // displacements, member_results, unity_checks, …
} else {
  console.error(res.error.code, res.error.message);
}

De resultaat-envelope

Elke solveraanroep geeft een JSON-envelope terug, zodat u één keer parseert en op ok vertakt — u hoeft nooit te raden of de teruggegeven tekenreeks op een fout lijkt. De teruggegeven waarde is altijd geldig JSON.

// success
{ "ok": true,  "result": { /* the full result document */ } }

// failure (invalid model, over the member limit, malformed JSON, …)
{ "ok": false, "error": { "code": "LimitExceeded",
                          "message": "Number of members (250) exceeds allowed maximum of 100" } }
error.codeBetekenis
InvalidJsonDe modeltekenreeks was geen parseerbaar JSON.
LimitExceededMeer staven dan het actieve abonnement toestaat (100 gratis, 10,000 Pro).
SolveErrorHet model is gelezen maar kon niet worden opgelost — meestal een singuliere stijfheidsmatrix door een ontbrekende of te losse oplegging.
InternalPanicEen fout in de rekenkern. Graag melden.
InternalSerializationDe resultaten konden niet worden geserialiseerd. Ook een fout die het melden waard is.

TypeScript-types

Het browserpakket levert gegenereerde modeltypes naast de functiehandtekeningen mee. Ze worden uit het OpenAPI-schema van de rekenkern gegenereerd en volgen dus de gepubliceerde versie in plaats van met de hand te worden bijgehouden.

import type {
  FERS,
  ResultsBundle,
} from "@ferscloud/fers-calculation-web/fers-models";

// FERS         — the input model
// ResultsBundle — the `result` payload of a successful envelope
// Both are generated from the engine's OpenAPI schema, so they track
// the published version.

FERS vermelden in het gratis abonnement

Resultaten uit het gratis abonnement dragen een attribution-object dat binnen de solver wordt aangemaakt. Pro-resultaten, gerekend met een geldig token, dragen het niet — dezelfde code toont dus een vermelding op gratis en levert onder Pro white-label-uitvoer, zonder dat u iets hoeft in te stellen.

Daarnaast worden getFersAttribution, fersAttributionText en createFersBadge geëxporteerd. Ze accepteren allemaal de envelope, het geparseerde model of de resultatenbundel, en geven allemaal niets terug bij een Pro-resultaat of een foutenvelope.

import { fersAttributionHtml } from "@ferscloud/fers-calculation-web/badge.js";

// Free-tier results carry result.attribution; this renders the credit.
// With a Pro solve token the field is absent and this returns "" — the
// same code white-labels, with no flag to set.
const credit = fersAttributionHtml(res);

Gebruikt u het gratis abonnement in een applicatie, toon dan de vermelding. Het is het enige dat het gratis abonnement van u vraagt. Beschikbaar vanaf engine 0.2.61.

Pro-grenzen met een rekentoken

De Pro-grenzen worden vrijgegeven met een kortlevend ondertekend token dat de FERS Cloud-server uitgeeft. Het token wordt binnen de WebAssembly-module geverifieerd tegen een in het binaire bestand ingebakken Ed25519-publieke sleutel en is daardoor niet te vervalsen.

Uw server houdt de API-sleutel en wisselt die in voor een token van 30 minuten; de browser ziet alleen het token. Houd FERS_API_KEY serverzijdig — nooit in browsercode.

// pages/api/solve-token.ts
const FERS_API_KEY = process.env.FERS_API_KEY!;

let cached: { token: string; expiresAt: number } | null = null;

export default async function handler(req, res) {
  const now = Date.now();

  // Re-use if more than 5 minutes remain
  if (cached && cached.expiresAt - now > 5 * 60 * 1000) {
    return res.json({ token: cached.token });
  }

  const resp = await fetch("https://ferscloud.com/api/solver/token", {
    method: "POST",
    headers: { "X-API-Key": FERS_API_KEY },
  });

  if (!resp.ok) return res.status(502).json({ error: "Token fetch failed" });

  const { token, expiresAt } = await resp.json();
  cached = { token, expiresAt: new Date(expiresAt).getTime() };
  return res.json({ token });
}

De solver met een token aanroepen

Ontbreekt het token of is het verlopen of ongeldig, dan valt de solver terug op de gratis staafgrens — hij werpt nooit een uitzondering. Een echte rekenfout komt nog steeds terug als { ok: false, error } en niet als exception.

import { calculate_from_json_with_token } from "@ferscloud/fers-calculation";

const { token } = await fetch("/api/solve-token").then((r) => r.json());

const res = JSON.parse(
  calculate_from_json_with_token(JSON.stringify(myModel), token),
);
if (!res.ok) throw new Error(`${res.error.code}: ${res.error.message}`);
const data = res.result;
GratisPro
Maximaal aantal staven10010,000
Functiecalculate_from_jsoncalculate_from_json_with_token
Token vereistNeeJa
Geldigheid van het token30 minuten

Doorbuigingslijn

Zet include_member_deflected_shape in de analyse-opties van het model om per staaf een direct tekenbare, belastingexacte doorbuigingslijn te krijgen — de globale vervorming van de staaf bemonsterd over zijn lengte — in plaats van de kromme zelf te reconstrueren.

Hij staat standaard uit om het antwoord licht te houden en ontbreekt in member_results wanneer hij niet is aangevraagd.

const model = {
  /* … model + load cases … */
  analysis: {
    /* … */
    options: {
      /* … */
      include_member_deflected_shape: true,
    },
  },
};

const res = JSON.parse(calculate_from_json(JSON.stringify(model)));
const mr = res.result.results.loadcases["…"].member_results["1"];

// mr.member_displacements: [{ x_frac, displacement: [dx, dy, dz] }, …]
//   x_frac 0–1 along the member; displacement in the global input frame.

Andere ingangen

Gerelateerde pagina’s

Zie ook

Veelgestelde vragen

Heb ik een API-sleutel nodig om in de browser te rekenen?

Nee. calculate_from_json werkt zonder sleutel en zonder account voor modellen tot 100 staven. Een sleutel is alleen nodig om het Pro-rekentoken uit te geven.

Verlaat het model de browser?

Nee. De solver is naar WebAssembly gecompileerd en draait op de client, dus model en resultaten blijven op de machine van de gebruiker. Er gaat niets naar FERS Cloud.

Waarom heeft Vite extra configuratie nodig?

Het browserpakket is een WASM-ES-module die zich met een top-level await initialiseert. vite-plugin-wasm verzorgt de WebAssembly-import en build.target: "esnext" houdt die await in de uitvoer — dat vereist Chrome, Edge of Firefox 89+, of Safari 15+. webpack heeft asyncWebAssembly en asyncFunction nodig in de experiments- en output-instellingen. Staat vite-plugin-top-level-await nog in je configuratie uit een eerdere versie van deze pagina, dan kun je het verwijderen: met recente @swc/core-versies laat het vite build mislukken.

Moet ik de solver in een Web Worker draaien?

Vanaf meer dan een handvol staven wel. De solver is synchroon en rekenintensief, dus hem op de UI-thread aanroepen blokkeert het renderen voor de duur van de berekening.

Heb ik een init()-aanroep nodig?

Nee. Zowel de Node- als de bundler-build initialiseert de WebAssembly-module automatisch bij het importeren. Oudere documentatie toonde await init(); dat is niet meer nodig.

Wat gebeurt er als het rekentoken is verlopen?

De solver valt stilzwijgend terug op de gratis grenzen. Hij werpt nooit een uitzondering bij een ongeldig token, dus een model binnen de gratis staafgrens blijft rekenen en een groter model geeft LimitExceeded.

Welk pakket gebruik ik op de server?

@ferscloud/fers-calculation, gebouwd voor het Node-target. Het vraagt geen bundlerinstelling en initialiseert zichzelf bij het importeren.

Zijn de resultaten dezelfde als in de webapplicatie?

Ja — het is dezelfde Rust-rekenkern, gecompileerd voor een ander target. De webapplicatie zelf draait op deze WebAssembly-build.