@controleonline/ui-common 1.2.70

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 (203) hide show
  1. package/.github/agents/developer.agent.md +30 -0
  2. package/.github/agents/devops.agent.md +30 -0
  3. package/.github/agents/qa.agent.md +30 -0
  4. package/.github/agents/security.agent.md +30 -0
  5. package/.github/workflows/npmjs.yml +35 -0
  6. package/.github/workflows/pull-request-checks.yml +19 -0
  7. package/.scrutinizer.yml +24 -0
  8. package/FUNDING.yml +1 -0
  9. package/package.json +28 -0
  10. package/src/api/fetch.js +74 -0
  11. package/src/api/index.js +155 -0
  12. package/src/api/localDB.js +131 -0
  13. package/src/api/queue.js +66 -0
  14. package/src/react/assets/tap.mp3 +0 -0
  15. package/src/react/components/AddImportModal.js +157 -0
  16. package/src/react/components/AddImportModal.styles.js +81 -0
  17. package/src/react/components/BackgroundRuntimeBridge.js +219 -0
  18. package/src/react/components/BottomNavigationBar.config.js +238 -0
  19. package/src/react/components/BottomNavigationBar.js +120 -0
  20. package/src/react/components/BottomNavigationBar.styles.js +110 -0
  21. package/src/react/components/CategoryForm.js +572 -0
  22. package/src/react/components/CategoryForm.styles.js +334 -0
  23. package/src/react/components/ConfirmModal.js +24 -0
  24. package/src/react/components/ConfirmModal.styles.js +43 -0
  25. package/src/react/components/ContextHelpButton.js +69 -0
  26. package/src/react/components/ContextHelpButton.styles.js +62 -0
  27. package/src/react/components/DefaultProvider.native.js +848 -0
  28. package/src/react/components/DefaultProvider.styles.js +21 -0
  29. package/src/react/components/DefaultProvider.web.js +909 -0
  30. package/src/react/components/DeliveryPushBridge.native.js +314 -0
  31. package/src/react/components/DeliveryPushBridge.web.js +5 -0
  32. package/src/react/components/DeviceAlertSoundService.js +499 -0
  33. package/src/react/components/EntityLogContent.js +909 -0
  34. package/src/react/components/EntityLogContent.styles.js +400 -0
  35. package/src/react/components/EventBus.js +12 -0
  36. package/src/react/components/KioskModeBridge.js +65 -0
  37. package/src/react/components/LauncherModeBridge.js +47 -0
  38. package/src/react/components/LinkedOrderProductsTab.js +388 -0
  39. package/src/react/components/LinkedOrderProductsTab.styles.js +180 -0
  40. package/src/react/components/ManagerPushBridge.native.js +345 -0
  41. package/src/react/components/MessageService.js +314 -0
  42. package/src/react/components/Paywall/Google.js +89 -0
  43. package/src/react/components/PrintService.js +778 -0
  44. package/src/react/components/ProductCatalogCacheService.js +45 -0
  45. package/src/react/components/RemoteCheckoutService.js +292 -0
  46. package/src/react/components/RuntimeBottomNavigationBar.js +151 -0
  47. package/src/react/components/RuntimeInfoFooter.js +214 -0
  48. package/src/react/components/RuntimeInfoFooter.styles.js +56 -0
  49. package/src/react/components/SystemErrorToast.js +29 -0
  50. package/src/react/components/SystemErrorToast.styles.js +38 -0
  51. package/src/react/components/TouchFeedbackProvider.js +65 -0
  52. package/src/react/components/UnifiedPaymentBar.js +155 -0
  53. package/src/react/components/UnifiedPaymentBar.styles.js +174 -0
  54. package/src/react/components/WebsocketListener.native.js +487 -0
  55. package/src/react/components/WebsocketListener.web.js +102 -0
  56. package/src/react/components/inputs/IdInput.js +49 -0
  57. package/src/react/components/inputs/IdInput.styles.js +26 -0
  58. package/src/react/components/inputs/InvoiceDueDateFilterInput.js +74 -0
  59. package/src/react/components/inputs/InvoiceDueDateFilterInput.styles.js +34 -0
  60. package/src/react/components/inputs/InvoiceDueDateRangeFilterInput.js +115 -0
  61. package/src/react/components/inputs/InvoiceDueDateRangeFilterInput.styles.js +39 -0
  62. package/src/react/components/lists/CategoriesList.js +56 -0
  63. package/src/react/components/lists/PaymentTypeList.js +55 -0
  64. package/src/react/components/lists/ReceiverList.js +56 -0
  65. package/src/react/components/lists/SelectList.styles.js +18 -0
  66. package/src/react/components/lists/StatusList.js +55 -0
  67. package/src/react/components/lists/WalletList.js +54 -0
  68. package/src/react/components/radio/Spotify.js +144 -0
  69. package/src/react/components/radio/Spotify.styles.js +32 -0
  70. package/src/react/components/radio/YouTube.js +82 -0
  71. package/src/react/components/radio/YouTube.styles.js +16 -0
  72. package/src/react/components/toastConfig.js +16 -0
  73. package/src/react/config/deviceConfigBootstrap.js +571 -0
  74. package/src/react/index.js +4 -0
  75. package/src/react/localStorage.js +30 -0
  76. package/src/react/pages/EntityLogPage.js +124 -0
  77. package/src/react/pages/EntityLogPage.styles.js +17 -0
  78. package/src/react/pages/GenericLogPage.js +760 -0
  79. package/src/react/pages/GenericLogPage.styles.js +401 -0
  80. package/src/react/pages/Imports.js +361 -0
  81. package/src/react/pages/Imports.styles.js +223 -0
  82. package/src/react/pages/SettingsPage/PaymentTypesByWalletTab.js +462 -0
  83. package/src/react/pages/SettingsPage/index.js +1171 -0
  84. package/src/react/pages/SettingsPage/index.styles.js +122 -0
  85. package/src/react/print/jobs.js +147 -0
  86. package/src/react/print/providers/local.js +53 -0
  87. package/src/react/print/providers/remote.js +81 -0
  88. package/src/react/print/selection.js +296 -0
  89. package/src/react/print/usePrintButtonController.js +474 -0
  90. package/src/react/router/routes.js +42 -0
  91. package/src/react/services/NetworkPrinterService.native.js +391 -0
  92. package/src/react/services/NetworkPrinterService.web.js +15 -0
  93. package/src/react/stores/index.js +128 -0
  94. package/src/react/stores/storeErrorBridge.js +36 -0
  95. package/src/react/utils/backgroundRuntimeRegistration.js +69 -0
  96. package/src/react/utils/cashPayment.js +87 -0
  97. package/src/react/utils/commercialDocumentOrders.js +269 -0
  98. package/src/react/utils/dateRangeFilter.js +264 -0
  99. package/src/react/utils/deviceRuntime.js +193 -0
  100. package/src/react/utils/entityDisplay.js +231 -0
  101. package/src/react/utils/entityLog.js +649 -0
  102. package/src/react/utils/fileUrl.js +102 -0
  103. package/src/react/utils/frontendDebugLog.js +45 -0
  104. package/src/react/utils/googleMapsConfig.js +49 -0
  105. package/src/react/utils/importStatus.js +100 -0
  106. package/src/react/utils/invoiceDueDateMessages.js +14 -0
  107. package/src/react/utils/invoicePresentation.js +46 -0
  108. package/src/react/utils/logSettings.js +143 -0
  109. package/src/react/utils/maintenanceSettings.js +53 -0
  110. package/src/react/utils/managerOrderNotifications.js +523 -0
  111. package/src/react/utils/mapNavigation.js +76 -0
  112. package/src/react/utils/menuCatalogConfig.js +8 -0
  113. package/src/react/utils/menuCatalogDownload.js +157 -0
  114. package/src/react/utils/networkCameraDevices.js +175 -0
  115. package/src/react/utils/networkDeviceProfiles.js +135 -0
  116. package/src/react/utils/normalizedCatalogDownload.js +157 -0
  117. package/src/react/utils/notificationNavigation.js +94 -0
  118. package/src/react/utils/notificationSound.js +42 -0
  119. package/src/react/utils/paymentDevices.js +397 -0
  120. package/src/react/utils/paymentGatewayExecution.js +91 -0
  121. package/src/react/utils/paymentOptions.js +88 -0
  122. package/src/react/utils/peopleDisplay.js +39 -0
  123. package/src/react/utils/printerDevices.js +465 -0
  124. package/src/react/utils/remotePayment.js +61 -0
  125. package/src/react/utils/runtimeFooter.js +475 -0
  126. package/src/react/utils/runtimeLanguage.js +50 -0
  127. package/src/react/utils/runtimeMenu.js +224 -0
  128. package/src/react/utils/screenMetrics.js +30 -0
  129. package/src/react/utils/shopConfig.js +294 -0
  130. package/src/react/utils/shopFranchises.js +114 -0
  131. package/src/react/utils/socketRuntimePipeline.js +454 -0
  132. package/src/react/utils/spoolAckTracker.js +77 -0
  133. package/src/react/utils/storeColumns.js +427 -0
  134. package/src/react/utils/systemErrorChannel.js +109 -0
  135. package/src/react/utils/systemErrorMessage.js +67 -0
  136. package/src/react/utils/toastPresentation.js +53 -0
  137. package/src/react/utils/websocketSharedRuntime.js +826 -0
  138. package/src/store/acl/getters.js +4 -0
  139. package/src/store/acl/index.js +19 -0
  140. package/src/store/acl/mutation_types.js +4 -0
  141. package/src/store/acl/mutations.js +17 -0
  142. package/src/store/address/city.js +22 -0
  143. package/src/store/categories/category_file/index.js +25 -0
  144. package/src/store/categories/index.js +93 -0
  145. package/src/store/configs/customActions.js +131 -0
  146. package/src/store/configs/index.js +25 -0
  147. package/src/store/connections/customActions.js +26 -0
  148. package/src/store/connections/index.js +124 -0
  149. package/src/store/device/index.js +22 -0
  150. package/src/store/device_config/customActions.js +190 -0
  151. package/src/store/device_config/index.js +28 -0
  152. package/src/store/entity_log/customActions.js +63 -0
  153. package/src/store/entity_log/index.js +25 -0
  154. package/src/store/extra/data.js +85 -0
  155. package/src/store/extra/fields.js +88 -0
  156. package/src/store/file/actions.js +27 -0
  157. package/src/store/file/index.js +24 -0
  158. package/src/store/imports/index.js +88 -0
  159. package/src/store/print/customActions.js +251 -0
  160. package/src/store/print/index.js +28 -0
  161. package/src/store/printer/customActions.js +54 -0
  162. package/src/store/printer/index.js +26 -0
  163. package/src/store/runtime_debug/customActions.js +71 -0
  164. package/src/store/runtime_debug/index.js +30 -0
  165. package/src/store/status/index.js +65 -0
  166. package/src/store/timezones/index.js +43 -0
  167. package/src/store/websocket/customActions.js +24 -0
  168. package/src/store/websocket/index.js +28 -0
  169. package/src/tests/react/components/LauncherModeBridge.test.js +93 -0
  170. package/src/tests/react/config/deviceConfigBootstrap.test.js +337 -0
  171. package/src/tests/react/print/localPrintProvider.test.js +45 -0
  172. package/src/tests/react/utils/backgroundRuntimeRegistration.test.js +123 -0
  173. package/src/tests/react/utils/cashPayment.test.js +41 -0
  174. package/src/tests/react/utils/dateRangeFilter.test.mjs +29 -0
  175. package/src/tests/react/utils/entityDisplay.test.js +18 -0
  176. package/src/tests/react/utils/googleMapsConfig.test.js +32 -0
  177. package/src/tests/react/utils/importStatus.test.js +85 -0
  178. package/src/tests/react/utils/invoicePresentation.test.mjs +40 -0
  179. package/src/tests/react/utils/managerOrderNotifications.test.js +127 -0
  180. package/src/tests/react/utils/mapNavigation.test.js +58 -0
  181. package/src/tests/react/utils/notificationNavigation.test.js +39 -0
  182. package/src/tests/react/utils/notificationSound.test.js +27 -0
  183. package/src/tests/react/utils/paymentDevices.test.js +88 -0
  184. package/src/tests/react/utils/runtimeFooter.test.js +429 -0
  185. package/src/tests/react/utils/runtimeLanguage.test.js +80 -0
  186. package/src/tests/react/utils/runtimeMenu.test.js +174 -0
  187. package/src/tests/react/utils/shopFranchises.test.js +82 -0
  188. package/src/tests/react/utils/socketRuntimePipeline.test.js +124 -0
  189. package/src/tests/react/utils/spoolAckTracker.test.js +40 -0
  190. package/src/tests/react/utils/storeErrorBridge.test.js +66 -0
  191. package/src/tests/react/utils/systemErrorChannel.test.js +58 -0
  192. package/src/tests/react/utils/systemErrorMessage.test.js +59 -0
  193. package/src/tests/react/utils/toastPresentation.test.js +75 -0
  194. package/src/tests/react/utils/translate.test.mjs +396 -0
  195. package/src/tests/react/utils/websocketSharedRuntime.test.js +245 -0
  196. package/src/utils/apiEntryPoint.js +31 -0
  197. package/src/utils/appDomain.js +50 -0
  198. package/src/utils/config.js +14 -0
  199. package/src/utils/formatter.js +419 -0
  200. package/src/utils/integrationConfigs.js +79 -0
  201. package/src/utils/methods.js +23 -0
  202. package/src/utils/oauth.js +42 -0
  203. package/src/utils/translate.js +620 -0
@@ -0,0 +1,454 @@
1
+ /*
2
+ * Regra transversal dos displays de pedidos
3
+ * - `orders`, `tv` e `products` precisam refletir novos pedidos em tempo real.
4
+ * - O websocket compartilhado e a fonte canonica: ele distribui as mensagens
5
+ * para os stores e alimenta o fluxo de alerta operacional.
6
+ * - Nao criar websocket paralelo, refresh manual ou audio fora desse contrato.
7
+ */
8
+
9
+ const normalizeText = value => String(value ?? '').trim();
10
+
11
+ const formatClock = value => {
12
+ const normalized = normalizeText(value);
13
+ if (!normalized) {
14
+ return '--';
15
+ }
16
+
17
+ try {
18
+ const date = new Date(normalized);
19
+ if (Number.isNaN(date.getTime())) {
20
+ return '--';
21
+ }
22
+
23
+ const pad = entry => String(entry).padStart(2, '0');
24
+ return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(
25
+ date.getSeconds(),
26
+ )}`;
27
+ } catch {
28
+ return '--';
29
+ }
30
+ };
31
+
32
+ const truncateText = (value, max = 44) => {
33
+ const normalized = normalizeText(value);
34
+ if (!normalized || normalized.length <= max) {
35
+ return normalized || '--';
36
+ }
37
+
38
+ return `${normalized.slice(0, max - 3)}...`;
39
+ };
40
+
41
+ const isFilledObject = value =>
42
+ !!value &&
43
+ typeof value === 'object' &&
44
+ !Array.isArray(value) &&
45
+ Object.keys(value).length > 0;
46
+
47
+ const parsePayload = rawPayload => {
48
+ if (typeof rawPayload !== 'string') {
49
+ return rawPayload;
50
+ }
51
+
52
+ const normalized = rawPayload.trim();
53
+ if (!normalized) {
54
+ return null;
55
+ }
56
+
57
+ try {
58
+ return JSON.parse(normalized);
59
+ } catch {
60
+ return null;
61
+ }
62
+ };
63
+
64
+ const createSocketRuntimePipeline = ({
65
+ getDeviceId = () => '',
66
+ getCurrentCompanyId = () => '',
67
+ websocketActions = {},
68
+ runtimeDebugActions = {},
69
+ getStoreByName = () => null,
70
+ source = 'background-runtime',
71
+ } = {}) => {
72
+ let pendingMessages = {};
73
+ let flushMessagesPromise = null;
74
+ let currentState = {
75
+ connected: false,
76
+ identified: false,
77
+ status: 'idle',
78
+ attempts: 0,
79
+ updatedAt: new Date().toISOString(),
80
+ device: normalizeText(getDeviceId()) || null,
81
+ error: null,
82
+ code: null,
83
+ reason: '',
84
+ ownerRegistrationId: '',
85
+ ownerPackageName: '',
86
+ ownerCompanyId: normalizeText(getCurrentCompanyId()),
87
+ lastEventAt: null,
88
+ lastEventCount: 0,
89
+ lastStores: [],
90
+ lastCompanies: [],
91
+ };
92
+
93
+ const publishSocketFooterEntry = (state = currentState) => {
94
+ if (typeof runtimeDebugActions?.setFooterEntry !== 'function') {
95
+ return;
96
+ }
97
+
98
+ const socketConnected = Boolean(state?.connected);
99
+ const socketIdentified = Boolean(state?.identified);
100
+ const normalizedStatus = normalizeText(state?.status).toLowerCase();
101
+ const stateLabel = socketConnected
102
+ ? socketIdentified
103
+ ? 'socket:on'
104
+ : 'socket:open'
105
+ : `socket:${normalizedStatus || 'off'}`;
106
+
107
+ const indicatorColor =
108
+ socketConnected && socketIdentified
109
+ ? '#10b981'
110
+ : (socketConnected ||
111
+ ['connecting', 'identifying', 'open', 'reconnecting'].includes(
112
+ normalizedStatus,
113
+ ))
114
+ ? '#e67e22'
115
+ : '#c10015';
116
+
117
+ const lastSocketStores = Array.isArray(state?.lastStores)
118
+ ? state.lastStores.filter(Boolean).join(', ')
119
+ : '';
120
+ const lastSocketCompanies = Array.isArray(state?.lastCompanies)
121
+ ? state.lastCompanies.filter(Boolean).join(', ')
122
+ : '';
123
+
124
+ runtimeDebugActions.setFooterEntry({
125
+ key: 'socket',
126
+ order: 10,
127
+ indicatorColor,
128
+ updatedAt: state?.updatedAt || new Date().toISOString(),
129
+ lines: [
130
+ `Realtime ${stateLabel} | empresa: ${normalizeText(
131
+ getCurrentCompanyId(),
132
+ ) || '--'} | device: ${truncateText(
133
+ state?.device || getDeviceId() || '--',
134
+ 34,
135
+ )}`,
136
+ `ultimo socket: ${formatClock(state?.lastEventAt)} | eventos: ${Number(
137
+ state?.lastEventCount || 0,
138
+ )} | stores: ${truncateText(
139
+ lastSocketStores || '--',
140
+ 28,
141
+ )} | empresas: ${truncateText(lastSocketCompanies || '--', 18)}`,
142
+ ],
143
+ });
144
+ };
145
+
146
+ const updateConnectionState = (state = {}) => {
147
+ const nextState = {
148
+ ...currentState,
149
+ connected: false,
150
+ identified: false,
151
+ status: 'idle',
152
+ attempts: 0,
153
+ updatedAt: new Date().toISOString(),
154
+ device: normalizeText(getDeviceId()) || currentState.device || null,
155
+ error: null,
156
+ code: null,
157
+ reason: '',
158
+ ownerRegistrationId: '',
159
+ ownerPackageName: '',
160
+ ownerCompanyId: normalizeText(getCurrentCompanyId()) || '',
161
+ lastEventAt: null,
162
+ lastEventCount: 0,
163
+ lastStores: [],
164
+ lastCompanies: [],
165
+ ...state,
166
+ };
167
+
168
+ nextState.device =
169
+ normalizeText(nextState.device) || normalizeText(getDeviceId()) || null;
170
+ nextState.ownerRegistrationId = normalizeText(
171
+ nextState.ownerRegistrationId,
172
+ );
173
+ nextState.ownerPackageName = normalizeText(nextState.ownerPackageName);
174
+ nextState.ownerCompanyId =
175
+ normalizeText(nextState.ownerCompanyId) ||
176
+ normalizeText(getCurrentCompanyId()) ||
177
+ '';
178
+ nextState.error = normalizeText(nextState.error) || null;
179
+ nextState.reason = normalizeText(nextState.reason);
180
+ nextState.status = normalizeText(nextState.status) || 'idle';
181
+ nextState.attempts = Number(nextState.attempts || 0);
182
+ nextState.lastEventCount = Number(nextState.lastEventCount || 0);
183
+ nextState.lastStores = Array.isArray(nextState.lastStores)
184
+ ? nextState.lastStores.filter(Boolean)
185
+ : [];
186
+ nextState.lastCompanies = Array.isArray(nextState.lastCompanies)
187
+ ? nextState.lastCompanies.filter(Boolean)
188
+ : [];
189
+
190
+ currentState = nextState;
191
+
192
+ if (typeof websocketActions?.setSummary === 'function') {
193
+ websocketActions.setSummary(nextState);
194
+ }
195
+
196
+ publishSocketFooterEntry(nextState);
197
+ return nextState;
198
+ };
199
+
200
+ const flushPendingMessages = () => {
201
+ flushMessagesPromise = null;
202
+ const pending = pendingMessages;
203
+ pendingMessages = {};
204
+ const deliveredStores = new Set();
205
+ const deliveredCompanies = new Set();
206
+ let deliveredMessages = 0;
207
+
208
+ Object.entries(pending).forEach(([storeName, messages]) => {
209
+ if (!Array.isArray(messages) || messages.length === 0) {
210
+ return;
211
+ }
212
+
213
+ const storeModule = getStoreByName(storeName);
214
+ const messageActions = storeModule?.actions || {};
215
+ if (typeof messageActions?.setMessages !== 'function') {
216
+ return;
217
+ }
218
+
219
+ const messageGetters = storeModule?.getters || {};
220
+ const currentMessages = Array.isArray(messageGetters?.messages)
221
+ ? messageGetters.messages
222
+ : [];
223
+
224
+ messageActions.setMessages([...currentMessages, ...messages]);
225
+ deliveredMessages += messages.length;
226
+ deliveredStores.add(storeName);
227
+
228
+ messages.forEach(message => {
229
+ const companyId = normalizeText(
230
+ message?.company?.id || message?.companyId || message?.company || '',
231
+ );
232
+ if (companyId) {
233
+ deliveredCompanies.add(companyId);
234
+ }
235
+ });
236
+ });
237
+
238
+ return {
239
+ deliveredMessages,
240
+ deliveredStores: Array.from(deliveredStores),
241
+ deliveredCompanies: Array.from(deliveredCompanies),
242
+ };
243
+ };
244
+
245
+ const scheduleFlush = () => {
246
+ if (!flushMessagesPromise) {
247
+ flushMessagesPromise = Promise.resolve().then(() => flushPendingMessages());
248
+ }
249
+ };
250
+
251
+ const appendMessageToStore = event => {
252
+ if (!event?.store) {
253
+ return false;
254
+ }
255
+
256
+ const storeModule = getStoreByName(event.store);
257
+ if (
258
+ !storeModule?.actions ||
259
+ typeof storeModule.actions.setMessages !== 'function'
260
+ ) {
261
+ return false;
262
+ }
263
+
264
+ if (!Array.isArray(pendingMessages[event.store])) {
265
+ pendingMessages[event.store] = [];
266
+ }
267
+
268
+ pendingMessages[event.store].push({
269
+ ...event,
270
+ source: event?.source || source,
271
+ });
272
+
273
+ scheduleFlush();
274
+ return true;
275
+ };
276
+
277
+ const processPayload = rawPayload => {
278
+ const payload = parsePayload(rawPayload);
279
+ if (!payload) {
280
+ return currentState;
281
+ }
282
+
283
+ if (payload.type === 'socket-state') {
284
+ return updateConnectionState({
285
+ connected: Boolean(payload.connected),
286
+ identified: Boolean(payload.identified),
287
+ status: normalizeText(payload.status) || 'connected',
288
+ attempts: Number(payload.attempts || 0),
289
+ updatedAt: payload.updatedAt || new Date().toISOString(),
290
+ device: normalizeText(payload.device) || normalizeText(getDeviceId()),
291
+ error: normalizeText(payload.error) || null,
292
+ code: payload.code ?? null,
293
+ reason: normalizeText(payload.reason),
294
+ ownerRegistrationId:
295
+ normalizeText(payload.ownerRegistrationId) ||
296
+ currentState.ownerRegistrationId ||
297
+ '',
298
+ ownerPackageName:
299
+ normalizeText(payload.ownerPackageName) ||
300
+ currentState.ownerPackageName ||
301
+ '',
302
+ ownerCompanyId:
303
+ normalizeText(payload.ownerCompanyId) ||
304
+ currentState.ownerCompanyId ||
305
+ normalizeText(getCurrentCompanyId()) ||
306
+ '',
307
+ lastEventAt: payload.lastEventAt || null,
308
+ lastEventCount: Number(payload.lastEventCount || 0),
309
+ lastStores: Array.isArray(payload.lastStores)
310
+ ? payload.lastStores.filter(Boolean)
311
+ : [],
312
+ lastCompanies: Array.isArray(payload.lastCompanies)
313
+ ? payload.lastCompanies.filter(Boolean)
314
+ : [],
315
+ });
316
+ }
317
+
318
+ const normalizedStatus = normalizeText(payload.status).toLowerCase();
319
+ if (normalizedStatus === 'identified') {
320
+ return updateConnectionState({
321
+ connected: true,
322
+ identified: true,
323
+ status: 'connected',
324
+ attempts: 0,
325
+ updatedAt: new Date().toISOString(),
326
+ device: normalizeText(payload.device) || normalizeText(getDeviceId()),
327
+ error: null,
328
+ code: null,
329
+ reason: '',
330
+ ownerRegistrationId: currentState.ownerRegistrationId || '',
331
+ ownerPackageName: currentState.ownerPackageName || '',
332
+ ownerCompanyId:
333
+ currentState.ownerCompanyId || normalizeText(getCurrentCompanyId()),
334
+ lastEventAt: currentState.lastEventAt,
335
+ lastEventCount: currentState.lastEventCount,
336
+ lastStores: currentState.lastStores,
337
+ lastCompanies: currentState.lastCompanies,
338
+ });
339
+ }
340
+
341
+ if (normalizedStatus === 'error') {
342
+ const message = normalizeText(payload.message) || 'Background runtime identify failed';
343
+ return updateConnectionState({
344
+ connected: false,
345
+ identified: false,
346
+ status: 'error',
347
+ attempts: Number(payload.attempts || 0),
348
+ updatedAt: new Date().toISOString(),
349
+ device: normalizeText(payload.device) || normalizeText(getDeviceId()),
350
+ error: message,
351
+ code: payload.code ?? null,
352
+ reason: message,
353
+ ownerRegistrationId: currentState.ownerRegistrationId || '',
354
+ ownerPackageName: currentState.ownerPackageName || '',
355
+ ownerCompanyId:
356
+ currentState.ownerCompanyId || normalizeText(getCurrentCompanyId()),
357
+ lastEventAt: currentState.lastEventAt,
358
+ lastEventCount: currentState.lastEventCount,
359
+ lastStores: currentState.lastStores,
360
+ lastCompanies: currentState.lastCompanies,
361
+ });
362
+ }
363
+
364
+ const events = Array.isArray(payload) ? payload : [payload];
365
+ const deliveredStores = new Set();
366
+ const deliveredCompanies = new Set();
367
+ let deliveredMessages = 0;
368
+
369
+ events.filter(isFilledObject).forEach(event => {
370
+ const store = normalizeText(event?.store).toLowerCase();
371
+ if (store) {
372
+ deliveredStores.add(store);
373
+ }
374
+
375
+ const companyId = normalizeText(
376
+ event?.company?.id || event?.companyId || event?.company || '',
377
+ );
378
+ if (companyId) {
379
+ deliveredCompanies.add(companyId);
380
+ }
381
+
382
+ if (appendMessageToStore(event)) {
383
+ deliveredMessages += 1;
384
+ }
385
+ });
386
+
387
+ if (deliveredMessages > 0) {
388
+ return updateConnectionState({
389
+ connected: true,
390
+ identified: true,
391
+ status: 'connected',
392
+ attempts: 0,
393
+ updatedAt: new Date().toISOString(),
394
+ device: normalizeText(getDeviceId()) || currentState.device || null,
395
+ error: null,
396
+ code: null,
397
+ reason: '',
398
+ ownerRegistrationId: currentState.ownerRegistrationId || '',
399
+ ownerPackageName: currentState.ownerPackageName || '',
400
+ ownerCompanyId:
401
+ currentState.ownerCompanyId || normalizeText(getCurrentCompanyId()),
402
+ lastEventAt: new Date().toISOString(),
403
+ lastEventCount: deliveredMessages,
404
+ lastStores: Array.from(deliveredStores),
405
+ lastCompanies: Array.from(deliveredCompanies),
406
+ });
407
+ }
408
+
409
+ return currentState;
410
+ };
411
+
412
+ const refreshFooter = () => {
413
+ publishSocketFooterEntry(currentState);
414
+ return currentState;
415
+ };
416
+
417
+ const reset = () => {
418
+ pendingMessages = {};
419
+ flushMessagesPromise = null;
420
+ return updateConnectionState({
421
+ connected: false,
422
+ identified: false,
423
+ status: normalizeText(getDeviceId()) ? 'closed' : 'idle',
424
+ attempts: 0,
425
+ updatedAt: new Date().toISOString(),
426
+ device: normalizeText(getDeviceId()) || null,
427
+ error: null,
428
+ code: null,
429
+ reason: '',
430
+ ownerRegistrationId: '',
431
+ ownerPackageName: '',
432
+ ownerCompanyId: normalizeText(getCurrentCompanyId()) || '',
433
+ lastEventAt: null,
434
+ lastEventCount: 0,
435
+ lastStores: [],
436
+ lastCompanies: [],
437
+ });
438
+ };
439
+
440
+ return {
441
+ appendMessageToStore,
442
+ formatClock,
443
+ getConnectionState: () => currentState,
444
+ normalizeText,
445
+ processPayload,
446
+ publishSocketFooterEntry,
447
+ refreshFooter,
448
+ reset,
449
+ truncateText,
450
+ updateConnectionState,
451
+ };
452
+ };
453
+
454
+ export {createSocketRuntimePipeline, formatClock, normalizeText, truncateText};
@@ -0,0 +1,77 @@
1
+ const normalizeTrackedSpoolId = value => {
2
+ if (value === null || value === undefined) {
3
+ return ''
4
+ }
5
+
6
+ if (typeof value === 'number') {
7
+ return Number.isFinite(value) ? String(value) : ''
8
+ }
9
+
10
+ const normalizedValue = String(value).replace(/\D+/g, '').trim()
11
+ return normalizedValue
12
+ }
13
+
14
+ export const getTrackedSpoolKey = value => normalizeTrackedSpoolId(value)
15
+
16
+ export const hasTrackedSpool = (registry, spoolId) => {
17
+ const spoolKey = getTrackedSpoolKey(spoolId)
18
+ return Boolean(spoolKey && registry instanceof Map && registry.has(spoolKey))
19
+ }
20
+
21
+ export const rememberTrackedSpool = (
22
+ registry,
23
+ spoolId,
24
+ metadata = {},
25
+ ) => {
26
+ if (!(registry instanceof Map)) {
27
+ return registry
28
+ }
29
+
30
+ const spoolKey = getTrackedSpoolKey(spoolId)
31
+ if (!spoolKey) {
32
+ return registry
33
+ }
34
+
35
+ registry.set(spoolKey, {
36
+ printedAt:
37
+ typeof metadata?.printedAt === 'number' && Number.isFinite(metadata.printedAt)
38
+ ? metadata.printedAt
39
+ : Date.now(),
40
+ })
41
+
42
+ return registry
43
+ }
44
+
45
+ export const forgetTrackedSpool = (registry, spoolId) => {
46
+ if (!(registry instanceof Map)) {
47
+ return registry
48
+ }
49
+
50
+ const spoolKey = getTrackedSpoolKey(spoolId)
51
+ if (!spoolKey) {
52
+ return registry
53
+ }
54
+
55
+ registry.delete(spoolKey)
56
+ return registry
57
+ }
58
+
59
+ export const pruneTrackedSpools = (registry, openSpoolIds = []) => {
60
+ if (!(registry instanceof Map)) {
61
+ return registry
62
+ }
63
+
64
+ const openSpoolKeys = new Set(
65
+ (Array.isArray(openSpoolIds) ? openSpoolIds : [])
66
+ .map(getTrackedSpoolKey)
67
+ .filter(Boolean),
68
+ )
69
+
70
+ Array.from(registry.keys()).forEach(spoolKey => {
71
+ if (!openSpoolKeys.has(spoolKey)) {
72
+ registry.delete(spoolKey)
73
+ }
74
+ })
75
+
76
+ return registry
77
+ }