Folosirea FERS din JavaScript
Solverul FERS este publicat ca o compilare WebAssembly a aceluiași motor Rust care alimentează aplicația web. Rulează în browser sau în Node, calculează fără drum dus-întors la server și nu are nevoie de cheie API în planul gratuit.
Instalare
Din același motor se publică două pachete cu API identic — diferă doar instalarea și configurarea bundlerului. Alegeți -web pentru tot ce trece printr-un bundler și pachetul fără sufix pentru Node pe server.
# Browser apps (Vite, Next.js, webpack):
npm install @ferscloud/fers-calculation-web
# Node.js / server-side:
npm install @ferscloud/fers-calculationAmbele pachete poartă versiunea motorului și avansează împreună. Fixați-le la aceeași versiune exactă, nu la un interval cu accent circumflex.
Configurarea bundlerului
@ferscloud/fers-calculation-web este un modul ES WASM care se inițializează printr-un await de nivel superior. Majoritatea bundlerelor au nevoie de o singură modificare de configurare; pachetul Node nu are nevoie de niciuna.
Vite
Adăugați pluginul, apoi setați un target de build care acceptă await de nivel superior.
npm i -D vite-plugin-wasmConfigurația Vite
// 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 și webpack
Transpilați pachetul și activați WebAssembly asincron. asyncFunction este necesar pentru că modulul se inițializează cu un await de nivel superior.
// 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;
},
};Solverul este sincron și consumă procesor. Pentru modele mari, rulați-l într-un Web Worker, ca firul de interfață să rămână receptiv.
Calculul unui model
Fără apel init() și fără cheie API. Planul gratuit acoperă orice model de până la 100 bare.
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);
}Plicul de răspuns
Fiecare apel al solverului returnează un plic JSON, deci analizați o singură dată și ramificați după ok — nu trebuie niciodată să ghiciți dacă șirul returnat arată ca o eroare. Valoarea returnată este întotdeauna JSON valid.
// 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.code | Semnificație |
|---|---|
InvalidJson | Șirul modelului nu era JSON analizabil. |
LimitExceeded | Mai multe bare decât permite planul activ (100 gratuit, 10,000 Pro). |
SolveError | Modelul a fost citit, dar nu a putut fi rezolvat — cel mai adesea o matrice de rigiditate singulară din cauza unui reazem lipsă sau insuficient. |
InternalPanic | O eroare a motorului. Vă rugăm să o raportați. |
InternalSerialization | Rezultatele nu au putut fi serializate. Tot o eroare care merită raportată. |
Tipuri TypeScript
Pachetul pentru browser livrează tipuri de model generate alături de semnăturile funcțiilor. Sunt generate din schema OpenAPI a motorului, deci urmăresc versiunea publicată în loc să fie întreținute manual.
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.Creditarea FERS în planul gratuit
Rezultatele din planul gratuit poartă un obiect attribution creat în interiorul solverului. Rezultatele Pro, calculate cu un token valid, nu îl poartă — același cod afișează deci un credit în planul gratuit și rămâne fără marcă în Pro, fără nicio opțiune de activat.
Alături de el sunt exportate getFersAttribution, fersAttributionText și createFersBadge. Toate acceptă plicul, modelul analizat sau pachetul de rezultate și toate nu returnează nimic pentru un rezultat Pro sau un plic de eroare.
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);Dacă distribuiți planul gratuit într-o aplicație, vă rugăm să afișați creditul. Este singurul lucru pe care planul gratuit vi-l cere. Disponibil începând cu motorul 0.2.61.
Limitele Pro cu un token de calcul
Limitele Pro se deblochează transmițând un token semnat, de scurtă durată, emis de serverul FERS Cloud. Tokenul este verificat în interiorul modulului WebAssembly față de o cheie publică Ed25519 înglobată în binar, deci nu poate fi falsificat.
Serverul dumneavoastră deține cheia API și o schimbă pentru un token de 30 de minute; browserul vede doar tokenul. Păstrați FERS_API_KEY pe server — niciodată în cod de browser.
// 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 });
}Apelarea solverului cu un token
Dacă tokenul lipsește, a expirat sau este invalid, solverul revine la limita gratuită de bare — nu aruncă niciodată o excepție. O eroare reală de calcul vine tot ca { ok: false, error }, nu ca excepție.
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;| Gratuit | Pro | |
|---|---|---|
| Număr maxim de bare | 100 | 10,000 |
| Funcție | calculate_from_json | calculate_from_json_with_token |
| Necesită token | Nu | Da |
| Valabilitatea tokenului | — | 30 de minute |
Deformata
Activați include_member_deflected_shape în opțiunile de analiză ale modelului pentru a obține, pentru fiecare bară, o deformată gata de desenat și exactă în raport cu încărcarea — deplasarea globală a barei eșantionată pe lungimea ei — în loc să reconstruiți curba singur.
Este dezactivată implicit, ca răspunsul să rămână ușor, și lipsește din member_results când nu este cerută.
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.Alte căi de acces
- De ce să calculați structuri în JavaScript — argumentele pentru un solver pe partea de client.
- API REST — apelarea solverului prin HTTP din orice limbaj.
- Server MCP — lăsați Claude, ChatGPT, Cursor sau VS Code să conducă FERS direct.
- Pachetul Python — același motor, dintr-un script.
Pagini conexe
Referință API REST
Fiecare punct final din SDK cu cerere și răspuns — autentificare, chei, calcul, validare, verificare de grindă și gestionarea modelelor.
Start rapid: primul model în browser
Construiți și calculați un cadru 3D în browser: materiale, secțiuni, noduri, reazeme, bare, încărcări, Calculați.
Vezi și
Întrebări frecvente
Am nevoie de o cheie API pentru a calcula în browser?
calculate_from_json funcționează fără cheie și fără cont pentru modele de până la 100 bare. O cheie este necesară doar pentru emiterea tokenului de calcul Pro.Modelul părăsește browserul?
De ce are Vite nevoie de configurare suplimentară?
await de nivel superior. vite-plugin-wasm se ocupă de importul WebAssembly, iar build.target: "esnext" păstrează acel await în rezultat — necesită Chrome, Edge sau Firefox 89+, ori Safari 15+. webpack are nevoie de asyncWebAssembly și asyncFunction în setările experiments și output. Dacă vite-plugin-top-level-await a rămas în configurație dintr-o versiune anterioară a acestei pagini, îl puteți elimina: cu versiunile recente de @swc/core face ca vite build să eșueze.Ar trebui să rulez solverul într-un Web Worker?
Este nevoie de un apel init()?
await init(); nu mai este necesar.Ce se întâmplă dacă tokenul de calcul a expirat?
LimitExceeded.Ce pachet folosesc pe server?
@ferscloud/fers-calculation, compilat pentru Node. Nu necesită configurare de bundler și se inițializează singur la import.