@runhuman/sensor 0.3.0 → 0.3.1

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/dist/index.mjs CHANGED
@@ -166,6 +166,8 @@ var apiRoutes = {
166
166
  job: defineRoute("/jobs/:jobId"),
167
167
  /** Cancel a job */
168
168
  jobCancel: defineRoute("/jobs/:jobId/cancel"),
169
+ /** Create a GitHub issue from an extracted finding (user-initiated) */
170
+ jobCreateIssue: defineRoute("/jobs/:jobId/create-issue"),
169
171
  /** Get job status (for polling) */
170
172
  jobStatus: defineRoute("/jobs/:jobId/status"),
171
173
  /** Get individual job artifact by type */
@@ -827,6 +829,7 @@ var InterceptorManager = class {
827
829
  var SessionManager = class {
828
830
  constructor(config) {
829
831
  this.state = "idle";
832
+ this._disabled = false;
830
833
  this.sessionId = null;
831
834
  this.activeJobId = null;
832
835
  this.pollTimer = null;
@@ -849,6 +852,10 @@ var SessionManager = class {
849
852
  getActiveJobId() {
850
853
  return this.activeJobId;
851
854
  }
855
+ /** True when the API rejected the session (e.g. subscription tier). Hides the overlay. */
856
+ isDisabled() {
857
+ return this._disabled;
858
+ }
852
859
  /**
853
860
  * Subscribe to state changes. Returns an unsubscribe function.
854
861
  * Compatible with React's useSyncExternalStore.
@@ -933,12 +940,22 @@ var SessionManager = class {
933
940
  async startSession() {
934
941
  this.setState("active");
935
942
  const now = /* @__PURE__ */ new Date();
936
- const response = await this.config.apiClient.createSession({
937
- jobId: this.activeJobId,
938
- platform: this.config.platform,
939
- sdkVersion: this.config.sdkVersion,
940
- clientStartTime: now.toISOString()
941
- });
943
+ let response;
944
+ try {
945
+ response = await this.config.apiClient.createSession({
946
+ jobId: this.activeJobId,
947
+ platform: this.config.platform,
948
+ sdkVersion: this.config.sdkVersion,
949
+ clientStartTime: now.toISOString()
950
+ });
951
+ } catch (error) {
952
+ const is403 = error instanceof Error && error.message.includes("403");
953
+ this.log(is403 ? "Subscription not eligible \u2014 disabling sensor" : "Session creation failed", { error });
954
+ if (is403) this._disabled = true;
955
+ this.activeJobId = null;
956
+ this.setState("idle");
957
+ return;
958
+ }
942
959
  this.sessionId = response.sessionId;
943
960
  const sessionStartTime = now.getTime();
944
961
  this.log("Session started", {
@@ -1168,7 +1185,7 @@ import { View as View2, StyleSheet as StyleSheet2 } from "react-native";
1168
1185
  // src/overlay/use-sensor-state.ts
1169
1186
  import { useCallback, useRef } from "react";
1170
1187
  import { useSyncExternalStore } from "react";
1171
- var IDLE_STATE = { state: "idle", activeJobId: null, sessionId: null };
1188
+ var IDLE_STATE = { state: "idle", activeJobId: null, sessionId: null, disabled: false };
1172
1189
  function tryGetInstance() {
1173
1190
  try {
1174
1191
  return Runhuman.getInstance();
@@ -1204,11 +1221,12 @@ function useSensorState() {
1204
1221
  const state = sm.getSnapshot();
1205
1222
  const activeJobId = sm.getActiveJobId();
1206
1223
  const sessionId = sm.getSessionId();
1224
+ const disabled = sm.isDisabled();
1207
1225
  const prev = cached.current;
1208
- if (prev.state === state && prev.activeJobId === activeJobId && prev.sessionId === sessionId) {
1226
+ if (prev.state === state && prev.activeJobId === activeJobId && prev.sessionId === sessionId && prev.disabled === disabled) {
1209
1227
  return prev;
1210
1228
  }
1211
- cached.current = { state, activeJobId, sessionId };
1229
+ cached.current = { state, activeJobId, sessionId, disabled };
1212
1230
  return cached.current;
1213
1231
  }, []);
1214
1232
  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
@@ -1372,12 +1390,18 @@ function CodeEntryPanel({ position }) {
1372
1390
  if (!trimmed) return;
1373
1391
  setResolving(true);
1374
1392
  setError(null);
1375
- const instance = Runhuman.getInstance();
1376
- const result = await instance.getApiClient().resolveShortCode(trimmed);
1377
- if (result) {
1378
- instance.activate(result.jobId);
1379
- } else {
1380
- setError("Invalid or expired code");
1393
+ try {
1394
+ const instance = Runhuman.getInstance();
1395
+ const result = await instance.getApiClient().resolveShortCode(trimmed);
1396
+ if (result) {
1397
+ await instance.activate(result.jobId);
1398
+ } else {
1399
+ setError("Invalid or expired code");
1400
+ setResolving(false);
1401
+ }
1402
+ } catch (err) {
1403
+ const message = err instanceof Error ? err.message : "Activation failed";
1404
+ setError(message);
1381
1405
  setResolving(false);
1382
1406
  }
1383
1407
  };
@@ -1468,6 +1492,7 @@ var positionMap = {
1468
1492
  function RunhumanProvider({
1469
1493
  children,
1470
1494
  apiKey,
1495
+ enabled = true,
1471
1496
  position = "bottom-right",
1472
1497
  baseUrl,
1473
1498
  jobId,
@@ -1480,7 +1505,7 @@ function RunhumanProvider({
1480
1505
  }) {
1481
1506
  const initializedRef = useRef3(false);
1482
1507
  useEffect2(() => {
1483
- if (initializedRef.current) return;
1508
+ if (!enabled || initializedRef.current) return;
1484
1509
  initializedRef.current = true;
1485
1510
  const config = {
1486
1511
  apiKey,
@@ -1498,13 +1523,14 @@ function RunhumanProvider({
1498
1523
  initializedRef.current = false;
1499
1524
  Runhuman.getInstance().destroy();
1500
1525
  };
1501
- }, []);
1502
- const { state, activeJobId } = useSensorState();
1526
+ }, [enabled]);
1527
+ const { state, activeJobId, disabled } = useSensorState();
1528
+ const showOverlay = enabled && !disabled;
1503
1529
  const posKey = positionMap[position];
1504
1530
  return /* @__PURE__ */ jsxs2(View2, { style: styles.container, children: [
1505
1531
  children,
1506
- state === "idle" && !activeJobId ? /* @__PURE__ */ jsx3(CodeEntryPanel, { position: posKey }) : null,
1507
- state !== "idle" ? /* @__PURE__ */ jsx3(ActiveIndicator, { state, position: posKey }) : null
1532
+ showOverlay && state === "idle" && !activeJobId ? /* @__PURE__ */ jsx3(CodeEntryPanel, { position: posKey }) : null,
1533
+ showOverlay && state !== "idle" ? /* @__PURE__ */ jsx3(ActiveIndicator, { state, position: posKey }) : null
1508
1534
  ] });
1509
1535
  }
1510
1536
  var styles = StyleSheet2.create({