@getuserfeedback/react-native 1.3.5 → 1.3.7

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
@@ -13,7 +13,9 @@ import { assertNoSegmentExternalIdsInValueArgument, CommandSettlementTimeoutErro
13
13
  import { parseWebViewTransportNativeMessage } from "@getuserfeedback/protocol/webview-transport";
14
14
  import { createContext, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
15
15
  import { useResolvedHostViewport } from "./host-viewport.js";
16
- import { toCommandFlowId, toCommandSettlementError, toRetryWithoutFlowHandle, toSettledFlowHandleId, } from "./provider-command-helpers.js";
16
+ import { toCommandFlowId, toCommandSettlementError, toRetryWithoutFlowHandle, } from "./provider-command-helpers.js";
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";
17
19
  import { applyProviderOverlayFlowState, applyProviderOverlayHandleInvalidated, createDefaultProviderOverlayState, DEFAULT_PROVIDER_OVERLAY_VISIBILITY, updateProviderOverlayReadySequence, } from "./provider-overlay-state.js";
18
20
  import { ProviderWidgetHostOverlay, toProviderWidgetHostStyle, toProviderWidgetSheetHostViewport, } from "./provider-widget-host-overlay.js";
19
21
  import { REACT_NATIVE_SDK_VERSION } from "./version.js";
@@ -115,9 +117,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
115
117
  const nativeMessagesRef = useRef([]);
116
118
  const pendingCommandsRef = useRef(new Map());
117
119
  const hostEpochRef = useRef(0);
118
- const flowHandleCacheEpochRef = useRef(0);
119
- const flowHandleIdsByFlowIdRef = useRef(new Map());
120
- const flowCommandSequencesByFlowIdRef = useRef(new Map());
120
+ const flowHandleCacheRef = useRef(createProviderFlowHandleCache());
121
121
  const providerOverlayStateRef = useRef(createDefaultProviderOverlayState());
122
122
  const initOptionsRef = useRef(initOptions);
123
123
  const configureOptionsRef = useRef(configureOptions);
@@ -143,8 +143,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
143
143
  }
144
144
  lastReadyRef.current = null;
145
145
  startupQueuedKeyRef.current = null;
146
- flowHandleCacheEpochRef.current += 1;
147
- flowHandleIdsByFlowIdRef.current.clear();
146
+ clearProviderFlowHandleCache(flowHandleCacheRef.current);
148
147
  providerOverlayStateRef.current = createDefaultProviderOverlayState();
149
148
  }
150
149
  initOptionsRef.current = initOptions;
@@ -172,7 +171,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
172
171
  if (pendingCommand.isStartup) {
173
172
  startupQueuedKeyRef.current = null;
174
173
  }
175
- setNativeMessages((messages) => messages.filter((entry) => entry.id !== pendingCommand.messageId));
174
+ setNativeMessages((messages) => removeProviderNativeMessageId(messages, pendingCommand.messageId));
176
175
  pendingCommand.reject(error);
177
176
  }, []);
178
177
  const startPendingCommandTimeout = useCallback((requestId, pendingCommand) => {
@@ -203,7 +202,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
203
202
  }
204
203
  }, []);
205
204
  const enqueueTransportCommand = useCallback((command, options, { isStartup = false, prioritizeStartup = false, } = {}) => {
206
- var _a, _b;
205
+ var _a;
207
206
  const requestId = createCommandRequestId();
208
207
  const idempotencyKey = (_a = normalizeOptionalString(options === null || options === void 0 ? void 0 : options.idempotencyKey)) !== null && _a !== void 0 ? _a : requestId;
209
208
  const envelope = {
@@ -233,17 +232,11 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
233
232
  envelope: validatedMessage.envelope,
234
233
  message: validatedMessage,
235
234
  };
236
- const flowId = toCommandFlowId(validatedMessage.envelope.command);
237
- const flowCommandSequence = flowId === undefined
238
- ? null
239
- : ((_b = flowCommandSequencesByFlowIdRef.current.get(flowId)) !== null && _b !== void 0 ? _b : 0) + 1;
240
- if (flowId !== undefined && flowCommandSequence !== null) {
241
- flowCommandSequencesByFlowIdRef.current.set(flowId, flowCommandSequence);
242
- }
235
+ const flowCommandSnapshot = snapshotProviderFlowCommand(flowHandleCacheRef.current, validatedMessage.envelope.command);
243
236
  const promise = new Promise((resolve, reject) => {
244
237
  pendingCommandsRef.current.set(requestId, {
245
- flowCommandSequence,
246
- flowHandleCacheEpoch: flowHandleCacheEpochRef.current,
238
+ flowCommandSequence: flowCommandSnapshot.flowCommandSequence,
239
+ flowHandleCacheEpoch: flowCommandSnapshot.flowHandleCacheEpoch,
247
240
  hostEpoch: null,
248
241
  isStartup,
249
242
  messageId: validatedMessage.id,
@@ -256,23 +249,15 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
256
249
  startPendingCommandTimeout(requestId, pendingCommandsRef.current.get(requestId));
257
250
  }
258
251
  });
259
- setNativeMessages((messages) => {
260
- if (!(isStartup && prioritizeStartup)) {
261
- return [...messages, validatedMessage];
262
- }
263
- const firstActionIndex = messages.findIndex((entry) => {
264
- const pendingCommand = pendingCommandsRef.current.get(entry.envelope.requestId);
265
- return !(pendingCommand === null || pendingCommand === void 0 ? void 0 : pendingCommand.isStartup);
266
- });
267
- if (firstActionIndex === -1) {
268
- return [...messages, validatedMessage];
269
- }
270
- return [
271
- ...messages.slice(0, firstActionIndex),
272
- validatedMessage,
273
- ...messages.slice(firstActionIndex),
274
- ];
275
- });
252
+ setNativeMessages((messages) => enqueueProviderNativeMessage(messages, {
253
+ isStartup,
254
+ isStartupMessage: (entry) => {
255
+ var _a;
256
+ return ((_a = pendingCommandsRef.current.get(entry.envelope.requestId)) === null || _a === void 0 ? void 0 : _a.isStartup) === true;
257
+ },
258
+ message: validatedMessage,
259
+ prioritizeStartup,
260
+ }));
276
261
  return promise;
277
262
  }, [instanceId, startPendingCommandTimeout]);
278
263
  const reissueDeliveredPendingActionCommands = useCallback(() => {
@@ -297,7 +282,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
297
282
  envelope: nextEnvelope,
298
283
  });
299
284
  const previousMessageId = pendingCommand.messageId;
300
- pendingCommand.flowHandleCacheEpoch = flowHandleCacheEpochRef.current;
285
+ pendingCommand.flowHandleCacheEpoch = flowHandleCacheRef.current.epoch;
301
286
  pendingCommand.hostEpoch = null;
302
287
  pendingCommand.messageId = nextMessage.id;
303
288
  pendingCommand.result = {
@@ -310,7 +295,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
310
295
  if (replacements.size === 0) {
311
296
  return false;
312
297
  }
313
- 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));
314
299
  return true;
315
300
  }, []);
316
301
  const cancelPendingStartupCommands = useCallback(() => {
@@ -329,7 +314,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
329
314
  if (canceledMessageIds.size === 0) {
330
315
  return;
331
316
  }
332
- setNativeMessages((messages) => messages.filter((entry) => !canceledMessageIds.has(entry.id)));
317
+ setNativeMessages((messages) => removeProviderNativeMessageIds(messages, canceledMessageIds));
333
318
  }, []);
334
319
  const enqueueStartupCommands = useCallback(({ force = false } = {}) => {
335
320
  if (!autoInit) {
@@ -375,8 +360,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
375
360
  if (previous !== null || hasDeliveredPendingCommands) {
376
361
  hostEpochRef.current += 1;
377
362
  startupQueuedKeyRef.current = null;
378
- flowHandleCacheEpochRef.current += 1;
379
- flowHandleIdsByFlowIdRef.current.clear();
363
+ clearProviderFlowHandleCache(flowHandleCacheRef.current);
380
364
  didReissueDeliveredCommands = reissueDeliveredPendingActionCommands();
381
365
  }
382
366
  lastReadyRef.current = Object.assign(Object.assign({}, event), { hostEpoch: hostEpochRef.current });
@@ -411,8 +395,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
411
395
  if (lastReadyRef.current !== null) {
412
396
  hostEpochRef.current += 1;
413
397
  startupQueuedKeyRef.current = null;
414
- flowHandleCacheEpochRef.current += 1;
415
- flowHandleIdsByFlowIdRef.current.clear();
398
+ clearProviderFlowHandleCache(flowHandleCacheRef.current);
416
399
  reissueDeliveredPendingActionCommands();
417
400
  }
418
401
  lastReadyRef.current = null;
@@ -425,12 +408,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
425
408
  reissueDeliveredPendingActionCommands,
426
409
  ]);
427
410
  const deleteCachedFlowHandleId = useCallback((flowHandleId) => {
428
- for (const [flowId, cachedFlowHandleId,] of flowHandleIdsByFlowIdRef.current) {
429
- if (cachedFlowHandleId === flowHandleId) {
430
- flowHandleIdsByFlowIdRef.current.delete(flowId);
431
- }
432
- }
433
- flowHandleCacheEpochRef.current += 1;
411
+ deleteCachedProviderFlowHandleId(flowHandleCacheRef.current, flowHandleId);
434
412
  }, []);
435
413
  const handleFlowHandleInvalidated = useCallback((flowHandleId) => {
436
414
  deleteCachedFlowHandleId(flowHandleId);
@@ -487,7 +465,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
487
465
  return;
488
466
  }
489
467
  pendingCommandsRef.current.delete(requestId);
490
- setNativeMessages((messages) => messages.filter((entry) => entry.id !== pendingCommand.messageId));
468
+ setNativeMessages((messages) => removeProviderNativeMessageId(messages, pendingCommand.messageId));
491
469
  if (pendingCommand.timeout) {
492
470
  clearTimeout(pendingCommand.timeout);
493
471
  }
@@ -500,7 +478,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
500
478
  const isStaleFlowHandleError = error.code === "STALE_HANDLE" ||
501
479
  error.message.includes("flowHandleId is stale");
502
480
  if (flowId && isStaleFlowHandleError) {
503
- flowHandleIdsByFlowIdRef.current.delete(flowId);
481
+ deleteCachedProviderFlowId(flowHandleCacheRef.current, flowId);
504
482
  }
505
483
  const retryCommand = isStaleFlowHandleError
506
484
  ? toRetryWithoutFlowHandle(pendingCommand.result.envelope.command)
@@ -514,20 +492,14 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
514
492
  else {
515
493
  const settlement = message.event
516
494
  .detail;
517
- const flowId = toCommandFlowId(pendingCommand.result.envelope.command);
518
- const flowHandleId = toSettledFlowHandleId(settlement.result);
519
- const canWriteFlowHandle = flowId &&
520
- flowHandleId &&
521
- pendingCommand.flowHandleCacheEpoch ===
522
- flowHandleCacheEpochRef.current &&
523
- pendingCommand.flowCommandSequence ===
524
- flowCommandSequencesByFlowIdRef.current.get(flowId);
525
- if (canWriteFlowHandle) {
526
- flowHandleIdsByFlowIdRef.current.set(flowId, flowHandleId);
527
- }
495
+ writeSettledProviderFlowHandleId(flowHandleCacheRef.current, {
496
+ command: pendingCommand.result.envelope.command,
497
+ flowCommandSequence: pendingCommand.flowCommandSequence,
498
+ flowHandleCacheEpoch: pendingCommand.flowHandleCacheEpoch,
499
+ settlementResult: settlement.result,
500
+ });
528
501
  if (pendingCommand.result.envelope.command.kind === "reset") {
529
- flowHandleCacheEpochRef.current += 1;
530
- flowHandleIdsByFlowIdRef.current.clear();
502
+ clearProviderFlowHandleCache(flowHandleCacheRef.current);
531
503
  }
532
504
  const settledResult = Object.assign(Object.assign({}, pendingCommand.result), { settlement, settlementResult: settlement.result });
533
505
  pendingCommand.resolve(settledResult);
@@ -582,7 +554,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
582
554
  return enqueueCommand({
583
555
  kind: "open",
584
556
  flowId: normalizedFlowId,
585
- flowHandleId: flowHandleIdsByFlowIdRef.current.get(normalizedFlowId),
557
+ flowHandleId: getCachedProviderFlowHandleId(flowHandleCacheRef.current, normalizedFlowId),
586
558
  hideCloseButton: options === null || options === void 0 ? void 0 : options.hideCloseButton,
587
559
  }, commandOptions);
588
560
  },
@@ -591,7 +563,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
591
563
  return enqueueCommand({
592
564
  kind: "prefetch",
593
565
  flowId: normalizedFlowId,
594
- flowHandleId: flowHandleIdsByFlowIdRef.current.get(normalizedFlowId),
566
+ flowHandleId: getCachedProviderFlowHandleId(flowHandleCacheRef.current, normalizedFlowId),
595
567
  }, options);
596
568
  },
597
569
  prerender: (flowId, options, commandOptions) => {
@@ -599,7 +571,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
599
571
  return enqueueCommand({
600
572
  kind: "prerender",
601
573
  flowId: normalizedFlowId,
602
- flowHandleId: flowHandleIdsByFlowIdRef.current.get(normalizedFlowId),
574
+ flowHandleId: getCachedProviderFlowHandleId(flowHandleCacheRef.current, normalizedFlowId),
603
575
  hideCloseButton: options === null || options === void 0 ? void 0 : options.hideCloseButton,
604
576
  }, commandOptions);
605
577
  },
@@ -0,0 +1,24 @@
1
+ import type { WebViewCommandEnvelope } from "@getuserfeedback/protocol/webview-transport";
2
+ type ReactNativeWidgetCommand = WebViewCommandEnvelope["command"];
3
+ export type ProviderFlowCommandSnapshot = {
4
+ flowCommandSequence: number | null;
5
+ flowHandleCacheEpoch: number;
6
+ };
7
+ export type ProviderFlowHandleCache = {
8
+ epoch: number;
9
+ flowCommandSequencesByFlowId: Map<string, number>;
10
+ flowHandleIdsByFlowId: Map<string, string>;
11
+ };
12
+ export declare function createProviderFlowHandleCache(): ProviderFlowHandleCache;
13
+ export declare function clearProviderFlowHandleCache(cache: ProviderFlowHandleCache): void;
14
+ export declare function deleteCachedProviderFlowHandleId(cache: ProviderFlowHandleCache, flowHandleId: string): void;
15
+ export declare function deleteCachedProviderFlowId(cache: ProviderFlowHandleCache, flowId: string): void;
16
+ export declare function getCachedProviderFlowHandleId(cache: ProviderFlowHandleCache, flowId: string): string | undefined;
17
+ export declare function snapshotProviderFlowCommand(cache: ProviderFlowHandleCache, command: ReactNativeWidgetCommand): ProviderFlowCommandSnapshot;
18
+ export declare function writeSettledProviderFlowHandleId(cache: ProviderFlowHandleCache, { command, flowCommandSequence, flowHandleCacheEpoch, settlementResult, }: {
19
+ command: ReactNativeWidgetCommand;
20
+ flowCommandSequence: number | null;
21
+ flowHandleCacheEpoch: number;
22
+ settlementResult: unknown;
23
+ }): boolean;
24
+ export {};
@@ -0,0 +1,53 @@
1
+ import { toCommandFlowId, toSettledFlowHandleId, } from "./provider-command-helpers.js";
2
+ export function createProviderFlowHandleCache() {
3
+ return {
4
+ epoch: 0,
5
+ flowCommandSequencesByFlowId: new Map(),
6
+ flowHandleIdsByFlowId: new Map(),
7
+ };
8
+ }
9
+ export function clearProviderFlowHandleCache(cache) {
10
+ cache.epoch += 1;
11
+ cache.flowHandleIdsByFlowId.clear();
12
+ }
13
+ export function deleteCachedProviderFlowHandleId(cache, flowHandleId) {
14
+ for (const [flowId, cachedFlowHandleId] of cache.flowHandleIdsByFlowId) {
15
+ if (cachedFlowHandleId === flowHandleId) {
16
+ cache.flowHandleIdsByFlowId.delete(flowId);
17
+ }
18
+ }
19
+ cache.epoch += 1;
20
+ }
21
+ export function deleteCachedProviderFlowId(cache, flowId) {
22
+ cache.flowHandleIdsByFlowId.delete(flowId);
23
+ }
24
+ export function getCachedProviderFlowHandleId(cache, flowId) {
25
+ return cache.flowHandleIdsByFlowId.get(flowId);
26
+ }
27
+ export function snapshotProviderFlowCommand(cache, command) {
28
+ var _a;
29
+ const flowId = toCommandFlowId(command);
30
+ const flowCommandSequence = flowId === undefined
31
+ ? null
32
+ : ((_a = cache.flowCommandSequencesByFlowId.get(flowId)) !== null && _a !== void 0 ? _a : 0) + 1;
33
+ if (flowId !== undefined && flowCommandSequence !== null) {
34
+ cache.flowCommandSequencesByFlowId.set(flowId, flowCommandSequence);
35
+ }
36
+ return {
37
+ flowCommandSequence,
38
+ flowHandleCacheEpoch: cache.epoch,
39
+ };
40
+ }
41
+ export function writeSettledProviderFlowHandleId(cache, { command, flowCommandSequence, flowHandleCacheEpoch, settlementResult, }) {
42
+ const flowId = toCommandFlowId(command);
43
+ const flowHandleId = toSettledFlowHandleId(settlementResult);
44
+ const canWriteFlowHandle = flowId &&
45
+ flowHandleId &&
46
+ flowHandleCacheEpoch === cache.epoch &&
47
+ flowCommandSequence === cache.flowCommandSequencesByFlowId.get(flowId);
48
+ if (!canWriteFlowHandle) {
49
+ return false;
50
+ }
51
+ cache.flowHandleIdsByFlowId.set(flowId, flowHandleId);
52
+ return true;
53
+ }
@@ -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
+ }
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.5";
6
+ export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "1.3.7";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/react-native",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "description": "getuserfeedback React Native SDK",
5
5
  "keywords": [
6
6
  "getuserfeedback",