@tensorfeed/status-widget 0.1.0

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.
Files changed (4) hide show
  1. package/README.md +72 -0
  2. package/index.d.ts +18 -0
  3. package/index.js +96 -0
  4. package/package.json +45 -0
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # @tensorfeed/status-widget
2
+
3
+ Drop the live [TensorFeed](https://tensorfeed.ai) AI status monitor onto
4
+ any site with one line. Real-time operational status and p95 latency for
5
+ every major AI provider and service, in a self-contained sci-fi console.
6
+ Free, no API key, no tracking, zero dependencies.
7
+
8
+ Live preview and docs: https://tensorfeed.ai/embed
9
+
10
+ ## Install
11
+
12
+ ```sh
13
+ npm install @tensorfeed/status-widget
14
+ ```
15
+
16
+ ## Use it (any framework, or none)
17
+
18
+ ```js
19
+ import '@tensorfeed/status-widget';
20
+ ```
21
+
22
+ ```html
23
+ <tensorfeed-status accent="blue" poll="30" height="600"></tensorfeed-status>
24
+ ```
25
+
26
+ The custom element renders the widget in a shadow root, so host-page CSS
27
+ cannot affect it and it cannot affect your page.
28
+
29
+ ### React
30
+
31
+ No custom element needed. Use the URL helper:
32
+
33
+ ```jsx
34
+ import { tensorfeedStatusSrc } from '@tensorfeed/status-widget';
35
+
36
+ <iframe
37
+ src={tensorfeedStatusSrc({ accent: 'blue' })}
38
+ title="TensorFeed live AI status"
39
+ loading="lazy"
40
+ style={{ width: '100%', maxWidth: 720, height: 600, border: 0 }}
41
+ />
42
+ ```
43
+
44
+ ### Plain HTML, no build
45
+
46
+ ```html
47
+ <script type="module">
48
+ import 'https://esm.sh/@tensorfeed/status-widget';
49
+ </script>
50
+ <tensorfeed-status></tensorfeed-status>
51
+ ```
52
+
53
+ ## Attributes
54
+
55
+ | Attribute | Values | Default | Notes |
56
+ |---|---|---|---|
57
+ | `accent` | `blue` \| `auto` \| `green` | `blue` | `blue` is a light-blue spine with green status indicators. `auto` greens the whole accent when all systems are nominal. `green` forces green. |
58
+ | `poll` | `5` to `600` | `30` | Client poll interval in seconds. Raise it on low-traffic pages. |
59
+ | `height` | px number or any CSS length | `600` | Widget caps at 720px wide and reflows down to ~320px. |
60
+ | `label` | string | `TensorFeed live AI status` | Accessible iframe title. |
61
+
62
+ ## What it shows
63
+
64
+ Operational status and probed p95 latency where TensorFeed measures it,
65
+ real 7-day uptime % otherwise. Vendor status is authoritative; a
66
+ provider with no status source is shown as "no data", never a false
67
+ alarm. "Detail" deep-links to the per-provider page on tensorfeed.ai.
68
+
69
+ ## License
70
+
71
+ MIT. The widget data comes from the public TensorFeed endpoints
72
+ `/api/status/summary` and `/api/status/leaderboard`.
package/index.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ export interface TensorfeedStatusOptions {
2
+ /** Accent scheme. Default "blue" (light-blue spine, green status).
3
+ * "auto" greens the whole accent when all systems are nominal.
4
+ * "green" forces green. */
5
+ accent?: 'blue' | 'auto' | 'green';
6
+ /** Client poll interval in seconds (5 to 600). Default 30. */
7
+ poll?: number;
8
+ }
9
+
10
+ /** Build the widget iframe URL with clean, default-aware query params. */
11
+ export function tensorfeedStatusSrc(opts?: TensorfeedStatusOptions): string;
12
+
13
+ /** Register the <tensorfeed-status> custom element. Idempotent; a no-op
14
+ * in non-DOM (SSR) environments. Called automatically on import. */
15
+ export function defineTensorFeedStatus(tag?: string): void;
16
+
17
+ /** The custom element class, exported for advanced registration. */
18
+ export class TensorFeedStatus extends HTMLElement {}
package/index.js ADDED
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @tensorfeed/status-widget
3
+ *
4
+ * The live TensorFeed AI status monitor, as a zero-dependency, framework
5
+ * agnostic custom element plus a tiny helper. The widget itself is a
6
+ * fully self-contained page at tensorfeed.ai/widget/status; this package
7
+ * just makes embedding it a one-liner and keeps the query params honest.
8
+ *
9
+ * HTML / any framework:
10
+ * import '@tensorfeed/status-widget';
11
+ * <tensorfeed-status accent="blue" poll="30" height="600"></tensorfeed-status>
12
+ *
13
+ * React (no custom element needed):
14
+ * import { tensorfeedStatusSrc } from '@tensorfeed/status-widget';
15
+ * <iframe src={tensorfeedStatusSrc({ accent: 'blue' })}
16
+ * title="TensorFeed live AI status"
17
+ * style={{ width: '100%', height: 600, border: 0, maxWidth: 720 }} />
18
+ */
19
+
20
+ const BASE = 'https://tensorfeed.ai/widget/status';
21
+
22
+ /**
23
+ * Build the widget iframe URL. Mirrors the widget's own defaults so the
24
+ * URL stays clean: accent defaults to blue, poll to 30s; only
25
+ * non-defaults are added as query params.
26
+ */
27
+ export function tensorfeedStatusSrc(opts = {}) {
28
+ const params = new URLSearchParams();
29
+ const accent = String(opts.accent || 'blue').toLowerCase();
30
+ if (accent === 'auto' || accent === 'green') params.set('accent', accent);
31
+ const poll = Number(opts.poll);
32
+ if (Number.isFinite(poll) && poll >= 5 && poll <= 600 && poll !== 30) {
33
+ params.set('poll', String(Math.round(poll)));
34
+ }
35
+ params.set('utm_source', 'npm');
36
+ params.set('utm_medium', 'component');
37
+ return `${BASE}?${params.toString()}`;
38
+ }
39
+
40
+ function resolveHeight(h) {
41
+ if (h == null || h === '') return '600px';
42
+ return /^\d+$/.test(String(h)) ? `${h}px` : String(h);
43
+ }
44
+
45
+ // Guarded base so `import`-ing this package never throws in Node / SSR
46
+ // (Next.js, etc.) where HTMLElement does not exist. The element only
47
+ // actually does anything once defineTensorFeedStatus runs in a browser.
48
+ const ElementBase = typeof HTMLElement !== 'undefined' ? HTMLElement : class {};
49
+
50
+ class TensorFeedStatus extends ElementBase {
51
+ static get observedAttributes() {
52
+ return ['accent', 'poll', 'height', 'label'];
53
+ }
54
+
55
+ connectedCallback() {
56
+ if (!this.shadowRoot) this.attachShadow({ mode: 'open' });
57
+ this._render();
58
+ }
59
+
60
+ attributeChangedCallback() {
61
+ if (this.shadowRoot) this._render();
62
+ }
63
+
64
+ _render() {
65
+ const src = tensorfeedStatusSrc({
66
+ accent: this.getAttribute('accent'),
67
+ poll: this.getAttribute('poll'),
68
+ });
69
+ const height = resolveHeight(this.getAttribute('height'));
70
+ const label = this.getAttribute('label') || 'TensorFeed live AI status';
71
+ // Shadow DOM keeps host page CSS from touching the iframe and vice
72
+ // versa. The widget brings all its own styling.
73
+ this.shadowRoot.innerHTML =
74
+ `<style>:host{display:block;width:100%}` +
75
+ `iframe{display:block;width:100%;max-width:720px;height:${height};border:0;` +
76
+ `border-radius:6px 28px 28px 6px;overflow:hidden}</style>` +
77
+ `<iframe src="${src}" title="${label.replace(/"/g, '&quot;')}" ` +
78
+ `loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>`;
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Register the <tensorfeed-status> custom element. Safe to call more
84
+ * than once and a no-op in non-DOM environments (SSR).
85
+ */
86
+ export function defineTensorFeedStatus(tag = 'tensorfeed-status') {
87
+ if (typeof window === 'undefined' || typeof customElements === 'undefined') return;
88
+ if (!customElements.get(tag)) customElements.define(tag, TensorFeedStatus);
89
+ }
90
+
91
+ // Importing the package auto-registers the element (declared as a side
92
+ // effect in package.json). React-only users can ignore this and use
93
+ // tensorfeedStatusSrc directly.
94
+ defineTensorFeedStatus();
95
+
96
+ export { TensorFeedStatus };
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@tensorfeed/status-widget",
3
+ "version": "0.1.0",
4
+ "description": "Drop the live TensorFeed AI status monitor onto any site with one line. Zero dependencies, framework agnostic web component plus a helper for React and plain HTML.",
5
+ "type": "module",
6
+ "main": "./index.js",
7
+ "module": "./index.js",
8
+ "types": "./index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./index.d.ts",
12
+ "import": "./index.js"
13
+ }
14
+ },
15
+ "files": ["index.js", "index.d.ts", "README.md"],
16
+ "sideEffects": ["./index.js"],
17
+ "keywords": [
18
+ "tensorfeed",
19
+ "ai",
20
+ "llm",
21
+ "status",
22
+ "monitor",
23
+ "uptime",
24
+ "widget",
25
+ "web-component",
26
+ "embed",
27
+ "openai",
28
+ "anthropic",
29
+ "claude",
30
+ "gemini"
31
+ ],
32
+ "homepage": "https://tensorfeed.ai/embed",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/RipperMercs/tensorfeed.git",
36
+ "directory": "packages/status-widget"
37
+ },
38
+ "license": "MIT",
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "engines": {
43
+ "node": ">=18"
44
+ }
45
+ }