@simplysm/angular 14.2.3 → 14.2.4

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 +1 @@
1
- {"version":3,"file":"provideSdAngular.d.ts","sourceRoot":"","sources":["../../src/core/provideSdAngular.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAoC1D,wBAAgB,gBAAgB,CAAC,GAAG,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,oBAAoB,CA8JlF"}
1
+ {"version":3,"file":"provideSdAngular.d.ts","sourceRoot":"","sources":["../../src/core/provideSdAngular.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAoE1D,wBAAgB,gBAAgB,CAAC,GAAG,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,oBAAoB,CA8KlF"}
@@ -14,6 +14,34 @@ import { SdOptionEventPlugin } from "./events/sd-option-event.plugin";
14
14
  import { createLogger } from "@simplysm/core-common";
15
15
  const logger = createLogger("angular:sw-update");
16
16
  const themeLogger = createLogger("angular:theme");
17
+ const errorLogger = createLogger("angular:global-error");
18
+ // 브라우저 확장은 자기 스크립트를 페이지 main world 에 주입해 실행하므로,
19
+ // 확장이 던진 오류도 페이지의 전역 error/unhandledrejection 이벤트로 올라온다.
20
+ // 앱 결함이 아니므로 오버레이, 앱 종료 대상에서 제외한다.
21
+ const EXTENSION_URL_SCHEMES = [
22
+ "chrome-extension://",
23
+ "moz-extension://",
24
+ "safari-web-extension://",
25
+ ];
26
+ // URL 스킴은 표준상 대소문자를 구분하지 않는다(RFC 3986 §3.1).
27
+ function isExtensionUrl(url) {
28
+ const lowerUrl = url.toLowerCase();
29
+ return EXTENSION_URL_SCHEMES.some((scheme) => lowerUrl.startsWith(scheme));
30
+ }
31
+ // 스택 포맷은 엔진마다 다르다(V8 은 "at fn (URL)", SpiderMonkey, JSC 는 "fn@URL").
32
+ // 포맷 대신 URL 이 처음 등장하는 줄을 최상단 프레임으로 보고, 그 URL 의 출처만 따진다.
33
+ // V8 의 "Error: 메시지" 헤더는 대개 URL 이 없어 건너뛰지만, 메시지에 URL 이 박히면 헤더가 최상단으로 잡힌다.
34
+ function isExtensionOriginRejection(reason) {
35
+ if (reason.stack == null)
36
+ return false;
37
+ for (const line of reason.stack.split("\n")) {
38
+ const topFrameUrl = /[a-z][a-z\d+.-]*:\/\/\S*/i.exec(line)?.[0];
39
+ if (topFrameUrl == null)
40
+ continue;
41
+ return isExtensionUrl(topFrameUrl);
42
+ }
43
+ return false;
44
+ }
17
45
  export function provideSdAngular(opt) {
18
46
  return makeEnvironmentProviders([
19
47
  {
@@ -73,11 +101,19 @@ export function provideSdAngular(opt) {
73
101
  const envInjector = inject(EnvironmentInjector);
74
102
  const rejectionListener = (event) => {
75
103
  event.preventDefault();
104
+ if (event.reason instanceof Error && isExtensionOriginRejection(event.reason)) {
105
+ errorLogger.warn("브라우저 확장 프로그램에서 발생한 오류로 판단해 무시함", event.reason);
106
+ return;
107
+ }
76
108
  const errorHandler = envInjector.get(ErrorHandler);
77
109
  errorHandler.handleError(event);
78
110
  };
79
111
  const errorListener = (event) => {
80
112
  event.preventDefault();
113
+ if (isExtensionUrl(event.filename)) {
114
+ errorLogger.warn("브라우저 확장 프로그램에서 발생한 오류로 판단해 무시함", `${event.message}\n${event.filename}(${event.lineno}, ${event.colno})`, event.error);
115
+ return;
116
+ }
81
117
  const errorHandler = envInjector.get(ErrorHandler);
82
118
  errorHandler.handleError(event);
83
119
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/angular",
3
- "version": "14.2.3",
3
+ "version": "14.2.4",
4
4
  "description": "심플리즘 패키지 - Angular",
5
5
  "author": "심플리즘",
6
6
  "license": "Apache-2.0",
@@ -58,10 +58,10 @@
58
58
  "jspdf": "^4.2.1",
59
59
  "rxjs": "^7.8.2",
60
60
  "tabbable": "^6.5.0",
61
- "@simplysm/core-browser": "14.2.3",
62
- "@simplysm/service-common": "14.2.3",
63
- "@simplysm/service-client": "14.2.3",
64
- "@simplysm/core-common": "14.2.3"
61
+ "@simplysm/core-browser": "14.2.4",
62
+ "@simplysm/core-common": "14.2.4",
63
+ "@simplysm/service-common": "14.2.4",
64
+ "@simplysm/service-client": "14.2.4"
65
65
  },
66
66
  "devDependencies": {
67
67
  "@angular/compiler": "^22.0.7"
@@ -33,6 +33,38 @@ import { createLogger } from "@simplysm/core-common";
33
33
 
34
34
  const logger = createLogger("angular:sw-update");
35
35
  const themeLogger = createLogger("angular:theme");
36
+ const errorLogger = createLogger("angular:global-error");
37
+
38
+ // 브라우저 확장은 자기 스크립트를 페이지 main world 에 주입해 실행하므로,
39
+ // 확장이 던진 오류도 페이지의 전역 error/unhandledrejection 이벤트로 올라온다.
40
+ // 앱 결함이 아니므로 오버레이, 앱 종료 대상에서 제외한다.
41
+ const EXTENSION_URL_SCHEMES = [
42
+ "chrome-extension://",
43
+ "moz-extension://",
44
+ "safari-web-extension://",
45
+ ];
46
+
47
+ // URL 스킴은 표준상 대소문자를 구분하지 않는다(RFC 3986 §3.1).
48
+ function isExtensionUrl(url: string): boolean {
49
+ const lowerUrl = url.toLowerCase();
50
+ return EXTENSION_URL_SCHEMES.some((scheme) => lowerUrl.startsWith(scheme));
51
+ }
52
+
53
+ // 스택 포맷은 엔진마다 다르다(V8 은 "at fn (URL)", SpiderMonkey, JSC 는 "fn@URL").
54
+ // 포맷 대신 URL 이 처음 등장하는 줄을 최상단 프레임으로 보고, 그 URL 의 출처만 따진다.
55
+ // V8 의 "Error: 메시지" 헤더는 대개 URL 이 없어 건너뛰지만, 메시지에 URL 이 박히면 헤더가 최상단으로 잡힌다.
56
+ function isExtensionOriginRejection(reason: Error): boolean {
57
+ if (reason.stack == null) return false;
58
+
59
+ for (const line of reason.stack.split("\n")) {
60
+ const topFrameUrl = /[a-z][a-z\d+.-]*:\/\/\S*/i.exec(line)?.[0];
61
+ if (topFrameUrl == null) continue;
62
+
63
+ return isExtensionUrl(topFrameUrl);
64
+ }
65
+
66
+ return false;
67
+ }
36
68
 
37
69
  export function provideSdAngular(opt: { clientName: string }): EnvironmentProviders {
38
70
  return makeEnvironmentProviders([
@@ -99,12 +131,28 @@ export function provideSdAngular(opt: { clientName: string }): EnvironmentProvid
99
131
 
100
132
  const rejectionListener = (event: PromiseRejectionEvent) => {
101
133
  event.preventDefault();
134
+
135
+ if (event.reason instanceof Error && isExtensionOriginRejection(event.reason)) {
136
+ errorLogger.warn("브라우저 확장 프로그램에서 발생한 오류로 판단해 무시함", event.reason);
137
+ return;
138
+ }
139
+
102
140
  const errorHandler = envInjector.get(ErrorHandler);
103
141
  errorHandler.handleError(event);
104
142
  };
105
143
 
106
144
  const errorListener = (event: ErrorEvent) => {
107
145
  event.preventDefault();
146
+
147
+ if (isExtensionUrl(event.filename)) {
148
+ errorLogger.warn(
149
+ "브라우저 확장 프로그램에서 발생한 오류로 판단해 무시함",
150
+ `${event.message}\n${event.filename}(${event.lineno}, ${event.colno})`,
151
+ event.error,
152
+ );
153
+ return;
154
+ }
155
+
108
156
  const errorHandler = envInjector.get(ErrorHandler);
109
157
  errorHandler.handleError(event);
110
158
  };