@merittdev/horus-lens 0.2.0 → 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/browser.cjs CHANGED
@@ -28980,6 +28980,7 @@ var AssetRefSchema = external_exports.object({
28980
28980
  byteSize: external_exports.number().optional()
28981
28981
  });
28982
28982
  var ReportStatusSchema = external_exports.enum(["initiated", "submitted", "triaged", "linked", "resolved"]);
28983
+ var ReportTriggerSchema = external_exports.enum(["user", "api", "error"]);
28983
28984
  var ReportMetadataSchema = external_exports.object({
28984
28985
  comment: external_exports.string().optional(),
28985
28986
  annotations: external_exports.array(AnnotationSchema).default([]),
@@ -28990,6 +28991,13 @@ var ReportMetadataSchema = external_exports.object({
28990
28991
  /** Small inline tails so the report list can render without fetching assets. */
28991
28992
  consoleTail: external_exports.array(ConsoleEntrySchema).default([]),
28992
28993
  networkTail: external_exports.array(NetworkEntrySchema).default([]),
28994
+ /**
28995
+ * How the report was triggered. Optional + non-breaking: this schema is a
28996
+ * plain `z.object` (NOT `.strict()`), so a cloud running an older shared
28997
+ * schema silently strips this unknown key on parse rather than rejecting.
28998
+ * Absent → treat as `user`.
28999
+ */
29000
+ trigger: ReportTriggerSchema.optional(),
28993
29001
  sdk: external_exports.object({ name: external_exports.string(), version: external_exports.string() })
28994
29002
  });
28995
29003
  var ReportSchema = external_exports.object({
@@ -29074,7 +29082,7 @@ var ApiErrorSchema = external_exports.object({
29074
29082
 
29075
29083
  // ../core/dist/index.js
29076
29084
  var SDK_NAME = "@merittdev/horus-lens";
29077
- var SDK_VERSION = "0.0.1";
29085
+ var SDK_VERSION = true ? "0.3.0" : "0.0.0-dev";
29078
29086
  var DEFAULT_ENDPOINT = "https://api.horus.sh";
29079
29087
  var DEFAULT_REPLAY_WINDOW_MS = 15e3;
29080
29088
  var DEFAULT_MAX_CONSOLE_ENTRIES = 200;
@@ -29088,9 +29096,85 @@ var MAX_TARGET_TEXT_CHARS = 200;
29088
29096
  var SCREENSHOT_TIMEOUT_MS = 2e4;
29089
29097
  var SCREENSHOT_MAX_SCALE = 2;
29090
29098
  var SCREENSHOT_MAX_PIXELS = 25e5;
29099
+ var AUTO_CAPTURE_COOLDOWN_MS = 10 * 60 * 1e3;
29100
+ var AUTO_CAPTURE_SESSION_CAP = 5;
29091
29101
  var MAX_MANUAL_RECORDING_MS = 12e4;
29092
29102
  var MAX_MANUAL_RECORDING_EVENTS = 1e4;
29093
29103
  var LENS_OVERLAY_HOST_ID = "__lens_root__";
29104
+ function autoCaptureSignature(message) {
29105
+ return message.toLowerCase().replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/g, "<uuid>").replace(/\d+/g, "<n>").replace(/\s+/g, " ").trim();
29106
+ }
29107
+ function reasonToMessage(reason) {
29108
+ if (reason instanceof Error) return reason.message || String(reason);
29109
+ if (typeof reason === "string") return reason;
29110
+ try {
29111
+ const json2 = JSON.stringify(reason);
29112
+ if (json2 && json2 !== "{}") return json2;
29113
+ } catch {
29114
+ }
29115
+ return String(reason);
29116
+ }
29117
+ function isIgnored2(message, ignore) {
29118
+ for (const entry of ignore) {
29119
+ if (typeof entry === "string") {
29120
+ if (message.includes(entry)) return true;
29121
+ } else if (entry.test(message)) {
29122
+ return true;
29123
+ }
29124
+ }
29125
+ return false;
29126
+ }
29127
+ function startAutoCapture(client, options = {}) {
29128
+ if (typeof window === "undefined") return () => {
29129
+ };
29130
+ const sampleRate = options.sampleRate ?? 1;
29131
+ const ignore = options.ignore ?? [];
29132
+ const lastSeen = /* @__PURE__ */ new Map();
29133
+ let sessionCount = 0;
29134
+ let submitting = false;
29135
+ const consider = (rawMessage) => {
29136
+ if (submitting) return;
29137
+ if (!rawMessage) return;
29138
+ if (isIgnored2(rawMessage, ignore)) return;
29139
+ if (sampleRate <= 0) return;
29140
+ if (sampleRate < 1 && Math.random() >= sampleRate) return;
29141
+ const signature = autoCaptureSignature(rawMessage);
29142
+ const now = Date.now();
29143
+ const last = lastSeen.get(signature);
29144
+ if (last !== void 0 && now - last < AUTO_CAPTURE_COOLDOWN_MS) return;
29145
+ if (sessionCount >= AUTO_CAPTURE_SESSION_CAP) return;
29146
+ lastSeen.set(signature, now);
29147
+ sessionCount += 1;
29148
+ submitting = true;
29149
+ options.onCapture?.(signature);
29150
+ void Promise.resolve().then(() => client.submitReport({ trigger: "error", include: { screenshot: false } })).catch(() => {
29151
+ }).finally(() => {
29152
+ submitting = false;
29153
+ });
29154
+ };
29155
+ const onError = (event) => {
29156
+ try {
29157
+ const e = event;
29158
+ const error51 = e.error;
29159
+ const message = e.message || (error51 instanceof Error ? error51.message : error51 != null ? String(error51) : "");
29160
+ consider(message);
29161
+ } catch {
29162
+ }
29163
+ };
29164
+ const onRejection = (event) => {
29165
+ try {
29166
+ const e = event;
29167
+ consider(reasonToMessage(e.reason));
29168
+ } catch {
29169
+ }
29170
+ };
29171
+ window.addEventListener("error", onError);
29172
+ window.addEventListener("unhandledrejection", onRejection);
29173
+ return () => {
29174
+ window.removeEventListener("error", onError);
29175
+ window.removeEventListener("unhandledrejection", onRejection);
29176
+ };
29177
+ }
29094
29178
  var RingBuffer = class {
29095
29179
  constructor(capacity) {
29096
29180
  this.capacity = capacity;
@@ -29936,6 +30020,7 @@ var LensClient = class {
29936
30020
  replayWindowMs;
29937
30021
  debug;
29938
30022
  screenshotEnabled;
30023
+ autoCapture;
29939
30024
  beforeSend;
29940
30025
  app;
29941
30026
  consoleBuffer;
@@ -29950,6 +30035,7 @@ var LensClient = class {
29950
30035
  this.endpoint = (config2.endpoint ?? DEFAULT_ENDPOINT).replace(/\/+$/, "");
29951
30036
  this.debug = config2.debug ?? false;
29952
30037
  this.screenshotEnabled = config2.screenshot ?? true;
30038
+ this.autoCapture = config2.autoCapture;
29953
30039
  this.beforeSend = config2.beforeSend;
29954
30040
  this.app = config2.app ?? {};
29955
30041
  this.replayWindowMs = config2.replay === false ? null : config2.replay?.windowMs ?? DEFAULT_REPLAY_WINDOW_MS;
@@ -29978,6 +30064,15 @@ var LensClient = class {
29978
30064
  this.teardowns.push(installNetwork(this.networkBuffer, this.endpoint));
29979
30065
  this.teardowns.push(installErrors(this.errorBuffer));
29980
30066
  this.replay?.start();
30067
+ if (this.autoCapture?.errors) {
30068
+ this.teardowns.push(
30069
+ startAutoCapture(this, {
30070
+ sampleRate: this.autoCapture.sampleRate,
30071
+ ignore: this.autoCapture.ignore,
30072
+ onCapture: (signature) => this.warn(`auto-capture: submitting report for "${signature}"`)
30073
+ })
30074
+ );
30075
+ }
29981
30076
  }
29982
30077
  stop() {
29983
30078
  if (!this.started) return;
@@ -30038,6 +30133,7 @@ var LensClient = class {
30038
30133
  errors: wantErrors ? errorEntries : [],
30039
30134
  consoleTail: wantConsole ? consoleTail : [],
30040
30135
  networkTail: wantNetwork ? networkTail : [],
30136
+ trigger: input2.trigger ?? "user",
30041
30137
  sdk: { name: SDK_NAME, version: SDK_VERSION }
30042
30138
  };
30043
30139
  if (input2.comment !== void 0) metadata.comment = input2.comment;
@@ -32429,7 +32525,8 @@ var Overlay = class {
32429
32525
  excludeFromScreenshot: this.host,
32430
32526
  screenshotCrop,
32431
32527
  annotationComposite: composite,
32432
- include
32528
+ include,
32529
+ trigger: "user"
32433
32530
  });
32434
32531
  this.target = null;
32435
32532
  this.annotator.clear();