@stapel/chat-react 0.1.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.
Files changed (195) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/MODULE.md +118 -0
  3. package/README.md +126 -0
  4. package/dist/api/chatApi.d.ts +49 -0
  5. package/dist/api/chatApi.d.ts.map +1 -0
  6. package/dist/api/chatApi.js +46 -0
  7. package/dist/api/chatApi.js.map +1 -0
  8. package/dist/api/extensions.d.ts +19 -0
  9. package/dist/api/extensions.d.ts.map +1 -0
  10. package/dist/api/extensions.js +19 -0
  11. package/dist/api/extensions.js.map +1 -0
  12. package/dist/api/generated/schema.d.ts +547 -0
  13. package/dist/api/generated/schema.d.ts.map +1 -0
  14. package/dist/api/generated/schema.js +2 -0
  15. package/dist/api/generated/schema.js.map +1 -0
  16. package/dist/api/types.d.ts +75 -0
  17. package/dist/api/types.d.ts.map +1 -0
  18. package/dist/api/types.js +2 -0
  19. package/dist/api/types.js.map +1 -0
  20. package/dist/default/ConversationListPanel.d.ts +22 -0
  21. package/dist/default/ConversationListPanel.d.ts.map +1 -0
  22. package/dist/default/ConversationListPanel.js +49 -0
  23. package/dist/default/ConversationListPanel.js.map +1 -0
  24. package/dist/default/ConversationThreadPanel.d.ts +21 -0
  25. package/dist/default/ConversationThreadPanel.d.ts.map +1 -0
  26. package/dist/default/ConversationThreadPanel.js +51 -0
  27. package/dist/default/ConversationThreadPanel.js.map +1 -0
  28. package/dist/default/ErrorAlert.d.ts +8 -0
  29. package/dist/default/ErrorAlert.d.ts.map +1 -0
  30. package/dist/default/ErrorAlert.js +26 -0
  31. package/dist/default/ErrorAlert.js.map +1 -0
  32. package/dist/default/StartChatButton.d.ts +17 -0
  33. package/dist/default/StartChatButton.d.ts.map +1 -0
  34. package/dist/default/StartChatButton.js +18 -0
  35. package/dist/default/StartChatButton.js.map +1 -0
  36. package/dist/default/index.d.ts +21 -0
  37. package/dist/default/index.d.ts.map +1 -0
  38. package/dist/default/index.js +18 -0
  39. package/dist/default/index.js.map +1 -0
  40. package/dist/flows/errors.d.ts +12 -0
  41. package/dist/flows/errors.d.ts.map +1 -0
  42. package/dist/flows/errors.js +13 -0
  43. package/dist/flows/errors.js.map +1 -0
  44. package/dist/flows/freshness.d.ts +69 -0
  45. package/dist/flows/freshness.d.ts.map +1 -0
  46. package/dist/flows/freshness.js +227 -0
  47. package/dist/flows/freshness.js.map +1 -0
  48. package/dist/flows/registry.d.ts +26 -0
  49. package/dist/flows/registry.d.ts.map +1 -0
  50. package/dist/flows/registry.js +24 -0
  51. package/dist/flows/registry.js.map +1 -0
  52. package/dist/headless/ChatProvider.d.ts +22 -0
  53. package/dist/headless/ChatProvider.d.ts.map +1 -0
  54. package/dist/headless/ChatProvider.js +18 -0
  55. package/dist/headless/ChatProvider.js.map +1 -0
  56. package/dist/headless/ConversationList.d.ts +51 -0
  57. package/dist/headless/ConversationList.d.ts.map +1 -0
  58. package/dist/headless/ConversationList.js +47 -0
  59. package/dist/headless/ConversationList.js.map +1 -0
  60. package/dist/headless/ConversationThread.d.ts +50 -0
  61. package/dist/headless/ConversationThread.d.ts.map +1 -0
  62. package/dist/headless/ConversationThread.js +64 -0
  63. package/dist/headless/ConversationThread.js.map +1 -0
  64. package/dist/headless/MessageComposer.d.ts +39 -0
  65. package/dist/headless/MessageComposer.d.ts.map +1 -0
  66. package/dist/headless/MessageComposer.js +45 -0
  67. package/dist/headless/MessageComposer.js.map +1 -0
  68. package/dist/headless/StartDirectChat.d.ts +40 -0
  69. package/dist/headless/StartDirectChat.d.ts.map +1 -0
  70. package/dist/headless/StartDirectChat.js +46 -0
  71. package/dist/headless/StartDirectChat.js.map +1 -0
  72. package/dist/i18n/errorsMap.d.ts +10 -0
  73. package/dist/i18n/errorsMap.d.ts.map +1 -0
  74. package/dist/i18n/errorsMap.js +20 -0
  75. package/dist/i18n/errorsMap.js.map +1 -0
  76. package/dist/i18n/es.d.ts +23 -0
  77. package/dist/i18n/es.d.ts.map +1 -0
  78. package/dist/i18n/es.js +75 -0
  79. package/dist/i18n/es.js.map +1 -0
  80. package/dist/i18n/generated/errors.es.gen.d.ts +16 -0
  81. package/dist/i18n/generated/errors.es.gen.d.ts.map +1 -0
  82. package/dist/i18n/generated/errors.es.gen.js +58 -0
  83. package/dist/i18n/generated/errors.es.gen.js.map +1 -0
  84. package/dist/i18n/generated/errors.gen.d.ts +359 -0
  85. package/dist/i18n/generated/errors.gen.d.ts.map +1 -0
  86. package/dist/i18n/generated/errors.gen.js +183 -0
  87. package/dist/i18n/generated/errors.gen.js.map +1 -0
  88. package/dist/i18n/generated/errors.ru.gen.d.ts +16 -0
  89. package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -0
  90. package/dist/i18n/generated/errors.ru.gen.js +58 -0
  91. package/dist/i18n/generated/errors.ru.gen.js.map +1 -0
  92. package/dist/i18n/keys.d.ts +78 -0
  93. package/dist/i18n/keys.d.ts.map +1 -0
  94. package/dist/i18n/keys.js +130 -0
  95. package/dist/i18n/keys.js.map +1 -0
  96. package/dist/i18n/ru.d.ts +28 -0
  97. package/dist/i18n/ru.d.ts.map +1 -0
  98. package/dist/i18n/ru.js +80 -0
  99. package/dist/i18n/ru.js.map +1 -0
  100. package/dist/index.d.ts +61 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +55 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/model/context.d.ts +11 -0
  105. package/dist/model/context.d.ts.map +1 -0
  106. package/dist/model/context.js +16 -0
  107. package/dist/model/context.js.map +1 -0
  108. package/dist/model/limits.d.ts +12 -0
  109. package/dist/model/limits.d.ts.map +1 -0
  110. package/dist/model/limits.js +12 -0
  111. package/dist/model/limits.js.map +1 -0
  112. package/dist/model/mutations.d.ts +66 -0
  113. package/dist/model/mutations.d.ts.map +1 -0
  114. package/dist/model/mutations.js +156 -0
  115. package/dist/model/mutations.js.map +1 -0
  116. package/dist/model/queries.d.ts +33 -0
  117. package/dist/model/queries.d.ts.map +1 -0
  118. package/dist/model/queries.js +93 -0
  119. package/dist/model/queries.js.map +1 -0
  120. package/dist/model/queryKeys.d.ts +8 -0
  121. package/dist/model/queryKeys.d.ts.map +1 -0
  122. package/dist/model/queryKeys.js +26 -0
  123. package/dist/model/queryKeys.js.map +1 -0
  124. package/dist/model/readMarker.d.ts +25 -0
  125. package/dist/model/readMarker.d.ts.map +1 -0
  126. package/dist/model/readMarker.js +31 -0
  127. package/dist/model/readMarker.js.map +1 -0
  128. package/dist/model/runtime.d.ts +50 -0
  129. package/dist/model/runtime.d.ts.map +1 -0
  130. package/dist/model/runtime.js +27 -0
  131. package/dist/model/runtime.js.map +1 -0
  132. package/dist/model/threadWindow.d.ts +95 -0
  133. package/dist/model/threadWindow.d.ts.map +1 -0
  134. package/dist/model/threadWindow.js +100 -0
  135. package/dist/model/threadWindow.js.map +1 -0
  136. package/dist/nav/manifest.d.ts +23 -0
  137. package/dist/nav/manifest.d.ts.map +1 -0
  138. package/dist/nav/manifest.js +15 -0
  139. package/dist/nav/manifest.js.map +1 -0
  140. package/dist/realtime/chatSocket.d.ts +93 -0
  141. package/dist/realtime/chatSocket.d.ts.map +1 -0
  142. package/dist/realtime/chatSocket.js +199 -0
  143. package/dist/realtime/chatSocket.js.map +1 -0
  144. package/dist/realtime/frames.d.ts +123 -0
  145. package/dist/realtime/frames.d.ts.map +1 -0
  146. package/dist/realtime/frames.js +123 -0
  147. package/dist/realtime/frames.js.map +1 -0
  148. package/dist/realtime/streams.d.ts +49 -0
  149. package/dist/realtime/streams.d.ts.map +1 -0
  150. package/dist/realtime/streams.js +52 -0
  151. package/dist/realtime/streams.js.map +1 -0
  152. package/llms.txt +89 -0
  153. package/manifest.json +733 -0
  154. package/nav-manifest.json +25 -0
  155. package/package.json +114 -0
  156. package/src/analytics/generated/events.json +7 -0
  157. package/src/api/chatApi.ts +142 -0
  158. package/src/api/extensions.ts +18 -0
  159. package/src/api/generated/schema.ts +549 -0
  160. package/src/api/types.ts +87 -0
  161. package/src/default/ConversationListPanel.tsx +163 -0
  162. package/src/default/ConversationThreadPanel.tsx +245 -0
  163. package/src/default/ErrorAlert.tsx +43 -0
  164. package/src/default/StartChatButton.tsx +78 -0
  165. package/src/default/index.ts +20 -0
  166. package/src/flows/errors.ts +16 -0
  167. package/src/flows/freshness.ts +315 -0
  168. package/src/flows/registry.ts +36 -0
  169. package/src/headless/ChatProvider.tsx +23 -0
  170. package/src/headless/ConversationList.tsx +92 -0
  171. package/src/headless/ConversationThread.tsx +107 -0
  172. package/src/headless/MessageComposer.tsx +86 -0
  173. package/src/headless/StartDirectChat.tsx +75 -0
  174. package/src/i18n/errorsMap.ts +31 -0
  175. package/src/i18n/es.ts +95 -0
  176. package/src/i18n/generated/errors.es.gen.ts +64 -0
  177. package/src/i18n/generated/errors.gen.ts +214 -0
  178. package/src/i18n/generated/errors.json +408 -0
  179. package/src/i18n/generated/errors.ru.gen.ts +64 -0
  180. package/src/i18n/keys.ts +152 -0
  181. package/src/i18n/ru.ts +98 -0
  182. package/src/index.ts +189 -0
  183. package/src/model/context.tsx +25 -0
  184. package/src/model/limits.ts +11 -0
  185. package/src/model/mutations.ts +208 -0
  186. package/src/model/queries.ts +120 -0
  187. package/src/model/queryKeys.ts +32 -0
  188. package/src/model/readMarker.ts +32 -0
  189. package/src/model/runtime.ts +90 -0
  190. package/src/model/threadWindow.ts +173 -0
  191. package/src/nav/manifest.ts +36 -0
  192. package/src/realtime/chatSocket.ts +304 -0
  193. package/src/realtime/frames.ts +229 -0
  194. package/src/realtime/streams.ts +85 -0
  195. package/tsconfig.json +26 -0
@@ -0,0 +1,45 @@
1
+ import { useCallback, useState } from "react";
2
+ import { actionAvailable, actionBlocked, firstBlock } from "@stapel/core";
3
+ import { useSendMessage } from "../model/mutations.js";
4
+ import { CHAT_DEFAULT_MAX_BODY_LENGTH } from "../model/limits.js";
5
+ import { CHAT_I18N_KEYS } from "../i18n/keys.js";
6
+ /**
7
+ * Headless composer over `POST /chat/api/v1/conversations/{id}/messages`.
8
+ * REST, always — the socket's `send` frame refuses with codes that carry no
9
+ * i18n key (`realtime/frames.ts`).
10
+ */
11
+ export function MessageComposer(props) {
12
+ const [value, setValue] = useState("");
13
+ const send = useSendMessage(props.conversationId);
14
+ const maxLength = props.maxLength ?? CHAT_DEFAULT_MAX_BODY_LENGTH;
15
+ const length = [...value].length;
16
+ const trimmed = value.trim();
17
+ const availability = firstBlock(trimmed.length === 0
18
+ ? actionBlocked(CHAT_I18N_KEYS.composerBlockedEmpty)
19
+ : actionAvailable(), length > maxLength
20
+ ? actionBlocked(CHAT_I18N_KEYS.composerBlockedTooLong, { max: maxLength })
21
+ : actionAvailable());
22
+ const { mutate, isPending, error } = send;
23
+ const onSent = props.onSent;
24
+ const doSend = useCallback(() => {
25
+ if (!availability.available || isPending)
26
+ return;
27
+ mutate({ body: trimmed }, {
28
+ onSuccess: (message) => {
29
+ setValue("");
30
+ onSent?.(message.seq);
31
+ },
32
+ });
33
+ }, [availability.available, isPending, mutate, trimmed, onSent]);
34
+ return props.children({
35
+ value,
36
+ setValue,
37
+ availability,
38
+ isSending: isPending,
39
+ error,
40
+ send: doSend,
41
+ maxLength,
42
+ length,
43
+ });
44
+ }
45
+ //# sourceMappingURL=MessageComposer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageComposer.js","sourceRoot":"","sources":["../../src/headless/MessageComposer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AA2BjD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAM/B;IACC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,4BAA4B,CAAC;IAClE,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC;IACjC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAE7B,MAAM,YAAY,GAAuB,UAAU,CACjD,OAAO,CAAC,MAAM,KAAK,CAAC;QAClB,CAAC,CAAC,aAAa,CAAC,cAAc,CAAC,oBAAoB,CAAC;QACpD,CAAC,CAAC,eAAe,EAAE,EACrB,MAAM,GAAG,SAAS;QAChB,CAAC,CAAC,aAAa,CAAC,cAAc,CAAC,sBAAsB,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;QAC1E,CAAC,CAAC,eAAe,EAAE,CACtB,CAAC;IAEF,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5B,MAAM,MAAM,GAAG,WAAW,CAAC,GAAS,EAAE;QACpC,IAAI,CAAC,YAAY,CAAC,SAAS,IAAI,SAAS;YAAE,OAAO;QACjD,MAAM,CACJ,EAAE,IAAI,EAAE,OAAO,EAAE,EACjB;YACE,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;gBACrB,QAAQ,CAAC,EAAE,CAAC,CAAC;gBACb,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACxB,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAEjE,OAAO,KAAK,CAAC,QAAQ,CAAC;QACpB,KAAK;QACL,QAAQ;QACR,YAAY;QACZ,SAAS,EAAE,SAAS;QACpB,KAAK;QACL,IAAI,EAAE,MAAM;QACZ,SAAS;QACT,MAAM;KACP,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,40 @@
1
+ import type { ReactNode } from "react";
2
+ import type { ActionAvailability } from "@stapel/core";
3
+ import type { Conversation } from "../api/types.js";
4
+ /** Render-prop bag for {@link StartDirectChat}. */
5
+ export interface StartDirectChatBag {
6
+ /** Blocked reasons: no seller on the listing, or the viewer IS the seller. */
7
+ readonly availability: ActionAvailability;
8
+ readonly isStarting: boolean;
9
+ /** The thread, once opened. */
10
+ readonly conversation: Conversation | undefined;
11
+ readonly error: unknown;
12
+ start(): void;
13
+ }
14
+ /**
15
+ * "Message the seller" — the buyer's entry into chat, headless.
16
+ *
17
+ * One press, one durable outcome: the direct thread with that person, created
18
+ * if it does not exist and returned if it does. The idempotency is the
19
+ * module's own (`direct_key` over the participant pair, under a unique
20
+ * constraint), so a double click, two tabs, or a second listing by the same
21
+ * seller all land in the same conversation rather than fanning out into
22
+ * near-duplicate threads.
23
+ *
24
+ * WHAT THIS BUTTON CANNOT DO, AND WHY IT SAYS SO HERE. It cannot open a
25
+ * thread ABOUT a listing. The thread is keyed by the pair of people, and
26
+ * `CreateConversationRequest.scope_key` — which looks like the place to put a
27
+ * listing id — is ignored by the server (`api/extensions.ts`). A host that
28
+ * wants the listing named does it in the first message, via
29
+ * `<MessageComposer>`'s initial value.
30
+ */
31
+ export declare function StartDirectChat(props: {
32
+ /** The other person. `null`/`undefined` blocks the control with a reason. */
33
+ sellerId: string | null | undefined;
34
+ /** The viewer, when known — writing to yourself is blocked with a reason. */
35
+ viewerId?: string | null;
36
+ /** Navigate to the thread. Called once, with the opened conversation. */
37
+ onOpened?: (conversation: Conversation) => void;
38
+ children: (bag: StartDirectChatBag) => ReactNode;
39
+ }): ReactNode;
40
+ //# sourceMappingURL=StartDirectChat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StartDirectChat.d.ts","sourceRoot":"","sources":["../../src/headless/StartDirectChat.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAIpD,mDAAmD;AACnD,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,+BAA+B;IAC/B,QAAQ,CAAC,YAAY,EAAE,YAAY,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,IAAI,CAAC;IAChD,QAAQ,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,SAAS,CAAC;CAClD,GAAG,SAAS,CA8BZ"}
@@ -0,0 +1,46 @@
1
+ import { useCallback } from "react";
2
+ import { actionAvailable, actionBlocked, firstBlock } from "@stapel/core";
3
+ import { useStartDirectChat } from "../model/mutations.js";
4
+ import { CHAT_I18N_KEYS } from "../i18n/keys.js";
5
+ /**
6
+ * "Message the seller" — the buyer's entry into chat, headless.
7
+ *
8
+ * One press, one durable outcome: the direct thread with that person, created
9
+ * if it does not exist and returned if it does. The idempotency is the
10
+ * module's own (`direct_key` over the participant pair, under a unique
11
+ * constraint), so a double click, two tabs, or a second listing by the same
12
+ * seller all land in the same conversation rather than fanning out into
13
+ * near-duplicate threads.
14
+ *
15
+ * WHAT THIS BUTTON CANNOT DO, AND WHY IT SAYS SO HERE. It cannot open a
16
+ * thread ABOUT a listing. The thread is keyed by the pair of people, and
17
+ * `CreateConversationRequest.scope_key` — which looks like the place to put a
18
+ * listing id — is ignored by the server (`api/extensions.ts`). A host that
19
+ * wants the listing named does it in the first message, via
20
+ * `<MessageComposer>`'s initial value.
21
+ */
22
+ export function StartDirectChat(props) {
23
+ const start = useStartDirectChat();
24
+ const { sellerId, viewerId, onOpened } = props;
25
+ const availability = firstBlock(sellerId === null || sellerId === undefined || sellerId.length === 0
26
+ ? actionBlocked(CHAT_I18N_KEYS.startBlockedUnknownSeller)
27
+ : actionAvailable(), viewerId != null && viewerId === sellerId
28
+ ? actionBlocked(CHAT_I18N_KEYS.startBlockedSelf)
29
+ : actionAvailable());
30
+ const { mutate, isPending, data, error } = start;
31
+ const doStart = useCallback(() => {
32
+ if (!availability.available || isPending)
33
+ return;
34
+ if (sellerId === null || sellerId === undefined)
35
+ return;
36
+ mutate({ userId: sellerId }, { onSuccess: (conversation) => onOpened?.(conversation) });
37
+ }, [availability.available, isPending, mutate, sellerId, onOpened]);
38
+ return props.children({
39
+ availability,
40
+ isStarting: isPending,
41
+ conversation: data,
42
+ error,
43
+ start: doStart,
44
+ });
45
+ }
46
+ //# sourceMappingURL=StartDirectChat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StartDirectChat.js","sourceRoot":"","sources":["../../src/headless/StartDirectChat.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEpC,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAajD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe,CAAC,KAQ/B;IACC,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAC;IACnC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAE/C,MAAM,YAAY,GAAuB,UAAU,CACjD,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAClE,CAAC,CAAC,aAAa,CAAC,cAAc,CAAC,yBAAyB,CAAC;QACzD,CAAC,CAAC,eAAe,EAAE,EACrB,QAAQ,IAAI,IAAI,IAAI,QAAQ,KAAK,QAAQ;QACvC,CAAC,CAAC,aAAa,CAAC,cAAc,CAAC,gBAAgB,CAAC;QAChD,CAAC,CAAC,eAAe,EAAE,CACtB,CAAC;IAEF,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IACjD,MAAM,OAAO,GAAG,WAAW,CAAC,GAAS,EAAE;QACrC,IAAI,CAAC,YAAY,CAAC,SAAS,IAAI,SAAS;YAAE,OAAO;QACjD,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO;QACxD,MAAM,CACJ,EAAE,MAAM,EAAE,QAAQ,EAAE,EACpB,EAAE,SAAS,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE,CAC1D,CAAC;IACJ,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEpE,OAAO,KAAK,CAAC,QAAQ,CAAC;QACpB,YAAY;QACZ,UAAU,EAAE,SAAS;QACrB,YAAY,EAAE,IAAI;QAClB,KAAK;QACL,KAAK,EAAE,OAAO;KACf,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Remediation } from "./generated/errors.gen.js";
2
+ export { CHAT_ERRORS, CHAT_ERROR_CODES, chatErrorBundleEn, } from "./generated/errors.gen.js";
3
+ export type { ChatErrorCode, ChatErrorSpec, Remediation, } from "./generated/errors.gen.js";
4
+ /**
5
+ * Resolve a backend error code to its remediation hint, or `undefined` for a
6
+ * code this module doesn't know (e.g. a cross-cutting `stapel.http.*`
7
+ * fallback). Zero guessing at runtime — a static lookup over the generated map.
8
+ */
9
+ export declare function explainChatError(code: string): Remediation | undefined;
10
+ //# sourceMappingURL=errorsMap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorsMap.d.ts","sourceRoot":"","sources":["../../src/i18n/errorsMap.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,aAAa,EACb,aAAa,EACb,WAAW,GACZ,MAAM,2BAA2B,CAAC;AAEnC;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAGtE"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The pair's error map (frontend-standard §4 checklist #7, frontend-core §2.5):
3
+ * the generated `code → { status, params, remediation, en }` catalog plus a
4
+ * tiny `explain()` lookup. Backs the manifest `errors` block and gives hosts a
5
+ * mechanical UX branch beside `t(code, params)`. The map itself is generated
6
+ * from the backend registry (`pnpm gen:errors`); this file only adds the
7
+ * lookup helper and re-exports the public surface.
8
+ */
9
+ import { CHAT_ERRORS } from "./generated/errors.gen.js";
10
+ export { CHAT_ERRORS, CHAT_ERROR_CODES, chatErrorBundleEn, } from "./generated/errors.gen.js";
11
+ /**
12
+ * Resolve a backend error code to its remediation hint, or `undefined` for a
13
+ * code this module doesn't know (e.g. a cross-cutting `stapel.http.*`
14
+ * fallback). Zero guessing at runtime — a static lookup over the generated map.
15
+ */
16
+ export function explainChatError(code) {
17
+ return CHAT_ERRORS[code]
18
+ ?.remediation;
19
+ }
20
+ //# sourceMappingURL=errorsMap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorsMap.js","sourceRoot":"","sources":["../../src/i18n/errorsMap.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAGxD,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AAOnC;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAQ,WAA4D,CAAC,IAAI,CAAC;QACxE,EAAE,WAAW,CAAC;AAClB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { I18nDictionary, I18nEngine } from "@stapel/core";
2
+ export { chatErrorBundleEs } from "./generated/errors.es.gen.js";
3
+ /**
4
+ * Spanish bundle for chat-react — the pair's `es` locale, shipped as the
5
+ * `@stapel/chat-react/i18n/es` subpath (i18n-shipping.md §2) so the locale is
6
+ * opt-in.
7
+ *
8
+ * Same two sources as the `ru` bundle: the generated `chatErrorBundleEs`
9
+ * carries the keys stapel-core owns; the 12 keys stapel-chat owns are authored
10
+ * here because the module ships no `translations/` directory (see `ru.ts` for
11
+ * the full note). Unlike notifications-react's es bundle, this one DOES carry
12
+ * hand-written UI copy — a marketplace's buyer-to-seller chat is the surface
13
+ * where a half-translated screen is most obvious.
14
+ */
15
+ export declare const chatI18nBundleEs: I18nDictionary;
16
+ /**
17
+ * Register the pair's `es` locale into a core i18n engine (call once at
18
+ * startup, after {@link registerChatI18n}). The en floor is registered UNDER
19
+ * the es texts inside the `es` locale, so any key the es bundle does not carry
20
+ * degrades to its English text rather than to a raw key.
21
+ */
22
+ export declare function registerChatI18nEs(engine: I18nEngine): void;
23
+ //# sourceMappingURL=es.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"es.d.ts","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAI/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,EAAE,cAiE9B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAG3D"}
@@ -0,0 +1,75 @@
1
+ import { chatI18nBundleEn } from "./keys.js";
2
+ import { chatErrorBundleEs } from "./generated/errors.es.gen.js";
3
+ export { chatErrorBundleEs } from "./generated/errors.es.gen.js";
4
+ /**
5
+ * Spanish bundle for chat-react — the pair's `es` locale, shipped as the
6
+ * `@stapel/chat-react/i18n/es` subpath (i18n-shipping.md §2) so the locale is
7
+ * opt-in.
8
+ *
9
+ * Same two sources as the `ru` bundle: the generated `chatErrorBundleEs`
10
+ * carries the keys stapel-core owns; the 12 keys stapel-chat owns are authored
11
+ * here because the module ships no `translations/` directory (see `ru.ts` for
12
+ * the full note). Unlike notifications-react's es bundle, this one DOES carry
13
+ * hand-written UI copy — a marketplace's buyer-to-seller chat is the surface
14
+ * where a half-translated screen is most obvious.
15
+ */
16
+ export const chatI18nBundleEs = {
17
+ // Backend error codes — generated es texts for every key core owns.
18
+ ...chatErrorBundleEs,
19
+ // Backend error codes stapel-chat owns — authored here (see the note above).
20
+ "error.400.chat_attachments_disabled": "Los archivos adjuntos no están habilitados en esta instalación",
21
+ "error.400.chat_body_too_long": "El mensaje supera la longitud máxima permitida",
22
+ "error.400.chat_empty_message": "Un mensaje debe llevar texto o al menos un archivo adjunto",
23
+ "error.400.chat_invalid_direct": "Una conversación directa necesita exactamente un interlocutor",
24
+ "error.400.chat_invalid_kind": "Tipo de conversación desconocido",
25
+ "error.400.chat_invalid_reply": "El mensaje al que respondes no pertenece a esta conversación",
26
+ "error.400.chat_kind_disabled": "Este tipo de conversación no está habilitado en esta instalación",
27
+ "error.400.chat_not_support": "Esta acción solo se aplica a conversaciones de soporte",
28
+ "error.403.chat_not_operator": "Solo un operador de soporte puede realizar esta acción",
29
+ "error.403.chat_not_participant": "No participas en esta conversación",
30
+ "error.404.chat_conversation_not_found": "Conversación no encontrada",
31
+ "error.409.chat_already_assigned": "Esta conversación de soporte ya está asignada",
32
+ // chat-react UI (hand-written es mirror of the en copy in keys.ts)
33
+ "chat.error.unknown": "Algo ha salido mal. Inténtalo de nuevo.",
34
+ "chat.list.title": "Mensajes",
35
+ "chat.list.empty": "Todavía no hay conversaciones.",
36
+ "chat.list.loading": "Cargando conversaciones…",
37
+ "chat.list.load_more": "Cargar más",
38
+ "chat.list.end": "Esto es todo.",
39
+ "chat.list.retry": "Reintentar",
40
+ "chat.list.unread": "{count} sin leer",
41
+ "chat.list.open": "Abrir",
42
+ "chat.kind.direct": "Mensaje directo",
43
+ "chat.kind.group": "Grupo",
44
+ "chat.kind.support": "Soporte",
45
+ "chat.thread.loading": "Cargando mensajes…",
46
+ "chat.thread.empty": "Todavía no hay mensajes. Saluda.",
47
+ "chat.thread.retry": "Reintentar",
48
+ "chat.thread.load_older": "Ver mensajes anteriores",
49
+ "chat.thread.beginning": "Este es el principio de la conversación.",
50
+ "chat.thread.system": "Sistema",
51
+ "chat.composer.placeholder": "Escribe un mensaje…",
52
+ "chat.composer.send": "Enviar",
53
+ "chat.composer.sending": "Enviando…",
54
+ "chat.composer.blocked.empty": "Escribe algo primero.",
55
+ "chat.composer.blocked.too_long": "Eso supera los {max} caracteres — acórtalo un poco.",
56
+ "chat.start.button": "Escribir al vendedor",
57
+ "chat.start.starting": "Abriendo…",
58
+ "chat.start.blocked.self": "Este anuncio es tuyo.",
59
+ "chat.start.blocked.unknown_seller": "Este anuncio no tiene vendedor a quien escribir.",
60
+ "chat.transport.live": "En directo",
61
+ "chat.transport.polling": "Actualizando cada pocos segundos",
62
+ "chat.transport.idle": "En pausa",
63
+ "chat.nav.conversations": "Mensajes",
64
+ };
65
+ /**
66
+ * Register the pair's `es` locale into a core i18n engine (call once at
67
+ * startup, after {@link registerChatI18n}). The en floor is registered UNDER
68
+ * the es texts inside the `es` locale, so any key the es bundle does not carry
69
+ * degrades to its English text rather than to a raw key.
70
+ */
71
+ export function registerChatI18nEs(engine) {
72
+ engine.registerBundle("es", chatI18nBundleEn);
73
+ engine.registerBundle("es", chatI18nBundleEs);
74
+ }
75
+ //# sourceMappingURL=es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"es.js","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAmB;IAC9C,oEAAoE;IACpE,GAAG,iBAAiB;IAEpB,6EAA6E;IAC7E,qCAAqC,EACnC,gEAAgE;IAClE,8BAA8B,EAAE,gDAAgD;IAChF,8BAA8B,EAC5B,4DAA4D;IAC9D,+BAA+B,EAC7B,+DAA+D;IACjE,6BAA6B,EAAE,kCAAkC;IACjE,8BAA8B,EAC5B,8DAA8D;IAChE,8BAA8B,EAC5B,kEAAkE;IACpE,4BAA4B,EAC1B,wDAAwD;IAC1D,6BAA6B,EAC3B,wDAAwD;IAC1D,gCAAgC,EAAE,oCAAoC;IACtE,uCAAuC,EAAE,4BAA4B;IACrE,iCAAiC,EAAE,+CAA+C;IAElF,mEAAmE;IACnE,oBAAoB,EAAE,yCAAyC;IAE/D,iBAAiB,EAAE,UAAU;IAC7B,iBAAiB,EAAE,gCAAgC;IACnD,mBAAmB,EAAE,0BAA0B;IAC/C,qBAAqB,EAAE,YAAY;IACnC,eAAe,EAAE,eAAe;IAChC,iBAAiB,EAAE,YAAY;IAC/B,kBAAkB,EAAE,kBAAkB;IACtC,gBAAgB,EAAE,OAAO;IAEzB,kBAAkB,EAAE,iBAAiB;IACrC,iBAAiB,EAAE,OAAO;IAC1B,mBAAmB,EAAE,SAAS;IAE9B,qBAAqB,EAAE,oBAAoB;IAC3C,mBAAmB,EAAE,kCAAkC;IACvD,mBAAmB,EAAE,YAAY;IACjC,wBAAwB,EAAE,yBAAyB;IACnD,uBAAuB,EAAE,0CAA0C;IACnE,oBAAoB,EAAE,SAAS;IAE/B,2BAA2B,EAAE,qBAAqB;IAClD,oBAAoB,EAAE,QAAQ;IAC9B,uBAAuB,EAAE,WAAW;IACpC,6BAA6B,EAAE,uBAAuB;IACtD,gCAAgC,EAC9B,qDAAqD;IAEvD,mBAAmB,EAAE,sBAAsB;IAC3C,qBAAqB,EAAE,WAAW;IAClC,yBAAyB,EAAE,uBAAuB;IAClD,mCAAmC,EAAE,kDAAkD;IAEvF,qBAAqB,EAAE,YAAY;IACnC,wBAAwB,EAAE,kCAAkC;IAC5D,qBAAqB,EAAE,UAAU;IAEjC,wBAAwB,EAAE,UAAU;CACrC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAkB;IACnD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IAC9C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { ChatErrorCode } from "./errors.gen.js";
2
+ /**
3
+ * `es` texts for the backend error codes this catalog carries.
4
+ *
5
+ * PARTIAL, and deliberately typed to say so: 12 key(s) owned by
6
+ * stapel_chat are absent, because that owner ships no locale catalog
7
+ * (ERRORS_LOCALE_EXEMPT_OWNERS). English for them still comes from the registry
8
+ * artifact via the en bundle; the pair layers its own authored `es`
9
+ * strings over this one until upstream ships translations. `Partial` is what
10
+ * makes the gap visible to TypeScript instead of a silent English fallback.
11
+ *
12
+ * Import from the pair's `./i18n/es` subpath, NOT the main entry, so
13
+ * the locale stays out of hosts that don't ship it.
14
+ */
15
+ export declare const chatErrorBundleEs: Partial<Record<ChatErrorCode, string>>;
16
+ //# sourceMappingURL=errors.es.gen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.es.gen.d.ts","sourceRoot":"","sources":["../../../src/i18n/generated/errors.es.gen.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CA2CpE,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * `es` texts for the backend error codes this catalog carries.
3
+ *
4
+ * PARTIAL, and deliberately typed to say so: 12 key(s) owned by
5
+ * stapel_chat are absent, because that owner ships no locale catalog
6
+ * (ERRORS_LOCALE_EXEMPT_OWNERS). English for them still comes from the registry
7
+ * artifact via the en bundle; the pair layers its own authored `es`
8
+ * strings over this one until upstream ships translations. `Partial` is what
9
+ * makes the gap visible to TypeScript instead of a silent English fallback.
10
+ *
11
+ * Import from the pair's `./i18n/es` subpath, NOT the main entry, so
12
+ * the locale stays out of hosts that don't ship it.
13
+ */
14
+ export const chatErrorBundleEs = {
15
+ "error.400.bad_request": "Solicitud incorrecta",
16
+ "error.400.captcha_invalid": "La verificación del captcha ha fallado. Inténtalo de nuevo.",
17
+ "error.400.captcha_required": "Se requiere el token del captcha.",
18
+ "error.400.expected_list": "Se esperaba una lista de elementos",
19
+ "error.400.field.blank": "{field} no puede estar vacío",
20
+ "error.400.field.does_not_exist": "{field} no existe",
21
+ "error.400.field.invalid": "{field} no es válido",
22
+ "error.400.field.invalid_choice": "{field} no es una opción válida",
23
+ "error.400.field.max_length": "{field} debe tener como máximo {max_length} caracteres",
24
+ "error.400.field.max_value": "{field} debe ser como máximo {max_value}",
25
+ "error.400.field.min_length": "{field} debe tener al menos {min_length} caracteres",
26
+ "error.400.field.min_value": "{field} debe ser como mínimo {min_value}",
27
+ "error.400.field.null": "{field} no puede ser nulo",
28
+ "error.400.field.required": "{field} es obligatorio",
29
+ "error.400.field.unique": "{field} debe ser único",
30
+ "error.400.invalid_ad_id": "ID de anuncio no válido",
31
+ "error.400.validation_error": "Error de validación",
32
+ "error.400.verification_failed": "La verificación ha fallado",
33
+ "error.400.verification_invalid_factor": "Este factor de verificación no está disponible",
34
+ "error.401.unauthorized": "Se requiere autenticación",
35
+ "error.402.payment_required": "Se requiere pago",
36
+ "error.403.forbidden": "No tienes permiso para realizar esta acción",
37
+ "error.403.network_blocked": "No se permiten solicitudes desde esta red.",
38
+ "error.403.verification_enrollment_required": "Es necesario registrar un factor de verificación.",
39
+ "error.403.verification_required": "Se requiere verificación adicional",
40
+ "error.404.ad_not_found": "Anuncio no encontrado",
41
+ "error.404.not_found": "Recurso solicitado no encontrado",
42
+ "error.404.verification_challenge_not_found": "Desafío de verificación no encontrado o caducado",
43
+ "error.405.method_not_allowed": "Método no permitido",
44
+ "error.406.not_acceptable": "No aceptable",
45
+ "error.408.request_timeout": "Tiempo de espera de la solicitud agotado",
46
+ "error.409.conflict": "El recurso ya existe",
47
+ "error.410.gone": "El recurso se ha eliminado permanentemente",
48
+ "error.413.payload_too_large": "El cuerpo de la solicitud es demasiado grande",
49
+ "error.415.unsupported_media_type": "Tipo de contenido no compatible",
50
+ "error.422.unprocessable_entity": "Entidad no procesable",
51
+ "error.423.locked": "El recurso está bloqueado",
52
+ "error.423.verification_locked": "Demasiados intentos fallidos — verificación bloqueada",
53
+ "error.429.rate_limit": "Demasiados intentos. Inténtalo de nuevo en {retry_after_minutes} minutos.",
54
+ "error.429.too_many_requests": "Demasiadas solicitudes. Inténtalo de nuevo más tarde.",
55
+ "error.500.internal": "Algo salió mal",
56
+ "error.503.mandate_unavailable": "No se puede verificar el mandato del espacio de trabajo",
57
+ };
58
+ //# sourceMappingURL=errors.es.gen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.es.gen.js","sourceRoot":"","sources":["../../../src/i18n/generated/errors.es.gen.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA2C;IACvE,uBAAuB,EAAE,sBAAsB;IAC/C,2BAA2B,EAAE,6DAA6D;IAC1F,4BAA4B,EAAE,mCAAmC;IACjE,yBAAyB,EAAE,oCAAoC;IAC/D,uBAAuB,EAAE,8BAA8B;IACvD,gCAAgC,EAAE,mBAAmB;IACrD,yBAAyB,EAAE,sBAAsB;IACjD,gCAAgC,EAAE,iCAAiC;IACnE,4BAA4B,EAAE,wDAAwD;IACtF,2BAA2B,EAAE,0CAA0C;IACvE,4BAA4B,EAAE,qDAAqD;IACnF,2BAA2B,EAAE,0CAA0C;IACvE,sBAAsB,EAAE,2BAA2B;IACnD,0BAA0B,EAAE,wBAAwB;IACpD,wBAAwB,EAAE,wBAAwB;IAClD,yBAAyB,EAAE,yBAAyB;IACpD,4BAA4B,EAAE,qBAAqB;IACnD,+BAA+B,EAAE,4BAA4B;IAC7D,uCAAuC,EAAE,gDAAgD;IACzF,wBAAwB,EAAE,2BAA2B;IACrD,4BAA4B,EAAE,kBAAkB;IAChD,qBAAqB,EAAE,6CAA6C;IACpE,2BAA2B,EAAE,4CAA4C;IACzE,4CAA4C,EAAE,mDAAmD;IACjG,iCAAiC,EAAE,oCAAoC;IACvE,wBAAwB,EAAE,uBAAuB;IACjD,qBAAqB,EAAE,kCAAkC;IACzD,4CAA4C,EAAE,kDAAkD;IAChG,8BAA8B,EAAE,qBAAqB;IACrD,0BAA0B,EAAE,cAAc;IAC1C,2BAA2B,EAAE,0CAA0C;IACvE,oBAAoB,EAAE,sBAAsB;IAC5C,gBAAgB,EAAE,4CAA4C;IAC9D,6BAA6B,EAAE,+CAA+C;IAC9E,kCAAkC,EAAE,iCAAiC;IACrE,gCAAgC,EAAE,uBAAuB;IACzD,kBAAkB,EAAE,2BAA2B;IAC/C,+BAA+B,EAAE,uDAAuD;IACxF,sBAAsB,EAAE,2EAA2E;IACnG,6BAA6B,EAAE,uDAAuD;IACtF,oBAAoB,EAAE,gBAAgB;IACtC,+BAA+B,EAAE,yDAAyD;CAC3F,CAAC"}