@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.d.mts CHANGED
@@ -168,20 +168,38 @@ declare class Runhuman {
168
168
  * After calling destroy(), you can call init() again.
169
169
  */
170
170
  destroy(): Promise<void>;
171
- /** Access the session manager (used by <RunhumanOverlay /> for reactive state) */
171
+ /** Access the session manager (used by <RunhumanProvider /> for reactive state) */
172
172
  getSessionManager(): SessionManager;
173
- /** Access the API client (used by <RunhumanOverlay /> for short code resolution) */
173
+ /** Access the API client (used by <RunhumanProvider /> for short code resolution) */
174
174
  getApiClient(): ApiClient;
175
175
  private log;
176
176
  }
177
177
 
178
178
  type OverlayPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
179
- interface RunhumanOverlayProps {
179
+ interface RunhumanProviderProps {
180
180
  children: React.ReactNode;
181
+ /** API key for authentication (e.g., 'rh_...') */
182
+ apiKey: string;
181
183
  /** Corner for the overlay UI (default: 'bottom-right') */
182
184
  position?: OverlayPosition;
185
+ /** Base URL of the Runhuman API (defaults to production) */
186
+ baseUrl?: string;
187
+ /** Job ID if known upfront (e.g., from deep link params at app launch) */
188
+ jobId?: string;
189
+ /** Target platform (defaults to 'react-native') */
190
+ platform?: TelemetryPlatform;
191
+ /** How often to flush buffered events in ms (default: 5000) */
192
+ flushIntervalMs?: number;
193
+ /** How often to poll for job status in ms (default: 10000) */
194
+ pollIntervalMs?: number;
195
+ /** Max events in the ring buffer before FIFO eviction (default: 1000) */
196
+ maxBufferSize?: number;
197
+ /** Enable deep link activation (default: true) */
198
+ enableDeepLinks?: boolean;
199
+ /** Log debug info to console (default: false) */
200
+ debug?: boolean;
183
201
  }
184
- declare function RunhumanOverlay({ children, position }: RunhumanOverlayProps): react_jsx_runtime.JSX.Element;
202
+ declare function RunhumanProvider({ children, apiKey, position, baseUrl, jobId, platform, flushIntervalMs, pollIntervalMs, maxBufferSize, enableDeepLinks, debug, }: RunhumanProviderProps): react_jsx_runtime.JSX.Element;
185
203
 
186
204
  /**
187
205
  * React hook for subscribing to sensor state changes.
@@ -199,4 +217,4 @@ interface SensorState {
199
217
  */
200
218
  declare function useSensorState(): SensorState;
201
219
 
202
- export { ApiClient, type OverlayPosition, Runhuman, type RunhumanConfig, RunhumanOverlay, type RunhumanOverlayProps, type SensorState, type SessionState, useSensorState };
220
+ export { ApiClient, type OverlayPosition, Runhuman, type RunhumanConfig, RunhumanProvider, type RunhumanProviderProps, type SensorState, type SessionState, useSensorState };
package/dist/index.d.ts CHANGED
@@ -168,20 +168,38 @@ declare class Runhuman {
168
168
  * After calling destroy(), you can call init() again.
169
169
  */
170
170
  destroy(): Promise<void>;
171
- /** Access the session manager (used by <RunhumanOverlay /> for reactive state) */
171
+ /** Access the session manager (used by <RunhumanProvider /> for reactive state) */
172
172
  getSessionManager(): SessionManager;
173
- /** Access the API client (used by <RunhumanOverlay /> for short code resolution) */
173
+ /** Access the API client (used by <RunhumanProvider /> for short code resolution) */
174
174
  getApiClient(): ApiClient;
175
175
  private log;
176
176
  }
177
177
 
178
178
  type OverlayPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
179
- interface RunhumanOverlayProps {
179
+ interface RunhumanProviderProps {
180
180
  children: React.ReactNode;
181
+ /** API key for authentication (e.g., 'rh_...') */
182
+ apiKey: string;
181
183
  /** Corner for the overlay UI (default: 'bottom-right') */
182
184
  position?: OverlayPosition;
185
+ /** Base URL of the Runhuman API (defaults to production) */
186
+ baseUrl?: string;
187
+ /** Job ID if known upfront (e.g., from deep link params at app launch) */
188
+ jobId?: string;
189
+ /** Target platform (defaults to 'react-native') */
190
+ platform?: TelemetryPlatform;
191
+ /** How often to flush buffered events in ms (default: 5000) */
192
+ flushIntervalMs?: number;
193
+ /** How often to poll for job status in ms (default: 10000) */
194
+ pollIntervalMs?: number;
195
+ /** Max events in the ring buffer before FIFO eviction (default: 1000) */
196
+ maxBufferSize?: number;
197
+ /** Enable deep link activation (default: true) */
198
+ enableDeepLinks?: boolean;
199
+ /** Log debug info to console (default: false) */
200
+ debug?: boolean;
183
201
  }
184
- declare function RunhumanOverlay({ children, position }: RunhumanOverlayProps): react_jsx_runtime.JSX.Element;
202
+ declare function RunhumanProvider({ children, apiKey, position, baseUrl, jobId, platform, flushIntervalMs, pollIntervalMs, maxBufferSize, enableDeepLinks, debug, }: RunhumanProviderProps): react_jsx_runtime.JSX.Element;
185
203
 
186
204
  /**
187
205
  * React hook for subscribing to sensor state changes.
@@ -199,4 +217,4 @@ interface SensorState {
199
217
  */
200
218
  declare function useSensorState(): SensorState;
201
219
 
202
- export { ApiClient, type OverlayPosition, Runhuman, type RunhumanConfig, RunhumanOverlay, type RunhumanOverlayProps, type SensorState, type SessionState, useSensorState };
220
+ export { ApiClient, type OverlayPosition, Runhuman, type RunhumanConfig, RunhumanProvider, type RunhumanProviderProps, type SensorState, type SessionState, useSensorState };
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,13 +17,21 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
23
33
  Runhuman: () => Runhuman,
24
- RunhumanOverlay: () => RunhumanOverlay,
34
+ RunhumanProvider: () => RunhumanProvider,
25
35
  useSensorState: () => useSensorState
26
36
  });
27
37
  module.exports = __toCommonJS(index_exports);
@@ -185,6 +195,8 @@ var apiRoutes = {
185
195
  jobs: defineRoute("/jobs"),
186
196
  /** Get/update/delete specific job */
187
197
  job: defineRoute("/jobs/:jobId"),
198
+ /** Cancel a job */
199
+ jobCancel: defineRoute("/jobs/:jobId/cancel"),
188
200
  /** Get job status (for polling) */
189
201
  jobStatus: defineRoute("/jobs/:jobId/status"),
190
202
  /** Get individual job artifact by type */
@@ -303,6 +315,8 @@ var apiRoutes = {
303
315
  githubLink: defineRoute("/github/link"),
304
316
  /** List issues for a repo (by owner/repo) */
305
317
  githubIssuesByRepo: defineRoute("/github/issues/:owner/:repo"),
318
+ /** Get a single issue for a repo (by owner/repo/issueNumber) */
319
+ githubIssueByRepo: defineRoute("/github/issues/:owner/:repo/:issueNumber"),
306
320
  /** List issues (by projectId query param) */
307
321
  githubIssues: defineRoute("/github/issues"),
308
322
  /** Get a single issue */
@@ -457,8 +471,10 @@ var apiRoutes = {
457
471
  organizationJobs: defineRoute("/organizations/:organizationId/jobs"),
458
472
  /** Transfer organization ownership */
459
473
  organizationTransferOwnership: defineRoute("/organizations/:organizationId/transfer-ownership"),
460
- /** Create organization API key */
474
+ /** List/create organization API keys */
461
475
  organizationApiKeys: defineRoute("/organizations/:organizationId/api-keys"),
476
+ /** Get/revoke/delete a specific organization API key */
477
+ organizationApiKey: defineRoute("/organizations/:organizationId/api-keys/:keyId"),
462
478
  /** Get GitHub installations for an organization */
463
479
  organizationGitHubInstallations: defineRoute("/organizations/:organizationId/github/installations"),
464
480
  /** Get/delete specific GitHub installation for an organization */
@@ -567,7 +583,7 @@ var ApiClient = class {
567
583
  return this.get(apiRoutes.telemetrySessionStatus.build({ jobId }));
568
584
  }
569
585
  async resolveShortCode(code) {
570
- const normalized = code.replace(/^RH-/i, "").toUpperCase();
586
+ const normalized = code.toUpperCase().trim();
571
587
  try {
572
588
  return await this.get(
573
589
  apiRoutes.telemetryShortCodeResolve.build({ code: normalized })
@@ -1161,11 +1177,11 @@ var Runhuman = class _Runhuman {
1161
1177
  _Runhuman.instance = null;
1162
1178
  this.log("Destroyed");
1163
1179
  }
1164
- /** Access the session manager (used by <RunhumanOverlay /> for reactive state) */
1180
+ /** Access the session manager (used by <RunhumanProvider /> for reactive state) */
1165
1181
  getSessionManager() {
1166
1182
  return this.sessionManager;
1167
1183
  }
1168
- /** Access the API client (used by <RunhumanOverlay /> for short code resolution) */
1184
+ /** Access the API client (used by <RunhumanProvider /> for short code resolution) */
1169
1185
  getApiClient() {
1170
1186
  return this.apiClient;
1171
1187
  }
@@ -1176,7 +1192,8 @@ var Runhuman = class _Runhuman {
1176
1192
  }
1177
1193
  };
1178
1194
 
1179
- // src/overlay/RunhumanOverlay.tsx
1195
+ // src/overlay/RunhumanProvider.tsx
1196
+ var import_react5 = require("react");
1180
1197
  var import_react_native4 = require("react-native");
1181
1198
 
1182
1199
  // src/overlay/use-sensor-state.ts
@@ -1194,16 +1211,22 @@ function useSensorState() {
1194
1211
  const cached = (0, import_react.useRef)(IDLE_STATE);
1195
1212
  const subscribe = (0, import_react.useCallback)((onStoreChange) => {
1196
1213
  const instance = tryGetInstance();
1197
- if (!instance) {
1198
- const interval = setInterval(() => {
1199
- if (tryGetInstance()) {
1200
- clearInterval(interval);
1201
- onStoreChange();
1202
- }
1203
- }, 100);
1204
- return () => clearInterval(interval);
1214
+ if (instance) {
1215
+ return instance.getSessionManager().subscribe(onStoreChange);
1205
1216
  }
1206
- return instance.getSessionManager().subscribe(onStoreChange);
1217
+ let unsub = null;
1218
+ const interval = setInterval(() => {
1219
+ const inst = tryGetInstance();
1220
+ if (inst) {
1221
+ clearInterval(interval);
1222
+ unsub = inst.getSessionManager().subscribe(onStoreChange);
1223
+ onStoreChange();
1224
+ }
1225
+ }, 100);
1226
+ return () => {
1227
+ clearInterval(interval);
1228
+ if (unsub) unsub();
1229
+ };
1207
1230
  }, []);
1208
1231
  const getSnapshot = (0, import_react.useCallback)(() => {
1209
1232
  const instance = tryGetInstance();
@@ -1257,6 +1280,11 @@ var overlayStyles = import_react_native.StyleSheet.create({
1257
1280
  fontWeight: "600",
1258
1281
  marginBottom: 8
1259
1282
  },
1283
+ inputRow: {
1284
+ flexDirection: "row",
1285
+ alignItems: "center",
1286
+ gap: 6
1287
+ },
1260
1288
  input: {
1261
1289
  backgroundColor: "rgba(255, 255, 255, 0.1)",
1262
1290
  borderRadius: 8,
@@ -1270,9 +1298,25 @@ var overlayStyles = import_react_native.StyleSheet.create({
1270
1298
  padding: 10,
1271
1299
  textAlign: "center"
1272
1300
  },
1301
+ inputFlex: {
1302
+ flex: 1
1303
+ },
1273
1304
  inputError: {
1274
1305
  borderColor: BRAND_RED
1275
1306
  },
1307
+ pasteButton: {
1308
+ backgroundColor: "rgba(255, 255, 255, 0.1)",
1309
+ borderRadius: 8,
1310
+ borderWidth: 1,
1311
+ borderColor: OVERLAY_BORDER,
1312
+ paddingVertical: 10,
1313
+ paddingHorizontal: 8
1314
+ },
1315
+ pasteButtonText: {
1316
+ color: "rgba(255, 255, 255, 0.6)",
1317
+ fontSize: 11,
1318
+ fontWeight: "600"
1319
+ },
1276
1320
  submitButton: {
1277
1321
  backgroundColor: BRAND_BLUE,
1278
1322
  borderRadius: 8,
@@ -1339,6 +1383,14 @@ var overlayStyles = import_react_native.StyleSheet.create({
1339
1383
  }
1340
1384
  });
1341
1385
 
1386
+ // src/overlay/clipboard.ts
1387
+ var ReactNative = __toESM(require("react-native"));
1388
+ var RN = ReactNative;
1389
+ var clipboard = RN["Clipboard"];
1390
+ async function getClipboardText() {
1391
+ return clipboard.getString();
1392
+ }
1393
+
1342
1394
  // src/overlay/CodeEntryPanel.tsx
1343
1395
  var import_jsx_runtime = require("react/jsx-runtime");
1344
1396
  function CodeEntryPanel({ position }) {
@@ -1360,29 +1412,40 @@ function CodeEntryPanel({ position }) {
1360
1412
  setResolving(false);
1361
1413
  }
1362
1414
  };
1415
+ const handlePaste = async () => {
1416
+ const text = await getClipboardText();
1417
+ const trimmed = text.trim().toUpperCase().slice(0, 6);
1418
+ if (trimmed) {
1419
+ setCode(trimmed);
1420
+ setError(null);
1421
+ }
1422
+ };
1363
1423
  if (minimized) {
1364
1424
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { style: [overlayStyles.fab, overlayStyles[position]], onPress: () => setMinimized(false), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: overlayStyles.fabText, children: "RH" }) });
1365
1425
  }
1366
1426
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: [overlayStyles.panel, overlayStyles[position]], children: [
1367
1427
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { style: overlayStyles.minimizeButton, onPress: () => setMinimized(true), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: overlayStyles.minimizeText, children: "-" }) }),
1368
1428
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: overlayStyles.panelTitle, children: "Runhuman Sensor" }),
1369
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1370
- import_react_native2.TextInput,
1371
- {
1372
- style: error ? { ...overlayStyles.input, ...overlayStyles.inputError } : overlayStyles.input,
1373
- value: code,
1374
- onChangeText: (text) => {
1375
- setCode(text.toUpperCase());
1376
- setError(null);
1377
- },
1378
- placeholder: "RH-XXXX",
1379
- placeholderTextColor: "rgba(255,255,255,0.3)",
1380
- autoCapitalize: "characters",
1381
- maxLength: 10,
1382
- editable: !resolving,
1383
- onSubmitEditing: handleSubmit
1384
- }
1385
- ),
1429
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: overlayStyles.inputRow, children: [
1430
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1431
+ import_react_native2.TextInput,
1432
+ {
1433
+ style: [error ? { ...overlayStyles.input, ...overlayStyles.inputError } : overlayStyles.input, overlayStyles.inputFlex],
1434
+ value: code,
1435
+ onChangeText: (text) => {
1436
+ setCode(text.toUpperCase());
1437
+ setError(null);
1438
+ },
1439
+ placeholder: "XXXX",
1440
+ placeholderTextColor: "rgba(255,255,255,0.3)",
1441
+ autoCapitalize: "characters",
1442
+ maxLength: 6,
1443
+ editable: !resolving,
1444
+ onSubmitEditing: handleSubmit
1445
+ }
1446
+ ),
1447
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { style: overlayStyles.pasteButton, onPress: handlePaste, disabled: resolving, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: overlayStyles.pasteButtonText, children: "Paste" }) })
1448
+ ] }),
1386
1449
  error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: overlayStyles.errorText, children: error }) : null,
1387
1450
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1388
1451
  import_react_native2.Pressable,
@@ -1425,7 +1488,7 @@ function ActiveIndicator({ state, position }) {
1425
1488
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Animated.View, { style: [overlayStyles.indicator, overlayStyles[position], colorStyle, { opacity: pulse }] });
1426
1489
  }
1427
1490
 
1428
- // src/overlay/RunhumanOverlay.tsx
1491
+ // src/overlay/RunhumanProvider.tsx
1429
1492
  var import_jsx_runtime3 = require("react/jsx-runtime");
1430
1493
  var positionMap = {
1431
1494
  "top-left": "topLeft",
@@ -1433,7 +1496,40 @@ var positionMap = {
1433
1496
  "bottom-left": "bottomLeft",
1434
1497
  "bottom-right": "bottomRight"
1435
1498
  };
1436
- function RunhumanOverlay({ children, position = "bottom-right" }) {
1499
+ function RunhumanProvider({
1500
+ children,
1501
+ apiKey,
1502
+ position = "bottom-right",
1503
+ baseUrl,
1504
+ jobId,
1505
+ platform,
1506
+ flushIntervalMs,
1507
+ pollIntervalMs,
1508
+ maxBufferSize,
1509
+ enableDeepLinks,
1510
+ debug
1511
+ }) {
1512
+ const initializedRef = (0, import_react5.useRef)(false);
1513
+ (0, import_react5.useEffect)(() => {
1514
+ if (initializedRef.current) return;
1515
+ initializedRef.current = true;
1516
+ const config = {
1517
+ apiKey,
1518
+ baseUrl,
1519
+ jobId,
1520
+ platform,
1521
+ flushIntervalMs,
1522
+ pollIntervalMs,
1523
+ maxBufferSize,
1524
+ enableDeepLinks,
1525
+ debug
1526
+ };
1527
+ Runhuman.init(config);
1528
+ return () => {
1529
+ initializedRef.current = false;
1530
+ Runhuman.getInstance().destroy();
1531
+ };
1532
+ }, []);
1437
1533
  const { state, activeJobId } = useSensorState();
1438
1534
  const posKey = positionMap[position];
1439
1535
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles.container, children: [
@@ -1450,7 +1546,7 @@ var styles = import_react_native4.StyleSheet.create({
1450
1546
  // Annotate the CommonJS export names for ESM import in node:
1451
1547
  0 && (module.exports = {
1452
1548
  Runhuman,
1453
- RunhumanOverlay,
1549
+ RunhumanProvider,
1454
1550
  useSensorState
1455
1551
  });
1456
1552
  //# sourceMappingURL=index.js.map