@merittdev/horus-lens 0.0.3 → 0.1.1

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.
Files changed (47) hide show
  1. package/README.md +9 -47
  2. package/dist/browser.cjs +84 -85
  3. package/dist/browser.cjs.map +1 -1
  4. package/dist/browser.d.cts +1 -1
  5. package/dist/browser.d.ts +1 -1
  6. package/dist/browser.js +2 -4
  7. package/dist/{chunk-CTBY5XIN.js → chunk-CRV65EEY.js} +40 -2
  8. package/dist/chunk-CRV65EEY.js.map +1 -0
  9. package/dist/{chunk-XRONR4GR.js → chunk-UB7YYHI4.js} +13672 -968
  10. package/dist/chunk-UB7YYHI4.js.map +1 -0
  11. package/dist/index.cjs +46 -111
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/{index.d-BA540Fae.d.ts → index.d-DeLYS02n.d.ts} +13 -0
  14. package/dist/{index.d-DOCLVJGS.d.cts → index.d-sNoEEgRg.d.cts} +13 -0
  15. package/dist/index.d.cts +14 -165
  16. package/dist/index.d.ts +14 -165
  17. package/dist/index.js +1 -29
  18. package/dist/lens.min.js +31 -31
  19. package/dist/lens.min.js.map +1 -1
  20. package/dist/react.cjs +84 -85
  21. package/dist/react.cjs.map +1 -1
  22. package/dist/react.d.cts +1 -1
  23. package/dist/react.d.ts +1 -1
  24. package/dist/react.js +2 -4
  25. package/dist/react.js.map +1 -1
  26. package/package.json +6 -19
  27. package/dist/chunk-CTBY5XIN.js.map +0 -1
  28. package/dist/chunk-DWOH2ENF.js +0 -17613
  29. package/dist/chunk-DWOH2ENF.js.map +0 -1
  30. package/dist/chunk-PZ5AY32C.js +0 -10
  31. package/dist/chunk-PZ5AY32C.js.map +0 -1
  32. package/dist/chunk-XRONR4GR.js.map +0 -1
  33. package/dist/dashboard.cjs +0 -20124
  34. package/dist/dashboard.cjs.map +0 -1
  35. package/dist/dashboard.css +0 -2456
  36. package/dist/dashboard.d.cts +0 -791
  37. package/dist/dashboard.d.ts +0 -791
  38. package/dist/dashboard.js +0 -2584
  39. package/dist/dashboard.js.map +0 -1
  40. package/dist/rrweb-EYUUZIYR.js +0 -30
  41. package/dist/rrweb-EYUUZIYR.js.map +0 -1
  42. package/dist/server.cjs +0 -109
  43. package/dist/server.cjs.map +0 -1
  44. package/dist/server.d.cts +0 -59
  45. package/dist/server.d.ts +0 -59
  46. package/dist/server.js +0 -82
  47. package/dist/server.js.map +0 -1
package/dist/react.cjs CHANGED
@@ -29001,93 +29001,11 @@ var ApiErrorSchema = external_exports.object({
29001
29001
  error: external_exports.string(),
29002
29002
  message: external_exports.string()
29003
29003
  });
29004
- var IntegrationProviderSchema = external_exports.enum(["github", "jira", "linear"]);
29005
- var IntegrationStatusSchema = external_exports.enum(["disconnected", "pending", "connected"]);
29006
- var IntegrationConfigSchema = external_exports.object({
29007
- /** github: "owner/repo" issues target. */
29008
- repo: external_exports.string().optional(),
29009
- /** linear: team key (e.g. "ENG"); defaults to the first team when unset. */
29010
- teamKey: external_exports.string().optional(),
29011
- /** jira: project key (e.g. "BUG"). Required before issues can be created. */
29012
- projectKey: external_exports.string().optional(),
29013
- /** jira: issue type name. Defaults to "Bug", falling back to "Task". */
29014
- issueType: external_exports.string().optional()
29015
- });
29016
- var IntegrationSchema = external_exports.object({
29017
- provider: IntegrationProviderSchema,
29018
- status: IntegrationStatusSchema,
29019
- account: external_exports.string().nullable().default(null),
29020
- active: external_exports.boolean().default(false),
29021
- config: IntegrationConfigSchema.default({})
29022
- });
29023
- var S3ConfigInputSchema = external_exports.object({
29024
- bucket: external_exports.string().min(1),
29025
- region: external_exports.string().min(1),
29026
- endpoint: external_exports.string().url().optional(),
29027
- accessKeyId: external_exports.string().min(1),
29028
- secretAccessKey: external_exports.string().min(1),
29029
- forcePathStyle: external_exports.boolean().optional()
29030
- });
29031
- var S3ConfigPublicSchema = external_exports.object({
29032
- bucket: external_exports.string(),
29033
- region: external_exports.string(),
29034
- endpoint: external_exports.string().optional(),
29035
- forcePathStyle: external_exports.boolean().optional(),
29036
- /** e.g. "AKIA…F3D2" */
29037
- accessKeyIdMasked: external_exports.string()
29038
- });
29039
- var ProjectSchema = external_exports.object({
29040
- id: external_exports.string(),
29041
- name: external_exports.string(),
29042
- accessId: external_exports.string(),
29043
- allowedOrigins: external_exports.array(external_exports.string()),
29044
- /** Active issue destination; null until onboarding picks one. */
29045
- destination: IntegrationProviderSchema.nullable(),
29046
- /**
29047
- * The customer dashboard page hosting the Lens components (e.g.
29048
- * "https://admin.acme.com/lens"). Auto-created issues deep-link reports as
29049
- * `<dashboardUrl>?report=<id>` when set.
29050
- */
29051
- dashboardUrl: external_exports.string().nullable().default(null),
29052
- s3: S3ConfigPublicSchema.nullable(),
29053
- onboardedAt: external_exports.string().nullable(),
29054
- createdAt: external_exports.string()
29055
- });
29056
- var CreateProjectRequestSchema = external_exports.object({
29057
- name: external_exports.string().min(1).max(120),
29058
- allowedOrigins: external_exports.array(external_exports.string()).default([])
29059
- });
29060
- var CreateProjectResponseSchema = external_exports.object({
29061
- project: ProjectSchema,
29062
- accessId: external_exports.string(),
29063
- accessSecret: external_exports.string()
29064
- });
29065
- var UpdateProjectRequestSchema = external_exports.object({
29066
- name: external_exports.string().min(1).max(120).optional(),
29067
- allowedOrigins: external_exports.array(external_exports.string()).optional(),
29068
- onboarded: external_exports.boolean().optional(),
29069
- dashboardUrl: external_exports.string().url().nullable().optional()
29070
- });
29071
- var ListIntegrationsResponseSchema = external_exports.object({
29072
- integrations: external_exports.array(IntegrationSchema)
29073
- });
29074
- var ConnectIntegrationRequestSchema = external_exports.object({
29075
- /**
29076
- * Where the provider's OAuth dance should land the user afterwards —
29077
- * the calling dashboard's own URL. Packed into the signed `state` so the
29078
- * fixed API callback can redirect back to any consumer dashboard.
29079
- */
29080
- returnUrl: external_exports.string().url().optional()
29081
- });
29082
- var ConnectIntegrationResponseSchema = external_exports.object({
29083
- authorizeUrl: external_exports.string(),
29084
- provider: IntegrationProviderSchema
29085
- });
29086
29004
 
29087
29005
  // ../core/dist/index.js
29088
29006
  var SDK_NAME = "@merittdev/horus-lens";
29089
29007
  var SDK_VERSION = "0.0.1";
29090
- var DEFAULT_ENDPOINT = "https://api-lens.meritt.app";
29008
+ var DEFAULT_ENDPOINT = "https://api.horus.sh";
29091
29009
  var DEFAULT_REPLAY_WINDOW_MS = 15e3;
29092
29010
  var DEFAULT_MAX_CONSOLE_ENTRIES = 200;
29093
29011
  var DEFAULT_MAX_NETWORK_ENTRIES = 100;
@@ -29436,6 +29354,11 @@ var ReplayRecorder = class {
29436
29354
  emit: (event, isCheckout) => this.onEmit(event, isCheckout),
29437
29355
  checkoutEveryNms: this.windowMs,
29438
29356
  recordCanvas: false,
29357
+ // Inline same-origin + CORS images as data URIs at snapshot time so the
29358
+ // dashboard replay paints on a different origin (tainted cross-origin
29359
+ // images fall back to their URL, which is fine for public CDNs).
29360
+ inlineImages: true,
29361
+ collectFonts: true,
29439
29362
  // Keep the Lens overlay itself out of every recording.
29440
29363
  blockSelector: `#${LENS_OVERLAY_HOST_ID}`
29441
29364
  });
@@ -29542,7 +29465,7 @@ var ReplayRecorder = class {
29542
29465
  console.warn("[lens] rrweb recording unavailable; replay disabled", err);
29543
29466
  }
29544
29467
  };
29545
- async function captureScreenshot(excludeHost) {
29468
+ async function captureScreenshot(excludeHost, crop) {
29546
29469
  if (typeof document === "undefined" || typeof window === "undefined") return null;
29547
29470
  try {
29548
29471
  const viewportPixels = window.innerWidth * window.innerHeight || 1;
@@ -29576,12 +29499,50 @@ async function captureScreenshot(excludeHost) {
29576
29499
  );
29577
29500
  return null;
29578
29501
  }
29502
+ if (crop) {
29503
+ const cropped = await cropBlob(blob2, crop, scale);
29504
+ return cropped ?? blob2;
29505
+ }
29579
29506
  return blob2;
29580
29507
  } catch (err) {
29581
29508
  console.warn("[lens] screenshot capture failed:", err);
29582
29509
  return null;
29583
29510
  }
29584
29511
  }
29512
+ async function cropBlob(blob2, crop, scale) {
29513
+ try {
29514
+ if (typeof createImageBitmap !== "function" || typeof document === "undefined") return null;
29515
+ const bitmap = await createImageBitmap(blob2);
29516
+ let sx = Math.round(crop.x * scale);
29517
+ let sy = Math.round(crop.y * scale);
29518
+ let sw = Math.round(crop.width * scale);
29519
+ let sh = Math.round(crop.height * scale);
29520
+ sx = Math.max(0, Math.min(sx, bitmap.width));
29521
+ sy = Math.max(0, Math.min(sy, bitmap.height));
29522
+ sw = Math.min(sw, bitmap.width - sx);
29523
+ sh = Math.min(sh, bitmap.height - sy);
29524
+ if (sw <= 0 || sh <= 0) {
29525
+ bitmap.close?.();
29526
+ return null;
29527
+ }
29528
+ const canvas = document.createElement("canvas");
29529
+ canvas.width = sw;
29530
+ canvas.height = sh;
29531
+ const ctx = canvas.getContext("2d");
29532
+ if (!ctx) {
29533
+ bitmap.close?.();
29534
+ return null;
29535
+ }
29536
+ ctx.drawImage(bitmap, sx, sy, sw, sh, 0, 0, sw, sh);
29537
+ bitmap.close?.();
29538
+ return await new Promise((resolve) => {
29539
+ canvas.toBlob((out) => resolve(out), "image/jpeg", 0.82);
29540
+ });
29541
+ } catch (err) {
29542
+ console.warn("[lens] screenshot crop failed:", err);
29543
+ return null;
29544
+ }
29545
+ }
29585
29546
  function parseBrowser(ua) {
29586
29547
  if (!ua) return void 0;
29587
29548
  const checks = [
@@ -29846,7 +29807,7 @@ var LensClient = class {
29846
29807
  const wantErrors = include.errors !== false;
29847
29808
  const wantScreenshot = include.screenshot !== false;
29848
29809
  const wantDom = include.dom !== false;
29849
- const screenshotPromise = this.screenshotEnabled && wantScreenshot ? captureScreenshot(input2.excludeFromScreenshot) : Promise.resolve(null);
29810
+ const screenshotPromise = this.screenshotEnabled && wantScreenshot ? captureScreenshot(input2.excludeFromScreenshot, input2.screenshotCrop) : Promise.resolve(null);
29850
29811
  const replayEvents = wantReplay ? this.replay?.snapshot() ?? [] : [];
29851
29812
  const errorEntries = this.errorBuffer.drain();
29852
29813
  const consoleTail = this.consoleBuffer.tail(CONSOLE_TAIL_SIZE);
@@ -30082,6 +30043,13 @@ var Annotator = class {
30082
30043
  list() {
30083
30044
  return this.annotations.map((a) => ({ ...a, viewport: { ...a.viewport } }));
30084
30045
  }
30046
+ /**
30047
+ * Live rendered rect elements (fixed-positioned, viewport coords). Exposed so
30048
+ * the overlay can derive a document-space bounding box for screenshot crop.
30049
+ */
30050
+ rects() {
30051
+ return [...this.renderedRects];
30052
+ }
30085
30053
  clear() {
30086
30054
  this.annotations = [];
30087
30055
  for (const rect of this.renderedRects) rect.remove();
@@ -31359,11 +31327,13 @@ var Overlay = class {
31359
31327
  }
31360
31328
  async submit(comment2, include) {
31361
31329
  const annotations = this.annotator.list();
31330
+ const screenshotCrop = this.computeAnnotationCrop();
31362
31331
  const result2 = await this.deps.client.submitReport({
31363
31332
  comment: comment2 || void 0,
31364
31333
  annotations,
31365
31334
  target: this.target ?? void 0,
31366
31335
  excludeFromScreenshot: this.host,
31336
+ screenshotCrop,
31367
31337
  include
31368
31338
  });
31369
31339
  this.target = null;
@@ -31372,6 +31342,35 @@ var Overlay = class {
31372
31342
  this.deps.client.discardRecording();
31373
31343
  return result2;
31374
31344
  }
31345
+ /**
31346
+ * Union the marked rects into a single bounding box in DOCUMENT coordinates,
31347
+ * or `undefined` if nothing is marked (→ full-page screenshot). Each rect is
31348
+ * fixed-positioned, so getBoundingClientRect() gives viewport coords; add the
31349
+ * page scroll offset to convert to document space.
31350
+ */
31351
+ computeAnnotationCrop() {
31352
+ const rects = this.annotator.rects();
31353
+ if (rects.length === 0) return void 0;
31354
+ const scrollX = window.scrollX || window.pageXOffset || 0;
31355
+ const scrollY = window.scrollY || window.pageYOffset || 0;
31356
+ let minX = Infinity;
31357
+ let minY = Infinity;
31358
+ let maxX = -Infinity;
31359
+ let maxY = -Infinity;
31360
+ for (const rect of rects) {
31361
+ const r = rect.getBoundingClientRect();
31362
+ const left = r.left + scrollX;
31363
+ const top = r.top + scrollY;
31364
+ minX = Math.min(minX, left);
31365
+ minY = Math.min(minY, top);
31366
+ maxX = Math.max(maxX, left + r.width);
31367
+ maxY = Math.max(maxY, top + r.height);
31368
+ }
31369
+ const width = maxX - minX;
31370
+ const height = maxY - minY;
31371
+ if (!(width > 0) || !(height > 0)) return void 0;
31372
+ return { x: minX, y: minY, width, height };
31373
+ }
31375
31374
  dismiss() {
31376
31375
  this.deps.onDismiss();
31377
31376
  this.destroy();