@getuserfeedback/react-native 1.3.6 → 1.3.8

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.
package/dist/index.js CHANGED
@@ -15,7 +15,9 @@ import { createContext, createElement, useCallback, useContext, useEffect, useMe
15
15
  import { useResolvedHostViewport } from "./host-viewport.js";
16
16
  import { toCommandFlowId, toCommandSettlementError, toRetryWithoutFlowHandle, } from "./provider-command-helpers.js";
17
17
  import { clearProviderFlowHandleCache, createProviderFlowHandleCache, deleteCachedProviderFlowHandleId, deleteCachedProviderFlowId, getCachedProviderFlowHandleId, snapshotProviderFlowCommand, writeSettledProviderFlowHandleId, } from "./provider-flow-handle-cache.js";
18
+ import { enqueueProviderNativeMessage, removeProviderNativeMessageId, removeProviderNativeMessageIds, replaceProviderNativeMessages, } from "./provider-message-queue.js";
18
19
  import { applyProviderOverlayFlowState, applyProviderOverlayHandleInvalidated, createDefaultProviderOverlayState, DEFAULT_PROVIDER_OVERLAY_VISIBILITY, updateProviderOverlayReadySequence, } from "./provider-overlay-state.js";
20
+ import { cancelProviderStartupCommands, clearProviderPendingCommands, createProviderPendingCommandRegistry, getProviderPendingCommand, getProviderPendingCommandEntries, getProviderPendingCommands, hasDeliveredProviderPendingCommands, isProviderPendingMessageStartup, registerProviderPendingCommand, reissueProviderPendingCommand, takeProviderPendingCommand, } from "./provider-pending-commands.js";
19
21
  import { ProviderWidgetHostOverlay, toProviderWidgetHostStyle, toProviderWidgetSheetHostViewport, } from "./provider-widget-host-overlay.js";
20
22
  import { REACT_NATIVE_SDK_VERSION } from "./version.js";
21
23
  import { WidgetHost, } from "./widget-host.js";
@@ -114,7 +116,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
114
116
  const [widgetHostVisibility, setWidgetHostVisibility] = useState(DEFAULT_PROVIDER_OVERLAY_VISIBILITY);
115
117
  const resolvedHostViewport = useResolvedHostViewport(hostViewport);
116
118
  const nativeMessagesRef = useRef([]);
117
- const pendingCommandsRef = useRef(new Map());
119
+ const pendingCommandsRef = useRef(createProviderPendingCommandRegistry());
118
120
  const hostEpochRef = useRef(0);
119
121
  const flowHandleCacheRef = useRef(createProviderFlowHandleCache());
120
122
  const providerOverlayStateRef = useRef(createDefaultProviderOverlayState());
@@ -133,7 +135,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
133
135
  if (hostSourceKeyRef.current !== hostSourceKey) {
134
136
  hostSourceKeyRef.current = hostSourceKey;
135
137
  hostSourceVersionRef.current += 1;
136
- for (const pendingCommand of pendingCommandsRef.current.values()) {
138
+ for (const pendingCommand of getProviderPendingCommands(pendingCommandsRef.current)) {
137
139
  if (!pendingCommand.timeout) {
138
140
  continue;
139
141
  }
@@ -162,7 +164,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
162
164
  }, 0);
163
165
  }, [onCommandError]);
164
166
  const rejectPendingCommand = useCallback((requestId, pendingCommand, error) => {
165
- pendingCommandsRef.current.delete(requestId);
167
+ takeProviderPendingCommand(pendingCommandsRef.current, requestId);
166
168
  if (pendingCommand.timeout) {
167
169
  clearTimeout(pendingCommand.timeout);
168
170
  pendingCommand.timeout = null;
@@ -170,7 +172,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
170
172
  if (pendingCommand.isStartup) {
171
173
  startupQueuedKeyRef.current = null;
172
174
  }
173
- setNativeMessages((messages) => messages.filter((entry) => entry.id !== pendingCommand.messageId));
175
+ setNativeMessages((messages) => removeProviderNativeMessageId(messages, pendingCommand.messageId));
174
176
  pendingCommand.reject(error);
175
177
  }, []);
176
178
  const startPendingCommandTimeout = useCallback((requestId, pendingCommand) => {
@@ -187,12 +189,12 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
187
189
  }, commandTimeoutMs);
188
190
  }, [commandTimeoutMs, rejectPendingCommand]);
189
191
  const startPendingCommandTimeouts = useCallback(() => {
190
- for (const [requestId, pendingCommand] of pendingCommandsRef.current) {
192
+ for (const [requestId, pendingCommand] of getProviderPendingCommandEntries(pendingCommandsRef.current)) {
191
193
  startPendingCommandTimeout(requestId, pendingCommand);
192
194
  }
193
195
  }, [startPendingCommandTimeout]);
194
196
  const pausePendingCommandTimeouts = useCallback(() => {
195
- for (const pendingCommand of pendingCommandsRef.current.values()) {
197
+ for (const pendingCommand of getProviderPendingCommands(pendingCommandsRef.current)) {
196
198
  if (!pendingCommand.timeout) {
197
199
  continue;
198
200
  }
@@ -233,7 +235,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
233
235
  };
234
236
  const flowCommandSnapshot = snapshotProviderFlowCommand(flowHandleCacheRef.current, validatedMessage.envelope.command);
235
237
  const promise = new Promise((resolve, reject) => {
236
- pendingCommandsRef.current.set(requestId, {
238
+ const pendingCommand = {
237
239
  flowCommandSequence: flowCommandSnapshot.flowCommandSequence,
238
240
  flowHandleCacheEpoch: flowCommandSnapshot.flowHandleCacheEpoch,
239
241
  hostEpoch: null,
@@ -243,40 +245,27 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
243
245
  resolve,
244
246
  result,
245
247
  timeout: null,
246
- });
248
+ };
249
+ registerProviderPendingCommand(pendingCommandsRef.current, requestId, pendingCommand);
247
250
  if (lastReadyRef.current !== null) {
248
- startPendingCommandTimeout(requestId, pendingCommandsRef.current.get(requestId));
251
+ startPendingCommandTimeout(requestId, pendingCommand);
249
252
  }
250
253
  });
251
- setNativeMessages((messages) => {
252
- if (!(isStartup && prioritizeStartup)) {
253
- return [...messages, validatedMessage];
254
- }
255
- const firstActionIndex = messages.findIndex((entry) => {
256
- const pendingCommand = pendingCommandsRef.current.get(entry.envelope.requestId);
257
- return !(pendingCommand === null || pendingCommand === void 0 ? void 0 : pendingCommand.isStartup);
258
- });
259
- if (firstActionIndex === -1) {
260
- return [...messages, validatedMessage];
261
- }
262
- return [
263
- ...messages.slice(0, firstActionIndex),
264
- validatedMessage,
265
- ...messages.slice(firstActionIndex),
266
- ];
267
- });
254
+ setNativeMessages((messages) => enqueueProviderNativeMessage(messages, {
255
+ isStartup,
256
+ isStartupMessage: (entry) => isProviderPendingMessageStartup(pendingCommandsRef.current, entry.envelope.requestId),
257
+ message: validatedMessage,
258
+ prioritizeStartup,
259
+ }));
268
260
  return promise;
269
261
  }, [instanceId, startPendingCommandTimeout]);
270
262
  const reissueDeliveredPendingActionCommands = useCallback(() => {
271
263
  var _a;
272
264
  const replacements = new Map();
273
- for (const [requestId, pendingCommand] of [
274
- ...pendingCommandsRef.current.entries(),
275
- ]) {
265
+ for (const [requestId, pendingCommand] of getProviderPendingCommandEntries(pendingCommandsRef.current)) {
276
266
  if (pendingCommand.isStartup || pendingCommand.hostEpoch === null) {
277
267
  continue;
278
268
  }
279
- pendingCommandsRef.current.delete(requestId);
280
269
  if (pendingCommand.timeout) {
281
270
  clearTimeout(pendingCommand.timeout);
282
271
  pendingCommand.timeout = null;
@@ -288,40 +277,39 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
288
277
  id: createTransportMessageId(),
289
278
  envelope: nextEnvelope,
290
279
  });
291
- const previousMessageId = pendingCommand.messageId;
292
- pendingCommand.flowHandleCacheEpoch = flowHandleCacheRef.current.epoch;
293
- pendingCommand.hostEpoch = null;
294
- pendingCommand.messageId = nextMessage.id;
295
- pendingCommand.result = {
296
- envelope: nextMessage.envelope,
297
- message: nextMessage,
298
- };
299
- pendingCommandsRef.current.set(nextEnvelope.requestId, pendingCommand);
300
- replacements.set(previousMessageId, nextMessage);
280
+ const reissuedCommand = reissueProviderPendingCommand(pendingCommandsRef.current, {
281
+ flowHandleCacheEpoch: flowHandleCacheRef.current.epoch,
282
+ nextMessageId: nextMessage.id,
283
+ nextRequestId: nextEnvelope.requestId,
284
+ nextResult: {
285
+ envelope: nextMessage.envelope,
286
+ message: nextMessage,
287
+ },
288
+ requestId,
289
+ });
290
+ if (!reissuedCommand) {
291
+ continue;
292
+ }
293
+ replacements.set(reissuedCommand.previousMessageId, nextMessage);
301
294
  }
302
295
  if (replacements.size === 0) {
303
296
  return false;
304
297
  }
305
- setNativeMessages((messages) => messages.map((message) => { var _a; return (_a = replacements.get(message.id)) !== null && _a !== void 0 ? _a : message; }));
298
+ setNativeMessages((messages) => replaceProviderNativeMessages(messages, replacements));
306
299
  return true;
307
300
  }, []);
308
301
  const cancelPendingStartupCommands = useCallback(() => {
309
- const canceledMessageIds = new Set();
310
- for (const [requestId, pendingCommand] of pendingCommandsRef.current) {
311
- if (!pendingCommand.isStartup) {
312
- continue;
313
- }
314
- pendingCommandsRef.current.delete(requestId);
315
- canceledMessageIds.add(pendingCommand.messageId);
302
+ const canceled = cancelProviderStartupCommands(pendingCommandsRef.current);
303
+ for (const pendingCommand of canceled.commands) {
316
304
  if (pendingCommand.timeout) {
317
305
  clearTimeout(pendingCommand.timeout);
318
306
  }
319
307
  pendingCommand.reject(new Error(STARTUP_COMMAND_REPLACED_ERROR_MESSAGE));
320
308
  }
321
- if (canceledMessageIds.size === 0) {
309
+ if (canceled.messageIds.size === 0) {
322
310
  return;
323
311
  }
324
- setNativeMessages((messages) => messages.filter((entry) => !canceledMessageIds.has(entry.id)));
312
+ setNativeMessages((messages) => removeProviderNativeMessageIds(messages, canceled.messageIds));
325
313
  }, []);
326
314
  const enqueueStartupCommands = useCallback(({ force = false } = {}) => {
327
315
  if (!autoInit) {
@@ -360,9 +348,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
360
348
  if (alreadySeen) {
361
349
  return false;
362
350
  }
363
- const hasDeliveredPendingCommands = [
364
- ...pendingCommandsRef.current.values(),
365
- ].some((pendingCommand) => pendingCommand.hostEpoch !== null);
351
+ const hasDeliveredPendingCommands = hasDeliveredProviderPendingCommands(pendingCommandsRef.current);
366
352
  let didReissueDeliveredCommands = false;
367
353
  if (previous !== null || hasDeliveredPendingCommands) {
368
354
  hostEpochRef.current += 1;
@@ -464,15 +450,15 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
464
450
  if (message.kind === "hostEvent" &&
465
451
  message.event.name === "instance:command:settled") {
466
452
  const requestId = message.event.detail.requestId;
467
- const pendingCommand = pendingCommandsRef.current.get(requestId);
453
+ const pendingCommand = getProviderPendingCommand(pendingCommandsRef.current, requestId);
468
454
  if (pendingCommand) {
469
455
  if (pendingCommand.hostEpoch !== null &&
470
456
  pendingCommand.hostEpoch !== ((_a = lastReadyRef.current) === null || _a === void 0 ? void 0 : _a.hostEpoch)) {
471
457
  onWebMessage === null || onWebMessage === void 0 ? void 0 : onWebMessage(message);
472
458
  return;
473
459
  }
474
- pendingCommandsRef.current.delete(requestId);
475
- setNativeMessages((messages) => messages.filter((entry) => entry.id !== pendingCommand.messageId));
460
+ takeProviderPendingCommand(pendingCommandsRef.current, requestId);
461
+ setNativeMessages((messages) => removeProviderNativeMessageId(messages, pendingCommand.messageId));
476
462
  if (pendingCommand.timeout) {
477
463
  clearTimeout(pendingCommand.timeout);
478
464
  }
@@ -521,13 +507,13 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
521
507
  onWebMessage,
522
508
  ]);
523
509
  useEffect(() => () => {
524
- for (const pendingCommand of pendingCommandsRef.current.values()) {
510
+ for (const pendingCommand of getProviderPendingCommands(pendingCommandsRef.current)) {
525
511
  if (pendingCommand.timeout) {
526
512
  clearTimeout(pendingCommand.timeout);
527
513
  }
528
514
  pendingCommand.reject(new Error(PROVIDER_UNMOUNTED_ERROR_MESSAGE));
529
515
  }
530
- pendingCommandsRef.current.clear();
516
+ clearProviderPendingCommands(pendingCommandsRef.current);
531
517
  }, []);
532
518
  useEffect(() => {
533
519
  if (visibilitySourceKeyRef.current === hostSourceKey) {
@@ -0,0 +1,11 @@
1
+ import type { WebViewTransportNativeMessage } from "@getuserfeedback/protocol/webview-transport";
2
+ export type ProviderNativeMessageQueue = readonly WebViewTransportNativeMessage[];
3
+ export declare function enqueueProviderNativeMessage(messages: ProviderNativeMessageQueue, { isStartup, isStartupMessage, message, prioritizeStartup, }: {
4
+ isStartup: boolean;
5
+ isStartupMessage: (message: WebViewTransportNativeMessage) => boolean;
6
+ message: WebViewTransportNativeMessage;
7
+ prioritizeStartup: boolean;
8
+ }): WebViewTransportNativeMessage[];
9
+ export declare function removeProviderNativeMessageIds(messages: ProviderNativeMessageQueue, messageIds: ReadonlySet<string>): WebViewTransportNativeMessage[];
10
+ export declare function removeProviderNativeMessageId(messages: ProviderNativeMessageQueue, messageId: string): WebViewTransportNativeMessage[];
11
+ export declare function replaceProviderNativeMessages(messages: ProviderNativeMessageQueue, replacementsByMessageId: ReadonlyMap<string, WebViewTransportNativeMessage>): WebViewTransportNativeMessage[];
@@ -0,0 +1,23 @@
1
+ export function enqueueProviderNativeMessage(messages, { isStartup, isStartupMessage, message, prioritizeStartup, }) {
2
+ if (!(isStartup && prioritizeStartup)) {
3
+ return [...messages, message];
4
+ }
5
+ const firstActionIndex = messages.findIndex((entry) => !isStartupMessage(entry));
6
+ if (firstActionIndex === -1) {
7
+ return [...messages, message];
8
+ }
9
+ return [
10
+ ...messages.slice(0, firstActionIndex),
11
+ message,
12
+ ...messages.slice(firstActionIndex),
13
+ ];
14
+ }
15
+ export function removeProviderNativeMessageIds(messages, messageIds) {
16
+ return messages.filter((entry) => !messageIds.has(entry.id));
17
+ }
18
+ export function removeProviderNativeMessageId(messages, messageId) {
19
+ return removeProviderNativeMessageIds(messages, new Set([messageId]));
20
+ }
21
+ export function replaceProviderNativeMessages(messages, replacementsByMessageId) {
22
+ return messages.map((message) => { var _a; return (_a = replacementsByMessageId.get(message.id)) !== null && _a !== void 0 ? _a : message; });
23
+ }
@@ -0,0 +1,37 @@
1
+ export type ProviderPendingCommand<Result> = {
2
+ flowCommandSequence: number | null;
3
+ flowHandleCacheEpoch: number;
4
+ hostEpoch: number | null;
5
+ isStartup: boolean;
6
+ messageId: string;
7
+ reject: (error: Error) => void;
8
+ resolve: (result: Result) => void;
9
+ result: Result;
10
+ timeout: ReturnType<typeof setTimeout> | null;
11
+ };
12
+ export type ProviderPendingCommandRegistry<Result> = Map<string, ProviderPendingCommand<Result>>;
13
+ export type ProviderCanceledStartupCommands<Result> = {
14
+ commands: ProviderPendingCommand<Result>[];
15
+ messageIds: Set<string>;
16
+ };
17
+ export type ProviderReissuedPendingCommand<Result> = {
18
+ command: ProviderPendingCommand<Result>;
19
+ previousMessageId: string;
20
+ };
21
+ export declare function createProviderPendingCommandRegistry<Result>(): ProviderPendingCommandRegistry<Result>;
22
+ export declare function registerProviderPendingCommand<Result>(registry: ProviderPendingCommandRegistry<Result>, requestId: string, command: ProviderPendingCommand<Result>): void;
23
+ export declare function getProviderPendingCommand<Result>(registry: ProviderPendingCommandRegistry<Result>, requestId: string): ProviderPendingCommand<Result> | undefined;
24
+ export declare function takeProviderPendingCommand<Result>(registry: ProviderPendingCommandRegistry<Result>, requestId: string): ProviderPendingCommand<Result> | undefined;
25
+ export declare function hasDeliveredProviderPendingCommands<Result>(registry: ProviderPendingCommandRegistry<Result>): boolean;
26
+ export declare function isProviderPendingMessageStartup<Result>(registry: ProviderPendingCommandRegistry<Result>, requestId: string): boolean;
27
+ export declare function getProviderPendingCommandEntries<Result>(registry: ProviderPendingCommandRegistry<Result>): Array<[string, ProviderPendingCommand<Result>]>;
28
+ export declare function getProviderPendingCommands<Result>(registry: ProviderPendingCommandRegistry<Result>): ProviderPendingCommand<Result>[];
29
+ export declare function cancelProviderStartupCommands<Result>(registry: ProviderPendingCommandRegistry<Result>): ProviderCanceledStartupCommands<Result>;
30
+ export declare function reissueProviderPendingCommand<Result>(registry: ProviderPendingCommandRegistry<Result>, { flowHandleCacheEpoch, nextMessageId, nextRequestId, nextResult, requestId, }: {
31
+ flowHandleCacheEpoch: number;
32
+ nextMessageId: string;
33
+ nextRequestId: string;
34
+ nextResult: Result;
35
+ requestId: string;
36
+ }): ProviderReissuedPendingCommand<Result> | null;
37
+ export declare function clearProviderPendingCommands<Result>(registry: ProviderPendingCommandRegistry<Result>): void;
@@ -0,0 +1,59 @@
1
+ export function createProviderPendingCommandRegistry() {
2
+ return new Map();
3
+ }
4
+ export function registerProviderPendingCommand(registry, requestId, command) {
5
+ registry.set(requestId, command);
6
+ }
7
+ export function getProviderPendingCommand(registry, requestId) {
8
+ return registry.get(requestId);
9
+ }
10
+ export function takeProviderPendingCommand(registry, requestId) {
11
+ const command = registry.get(requestId);
12
+ if (command) {
13
+ registry.delete(requestId);
14
+ }
15
+ return command;
16
+ }
17
+ export function hasDeliveredProviderPendingCommands(registry) {
18
+ return [...registry.values()].some((command) => command.hostEpoch !== null);
19
+ }
20
+ export function isProviderPendingMessageStartup(registry, requestId) {
21
+ var _a;
22
+ return ((_a = registry.get(requestId)) === null || _a === void 0 ? void 0 : _a.isStartup) === true;
23
+ }
24
+ export function getProviderPendingCommandEntries(registry) {
25
+ return [...registry.entries()];
26
+ }
27
+ export function getProviderPendingCommands(registry) {
28
+ return [...registry.values()];
29
+ }
30
+ export function cancelProviderStartupCommands(registry) {
31
+ const commands = [];
32
+ const messageIds = new Set();
33
+ for (const [requestId, command] of registry) {
34
+ if (!command.isStartup) {
35
+ continue;
36
+ }
37
+ registry.delete(requestId);
38
+ commands.push(command);
39
+ messageIds.add(command.messageId);
40
+ }
41
+ return { commands, messageIds };
42
+ }
43
+ export function reissueProviderPendingCommand(registry, { flowHandleCacheEpoch, nextMessageId, nextRequestId, nextResult, requestId, }) {
44
+ const command = registry.get(requestId);
45
+ if (!command || command.isStartup || command.hostEpoch === null) {
46
+ return null;
47
+ }
48
+ registry.delete(requestId);
49
+ const previousMessageId = command.messageId;
50
+ command.flowHandleCacheEpoch = flowHandleCacheEpoch;
51
+ command.hostEpoch = null;
52
+ command.messageId = nextMessageId;
53
+ command.result = nextResult;
54
+ registry.set(nextRequestId, command);
55
+ return { command, previousMessageId };
56
+ }
57
+ export function clearProviderPendingCommands(registry) {
58
+ registry.clear();
59
+ }
package/dist/version.js CHANGED
@@ -3,4 +3,4 @@ const reactNativeSdkVersion = typeof __GX_REACT_NATIVE_SDK_VERSION__ === "string
3
3
  : "";
4
4
  // Build scripts patch this fallback to the package version for published artifacts.
5
5
  // Source-linked workspace usage keeps the local fallback.
6
- export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "1.3.6";
6
+ export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "1.3.8";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/react-native",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "getuserfeedback React Native SDK",
5
5
  "keywords": [
6
6
  "getuserfeedback",