@runhuman/sensor 0.1.2 → 0.2.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.
@@ -1,5 +1,7 @@
1
1
  import { TelemetryPlatform } from '@runhuman/shared';
2
2
  export { TelemetryPlatform } from '@runhuman/shared';
3
+ import { S as SessionManager, A as ApiClient } from './session-manager-B6tiwEQm.mjs';
4
+ export { a as SessionState } from './session-manager-B6tiwEQm.mjs';
3
5
 
4
6
  /**
5
7
  * Runhuman Sensor — Public API
@@ -35,6 +37,7 @@ interface RunhumanConfig {
35
37
  }
36
38
  declare class Runhuman {
37
39
  private static instance;
40
+ private readonly apiClient;
38
41
  private readonly sessionManager;
39
42
  private readonly deepLinkHandler;
40
43
  private readonly debug;
@@ -68,7 +71,11 @@ declare class Runhuman {
68
71
  * After calling destroy(), you can call init() again.
69
72
  */
70
73
  destroy(): Promise<void>;
74
+ /** Access the session manager (used by <RunhumanOverlay /> for reactive state) */
75
+ getSessionManager(): SessionManager;
76
+ /** Access the API client (used by <RunhumanOverlay /> for short code resolution) */
77
+ getApiClient(): ApiClient;
71
78
  private log;
72
79
  }
73
80
 
74
- export { Runhuman, type RunhumanConfig };
81
+ export { ApiClient, Runhuman, type RunhumanConfig };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { TelemetryPlatform } from '@runhuman/shared';
2
2
  export { TelemetryPlatform } from '@runhuman/shared';
3
+ import { S as SessionManager, A as ApiClient } from './session-manager-B6tiwEQm.js';
4
+ export { a as SessionState } from './session-manager-B6tiwEQm.js';
3
5
 
4
6
  /**
5
7
  * Runhuman Sensor — Public API
@@ -35,6 +37,7 @@ interface RunhumanConfig {
35
37
  }
36
38
  declare class Runhuman {
37
39
  private static instance;
40
+ private readonly apiClient;
38
41
  private readonly sessionManager;
39
42
  private readonly deepLinkHandler;
40
43
  private readonly debug;
@@ -68,7 +71,11 @@ declare class Runhuman {
68
71
  * After calling destroy(), you can call init() again.
69
72
  */
70
73
  destroy(): Promise<void>;
74
+ /** Access the session manager (used by <RunhumanOverlay /> for reactive state) */
75
+ getSessionManager(): SessionManager;
76
+ /** Access the API client (used by <RunhumanOverlay /> for short code resolution) */
77
+ getApiClient(): ApiClient;
71
78
  private log;
72
79
  }
73
80
 
74
- export { Runhuman, type RunhumanConfig };
81
+ export { ApiClient, Runhuman, type RunhumanConfig };
package/dist/index.js CHANGED
@@ -1,9 +1,28 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Runhuman: () => Runhuman
6
24
  });
25
+ module.exports = __toCommonJS(index_exports);
7
26
 
8
27
  // ../shared/dist/routes/route-builder.js
9
28
  var API_PREFIX = "/api";
@@ -74,6 +93,8 @@ var webRoutes = {
74
93
  organizationGitHub: defineRoute("/dashboard/organizations/:organizationId/github"),
75
94
  /** Organization SSO/SAML configuration page */
76
95
  organizationSso: defineRoute("/dashboard/organizations/:organizationId/sso"),
96
+ /** Organization schedules overview */
97
+ organizationSchedules: defineRoute("/dashboard/organizations/:organizationId/schedules"),
77
98
  /** Import from GitHub page */
78
99
  organizationImportGitHub: defineRoute("/dashboard/organizations/:organizationId/import"),
79
100
  // ============================================
@@ -119,6 +140,8 @@ var webRoutes = {
119
140
  issueSession: defineRoute("/dashboard/:projectId/issue-sessions/:sessionId"),
120
141
  /** Project settings page */
121
142
  projectSettings: defineRoute("/dashboard/:projectId/settings"),
143
+ /** Schedules page */
144
+ schedules: defineRoute("/dashboard/:projectId/schedules"),
122
145
  /** Flow charts page */
123
146
  flowCharts: defineRoute("/dashboard/:projectId/flowcharts"),
124
147
  /** Single flow chart detail (embedded in dashboard - deprecated, use flowChartView) */
@@ -162,6 +185,8 @@ var apiRoutes = {
162
185
  job: defineRoute("/jobs/:jobId"),
163
186
  /** Get job status (for polling) */
164
187
  jobStatus: defineRoute("/jobs/:jobId/status"),
188
+ /** Get individual job artifact by type */
189
+ jobArtifact: defineRoute("/jobs/:jobId/artifacts/:artifactType"),
165
190
  /** Update job feedback and rating */
166
191
  jobFeedback: defineRoute("/jobs/:jobId/feedback"),
167
192
  /** Enable/disable public sharing for a job (POST = enable, DELETE = disable) */
@@ -257,6 +282,12 @@ var apiRoutes = {
257
282
  projectFlowChartChat: defineRoute("/projects/:projectId/flowcharts/:flowchartId/chat"),
258
283
  /** Enable/disable public sharing for a flow chart */
259
284
  projectFlowChartShare: defineRoute("/projects/:projectId/flowcharts/:flowchartId/share"),
285
+ /** List schedules for a project (GET) or create schedule (POST) */
286
+ projectSchedules: defineRoute("/projects/:projectId/schedules"),
287
+ /** Get/update/delete specific schedule */
288
+ projectSchedule: defineRoute("/projects/:projectId/schedules/:scheduleId"),
289
+ /** List execution history for a schedule */
290
+ projectScheduleExecutions: defineRoute("/projects/:projectId/schedules/:scheduleId/executions"),
260
291
  /** Bulk create projects from GitHub repos */
261
292
  bulkCreateProjects: defineRoute("/projects/bulk"),
262
293
  // ============================================
@@ -438,6 +469,8 @@ var apiRoutes = {
438
469
  organizationGitHubRepoCheckAccess: defineRoute("/organizations/:organizationId/github/repos/check-access"),
439
470
  /** Find deployed URL for a repo via org's GitHub installations */
440
471
  organizationGitHubRepoFindUrl: defineRoute("/organizations/:organizationId/github/repos/find-url"),
472
+ /** Get all schedules across projects in the organization */
473
+ organizationSchedules: defineRoute("/organizations/:organizationId/schedules"),
441
474
  /** Get organization billing balance (Polar) */
442
475
  organizationBilling: defineRoute("/organizations/:organizationId/billing"),
443
476
  // ============================================
@@ -498,7 +531,9 @@ var apiRoutes = {
498
531
  /** Submit telemetry event batch (POST) — SDK periodically flushes captured events */
499
532
  telemetryBatch: defineRoute("/telemetry/sessions/:sessionId/events"),
500
533
  /** Check session status for a job (GET) — SDK polls to know when to activate */
501
- telemetrySessionStatus: defineRoute("/telemetry/jobs/:jobId/status")
534
+ telemetrySessionStatus: defineRoute("/telemetry/jobs/:jobId/status"),
535
+ /** Resolve a sensor short code to a jobId (GET) — SDK calls this when tester enters a code */
536
+ telemetryShortCodeResolve: defineRoute("/telemetry/short-codes/:code")
502
537
  };
503
538
 
504
539
  // src/api-client.ts
@@ -529,6 +564,17 @@ var ApiClient = class {
529
564
  async getSessionStatus(jobId) {
530
565
  return this.get(apiRoutes.telemetrySessionStatus.build({ jobId }));
531
566
  }
567
+ async resolveShortCode(code) {
568
+ const normalized = code.replace(/^RH-/i, "").toUpperCase();
569
+ try {
570
+ return await this.get(
571
+ apiRoutes.telemetryShortCodeResolve.build({ code: normalized })
572
+ );
573
+ } catch (error) {
574
+ if (error instanceof Error && error.message.includes("404")) return null;
575
+ throw error;
576
+ }
577
+ }
532
578
  url(routePath) {
533
579
  return `${this.baseUrl}${API_PREFIX}${routePath}`;
534
580
  }
@@ -798,6 +844,7 @@ var SessionManager = class {
798
844
  this.activeJobId = null;
799
845
  this.pollTimer = null;
800
846
  this.flushTimer = null;
847
+ this.listeners = /* @__PURE__ */ new Set();
801
848
  this.config = config;
802
849
  this.buffer = new EventBuffer(config.maxBufferSize);
803
850
  this.interceptors = new InterceptorManager();
@@ -805,9 +852,30 @@ var SessionManager = class {
805
852
  getState() {
806
853
  return this.state;
807
854
  }
855
+ /** Alias for getState() — named for React's useSyncExternalStore convention */
856
+ getSnapshot() {
857
+ return this.state;
858
+ }
808
859
  getSessionId() {
809
860
  return this.sessionId;
810
861
  }
862
+ getActiveJobId() {
863
+ return this.activeJobId;
864
+ }
865
+ /**
866
+ * Subscribe to state changes. Returns an unsubscribe function.
867
+ * Compatible with React's useSyncExternalStore.
868
+ */
869
+ subscribe(listener) {
870
+ this.listeners.add(listener);
871
+ return () => this.listeners.delete(listener);
872
+ }
873
+ setState(newState) {
874
+ this.state = newState;
875
+ for (const listener of this.listeners) {
876
+ listener();
877
+ }
878
+ }
811
879
  /**
812
880
  * Start polling for job activation.
813
881
  * The sensor calls this on init — polling continues until a job is detected
@@ -816,7 +884,7 @@ var SessionManager = class {
816
884
  startPolling(jobId) {
817
885
  if (this.state !== "idle") return;
818
886
  this.activeJobId = jobId;
819
- this.state = "polling";
887
+ this.setState("polling");
820
888
  this.log("Polling started", { jobId });
821
889
  this.pollTimer = setInterval(() => this.pollOnce(), this.config.pollIntervalMs);
822
890
  this.pollOnce();
@@ -827,7 +895,7 @@ var SessionManager = class {
827
895
  this.pollTimer = null;
828
896
  }
829
897
  if (this.state === "polling") {
830
- this.state = "idle";
898
+ this.setState("idle");
831
899
  this.log("Polling stopped");
832
900
  }
833
901
  }
@@ -864,10 +932,9 @@ var SessionManager = class {
864
932
  if (this.state !== "polling" || !this.activeJobId) return;
865
933
  try {
866
934
  const status = await this.config.apiClient.getSessionStatus(this.activeJobId);
867
- if (status.jobActive && status.sdkEnabled && status.activeSessionId) {
868
- this.log("Job has active session, starting capture", {
869
- jobId: this.activeJobId,
870
- activeSessionId: status.activeSessionId
935
+ if (status.jobActive && !status.activeSessionId) {
936
+ this.log("Job is active, creating session", {
937
+ jobId: this.activeJobId
871
938
  });
872
939
  this.stopPolling();
873
940
  await this.startSession();
@@ -877,7 +944,7 @@ var SessionManager = class {
877
944
  }
878
945
  }
879
946
  async startSession() {
880
- this.state = "active";
947
+ this.setState("active");
881
948
  const now = /* @__PURE__ */ new Date();
882
949
  const response = await this.config.apiClient.createSession({
883
950
  jobId: this.activeJobId,
@@ -896,7 +963,7 @@ var SessionManager = class {
896
963
  this.flushTimer = setInterval(() => this.flush(), this.config.flushIntervalMs);
897
964
  }
898
965
  async endSession() {
899
- this.state = "ending";
966
+ this.setState("ending");
900
967
  if (this.flushTimer) {
901
968
  clearInterval(this.flushTimer);
902
969
  this.flushTimer = null;
@@ -918,7 +985,7 @@ var SessionManager = class {
918
985
  this.sessionId = null;
919
986
  this.activeJobId = null;
920
987
  this.buffer.clear();
921
- this.state = "idle";
988
+ this.setState("idle");
922
989
  }
923
990
  async flush() {
924
991
  if (!this.sessionId) return;
@@ -990,7 +1057,7 @@ var DeepLinkHandler = class {
990
1057
  }
991
1058
  getLinking() {
992
1059
  try {
993
- const { Linking } = __require("react-native");
1060
+ const { Linking } = require("react-native");
994
1061
  return Linking;
995
1062
  } catch {
996
1063
  return null;
@@ -1009,12 +1076,12 @@ var SDK_VERSION = "0.1.0";
1009
1076
  var _Runhuman = class _Runhuman {
1010
1077
  constructor(config) {
1011
1078
  this.debug = config.debug === true;
1012
- const apiClient = new ApiClient(
1079
+ this.apiClient = new ApiClient(
1013
1080
  config.baseUrl ?? PRODUCTION_BASE_URL,
1014
1081
  config.apiKey
1015
1082
  );
1016
1083
  this.sessionManager = new SessionManager({
1017
- apiClient,
1084
+ apiClient: this.apiClient,
1018
1085
  platform: config.platform ?? "react-native",
1019
1086
  sdkVersion: SDK_VERSION,
1020
1087
  flushIntervalMs: config.flushIntervalMs ?? 5e3,
@@ -1085,6 +1152,14 @@ var _Runhuman = class _Runhuman {
1085
1152
  _Runhuman.instance = null;
1086
1153
  this.log("Destroyed");
1087
1154
  }
1155
+ /** Access the session manager (used by <RunhumanOverlay /> for reactive state) */
1156
+ getSessionManager() {
1157
+ return this.sessionManager;
1158
+ }
1159
+ /** Access the API client (used by <RunhumanOverlay /> for short code resolution) */
1160
+ getApiClient() {
1161
+ return this.apiClient;
1162
+ }
1088
1163
  log(message) {
1089
1164
  if (this.debug) {
1090
1165
  console.debug(`[Runhuman] ${message}`);
@@ -1093,7 +1168,8 @@ var _Runhuman = class _Runhuman {
1093
1168
  };
1094
1169
  _Runhuman.instance = null;
1095
1170
  var Runhuman = _Runhuman;
1096
- export {
1171
+ // Annotate the CommonJS export names for ESM import in node:
1172
+ 0 && (module.exports = {
1097
1173
  Runhuman
1098
- };
1174
+ });
1099
1175
  //# sourceMappingURL=index.js.map