@merittdev/horus-lens 0.3.0 → 0.5.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,4 +1,4 @@
1
- import { L as LensConfig, a as LensClient } from './index.d-BYG_Mjs-.cjs';
1
+ import { L as LensConfig, a as LensClient } from './index.d-DeJ1mfh0.cjs';
2
2
  import { z } from 'zod';
3
3
  import './index.d-DTx4C384.cjs';
4
4
 
package/dist/browser.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { L as LensConfig, a as LensClient } from './index.d-Dyzc1E9T.js';
1
+ import { L as LensConfig, a as LensClient } from './index.d-BYuZWEkh.js';
2
2
  import { z } from 'zod';
3
3
  import './index.d-DTx4C384.js';
4
4
 
package/dist/browser.js CHANGED
@@ -7,8 +7,8 @@ import {
7
7
  isGateActive,
8
8
  loaderSnippet,
9
9
  processQueue
10
- } from "./chunk-PNY6BL4C.js";
11
- import "./chunk-LIYEDZV7.js";
10
+ } from "./chunk-M3QMIY4Y.js";
11
+ import "./chunk-2G5FEWPU.js";
12
12
  export {
13
13
  DEFAULT_CDN_URL,
14
14
  LOADER_SNIPPET,
@@ -29063,7 +29063,7 @@ async function domToBlob(node2, options) {
29063
29063
 
29064
29064
  // ../core/dist/index.js
29065
29065
  var SDK_NAME = "@merittdev/horus-lens";
29066
- var SDK_VERSION = true ? "0.3.0" : "0.0.0-dev";
29066
+ var SDK_VERSION = true ? "0.5.0" : "0.0.0-dev";
29067
29067
  var DEFAULT_ENDPOINT = "https://api.horus.sh";
29068
29068
  var DEFAULT_REPLAY_WINDOW_MS = 15e3;
29069
29069
  var DEFAULT_MAX_CONSOLE_ENTRIES = 200;
@@ -29124,11 +29124,15 @@ function startAutoCapture(client, options = {}) {
29124
29124
  const last = lastSeen.get(signature);
29125
29125
  if (last !== void 0 && now - last < AUTO_CAPTURE_COOLDOWN_MS) return;
29126
29126
  if (sessionCount >= AUTO_CAPTURE_SESSION_CAP) return;
29127
+ const previousSeen = lastSeen.get(signature);
29127
29128
  lastSeen.set(signature, now);
29128
29129
  sessionCount += 1;
29129
29130
  submitting = true;
29130
29131
  options.onCapture?.(signature);
29131
29132
  void Promise.resolve().then(() => client.submitReport({ trigger: "error", include: { screenshot: false } })).catch(() => {
29133
+ if (previousSeen === void 0) lastSeen.delete(signature);
29134
+ else lastSeen.set(signature, previousSeen);
29135
+ sessionCount -= 1;
29132
29136
  }).finally(() => {
29133
29137
  submitting = false;
29134
29138
  });
@@ -29183,6 +29187,14 @@ var RingBuffer = class {
29183
29187
  return this.items.length;
29184
29188
  }
29185
29189
  };
29190
+ var HttpError = class extends Error {
29191
+ constructor(status, message) {
29192
+ super(message);
29193
+ this.status = status;
29194
+ this.name = "HttpError";
29195
+ }
29196
+ status;
29197
+ };
29186
29198
  var Transport = class {
29187
29199
  constructor(config2) {
29188
29200
  this.config = config2;
@@ -29190,18 +29202,23 @@ var Transport = class {
29190
29202
  config;
29191
29203
  async initiate(assets) {
29192
29204
  const body = { accessId: this.config.accessId, assets };
29193
- return this.postJson(`${this.config.endpoint}/v1/reports/initiate`, body);
29205
+ return this.postJson(
29206
+ `${this.config.endpoint}/v1/reports/initiate`,
29207
+ body,
29208
+ { retries: 0 }
29209
+ );
29194
29210
  }
29195
29211
  /** Record a late-uploaded asset (background screenshot) on a finalized report. */
29196
29212
  async attachAsset(reportId, asset) {
29197
29213
  const body = { accessId: this.config.accessId, ...asset };
29198
29214
  await this.postJson(`${this.config.endpoint}/v1/reports/${encodeURIComponent(reportId)}/assets`, body);
29199
29215
  }
29200
- async uploadAsset(upload, blob2) {
29216
+ async uploadAsset(upload, blob2, signal) {
29201
29217
  const response = await fetch(upload.url, {
29202
29218
  method: upload.method,
29203
29219
  headers: upload.headers,
29204
- body: blob2
29220
+ body: blob2,
29221
+ signal
29205
29222
  });
29206
29223
  if (!response.ok) {
29207
29224
  throw new Error(`Asset upload failed (${upload.kind}): ${response.status}`);
@@ -29209,12 +29226,20 @@ var Transport = class {
29209
29226
  }
29210
29227
  async finalize(reportId, metadata, uploadedAssets) {
29211
29228
  const body = { accessId: this.config.accessId, metadata, uploadedAssets };
29212
- return this.postJson(
29213
- `${this.config.endpoint}/v1/reports/${reportId}/finalize`,
29214
- body
29215
- );
29229
+ try {
29230
+ return await this.postJson(
29231
+ `${this.config.endpoint}/v1/reports/${reportId}/finalize`,
29232
+ body
29233
+ );
29234
+ } catch (err) {
29235
+ if (err instanceof HttpError && err.status === 409) {
29236
+ return { reportId, status: "submitted" };
29237
+ }
29238
+ throw err;
29239
+ }
29216
29240
  }
29217
- async postJson(url2, body, retries = 1) {
29241
+ async postJson(url2, body, opts = {}) {
29242
+ const retries = opts.retries ?? 1;
29218
29243
  let lastError;
29219
29244
  for (let attempt = 0; attempt <= retries; attempt++) {
29220
29245
  try {
@@ -29225,7 +29250,10 @@ var Transport = class {
29225
29250
  });
29226
29251
  if (!response.ok) {
29227
29252
  const text = await response.text().catch(() => "");
29228
- throw new Error(`Request to ${url2} failed: ${response.status} ${text}`.trim());
29253
+ throw new HttpError(
29254
+ response.status,
29255
+ `Request to ${url2} failed: ${response.status} ${text}`.trim()
29256
+ );
29229
29257
  }
29230
29258
  return await response.json();
29231
29259
  } catch (err) {
@@ -29666,8 +29694,14 @@ async function captureScreenshot(excludeHost, crop, composite) {
29666
29694
  return null;
29667
29695
  }
29668
29696
  }
29669
- if (crop) {
29670
- const cropped = await cropBlob(blob2, crop, scale);
29697
+ const effectiveCrop = crop ?? (composite ? void 0 : {
29698
+ x: window.scrollX,
29699
+ y: window.scrollY,
29700
+ width: window.innerWidth,
29701
+ height: window.innerHeight
29702
+ });
29703
+ if (effectiveCrop) {
29704
+ const cropped = await cropBlob(blob2, effectiveCrop, scale);
29671
29705
  return cropped ?? blob2;
29672
29706
  }
29673
29707
  return blob2;
@@ -30101,12 +30135,22 @@ var LensClient = class {
30101
30135
  input2.screenshotCrop,
30102
30136
  input2.annotationComposite
30103
30137
  ) : Promise.resolve(null);
30138
+ const consumingManualRecording = wantReplay && (this.replay?.hasManualRecording() ?? false) && !(this.replay?.isManualRecording() ?? false);
30104
30139
  const replayEvents = wantReplay ? this.replay?.snapshot() ?? [] : [];
30105
30140
  const errorEntries = this.errorBuffer.drain();
30106
- const consoleTail = this.consoleBuffer.tail(CONSOLE_TAIL_SIZE);
30107
- const networkTail = this.networkBuffer.tail(NETWORK_TAIL_SIZE);
30108
30141
  const consoleEntries = this.consoleBuffer.drain();
30109
30142
  const networkEntries = this.networkBuffer.drain();
30143
+ this.errorBuffer.clear();
30144
+ this.consoleBuffer.clear();
30145
+ this.networkBuffer.clear();
30146
+ const consoleTail = consoleEntries.slice(-CONSOLE_TAIL_SIZE);
30147
+ const isNetFailure = (e) => e.ok !== true || Boolean(e.error);
30148
+ const recentFailures = networkEntries.filter(isNetFailure).slice(-NETWORK_TAIL_SIZE);
30149
+ const keep = /* @__PURE__ */ new Set([
30150
+ ...recentFailures,
30151
+ ...networkEntries.slice(-NETWORK_TAIL_SIZE)
30152
+ ]);
30153
+ const networkTail = networkEntries.filter((e) => keep.has(e)).slice(-NETWORK_TAIL_SIZE);
30110
30154
  let metadata = {
30111
30155
  annotations: input2.annotations ?? [],
30112
30156
  env: collectEnv(),
@@ -30160,13 +30204,14 @@ var LensClient = class {
30160
30204
  }
30161
30205
  if (!asset.blob) continue;
30162
30206
  try {
30163
- await this.transport.uploadAsset(upload, asset.blob);
30207
+ await this.uploadAssetWithTimeout(upload, asset.blob);
30164
30208
  uploadedAssets.push({ kind: upload.kind, key: upload.key, byteSize: asset.blob.size });
30165
30209
  } catch (err) {
30166
30210
  this.warn(`asset upload failed (${upload.kind})`, err);
30167
30211
  }
30168
30212
  }
30169
30213
  const finalized = await this.transport.finalize(initiated.reportId, metadata, uploadedAssets);
30214
+ if (consumingManualRecording) this.replay?.discardManualRecording();
30170
30215
  if (screenshotUpload) {
30171
30216
  const upload = screenshotUpload;
30172
30217
  void screenshotPromise.then(async (blob2) => {
@@ -30184,6 +30229,21 @@ var LensClient = class {
30184
30229
  }
30185
30230
  return { reportId: finalized.reportId };
30186
30231
  }
30232
+ /**
30233
+ * Upload a foreground asset with a bounded timeout. Without this a stuck S3
30234
+ * PUT (dropped connection, half-open socket) would hang `submitReport`
30235
+ * forever; the timeout aborts the individual PUT so it fails as one asset
30236
+ * (caught by the caller) instead of wedging the whole submit.
30237
+ */
30238
+ async uploadAssetWithTimeout(upload, blob2) {
30239
+ const controller = new AbortController();
30240
+ const timer = setTimeout(() => controller.abort(), SCREENSHOT_TIMEOUT_MS);
30241
+ try {
30242
+ await this.transport.uploadAsset(upload, blob2, controller.signal);
30243
+ } finally {
30244
+ clearTimeout(timer);
30245
+ }
30246
+ }
30187
30247
  warn(message, err) {
30188
30248
  if (!this.debug) return;
30189
30249
  if (err !== void 0) console.warn(`[lens] ${message}`, err);
@@ -30241,4 +30301,4 @@ rrweb/dist/rrweb.js:
30241
30301
  PERFORMANCE OF THIS SOFTWARE.
30242
30302
  ***************************************************************************** *)
30243
30303
  */
30244
- //# sourceMappingURL=chunk-LIYEDZV7.js.map
30304
+ //# sourceMappingURL=chunk-2G5FEWPU.js.map