@merittdev/horus-lens 0.2.1 → 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.cjs CHANGED
@@ -43,6 +43,7 @@ __export(src_exports, {
43
43
  ReportSchema: () => ReportSchema,
44
44
  ReportStatusSchema: () => ReportStatusSchema,
45
45
  ReportSummarySchema: () => ReportSummarySchema,
46
+ ReportTriggerSchema: () => ReportTriggerSchema,
46
47
  SDK_NAME: () => SDK_NAME,
47
48
  SDK_VERSION: () => SDK_VERSION,
48
49
  TargetElementSchema: () => TargetElementSchema,
@@ -14721,6 +14722,7 @@ var AssetRefSchema = external_exports.object({
14721
14722
  byteSize: external_exports.number().optional()
14722
14723
  });
14723
14724
  var ReportStatusSchema = external_exports.enum(["initiated", "submitted", "triaged", "linked", "resolved"]);
14725
+ var ReportTriggerSchema = external_exports.enum(["user", "api", "error"]);
14724
14726
  var ReportMetadataSchema = external_exports.object({
14725
14727
  comment: external_exports.string().optional(),
14726
14728
  annotations: external_exports.array(AnnotationSchema).default([]),
@@ -14731,6 +14733,13 @@ var ReportMetadataSchema = external_exports.object({
14731
14733
  /** Small inline tails so the report list can render without fetching assets. */
14732
14734
  consoleTail: external_exports.array(ConsoleEntrySchema).default([]),
14733
14735
  networkTail: external_exports.array(NetworkEntrySchema).default([]),
14736
+ /**
14737
+ * How the report was triggered. Optional + non-breaking: this schema is a
14738
+ * plain `z.object` (NOT `.strict()`), so a cloud running an older shared
14739
+ * schema silently strips this unknown key on parse rather than rejecting.
14740
+ * Absent → treat as `user`.
14741
+ */
14742
+ trigger: ReportTriggerSchema.optional(),
14734
14743
  sdk: external_exports.object({ name: external_exports.string(), version: external_exports.string() })
14735
14744
  });
14736
14745
  var ReportSchema = external_exports.object({
@@ -29102,7 +29111,7 @@ async function domToBlob(node2, options) {
29102
29111
 
29103
29112
  // ../core/dist/index.js
29104
29113
  var SDK_NAME = "@merittdev/horus-lens";
29105
- var SDK_VERSION = true ? "0.2.1" : "0.0.0-dev";
29114
+ var SDK_VERSION = true ? "0.3.0" : "0.0.0-dev";
29106
29115
  var DEFAULT_ENDPOINT = "https://api.horus.sh";
29107
29116
  var DEFAULT_REPLAY_WINDOW_MS = 15e3;
29108
29117
  var DEFAULT_MAX_CONSOLE_ENTRIES = 200;
@@ -29116,9 +29125,85 @@ var MAX_TARGET_TEXT_CHARS = 200;
29116
29125
  var SCREENSHOT_TIMEOUT_MS = 2e4;
29117
29126
  var SCREENSHOT_MAX_SCALE = 2;
29118
29127
  var SCREENSHOT_MAX_PIXELS = 25e5;
29128
+ var AUTO_CAPTURE_COOLDOWN_MS = 10 * 60 * 1e3;
29129
+ var AUTO_CAPTURE_SESSION_CAP = 5;
29119
29130
  var MAX_MANUAL_RECORDING_MS = 12e4;
29120
29131
  var MAX_MANUAL_RECORDING_EVENTS = 1e4;
29121
29132
  var LENS_OVERLAY_HOST_ID = "__lens_root__";
29133
+ function autoCaptureSignature(message) {
29134
+ 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();
29135
+ }
29136
+ function reasonToMessage(reason) {
29137
+ if (reason instanceof Error) return reason.message || String(reason);
29138
+ if (typeof reason === "string") return reason;
29139
+ try {
29140
+ const json2 = JSON.stringify(reason);
29141
+ if (json2 && json2 !== "{}") return json2;
29142
+ } catch {
29143
+ }
29144
+ return String(reason);
29145
+ }
29146
+ function isIgnored2(message, ignore) {
29147
+ for (const entry of ignore) {
29148
+ if (typeof entry === "string") {
29149
+ if (message.includes(entry)) return true;
29150
+ } else if (entry.test(message)) {
29151
+ return true;
29152
+ }
29153
+ }
29154
+ return false;
29155
+ }
29156
+ function startAutoCapture(client, options = {}) {
29157
+ if (typeof window === "undefined") return () => {
29158
+ };
29159
+ const sampleRate = options.sampleRate ?? 1;
29160
+ const ignore = options.ignore ?? [];
29161
+ const lastSeen = /* @__PURE__ */ new Map();
29162
+ let sessionCount = 0;
29163
+ let submitting = false;
29164
+ const consider = (rawMessage) => {
29165
+ if (submitting) return;
29166
+ if (!rawMessage) return;
29167
+ if (isIgnored2(rawMessage, ignore)) return;
29168
+ if (sampleRate <= 0) return;
29169
+ if (sampleRate < 1 && Math.random() >= sampleRate) return;
29170
+ const signature = autoCaptureSignature(rawMessage);
29171
+ const now = Date.now();
29172
+ const last = lastSeen.get(signature);
29173
+ if (last !== void 0 && now - last < AUTO_CAPTURE_COOLDOWN_MS) return;
29174
+ if (sessionCount >= AUTO_CAPTURE_SESSION_CAP) return;
29175
+ lastSeen.set(signature, now);
29176
+ sessionCount += 1;
29177
+ submitting = true;
29178
+ options.onCapture?.(signature);
29179
+ void Promise.resolve().then(() => client.submitReport({ trigger: "error", include: { screenshot: false } })).catch(() => {
29180
+ }).finally(() => {
29181
+ submitting = false;
29182
+ });
29183
+ };
29184
+ const onError = (event) => {
29185
+ try {
29186
+ const e = event;
29187
+ const error51 = e.error;
29188
+ const message = e.message || (error51 instanceof Error ? error51.message : error51 != null ? String(error51) : "");
29189
+ consider(message);
29190
+ } catch {
29191
+ }
29192
+ };
29193
+ const onRejection = (event) => {
29194
+ try {
29195
+ const e = event;
29196
+ consider(reasonToMessage(e.reason));
29197
+ } catch {
29198
+ }
29199
+ };
29200
+ window.addEventListener("error", onError);
29201
+ window.addEventListener("unhandledrejection", onRejection);
29202
+ return () => {
29203
+ window.removeEventListener("error", onError);
29204
+ window.removeEventListener("unhandledrejection", onRejection);
29205
+ };
29206
+ }
29122
29207
  var RingBuffer = class {
29123
29208
  constructor(capacity) {
29124
29209
  this.capacity = capacity;
@@ -29964,6 +30049,7 @@ var LensClient = class {
29964
30049
  replayWindowMs;
29965
30050
  debug;
29966
30051
  screenshotEnabled;
30052
+ autoCapture;
29967
30053
  beforeSend;
29968
30054
  app;
29969
30055
  consoleBuffer;
@@ -29978,6 +30064,7 @@ var LensClient = class {
29978
30064
  this.endpoint = (config2.endpoint ?? DEFAULT_ENDPOINT).replace(/\/+$/, "");
29979
30065
  this.debug = config2.debug ?? false;
29980
30066
  this.screenshotEnabled = config2.screenshot ?? true;
30067
+ this.autoCapture = config2.autoCapture;
29981
30068
  this.beforeSend = config2.beforeSend;
29982
30069
  this.app = config2.app ?? {};
29983
30070
  this.replayWindowMs = config2.replay === false ? null : config2.replay?.windowMs ?? DEFAULT_REPLAY_WINDOW_MS;
@@ -30006,6 +30093,15 @@ var LensClient = class {
30006
30093
  this.teardowns.push(installNetwork(this.networkBuffer, this.endpoint));
30007
30094
  this.teardowns.push(installErrors(this.errorBuffer));
30008
30095
  this.replay?.start();
30096
+ if (this.autoCapture?.errors) {
30097
+ this.teardowns.push(
30098
+ startAutoCapture(this, {
30099
+ sampleRate: this.autoCapture.sampleRate,
30100
+ ignore: this.autoCapture.ignore,
30101
+ onCapture: (signature) => this.warn(`auto-capture: submitting report for "${signature}"`)
30102
+ })
30103
+ );
30104
+ }
30009
30105
  }
30010
30106
  stop() {
30011
30107
  if (!this.started) return;
@@ -30066,6 +30162,7 @@ var LensClient = class {
30066
30162
  errors: wantErrors ? errorEntries : [],
30067
30163
  consoleTail: wantConsole ? consoleTail : [],
30068
30164
  networkTail: wantNetwork ? networkTail : [],
30165
+ trigger: input2.trigger ?? "user",
30069
30166
  sdk: { name: SDK_NAME, version: SDK_VERSION }
30070
30167
  };
30071
30168
  if (input2.comment !== void 0) metadata.comment = input2.comment;
@@ -30166,6 +30263,7 @@ var LensClient = class {
30166
30263
  ReportSchema,
30167
30264
  ReportStatusSchema,
30168
30265
  ReportSummarySchema,
30266
+ ReportTriggerSchema,
30169
30267
  SDK_NAME,
30170
30268
  SDK_VERSION,
30171
30269
  TargetElementSchema,