@runhuman/sensor 0.2.4 → 0.3.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/dist/index.mjs CHANGED
@@ -164,6 +164,8 @@ 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"),
167
169
  /** Get job status (for polling) */
168
170
  jobStatus: defineRoute("/jobs/:jobId/status"),
169
171
  /** Get individual job artifact by type */
@@ -282,6 +284,8 @@ var apiRoutes = {
282
284
  githubLink: defineRoute("/github/link"),
283
285
  /** List issues for a repo (by owner/repo) */
284
286
  githubIssuesByRepo: defineRoute("/github/issues/:owner/:repo"),
287
+ /** Get a single issue for a repo (by owner/repo/issueNumber) */
288
+ githubIssueByRepo: defineRoute("/github/issues/:owner/:repo/:issueNumber"),
285
289
  /** List issues (by projectId query param) */
286
290
  githubIssues: defineRoute("/github/issues"),
287
291
  /** Get a single issue */
@@ -436,8 +440,10 @@ var apiRoutes = {
436
440
  organizationJobs: defineRoute("/organizations/:organizationId/jobs"),
437
441
  /** Transfer organization ownership */
438
442
  organizationTransferOwnership: defineRoute("/organizations/:organizationId/transfer-ownership"),
439
- /** Create organization API key */
443
+ /** List/create organization API keys */
440
444
  organizationApiKeys: defineRoute("/organizations/:organizationId/api-keys"),
445
+ /** Get/revoke/delete a specific organization API key */
446
+ organizationApiKey: defineRoute("/organizations/:organizationId/api-keys/:keyId"),
441
447
  /** Get GitHub installations for an organization */
442
448
  organizationGitHubInstallations: defineRoute("/organizations/:organizationId/github/installations"),
443
449
  /** Get/delete specific GitHub installation for an organization */
@@ -546,7 +552,7 @@ var ApiClient = class {
546
552
  return this.get(apiRoutes.telemetrySessionStatus.build({ jobId }));
547
553
  }
548
554
  async resolveShortCode(code) {
549
- const normalized = code.replace(/^RH-/i, "").toUpperCase();
555
+ const normalized = code.toUpperCase().trim();
550
556
  try {
551
557
  return await this.get(
552
558
  apiRoutes.telemetryShortCodeResolve.build({ code: normalized })
@@ -1140,11 +1146,11 @@ var Runhuman = class _Runhuman {
1140
1146
  _Runhuman.instance = null;
1141
1147
  this.log("Destroyed");
1142
1148
  }
1143
- /** Access the session manager (used by <RunhumanOverlay /> for reactive state) */
1149
+ /** Access the session manager (used by <RunhumanProvider /> for reactive state) */
1144
1150
  getSessionManager() {
1145
1151
  return this.sessionManager;
1146
1152
  }
1147
- /** Access the API client (used by <RunhumanOverlay /> for short code resolution) */
1153
+ /** Access the API client (used by <RunhumanProvider /> for short code resolution) */
1148
1154
  getApiClient() {
1149
1155
  return this.apiClient;
1150
1156
  }
@@ -1155,7 +1161,8 @@ var Runhuman = class _Runhuman {
1155
1161
  }
1156
1162
  };
1157
1163
 
1158
- // src/overlay/RunhumanOverlay.tsx
1164
+ // src/overlay/RunhumanProvider.tsx
1165
+ import { useEffect as useEffect2, useRef as useRef3 } from "react";
1159
1166
  import { View as View2, StyleSheet as StyleSheet2 } from "react-native";
1160
1167
 
1161
1168
  // src/overlay/use-sensor-state.ts
@@ -1173,16 +1180,22 @@ function useSensorState() {
1173
1180
  const cached = useRef(IDLE_STATE);
1174
1181
  const subscribe = useCallback((onStoreChange) => {
1175
1182
  const instance = tryGetInstance();
1176
- if (!instance) {
1177
- const interval = setInterval(() => {
1178
- if (tryGetInstance()) {
1179
- clearInterval(interval);
1180
- onStoreChange();
1181
- }
1182
- }, 100);
1183
- return () => clearInterval(interval);
1183
+ if (instance) {
1184
+ return instance.getSessionManager().subscribe(onStoreChange);
1184
1185
  }
1185
- return instance.getSessionManager().subscribe(onStoreChange);
1186
+ let unsub = null;
1187
+ const interval = setInterval(() => {
1188
+ const inst = tryGetInstance();
1189
+ if (inst) {
1190
+ clearInterval(interval);
1191
+ unsub = inst.getSessionManager().subscribe(onStoreChange);
1192
+ onStoreChange();
1193
+ }
1194
+ }, 100);
1195
+ return () => {
1196
+ clearInterval(interval);
1197
+ if (unsub) unsub();
1198
+ };
1186
1199
  }, []);
1187
1200
  const getSnapshot = useCallback(() => {
1188
1201
  const instance = tryGetInstance();
@@ -1236,6 +1249,11 @@ var overlayStyles = StyleSheet.create({
1236
1249
  fontWeight: "600",
1237
1250
  marginBottom: 8
1238
1251
  },
1252
+ inputRow: {
1253
+ flexDirection: "row",
1254
+ alignItems: "center",
1255
+ gap: 6
1256
+ },
1239
1257
  input: {
1240
1258
  backgroundColor: "rgba(255, 255, 255, 0.1)",
1241
1259
  borderRadius: 8,
@@ -1249,9 +1267,25 @@ var overlayStyles = StyleSheet.create({
1249
1267
  padding: 10,
1250
1268
  textAlign: "center"
1251
1269
  },
1270
+ inputFlex: {
1271
+ flex: 1
1272
+ },
1252
1273
  inputError: {
1253
1274
  borderColor: BRAND_RED
1254
1275
  },
1276
+ pasteButton: {
1277
+ backgroundColor: "rgba(255, 255, 255, 0.1)",
1278
+ borderRadius: 8,
1279
+ borderWidth: 1,
1280
+ borderColor: OVERLAY_BORDER,
1281
+ paddingVertical: 10,
1282
+ paddingHorizontal: 8
1283
+ },
1284
+ pasteButtonText: {
1285
+ color: "rgba(255, 255, 255, 0.6)",
1286
+ fontSize: 11,
1287
+ fontWeight: "600"
1288
+ },
1255
1289
  submitButton: {
1256
1290
  backgroundColor: BRAND_BLUE,
1257
1291
  borderRadius: 8,
@@ -1318,6 +1352,14 @@ var overlayStyles = StyleSheet.create({
1318
1352
  }
1319
1353
  });
1320
1354
 
1355
+ // src/overlay/clipboard.ts
1356
+ import * as ReactNative from "react-native";
1357
+ var RN = ReactNative;
1358
+ var clipboard = RN["Clipboard"];
1359
+ async function getClipboardText() {
1360
+ return clipboard.getString();
1361
+ }
1362
+
1321
1363
  // src/overlay/CodeEntryPanel.tsx
1322
1364
  import { jsx, jsxs } from "react/jsx-runtime";
1323
1365
  function CodeEntryPanel({ position }) {
@@ -1339,29 +1381,40 @@ function CodeEntryPanel({ position }) {
1339
1381
  setResolving(false);
1340
1382
  }
1341
1383
  };
1384
+ const handlePaste = async () => {
1385
+ const text = await getClipboardText();
1386
+ const trimmed = text.trim().toUpperCase().slice(0, 6);
1387
+ if (trimmed) {
1388
+ setCode(trimmed);
1389
+ setError(null);
1390
+ }
1391
+ };
1342
1392
  if (minimized) {
1343
1393
  return /* @__PURE__ */ jsx(Pressable, { style: [overlayStyles.fab, overlayStyles[position]], onPress: () => setMinimized(false), children: /* @__PURE__ */ jsx(Text, { style: overlayStyles.fabText, children: "RH" }) });
1344
1394
  }
1345
1395
  return /* @__PURE__ */ jsxs(View, { style: [overlayStyles.panel, overlayStyles[position]], children: [
1346
1396
  /* @__PURE__ */ jsx(Pressable, { style: overlayStyles.minimizeButton, onPress: () => setMinimized(true), children: /* @__PURE__ */ jsx(Text, { style: overlayStyles.minimizeText, children: "-" }) }),
1347
1397
  /* @__PURE__ */ jsx(Text, { style: overlayStyles.panelTitle, children: "Runhuman Sensor" }),
1348
- /* @__PURE__ */ jsx(
1349
- TextInput,
1350
- {
1351
- style: error ? { ...overlayStyles.input, ...overlayStyles.inputError } : overlayStyles.input,
1352
- value: code,
1353
- onChangeText: (text) => {
1354
- setCode(text.toUpperCase());
1355
- setError(null);
1356
- },
1357
- placeholder: "RH-XXXX",
1358
- placeholderTextColor: "rgba(255,255,255,0.3)",
1359
- autoCapitalize: "characters",
1360
- maxLength: 10,
1361
- editable: !resolving,
1362
- onSubmitEditing: handleSubmit
1363
- }
1364
- ),
1398
+ /* @__PURE__ */ jsxs(View, { style: overlayStyles.inputRow, children: [
1399
+ /* @__PURE__ */ jsx(
1400
+ TextInput,
1401
+ {
1402
+ style: [error ? { ...overlayStyles.input, ...overlayStyles.inputError } : overlayStyles.input, overlayStyles.inputFlex],
1403
+ value: code,
1404
+ onChangeText: (text) => {
1405
+ setCode(text.toUpperCase());
1406
+ setError(null);
1407
+ },
1408
+ placeholder: "XXXX",
1409
+ placeholderTextColor: "rgba(255,255,255,0.3)",
1410
+ autoCapitalize: "characters",
1411
+ maxLength: 6,
1412
+ editable: !resolving,
1413
+ onSubmitEditing: handleSubmit
1414
+ }
1415
+ ),
1416
+ /* @__PURE__ */ jsx(Pressable, { style: overlayStyles.pasteButton, onPress: handlePaste, disabled: resolving, children: /* @__PURE__ */ jsx(Text, { style: overlayStyles.pasteButtonText, children: "Paste" }) })
1417
+ ] }),
1365
1418
  error ? /* @__PURE__ */ jsx(Text, { style: overlayStyles.errorText, children: error }) : null,
1366
1419
  /* @__PURE__ */ jsx(
1367
1420
  Pressable,
@@ -1404,7 +1457,7 @@ function ActiveIndicator({ state, position }) {
1404
1457
  return /* @__PURE__ */ jsx2(Animated.View, { style: [overlayStyles.indicator, overlayStyles[position], colorStyle, { opacity: pulse }] });
1405
1458
  }
1406
1459
 
1407
- // src/overlay/RunhumanOverlay.tsx
1460
+ // src/overlay/RunhumanProvider.tsx
1408
1461
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1409
1462
  var positionMap = {
1410
1463
  "top-left": "topLeft",
@@ -1412,7 +1465,40 @@ var positionMap = {
1412
1465
  "bottom-left": "bottomLeft",
1413
1466
  "bottom-right": "bottomRight"
1414
1467
  };
1415
- function RunhumanOverlay({ children, position = "bottom-right" }) {
1468
+ function RunhumanProvider({
1469
+ children,
1470
+ apiKey,
1471
+ position = "bottom-right",
1472
+ baseUrl,
1473
+ jobId,
1474
+ platform,
1475
+ flushIntervalMs,
1476
+ pollIntervalMs,
1477
+ maxBufferSize,
1478
+ enableDeepLinks,
1479
+ debug
1480
+ }) {
1481
+ const initializedRef = useRef3(false);
1482
+ useEffect2(() => {
1483
+ if (initializedRef.current) return;
1484
+ initializedRef.current = true;
1485
+ const config = {
1486
+ apiKey,
1487
+ baseUrl,
1488
+ jobId,
1489
+ platform,
1490
+ flushIntervalMs,
1491
+ pollIntervalMs,
1492
+ maxBufferSize,
1493
+ enableDeepLinks,
1494
+ debug
1495
+ };
1496
+ Runhuman.init(config);
1497
+ return () => {
1498
+ initializedRef.current = false;
1499
+ Runhuman.getInstance().destroy();
1500
+ };
1501
+ }, []);
1416
1502
  const { state, activeJobId } = useSensorState();
1417
1503
  const posKey = positionMap[position];
1418
1504
  return /* @__PURE__ */ jsxs2(View2, { style: styles.container, children: [
@@ -1428,7 +1514,7 @@ var styles = StyleSheet2.create({
1428
1514
  });
1429
1515
  export {
1430
1516
  Runhuman,
1431
- RunhumanOverlay,
1517
+ RunhumanProvider,
1432
1518
  useSensorState
1433
1519
  };
1434
1520
  //# sourceMappingURL=index.mjs.map