@ferscloud/fers-calculation 0.2.39 → 0.2.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -11
- package/fers_calculations.d.ts +7 -2
- package/fers_calculations.js +7 -4
- package/fers_calculations_bg.wasm +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,25 +2,82 @@
|
|
|
2
2
|
|
|
3
3
|
High-performance structural engineering FEM solver compiled from Rust to WebAssembly. Runs entirely in the browser — no server round-trip per calculation.
|
|
4
4
|
|
|
5
|
+
> This README covers both published packages: **`@ferscloud/fers-calculation`** (Node.js / server-side, `--target nodejs`) and **`@ferscloud/fers-calculation-web`** (browser / bundler, `--target bundler`). The API is identical; only installation and bundler setup differ.
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
```bash
|
|
10
|
+
# Browser apps (Vite, Next.js, webpack):
|
|
11
|
+
npm install @ferscloud/fers-calculation-web
|
|
12
|
+
# Node.js / server-side:
|
|
8
13
|
npm install @ferscloud/fers-calculation
|
|
9
14
|
```
|
|
10
15
|
|
|
11
|
-
##
|
|
16
|
+
## Bundler setup (browser build)
|
|
17
|
+
|
|
18
|
+
`@ferscloud/fers-calculation-web` is a WASM ES module that initialises via top-level `await`. Most bundlers need a one-time config:
|
|
19
|
+
|
|
20
|
+
**Vite**
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm i -D vite-plugin-wasm vite-plugin-top-level-await
|
|
24
|
+
```
|
|
12
25
|
|
|
13
26
|
```ts
|
|
14
|
-
|
|
27
|
+
// vite.config.ts
|
|
28
|
+
import wasm from "vite-plugin-wasm";
|
|
29
|
+
import topLevelAwait from "vite-plugin-top-level-await";
|
|
15
30
|
|
|
16
|
-
|
|
31
|
+
export default { plugins: [wasm(), topLevelAwait()] };
|
|
32
|
+
```
|
|
17
33
|
|
|
18
|
-
|
|
19
|
-
|
|
34
|
+
**Next.js / webpack**
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
// next.config.js
|
|
38
|
+
module.exports = {
|
|
39
|
+
transpilePackages: ["@ferscloud/fers-calculation-web"],
|
|
40
|
+
webpack(config) {
|
|
41
|
+
config.experiments = { ...config.experiments, asyncWebAssembly: true };
|
|
42
|
+
config.output.environment = { ...config.output.environment, asyncFunction: true };
|
|
43
|
+
return config;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The solver is synchronous and CPU-bound; for large models run it inside a Web Worker so the UI thread stays responsive. The Node.js package (`@ferscloud/fers-calculation`) needs no bundler config.
|
|
49
|
+
|
|
50
|
+
## Quick start — free tier (up to 100 members)
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { calculate_from_json } from "@ferscloud/fers-calculation";
|
|
54
|
+
|
|
55
|
+
// No init() call needed — the nodejs and bundler builds initialise the
|
|
56
|
+
// WASM module automatically on import.
|
|
57
|
+
const res = JSON.parse(calculate_from_json(JSON.stringify(myModel)));
|
|
58
|
+
if (res.ok) {
|
|
59
|
+
const data = res.result; // displacements, member_results, unity_checks, …
|
|
60
|
+
} else {
|
|
61
|
+
console.error(res.error.code, res.error.message);
|
|
62
|
+
}
|
|
20
63
|
```
|
|
21
64
|
|
|
22
65
|
No API key required. Works for any model with up to 100 members.
|
|
23
66
|
|
|
67
|
+
## Response shape
|
|
68
|
+
|
|
69
|
+
Every solver call returns a JSON **envelope**, so you `JSON.parse` once and branch on `ok` — you never have to sniff whether the returned string "looks like" an error:
|
|
70
|
+
|
|
71
|
+
```jsonc
|
|
72
|
+
// success
|
|
73
|
+
{ "ok": true, "result": { /* the full result document */ } }
|
|
74
|
+
// failure (invalid model, over the member limit, malformed JSON, …)
|
|
75
|
+
{ "ok": false, "error": { "code": "LimitExceeded",
|
|
76
|
+
"message": "Number of members (250) exceeds allowed maximum of 100" } }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`error.code` is one of `InvalidJson`, `LimitExceeded`, `SolveError`, `InternalPanic`, `InternalSerialization`. The return value is **always** valid JSON.
|
|
80
|
+
|
|
24
81
|
## Authenticated tier — Pro (up to 10 000 members)
|
|
25
82
|
|
|
26
83
|
Pro limits are unlocked by passing a short-lived signed token issued by the FERS Cloud server. The token is verified inside the WASM using an Ed25519 public key baked into the binary — it cannot be forged.
|
|
@@ -74,17 +131,16 @@ Same pattern works for Express, Deno, Bun, Cloudflare Workers, or any server-sid
|
|
|
74
131
|
### 3. Frontend: call the solver with the token
|
|
75
132
|
|
|
76
133
|
```ts
|
|
77
|
-
import
|
|
78
|
-
|
|
79
|
-
await init();
|
|
134
|
+
import { calculate_from_json_with_token } from "@ferscloud/fers-calculation";
|
|
80
135
|
|
|
81
136
|
const { token } = await fetch("/api/solve-token").then(r => r.json());
|
|
82
137
|
|
|
83
|
-
const
|
|
84
|
-
|
|
138
|
+
const res = JSON.parse(calculate_from_json_with_token(JSON.stringify(myModel), token));
|
|
139
|
+
if (!res.ok) throw new Error(`${res.error.code}: ${res.error.message}`);
|
|
140
|
+
const data = res.result;
|
|
85
141
|
```
|
|
86
142
|
|
|
87
|
-
If the token is missing, expired, or invalid, the solver falls back to the free 100-member limit — it never throws.
|
|
143
|
+
If the token is missing, expired, or invalid, the solver falls back to the free 100-member limit — it never throws (a genuine solve failure comes back as `{ ok: false, error }`, not an exception).
|
|
88
144
|
|
|
89
145
|
## Tier comparison
|
|
90
146
|
|
|
@@ -99,6 +155,36 @@ If the token is missing, expired, or invalid, the solver falls back to the free
|
|
|
99
155
|
|
|
100
156
|
Keep your `FERS_API_KEY` server-side only. The solve token it fetches is safe to pass to the browser — it is short-lived and cryptographically signed. Only FERS Cloud can issue valid tokens; the browser WASM can only verify them.
|
|
101
157
|
|
|
158
|
+
## TypeScript types
|
|
159
|
+
|
|
160
|
+
The browser package ships generated model types alongside the function signatures:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import type { FERS, ResultsBundle } from "@ferscloud/fers-calculation-web/fers-models";
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`FERS` is the input model; `ResultsBundle` is the `result` payload of a successful envelope. Both are generated from the engine's OpenAPI schema, so they track the published version.
|
|
167
|
+
|
|
168
|
+
## Deflected shape (optional)
|
|
169
|
+
|
|
170
|
+
Set `include_member_deflected_shape` in the model's analysis options to get a
|
|
171
|
+
ready-to-plot, **load-exact** deflected shape per member — the member's global
|
|
172
|
+
displacement sampled along its length — instead of reconstructing the curve yourself:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
const model = {
|
|
176
|
+
/* … model + load cases … */
|
|
177
|
+
analysis: { /* … */ options: { /* … */ include_member_deflected_shape: true } },
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const res = JSON.parse(calculate_from_json(JSON.stringify(model)));
|
|
181
|
+
const mr = res.result.results.loadcases["…"].member_results["1"];
|
|
182
|
+
// mr.member_displacements: [{ x_frac, displacement: [dx, dy, dz] }, …]
|
|
183
|
+
// x_frac 0→1 along the member; displacement in the global input frame.
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Off by default to keep the payload lean; omitted from `member_results` when not requested.
|
|
187
|
+
|
|
102
188
|
## Links
|
|
103
189
|
|
|
104
190
|
- [Full documentation & getting started](https://ferscloud.com/getting-started)
|
package/fers_calculations.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Free-tier solver (100-member limit). Used when no valid solve token is present.
|
|
6
|
+
* Returns the JSON envelope described above.
|
|
6
7
|
*/
|
|
7
8
|
export function calculate_from_json(json_data: string): string;
|
|
8
9
|
|
|
@@ -10,15 +11,19 @@ export function calculate_from_json(json_data: string): string;
|
|
|
10
11
|
* Tier-aware solver. Verifies the Ed25519-signed solve token issued by the
|
|
11
12
|
* FERS Cloud server; grants Premium limits (10 000 members) when the token
|
|
12
13
|
* is valid and contains `"tier":"premium"`. Falls back to Free on any
|
|
13
|
-
* failure — expired, malformed, or wrong signature.
|
|
14
|
+
* failure — expired, malformed, or wrong signature. Returns the JSON envelope.
|
|
14
15
|
*/
|
|
15
16
|
export function calculate_from_json_with_token(json_data: string, solve_token: string): string;
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Parse (without solving) a model from a file path and return it as the JSON
|
|
20
|
+
* envelope: `{"ok":true,"result": <FERS JSON> }` or an error envelope.
|
|
21
|
+
*/
|
|
17
22
|
export function load_fers_from_file(path: string): string;
|
|
18
23
|
|
|
19
24
|
/**
|
|
20
25
|
* Re-render unity-check reports from already-solved results (no re-solve). Fills
|
|
21
26
|
* each `rendered_report` from its check's `report_template` and rebuilds
|
|
22
|
-
* `report_html`. Returns the
|
|
27
|
+
* `report_html`. Returns the JSON envelope.
|
|
23
28
|
*/
|
|
24
29
|
export function render_reports_from_json(json_data: string): string;
|
package/fers_calculations.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Free-tier solver (100-member limit). Used when no valid solve token is present.
|
|
5
|
+
* Returns the JSON envelope described above.
|
|
5
6
|
* @param {string} json_data
|
|
6
7
|
* @returns {string}
|
|
7
8
|
*/
|
|
@@ -25,7 +26,7 @@ exports.calculate_from_json = calculate_from_json;
|
|
|
25
26
|
* Tier-aware solver. Verifies the Ed25519-signed solve token issued by the
|
|
26
27
|
* FERS Cloud server; grants Premium limits (10 000 members) when the token
|
|
27
28
|
* is valid and contains `"tier":"premium"`. Falls back to Free on any
|
|
28
|
-
* failure — expired, malformed, or wrong signature.
|
|
29
|
+
* failure — expired, malformed, or wrong signature. Returns the JSON envelope.
|
|
29
30
|
* @param {string} json_data
|
|
30
31
|
* @param {string} solve_token
|
|
31
32
|
* @returns {string}
|
|
@@ -49,6 +50,8 @@ function calculate_from_json_with_token(json_data, solve_token) {
|
|
|
49
50
|
exports.calculate_from_json_with_token = calculate_from_json_with_token;
|
|
50
51
|
|
|
51
52
|
/**
|
|
53
|
+
* Parse (without solving) a model from a file path and return it as the JSON
|
|
54
|
+
* envelope: `{"ok":true,"result": <FERS JSON> }` or an error envelope.
|
|
52
55
|
* @param {string} path
|
|
53
56
|
* @returns {string}
|
|
54
57
|
*/
|
|
@@ -71,7 +74,7 @@ exports.load_fers_from_file = load_fers_from_file;
|
|
|
71
74
|
/**
|
|
72
75
|
* Re-render unity-check reports from already-solved results (no re-solve). Fills
|
|
73
76
|
* each `rendered_report` from its check's `report_template` and rebuilds
|
|
74
|
-
* `report_html`. Returns the
|
|
77
|
+
* `report_html`. Returns the JSON envelope.
|
|
75
78
|
* @param {string} json_data
|
|
76
79
|
* @returns {string}
|
|
77
80
|
*/
|
|
@@ -93,10 +96,10 @@ exports.render_reports_from_json = render_reports_from_json;
|
|
|
93
96
|
function __wbg_get_imports() {
|
|
94
97
|
const import0 = {
|
|
95
98
|
__proto__: null,
|
|
96
|
-
|
|
99
|
+
__wbg___wbindgen_throw_344f42d3211c4765: function(arg0, arg1) {
|
|
97
100
|
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
98
101
|
},
|
|
99
|
-
|
|
102
|
+
__wbg_now_86c0d4ba3fa605b8: function() {
|
|
100
103
|
const ret = Date.now();
|
|
101
104
|
return ret;
|
|
102
105
|
},
|
|
Binary file
|