issue-sticker 0.8.1 → 0.9.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.
@@ -2,6 +2,41 @@ import * as React from "react";
2
2
  import { useLayoutEffect, forwardRef, createElement } from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import * as ReactDOM from "react-dom";
5
+ const sources = /* @__PURE__ */ new WeakMap();
6
+ const registrationListeners = /* @__PURE__ */ new Set();
7
+ function onCanvasSourceRegistered(listener) {
8
+ registrationListeners.add(listener);
9
+ return () => {
10
+ registrationListeners.delete(listener);
11
+ };
12
+ }
13
+ function registerCanvasSource(canvas, source) {
14
+ const isNew = !sources.has(canvas);
15
+ sources.set(canvas, source);
16
+ if (isNew) {
17
+ registrationListeners.forEach((listener) => {
18
+ try {
19
+ listener(canvas);
20
+ } catch {
21
+ }
22
+ });
23
+ }
24
+ return () => {
25
+ if (sources.get(canvas) === source) {
26
+ sources.delete(canvas);
27
+ }
28
+ };
29
+ }
30
+ function getCanvasSource(canvas) {
31
+ return sources.get(canvas);
32
+ }
33
+ const REPLAY_EVENT_TYPE = {
34
+ FullSnapshot: 2,
35
+ IncrementalSnapshot: 3,
36
+ Meta: 4,
37
+ Custom: 5
38
+ };
39
+ const CANVAS_INTERACTION_TAG = "issue-sticker:canvas-interaction";
5
40
  /*! pako 2.2.0 https://github.com/nodeca/pako @license (MIT AND Zlib) */
6
41
  const Z_FIXED$1 = 4;
7
42
  const Z_BINARY = 0;
@@ -1893,9 +1928,9 @@ const _has = (obj, key) => {
1893
1928
  return Object.prototype.hasOwnProperty.call(obj, key);
1894
1929
  };
1895
1930
  var assign = function(obj) {
1896
- const sources = Array.prototype.slice.call(arguments, 1);
1897
- while (sources.length) {
1898
- const source = sources.shift();
1931
+ const sources2 = Array.prototype.slice.call(arguments, 1);
1932
+ while (sources2.length) {
1933
+ const source = sources2.shift();
1899
1934
  if (!source) {
1900
1935
  continue;
1901
1936
  }
@@ -15433,6 +15468,42 @@ function inDom(n2) {
15433
15468
  if (!doc) return false;
15434
15469
  return index$2.contains(doc, n2) || shadowHostInDom(n2);
15435
15470
  }
15471
+ const utils = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
15472
+ __proto__: null,
15473
+ StyleSheetMirror,
15474
+ get _mirror() {
15475
+ return _mirror;
15476
+ },
15477
+ closestElementOfNode,
15478
+ getBaseDimension,
15479
+ getNestedRule,
15480
+ getPositionsAndIndex,
15481
+ getRootShadowHost,
15482
+ getShadowHost,
15483
+ getWindowHeight,
15484
+ getWindowScroll,
15485
+ getWindowWidth,
15486
+ hasShadowRoot,
15487
+ hookSetter,
15488
+ inDom,
15489
+ isAncestorRemoved,
15490
+ isBlocked,
15491
+ isIgnored,
15492
+ isSerialized,
15493
+ isSerializedIframe,
15494
+ isSerializedStylesheet,
15495
+ iterateResolveTree,
15496
+ legacy_isTouchEvent,
15497
+ get nowTimestamp() {
15498
+ return nowTimestamp;
15499
+ },
15500
+ on,
15501
+ polyfill: polyfill$1,
15502
+ queueToResolveTrees,
15503
+ shadowHostInDom,
15504
+ throttle,
15505
+ uniqueTextMutations
15506
+ }, Symbol.toStringTag, { value: "Module" }));
15436
15507
  var EventType = /* @__PURE__ */ ((EventType2) => {
15437
15508
  EventType2[EventType2["DomContentLoaded"] = 0] = "DomContentLoaded";
15438
15509
  EventType2[EventType2["Load"] = 1] = "Load";
@@ -21615,6 +21686,222 @@ class Replayer {
21615
21686
  const { addCustomEvent } = record;
21616
21687
  const { freezePage } = record;
21617
21688
  const { takeFullSnapshot } = record;
21689
+ const rrweb = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
21690
+ __proto__: null,
21691
+ EventType,
21692
+ IncrementalSource,
21693
+ MouseInteractions,
21694
+ Replayer,
21695
+ ReplayerEvents,
21696
+ addCustomEvent,
21697
+ canvasMutation,
21698
+ freezePage,
21699
+ get mirror() {
21700
+ return _mirror;
21701
+ },
21702
+ record,
21703
+ takeFullSnapshot,
21704
+ utils
21705
+ }, Symbol.toStringTag, { value: "Module" }));
21706
+ const threeHandles = /* @__PURE__ */ new WeakMap();
21707
+ function isThreeNamespace(value) {
21708
+ const candidate = value;
21709
+ return typeof (candidate == null ? void 0 : candidate.Raycaster) === "function" && typeof (candidate == null ? void 0 : candidate.Vector2) === "function";
21710
+ }
21711
+ function isHelper(object) {
21712
+ let current = object;
21713
+ while (current) {
21714
+ if (typeof current.type === "string" && current.type.endsWith("Helper")) {
21715
+ return true;
21716
+ }
21717
+ current = current.parent;
21718
+ }
21719
+ return false;
21720
+ }
21721
+ function nameOf(object) {
21722
+ let current = object;
21723
+ while (current) {
21724
+ if (current.name) {
21725
+ return current.name;
21726
+ }
21727
+ current = current.parent;
21728
+ }
21729
+ return (object == null ? void 0 : object.type) ?? null;
21730
+ }
21731
+ function pickTarget(handle, pointer) {
21732
+ var _a2;
21733
+ const three = handle.three;
21734
+ if (!isThreeNamespace(three)) {
21735
+ return null;
21736
+ }
21737
+ const children = (_a2 = handle.scene) == null ? void 0 : _a2.children;
21738
+ if (!Array.isArray(children)) {
21739
+ return null;
21740
+ }
21741
+ try {
21742
+ const raycaster = new three.Raycaster();
21743
+ raycaster.setFromCamera(new three.Vector2(pointer[0], pointer[1]), handle.camera);
21744
+ const hits = raycaster.intersectObjects(children, true);
21745
+ const hit = hits.find(
21746
+ (candidate) => {
21747
+ var _a3, _b;
21748
+ return ((_a3 = candidate.object) == null ? void 0 : _a3.isMesh) === true && ((_b = candidate.object) == null ? void 0 : _b.visible) !== false && !isHelper(candidate.object);
21749
+ }
21750
+ );
21751
+ return hit ? nameOf(hit.object) : null;
21752
+ } catch {
21753
+ return null;
21754
+ }
21755
+ }
21756
+ function cameraMatrixOf(handle) {
21757
+ var _a2, _b;
21758
+ const matrix = (_a2 = handle.camera) == null ? void 0 : _a2.matrixWorld;
21759
+ try {
21760
+ const values = (_b = matrix == null ? void 0 : matrix.toArray) == null ? void 0 : _b.call(matrix);
21761
+ return Array.isArray(values) ? values : null;
21762
+ } catch {
21763
+ return null;
21764
+ }
21765
+ }
21766
+ function threeSourceOf(canvas) {
21767
+ const current = () => threeHandles.get(canvas);
21768
+ return {
21769
+ redraw() {
21770
+ const handle = current();
21771
+ handle == null ? void 0 : handle.renderer.render(handle.scene, handle.camera);
21772
+ },
21773
+ pickTarget(pointer) {
21774
+ const handle = current();
21775
+ return handle ? pickTarget(handle, pointer) : null;
21776
+ },
21777
+ cameraMatrix() {
21778
+ const handle = current();
21779
+ return handle ? cameraMatrixOf(handle) : null;
21780
+ }
21781
+ };
21782
+ }
21783
+ function registerThreeRenderer(handle) {
21784
+ var _a2;
21785
+ const canvas = (_a2 = handle == null ? void 0 : handle.renderer) == null ? void 0 : _a2.domElement;
21786
+ if (!(canvas instanceof HTMLCanvasElement)) {
21787
+ return () => void 0;
21788
+ }
21789
+ threeHandles.set(canvas, handle);
21790
+ const unregisterSource = registerCanvasSource(canvas, threeSourceOf(canvas));
21791
+ return () => {
21792
+ if (threeHandles.get(canvas) !== handle) return;
21793
+ threeHandles.delete(canvas);
21794
+ unregisterSource();
21795
+ };
21796
+ }
21797
+ function installThreeAutoDetect() {
21798
+ if (typeof window === "undefined") {
21799
+ return () => void 0;
21800
+ }
21801
+ const holder = window;
21802
+ const restorePatches = [];
21803
+ const observe = (event) => {
21804
+ const detail = event.detail;
21805
+ if ((detail == null ? void 0 : detail.isWebGLRenderer) === true) {
21806
+ observeRenderer(detail, restorePatches);
21807
+ }
21808
+ };
21809
+ const wrap = (hook) => {
21810
+ if (!hook) {
21811
+ return {
21812
+ dispatchEvent(event) {
21813
+ observe(event);
21814
+ return true;
21815
+ }
21816
+ };
21817
+ }
21818
+ const original = hook.dispatchEvent;
21819
+ if (typeof original !== "function" || original.__probed === true) {
21820
+ return hook;
21821
+ }
21822
+ const patched = function(event) {
21823
+ observe(event);
21824
+ return original.call(this, event);
21825
+ };
21826
+ patched.__probed = true;
21827
+ hook.dispatchEvent = patched;
21828
+ restorePatches.push(() => {
21829
+ hook.dispatchEvent = original;
21830
+ });
21831
+ return hook;
21832
+ };
21833
+ const previousDescriptor = Object.getOwnPropertyDescriptor(window, "__THREE_DEVTOOLS__");
21834
+ let current = wrap(holder.__THREE_DEVTOOLS__);
21835
+ Object.defineProperty(window, "__THREE_DEVTOOLS__", {
21836
+ configurable: true,
21837
+ enumerable: true,
21838
+ get: () => current,
21839
+ set: (next) => {
21840
+ current = wrap(next);
21841
+ }
21842
+ });
21843
+ return () => {
21844
+ restorePatches.forEach((restore) => restore());
21845
+ restorePatches.length = 0;
21846
+ const survivor = current;
21847
+ delete window.__THREE_DEVTOOLS__;
21848
+ if (previousDescriptor) {
21849
+ Object.defineProperty(window, "__THREE_DEVTOOLS__", previousDescriptor);
21850
+ return;
21851
+ }
21852
+ if (survivor && !holder.__THREE_DEVTOOLS__) {
21853
+ const isOurs = Object.keys(survivor).length === 1 && "dispatchEvent" in survivor;
21854
+ if (!isOurs) {
21855
+ holder.__THREE_DEVTOOLS__ = survivor;
21856
+ }
21857
+ }
21858
+ };
21859
+ }
21860
+ function isSceneLike(value) {
21861
+ return (value == null ? void 0 : value.isScene) === true;
21862
+ }
21863
+ const lastDrawn = /* @__PURE__ */ new WeakMap();
21864
+ function observeRenderer(renderer, restorePatches) {
21865
+ queueMicrotask(() => {
21866
+ const owner = Object.prototype.hasOwnProperty.call(renderer, "render") ? renderer : Object.getPrototypeOf(renderer);
21867
+ const original = owner.render;
21868
+ if (typeof original !== "function") {
21869
+ return;
21870
+ }
21871
+ owner.render = function(scene, camera) {
21872
+ const canvas = (this == null ? void 0 : this.domElement) ?? renderer.domElement;
21873
+ if (canvas instanceof HTMLCanvasElement) {
21874
+ lastDrawn.set(canvas, [scene, camera]);
21875
+ if (isSceneLike(scene)) {
21876
+ const existing = threeHandles.get(canvas);
21877
+ if (existing) {
21878
+ existing.scene = scene;
21879
+ existing.camera = camera;
21880
+ } else {
21881
+ registerThreeRenderer({
21882
+ // 강제 렌더는 **앱이 마지막으로 그린 그대로** 다시 그린다. 후처리를 쓰면 화면을
21883
+ // 그리는 것은 풀스크린 쿼드 패스라, 앱의 씬으로 그리면 후처리가 빠진다.
21884
+ // 원본을 부른다 — 우리 래퍼를 다시 타지 않게 한다.
21885
+ renderer: {
21886
+ domElement: canvas,
21887
+ render: (s2, c2) => {
21888
+ const last = lastDrawn.get(canvas);
21889
+ return last ? original.call(this, last[0], last[1]) : original.call(this, s2, c2);
21890
+ }
21891
+ },
21892
+ scene,
21893
+ camera
21894
+ });
21895
+ }
21896
+ }
21897
+ }
21898
+ return original.call(this, scene, camera);
21899
+ };
21900
+ restorePatches.push(() => {
21901
+ owner.render = original;
21902
+ });
21903
+ });
21904
+ }
21618
21905
  const OVERLAY_LAYER_INDEX = {
21619
21906
  // 익스텐션·SDK 위젯의 shadow host. isolation:isolate 로 stacking context 를 만들기 때문에
21620
21907
  // 아래 레이어 값들은 호스트 내부 순서만 정한다. 호스트 페이지의 오버레이와 겨루는 것은
@@ -27397,40 +27684,50 @@ const MousePointer2 = createLucideIcon("MousePointer2", [
27397
27684
  }
27398
27685
  ]
27399
27686
  ]);
27687
+ function registerThree(handle) {
27688
+ return registerThreeRenderer(handle);
27689
+ }
27690
+ installThreeAutoDetect();
27400
27691
  export {
27401
- Anchor as A,
27402
- Content as C,
27692
+ Root2 as A,
27693
+ Anchor as B,
27694
+ CANVAS_INTERACTION_TAG as C,
27403
27695
  DismissableLayer as D,
27696
+ Arrow as E,
27697
+ clsx as F,
27698
+ Root as G,
27699
+ createSlottable as H,
27700
+ rrweb as I,
27404
27701
  MousePointer2 as M,
27405
27702
  OVERLAY_LAYER_INDEX as O,
27406
27703
  Presence as P,
27407
- Replayer as R,
27704
+ REPLAY_EVENT_TYPE as R,
27408
27705
  Slot as S,
27409
27706
  VISUALLY_HIDDEN_STYLES as V,
27410
27707
  cn as a,
27411
- usePortalContainer as b,
27708
+ Replayer as b,
27412
27709
  createLucideIcon as c,
27413
- OVERLAY_LAYER as d,
27414
- Primitive as e,
27415
- composeEventHandlers as f,
27416
- useDismissableLayerSurface as g,
27417
- useComposedRefs as h,
27418
- Portal as i,
27419
- createContextScope as j,
27420
- createSlot as k,
27421
- useControllableState as l,
27422
- useId as m,
27423
- useLayoutEffect2 as n,
27424
- useCallbackRef as o,
27425
- PortalContainerProvider as p,
27426
- gzip_1 as q,
27427
- record as r,
27710
+ usePortalContainer as d,
27711
+ OVERLAY_LAYER as e,
27712
+ Primitive as f,
27713
+ composeEventHandlers as g,
27714
+ useDismissableLayerSurface as h,
27715
+ useComposedRefs as i,
27716
+ Portal as j,
27717
+ createContextScope as k,
27718
+ createSlot as l,
27719
+ useControllableState as m,
27720
+ useId as n,
27721
+ useLayoutEffect2 as o,
27722
+ useCallbackRef as p,
27723
+ PortalContainerProvider as q,
27724
+ registerThree as r,
27428
27725
  stopEscapePropagation as s,
27429
- createPopperScope as t,
27726
+ getCanvasSource as t,
27430
27727
  ungzip_1 as u,
27431
- Root2 as v,
27432
- Arrow as w,
27433
- clsx as x,
27434
- Root as y,
27435
- createSlottable as z
27728
+ onCanvasSourceRegistered as v,
27729
+ gzip_1 as w,
27730
+ record as x,
27731
+ Content as y,
27732
+ createPopperScope as z
27436
27733
  };
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
- import { P as Presence, i as Portal$1, w as Arrow, D as DismissableLayer, C as Content, y as Root, h as useComposedRefs, t as createPopperScope, j as createContextScope, z as createSlottable, m as useId, l as useControllableState, v as Root2, A as Anchor, e as Primitive, f as composeEventHandlers, b as usePortalContainer, a as cn, d as OVERLAY_LAYER, s as stopEscapePropagation } from "./mouse-pointer-2-BR00y3ir.js";
3
+ import { P as Presence, j as Portal$1, E as Arrow, D as DismissableLayer, y as Content, G as Root, i as useComposedRefs, z as createPopperScope, k as createContextScope, H as createSlottable, n as useId, m as useControllableState, A as Root2, B as Anchor, f as Primitive, g as composeEventHandlers, d as usePortalContainer, a as cn, e as OVERLAY_LAYER, s as stopEscapePropagation } from "./three-_bdgDAmI.js";
4
4
  var [createTooltipContext] = createContextScope("Tooltip", [
5
5
  createPopperScope
6
6
  ]);
@@ -10,3 +10,29 @@ export interface SessionReplayViewerProps {
10
10
  export declare function SessionReplayViewer(
11
11
  props: SessionReplayViewerProps
12
12
  ): import('react').ReactElement;
13
+
14
+ /**
15
+ * three.js 화면을 스크린샷과 세션 리플레이에 담기 위한 연결 지점.
16
+ *
17
+ * WebGL 캔버스는 `preserveDrawingBuffer` 기본값이 false 라 합성이 끝나면 드로잉 버퍼가
18
+ * 비워집니다. 렌더러를 넘기면 캡처 순간에 한 프레임 더 그린 뒤 바로 읽습니다.
19
+ */
20
+ export interface ThreeRenderTarget {
21
+ domElement: HTMLCanvasElement;
22
+ render(scene: unknown, camera: unknown): void;
23
+ }
24
+
25
+ export interface ThreeHandle {
26
+ renderer: ThreeRenderTarget;
27
+ scene: unknown;
28
+ camera: unknown;
29
+ /**
30
+ * 앱이 쓰는 three 네임스페이스(`import * as THREE from 'three'`). 넘기면 캔버스 조작이
31
+ * 일어날 때 어떤 오브젝트를 눌렀는지 이슈스티커가 직접 계산해 세션 리플레이 로그에
32
+ * 이름으로 남깁니다.
33
+ */
34
+ three?: unknown;
35
+ }
36
+
37
+ /** three.js 렌더러를 캡처에 등록합니다. 반환값을 부르면 해제됩니다. */
38
+ export declare function registerThree(handle: ThreeHandle): () => void;
package/headless.d.ts CHANGED
@@ -160,6 +160,7 @@ export interface HeadlessConfig {
160
160
  capture?: {
161
161
  networkLogs?: boolean;
162
162
  consoleLogs?: boolean;
163
+ socketLogs?: boolean;
163
164
  excludeSelectors?: string[];
164
165
  };
165
166
  }
@@ -329,6 +330,33 @@ export declare class IssueStickerHeadlessError extends Error {
329
330
  constructor(code: HeadlessErrorCode, message: string, cause?: unknown);
330
331
  }
331
332
 
333
+ /**
334
+ * three.js 화면을 스크린샷에 담기 위한 연결 지점.
335
+ *
336
+ * WebGL 캔버스는 `preserveDrawingBuffer` 기본값이 false 라 합성이 끝나면 드로잉 버퍼가
337
+ * 비워진다. 렌더러를 넘겨 주면 캡처 순간에 한 프레임 더 그린 뒤 바로 읽는다. 변경이 있을
338
+ * 때만 그리는 앱(편집기·컨피규레이터)은 이 등록이 있어야 WebGL 화면이 찍힌다.
339
+ */
340
+ export interface ThreeRenderTarget {
341
+ domElement: HTMLCanvasElement;
342
+ render(scene: unknown, camera: unknown): void;
343
+ }
344
+
345
+ export interface ThreeHandle {
346
+ renderer: ThreeRenderTarget;
347
+ scene: unknown;
348
+ camera: unknown;
349
+ /**
350
+ * 앱이 쓰는 three 네임스페이스(`import * as THREE from 'three'`). 넘기면 캔버스 조작이
351
+ * 일어날 때 어떤 오브젝트를 눌렀는지 이슈스티커가 직접 계산해 세션 리플레이 로그에
352
+ * 이름으로 남깁니다. 넘기지 않으면 이름 없이 화면과 카메라만 남습니다.
353
+ */
354
+ three?: unknown;
355
+ }
356
+
357
+ /** three.js 렌더러를 캡처에 등록한다. 반환값을 부르면 해제된다. */
358
+ export declare function registerThree(handle: ThreeHandle): () => void;
359
+
332
360
  export declare function createIssueStickerHeadless(config: HeadlessConfig): HeadlessClient;
333
361
 
334
362
  export default createIssueStickerHeadless;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "issue-sticker",
3
- "version": "0.8.1",
3
+ "version": "0.9.1",
4
4
  "description": "IssueSticker SDK - Visual bug tracking widget for web applications",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -95,6 +95,8 @@
95
95
  "@testing-library/react": "^16.3.2",
96
96
  "@types/react": "^18.2.0",
97
97
  "@types/react-dom": "^18.2.0",
98
+ "@types/three": "^0.186.0",
99
+ "@types/ws": "^8.5.12",
98
100
  "@vitejs/plugin-react": "^4.7.0",
99
101
  "@vitest/ui": "^3.2.6",
100
102
  "autoprefixer": "^10.4.23",
@@ -105,9 +107,11 @@
105
107
  "serve": "^14.2.6",
106
108
  "tailwindcss": "^3.4.19",
107
109
  "terser": "^5.44.1",
110
+ "three": "^0.186.0",
108
111
  "typescript": "^5.0.0",
109
112
  "vite": "^6.4.3",
110
- "vitest": "^3.2.6"
113
+ "vitest": "^3.2.6",
114
+ "ws": "^8.18.0"
111
115
  },
112
116
  "peerDependencies": {
113
117
  "react": "^18.0.0 || ^19.0.0",
package/react.d.ts CHANGED
@@ -40,14 +40,42 @@ export interface UseIssueStickerConfig extends SDKConfig {
40
40
  enabled?: boolean;
41
41
  }
42
42
 
43
+ /**
44
+ * three.js 화면을 스크린샷에 담기 위한 연결 지점.
45
+ *
46
+ * WebGL 캔버스는 `preserveDrawingBuffer` 기본값이 false 라 합성이 끝나면 드로잉 버퍼가
47
+ * 비워진다. 렌더러를 넘겨 주면 캡처 순간에 한 프레임 더 그린 뒤 바로 읽는다. 변경이 있을
48
+ * 때만 그리는 앱(편집기·컨피규레이터)은 이 등록이 있어야 WebGL 화면이 찍힌다.
49
+ */
50
+ export interface ThreeRenderTarget {
51
+ domElement: HTMLCanvasElement;
52
+ render(scene: unknown, camera: unknown): void;
53
+ }
54
+
55
+ export interface ThreeHandle {
56
+ renderer: ThreeRenderTarget;
57
+ scene: unknown;
58
+ camera: unknown;
59
+ /**
60
+ * 앱이 쓰는 three 네임스페이스(`import * as THREE from 'three'`). 넘기면 캔버스 조작이
61
+ * 일어날 때 어떤 오브젝트를 눌렀는지 이슈스티커가 직접 계산해 세션 리플레이 로그에
62
+ * 이름으로 남깁니다. 넘기지 않으면 이름 없이 화면과 카메라만 남습니다.
63
+ */
64
+ three?: unknown;
65
+ }
66
+
43
67
  export declare const IssueSticker: {
44
68
  init(config: SDKConfig): void;
45
69
  updateConfig(config: SDKConfig): void;
46
70
  destroy(): void;
47
71
  on(event: SDKEvent, callback: (...args: unknown[]) => void): void;
48
72
  off(event: SDKEvent, callback: (...args: unknown[]) => void): void;
73
+ /** three.js 렌더러를 캡처에 등록한다. 반환값을 부르면 해제된다. */
74
+ registerThree(handle: ThreeHandle): () => void;
49
75
  };
50
76
 
77
+ export declare function registerThree(handle: ThreeHandle): () => void;
78
+
51
79
  export declare function useIssueSticker(config: UseIssueStickerConfig): void;
52
80
 
53
81
  export default IssueSticker;