quidproquo-web-react 0.0.262 → 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 (129) hide show
  1. package/lib/commonjs/actionProcessor/ActionProcessorContext.d.ts +2 -0
  2. package/lib/commonjs/actionProcessor/ActionProcessorContext.js +14 -0
  3. package/lib/commonjs/actionProcessor/ActionProcessorProvider.d.ts +6 -0
  4. package/lib/commonjs/actionProcessor/ActionProcessorProvider.js +24 -0
  5. package/lib/commonjs/actionProcessor/index.d.ts +3 -0
  6. package/lib/commonjs/actionProcessor/index.js +19 -0
  7. package/lib/commonjs/actionProcessor/useActionProcessors.d.ts +1 -0
  8. package/lib/commonjs/actionProcessor/useActionProcessors.js +7 -0
  9. package/lib/commonjs/api/hooks/index.d.ts +1 -0
  10. package/lib/commonjs/api/hooks/index.js +1 -0
  11. package/lib/commonjs/api/hooks/useApiRequestActionProcessor.d.ts +5 -0
  12. package/lib/commonjs/api/hooks/useApiRequestActionProcessor.js +22 -0
  13. package/lib/commonjs/api/hooks/useAuthenticatedNetworkRequest.js +2 -2
  14. package/lib/commonjs/api/hooks/useNetworkRequest.js +2 -2
  15. package/lib/commonjs/auth/hooks/useRefreshTokens.js +11 -3
  16. package/lib/commonjs/dateTime/DateTime.d.ts +28 -0
  17. package/lib/commonjs/dateTime/DateTime.js +57 -0
  18. package/lib/commonjs/dateTime/hooks/index.d.ts +1 -0
  19. package/lib/commonjs/dateTime/hooks/index.js +17 -0
  20. package/lib/commonjs/dateTime/hooks/useTimeAgo.d.ts +6 -0
  21. package/lib/commonjs/dateTime/hooks/useTimeAgo.js +26 -0
  22. package/lib/commonjs/dateTime/index.d.ts +2 -0
  23. package/lib/commonjs/dateTime/index.js +18 -0
  24. package/lib/commonjs/dateTime/logic/formatTimeAgo.d.ts +11 -0
  25. package/lib/commonjs/dateTime/logic/formatTimeAgo.js +49 -0
  26. package/lib/commonjs/dateTime/logic/index.d.ts +1 -0
  27. package/lib/commonjs/dateTime/logic/index.js +17 -0
  28. package/lib/commonjs/hooks/asmj/QpqContextProvider.d.ts +2 -1
  29. package/lib/commonjs/hooks/asmj/QpqContextProvider.js +6 -1
  30. package/lib/commonjs/hooks/asmj/QpqRuntimeEffectCatcher.d.ts +2 -2
  31. package/lib/commonjs/hooks/asmj/index.d.ts +1 -0
  32. package/lib/commonjs/hooks/asmj/index.js +1 -0
  33. package/lib/commonjs/hooks/asmj/useBubbleReducer.d.ts +2 -0
  34. package/lib/commonjs/hooks/asmj/useBubbleReducer.js +22 -0
  35. package/lib/commonjs/hooks/asmj/useQpqRuntime.d.ts +4 -2
  36. package/lib/commonjs/hooks/asmj/useQpqRuntime.js +14 -2
  37. package/lib/commonjs/hooks/index.d.ts +1 -0
  38. package/lib/commonjs/hooks/index.js +1 -0
  39. package/lib/commonjs/hooks/useComputed.d.ts +1 -0
  40. package/lib/commonjs/hooks/useComputed.js +7 -0
  41. package/lib/commonjs/hooks/useQpq.js +3 -1
  42. package/lib/commonjs/index.d.ts +2 -0
  43. package/lib/commonjs/index.js +2 -0
  44. package/lib/commonjs/webSocketQueue/hooks/actionProcessor/getServiceRequestActionProcessor.d.ts +4 -0
  45. package/lib/commonjs/webSocketQueue/hooks/actionProcessor/getServiceRequestActionProcessor.js +25 -0
  46. package/lib/commonjs/webSocketQueue/hooks/index.d.ts +2 -0
  47. package/lib/commonjs/webSocketQueue/hooks/index.js +2 -0
  48. package/lib/commonjs/webSocketQueue/hooks/useQpqWebsocketQueueRuntime.d.ts +11 -0
  49. package/lib/commonjs/webSocketQueue/hooks/useQpqWebsocketQueueRuntime.js +35 -0
  50. package/lib/commonjs/webSocketQueue/hooks/useWebsocketQueueSendEvent.d.ts +1 -1
  51. package/lib/commonjs/webSocketQueue/hooks/useWebsocketQueueSendEvent.js +53 -3
  52. package/lib/commonjs/websocket/WebSocketAuthSync/WebSocketAuthContext.d.ts +1 -0
  53. package/lib/commonjs/websocket/WebSocketAuthSync/WebSocketAuthContext.js +5 -0
  54. package/lib/commonjs/websocket/WebSocketAuthSync/WebSocketAuthSync.js +3 -3
  55. package/lib/commonjs/websocket/WebSocketAuthSync/hooks/index.d.ts +1 -0
  56. package/lib/commonjs/websocket/WebSocketAuthSync/hooks/index.js +1 -0
  57. package/lib/commonjs/websocket/WebSocketAuthSync/hooks/useWebSocketIsAuthenticated.d.ts +1 -0
  58. package/lib/commonjs/websocket/WebSocketAuthSync/hooks/useWebSocketIsAuthenticated.js +9 -0
  59. package/lib/commonjs/websocket/WebSocketAuthSync/hooks/useWebsocketAuthSync.d.ts +1 -1
  60. package/lib/commonjs/websocket/WebSocketAuthSync/hooks/useWebsocketAuthSync.js +11 -8
  61. package/lib/commonjs/websocket/WebSocketAuthSync/index.d.ts +1 -0
  62. package/lib/commonjs/websocket/WebSocketAuthSync/index.js +1 -0
  63. package/lib/commonjs/websocket/hooks/useSubscribeToWebSocketEvent.js +4 -2
  64. package/lib/commonjs/websocket/hooks/useSubscribeToWebsocket.js +4 -2
  65. package/lib/esm/actionProcessor/ActionProcessorContext.d.ts +2 -0
  66. package/lib/esm/actionProcessor/ActionProcessorContext.js +2 -0
  67. package/lib/esm/actionProcessor/ActionProcessorProvider.d.ts +6 -0
  68. package/lib/esm/actionProcessor/ActionProcessorProvider.js +12 -0
  69. package/lib/esm/actionProcessor/index.d.ts +3 -0
  70. package/lib/esm/actionProcessor/index.js +3 -0
  71. package/lib/esm/actionProcessor/useActionProcessors.d.ts +1 -0
  72. package/lib/esm/actionProcessor/useActionProcessors.js +3 -0
  73. package/lib/esm/api/hooks/index.d.ts +1 -0
  74. package/lib/esm/api/hooks/index.js +1 -0
  75. package/lib/esm/api/hooks/useApiRequestActionProcessor.d.ts +5 -0
  76. package/lib/esm/api/hooks/useApiRequestActionProcessor.js +15 -0
  77. package/lib/esm/api/hooks/useAuthenticatedNetworkRequest.js +1 -1
  78. package/lib/esm/api/hooks/useNetworkRequest.js +1 -1
  79. package/lib/esm/auth/hooks/useRefreshTokens.js +11 -3
  80. package/lib/esm/dateTime/DateTime.d.ts +28 -0
  81. package/lib/esm/dateTime/DateTime.js +54 -0
  82. package/lib/esm/dateTime/hooks/index.d.ts +1 -0
  83. package/lib/esm/dateTime/hooks/index.js +1 -0
  84. package/lib/esm/dateTime/hooks/useTimeAgo.d.ts +6 -0
  85. package/lib/esm/dateTime/hooks/useTimeAgo.js +22 -0
  86. package/lib/esm/dateTime/index.d.ts +2 -0
  87. package/lib/esm/dateTime/index.js +2 -0
  88. package/lib/esm/dateTime/logic/formatTimeAgo.d.ts +11 -0
  89. package/lib/esm/dateTime/logic/formatTimeAgo.js +44 -0
  90. package/lib/esm/dateTime/logic/index.d.ts +1 -0
  91. package/lib/esm/dateTime/logic/index.js +1 -0
  92. package/lib/esm/hooks/asmj/QpqContextProvider.d.ts +2 -1
  93. package/lib/esm/hooks/asmj/QpqContextProvider.js +4 -0
  94. package/lib/esm/hooks/asmj/QpqRuntimeEffectCatcher.d.ts +2 -2
  95. package/lib/esm/hooks/asmj/index.d.ts +1 -0
  96. package/lib/esm/hooks/asmj/index.js +1 -0
  97. package/lib/esm/hooks/asmj/useBubbleReducer.d.ts +2 -0
  98. package/lib/esm/hooks/asmj/useBubbleReducer.js +18 -0
  99. package/lib/esm/hooks/asmj/useQpqRuntime.d.ts +4 -2
  100. package/lib/esm/hooks/asmj/useQpqRuntime.js +6 -2
  101. package/lib/esm/hooks/index.d.ts +1 -0
  102. package/lib/esm/hooks/index.js +1 -0
  103. package/lib/esm/hooks/useComputed.d.ts +1 -0
  104. package/lib/esm/hooks/useComputed.js +4 -0
  105. package/lib/esm/hooks/useQpq.js +3 -0
  106. package/lib/esm/index.d.ts +2 -0
  107. package/lib/esm/index.js +2 -0
  108. package/lib/esm/webSocketQueue/hooks/actionProcessor/getServiceRequestActionProcessor.d.ts +4 -0
  109. package/lib/esm/webSocketQueue/hooks/actionProcessor/getServiceRequestActionProcessor.js +11 -0
  110. package/lib/esm/webSocketQueue/hooks/index.d.ts +2 -0
  111. package/lib/esm/webSocketQueue/hooks/index.js +2 -0
  112. package/lib/esm/webSocketQueue/hooks/useQpqWebsocketQueueRuntime.d.ts +11 -0
  113. package/lib/esm/webSocketQueue/hooks/useQpqWebsocketQueueRuntime.js +24 -0
  114. package/lib/esm/webSocketQueue/hooks/useWebsocketQueueSendEvent.d.ts +1 -1
  115. package/lib/esm/webSocketQueue/hooks/useWebsocketQueueSendEvent.js +54 -4
  116. package/lib/esm/websocket/WebSocketAuthSync/WebSocketAuthContext.d.ts +1 -0
  117. package/lib/esm/websocket/WebSocketAuthSync/WebSocketAuthContext.js +2 -0
  118. package/lib/esm/websocket/WebSocketAuthSync/WebSocketAuthSync.js +4 -4
  119. package/lib/esm/websocket/WebSocketAuthSync/hooks/index.d.ts +1 -0
  120. package/lib/esm/websocket/WebSocketAuthSync/hooks/index.js +1 -0
  121. package/lib/esm/websocket/WebSocketAuthSync/hooks/useWebSocketIsAuthenticated.d.ts +1 -0
  122. package/lib/esm/websocket/WebSocketAuthSync/hooks/useWebSocketIsAuthenticated.js +5 -0
  123. package/lib/esm/websocket/WebSocketAuthSync/hooks/useWebsocketAuthSync.d.ts +1 -1
  124. package/lib/esm/websocket/WebSocketAuthSync/hooks/useWebsocketAuthSync.js +14 -11
  125. package/lib/esm/websocket/WebSocketAuthSync/index.d.ts +1 -0
  126. package/lib/esm/websocket/WebSocketAuthSync/index.js +1 -0
  127. package/lib/esm/websocket/hooks/useSubscribeToWebSocketEvent.js +4 -2
  128. package/lib/esm/websocket/hooks/useSubscribeToWebsocket.js +4 -2
  129. package/package.json +11 -9
@@ -13,6 +13,7 @@ exports.useQpq = useQpq;
13
13
  const quidproquo_actionprocessor_web_1 = require("quidproquo-actionprocessor-web");
14
14
  const quidproquo_core_1 = require("quidproquo-core");
15
15
  const react_1 = require("react");
16
+ const actionProcessor_1 = require("../actionProcessor");
16
17
  const QpqContextProvider_1 = require("./asmj/QpqContextProvider");
17
18
  function* withVersionCheck(story, versionRef, capturedVersion) {
18
19
  let nextValue = undefined;
@@ -37,6 +38,7 @@ const logger = {
37
38
  };
38
39
  function useQpq(getActionProcessors = () => __awaiter(this, void 0, void 0, function* () { return ({}); })) {
39
40
  const qpqContextValues = (0, QpqContextProvider_1.useQpqContextValues)();
41
+ const contextGetActionProcessors = (0, actionProcessor_1.useActionProcessors)();
40
42
  const versionRef = (0, react_1.useRef)(0);
41
43
  (0, react_1.useEffect)(() => {
42
44
  return () => {
@@ -47,7 +49,7 @@ function useQpq(getActionProcessors = () => __awaiter(this, void 0, void 0, func
47
49
  depth: 0,
48
50
  context: qpqContextValues,
49
51
  }, (qpqConfig, dynamicModuleLoader) => __awaiter(this, void 0, void 0, function* () {
50
- return (Object.assign(Object.assign({}, (yield (0, quidproquo_actionprocessor_web_1.getWebActionProcessors)(qpqConfig, dynamicModuleLoader))), (yield getActionProcessors(qpqConfig, dynamicModuleLoader))));
52
+ return (Object.assign(Object.assign(Object.assign({}, (yield (0, quidproquo_actionprocessor_web_1.getWebActionProcessors)(qpqConfig, dynamicModuleLoader))), (yield contextGetActionProcessors(qpqConfig, dynamicModuleLoader))), (yield getActionProcessors(qpqConfig, dynamicModuleLoader))));
51
53
  }), () => new Date().toISOString(), logger, `frontend::${'uuid'}`, quidproquo_core_1.QpqRuntimeType.UI, (_runtime) => __awaiter(this, void 0, void 0, function* () {
52
54
  // noop
53
55
  })), [qpqContextValues]);
@@ -1,7 +1,9 @@
1
1
  import 'symbol-observable';
2
+ export * from './actionProcessor';
2
3
  export * from './api';
3
4
  export * from './auth';
4
5
  export * from './baseUrl';
6
+ export * from './dateTime';
5
7
  export * from './hooks';
6
8
  export * from './state';
7
9
  export * from './useFieldBinding';
@@ -15,9 +15,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  require("symbol-observable");
18
+ __exportStar(require("./actionProcessor"), exports);
18
19
  __exportStar(require("./api"), exports);
19
20
  __exportStar(require("./auth"), exports);
20
21
  __exportStar(require("./baseUrl"), exports);
22
+ __exportStar(require("./dateTime"), exports);
21
23
  __exportStar(require("./hooks"), exports);
22
24
  __exportStar(require("./state"), exports);
23
25
  __exportStar(require("./useFieldBinding"), exports);
@@ -0,0 +1,4 @@
1
+ import { ActionProcessorList } from 'quidproquo-core';
2
+ import { AnyWebSocketQueueEventMessageWithCorrelation } from 'quidproquo-webserver';
3
+ import { RefObject } from 'react';
4
+ export declare const getServiceRequestActionProcessor: (sendEventRef: RefObject<((event: Omit<AnyWebSocketQueueEventMessageWithCorrelation, "correlationId">) => Promise<any>) | null>) => ActionProcessorList;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getServiceRequestActionProcessor = void 0;
13
+ const quidproquo_core_1 = require("quidproquo-core");
14
+ const quidproquo_webserver_1 = require("quidproquo-webserver");
15
+ const getServiceRequestActionProcessor = (sendEventRef) => ({
16
+ [quidproquo_webserver_1.ServiceActionType.Request]: (_a) => __awaiter(void 0, [_a], void 0, function* ({ serviceName, method, payload, }) {
17
+ var _b;
18
+ const response = yield ((_b = sendEventRef.current) === null || _b === void 0 ? void 0 : _b.call(sendEventRef, { type: `qpq/serviceRequest/${serviceName}/${method}`, payload }));
19
+ if (response && !response.success) {
20
+ return (0, quidproquo_core_1.actionResultError)(response.error.errorType, response.error.errorText, response.error.errorStack);
21
+ }
22
+ return (0, quidproquo_core_1.actionResult)(response === null || response === void 0 ? void 0 : response.result);
23
+ }),
24
+ });
25
+ exports.getServiceRequestActionProcessor = getServiceRequestActionProcessor;
@@ -1,2 +1,4 @@
1
+ export * from './actionProcessor/getServiceRequestActionProcessor';
2
+ export * from './useQpqWebsocketQueueRuntime';
1
3
  export * from './useSubscribeToWebSocketQueueEvent';
2
4
  export * from './useWebsocketQueueSendEvent';
@@ -14,5 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./actionProcessor/getServiceRequestActionProcessor"), exports);
18
+ __exportStar(require("./useQpqWebsocketQueueRuntime"), exports);
17
19
  __exportStar(require("./useSubscribeToWebSocketQueueEvent"), exports);
18
20
  __exportStar(require("./useWebsocketQueueSendEvent"), exports);
@@ -0,0 +1,11 @@
1
+ import { Story } from 'quidproquo-core';
2
+ import { AnyWebSocketQueueEventMessageWithCorrelation } from 'quidproquo-webserver';
3
+ import { QpqRuntimeDefinition } from '../../hooks/asmj/createQpqRuntimeDefinition';
4
+ import { QpqApi, QpqMappedApi } from '../../hooks/asmj/QpqMappedApi';
5
+ import { ActionProcessorListResolverFactory } from '../../hooks/asmj/useQpqRuntime';
6
+ export declare function useQpqWebsocketQueueRuntime<TState, TAction, TApi extends QpqApi>(atom: QpqRuntimeDefinition<TState, TAction, TApi>, mainStory?: Story<any, any>, name?: string, getActionProcessors?: ActionProcessorListResolverFactory<TState>): [
7
+ QpqMappedApi<TApi>,
8
+ TState,
9
+ (action: any) => void,
10
+ (event: Omit<AnyWebSocketQueueEventMessageWithCorrelation, 'correlationId'>) => Promise<any>
11
+ ];
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.useQpqWebsocketQueueRuntime = useQpqWebsocketQueueRuntime;
13
+ const quidproquo_webserver_1 = require("quidproquo-webserver");
14
+ const react_1 = require("react");
15
+ const useQpqRuntime_1 = require("../../hooks/asmj/useQpqRuntime");
16
+ const getServiceRequestActionProcessor_1 = require("./actionProcessor/getServiceRequestActionProcessor");
17
+ const useWebsocketQueueSendEvent_1 = require("./useWebsocketQueueSendEvent");
18
+ function useQpqWebsocketQueueRuntime(atom, mainStory, name, getActionProcessors) {
19
+ const sendEventRef = (0, react_1.useRef)(null);
20
+ const mergedFactory = (dispatch, getCurrentState) => {
21
+ const serviceResolver = () => __awaiter(this, void 0, void 0, function* () { return (0, getServiceRequestActionProcessor_1.getServiceRequestActionProcessor)(sendEventRef); });
22
+ const callerResolver = getActionProcessors === null || getActionProcessors === void 0 ? void 0 : getActionProcessors(dispatch, getCurrentState);
23
+ return (qpqConfig, dynamicModuleLoader) => __awaiter(this, void 0, void 0, function* () {
24
+ return (Object.assign(Object.assign({}, (yield serviceResolver())), (callerResolver ? yield callerResolver(qpqConfig, dynamicModuleLoader) : {})));
25
+ });
26
+ };
27
+ const [api, state, dispatch] = (0, useQpqRuntime_1.useQpqRuntime)(atom, mainStory, name, mergedFactory);
28
+ const sendEvent = (0, useWebsocketQueueSendEvent_1.useWebsocketQueueSendEvent)((event) => {
29
+ if (event.type === quidproquo_webserver_1.WebSocketQueueServerMessageEventType.StateDispatch) {
30
+ dispatch(event.payload);
31
+ }
32
+ });
33
+ sendEventRef.current = sendEvent;
34
+ return [api, state, dispatch, sendEvent];
35
+ }
@@ -1,2 +1,2 @@
1
1
  import { AnyWebSocketQueueEventMessageWithCorrelation } from 'quidproquo-webserver';
2
- export declare const useWebsocketQueueSendEvent: <E extends AnyWebSocketQueueEventMessageWithCorrelation>() => (event: E) => void;
2
+ export declare const useWebsocketQueueSendEvent: <TSend extends AnyWebSocketQueueEventMessageWithCorrelation>(onCorrelatedMessage?: (event: AnyWebSocketQueueEventMessageWithCorrelation) => void) => (event: Omit<TSend, "correlationId">) => Promise<any>;
@@ -1,9 +1,59 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useWebsocketQueueSendEvent = void 0;
4
+ const quidproquo_web_1 = require("quidproquo-web");
5
+ const quidproquo_webserver_1 = require("quidproquo-webserver");
6
+ const react_1 = require("react");
7
+ const hooks_1 = require("../../hooks");
4
8
  const websocket_1 = require("../../websocket");
5
- const useWebsocketQueueSendEvent = () => {
6
- const sendMessage = (0, websocket_1.useWebsocketSendEvent)();
7
- return sendMessage;
9
+ const useWebsocketQueueSendEvent = (onCorrelatedMessage) => {
10
+ const websocketApi = (0, websocket_1.useWebsocketApi)();
11
+ const activeCorrelationsRef = (0, react_1.useRef)(new Set());
12
+ const pendingResolversRef = (0, react_1.useRef)(new Map());
13
+ // Subscribe to ALL messages, filter by active correlationIds
14
+ const handleMessage = (0, hooks_1.useFastCallback)((_ws, rawEvent) => {
15
+ if (!rawEvent)
16
+ return;
17
+ try {
18
+ const parsed = JSON.parse(rawEvent.data);
19
+ if (!parsed.correlationId || !activeCorrelationsRef.current.has(parsed.correlationId)) {
20
+ return;
21
+ }
22
+ if (parsed.type === quidproquo_webserver_1.WebSocketQueueServerMessageEventType.ServiceRequestResponse) {
23
+ const resolve = pendingResolversRef.current.get(parsed.correlationId);
24
+ if (resolve) {
25
+ resolve(parsed.payload);
26
+ pendingResolversRef.current.delete(parsed.correlationId);
27
+ activeCorrelationsRef.current.delete(parsed.correlationId);
28
+ }
29
+ }
30
+ else {
31
+ onCorrelatedMessage === null || onCorrelatedMessage === void 0 ? void 0 : onCorrelatedMessage(parsed);
32
+ }
33
+ }
34
+ catch (_a) {
35
+ // Not JSON or not a queue message — ignore
36
+ }
37
+ });
38
+ (0, websocket_1.useSubscribeToWebsocket)(quidproquo_web_1.WebsocketServiceEvent.MESSAGE, handleMessage);
39
+ // Send with auto-generated correlationId, register it as active
40
+ const sendEvent = (0, hooks_1.useFastCallback)((event) => {
41
+ if (!websocketApi) {
42
+ return Promise.resolve(undefined);
43
+ }
44
+ const correlationId = crypto.randomUUID();
45
+ activeCorrelationsRef.current.add(correlationId);
46
+ const isServiceRequest = event.type.startsWith('qpq/serviceRequest/');
47
+ if (isServiceRequest) {
48
+ const promise = new Promise((resolve) => {
49
+ pendingResolversRef.current.set(correlationId, resolve);
50
+ });
51
+ websocketApi.sendEvent(Object.assign(Object.assign({}, event), { correlationId }));
52
+ return promise;
53
+ }
54
+ websocketApi.sendEvent(Object.assign(Object.assign({}, event), { correlationId }));
55
+ return Promise.resolve(undefined);
56
+ });
57
+ return sendEvent;
8
58
  };
9
59
  exports.useWebsocketQueueSendEvent = useWebsocketQueueSendEvent;
@@ -0,0 +1 @@
1
+ export declare const WebSocketAuthContext: import("react").Context<boolean>;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebSocketAuthContext = void 0;
4
+ const react_1 = require("react");
5
+ exports.WebSocketAuthContext = (0, react_1.createContext)(false);
@@ -4,11 +4,11 @@ exports.WebSocketAuthSync = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const hooks_1 = require("./hooks");
7
+ const WebSocketAuthContext_1 = require("./WebSocketAuthContext");
7
8
  const component = ({ children, accessToken }) => {
8
- (0, hooks_1.useWebsocketAuthSync)(accessToken);
9
+ const isAuthenticated = (0, hooks_1.useWebsocketAuthSync)(accessToken);
9
10
  // Keep the active websocket alive
10
11
  (0, hooks_1.useWebsocketPingPong)();
11
- // This fragment is not useless!
12
- return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children });
12
+ return ((0, jsx_runtime_1.jsx)(WebSocketAuthContext_1.WebSocketAuthContext.Provider, { value: isAuthenticated, children: children }));
13
13
  };
14
14
  exports.WebSocketAuthSync = (0, react_1.memo)(component);
@@ -1,2 +1,3 @@
1
1
  export * from './useWebsocketAuthSync';
2
+ export * from './useWebSocketIsAuthenticated';
2
3
  export * from './useWebsocketPingPong';
@@ -15,4 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./useWebsocketAuthSync"), exports);
18
+ __exportStar(require("./useWebSocketIsAuthenticated"), exports);
18
19
  __exportStar(require("./useWebsocketPingPong"), exports);
@@ -0,0 +1 @@
1
+ export declare const useWebSocketIsAuthenticated: () => boolean;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useWebSocketIsAuthenticated = void 0;
4
+ const react_1 = require("react");
5
+ const WebSocketAuthContext_1 = require("../WebSocketAuthContext");
6
+ const useWebSocketIsAuthenticated = () => {
7
+ return (0, react_1.useContext)(WebSocketAuthContext_1.WebSocketAuthContext);
8
+ };
9
+ exports.useWebSocketIsAuthenticated = useWebSocketIsAuthenticated;
@@ -1,2 +1,2 @@
1
1
  import { AuthenticationInfo } from 'quidproquo-core';
2
- export declare const useWebsocketAuthSync: (accessToken: AuthenticationInfo["accessToken"]) => void;
2
+ export declare const useWebsocketAuthSync: (accessToken: AuthenticationInfo["accessToken"]) => boolean;
@@ -9,29 +9,32 @@ const hooks_2 = require("../../hooks");
9
9
  const useWebsocketAuthSync = (accessToken) => {
10
10
  const sendMessage = (0, hooks_2.useWebsocketSendEvent)();
11
11
  const websocketApi = (0, hooks_2.useWebsocketApi)();
12
+ const [isAuthenticated, setIsAuthenticated] = (0, react_1.useState)(false);
12
13
  const updateAuthTokens = (0, hooks_1.useFastCallback)(() => {
13
14
  if (!(websocketApi === null || websocketApi === void 0 ? void 0 : websocketApi.isConnected())) {
14
15
  return;
15
16
  }
16
17
  if (accessToken) {
17
- const authMessage = {
18
+ sendMessage({
18
19
  type: quidproquo_webserver_1.WebSocketQueueClientMessageEventType.Authenticate,
19
20
  payload: {
20
21
  accessToken: accessToken,
21
22
  },
22
- };
23
- sendMessage(authMessage);
23
+ });
24
24
  }
25
- else {
26
- const authMessage = {
25
+ else if (isAuthenticated) {
26
+ sendMessage({
27
27
  type: quidproquo_webserver_1.WebSocketQueueClientMessageEventType.Unauthenticate,
28
- };
29
- sendMessage(authMessage);
28
+ });
30
29
  }
31
30
  });
31
+ (0, hooks_2.useSubscribeToWebSocketEvent)(quidproquo_webserver_1.WebSocketQueueServerMessageEventType.Authenticated, () => setIsAuthenticated(true));
32
+ (0, hooks_2.useSubscribeToWebSocketEvent)(quidproquo_webserver_1.WebSocketQueueServerMessageEventType.Unauthenticated, () => setIsAuthenticated(false));
32
33
  // Sync the tokens in on open
33
34
  (0, hooks_2.useSubscribeToWebsocket)(quidproquo_web_1.WebsocketServiceEvent.OPEN, updateAuthTokens);
35
+ (0, hooks_2.useSubscribeToWebsocket)(quidproquo_web_1.WebsocketServiceEvent.CLOSE, () => setIsAuthenticated(false));
34
36
  // Sync the tokens when they change
35
- (0, react_1.useEffect)(updateAuthTokens, [accessToken, websocketApi]);
37
+ (0, react_1.useEffect)(updateAuthTokens, [accessToken, websocketApi, isAuthenticated]);
38
+ return isAuthenticated;
36
39
  };
37
40
  exports.useWebsocketAuthSync = useWebsocketAuthSync;
@@ -1 +1,2 @@
1
+ export * from './hooks/useWebSocketIsAuthenticated';
1
2
  export * from './WebSocketAuthSync';
@@ -14,4 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./hooks/useWebSocketIsAuthenticated"), exports);
17
18
  __exportStar(require("./WebSocketAuthSync"), exports);
@@ -2,16 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useSubscribeToWebSocketEvent = void 0;
4
4
  const react_1 = require("react");
5
+ const hooks_1 = require("../../hooks");
5
6
  const useWebsocketApi_1 = require("./useWebsocketApi");
6
7
  const useSubscribeToWebSocketEvent = (subscriptionType, callback) => {
8
+ const stableCallback = (0, hooks_1.useFastCallback)(callback);
7
9
  const websocketService = (0, useWebsocketApi_1.useWebsocketApi)();
8
10
  (0, react_1.useEffect)(() => {
9
- const subscriptionHandle = websocketService === null || websocketService === void 0 ? void 0 : websocketService.subscribeToEvent(subscriptionType, callback);
11
+ const subscriptionHandle = websocketService === null || websocketService === void 0 ? void 0 : websocketService.subscribeToEvent(subscriptionType, stableCallback);
10
12
  return () => {
11
13
  if (subscriptionHandle) {
12
14
  websocketService === null || websocketService === void 0 ? void 0 : websocketService.unsubscribe(subscriptionHandle);
13
15
  }
14
16
  };
15
- }, [websocketService, subscriptionType, callback]);
17
+ }, [websocketService, subscriptionType, stableCallback]);
16
18
  };
17
19
  exports.useSubscribeToWebSocketEvent = useSubscribeToWebSocketEvent;
@@ -2,16 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useSubscribeToWebsocket = void 0;
4
4
  const react_1 = require("react");
5
+ const hooks_1 = require("../../hooks");
5
6
  const useWebsocketApi_1 = require("./useWebsocketApi");
6
7
  const useSubscribeToWebsocket = (subscriptionType, callback) => {
8
+ const stableCallback = (0, hooks_1.useFastCallback)(callback);
7
9
  const websocketService = (0, useWebsocketApi_1.useWebsocketApi)();
8
10
  (0, react_1.useEffect)(() => {
9
- const handle = websocketService === null || websocketService === void 0 ? void 0 : websocketService.subscribe(subscriptionType, callback);
11
+ const handle = websocketService === null || websocketService === void 0 ? void 0 : websocketService.subscribe(subscriptionType, stableCallback);
10
12
  return () => {
11
13
  if (handle) {
12
14
  websocketService === null || websocketService === void 0 ? void 0 : websocketService.unsubscribe(handle);
13
15
  }
14
16
  };
15
- }, [websocketService, subscriptionType, callback]);
17
+ }, [websocketService, subscriptionType, stableCallback]);
16
18
  };
17
19
  exports.useSubscribeToWebsocket = useSubscribeToWebsocket;
@@ -0,0 +1,2 @@
1
+ import { ActionProcessorListResolver } from 'quidproquo-core';
2
+ export declare const ActionProcessorContext: import("react").Context<ActionProcessorListResolver>;
@@ -0,0 +1,2 @@
1
+ import { createContext } from 'react';
2
+ export const ActionProcessorContext = createContext(async () => ({}));
@@ -0,0 +1,6 @@
1
+ import { ActionProcessorListResolver } from 'quidproquo-core';
2
+ export type ActionProcessorProviderProps = {
3
+ children: React.ReactNode;
4
+ getActionProcessors: ActionProcessorListResolver;
5
+ };
6
+ export declare const ActionProcessorProvider: React.FC<ActionProcessorProviderProps>;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useContext } from 'react';
3
+ import { ActionProcessorContext } from './ActionProcessorContext';
4
+ export const ActionProcessorProvider = ({ children, getActionProcessors }) => {
5
+ const parentGetActionProcessors = useContext(ActionProcessorContext);
6
+ // Merge: parent processors first, then this provider's (so child overrides parent)
7
+ const mergedGetActionProcessors = async (qpqConfig, dynamicModuleLoader) => ({
8
+ ...(await parentGetActionProcessors(qpqConfig, dynamicModuleLoader)),
9
+ ...(await getActionProcessors(qpqConfig, dynamicModuleLoader)),
10
+ });
11
+ return _jsx(ActionProcessorContext.Provider, { value: mergedGetActionProcessors, children: children });
12
+ };
@@ -0,0 +1,3 @@
1
+ export * from './ActionProcessorContext';
2
+ export * from './ActionProcessorProvider';
3
+ export * from './useActionProcessors';
@@ -0,0 +1,3 @@
1
+ export * from './ActionProcessorContext';
2
+ export * from './ActionProcessorProvider';
3
+ export * from './useActionProcessors';
@@ -0,0 +1 @@
1
+ export declare const useActionProcessors: () => import("quidproquo-core").ActionProcessorListResolver;
@@ -0,0 +1,3 @@
1
+ import { useContext } from 'react';
2
+ import { ActionProcessorContext } from './ActionProcessorContext';
3
+ export const useActionProcessors = () => useContext(ActionProcessorContext);
@@ -1,2 +1,3 @@
1
+ export * from './useApiRequestActionProcessor';
1
2
  export * from './useAuthenticatedNetworkRequest';
2
3
  export * from './useNetworkRequest';
@@ -1,2 +1,3 @@
1
+ export * from './useApiRequestActionProcessor';
1
2
  export * from './useAuthenticatedNetworkRequest';
2
3
  export * from './useNetworkRequest';
@@ -0,0 +1,5 @@
1
+ import { ActionProcessorListResolver } from 'quidproquo-core';
2
+ export type UseApiRequestActionProcessorOptions = {
3
+ resolveServiceBaseUrl?: (service: string) => string;
4
+ };
5
+ export declare const useApiRequestActionProcessor: (options?: UseApiRequestActionProcessorOptions) => ActionProcessorListResolver;
@@ -0,0 +1,15 @@
1
+ import { createApiRequestActionProcessor } from 'quidproquo-actionprocessor-web';
2
+ import { useMemo, useRef } from 'react';
3
+ import { useAuthAccessToken } from '../../auth/hooks';
4
+ import { useBaseUrlResolvers } from '../../baseUrl/hooks';
5
+ export const useApiRequestActionProcessor = (options) => {
6
+ const accessToken = useAuthAccessToken();
7
+ const { getApiUrl } = useBaseUrlResolvers();
8
+ // Hold the token in a ref so the processor closure always reads the current value.
9
+ const tokenRef = useRef(accessToken);
10
+ tokenRef.current = accessToken;
11
+ return useMemo(() => createApiRequestActionProcessor({
12
+ getHeaders: () => (tokenRef.current ? { Authorization: `Bearer ${tokenRef.current}` } : {}),
13
+ resolveServiceBaseUrl: options?.resolveServiceBaseUrl ?? (() => getApiUrl()),
14
+ }), [options?.resolveServiceBaseUrl, getApiUrl]);
15
+ };
@@ -1,4 +1,4 @@
1
- import { preformNetworkRequest } from 'quidproquo-web';
1
+ import { preformNetworkRequest } from 'quidproquo-webserver';
2
2
  import { useAuthAccessToken } from '../../auth';
3
3
  import { useFastCallback } from '../../hooks';
4
4
  export const useAuthenticatedNetworkRequest = (payload) => {
@@ -1,4 +1,4 @@
1
- import { preformNetworkRequest } from 'quidproquo-web';
1
+ import { preformNetworkRequest } from 'quidproquo-webserver';
2
2
  import { useFastCallback } from '../../hooks';
3
3
  export const useNetworkRequest = (payload) => {
4
4
  const requeser = useFastCallback(() => preformNetworkRequest(payload));
@@ -1,5 +1,7 @@
1
1
  import { useEffect } from 'react';
2
+ import { useFastCallback } from '../../hooks/useFastCallback';
2
3
  export const useRefreshTokens = (authenticationInfo, refreshTokens) => {
4
+ const stableRefreshTokens = useFastCallback(refreshTokens);
3
5
  const refresh = () => {
4
6
  if (authenticationInfo && authenticationInfo.refreshToken && authenticationInfo.expiresAt) {
5
7
  const now = new Date().toISOString();
@@ -9,12 +11,12 @@ export const useRefreshTokens = (authenticationInfo, refreshTokens) => {
9
11
  const refreshTime = timeToExpire - bufferTime;
10
12
  if (refreshTime > 0) {
11
13
  return setTimeout(() => {
12
- refreshTokens(authenticationInfo);
14
+ stableRefreshTokens(authenticationInfo);
13
15
  }, refreshTime);
14
16
  }
15
17
  else {
16
18
  // If the token is already expired or very close to expiration, refresh immediately
17
- refreshTokens(authenticationInfo);
19
+ stableRefreshTokens(authenticationInfo);
18
20
  }
19
21
  }
20
22
  return null;
@@ -27,5 +29,11 @@ export const useRefreshTokens = (authenticationInfo, refreshTokens) => {
27
29
  clearTimeout(timerId);
28
30
  }
29
31
  };
30
- }, [authenticationInfo, refreshTokens]);
32
+ // Key on the stable primitives that actually drive a refresh, not the
33
+ // authenticationInfo object itself. Callers commonly derive that object
34
+ // fresh on every render (e.g. an unmemoized selector), so depending on its
35
+ // reference would re-run this effect every render — and when the token is
36
+ // expired/near-expiry the "refresh immediately" branch would then fire a
37
+ // network refresh on every render, an unbounded loop.
38
+ }, [authenticationInfo?.expiresAt, authenticationInfo?.refreshToken]);
31
39
  };
@@ -0,0 +1,28 @@
1
+ type DateInput = {
2
+ isoDateTime: string;
3
+ } | {
4
+ unixTimestampMs: number;
5
+ } | {
6
+ date: Date;
7
+ };
8
+ export type DateTimeProps = DateInput & {
9
+ /** Locale(s) for both the absolute and relative formatting. Defaults to the runtime locale. */
10
+ locale?: string | string[];
11
+ /** Options for the absolute date/time. Defaults to a short date + time. */
12
+ dateTimeFormatOptions?: Intl.DateTimeFormatOptions;
13
+ /** Show the "x minutes ago" label alongside the absolute time. Defaults to true. */
14
+ showTimeAgo?: boolean;
15
+ /** Hide the date portion of the absolute time. Defaults to false. */
16
+ hideDate?: boolean;
17
+ /** Hide the time portion of the absolute time. Defaults to false. */
18
+ hideTime?: boolean;
19
+ /** Hide the "x minutes ago" label. Takes precedence over showTimeAgo. Defaults to false. */
20
+ hideTimeAgo?: boolean;
21
+ /** Render each part on its own line instead of inline. Defaults to true. */
22
+ isMultiline?: boolean;
23
+ /** What to render when the date is missing/invalid (e.g. an empty isoDateTime). Defaults to "—". */
24
+ placeholder?: React.ReactNode;
25
+ className?: string;
26
+ };
27
+ export declare const DateTime: import("react").NamedExoticComponent<DateTimeProps>;
28
+ export {};
@@ -0,0 +1,54 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { memo, useMemo } from 'react';
3
+ import { useTimeAgo } from './hooks';
4
+ const DEFAULT_DATE_OPTIONS = {
5
+ day: '2-digit',
6
+ month: '2-digit',
7
+ year: '2-digit',
8
+ };
9
+ const DEFAULT_TIME_OPTIONS = {
10
+ hour: '2-digit',
11
+ minute: '2-digit',
12
+ };
13
+ const DATE_OPTION_KEYS = ['weekday', 'era', 'year', 'month', 'day'];
14
+ const TIME_OPTION_KEYS = ['hour', 'minute', 'second', 'dayPeriod', 'timeZoneName'];
15
+ const pickOptions = (options, keys) => {
16
+ if (!options) {
17
+ return undefined;
18
+ }
19
+ const picked = keys.reduce((acc, key) => {
20
+ if (options[key] !== undefined) {
21
+ acc[key] = options[key];
22
+ }
23
+ return acc;
24
+ }, {});
25
+ return Object.keys(picked).length > 0 ? picked : undefined;
26
+ };
27
+ const toDate = (props) => {
28
+ if ('isoDateTime' in props) {
29
+ return new Date(props.isoDateTime);
30
+ }
31
+ if ('unixTimestampMs' in props) {
32
+ return new Date(props.unixTimestampMs);
33
+ }
34
+ return props.date;
35
+ };
36
+ const component = (props) => {
37
+ const { locale, dateTimeFormatOptions, showTimeAgo = true, hideDate = false, hideTime = false, hideTimeAgo = false, isMultiline = true, placeholder = '—', className } = props;
38
+ // Stable primitive key so a fresh props object doesn't churn the memo.
39
+ const dateKey = 'isoDateTime' in props ? props.isoDateTime : 'unixTimestampMs' in props ? props.unixTimestampMs : props.date.getTime();
40
+ const date = useMemo(() => toDate(props), [dateKey]);
41
+ const isValidDate = !Number.isNaN(date.getTime());
42
+ const formattedDate = useMemo(() => (hideDate ? '' : date.toLocaleDateString(locale, pickOptions(dateTimeFormatOptions, DATE_OPTION_KEYS) ?? DEFAULT_DATE_OPTIONS)), [date, locale, dateTimeFormatOptions, hideDate]);
43
+ const formattedTime = useMemo(() => (hideTime ? '' : date.toLocaleTimeString(locale, pickOptions(dateTimeFormatOptions, TIME_OPTION_KEYS) ?? DEFAULT_TIME_OPTIONS)), [date, locale, dateTimeFormatOptions, hideTime]);
44
+ const timeAgo = useTimeAgo(date, locale);
45
+ const formattedDateTime = [formattedDate, formattedTime].filter(Boolean).join(' ');
46
+ const displayTimeAgo = showTimeAgo && !hideTimeAgo;
47
+ // A missing/invalid date (e.g. an empty isoDateTime) renders the placeholder instead of
48
+ // an "Invalid Date" string or crashing the relative-time formatter.
49
+ if (!isValidDate) {
50
+ return _jsx("time", { className: className, children: placeholder });
51
+ }
52
+ return (_jsx("time", { dateTime: date.toISOString(), title: date.toLocaleString(locale), className: className, children: isMultiline ? (_jsxs(_Fragment, { children: [formattedDateTime ? _jsx("div", { children: formattedDateTime }) : null, displayTimeAgo ? _jsx("div", { children: timeAgo }) : null] })) : (_jsxs(_Fragment, { children: [formattedDateTime, displayTimeAgo ? ` (${timeAgo})` : ''] })) }));
53
+ };
54
+ export const DateTime = memo(component);
@@ -0,0 +1 @@
1
+ export * from './useTimeAgo';
@@ -0,0 +1 @@
1
+ export * from './useTimeAgo';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Returns a relative time phrase for `date` (e.g. "5 minutes ago") that
3
+ * updates itself over time. The re-render cadence adapts to the age of the
4
+ * date, so recent times tick every second and older ones only update hourly.
5
+ */
6
+ export declare const useTimeAgo: (date: Date, locale?: string | string[]) => string;