@theruntimehq/react 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TheRuntimeHQ
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,202 @@
1
+ # @theruntimehq/react
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@theruntimehq/react.svg)](https://www.npmjs.com/package/@theruntimehq/react)
4
+ [![license](https://img.shields.io/npm/l/@theruntimehq/react.svg)](https://github.com/TheRuntimeHQ/runtimehq-react/blob/main/LICENSE)
5
+
6
+ The official React state management SDK for [RuntimeHQ](https://theruntimehq.com). Connect your status checks directly to your React primitives.
7
+
8
+ This SDK is a **pure state management SDK** with:
9
+ - 🚫 **No visual UI components** (Customers use their own design systems).
10
+ - 🚫 **No CSS, Tailwind, or style sheet dependencies**.
11
+ - 🚫 **No external state libraries**.
12
+ - ⚛️ Full support for **React 18+ and 19+**.
13
+ - 🌐 Native compatibility with Server-Side Rendering (SSR), Vite, Next.js, and Remix.
14
+
15
+ ---
16
+
17
+ ## Installation
18
+
19
+ Ensure you have `@theruntimehq/js` and React installed in your project:
20
+
21
+ ```bash
22
+ npm install @theruntimehq/react @theruntimehq/js
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Core Hooks & Provider APIs
28
+
29
+ ### 1. Global Provider (`RuntimeHQProvider`)
30
+
31
+ Wrap your root application with the `RuntimeHQProvider`. It internally manages a single `RuntimeHQClient` and handles global state subscription and cleanup.
32
+
33
+ ```tsx
34
+ import { RuntimeHQProvider } from "@theruntimehq/react";
35
+
36
+ export default function Root() {
37
+ return (
38
+ <RuntimeHQProvider
39
+ runtimeKey="rt_prod_your_key_here"
40
+ intervalSeconds={15}
41
+ >
42
+ <App />
43
+ </RuntimeHQProvider>
44
+ );
45
+ }
46
+ ```
47
+
48
+ #### Provider Props
49
+ | Prop | Type | Required | Default | Description |
50
+ | :--- | :--- | :--- | :--- | :--- |
51
+ | `runtimeKey` | `string` | **Yes** | - | Your RuntimeHQ API status key (must start with `rt_prod_` or `rt_test_`). |
52
+ | `intervalSeconds` | `number` | No | `15` | Polling interval for updates in seconds. |
53
+
54
+ ---
55
+
56
+ ### 2. Context Hook (`useRuntimeHQ`)
57
+
58
+ Consume the global status state anywhere inside the provider.
59
+
60
+ ```tsx
61
+ import { useRuntimeHQ, isOperational } from "@theruntimehq/react";
62
+
63
+ function StatusBanner() {
64
+ const { runtime, loading, error } = useRuntimeHQ();
65
+
66
+ if (loading) return <div>Checking status...</div>;
67
+ if (error) return <div>Error fetching status: {error.message}</div>;
68
+ if (!runtime || isOperational(runtime)) return null;
69
+
70
+ return (
71
+ <div className={`banner ${runtime.state.toLowerCase()}`}>
72
+ ⚠️ {runtime.message}
73
+ </div>
74
+ );
75
+ }
76
+ ```
77
+
78
+ #### Return Value
79
+ ```typescript
80
+ interface RuntimeHQContextValue {
81
+ runtime: RuntimeResponse | null; // Detailed status info or null before first fetch
82
+ loading: boolean; // true until the first fetch (success or failure) completes
83
+ error: Error | null; // Captured network or validation error (if any)
84
+ }
85
+ ```
86
+
87
+ > [!IMPORTANT]
88
+ > If `useRuntimeHQ` is invoked outside a `<RuntimeHQProvider>`, it throws a descriptive error:
89
+ > `useRuntimeHQ must be used within a RuntimeHQProvider`
90
+
91
+ ---
92
+
93
+ ### 3. Standalone Direct Hook (`useRuntimeHQState`)
94
+
95
+ If you want to read runtime status inside isolated widgets without setting up a context provider at the root level, use `useRuntimeHQState`. It shares the same state management and cleanup logic as the provider.
96
+
97
+ ```tsx
98
+ import { useRuntimeHQState } from "@theruntimehq/react";
99
+
100
+ function IndependentWidget() {
101
+ const { runtime, loading, error } = useRuntimeHQState({
102
+ runtimeKey: "rt_prod_your_key_here",
103
+ intervalSeconds: 30,
104
+ });
105
+
106
+ if (loading) return <Spinner />;
107
+ return <div>State: {runtime?.state}</div>;
108
+ }
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Convenience Helpers
114
+
115
+ Quickly determine states using utility checkers. These accept either the full `RuntimeResponse` object, the `RuntimeState` string, or `null`/`undefined`.
116
+
117
+ ```typescript
118
+ import {
119
+ isOperational,
120
+ isMaintenance,
121
+ isDegraded,
122
+ isOutage
123
+ } from "@theruntimehq/react";
124
+
125
+ // Usage
126
+ isOperational(runtime) // returns boolean
127
+ isMaintenance(runtime) // returns boolean
128
+ isDegraded(runtime) // returns boolean
129
+ isOutage(runtime) // returns boolean
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Server Rendering (SSR) & Next.js App Router Integration
135
+
136
+ To avoid layout shifts and flashes of loading states on initial load, fetch the status server-side using the underlying `@theruntimehq/js` SDK directly, and render a static warning component on the server:
137
+
138
+ ```tsx
139
+ // src/app/page.tsx (Next.js Server Component)
140
+ import { RuntimeHQClient } from "@theruntimehq/js";
141
+ import ClientSidePoller from "./ClientSidePoller";
142
+
143
+ export default async function Page() {
144
+ const client = new RuntimeHQClient({ runtimeKey: process.env.RUNTIMEHQ_KEY! });
145
+ let initialRuntime = null;
146
+
147
+ try {
148
+ initialRuntime = await client.getRuntime();
149
+ } catch (err) {
150
+ // Fail-open: ignore server-side fetch errors during build/request
151
+ console.error("Failed to check status during SSR:", err);
152
+ }
153
+
154
+ return (
155
+ <main>
156
+ {/* 1. SSR Static Layout (Zero layout shift on load) */}
157
+ {initialRuntime && initialRuntime.state !== "OPERATIONAL" && (
158
+ <div className="banner">
159
+ ⚠️ {initialRuntime.message}
160
+ </div>
161
+ )}
162
+
163
+ {/* 2. Client Side Poller (Handles live updates) */}
164
+ <ClientSidePoller initialData={initialRuntime} />
165
+ </main>
166
+ );
167
+ }
168
+ ```
169
+
170
+ ```tsx
171
+ // src/app/ClientSidePoller.tsx (Client Component)
172
+ "use client";
173
+
174
+ import { useRuntimeHQState } from "@theruntimehq/react";
175
+ import type { RuntimeResponse } from "@theruntimehq/react";
176
+
177
+ interface ClientSidePollerProps {
178
+ initialData: RuntimeResponse | null;
179
+ }
180
+
181
+ export default function ClientSidePoller({ initialData }: ClientSidePollerProps) {
182
+ const { runtime } = useRuntimeHQState({
183
+ runtimeKey: "rt_prod_your_key_here",
184
+ intervalSeconds: 15,
185
+ });
186
+
187
+ // Hydrate client-side with server-fetched data initially
188
+ const currentRuntime = runtime || initialData;
189
+
190
+ if (!currentRuntime || currentRuntime.state === "OPERATIONAL") return null;
191
+
192
+ return (
193
+ <div className="interactive-status">
194
+ Status is {currentRuntime.state} (Polled: {runtime ? "Yes" : "No"})
195
+ </div>
196
+ );
197
+ }
198
+ ```
199
+
200
+ ## License
201
+
202
+ MIT
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+ import { RuntimeResponse, RuntimeState } from '@theruntimehq/js';
3
+ export { RuntimeHQClientOptions, RuntimeResponse, RuntimeSourceType, RuntimeState, WatchRuntimeOptions } from '@theruntimehq/js';
4
+
5
+ interface RuntimeHQProviderProps {
6
+ runtimeKey: string;
7
+ intervalSeconds?: number;
8
+ children: React.ReactNode;
9
+ }
10
+ /**
11
+ * Context Provider that manages a global RuntimeHQ client subscription and polling loop,
12
+ * making the status state available to all child components using `useRuntimeHQ()`.
13
+ */
14
+ declare function RuntimeHQProvider({ runtimeKey, intervalSeconds, children, }: RuntimeHQProviderProps): React.JSX.Element;
15
+
16
+ interface RuntimeHQContextValue {
17
+ runtime: RuntimeResponse | null;
18
+ loading: boolean;
19
+ error: Error | null;
20
+ }
21
+
22
+ /**
23
+ * Accesses the global RuntimeHQ status check context.
24
+ * Must be used within a `<RuntimeHQProvider>`.
25
+ */
26
+ declare function useRuntimeHQ(): RuntimeHQContextValue;
27
+
28
+ interface UseRuntimeHQStateOptions {
29
+ runtimeKey: string;
30
+ intervalSeconds?: number;
31
+ }
32
+ /**
33
+ * A direct React hook to fetch and watch RuntimeHQ status without using a Context Provider.
34
+ */
35
+ declare function useRuntimeHQState(options: UseRuntimeHQStateOptions): RuntimeHQContextValue;
36
+
37
+ /**
38
+ * Checks if the application runtime status is OPERATIONAL.
39
+ */
40
+ declare function isOperational(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean;
41
+ /**
42
+ * Checks if the application runtime status is MAINTENANCE.
43
+ */
44
+ declare function isMaintenance(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean;
45
+ /**
46
+ * Checks if the application runtime status is DEGRADED.
47
+ */
48
+ declare function isDegraded(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean;
49
+ /**
50
+ * Checks if the application runtime status is OUTAGE.
51
+ */
52
+ declare function isOutage(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean;
53
+
54
+ export { type RuntimeHQContextValue, RuntimeHQProvider, type RuntimeHQProviderProps, type UseRuntimeHQStateOptions, isDegraded, isMaintenance, isOperational, isOutage, useRuntimeHQ, useRuntimeHQState };
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+ import { RuntimeResponse, RuntimeState } from '@theruntimehq/js';
3
+ export { RuntimeHQClientOptions, RuntimeResponse, RuntimeSourceType, RuntimeState, WatchRuntimeOptions } from '@theruntimehq/js';
4
+
5
+ interface RuntimeHQProviderProps {
6
+ runtimeKey: string;
7
+ intervalSeconds?: number;
8
+ children: React.ReactNode;
9
+ }
10
+ /**
11
+ * Context Provider that manages a global RuntimeHQ client subscription and polling loop,
12
+ * making the status state available to all child components using `useRuntimeHQ()`.
13
+ */
14
+ declare function RuntimeHQProvider({ runtimeKey, intervalSeconds, children, }: RuntimeHQProviderProps): React.JSX.Element;
15
+
16
+ interface RuntimeHQContextValue {
17
+ runtime: RuntimeResponse | null;
18
+ loading: boolean;
19
+ error: Error | null;
20
+ }
21
+
22
+ /**
23
+ * Accesses the global RuntimeHQ status check context.
24
+ * Must be used within a `<RuntimeHQProvider>`.
25
+ */
26
+ declare function useRuntimeHQ(): RuntimeHQContextValue;
27
+
28
+ interface UseRuntimeHQStateOptions {
29
+ runtimeKey: string;
30
+ intervalSeconds?: number;
31
+ }
32
+ /**
33
+ * A direct React hook to fetch and watch RuntimeHQ status without using a Context Provider.
34
+ */
35
+ declare function useRuntimeHQState(options: UseRuntimeHQStateOptions): RuntimeHQContextValue;
36
+
37
+ /**
38
+ * Checks if the application runtime status is OPERATIONAL.
39
+ */
40
+ declare function isOperational(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean;
41
+ /**
42
+ * Checks if the application runtime status is MAINTENANCE.
43
+ */
44
+ declare function isMaintenance(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean;
45
+ /**
46
+ * Checks if the application runtime status is DEGRADED.
47
+ */
48
+ declare function isDegraded(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean;
49
+ /**
50
+ * Checks if the application runtime status is OUTAGE.
51
+ */
52
+ declare function isOutage(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean;
53
+
54
+ export { type RuntimeHQContextValue, RuntimeHQProvider, type RuntimeHQProviderProps, type UseRuntimeHQStateOptions, isDegraded, isMaintenance, isOperational, isOutage, useRuntimeHQ, useRuntimeHQState };
package/dist/index.js ADDED
@@ -0,0 +1,107 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var js = require('@theruntimehq/js');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/context/index.ts
8
+ var RuntimeHQContext = react.createContext(null);
9
+ function useRuntimeHQState(options) {
10
+ const { runtimeKey, intervalSeconds = 15 } = options;
11
+ const [client, clientInitError] = react.useMemo(() => {
12
+ if (!runtimeKey) {
13
+ return [null, new Error("runtimeKey is required")];
14
+ }
15
+ try {
16
+ return [new js.RuntimeHQClient({ runtimeKey }), null];
17
+ } catch (err) {
18
+ return [null, err instanceof Error ? err : new Error(String(err))];
19
+ }
20
+ }, [runtimeKey]);
21
+ const [runtime, setRuntime] = react.useState(null);
22
+ const [error, setError] = react.useState(clientInitError || null);
23
+ const [loading, setLoading] = react.useState(!clientInitError);
24
+ react.useEffect(() => {
25
+ if (clientInitError) {
26
+ setError(clientInitError);
27
+ setLoading(false);
28
+ return;
29
+ }
30
+ if (!client) {
31
+ return;
32
+ }
33
+ setRuntime(null);
34
+ setError(null);
35
+ setLoading(true);
36
+ let active = true;
37
+ const unsubscribe = client.watchRuntime({
38
+ intervalSeconds,
39
+ onUpdate: (data) => {
40
+ if (active) {
41
+ setRuntime(data);
42
+ setError(null);
43
+ setLoading(false);
44
+ }
45
+ },
46
+ onError: (err) => {
47
+ if (active) {
48
+ setError(err);
49
+ setLoading(false);
50
+ }
51
+ }
52
+ });
53
+ return () => {
54
+ active = false;
55
+ unsubscribe();
56
+ };
57
+ }, [client, clientInitError, intervalSeconds]);
58
+ return {
59
+ runtime,
60
+ loading,
61
+ error
62
+ };
63
+ }
64
+ function RuntimeHQProvider({
65
+ runtimeKey,
66
+ intervalSeconds,
67
+ children
68
+ }) {
69
+ const value = useRuntimeHQState({ runtimeKey, intervalSeconds });
70
+ return /* @__PURE__ */ jsxRuntime.jsx(RuntimeHQContext.Provider, { value, children });
71
+ }
72
+ function useRuntimeHQ() {
73
+ const context = react.useContext(RuntimeHQContext);
74
+ if (!context) {
75
+ throw new Error("useRuntimeHQ must be used within a RuntimeHQProvider");
76
+ }
77
+ return context;
78
+ }
79
+
80
+ // src/helpers/index.ts
81
+ function getState(runtime) {
82
+ if (!runtime) return null;
83
+ if (typeof runtime === "string") return runtime;
84
+ return runtime.state || null;
85
+ }
86
+ function isOperational(runtime) {
87
+ return getState(runtime) === "OPERATIONAL";
88
+ }
89
+ function isMaintenance(runtime) {
90
+ return getState(runtime) === "MAINTENANCE";
91
+ }
92
+ function isDegraded(runtime) {
93
+ return getState(runtime) === "DEGRADED";
94
+ }
95
+ function isOutage(runtime) {
96
+ return getState(runtime) === "OUTAGE";
97
+ }
98
+
99
+ exports.RuntimeHQProvider = RuntimeHQProvider;
100
+ exports.isDegraded = isDegraded;
101
+ exports.isMaintenance = isMaintenance;
102
+ exports.isOperational = isOperational;
103
+ exports.isOutage = isOutage;
104
+ exports.useRuntimeHQ = useRuntimeHQ;
105
+ exports.useRuntimeHQState = useRuntimeHQState;
106
+ //# sourceMappingURL=index.js.map
107
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context/index.ts","../src/hooks/useRuntimeHQState.ts","../src/provider/index.tsx","../src/hooks/useRuntimeHQ.ts","../src/helpers/index.ts"],"names":["createContext","useMemo","RuntimeHQClient","useState","useEffect","jsx","useContext"],"mappings":"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","file":"index.js","sourcesContent":["\"use client\";\n\nimport { createContext } from \"react\";\nimport { RuntimeHQContextValue } from \"../types\";\n\nexport const RuntimeHQContext = createContext<RuntimeHQContextValue | null>(null);\n","\"use client\";\n\nimport { useState, useEffect, useMemo } from \"react\";\nimport { RuntimeHQClient } from \"@theruntimehq/js\";\nimport { RuntimeResponse, RuntimeHQContextValue } from \"../types\";\n\nexport interface UseRuntimeHQStateOptions {\n runtimeKey: string;\n intervalSeconds?: number;\n}\n\n/**\n * A direct React hook to fetch and watch RuntimeHQ status without using a Context Provider.\n */\nexport function useRuntimeHQState(options: UseRuntimeHQStateOptions): RuntimeHQContextValue {\n const { runtimeKey, intervalSeconds = 15 } = options;\n\n // Safely instantiate RuntimeHQClient\n const [client, clientInitError] = useMemo(() => {\n if (!runtimeKey) {\n return [null, new Error(\"runtimeKey is required\")] as const;\n }\n try {\n return [new RuntimeHQClient({ runtimeKey }), null] as const;\n } catch (err) {\n return [null, err instanceof Error ? err : new Error(String(err))] as const;\n }\n }, [runtimeKey]);\n\n const [runtime, setRuntime] = useState<RuntimeResponse | null>(null);\n const [error, setError] = useState<Error | null>(clientInitError || null);\n const [loading, setLoading] = useState<boolean>(!clientInitError);\n\n useEffect(() => {\n if (clientInitError) {\n setError(clientInitError);\n setLoading(false);\n return;\n }\n\n if (!client) {\n return;\n }\n\n // Reset states when the client or key changes\n setRuntime(null);\n setError(null);\n setLoading(true);\n\n let active = true;\n\n const unsubscribe = client.watchRuntime({\n intervalSeconds,\n onUpdate: (data) => {\n if (active) {\n setRuntime(data);\n setError(null);\n setLoading(false);\n }\n },\n onError: (err) => {\n if (active) {\n setError(err);\n setLoading(false);\n }\n },\n });\n\n return () => {\n active = false;\n unsubscribe();\n };\n }, [client, clientInitError, intervalSeconds]);\n\n return {\n runtime,\n loading,\n error,\n };\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { RuntimeHQContext } from \"../context\";\nimport { useRuntimeHQState } from \"../hooks/useRuntimeHQState\";\n\nexport interface RuntimeHQProviderProps {\n runtimeKey: string;\n intervalSeconds?: number;\n children: React.ReactNode;\n}\n\n/**\n * Context Provider that manages a global RuntimeHQ client subscription and polling loop,\n * making the status state available to all child components using `useRuntimeHQ()`.\n */\nexport function RuntimeHQProvider({\n runtimeKey,\n intervalSeconds,\n children,\n}: RuntimeHQProviderProps) {\n const value = useRuntimeHQState({ runtimeKey, intervalSeconds });\n\n return (\n <RuntimeHQContext.Provider value={value}>\n {children}\n </RuntimeHQContext.Provider>\n );\n}\n","\"use client\";\n\nimport { useContext } from \"react\";\nimport { RuntimeHQContext } from \"../context\";\nimport { RuntimeHQContextValue } from \"../types\";\n\n/**\n * Accesses the global RuntimeHQ status check context.\n * Must be used within a `<RuntimeHQProvider>`.\n */\nexport function useRuntimeHQ(): RuntimeHQContextValue {\n const context = useContext(RuntimeHQContext);\n if (!context) {\n throw new Error(\"useRuntimeHQ must be used within a RuntimeHQProvider\");\n }\n return context;\n}\n","import { RuntimeResponse, RuntimeState } from \"../types\";\n\nfunction getState(runtime: RuntimeResponse | RuntimeState | null | undefined): RuntimeState | null {\n if (!runtime) return null;\n if (typeof runtime === \"string\") return runtime;\n return runtime.state || null;\n}\n\n/**\n * Checks if the application runtime status is OPERATIONAL.\n */\nexport function isOperational(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean {\n return getState(runtime) === \"OPERATIONAL\";\n}\n\n/**\n * Checks if the application runtime status is MAINTENANCE.\n */\nexport function isMaintenance(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean {\n return getState(runtime) === \"MAINTENANCE\";\n}\n\n/**\n * Checks if the application runtime status is DEGRADED.\n */\nexport function isDegraded(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean {\n return getState(runtime) === \"DEGRADED\";\n}\n\n/**\n * Checks if the application runtime status is OUTAGE.\n */\nexport function isOutage(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean {\n return getState(runtime) === \"OUTAGE\";\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,99 @@
1
+ import { createContext, useMemo, useState, useEffect, useContext } from 'react';
2
+ import { RuntimeHQClient } from '@theruntimehq/js';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ // src/context/index.ts
6
+ var RuntimeHQContext = createContext(null);
7
+ function useRuntimeHQState(options) {
8
+ const { runtimeKey, intervalSeconds = 15 } = options;
9
+ const [client, clientInitError] = useMemo(() => {
10
+ if (!runtimeKey) {
11
+ return [null, new Error("runtimeKey is required")];
12
+ }
13
+ try {
14
+ return [new RuntimeHQClient({ runtimeKey }), null];
15
+ } catch (err) {
16
+ return [null, err instanceof Error ? err : new Error(String(err))];
17
+ }
18
+ }, [runtimeKey]);
19
+ const [runtime, setRuntime] = useState(null);
20
+ const [error, setError] = useState(clientInitError || null);
21
+ const [loading, setLoading] = useState(!clientInitError);
22
+ useEffect(() => {
23
+ if (clientInitError) {
24
+ setError(clientInitError);
25
+ setLoading(false);
26
+ return;
27
+ }
28
+ if (!client) {
29
+ return;
30
+ }
31
+ setRuntime(null);
32
+ setError(null);
33
+ setLoading(true);
34
+ let active = true;
35
+ const unsubscribe = client.watchRuntime({
36
+ intervalSeconds,
37
+ onUpdate: (data) => {
38
+ if (active) {
39
+ setRuntime(data);
40
+ setError(null);
41
+ setLoading(false);
42
+ }
43
+ },
44
+ onError: (err) => {
45
+ if (active) {
46
+ setError(err);
47
+ setLoading(false);
48
+ }
49
+ }
50
+ });
51
+ return () => {
52
+ active = false;
53
+ unsubscribe();
54
+ };
55
+ }, [client, clientInitError, intervalSeconds]);
56
+ return {
57
+ runtime,
58
+ loading,
59
+ error
60
+ };
61
+ }
62
+ function RuntimeHQProvider({
63
+ runtimeKey,
64
+ intervalSeconds,
65
+ children
66
+ }) {
67
+ const value = useRuntimeHQState({ runtimeKey, intervalSeconds });
68
+ return /* @__PURE__ */ jsx(RuntimeHQContext.Provider, { value, children });
69
+ }
70
+ function useRuntimeHQ() {
71
+ const context = useContext(RuntimeHQContext);
72
+ if (!context) {
73
+ throw new Error("useRuntimeHQ must be used within a RuntimeHQProvider");
74
+ }
75
+ return context;
76
+ }
77
+
78
+ // src/helpers/index.ts
79
+ function getState(runtime) {
80
+ if (!runtime) return null;
81
+ if (typeof runtime === "string") return runtime;
82
+ return runtime.state || null;
83
+ }
84
+ function isOperational(runtime) {
85
+ return getState(runtime) === "OPERATIONAL";
86
+ }
87
+ function isMaintenance(runtime) {
88
+ return getState(runtime) === "MAINTENANCE";
89
+ }
90
+ function isDegraded(runtime) {
91
+ return getState(runtime) === "DEGRADED";
92
+ }
93
+ function isOutage(runtime) {
94
+ return getState(runtime) === "OUTAGE";
95
+ }
96
+
97
+ export { RuntimeHQProvider, isDegraded, isMaintenance, isOperational, isOutage, useRuntimeHQ, useRuntimeHQState };
98
+ //# sourceMappingURL=index.mjs.map
99
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context/index.ts","../src/hooks/useRuntimeHQState.ts","../src/provider/index.tsx","../src/hooks/useRuntimeHQ.ts","../src/helpers/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["\"use client\";\n\nimport { createContext } from \"react\";\nimport { RuntimeHQContextValue } from \"../types\";\n\nexport const RuntimeHQContext = createContext<RuntimeHQContextValue | null>(null);\n","\"use client\";\n\nimport { useState, useEffect, useMemo } from \"react\";\nimport { RuntimeHQClient } from \"@theruntimehq/js\";\nimport { RuntimeResponse, RuntimeHQContextValue } from \"../types\";\n\nexport interface UseRuntimeHQStateOptions {\n runtimeKey: string;\n intervalSeconds?: number;\n}\n\n/**\n * A direct React hook to fetch and watch RuntimeHQ status without using a Context Provider.\n */\nexport function useRuntimeHQState(options: UseRuntimeHQStateOptions): RuntimeHQContextValue {\n const { runtimeKey, intervalSeconds = 15 } = options;\n\n // Safely instantiate RuntimeHQClient\n const [client, clientInitError] = useMemo(() => {\n if (!runtimeKey) {\n return [null, new Error(\"runtimeKey is required\")] as const;\n }\n try {\n return [new RuntimeHQClient({ runtimeKey }), null] as const;\n } catch (err) {\n return [null, err instanceof Error ? err : new Error(String(err))] as const;\n }\n }, [runtimeKey]);\n\n const [runtime, setRuntime] = useState<RuntimeResponse | null>(null);\n const [error, setError] = useState<Error | null>(clientInitError || null);\n const [loading, setLoading] = useState<boolean>(!clientInitError);\n\n useEffect(() => {\n if (clientInitError) {\n setError(clientInitError);\n setLoading(false);\n return;\n }\n\n if (!client) {\n return;\n }\n\n // Reset states when the client or key changes\n setRuntime(null);\n setError(null);\n setLoading(true);\n\n let active = true;\n\n const unsubscribe = client.watchRuntime({\n intervalSeconds,\n onUpdate: (data) => {\n if (active) {\n setRuntime(data);\n setError(null);\n setLoading(false);\n }\n },\n onError: (err) => {\n if (active) {\n setError(err);\n setLoading(false);\n }\n },\n });\n\n return () => {\n active = false;\n unsubscribe();\n };\n }, [client, clientInitError, intervalSeconds]);\n\n return {\n runtime,\n loading,\n error,\n };\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { RuntimeHQContext } from \"../context\";\nimport { useRuntimeHQState } from \"../hooks/useRuntimeHQState\";\n\nexport interface RuntimeHQProviderProps {\n runtimeKey: string;\n intervalSeconds?: number;\n children: React.ReactNode;\n}\n\n/**\n * Context Provider that manages a global RuntimeHQ client subscription and polling loop,\n * making the status state available to all child components using `useRuntimeHQ()`.\n */\nexport function RuntimeHQProvider({\n runtimeKey,\n intervalSeconds,\n children,\n}: RuntimeHQProviderProps) {\n const value = useRuntimeHQState({ runtimeKey, intervalSeconds });\n\n return (\n <RuntimeHQContext.Provider value={value}>\n {children}\n </RuntimeHQContext.Provider>\n );\n}\n","\"use client\";\n\nimport { useContext } from \"react\";\nimport { RuntimeHQContext } from \"../context\";\nimport { RuntimeHQContextValue } from \"../types\";\n\n/**\n * Accesses the global RuntimeHQ status check context.\n * Must be used within a `<RuntimeHQProvider>`.\n */\nexport function useRuntimeHQ(): RuntimeHQContextValue {\n const context = useContext(RuntimeHQContext);\n if (!context) {\n throw new Error(\"useRuntimeHQ must be used within a RuntimeHQProvider\");\n }\n return context;\n}\n","import { RuntimeResponse, RuntimeState } from \"../types\";\n\nfunction getState(runtime: RuntimeResponse | RuntimeState | null | undefined): RuntimeState | null {\n if (!runtime) return null;\n if (typeof runtime === \"string\") return runtime;\n return runtime.state || null;\n}\n\n/**\n * Checks if the application runtime status is OPERATIONAL.\n */\nexport function isOperational(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean {\n return getState(runtime) === \"OPERATIONAL\";\n}\n\n/**\n * Checks if the application runtime status is MAINTENANCE.\n */\nexport function isMaintenance(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean {\n return getState(runtime) === \"MAINTENANCE\";\n}\n\n/**\n * Checks if the application runtime status is DEGRADED.\n */\nexport function isDegraded(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean {\n return getState(runtime) === \"DEGRADED\";\n}\n\n/**\n * Checks if the application runtime status is OUTAGE.\n */\nexport function isOutage(runtime: RuntimeResponse | RuntimeState | null | undefined): boolean {\n return getState(runtime) === \"OUTAGE\";\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@theruntimehq/react",
3
+ "version": "0.1.0",
4
+ "description": "Official React SDK for RuntimeHQ status checking and monitoring.",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "require": "./dist/index.js",
12
+ "import": "./dist/index.mjs"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "test": "vitest run",
21
+ "prepublishOnly": "npm run build"
22
+ },
23
+ "keywords": [
24
+ "runtimehq",
25
+ "status",
26
+ "monitoring",
27
+ "sdk",
28
+ "react",
29
+ "hooks"
30
+ ],
31
+ "author": "RuntimeHQ",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/TheRuntimeHQ/runtimehq-react.git"
36
+ },
37
+ "peerDependencies": {
38
+ "react": ">=18.0.0",
39
+ "react-dom": ">=18.0.0"
40
+ },
41
+ "dependencies": {
42
+ "@theruntimehq/js": "^0.1.0"
43
+ },
44
+ "devDependencies": {
45
+ "@testing-library/react": "^15.0.7",
46
+ "@types/react": "^18.2.79",
47
+ "@types/react-dom": "^18.2.25",
48
+ "jsdom": "^24.0.0",
49
+ "react": "^18.2.0",
50
+ "react-dom": "^18.2.0",
51
+ "tsup": "^8.0.2",
52
+ "typescript": "^5.4.5",
53
+ "vitest": "^1.6.0"
54
+ }
55
+ }