@getuserfeedback/react-native 3.0.79 → 3.0.81

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.
@@ -0,0 +1,9 @@
1
+ import type { NativeDirectCommandSession } from "./native-direct-command-session.js";
2
+ export type NativeDirectCommandSessionController = {
3
+ attach: (session: NativeDirectCommandSession) => void;
4
+ detach: (session: NativeDirectCommandSession) => void;
5
+ dispose: (error: Error) => void;
6
+ rejectUntilAttached: (error: Error) => void;
7
+ session: NativeDirectCommandSession;
8
+ };
9
+ export declare function createNativeDirectCommandSessionController(): NativeDirectCommandSessionController;
@@ -0,0 +1,78 @@
1
+ export function createNativeDirectCommandSessionController() {
2
+ let attachedSession = null;
3
+ let disposed = false;
4
+ let disposalError;
5
+ let pendingCommands = [];
6
+ let unavailableError;
7
+ const dispatchThrough = (session, envelope) => {
8
+ try {
9
+ return Promise.resolve(session.dispatch(envelope));
10
+ }
11
+ catch (error) {
12
+ return Promise.reject(error);
13
+ }
14
+ };
15
+ const session = {
16
+ dispatch: (envelope) => {
17
+ if (disposed) {
18
+ return Promise.reject(disposalError);
19
+ }
20
+ if (attachedSession !== null) {
21
+ return dispatchThrough(attachedSession, envelope);
22
+ }
23
+ if (unavailableError !== undefined) {
24
+ return Promise.reject(unavailableError);
25
+ }
26
+ return new Promise((resolve, reject) => {
27
+ pendingCommands.push({ envelope, reject, resolve });
28
+ });
29
+ },
30
+ };
31
+ const dispose = (error) => {
32
+ if (disposed) {
33
+ return;
34
+ }
35
+ disposed = true;
36
+ disposalError = error;
37
+ attachedSession = null;
38
+ const queuedCommands = pendingCommands;
39
+ pendingCommands = [];
40
+ for (const command of queuedCommands) {
41
+ command.reject(error);
42
+ }
43
+ };
44
+ return {
45
+ attach: (nextSession) => {
46
+ if (disposed) {
47
+ return;
48
+ }
49
+ attachedSession = nextSession;
50
+ unavailableError = undefined;
51
+ const queuedCommands = pendingCommands;
52
+ pendingCommands = [];
53
+ for (const command of queuedCommands) {
54
+ if (disposed) {
55
+ command.reject(disposalError);
56
+ continue;
57
+ }
58
+ void dispatchThrough(nextSession, command.envelope).then(command.resolve, command.reject);
59
+ }
60
+ },
61
+ detach: (sessionToDetach) => {
62
+ if (attachedSession === sessionToDetach) {
63
+ attachedSession = null;
64
+ }
65
+ },
66
+ dispose,
67
+ rejectUntilAttached: (error) => {
68
+ attachedSession = null;
69
+ unavailableError = error;
70
+ const queuedCommands = pendingCommands;
71
+ pendingCommands = [];
72
+ for (const command of queuedCommands) {
73
+ command.reject(error);
74
+ }
75
+ },
76
+ session,
77
+ };
78
+ }
@@ -10,7 +10,7 @@ type NativeFlowAllocationCommand = (Omit<Extract<CoreTranslatablePublicCommandPa
10
10
  }>;
11
11
  /** Public commands accepted by the direct native provider session. */
12
12
  type NativeDirectCommandPayload = Exclude<CoreTranslatablePublicCommandPayload, {
13
- kind: "init" | "open" | "prefetch" | "prerender" | "reset";
13
+ kind: "init" | "open" | "prefetch" | "prerender";
14
14
  }> | NativeFlowAllocationCommand;
15
15
  /** Public command envelope accepted by the direct native provider session. */
16
16
  export type NativeDirectCommandEnvelope = Omit<CommandEnvelopeWithInstanceId, "command"> & {
@@ -1,6 +1,6 @@
1
1
  import { getFlowHandleFromSettlementDetail } from "@getuserfeedback/protocol/host";
2
2
  import { toCoreCommandPayload, } from "@getuserfeedback/protocol/internal/public-core-command";
3
- // TODO(migration): Route reset and the public provider client through this core-ordered direct session.
3
+ // TODO(migration): Route the public provider client through this core-ordered direct session.
4
4
  // [from=native-core-ordered-command-session] [to=native-provider-direct-session] [scope=slice] [principle=core-owned-flow-lifecycle] [priority=high] [impact=high] [risk=high] [epic=runtime-neutral-view-host-orchestration] [epic_order=180]
5
5
  export function createNativeDirectCommandSession(input) {
6
6
  const dispatchToCore = (envelope, command) => {
@@ -13,6 +13,7 @@ export type NativeRuntimeRootProps = {
13
13
  onCommandSessionChange?: (session: NativeCoreCommandSession | null) => void;
14
14
  onError?: (error: Error) => void;
15
15
  onInvalidMessage?: (error: Error, value: unknown) => void;
16
+ onStartupTerminalError?: (error: Error) => void;
16
17
  startupCommandSettlementTimeoutMs?: number;
17
18
  viewWebViewComponent?: NativeViewHostProjectionProps["webViewComponent"];
18
19
  viewWebViewProps?: NativeViewHostProjectionProps["webViewProps"];
@@ -28,12 +29,12 @@ type NativeRuntimeConfigureCommand = Omit<CoreCommandEnvelope, "command"> & {
28
29
  }>;
29
30
  };
30
31
  type NativeRuntimeStartupCommands = readonly [NativeRuntimeInitCommand] | readonly [NativeRuntimeInitCommand, NativeRuntimeConfigureCommand];
31
- type NativeProviderRuntimeProps = Omit<NativeRuntimeRootProps, "onCommandSessionChange" | "startupCommands"> & {
32
+ type NativeProviderRuntimeProps = Omit<NativeRuntimeRootProps, "onCommandSessionChange" | "onStartupTerminalError" | "startupCommands"> & {
32
33
  initialConfigureOptions?: ConfigureOptions;
33
34
  initOptions: InitOptions;
34
35
  instanceId: string;
35
36
  onCommandSessionChange?: (session: NativeDirectCommandSession | null) => void;
36
37
  };
37
- export declare function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewProps, onCommandSessionChange, onError, onInvalidMessage, startupCommandSettlementTimeoutMs, startupCommands, viewWebViewComponent, viewWebViewProps, }: NativeRuntimeRootProps): ReactElement;
38
- export declare function NativeProviderRuntime({ initOptions, initialConfigureOptions, instanceId, onCommandSessionChange, ...runtimeProps }: NativeProviderRuntimeProps): ReactElement;
38
+ export declare function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewProps, onCommandSessionChange, onError, onInvalidMessage, onStartupTerminalError, startupCommandSettlementTimeoutMs, startupCommands, viewWebViewComponent, viewWebViewProps, }: NativeRuntimeRootProps): ReactElement;
39
+ export declare function NativeProviderRuntime({ initOptions, initialConfigureOptions, instanceId, onCommandSessionChange, onError, ...runtimeProps }: NativeProviderRuntimeProps): ReactElement;
39
40
  export {};
@@ -18,6 +18,7 @@ import { createNativeDirectCommandSession, } from "./native-direct-command-sessi
18
18
  import { NativeViewHostProjection, } from "./native-view-host-projection.js";
19
19
  import { createNativeViewRecordController, } from "./native-view-record-controller.js";
20
20
  import { createProviderCommandEnvelope, REACT_NATIVE_CLIENT_META, } from "./provider-command-helpers.js";
21
+ import { useNativeDirectCommandSessionController } from "./use-native-direct-command-session-controller.js";
21
22
  const DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS = 30000;
22
23
  function dispatchStartupCommand(input) {
23
24
  let timeoutId;
@@ -42,7 +43,7 @@ async function dispatchStartupCommands(input) {
42
43
  });
43
44
  }
44
45
  }
45
- export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewProps, onCommandSessionChange, onError, onInvalidMessage, startupCommandSettlementTimeoutMs = DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS, startupCommands, viewWebViewComponent, viewWebViewProps, }) {
46
+ export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewProps, onCommandSessionChange, onError, onInvalidMessage, onStartupTerminalError, startupCommandSettlementTimeoutMs = DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS, startupCommands, viewWebViewComponent, viewWebViewProps, }) {
46
47
  const [coreHostRevision, setCoreHostRevision] = useState(0);
47
48
  const [session, setSession] = useState(null);
48
49
  const sessionRef = useRef(null);
@@ -54,6 +55,8 @@ export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewPr
54
55
  onCommandSessionChangeRef.current = onCommandSessionChange;
55
56
  const onInvalidMessageRef = useRef(onInvalidMessage);
56
57
  onInvalidMessageRef.current = onInvalidMessage;
58
+ const onStartupTerminalErrorRef = useRef(onStartupTerminalError);
59
+ onStartupTerminalErrorRef.current = onStartupTerminalError;
57
60
  const startupCommandsRef = useRef(startupCommands);
58
61
  startupCommandsRef.current = startupCommands;
59
62
  const reportError = useCallback((error) => {
@@ -124,6 +127,7 @@ export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewPr
124
127
  })
125
128
  .then(commitSession)
126
129
  .catch((error) => {
130
+ var _a;
127
131
  if (sessionRef.current !== nextSession) {
128
132
  return;
129
133
  }
@@ -131,11 +135,21 @@ export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewPr
131
135
  commandSessionOwner.dispose();
132
136
  commandChannelOwner.dispose();
133
137
  controller.dispose();
134
- if (!(error instanceof CommandSettlementError) &&
135
- !startupRetryAttemptedRef.current) {
138
+ const shouldRetry = !(error instanceof CommandSettlementError) &&
139
+ !startupRetryAttemptedRef.current;
140
+ if (shouldRetry) {
136
141
  startupRetryAttemptedRef.current = true;
137
142
  setCoreHostRevision((revision) => revision + 1);
138
143
  }
144
+ else {
145
+ startupRetryAttemptedRef.current = false;
146
+ try {
147
+ (_a = onStartupTerminalErrorRef.current) === null || _a === void 0 ? void 0 : _a.call(onStartupTerminalErrorRef, error instanceof Error ? error : new Error(String(error)));
148
+ }
149
+ catch (observerError) {
150
+ reportError(observerError);
151
+ }
152
+ }
139
153
  reportError(error);
140
154
  });
141
155
  return;
@@ -205,11 +219,19 @@ export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewPr
205
219
  }));
206
220
  }
207
221
  export function NativeProviderRuntime(_a) {
208
- var { initOptions, initialConfigureOptions, instanceId, onCommandSessionChange } = _a, runtimeProps = __rest(_a, ["initOptions", "initialConfigureOptions", "instanceId", "onCommandSessionChange"]);
222
+ var { initOptions, initialConfigureOptions, instanceId, onCommandSessionChange, onError } = _a, runtimeProps = __rest(_a, ["initOptions", "initialConfigureOptions", "instanceId", "onCommandSessionChange", "onError"]);
223
+ const directSessionController = useNativeDirectCommandSessionController();
209
224
  const directSessionRef = useRef(null);
225
+ const handleStartupTerminalError = useCallback((error) => {
226
+ directSessionController.rejectUntilAttached(error);
227
+ }, [directSessionController]);
210
228
  const handleCommandSessionChange = useCallback((session) => {
211
229
  var _a;
212
230
  if (session === null) {
231
+ if (directSessionRef.current !== null) {
232
+ directSessionController.detach(directSessionRef.current.directSession);
233
+ directSessionRef.current = null;
234
+ }
213
235
  onCommandSessionChange === null || onCommandSessionChange === void 0 ? void 0 : onCommandSessionChange(null);
214
236
  return;
215
237
  }
@@ -220,9 +242,10 @@ export function NativeProviderRuntime(_a) {
220
242
  coreSession: session,
221
243
  }),
222
244
  };
245
+ directSessionController.attach(directSessionRef.current.directSession);
223
246
  }
224
- onCommandSessionChange === null || onCommandSessionChange === void 0 ? void 0 : onCommandSessionChange(directSessionRef.current.directSession);
225
- }, [onCommandSessionChange]);
247
+ onCommandSessionChange === null || onCommandSessionChange === void 0 ? void 0 : onCommandSessionChange(directSessionController.session);
248
+ }, [directSessionController, onCommandSessionChange]);
226
249
  const startupCommands = useMemo(() => {
227
250
  const initCommand = createProviderCommandEnvelope({
228
251
  clientMeta: REACT_NATIVE_CLIENT_META,
@@ -240,5 +263,5 @@ export function NativeProviderRuntime(_a) {
240
263
  }),
241
264
  ];
242
265
  }, [initialConfigureOptions, initOptions, instanceId]);
243
- return createElement(NativeRuntimeRoot, Object.assign(Object.assign({}, runtimeProps), { onCommandSessionChange: handleCommandSessionChange, startupCommands }));
266
+ return createElement(NativeRuntimeRoot, Object.assign(Object.assign({}, runtimeProps), { onCommandSessionChange: handleCommandSessionChange, onError, onStartupTerminalError: handleStartupTerminalError, startupCommands }));
244
267
  }
@@ -0,0 +1,2 @@
1
+ import { type NativeDirectCommandSessionController } from "./native-direct-command-session-controller.js";
2
+ export declare function useNativeDirectCommandSessionController(): NativeDirectCommandSessionController;
@@ -0,0 +1,21 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { createNativeDirectCommandSessionController, } from "./native-direct-command-session-controller.js";
3
+ export function useNativeDirectCommandSessionController() {
4
+ var _a;
5
+ const controllerRef = useRef(null);
6
+ (_a = controllerRef.current) !== null && _a !== void 0 ? _a : (controllerRef.current = createNativeDirectCommandSessionController());
7
+ const controller = controllerRef.current;
8
+ const lifecycleRevisionRef = useRef(0);
9
+ useEffect(() => {
10
+ lifecycleRevisionRef.current += 1;
11
+ const lifecycleRevision = lifecycleRevisionRef.current;
12
+ return () => {
13
+ queueMicrotask(() => {
14
+ if (lifecycleRevisionRef.current === lifecycleRevision) {
15
+ controller.dispose(new Error("Native provider runtime unmounted"));
16
+ }
17
+ });
18
+ };
19
+ }, [controller]);
20
+ return controller;
21
+ }
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 : "3.0.79";
6
+ export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "3.0.81";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/react-native",
3
- "version": "3.0.79",
3
+ "version": "3.0.81",
4
4
  "description": "getuserfeedback React Native SDK",
5
5
  "keywords": [
6
6
  "getuserfeedback",