@runhuman/sensor 0.2.5 → 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.d.mts +29 -5
- package/dist/index.d.ts +29 -5
- package/dist/index.js +160 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +149 -43
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -164,6 +164,10 @@ var apiRoutes = {
|
|
|
164
164
|
jobs: defineRoute("/jobs"),
|
|
165
165
|
/** Get/update/delete specific job */
|
|
166
166
|
job: defineRoute("/jobs/:jobId"),
|
|
167
|
+
/** Cancel a job */
|
|
168
|
+
jobCancel: defineRoute("/jobs/:jobId/cancel"),
|
|
169
|
+
/** Create a GitHub issue from an extracted finding (user-initiated) */
|
|
170
|
+
jobCreateIssue: defineRoute("/jobs/:jobId/create-issue"),
|
|
167
171
|
/** Get job status (for polling) */
|
|
168
172
|
jobStatus: defineRoute("/jobs/:jobId/status"),
|
|
169
173
|
/** Get individual job artifact by type */
|
|
@@ -282,6 +286,8 @@ var apiRoutes = {
|
|
|
282
286
|
githubLink: defineRoute("/github/link"),
|
|
283
287
|
/** List issues for a repo (by owner/repo) */
|
|
284
288
|
githubIssuesByRepo: defineRoute("/github/issues/:owner/:repo"),
|
|
289
|
+
/** Get a single issue for a repo (by owner/repo/issueNumber) */
|
|
290
|
+
githubIssueByRepo: defineRoute("/github/issues/:owner/:repo/:issueNumber"),
|
|
285
291
|
/** List issues (by projectId query param) */
|
|
286
292
|
githubIssues: defineRoute("/github/issues"),
|
|
287
293
|
/** Get a single issue */
|
|
@@ -436,8 +442,10 @@ var apiRoutes = {
|
|
|
436
442
|
organizationJobs: defineRoute("/organizations/:organizationId/jobs"),
|
|
437
443
|
/** Transfer organization ownership */
|
|
438
444
|
organizationTransferOwnership: defineRoute("/organizations/:organizationId/transfer-ownership"),
|
|
439
|
-
/**
|
|
445
|
+
/** List/create organization API keys */
|
|
440
446
|
organizationApiKeys: defineRoute("/organizations/:organizationId/api-keys"),
|
|
447
|
+
/** Get/revoke/delete a specific organization API key */
|
|
448
|
+
organizationApiKey: defineRoute("/organizations/:organizationId/api-keys/:keyId"),
|
|
441
449
|
/** Get GitHub installations for an organization */
|
|
442
450
|
organizationGitHubInstallations: defineRoute("/organizations/:organizationId/github/installations"),
|
|
443
451
|
/** Get/delete specific GitHub installation for an organization */
|
|
@@ -546,7 +554,7 @@ var ApiClient = class {
|
|
|
546
554
|
return this.get(apiRoutes.telemetrySessionStatus.build({ jobId }));
|
|
547
555
|
}
|
|
548
556
|
async resolveShortCode(code) {
|
|
549
|
-
const normalized = code.
|
|
557
|
+
const normalized = code.toUpperCase().trim();
|
|
550
558
|
try {
|
|
551
559
|
return await this.get(
|
|
552
560
|
apiRoutes.telemetryShortCodeResolve.build({ code: normalized })
|
|
@@ -821,6 +829,7 @@ var InterceptorManager = class {
|
|
|
821
829
|
var SessionManager = class {
|
|
822
830
|
constructor(config) {
|
|
823
831
|
this.state = "idle";
|
|
832
|
+
this._disabled = false;
|
|
824
833
|
this.sessionId = null;
|
|
825
834
|
this.activeJobId = null;
|
|
826
835
|
this.pollTimer = null;
|
|
@@ -843,6 +852,10 @@ var SessionManager = class {
|
|
|
843
852
|
getActiveJobId() {
|
|
844
853
|
return this.activeJobId;
|
|
845
854
|
}
|
|
855
|
+
/** True when the API rejected the session (e.g. subscription tier). Hides the overlay. */
|
|
856
|
+
isDisabled() {
|
|
857
|
+
return this._disabled;
|
|
858
|
+
}
|
|
846
859
|
/**
|
|
847
860
|
* Subscribe to state changes. Returns an unsubscribe function.
|
|
848
861
|
* Compatible with React's useSyncExternalStore.
|
|
@@ -927,12 +940,22 @@ var SessionManager = class {
|
|
|
927
940
|
async startSession() {
|
|
928
941
|
this.setState("active");
|
|
929
942
|
const now = /* @__PURE__ */ new Date();
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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
|
+
}
|
|
936
959
|
this.sessionId = response.sessionId;
|
|
937
960
|
const sessionStartTime = now.getTime();
|
|
938
961
|
this.log("Session started", {
|
|
@@ -1140,11 +1163,11 @@ var Runhuman = class _Runhuman {
|
|
|
1140
1163
|
_Runhuman.instance = null;
|
|
1141
1164
|
this.log("Destroyed");
|
|
1142
1165
|
}
|
|
1143
|
-
/** Access the session manager (used by <
|
|
1166
|
+
/** Access the session manager (used by <RunhumanProvider /> for reactive state) */
|
|
1144
1167
|
getSessionManager() {
|
|
1145
1168
|
return this.sessionManager;
|
|
1146
1169
|
}
|
|
1147
|
-
/** Access the API client (used by <
|
|
1170
|
+
/** Access the API client (used by <RunhumanProvider /> for short code resolution) */
|
|
1148
1171
|
getApiClient() {
|
|
1149
1172
|
return this.apiClient;
|
|
1150
1173
|
}
|
|
@@ -1155,13 +1178,14 @@ var Runhuman = class _Runhuman {
|
|
|
1155
1178
|
}
|
|
1156
1179
|
};
|
|
1157
1180
|
|
|
1158
|
-
// src/overlay/
|
|
1181
|
+
// src/overlay/RunhumanProvider.tsx
|
|
1182
|
+
import { useEffect as useEffect2, useRef as useRef3 } from "react";
|
|
1159
1183
|
import { View as View2, StyleSheet as StyleSheet2 } from "react-native";
|
|
1160
1184
|
|
|
1161
1185
|
// src/overlay/use-sensor-state.ts
|
|
1162
1186
|
import { useCallback, useRef } from "react";
|
|
1163
1187
|
import { useSyncExternalStore } from "react";
|
|
1164
|
-
var IDLE_STATE = { state: "idle", activeJobId: null, sessionId: null };
|
|
1188
|
+
var IDLE_STATE = { state: "idle", activeJobId: null, sessionId: null, disabled: false };
|
|
1165
1189
|
function tryGetInstance() {
|
|
1166
1190
|
try {
|
|
1167
1191
|
return Runhuman.getInstance();
|
|
@@ -1197,11 +1221,12 @@ function useSensorState() {
|
|
|
1197
1221
|
const state = sm.getSnapshot();
|
|
1198
1222
|
const activeJobId = sm.getActiveJobId();
|
|
1199
1223
|
const sessionId = sm.getSessionId();
|
|
1224
|
+
const disabled = sm.isDisabled();
|
|
1200
1225
|
const prev = cached.current;
|
|
1201
|
-
if (prev.state === state && prev.activeJobId === activeJobId && prev.sessionId === sessionId) {
|
|
1226
|
+
if (prev.state === state && prev.activeJobId === activeJobId && prev.sessionId === sessionId && prev.disabled === disabled) {
|
|
1202
1227
|
return prev;
|
|
1203
1228
|
}
|
|
1204
|
-
cached.current = { state, activeJobId, sessionId };
|
|
1229
|
+
cached.current = { state, activeJobId, sessionId, disabled };
|
|
1205
1230
|
return cached.current;
|
|
1206
1231
|
}, []);
|
|
1207
1232
|
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
@@ -1242,6 +1267,11 @@ var overlayStyles = StyleSheet.create({
|
|
|
1242
1267
|
fontWeight: "600",
|
|
1243
1268
|
marginBottom: 8
|
|
1244
1269
|
},
|
|
1270
|
+
inputRow: {
|
|
1271
|
+
flexDirection: "row",
|
|
1272
|
+
alignItems: "center",
|
|
1273
|
+
gap: 6
|
|
1274
|
+
},
|
|
1245
1275
|
input: {
|
|
1246
1276
|
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
|
1247
1277
|
borderRadius: 8,
|
|
@@ -1255,9 +1285,25 @@ var overlayStyles = StyleSheet.create({
|
|
|
1255
1285
|
padding: 10,
|
|
1256
1286
|
textAlign: "center"
|
|
1257
1287
|
},
|
|
1288
|
+
inputFlex: {
|
|
1289
|
+
flex: 1
|
|
1290
|
+
},
|
|
1258
1291
|
inputError: {
|
|
1259
1292
|
borderColor: BRAND_RED
|
|
1260
1293
|
},
|
|
1294
|
+
pasteButton: {
|
|
1295
|
+
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
|
1296
|
+
borderRadius: 8,
|
|
1297
|
+
borderWidth: 1,
|
|
1298
|
+
borderColor: OVERLAY_BORDER,
|
|
1299
|
+
paddingVertical: 10,
|
|
1300
|
+
paddingHorizontal: 8
|
|
1301
|
+
},
|
|
1302
|
+
pasteButtonText: {
|
|
1303
|
+
color: "rgba(255, 255, 255, 0.6)",
|
|
1304
|
+
fontSize: 11,
|
|
1305
|
+
fontWeight: "600"
|
|
1306
|
+
},
|
|
1261
1307
|
submitButton: {
|
|
1262
1308
|
backgroundColor: BRAND_BLUE,
|
|
1263
1309
|
borderRadius: 8,
|
|
@@ -1324,6 +1370,14 @@ var overlayStyles = StyleSheet.create({
|
|
|
1324
1370
|
}
|
|
1325
1371
|
});
|
|
1326
1372
|
|
|
1373
|
+
// src/overlay/clipboard.ts
|
|
1374
|
+
import * as ReactNative from "react-native";
|
|
1375
|
+
var RN = ReactNative;
|
|
1376
|
+
var clipboard = RN["Clipboard"];
|
|
1377
|
+
async function getClipboardText() {
|
|
1378
|
+
return clipboard.getString();
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1327
1381
|
// src/overlay/CodeEntryPanel.tsx
|
|
1328
1382
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1329
1383
|
function CodeEntryPanel({ position }) {
|
|
@@ -1336,38 +1390,55 @@ function CodeEntryPanel({ position }) {
|
|
|
1336
1390
|
if (!trimmed) return;
|
|
1337
1391
|
setResolving(true);
|
|
1338
1392
|
setError(null);
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
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);
|
|
1345
1405
|
setResolving(false);
|
|
1346
1406
|
}
|
|
1347
1407
|
};
|
|
1408
|
+
const handlePaste = async () => {
|
|
1409
|
+
const text = await getClipboardText();
|
|
1410
|
+
const trimmed = text.trim().toUpperCase().slice(0, 6);
|
|
1411
|
+
if (trimmed) {
|
|
1412
|
+
setCode(trimmed);
|
|
1413
|
+
setError(null);
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1348
1416
|
if (minimized) {
|
|
1349
1417
|
return /* @__PURE__ */ jsx(Pressable, { style: [overlayStyles.fab, overlayStyles[position]], onPress: () => setMinimized(false), children: /* @__PURE__ */ jsx(Text, { style: overlayStyles.fabText, children: "RH" }) });
|
|
1350
1418
|
}
|
|
1351
1419
|
return /* @__PURE__ */ jsxs(View, { style: [overlayStyles.panel, overlayStyles[position]], children: [
|
|
1352
1420
|
/* @__PURE__ */ jsx(Pressable, { style: overlayStyles.minimizeButton, onPress: () => setMinimized(true), children: /* @__PURE__ */ jsx(Text, { style: overlayStyles.minimizeText, children: "-" }) }),
|
|
1353
1421
|
/* @__PURE__ */ jsx(Text, { style: overlayStyles.panelTitle, children: "Runhuman Sensor" }),
|
|
1354
|
-
/* @__PURE__ */
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1422
|
+
/* @__PURE__ */ jsxs(View, { style: overlayStyles.inputRow, children: [
|
|
1423
|
+
/* @__PURE__ */ jsx(
|
|
1424
|
+
TextInput,
|
|
1425
|
+
{
|
|
1426
|
+
style: [error ? { ...overlayStyles.input, ...overlayStyles.inputError } : overlayStyles.input, overlayStyles.inputFlex],
|
|
1427
|
+
value: code,
|
|
1428
|
+
onChangeText: (text) => {
|
|
1429
|
+
setCode(text.toUpperCase());
|
|
1430
|
+
setError(null);
|
|
1431
|
+
},
|
|
1432
|
+
placeholder: "XXXX",
|
|
1433
|
+
placeholderTextColor: "rgba(255,255,255,0.3)",
|
|
1434
|
+
autoCapitalize: "characters",
|
|
1435
|
+
maxLength: 6,
|
|
1436
|
+
editable: !resolving,
|
|
1437
|
+
onSubmitEditing: handleSubmit
|
|
1438
|
+
}
|
|
1439
|
+
),
|
|
1440
|
+
/* @__PURE__ */ jsx(Pressable, { style: overlayStyles.pasteButton, onPress: handlePaste, disabled: resolving, children: /* @__PURE__ */ jsx(Text, { style: overlayStyles.pasteButtonText, children: "Paste" }) })
|
|
1441
|
+
] }),
|
|
1371
1442
|
error ? /* @__PURE__ */ jsx(Text, { style: overlayStyles.errorText, children: error }) : null,
|
|
1372
1443
|
/* @__PURE__ */ jsx(
|
|
1373
1444
|
Pressable,
|
|
@@ -1410,7 +1481,7 @@ function ActiveIndicator({ state, position }) {
|
|
|
1410
1481
|
return /* @__PURE__ */ jsx2(Animated.View, { style: [overlayStyles.indicator, overlayStyles[position], colorStyle, { opacity: pulse }] });
|
|
1411
1482
|
}
|
|
1412
1483
|
|
|
1413
|
-
// src/overlay/
|
|
1484
|
+
// src/overlay/RunhumanProvider.tsx
|
|
1414
1485
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1415
1486
|
var positionMap = {
|
|
1416
1487
|
"top-left": "topLeft",
|
|
@@ -1418,13 +1489,48 @@ var positionMap = {
|
|
|
1418
1489
|
"bottom-left": "bottomLeft",
|
|
1419
1490
|
"bottom-right": "bottomRight"
|
|
1420
1491
|
};
|
|
1421
|
-
function
|
|
1422
|
-
|
|
1492
|
+
function RunhumanProvider({
|
|
1493
|
+
children,
|
|
1494
|
+
apiKey,
|
|
1495
|
+
enabled = true,
|
|
1496
|
+
position = "bottom-right",
|
|
1497
|
+
baseUrl,
|
|
1498
|
+
jobId,
|
|
1499
|
+
platform,
|
|
1500
|
+
flushIntervalMs,
|
|
1501
|
+
pollIntervalMs,
|
|
1502
|
+
maxBufferSize,
|
|
1503
|
+
enableDeepLinks,
|
|
1504
|
+
debug
|
|
1505
|
+
}) {
|
|
1506
|
+
const initializedRef = useRef3(false);
|
|
1507
|
+
useEffect2(() => {
|
|
1508
|
+
if (!enabled || initializedRef.current) return;
|
|
1509
|
+
initializedRef.current = true;
|
|
1510
|
+
const config = {
|
|
1511
|
+
apiKey,
|
|
1512
|
+
baseUrl,
|
|
1513
|
+
jobId,
|
|
1514
|
+
platform,
|
|
1515
|
+
flushIntervalMs,
|
|
1516
|
+
pollIntervalMs,
|
|
1517
|
+
maxBufferSize,
|
|
1518
|
+
enableDeepLinks,
|
|
1519
|
+
debug
|
|
1520
|
+
};
|
|
1521
|
+
Runhuman.init(config);
|
|
1522
|
+
return () => {
|
|
1523
|
+
initializedRef.current = false;
|
|
1524
|
+
Runhuman.getInstance().destroy();
|
|
1525
|
+
};
|
|
1526
|
+
}, [enabled]);
|
|
1527
|
+
const { state, activeJobId, disabled } = useSensorState();
|
|
1528
|
+
const showOverlay = enabled && !disabled;
|
|
1423
1529
|
const posKey = positionMap[position];
|
|
1424
1530
|
return /* @__PURE__ */ jsxs2(View2, { style: styles.container, children: [
|
|
1425
1531
|
children,
|
|
1426
|
-
state === "idle" && !activeJobId ? /* @__PURE__ */ jsx3(CodeEntryPanel, { position: posKey }) : null,
|
|
1427
|
-
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
|
|
1428
1534
|
] });
|
|
1429
1535
|
}
|
|
1430
1536
|
var styles = StyleSheet2.create({
|
|
@@ -1434,7 +1540,7 @@ var styles = StyleSheet2.create({
|
|
|
1434
1540
|
});
|
|
1435
1541
|
export {
|
|
1436
1542
|
Runhuman,
|
|
1437
|
-
|
|
1543
|
+
RunhumanProvider,
|
|
1438
1544
|
useSensorState
|
|
1439
1545
|
};
|
|
1440
1546
|
//# sourceMappingURL=index.mjs.map
|