@remember-web/sse 0.1.0-alpha.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 (160) hide show
  1. package/README.md +238 -0
  2. package/dist/src/core/BaseSseClient.cjs.js +97 -0
  3. package/dist/src/core/BaseSseClient.cjs.js.map +1 -0
  4. package/dist/src/core/BaseSseClient.d.ts +33 -0
  5. package/dist/src/core/BaseSseClient.d.ts.map +1 -0
  6. package/dist/src/core/BaseSseClient.esm.js +89 -0
  7. package/dist/src/core/BaseSseClient.esm.js.map +1 -0
  8. package/dist/src/core/SseClient.cjs.js +382 -0
  9. package/dist/src/core/SseClient.cjs.js.map +1 -0
  10. package/dist/src/core/SseClient.d.ts +24 -0
  11. package/dist/src/core/SseClient.d.ts.map +1 -0
  12. package/dist/src/core/SseClient.esm.js +370 -0
  13. package/dist/src/core/SseClient.esm.js.map +1 -0
  14. package/dist/src/core/backoff.cjs.js +30 -0
  15. package/dist/src/core/backoff.cjs.js.map +1 -0
  16. package/dist/src/core/backoff.d.ts +12 -0
  17. package/dist/src/core/backoff.d.ts.map +1 -0
  18. package/dist/src/core/backoff.esm.js +28 -0
  19. package/dist/src/core/backoff.esm.js.map +1 -0
  20. package/dist/src/core/emitter.cjs.js +57 -0
  21. package/dist/src/core/emitter.cjs.js.map +1 -0
  22. package/dist/src/core/emitter.d.ts +14 -0
  23. package/dist/src/core/emitter.d.ts.map +1 -0
  24. package/dist/src/core/emitter.esm.js +51 -0
  25. package/dist/src/core/emitter.esm.js.map +1 -0
  26. package/dist/src/core/eventNames.cjs.js +64 -0
  27. package/dist/src/core/eventNames.cjs.js.map +1 -0
  28. package/dist/src/core/eventNames.d.ts +31 -0
  29. package/dist/src/core/eventNames.d.ts.map +1 -0
  30. package/dist/src/core/eventNames.esm.js +54 -0
  31. package/dist/src/core/eventNames.esm.js.map +1 -0
  32. package/dist/src/core/retryWait.cjs.js +20 -0
  33. package/dist/src/core/retryWait.cjs.js.map +1 -0
  34. package/dist/src/core/retryWait.d.ts +6 -0
  35. package/dist/src/core/retryWait.d.ts.map +1 -0
  36. package/dist/src/core/retryWait.esm.js +18 -0
  37. package/dist/src/core/retryWait.esm.js.map +1 -0
  38. package/dist/src/core/statusMachine.cjs.js +56 -0
  39. package/dist/src/core/statusMachine.cjs.js.map +1 -0
  40. package/dist/src/core/statusMachine.d.ts +9 -0
  41. package/dist/src/core/statusMachine.d.ts.map +1 -0
  42. package/dist/src/core/statusMachine.esm.js +54 -0
  43. package/dist/src/core/statusMachine.esm.js.map +1 -0
  44. package/dist/src/core/stream.cjs.js +136 -0
  45. package/dist/src/core/stream.cjs.js.map +1 -0
  46. package/dist/src/core/stream.d.ts +42 -0
  47. package/dist/src/core/stream.d.ts.map +1 -0
  48. package/dist/src/core/stream.esm.js +128 -0
  49. package/dist/src/core/stream.esm.js.map +1 -0
  50. package/dist/src/core/ticket.cjs.js +237 -0
  51. package/dist/src/core/ticket.cjs.js.map +1 -0
  52. package/dist/src/core/ticket.d.ts +31 -0
  53. package/dist/src/core/ticket.d.ts.map +1 -0
  54. package/dist/src/core/ticket.esm.js +220 -0
  55. package/dist/src/core/ticket.esm.js.map +1 -0
  56. package/dist/src/core/types.cjs.js +54 -0
  57. package/dist/src/core/types.cjs.js.map +1 -0
  58. package/dist/src/core/types.d.ts +131 -0
  59. package/dist/src/core/types.d.ts.map +1 -0
  60. package/dist/src/core/types.esm.js +50 -0
  61. package/dist/src/core/types.esm.js.map +1 -0
  62. package/dist/src/core/wire.cjs.js +29 -0
  63. package/dist/src/core/wire.cjs.js.map +1 -0
  64. package/dist/src/core/wire.d.ts +7 -0
  65. package/dist/src/core/wire.d.ts.map +1 -0
  66. package/dist/src/core/wire.esm.js +23 -0
  67. package/dist/src/core/wire.esm.js.map +1 -0
  68. package/dist/src/createSseClient.cjs.js +30 -0
  69. package/dist/src/createSseClient.cjs.js.map +1 -0
  70. package/dist/src/createSseClient.d.ts +8 -0
  71. package/dist/src/createSseClient.d.ts.map +1 -0
  72. package/dist/src/createSseClient.esm.js +28 -0
  73. package/dist/src/createSseClient.esm.js.map +1 -0
  74. package/dist/src/index.cjs.js +10 -0
  75. package/dist/src/index.cjs.js.map +1 -0
  76. package/dist/src/index.d.ts +6 -0
  77. package/dist/src/index.d.ts.map +1 -0
  78. package/dist/src/index.esm.js +3 -0
  79. package/dist/src/index.esm.js.map +1 -0
  80. package/dist/src/react/createSseContext.cjs.js +130 -0
  81. package/dist/src/react/createSseContext.cjs.js.map +1 -0
  82. package/dist/src/react/createSseContext.d.ts +32 -0
  83. package/dist/src/react/createSseContext.d.ts.map +1 -0
  84. package/dist/src/react/createSseContext.esm.js +122 -0
  85. package/dist/src/react/createSseContext.esm.js.map +1 -0
  86. package/dist/src/react/index.cjs.js +8 -0
  87. package/dist/src/react/index.cjs.js.map +1 -0
  88. package/dist/src/react/index.d.ts +3 -0
  89. package/dist/src/react/index.d.ts.map +1 -0
  90. package/dist/src/react/index.esm.js +2 -0
  91. package/dist/src/react/index.esm.js.map +1 -0
  92. package/dist/src/testing/doubles.d.ts +50 -0
  93. package/dist/src/testing/doubles.d.ts.map +1 -0
  94. package/dist/src/testing/harness.d.ts +43 -0
  95. package/dist/src/testing/harness.d.ts.map +1 -0
  96. package/dist/src/testing/index.d.ts +3 -0
  97. package/dist/src/testing/index.d.ts.map +1 -0
  98. package/dist/src/worker/WorkerSseClient.cjs.js +240 -0
  99. package/dist/src/worker/WorkerSseClient.cjs.js.map +1 -0
  100. package/dist/src/worker/WorkerSseClient.d.ts +23 -0
  101. package/dist/src/worker/WorkerSseClient.d.ts.map +1 -0
  102. package/dist/src/worker/WorkerSseClient.esm.js +228 -0
  103. package/dist/src/worker/WorkerSseClient.esm.js.map +1 -0
  104. package/dist/src/worker/hub.d.ts +19 -0
  105. package/dist/src/worker/hub.d.ts.map +1 -0
  106. package/dist/src/worker/portRegistry.d.ts +41 -0
  107. package/dist/src/worker/portRegistry.d.ts.map +1 -0
  108. package/dist/src/worker/protocol.d.ts +63 -0
  109. package/dist/src/worker/protocol.d.ts.map +1 -0
  110. package/dist/src/worker/sse.worker.d.ts +2 -0
  111. package/dist/src/worker/sse.worker.d.ts.map +1 -0
  112. package/dist/src/worker/ticketDelegate.d.ts +16 -0
  113. package/dist/src/worker/ticketDelegate.d.ts.map +1 -0
  114. package/dist/src/worker/workerConnection.d.ts +28 -0
  115. package/dist/src/worker/workerConnection.d.ts.map +1 -0
  116. package/dist/worker/sse.worker.js +1865 -0
  117. package/dist/worker/sse.worker.js.map +1 -0
  118. package/package.json +87 -0
  119. package/src/core/BaseSseClient.test.ts +142 -0
  120. package/src/core/BaseSseClient.ts +103 -0
  121. package/src/core/SseClient.connection.test.ts +863 -0
  122. package/src/core/SseClient.scenarios.test.ts +164 -0
  123. package/src/core/SseClient.test.ts +63 -0
  124. package/src/core/SseClient.ts +310 -0
  125. package/src/core/backoff.test.ts +43 -0
  126. package/src/core/backoff.ts +39 -0
  127. package/src/core/emitter.ts +56 -0
  128. package/src/core/eventNames.ts +53 -0
  129. package/src/core/retryWait.ts +18 -0
  130. package/src/core/statusMachine.ts +56 -0
  131. package/src/core/stream.ts +141 -0
  132. package/src/core/ticket.ts +146 -0
  133. package/src/core/types.ts +182 -0
  134. package/src/core/wire.ts +23 -0
  135. package/src/createSseClient.test.ts +82 -0
  136. package/src/createSseClient.ts +34 -0
  137. package/src/index.ts +21 -0
  138. package/src/react/SseProvider.test.tsx +129 -0
  139. package/src/react/createSseContext.test.ts +47 -0
  140. package/src/react/createSseContext.tsx +140 -0
  141. package/src/react/index.ts +2 -0
  142. package/src/react/useSseEvent.test.tsx +71 -0
  143. package/src/react/useSseStatus.test.tsx +40 -0
  144. package/src/testing/doubles.ts +128 -0
  145. package/src/testing/harness.ts +82 -0
  146. package/src/testing/index.ts +3 -0
  147. package/src/worker/SseClientLike.contract.test.ts +270 -0
  148. package/src/worker/WorkerSseClient.scenarios.test.ts +179 -0
  149. package/src/worker/WorkerSseClient.test.ts +377 -0
  150. package/src/worker/WorkerSseClient.ts +190 -0
  151. package/src/worker/hub.connection.test.ts +1023 -0
  152. package/src/worker/hub.test.ts +213 -0
  153. package/src/worker/hub.ts +120 -0
  154. package/src/worker/portRegistry.test.ts +59 -0
  155. package/src/worker/portRegistry.ts +86 -0
  156. package/src/worker/protocol.ts +80 -0
  157. package/src/worker/sse.worker.ts +19 -0
  158. package/src/worker/ticketDelegate.test.ts +99 -0
  159. package/src/worker/ticketDelegate.ts +80 -0
  160. package/src/worker/workerConnection.ts +134 -0
@@ -0,0 +1,42 @@
1
+ import type { GoawayPayload } from './types';
2
+ /**
3
+ * @description 스트림이 끊긴 이유.
4
+ * goaway는 서버가 예고하고 닫는 정상 종료라 백오프 없이 즉시 재수립하고,
5
+ * goaway-close는 서버가 재연결하지 말라고 한 것이라 루프를 끝냅니다.
6
+ */
7
+ export type StreamOutcome = 'error' | 'goaway' | 'goaway-close';
8
+ /**
9
+ * @description 끊김의 전말 — goaway 계열에만 페이로드가 붙습니다.
10
+ * 유니온으로 묶어 "outcome이 goaway일 때만 payload가 있다"를 타입이 강제하게 합니다.
11
+ */
12
+ export type StreamClosure = {
13
+ outcome: 'error';
14
+ } | {
15
+ outcome: 'goaway' | 'goaway-close';
16
+ goaway: GoawayPayload;
17
+ };
18
+ /**
19
+ * @description 한 EventSource에 리스너를 이미 건 이벤트 이름들 — 중복 부착을 막는 장부입니다.
20
+ * 소스가 바뀌면 리스너도 함께 사라지므로, 이 장부는 소스와 수명을 같이해야 합니다.
21
+ */
22
+ export type AttachedEvents = Set<string>;
23
+ /**
24
+ * @description 도메인 이벤트 리스너를 소스에 1회 부착합니다 — SDK 예약 이벤트는 소비처로 흘리지 않습니다
25
+ */
26
+ export declare const attachDomainListener: (source: EventSource, attachedEvents: AttachedEvents, type: string, deliver: (type: string, payload: unknown) => void) => void;
27
+ export interface StreamHooks {
28
+ helloTimeoutMs: number;
29
+ /** @description hello 프레임 수신 — 수립으로 인정하면 true를 반환해 타임아웃을 해제시킵니다 */
30
+ onHello: () => boolean;
31
+ /**
32
+ * @description 끊김 확정 — resolve 전에 동기로 호출됩니다 (정리·상태 전이는 호출자 몫).
33
+ * goaway면 페이로드가 함께 옵니다: 소비처가 reason으로 안내를 정하도록 그대로 넘깁니다.
34
+ */
35
+ onClosed: (closure: StreamClosure) => void;
36
+ }
37
+ /**
38
+ * @description 콜백 세계(EventSource 이벤트·타이머·abort)를 Promise 하나로 바꾸는 경계 어댑터.
39
+ * 아래 결말 4개 중 먼저 발생하는 것으로 정확히 한 번 끝나고, hello는 결말이 아니라 수립 신호입니다.
40
+ */
41
+ export declare const streamUntilClosed: (source: EventSource, signal: AbortSignal, hooks: StreamHooks) => Promise<StreamOutcome>;
42
+ //# sourceMappingURL=stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/core/stream.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG7C;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,cAAc,CAAC;AAEhE;;;GAGG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GACpB;IAAE,OAAO,EAAE,QAAQ,GAAG,cAAc,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC;AAElE;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;AA2BzC;;GAEG;AACH,eAAO,MAAM,oBAAoB,WACvB,WAAW,wCAEb,MAAM,WACH,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,KAChD,IAYF,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,OAAO,EAAE,MAAM,OAAO,CAAC;IACvB;;;OAGG;IACH,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;CAC5C;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,WACpB,WAAW,UACX,WAAW,SACZ,WAAW,KACjB,QAAQ,aAAa,CAiDpB,CAAC"}
@@ -0,0 +1,128 @@
1
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
2
+ import _typeof from '@babel/runtime/helpers/typeof';
3
+ import { isSubscribableEvent, SERVER_CONNECTION_EVENTS } from './eventNames.esm.js';
4
+ import { isGoawayReason, isGoawayAction } from './types.esm.js';
5
+
6
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
7
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
8
+
9
+ /**
10
+ * @description 스트림이 끊긴 이유.
11
+ * goaway는 서버가 예고하고 닫는 정상 종료라 백오프 없이 즉시 재수립하고,
12
+ * goaway-close는 서버가 재연결하지 말라고 한 것이라 루프를 끝냅니다.
13
+ */
14
+
15
+ /**
16
+ * @description 끊김의 전말 — goaway 계열에만 페이로드가 붙습니다.
17
+ * 유니온으로 묶어 "outcome이 goaway일 때만 payload가 있다"를 타입이 강제하게 합니다.
18
+ */
19
+
20
+ /**
21
+ * @description 한 EventSource에 리스너를 이미 건 이벤트 이름들 — 중복 부착을 막는 장부입니다.
22
+ * 소스가 바뀌면 리스너도 함께 사라지므로, 이 장부는 소스와 수명을 같이해야 합니다.
23
+ */
24
+
25
+ var parsePayload = function parsePayload(event) {
26
+ if (typeof event.data !== 'string' || event.data === '') {
27
+ return undefined;
28
+ }
29
+ try {
30
+ return JSON.parse(event.data);
31
+ } catch (_unused) {
32
+ return event.data;
33
+ }
34
+ };
35
+
36
+ // 구버전 서버·잘린 프레임에서는 필드가 없거나 미지 값이 옵니다 — 아는 값만 남기고 나머지는 버립니다
37
+ var toGoawayPayload = function toGoawayPayload(parsed) {
38
+ if (_typeof(parsed) !== 'object' || parsed === null) {
39
+ return {};
40
+ }
41
+ var _ref = parsed,
42
+ reason = _ref.reason,
43
+ action = _ref.action;
44
+ return _objectSpread(_objectSpread({}, isGoawayReason(reason) && {
45
+ reason: reason
46
+ }), isGoawayAction(action) && {
47
+ action: action
48
+ });
49
+ };
50
+
51
+ /**
52
+ * @description 도메인 이벤트 리스너를 소스에 1회 부착합니다 — SDK 예약 이벤트는 소비처로 흘리지 않습니다
53
+ */
54
+ var attachDomainListener = function attachDomainListener(source, attachedEvents, type, deliver) {
55
+ if (attachedEvents.has(type)) {
56
+ return;
57
+ }
58
+ if (!isSubscribableEvent(type)) {
59
+ return;
60
+ }
61
+ attachedEvents.add(type);
62
+ source.addEventListener(type, function (event) {
63
+ deliver(type, parsePayload(event));
64
+ });
65
+ };
66
+ /**
67
+ * @description 콜백 세계(EventSource 이벤트·타이머·abort)를 Promise 하나로 바꾸는 경계 어댑터.
68
+ * 아래 결말 4개 중 먼저 발생하는 것으로 정확히 한 번 끝나고, hello는 결말이 아니라 수립 신호입니다.
69
+ */
70
+ var streamUntilClosed = function streamUntilClosed(source, signal, hooks) {
71
+ return new Promise(function (resolve) {
72
+ var settled = false;
73
+ var settle = function settle(closure, options) {
74
+ if (settled) {
75
+ return;
76
+ }
77
+ settled = true;
78
+ clearTimeout(helloTimer);
79
+ signal.removeEventListener('abort', onAbort);
80
+ if (options.notifyClosed) {
81
+ hooks.onClosed(closure);
82
+ }
83
+ resolve(closure.outcome);
84
+ };
85
+ var helloTimer = setTimeout(function () {
86
+ return settle({
87
+ outcome: 'error'
88
+ }, {
89
+ notifyClosed: true
90
+ });
91
+ }, hooks.helloTimeoutMs);
92
+ source.addEventListener(SERVER_CONNECTION_EVENTS.goaway, function (event) {
93
+ var goaway = toGoawayPayload(parsePayload(event));
94
+ settle({
95
+ outcome: goaway.action === 'close' ? 'goaway-close' : 'goaway',
96
+ goaway: goaway
97
+ }, {
98
+ notifyClosed: true
99
+ });
100
+ });
101
+ source.onerror = function () {
102
+ return settle({
103
+ outcome: 'error'
104
+ }, {
105
+ notifyClosed: true
106
+ });
107
+ };
108
+ var onAbort = function onAbort() {
109
+ return settle({
110
+ outcome: 'error'
111
+ }, {
112
+ notifyClosed: false
113
+ });
114
+ };
115
+ signal.addEventListener('abort', onAbort);
116
+ source.addEventListener(SERVER_CONNECTION_EVENTS.hello, function () {
117
+ if (settled) {
118
+ return;
119
+ }
120
+ if (hooks.onHello()) {
121
+ clearTimeout(helloTimer);
122
+ }
123
+ });
124
+ });
125
+ };
126
+
127
+ export { attachDomainListener, streamUntilClosed };
128
+ //# sourceMappingURL=stream.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.esm.js","sources":["../../../src/core/stream.ts"],"sourcesContent":["import { isSubscribableEvent, SERVER_CONNECTION_EVENTS } from './eventNames';\nimport type { GoawayPayload } from './types';\nimport { isGoawayAction, isGoawayReason } from './types';\n\n/**\n * @description 스트림이 끊긴 이유.\n * goaway는 서버가 예고하고 닫는 정상 종료라 백오프 없이 즉시 재수립하고,\n * goaway-close는 서버가 재연결하지 말라고 한 것이라 루프를 끝냅니다.\n */\nexport type StreamOutcome = 'error' | 'goaway' | 'goaway-close';\n\n/**\n * @description 끊김의 전말 — goaway 계열에만 페이로드가 붙습니다.\n * 유니온으로 묶어 \"outcome이 goaway일 때만 payload가 있다\"를 타입이 강제하게 합니다.\n */\nexport type StreamClosure =\n | { outcome: 'error' }\n | { outcome: 'goaway' | 'goaway-close'; goaway: GoawayPayload };\n\n/**\n * @description 한 EventSource에 리스너를 이미 건 이벤트 이름들 — 중복 부착을 막는 장부입니다.\n * 소스가 바뀌면 리스너도 함께 사라지므로, 이 장부는 소스와 수명을 같이해야 합니다.\n */\nexport type AttachedEvents = Set<string>;\n\nconst parsePayload = (event: { data?: unknown }): unknown => {\n if (typeof event.data !== 'string' || event.data === '') {\n return undefined;\n }\n try {\n return JSON.parse(event.data);\n } catch {\n return event.data;\n }\n};\n\n// 구버전 서버·잘린 프레임에서는 필드가 없거나 미지 값이 옵니다 — 아는 값만 남기고 나머지는 버립니다\nconst toGoawayPayload = (parsed: unknown): GoawayPayload => {\n if (typeof parsed !== 'object' || parsed === null) {\n return {};\n }\n\n const { reason, action } = parsed as { reason?: unknown; action?: unknown };\n\n return {\n ...(isGoawayReason(reason) && { reason }),\n ...(isGoawayAction(action) && { action }),\n };\n};\n\n/**\n * @description 도메인 이벤트 리스너를 소스에 1회 부착합니다 — SDK 예약 이벤트는 소비처로 흘리지 않습니다\n */\nexport const attachDomainListener = (\n source: EventSource,\n attachedEvents: AttachedEvents,\n type: string,\n deliver: (type: string, payload: unknown) => void\n): void => {\n if (attachedEvents.has(type)) {\n return;\n }\n if (!isSubscribableEvent(type)) {\n return;\n }\n\n attachedEvents.add(type);\n source.addEventListener(type, (event) => {\n deliver(type, parsePayload(event));\n });\n};\n\nexport interface StreamHooks {\n helloTimeoutMs: number;\n /** @description hello 프레임 수신 — 수립으로 인정하면 true를 반환해 타임아웃을 해제시킵니다 */\n onHello: () => boolean;\n /**\n * @description 끊김 확정 — resolve 전에 동기로 호출됩니다 (정리·상태 전이는 호출자 몫).\n * goaway면 페이로드가 함께 옵니다: 소비처가 reason으로 안내를 정하도록 그대로 넘깁니다.\n */\n onClosed: (closure: StreamClosure) => void;\n}\n\n/**\n * @description 콜백 세계(EventSource 이벤트·타이머·abort)를 Promise 하나로 바꾸는 경계 어댑터.\n * 아래 결말 4개 중 먼저 발생하는 것으로 정확히 한 번 끝나고, hello는 결말이 아니라 수립 신호입니다.\n */\nexport const streamUntilClosed = (\n source: EventSource,\n signal: AbortSignal,\n hooks: StreamHooks\n): Promise<StreamOutcome> =>\n new Promise((resolve) => {\n let settled = false;\n\n const settle = (\n closure: StreamClosure,\n options: { notifyClosed: boolean }\n ) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(helloTimer);\n signal.removeEventListener('abort', onAbort);\n if (options.notifyClosed) {\n hooks.onClosed(closure);\n }\n resolve(closure.outcome);\n };\n\n const helloTimer = setTimeout(\n () => settle({ outcome: 'error' }, { notifyClosed: true }),\n hooks.helloTimeoutMs\n );\n\n source.addEventListener(SERVER_CONNECTION_EVENTS.goaway, (event) => {\n const goaway = toGoawayPayload(parsePayload(event));\n settle(\n {\n outcome: goaway.action === 'close' ? 'goaway-close' : 'goaway',\n goaway,\n },\n { notifyClosed: true }\n );\n });\n\n source.onerror = () => settle({ outcome: 'error' }, { notifyClosed: true });\n\n const onAbort = () => settle({ outcome: 'error' }, { notifyClosed: false });\n signal.addEventListener('abort', onAbort);\n\n source.addEventListener(SERVER_CONNECTION_EVENTS.hello, () => {\n if (settled) {\n return;\n }\n if (hooks.onHello()) {\n clearTimeout(helloTimer);\n }\n });\n });\n"],"names":["parsePayload","event","data","undefined","JSON","parse","_unused","toGoawayPayload","parsed","_typeof","_ref","reason","action","_objectSpread","isGoawayReason","isGoawayAction","attachDomainListener","source","attachedEvents","type","deliver","has","isSubscribableEvent","add","addEventListener","streamUntilClosed","signal","hooks","Promise","resolve","settled","settle","closure","options","clearTimeout","helloTimer","removeEventListener","onAbort","notifyClosed","onClosed","outcome","setTimeout","helloTimeoutMs","SERVER_CONNECTION_EVENTS","goaway","onerror","hello","onHello"],"mappings":"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"}
@@ -0,0 +1,237 @@
1
+ 'use strict';
2
+
3
+ var _typeof = require('@babel/runtime/helpers/typeof');
4
+ var _asyncToGenerator = require('@babel/runtime/helpers/asyncToGenerator');
5
+ var _createClass = require('@babel/runtime/helpers/createClass');
6
+ var _classCallCheck = require('@babel/runtime/helpers/classCallCheck');
7
+ var _possibleConstructorReturn = require('@babel/runtime/helpers/possibleConstructorReturn');
8
+ var _getPrototypeOf = require('@babel/runtime/helpers/getPrototypeOf');
9
+ var _inherits = require('@babel/runtime/helpers/inherits');
10
+ var _wrapNativeSuper = require('@babel/runtime/helpers/wrapNativeSuper');
11
+ var _regeneratorRuntime = require('@babel/runtime/regenerator');
12
+
13
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
+
15
+ var _typeof__default = /*#__PURE__*/_interopDefault(_typeof);
16
+ var _asyncToGenerator__default = /*#__PURE__*/_interopDefault(_asyncToGenerator);
17
+ var _createClass__default = /*#__PURE__*/_interopDefault(_createClass);
18
+ var _classCallCheck__default = /*#__PURE__*/_interopDefault(_classCallCheck);
19
+ var _possibleConstructorReturn__default = /*#__PURE__*/_interopDefault(_possibleConstructorReturn);
20
+ var _getPrototypeOf__default = /*#__PURE__*/_interopDefault(_getPrototypeOf);
21
+ var _inherits__default = /*#__PURE__*/_interopDefault(_inherits);
22
+ var _wrapNativeSuper__default = /*#__PURE__*/_interopDefault(_wrapNativeSuper);
23
+ var _regeneratorRuntime__default = /*#__PURE__*/_interopDefault(_regeneratorRuntime);
24
+
25
+ function _callSuper(t, o, e) { return o = _getPrototypeOf__default.default(o), _possibleConstructorReturn__default.default(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf__default.default(t).constructor) : o.apply(t, e)); }
26
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
27
+
28
+ /**
29
+ * @description 티켓 발급 실패의 분류 — status 부재 = 네트워크성, cause = 네트워크가 아닌 실패의 출처.
30
+ * 워커 프로토콜이 이 객체를 그대로 실어 나르므로 직렬화 가능한 값만 담습니다.
31
+ */
32
+
33
+ var TICKET_TIMEOUT_MS = 10000;
34
+ var TICKET_NETWORK_FAILURE = Object.freeze({
35
+ ok: false,
36
+ error: Object.freeze({})
37
+ });
38
+ var TICKET_AUTH_CALLBACK_FAILURE = Object.freeze({
39
+ ok: false,
40
+ error: Object.freeze({
41
+ cause: 'auth_callback'
42
+ })
43
+ });
44
+ var AuthTokenError = /*#__PURE__*/function (_Error) {
45
+ function AuthTokenError(message, options) {
46
+ var _this;
47
+ _classCallCheck__default.default(this, AuthTokenError);
48
+ _this = _callSuper(this, AuthTokenError, [message, options]);
49
+ _this.name = 'AuthTokenError';
50
+ return _this;
51
+ }
52
+ _inherits__default.default(AuthTokenError, _Error);
53
+ return _createClass__default.default(AuthTokenError);
54
+ }(/*#__PURE__*/_wrapNativeSuper__default.default(Error));
55
+ var resolveAuthToken = /*#__PURE__*/function () {
56
+ var _ref = _asyncToGenerator__default.default(/*#__PURE__*/_regeneratorRuntime__default.default.mark(function _callee(getAuthToken) {
57
+ return _regeneratorRuntime__default.default.wrap(function _callee$(_context) {
58
+ while (1) switch (_context.prev = _context.next) {
59
+ case 0:
60
+ _context.prev = 0;
61
+ _context.next = 3;
62
+ return getAuthToken();
63
+ case 3:
64
+ return _context.abrupt("return", _context.sent);
65
+ case 6:
66
+ _context.prev = 6;
67
+ _context.t0 = _context["catch"](0);
68
+ throw new AuthTokenError('getAuthToken threw', {
69
+ cause: _context.t0
70
+ });
71
+ case 9:
72
+ case "end":
73
+ return _context.stop();
74
+ }
75
+ }, _callee, null, [[0, 6]]);
76
+ }));
77
+ return function resolveAuthToken(_x) {
78
+ return _ref.apply(this, arguments);
79
+ };
80
+ }();
81
+ var authHeaders = function authHeaders(token) {
82
+ return token === null ? undefined : {
83
+ Authorization: "Bearer ".concat(token)
84
+ };
85
+ };
86
+ var hasTicket = function hasTicket(body) {
87
+ if (_typeof__default.default(body) !== 'object' || body === null) {
88
+ return false;
89
+ }
90
+ var _ref2 = body,
91
+ data = _ref2.data;
92
+ return _typeof__default.default(data) === 'object' && data !== null && typeof data.ticket === 'string';
93
+ };
94
+
95
+ /**
96
+ * @description 본문을 계약({ data: { ticket: string } } — 사내 기본 응답 스키마)으로 좁혀 값으로 돌려줍니다 —
97
+ * 파싱 실패(게이트웨이·프록시가 200으로 주는 HTML 등)와 형태 위반(ticket 부재)을 가르지 않습니다:
98
+ * 어느 쪽이든 서버가 응답한 본문 계약 위반이고, 경로 생존 증거라 status를 실어 네트워크성 연속 판정을 끊습니다.
99
+ * 이 분기는 stalled·fatal 어느 쪽에도 닿지 않는 유일한 침묵 실패라 warn을 남깁니다 — 서버 로그에도 흔적이
100
+ * 없는 실패(서버 입장에선 정상 200)여서 이 로그가 유일한 단서입니다.
101
+ */
102
+ var parseTicketBody = /*#__PURE__*/function () {
103
+ var _ref3 = _asyncToGenerator__default.default(/*#__PURE__*/_regeneratorRuntime__default.default.mark(function _callee2(response, logger) {
104
+ var body;
105
+ return _regeneratorRuntime__default.default.wrap(function _callee2$(_context2) {
106
+ while (1) switch (_context2.prev = _context2.next) {
107
+ case 0:
108
+ _context2.next = 2;
109
+ return response.json()["catch"](function () {
110
+ return null;
111
+ });
112
+ case 2:
113
+ body = _context2.sent;
114
+ if (hasTicket(body)) {
115
+ _context2.next = 6;
116
+ break;
117
+ }
118
+ logger === null || logger === void 0 || logger.warn("sse: \uD2F0\uCF13 \uC751\uB2F5(".concat(response.status, ") \uBCF8\uBB38\uC774 \uACC4\uC57D({ data: { ticket } })\uACFC \uB2E4\uB985\uB2C8\uB2E4 \u2014 \uC7AC\uC2DC\uB3C4\uB294 \uACC4\uC18D\uD569\uB2C8\uB2E4"));
119
+ return _context2.abrupt("return", {
120
+ ok: false,
121
+ error: {
122
+ status: response.status
123
+ }
124
+ });
125
+ case 6:
126
+ return _context2.abrupt("return", {
127
+ ok: true,
128
+ ticket: body.data.ticket
129
+ });
130
+ case 7:
131
+ case "end":
132
+ return _context2.stop();
133
+ }
134
+ }, _callee2);
135
+ }));
136
+ return function parseTicketBody(_x2, _x3) {
137
+ return _ref3.apply(this, arguments);
138
+ };
139
+ }();
140
+
141
+ /**
142
+ * @description 연결 티켓을 발급합니다 — TTL 15s이므로 발급 즉시 연결해야 합니다
143
+ */
144
+ var issueTicket = /*#__PURE__*/function () {
145
+ var _ref4 = _asyncToGenerator__default.default(/*#__PURE__*/_regeneratorRuntime__default.default.mark(function _callee3(options) {
146
+ var _options$fetch;
147
+ var fetchImpl, token, response, _options$logger;
148
+ return _regeneratorRuntime__default.default.wrap(function _callee3$(_context3) {
149
+ while (1) switch (_context3.prev = _context3.next) {
150
+ case 0:
151
+ fetchImpl = (_options$fetch = options.fetch) !== null && _options$fetch !== void 0 ? _options$fetch : globalThis.fetch;
152
+ _context3.prev = 1;
153
+ _context3.next = 4;
154
+ return resolveAuthToken(options.getAuthToken);
155
+ case 4:
156
+ token = _context3.sent;
157
+ _context3.next = 7;
158
+ return fetchImpl("".concat(options.baseUrl, "/v1/events/ticket"), {
159
+ method: 'POST',
160
+ headers: authHeaders(token)
161
+ });
162
+ case 7:
163
+ response = _context3.sent;
164
+ if (response.ok) {
165
+ _context3.next = 10;
166
+ break;
167
+ }
168
+ return _context3.abrupt("return", {
169
+ ok: false,
170
+ error: {
171
+ status: response.status
172
+ }
173
+ });
174
+ case 10:
175
+ _context3.next = 12;
176
+ return parseTicketBody(response, options.logger);
177
+ case 12:
178
+ return _context3.abrupt("return", _context3.sent);
179
+ case 15:
180
+ _context3.prev = 15;
181
+ _context3.t0 = _context3["catch"](1);
182
+ if (!(_context3.t0 instanceof AuthTokenError)) {
183
+ _context3.next = 20;
184
+ break;
185
+ }
186
+ // 정지 결정은 SseClient 몫이지만, 로그는 원인 예외가 있는 여기서 한 번만 — 워커 경로에선 탭 스코프라 유일한 기록입니다
187
+ (_options$logger = options.logger) === null || _options$logger === void 0 || _options$logger.error('sse: getAuthToken이 예외를 던져 멈춥니다 — 콜백은 실패 시 null을 반환해야 합니다', _context3.t0.cause);
188
+ return _context3.abrupt("return", TICKET_AUTH_CALLBACK_FAILURE);
189
+ case 20:
190
+ return _context3.abrupt("return", TICKET_NETWORK_FAILURE);
191
+ case 21:
192
+ case "end":
193
+ return _context3.stop();
194
+ }
195
+ }, _callee3, null, [[1, 15]]);
196
+ }));
197
+ return function issueTicket(_x4) {
198
+ return _ref4.apply(this, arguments);
199
+ };
200
+ }();
201
+
202
+ /**
203
+ * @description 티켓 발급에 시간 제한을 겁니다 — 타임아웃 이후 도착한 응답은 race가 이미 완료돼 무시됩니다
204
+ */
205
+ var issueTicketWithTimeout = /*#__PURE__*/function () {
206
+ var _ref5 = _asyncToGenerator__default.default(/*#__PURE__*/_regeneratorRuntime__default.default.mark(function _callee4(options) {
207
+ var ticketTimer, ticketTimeout, result;
208
+ return _regeneratorRuntime__default.default.wrap(function _callee4$(_context4) {
209
+ while (1) switch (_context4.prev = _context4.next) {
210
+ case 0:
211
+ ticketTimeout = new Promise(function (resolve) {
212
+ ticketTimer = setTimeout(function () {
213
+ return resolve(TICKET_NETWORK_FAILURE);
214
+ }, TICKET_TIMEOUT_MS);
215
+ });
216
+ _context4.next = 3;
217
+ return Promise.race([issueTicket(options), ticketTimeout]);
218
+ case 3:
219
+ result = _context4.sent;
220
+ clearTimeout(ticketTimer);
221
+ return _context4.abrupt("return", result);
222
+ case 6:
223
+ case "end":
224
+ return _context4.stop();
225
+ }
226
+ }, _callee4);
227
+ }));
228
+ return function issueTicketWithTimeout(_x5) {
229
+ return _ref5.apply(this, arguments);
230
+ };
231
+ }();
232
+
233
+ exports.TICKET_NETWORK_FAILURE = TICKET_NETWORK_FAILURE;
234
+ exports.TICKET_TIMEOUT_MS = TICKET_TIMEOUT_MS;
235
+ exports.issueTicket = issueTicket;
236
+ exports.issueTicketWithTimeout = issueTicketWithTimeout;
237
+ //# sourceMappingURL=ticket.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket.cjs.js","sources":["../../../src/core/ticket.ts"],"sourcesContent":["import type { FatalCause, SseClientOptions, SseLogger } from './types';\n\n// 티켓 층이 만드는 cause의 단일 원천 — fatal로 그대로 이어지므로 FatalCause의 부분집합이어야 합니다(satisfies가 강제)\nconst TICKET_FAILURE_CAUSES = [\n 'auth_callback',\n] as const satisfies readonly FatalCause[];\n\ntype TicketFailureCause = (typeof TICKET_FAILURE_CAUSES)[number];\n\n/**\n * @description 티켓 발급 실패의 분류 — status 부재 = 네트워크성, cause = 네트워크가 아닌 실패의 출처.\n * 워커 프로토콜이 이 객체를 그대로 실어 나르므로 직렬화 가능한 값만 담습니다.\n */\nexport interface TicketError {\n status?: number;\n // 와이어 너머의 신·구 버전이 미지 cause를 보낼 수 있습니다 — 코어는 아는 값만 동등 비교로 골라 씁니다\n cause?: TicketFailureCause | (string & Record<never, never>);\n}\n\nexport type TicketResult =\n | { ok: true; ticket: string }\n | { ok: false; error: TicketError };\n\ntype ServerContractOptions = Pick<\n SseClientOptions,\n 'baseUrl' | 'getAuthToken' | 'fetch' | 'logger'\n>;\n\nexport const TICKET_TIMEOUT_MS = 10_000;\n\nexport const TICKET_NETWORK_FAILURE: TicketResult = Object.freeze({\n ok: false,\n error: Object.freeze({}),\n});\n\nconst TICKET_AUTH_CALLBACK_FAILURE: TicketResult = Object.freeze({\n ok: false,\n error: Object.freeze({ cause: 'auth_callback' as const }),\n});\n\nclass AuthTokenError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = 'AuthTokenError';\n }\n}\n\nconst resolveAuthToken = async (\n getAuthToken: ServerContractOptions['getAuthToken']\n): Promise<string | null> => {\n try {\n return await getAuthToken();\n } catch (error) {\n throw new AuthTokenError('getAuthToken threw', { cause: error });\n }\n};\n\nconst authHeaders = (token: string | null) =>\n token === null ? undefined : { Authorization: `Bearer ${token}` };\n\nconst hasTicket = (body: unknown): body is { data: { ticket: string } } => {\n if (typeof body !== 'object' || body === null) {\n return false;\n }\n const { data } = body as { data?: unknown };\n return (\n typeof data === 'object' &&\n data !== null &&\n typeof (data as { ticket?: unknown }).ticket === 'string'\n );\n};\n\n/**\n * @description 본문을 계약({ data: { ticket: string } } — 사내 기본 응답 스키마)으로 좁혀 값으로 돌려줍니다 —\n * 파싱 실패(게이트웨이·프록시가 200으로 주는 HTML 등)와 형태 위반(ticket 부재)을 가르지 않습니다:\n * 어느 쪽이든 서버가 응답한 본문 계약 위반이고, 경로 생존 증거라 status를 실어 네트워크성 연속 판정을 끊습니다.\n * 이 분기는 stalled·fatal 어느 쪽에도 닿지 않는 유일한 침묵 실패라 warn을 남깁니다 — 서버 로그에도 흔적이\n * 없는 실패(서버 입장에선 정상 200)여서 이 로그가 유일한 단서입니다.\n */\nconst parseTicketBody = async (\n response: Response,\n logger?: SseLogger\n): Promise<TicketResult> => {\n const body: unknown = await response.json().catch(() => null);\n if (!hasTicket(body)) {\n logger?.warn(\n `sse: 티켓 응답(${response.status}) 본문이 계약({ data: { ticket } })과 다릅니다 — 재시도는 계속합니다`\n );\n return { ok: false, error: { status: response.status } };\n }\n return { ok: true, ticket: body.data.ticket };\n};\n\n/**\n * @description 연결 티켓을 발급합니다 — TTL 15s이므로 발급 즉시 연결해야 합니다\n */\nexport const issueTicket = async (\n options: ServerContractOptions\n): Promise<TicketResult> => {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n\n try {\n const token = await resolveAuthToken(options.getAuthToken);\n const response = await fetchImpl(`${options.baseUrl}/v1/events/ticket`, {\n method: 'POST',\n headers: authHeaders(token),\n });\n\n if (!response.ok) {\n return { ok: false, error: { status: response.status } };\n }\n\n return await parseTicketBody(response, options.logger);\n } catch (error) {\n if (error instanceof AuthTokenError) {\n // 정지 결정은 SseClient 몫이지만, 로그는 원인 예외가 있는 여기서 한 번만 — 워커 경로에선 탭 스코프라 유일한 기록입니다\n options.logger?.error(\n 'sse: getAuthToken이 예외를 던져 멈춥니다 — 콜백은 실패 시 null을 반환해야 합니다',\n error.cause\n );\n return TICKET_AUTH_CALLBACK_FAILURE;\n }\n return TICKET_NETWORK_FAILURE;\n }\n};\n\n/**\n * @description 티켓 발급에 시간 제한을 겁니다 — 타임아웃 이후 도착한 응답은 race가 이미 완료돼 무시됩니다\n */\nexport const issueTicketWithTimeout = async (\n options: ServerContractOptions\n): Promise<TicketResult> => {\n let ticketTimer: ReturnType<typeof setTimeout> | undefined;\n\n const ticketTimeout = new Promise<TicketResult>((resolve) => {\n ticketTimer = setTimeout(\n () => resolve(TICKET_NETWORK_FAILURE),\n TICKET_TIMEOUT_MS\n );\n });\n\n const result = await Promise.race([issueTicket(options), ticketTimeout]);\n clearTimeout(ticketTimer);\n\n return result;\n};\n"],"names":["TICKET_TIMEOUT_MS","TICKET_NETWORK_FAILURE","Object","freeze","ok","error","TICKET_AUTH_CALLBACK_FAILURE","cause","AuthTokenError","_Error","message","options","_this","_classCallCheck","_callSuper","name","_inherits","_createClass","_wrapNativeSuper","Error","resolveAuthToken","_ref","_asyncToGenerator","_regeneratorRuntime","mark","_callee","getAuthToken","wrap","_callee$","_context","prev","next","abrupt","sent","t0","stop","_x","apply","arguments","authHeaders","token","undefined","Authorization","concat","hasTicket","body","_typeof","_ref2","data","ticket","parseTicketBody","_ref3","_callee2","response","logger","_callee2$","_context2","json","warn","status","_x2","_x3","issueTicket","_ref4","_callee3","_options$fetch","fetchImpl","_options$logger","_callee3$","_context3","fetch","globalThis","baseUrl","method","headers","_x4","issueTicketWithTimeout","_ref5","_callee4","ticketTimer","ticketTimeout","result","_callee4$","_context4","Promise","resolve","setTimeout","race","clearTimeout","_x5"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { SseClientOptions } from './types';
2
+ declare const TICKET_FAILURE_CAUSES: readonly ["auth_callback"];
3
+ type TicketFailureCause = (typeof TICKET_FAILURE_CAUSES)[number];
4
+ /**
5
+ * @description 티켓 발급 실패의 분류 — status 부재 = 네트워크성, cause = 네트워크가 아닌 실패의 출처.
6
+ * 워커 프로토콜이 이 객체를 그대로 실어 나르므로 직렬화 가능한 값만 담습니다.
7
+ */
8
+ export interface TicketError {
9
+ status?: number;
10
+ cause?: TicketFailureCause | (string & Record<never, never>);
11
+ }
12
+ export type TicketResult = {
13
+ ok: true;
14
+ ticket: string;
15
+ } | {
16
+ ok: false;
17
+ error: TicketError;
18
+ };
19
+ type ServerContractOptions = Pick<SseClientOptions, 'baseUrl' | 'getAuthToken' | 'fetch' | 'logger'>;
20
+ export declare const TICKET_TIMEOUT_MS = 10000;
21
+ export declare const TICKET_NETWORK_FAILURE: TicketResult;
22
+ /**
23
+ * @description 연결 티켓을 발급합니다 — TTL 15s이므로 발급 즉시 연결해야 합니다
24
+ */
25
+ export declare const issueTicket: (options: ServerContractOptions) => Promise<TicketResult>;
26
+ /**
27
+ * @description 티켓 발급에 시간 제한을 겁니다 — 타임아웃 이후 도착한 응답은 race가 이미 완료돼 무시됩니다
28
+ */
29
+ export declare const issueTicketWithTimeout: (options: ServerContractOptions) => Promise<TicketResult>;
30
+ export {};
31
+ //# sourceMappingURL=ticket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket.d.ts","sourceRoot":"","sources":["../../../src/core/ticket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,gBAAgB,EAAa,MAAM,SAAS,CAAC;AAGvE,QAAA,MAAM,qBAAqB,4BAEe,CAAC;AAE3C,KAAK,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,KAAK,CAAC,EAAE,kBAAkB,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;CAC9D;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAC;AAEtC,KAAK,qBAAqB,GAAG,IAAI,CAC/B,gBAAgB,EAChB,SAAS,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAChD,CAAC;AAEF,eAAO,MAAM,iBAAiB,QAAS,CAAC;AAExC,eAAO,MAAM,sBAAsB,EAAE,YAGnC,CAAC;AA4DH;;GAEG;AACH,eAAO,MAAM,WAAW,YACb,qBAAqB,KAC7B,QAAQ,YAAY,CA0BtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,YACxB,qBAAqB,KAC7B,QAAQ,YAAY,CActB,CAAC"}