@ferscloud/fers-calculation-web 0.2.60 → 0.2.62

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 CHANGED
@@ -185,8 +185,35 @@ const mr = res.result.results.loadcases["…"].member_results["1"];
185
185
 
186
186
  Off by default to keep the payload lean; omitted from `member_results` when not requested.
187
187
 
188
+ ## Attribution
189
+
190
+ Free-tier results carry an `attribution` object minted inside the solver.
191
+ Premium results (solved with a valid solve token) do not, so the same code
192
+ credits FERS on the free tier and white-labels on Pro:
193
+
194
+ ```ts
195
+ import { fersAttributionHtml } from "@ferscloud/fers-calculation-web/badge";
196
+
197
+ // "" when the result came back from a Pro solve.
198
+ const credit = fersAttributionHtml(res);
199
+ ```
200
+
201
+ `getFersAttribution`, `fersAttributionText` and `createFersBadge` are also
202
+ exported. All of them accept the envelope, the parsed model or the results
203
+ bundle, and all return nothing for a Pro result or an error envelope.
204
+
205
+ On 0.2.61 this subpath resolved only under a bundler; plain Node ESM needed
206
+ `/badge.js`. From 0.2.62 the package ships an `exports` map and both forms work
207
+ everywhere.
208
+
209
+ Using the free tier in an application? Please display the credit. It is the
210
+ only thing the free tier asks of you.
211
+
188
212
  ## Links
189
213
 
190
- - [Full documentation & getting started](https://ferscloud.com/getting-started)
214
+ - [Structural analysis in JavaScript](https://ferscloud.com/structural-analysis-javascript) — why run the solver client-side
215
+ - [JavaScript documentation](https://ferscloud.com/docs/javascript) — bundler setup, error codes, types, solve tokens
216
+ - [Full documentation](https://ferscloud.com/getting-started) — every route into FERS
217
+ - [llms-full.txt](https://ferscloud.com/llms-full.txt) — the whole documentation in one fetch, for agents
191
218
  - [FERS Cloud](https://ferscloud.com)
192
- - [FERS_core Python package](https://pypi.org/project/fers-core/)
219
+ - [FERS Python package](https://pypi.org/project/fers/) — `pip install FERS`
package/badge.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ /** Free-tier provenance stamp. Absent from Premium results. */
2
+ export interface FersAttribution {
3
+ /** Always "FERS". */
4
+ generated_by: string;
5
+ /** Canonical product URL. */
6
+ url: string;
7
+ /** Engine version that produced the results. */
8
+ engine_version: string;
9
+ /** Always "free" — Premium results carry no attribution at all. */
10
+ tier: string;
11
+ /** Plain-text credit. */
12
+ text: string;
13
+ /** Ready-to-inject HTML anchor. */
14
+ html: string;
15
+ }
16
+
17
+ /**
18
+ * Find the attribution object in a solver envelope, a parsed model, or a
19
+ * results bundle. Returns null for Premium results and for error envelopes.
20
+ */
21
+ export function getFersAttribution(input: unknown): FersAttribution | null;
22
+
23
+ /** Ready-to-inject HTML anchor, or "" on Pro. */
24
+ export function fersAttributionHtml(input: unknown): string;
25
+
26
+ /** Plain-text credit, or "" on Pro. */
27
+ export function fersAttributionText(input: unknown): string;
28
+
29
+ /** A detached DOM element carrying the credit, or null on Pro. */
30
+ export function createFersBadge(
31
+ input: unknown,
32
+ doc?: Document,
33
+ ): HTMLElement | null;
package/badge.js ADDED
@@ -0,0 +1,69 @@
1
+ // Attribution helpers for @ferscloud/fers-calculation-web.
2
+ //
3
+ // Free-tier results carry an `attribution` object minted inside the solver;
4
+ // Premium results (solved with a valid solve token) do not. Everything here
5
+ // returns nothing when the field is absent, so the same code shows a credit on
6
+ // the free tier and white-labels on Pro with no flag to set and no branch to
7
+ // write.
8
+ //
9
+ // Deliberately framework-free: a solver package should not drag in React. Use
10
+ // `fersAttributionHtml()` with your framework's raw-HTML escape hatch, or
11
+ // `createFersBadge()` if you would rather be handed a DOM node.
12
+ //
13
+ // Shipped only with the browser package. The Node build is server-side, where
14
+ // a badge has nothing to render into — read `attribution.text` directly there.
15
+
16
+ /**
17
+ * Find the attribution object, accepting whichever shape you happen to hold:
18
+ * the solver envelope, the parsed model, or the results bundle itself.
19
+ * @returns {{generated_by: string, url: string, engine_version: string, tier: string, text: string, html: string} | null}
20
+ */
21
+ export function getFersAttribution(input) {
22
+ if (!input || typeof input !== "object") return null;
23
+ // Envelope: { ok, result } — an error envelope has nothing to credit.
24
+ if ("ok" in input) return input.ok ? getFersAttribution(input.result) : null;
25
+ // Parsed model: { ..., results: ResultsBundle }
26
+ if (input.results) return getFersAttribution(input.results);
27
+ // Results bundle.
28
+ return input.attribution ?? null;
29
+ }
30
+
31
+ /** Ready-to-inject HTML anchor, or "" on Pro. */
32
+ export function fersAttributionHtml(input) {
33
+ return getFersAttribution(input)?.html ?? "";
34
+ }
35
+
36
+ /** Plain-text credit, or "" on Pro. Use for text reports and console output. */
37
+ export function fersAttributionText(input) {
38
+ return getFersAttribution(input)?.text ?? "";
39
+ }
40
+
41
+ /**
42
+ * Build a detached DOM element carrying the credit, or null on Pro.
43
+ * @param {object} input solver envelope, model, or results bundle
44
+ * @param {Document} [doc] defaults to the global document
45
+ * @returns {HTMLElement | null}
46
+ */
47
+ export function createFersBadge(input, doc) {
48
+ const attribution = getFersAttribution(input);
49
+ if (!attribution) return null;
50
+
51
+ const d = doc ?? (typeof document !== "undefined" ? document : null);
52
+ if (!d) return null;
53
+
54
+ const el = d.createElement("span");
55
+ el.className = "fers-attribution";
56
+ el.style.fontSize = "12px";
57
+ el.style.opacity = "0.75";
58
+
59
+ const a = d.createElement("a");
60
+ a.href = attribution.url;
61
+ a.target = "_blank";
62
+ a.rel = "noopener";
63
+ // textContent, not innerHTML: the string comes from the solver, but building
64
+ // the node by hand keeps this helper injection-proof by construction.
65
+ a.textContent = attribution.text;
66
+
67
+ el.appendChild(a);
68
+ return el;
69
+ }
package/fers-models.d.ts CHANGED
@@ -211,6 +211,50 @@ export interface components {
211
211
  * @enum {string}
212
212
  */
213
213
  AnalysisOrder: "LINEAR" | "NONLINEAR";
214
+ /**
215
+ * @description Free-tier provenance stamp, attached to every result the free solver
216
+ * produces and absent from Premium results.
217
+ *
218
+ * Why it lives in the engine rather than in a JS wrapper: the tier is decided
219
+ * inside the WASM module, by Ed25519-verifying a solve token against a public
220
+ * key compiled into the binary (`wasm_bindings::verify_solve_token`). Anything
221
+ * downstream of that boundary — a bundler config, a React component, a JSON
222
+ * post-processing step — can be edited by whoever ships the page. Minting the
223
+ * attribution here means the branded path is the default one, and removing it
224
+ * means either holding the server's private key or patching and rebuilding a
225
+ * WebAssembly binary.
226
+ *
227
+ * It is not, and cannot be, an absolute guarantee: anything shipped to a
228
+ * browser can ultimately be modified. It raises the cost of stripping
229
+ * attribution from "delete a div" to "rebuild the engine", and the licence
230
+ * carries the rest.
231
+ *
232
+ * `html` and `text` are pre-rendered so a consumer can display the credit
233
+ * without knowing anything about our brand. `fersAttributionHtml()` in
234
+ * `@ferscloud/fers-calculation-web/badge` simply returns `attribution.html`,
235
+ * and returns "" when the field is absent — so upgrading to Pro white-labels
236
+ * with no code change.
237
+ */
238
+ Attribution: {
239
+ /**
240
+ * @description Engine version that produced the results. Mirrors
241
+ * [`ResultsBundle::engine_version`].
242
+ */
243
+ engine_version: string;
244
+ /** @description Always "FERS". */
245
+ generated_by: string;
246
+ /** @description Ready-to-inject HTML anchor, for web UIs. */
247
+ html: string;
248
+ /** @description Plain-text credit, for console output, PDFs and text reports. */
249
+ text: string;
250
+ /**
251
+ * @description The tier this solve ran under. Only ever "free" — Premium results carry
252
+ * no `attribution` object at all.
253
+ */
254
+ tier: string;
255
+ /** @description Canonical product URL. */
256
+ url: string;
257
+ };
214
258
  /**
215
259
  * @description A global coordinate axis.
216
260
  * @enum {string}
@@ -2355,6 +2399,7 @@ export interface components {
2355
2399
  };
2356
2400
  /** @description All analysis results: per load case, per load combination, unity-check results and the optional HTML report. */
2357
2401
  ResultsBundle: {
2402
+ attribution?: null | components["schemas"]["Attribution"];
2358
2403
  buckling?: null | components["schemas"]["BucklingResults"];
2359
2404
  /**
2360
2405
  * @description Per-reference buckling runs, present only when `analysis.buckling`
Binary file
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ferscloud/fers-calculation-web",
3
3
  "type": "module",
4
- "version": "0.2.60",
4
+ "version": "0.2.62",
5
5
  "license": "BSD-3-Clause",
6
6
  "repository": {
7
7
  "type": "git",
@@ -12,16 +12,63 @@
12
12
  "fers_calculations.js",
13
13
  "fers_calculations_bg.js",
14
14
  "fers_calculations.d.ts",
15
- "fers-models.d.ts"
15
+ "fers-models.d.ts",
16
+ "badge.js",
17
+ "badge.d.ts"
16
18
  ],
17
19
  "main": "fers_calculations.js",
18
- "homepage": "https://ferscloud.com",
20
+ "homepage": "https://ferscloud.com/structural-analysis-javascript",
19
21
  "types": "fers_calculations.d.ts",
20
22
  "sideEffects": [
21
23
  "./fers_calculations.js",
22
24
  "./snippets/*"
23
25
  ],
26
+ "description": "Structural analysis FEM solver for beams, frames and trusses, compiled from Rust to WebAssembly. Runs in the browser or in Node with no server round-trip. Includes Eurocode EN 1993-1-1 steel checks.",
27
+ "keywords": [
28
+ "structural-analysis",
29
+ "structural-engineering",
30
+ "finite-element",
31
+ "finite-element-analysis",
32
+ "fem",
33
+ "fea",
34
+ "solver",
35
+ "beam",
36
+ "frame",
37
+ "truss",
38
+ "stiffness-matrix",
39
+ "bending-moment",
40
+ "shear-force",
41
+ "deflection",
42
+ "buckling",
43
+ "eurocode",
44
+ "en1993",
45
+ "steel-design",
46
+ "wasm",
47
+ "webassembly",
48
+ "rust",
49
+ "engineering",
50
+ "civil-engineering",
51
+ "cad"
52
+ ],
53
+ "bugs": {
54
+ "url": "https://github.com/Jeroen124/FERS_calculations/issues"
55
+ },
24
56
  "publishConfig": {
25
57
  "access": "public"
58
+ },
59
+ "exports": {
60
+ ".": {
61
+ "types": "./fers_calculations.d.ts",
62
+ "default": "./fers_calculations.js"
63
+ },
64
+ "./badge": {
65
+ "types": "./badge.d.ts",
66
+ "default": "./badge.js"
67
+ },
68
+ "./fers-models": {
69
+ "types": "./fers-models.d.ts"
70
+ },
71
+ "./package.json": "./package.json",
72
+ "./*": "./*"
26
73
  }
27
74
  }