@getuserfeedback/react-native 5.1.4 → 5.1.6

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.
@@ -1,10 +1,12 @@
1
1
  import type { EventHandleInvalidated } from "@getuserfeedback/protocol/internal/core-handle-invalidation";
2
+ import type { ConfigureOptions } from "@getuserfeedback/sdk";
2
3
  export declare function createNativeProviderClientController(input: {
3
4
  instanceId: string;
4
5
  onError?: (error: Error) => void;
5
6
  }): {
6
7
  client: import("./client.js").Client;
7
8
  directSessionController: import("./native-direct-command-session-controller.js").NativeDirectCommandSessionController;
9
+ getRuntimeConfiguration: () => ConfigureOptions;
8
10
  dispose: () => void;
9
11
  onHandleInvalidated: (message: EventHandleInvalidated) => void;
10
12
  onSessionEnded: () => void;
@@ -1,18 +1,39 @@
1
+ import { parsePublicCommand } from "@getuserfeedback/protocol";
1
2
  import { createNativeProviderClient, parseRequiredString, } from "./native-provider-client.js";
2
3
  import { createNativeProviderCommandController } from "./native-provider-command-controller.js";
3
4
  import { createNativeProviderFlowRegistry } from "./native-provider-flow-registry.js";
4
5
  export function createNativeProviderClientController(input) {
6
+ let runtimeConfiguration = {};
7
+ const updateRuntimeConfiguration = (updates) => {
8
+ runtimeConfiguration = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, runtimeConfiguration), (updates.auth === undefined ? {} : { auth: updates.auth })), (updates.capabilities === undefined
9
+ ? {}
10
+ : { capabilities: updates.capabilities })), (updates.colorScheme === undefined
11
+ ? {}
12
+ : { colorScheme: updates.colorScheme })), (updates.consent === undefined ? {} : { consent: updates.consent }));
13
+ };
5
14
  const commands = createNativeProviderCommandController(input);
6
15
  const flows = createNativeProviderFlowRegistry(commands);
7
16
  const session = commands.directSessionController;
8
17
  const client = createNativeProviderClient({
9
- dispatchCommand: (command, options) => {
18
+ dispatchCommand: async (command, options) => {
10
19
  if (command.kind === "close" || command.kind === "reset") {
11
- return commands.runBarrier(command.kind, flows.reset, options);
20
+ await commands.runBarrier(command.kind, flows.reset, options);
21
+ if (command.kind === "reset") {
22
+ updateRuntimeConfiguration({ auth: { jwt: null } });
23
+ }
24
+ return;
25
+ }
26
+ let canonicalCommand;
27
+ try {
28
+ canonicalCommand = parsePublicCommand(command);
29
+ }
30
+ catch (error) {
31
+ return commands.reject(error);
32
+ }
33
+ const settlement = await commands.runOperation((dispatch) => dispatch(canonicalCommand), options);
34
+ if (canonicalCommand.kind === "configure" && settlement !== undefined) {
35
+ updateRuntimeConfiguration(canonicalCommand.opts);
12
36
  }
13
- return commands
14
- .runOperation((dispatch) => dispatch(command), options)
15
- .then(() => undefined);
16
37
  },
17
38
  flow: (flowId) => flows.flow(parseRequiredString("flowId", flowId)),
18
39
  instanceId: input.instanceId,
@@ -20,6 +41,7 @@ export function createNativeProviderClientController(input) {
20
41
  return {
21
42
  client,
22
43
  directSessionController: session,
44
+ getRuntimeConfiguration: () => (Object.assign({}, runtimeConfiguration)),
23
45
  dispose: () => {
24
46
  flows.reset();
25
47
  commands.dispose();
@@ -78,14 +78,18 @@ export function GetUserFeedbackProvider({ children, clientOptions, instanceId: i
78
78
  // Error observers cannot change runtime cleanup or command settlement.
79
79
  }
80
80
  }, []);
81
- const controllerRef = useRef(null);
82
- if (controllerRef.current === null) {
83
- controllerRef.current = createNativeProviderClientController({
81
+ const clientIdentityKey = toClientOptionsKey({
82
+ apiKey: normalizedClientOptions.apiKey,
83
+ hostCapabilities: normalizedClientOptions.hostCapabilities,
84
+ });
85
+ const controllerOwner = useMemo(() => ({
86
+ identityKey: clientIdentityKey,
87
+ controller: createNativeProviderClientController({
84
88
  instanceId,
85
89
  onError: reportError,
86
- });
87
- }
88
- const controller = controllerRef.current;
90
+ }),
91
+ }), [clientIdentityKey, instanceId, reportError]);
92
+ const controller = controllerOwner.controller;
89
93
  const attachViewProjection = useCallback((nextProjection) => {
90
94
  setProjection(nextProjection);
91
95
  return () => setProjection((current) => current === nextProjection ? null : current);
@@ -109,13 +113,15 @@ export function GetUserFeedbackProvider({ children, clientOptions, instanceId: i
109
113
  projection,
110
114
  registerContent,
111
115
  }), [contentOwner, controller.client, projection, registerContent]);
112
- const lifecycleRevisionRef = useRef(0);
116
+ const controllerLifecycleTokensRef = useRef(new WeakMap());
113
117
  useEffect(() => {
114
- lifecycleRevisionRef.current += 1;
115
- const lifecycleRevision = lifecycleRevisionRef.current;
118
+ const lifecycleToken = {};
119
+ controllerLifecycleTokensRef.current.set(controller, lifecycleToken);
116
120
  return () => {
117
121
  queueMicrotask(() => {
118
- if (lifecycleRevisionRef.current === lifecycleRevision) {
122
+ if (controllerLifecycleTokensRef.current.get(controller) ===
123
+ lifecycleToken) {
124
+ controllerLifecycleTokensRef.current.delete(controller);
119
125
  controller.dispose();
120
126
  }
121
127
  });
@@ -126,6 +132,7 @@ export function GetUserFeedbackProvider({ children, clientOptions, instanceId: i
126
132
  controller.onSessionEnded();
127
133
  }
128
134
  }, [controller]);
135
+ const getRuntimeConfiguration = useCallback(() => controller.getRuntimeConfiguration(), [controller]);
129
136
  const handleHandleInvalidated = useCallback((message) => controller.onHandleInvalidated(message), [controller]);
130
137
  return createElement(GetUserFeedbackContext.Provider, { value: controller.client }, createElement(NativeFlowContainerContext.Provider, { value: flowContainerContext }, createElement(Fragment, null, children, createElement(NativeStandardFlowContainer), createElement(NativeProviderRuntime, {
131
138
  attachViewProjection,
@@ -135,6 +142,7 @@ export function GetUserFeedbackProvider({ children, clientOptions, instanceId: i
135
142
  initOptions: normalizedClientOptions,
136
143
  instanceId,
137
144
  key: clientOptionsKey,
145
+ getRuntimeConfiguration,
138
146
  onCommandSessionChange: handleCommandSessionChange,
139
147
  onError: reportError,
140
148
  onHandleInvalidated: handleHandleInvalidated,
@@ -1,6 +1,6 @@
1
1
  import type { CoreCommandEnvelope } from "@getuserfeedback/protocol";
2
2
  import type { EventHandleInvalidated } from "@getuserfeedback/protocol/internal/core-handle-invalidation";
3
- import type { InitOptions } from "@getuserfeedback/sdk";
3
+ import type { ConfigureOptions, InitOptions } from "@getuserfeedback/sdk";
4
4
  import { type ReactElement } from "react";
5
5
  import { type CoreWebViewHostProps } from "./core-webview-host.js";
6
6
  import { type NativeCoreCommandSession } from "./native-core-command-session.js";
@@ -10,7 +10,7 @@ import { type NativeViewHostProjectionProps, type NativeViewProjection } from ".
10
10
  export type NativeRuntimeRootProps = {
11
11
  coreUrl: string;
12
12
  coreWebViewComponent?: CoreWebViewHostProps["webViewComponent"];
13
- startupCommand?: NativeRuntimeInitCommand;
13
+ createStartupCommand?: () => NativeRuntimeInitCommand;
14
14
  onCommandSessionChange?: (session: NativeCoreCommandSession | null) => void;
15
15
  onError?: (error: Error) => void;
16
16
  onHandleInvalidated?: (message: EventHandleInvalidated) => void;
@@ -26,13 +26,14 @@ type NativeRuntimeInitCommand = Omit<CoreCommandEnvelope, "command"> & {
26
26
  kind: "init";
27
27
  }>;
28
28
  };
29
- type NativeProviderRuntimeProps = Omit<NativeRuntimeRootProps, "onCommandSessionChange" | "onStartupTerminalError" | "startupCommand"> & {
29
+ type NativeProviderRuntimeProps = Omit<NativeRuntimeRootProps, "createStartupCommand" | "onCommandSessionChange" | "onStartupTerminalError"> & {
30
30
  /** Stable, exclusive controller retained and disposed by the component that owns this runtime's mounted lifetime. */
31
31
  directSessionController: NativeDirectCommandSessionController;
32
32
  initOptions: InitOptions;
33
33
  instanceId: string;
34
+ getRuntimeConfiguration?: () => ConfigureOptions;
34
35
  onCommandSessionChange?: (session: NativeDirectCommandSession | null) => void;
35
36
  };
36
- export declare function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewComponent, onCommandSessionChange, onError, onHandleInvalidated, onInvalidMessage, onStartupTerminalError, startupCommandSettlementTimeoutMs, startupCommand, viewNativeViewComponent, viewWebViewComponent, }: NativeRuntimeRootProps): ReactElement;
37
- export declare function NativeProviderRuntime({ directSessionController, initOptions, instanceId, onCommandSessionChange, onError, ...runtimeProps }: NativeProviderRuntimeProps): ReactElement;
37
+ export declare function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewComponent, createStartupCommand, onCommandSessionChange, onError, onHandleInvalidated, onInvalidMessage, onStartupTerminalError, startupCommandSettlementTimeoutMs, viewNativeViewComponent, viewWebViewComponent, }: NativeRuntimeRootProps): ReactElement;
38
+ export declare function NativeProviderRuntime({ directSessionController, getRuntimeConfiguration, initOptions, instanceId, onCommandSessionChange, onError, ...runtimeProps }: NativeProviderRuntimeProps): ReactElement;
38
39
  export {};
@@ -10,7 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
10
10
  return t;
11
11
  };
12
12
  import { CommandSettlementError, CommandSettlementTimeoutError, } from "@getuserfeedback/protocol/host";
13
- import { createElement, Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
13
+ import { createElement, Fragment, useCallback, useEffect, useLayoutEffect, useRef, useState, } from "react";
14
14
  import { CoreWebViewHost, } from "./core-webview-host.js";
15
15
  import { createNativeCoreCommandChannel } from "./native-core-command-channel.js";
16
16
  import { createNativeCoreCommandSession, } from "./native-core-command-session.js";
@@ -19,7 +19,8 @@ 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
21
  const DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS = 30000;
22
- export function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewComponent, onCommandSessionChange, onError, onHandleInvalidated, onInvalidMessage, onStartupTerminalError, startupCommandSettlementTimeoutMs = DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS, startupCommand, viewNativeViewComponent, viewWebViewComponent, }) {
22
+ const getEmptyRuntimeConfiguration = () => ({});
23
+ export function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewComponent, createStartupCommand, onCommandSessionChange, onError, onHandleInvalidated, onInvalidMessage, onStartupTerminalError, startupCommandSettlementTimeoutMs = DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS, viewNativeViewComponent, viewWebViewComponent, }) {
23
24
  const [coreHostRevision, setCoreHostRevision] = useState(0);
24
25
  const [session, setSession] = useState(null);
25
26
  const sessionRef = useRef(null);
@@ -35,8 +36,8 @@ export function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewCo
35
36
  onInvalidMessageRef.current = onInvalidMessage;
36
37
  const onStartupTerminalErrorRef = useRef(onStartupTerminalError);
37
38
  onStartupTerminalErrorRef.current = onStartupTerminalError;
38
- const startupCommandRef = useRef(startupCommand);
39
- startupCommandRef.current = startupCommand;
39
+ const createStartupCommandRef = useRef(createStartupCommand);
40
+ createStartupCommandRef.current = createStartupCommand;
40
41
  const reportError = useCallback((error) => {
41
42
  var _a;
42
43
  try {
@@ -65,6 +66,7 @@ export function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewCo
65
66
  reportError(error);
66
67
  }, [reportError]);
67
68
  const handleConnected = useCallback((coreConnection) => {
69
+ var _a;
68
70
  const previousSession = sessionRef.current;
69
71
  if (previousSession) {
70
72
  sessionRef.current = null;
@@ -119,7 +121,7 @@ export function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewCo
119
121
  setSession(nextSession);
120
122
  notifyCommandSessionObserver(nextSession.commandSessionObserver, commandSessionOwner.session);
121
123
  };
122
- const startupCommand = startupCommandRef.current;
124
+ const startupCommand = (_a = createStartupCommandRef.current) === null || _a === void 0 ? void 0 : _a.call(createStartupCommandRef);
123
125
  if (startupCommand) {
124
126
  // TODO(architecture): Reconcile direct-runtime startup command settlement
125
127
  // with view projection. Android smoke can project the opened view while the
@@ -238,7 +240,7 @@ export function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewCo
238
240
  }));
239
241
  }
240
242
  export function NativeProviderRuntime(_a) {
241
- var { directSessionController, initOptions, instanceId, onCommandSessionChange, onError } = _a, runtimeProps = __rest(_a, ["directSessionController", "initOptions", "instanceId", "onCommandSessionChange", "onError"]);
243
+ var { directSessionController, getRuntimeConfiguration = getEmptyRuntimeConfiguration, initOptions, instanceId, onCommandSessionChange, onError } = _a, runtimeProps = __rest(_a, ["directSessionController", "getRuntimeConfiguration", "initOptions", "instanceId", "onCommandSessionChange", "onError"]);
242
244
  const directSessionRef = useRef(null);
243
245
  useLayoutEffect(() => {
244
246
  directSessionController.beginAttachmentAttempt();
@@ -267,12 +269,15 @@ export function NativeProviderRuntime(_a) {
267
269
  }
268
270
  onCommandSessionChange === null || onCommandSessionChange === void 0 ? void 0 : onCommandSessionChange(directSessionController.session);
269
271
  }, [directSessionController, onCommandSessionChange]);
270
- const startupCommand = useMemo(() => {
272
+ const createStartupCommand = useCallback(() => {
271
273
  return createProviderCommandEnvelope({
272
274
  clientMeta: REACT_NATIVE_CLIENT_META,
273
- command: { kind: "init", opts: initOptions },
275
+ command: {
276
+ kind: "init",
277
+ opts: Object.assign(Object.assign({}, initOptions), { runtimeConfiguration: getRuntimeConfiguration() }),
278
+ },
274
279
  instanceId,
275
280
  });
276
- }, [initOptions, instanceId]);
277
- return createElement(NativeRuntimeRoot, Object.assign(Object.assign({}, runtimeProps), { onCommandSessionChange: handleCommandSessionChange, onError, onStartupTerminalError: handleStartupTerminalError, startupCommand }));
281
+ }, [getRuntimeConfiguration, initOptions, instanceId]);
282
+ return createElement(NativeRuntimeRoot, Object.assign(Object.assign({}, runtimeProps), { onCommandSessionChange: handleCommandSessionChange, onError, onStartupTerminalError: handleStartupTerminalError, createStartupCommand }));
278
283
  }
@@ -1,29 +1,16 @@
1
- import type { ClientMeta } from "@getuserfeedback/protocol";
2
- import type { WebViewCommandEnvelope } from "@getuserfeedback/protocol/webview-transport";
3
- type ReactNativeWidgetCommand = WebViewCommandEnvelope["command"];
4
- type ReactNativeInitCommand = Extract<ReactNativeWidgetCommand, {
1
+ import type { ClientMeta, CoreCommandEnvelope } from "@getuserfeedback/protocol";
2
+ export type ReactNativeInitCommand = Extract<CoreCommandEnvelope["command"], {
5
3
  kind: "init";
6
4
  }>;
7
- type ReactNativeConfigureCommand = Extract<ReactNativeWidgetCommand, {
8
- kind: "configure";
9
- }>;
10
5
  export declare const REACT_NATIVE_CLIENT_META: ClientMeta;
11
6
  type CreateProviderCommandEnvelopeInput = {
12
7
  clientMeta?: ClientMeta;
13
- command: ReactNativeWidgetCommand;
8
+ command: ReactNativeInitCommand;
14
9
  idempotencyKey?: string;
15
10
  instanceId: string;
16
11
  requestId?: string;
17
12
  };
18
- export declare function createProviderCommandEnvelope(input: CreateProviderCommandEnvelopeInput & {
13
+ export declare function createProviderCommandEnvelope(input: CreateProviderCommandEnvelopeInput): Omit<CoreCommandEnvelope, "command"> & {
19
14
  command: ReactNativeInitCommand;
20
- }): Omit<WebViewCommandEnvelope, "command"> & {
21
- command: ReactNativeInitCommand;
22
- };
23
- export declare function createProviderCommandEnvelope(input: CreateProviderCommandEnvelopeInput & {
24
- command: ReactNativeConfigureCommand;
25
- }): Omit<WebViewCommandEnvelope, "command"> & {
26
- command: ReactNativeConfigureCommand;
27
15
  };
28
- export declare function createProviderCommandEnvelope(input: CreateProviderCommandEnvelopeInput): WebViewCommandEnvelope;
29
16
  export {};
@@ -1,4 +1,4 @@
1
- import { createCommandEnvelopeWithInstanceId, REACT_NATIVE_WEBVIEW_TRANSPORT_CAPABILITIES, } from "@getuserfeedback/protocol/host";
1
+ import { createCommandRequestId, REACT_NATIVE_WEBVIEW_TRANSPORT_CAPABILITIES, } from "@getuserfeedback/protocol/host";
2
2
  import { REACT_NATIVE_SDK_VERSION } from "./version.js";
3
3
  export const REACT_NATIVE_CLIENT_META = {
4
4
  clientName: "@getuserfeedback/react-native",
@@ -10,13 +10,13 @@ export const REACT_NATIVE_CLIENT_META = {
10
10
  ],
11
11
  };
12
12
  export function createProviderCommandEnvelope({ clientMeta, command, idempotencyKey, instanceId, requestId, }) {
13
- const resolvedCommand = command.kind === "init" && clientMeta !== undefined
13
+ const resolvedInstanceId = instanceId.trim();
14
+ if (!resolvedInstanceId) {
15
+ throw new Error("instanceId must be a non-empty string");
16
+ }
17
+ const resolvedRequestId = (requestId === null || requestId === void 0 ? void 0 : requestId.trim()) || createCommandRequestId();
18
+ const resolvedIdempotencyKey = (idempotencyKey === null || idempotencyKey === void 0 ? void 0 : idempotencyKey.trim()) || resolvedRequestId;
19
+ const resolvedCommand = clientMeta !== undefined
14
20
  ? Object.assign(Object.assign({}, command), { opts: Object.assign(Object.assign({}, command.opts), { clientMeta }) }) : command;
15
- return createCommandEnvelopeWithInstanceId({
16
- clientMeta,
17
- command: resolvedCommand,
18
- idempotencyKey,
19
- instanceId,
20
- requestId,
21
- });
21
+ return Object.assign({ version: "1", command: resolvedCommand, idempotencyKey: resolvedIdempotencyKey, instanceId: resolvedInstanceId, requestId: resolvedRequestId }, (clientMeta === undefined ? {} : { clientMeta }));
22
22
  }
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 : "5.1.4";
6
+ export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "5.1.6";
@@ -198,7 +198,7 @@ function createViewPreparationReadinessRegistry2() {
198
198
  return createViewPreparationReadinessRegistry();
199
199
  }
200
200
  export {
201
- createViewPreparationRegistry2 as createViewPreparationRegistry,
201
+ createPendingCommandTracker,
202
202
  createViewPreparationReadinessRegistry2 as createViewPreparationReadinessRegistry,
203
- createPendingCommandTracker
203
+ createViewPreparationRegistry2 as createViewPreparationRegistry
204
204
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/react-native",
3
- "version": "5.1.4",
3
+ "version": "5.1.6",
4
4
  "description": "getuserfeedback React Native SDK",
5
5
  "keywords": [
6
6
  "getuserfeedback",
@@ -44,8 +44,8 @@
44
44
  "lint": "biome check ."
45
45
  },
46
46
  "dependencies": {
47
- "@getuserfeedback/protocol": "^4.0.0",
48
- "@getuserfeedback/sdk": "^0.13.4",
47
+ "@getuserfeedback/protocol": "^5.0.0",
48
+ "@getuserfeedback/sdk": "^0.13.5",
49
49
  "robot3": "^1.2.0"
50
50
  },
51
51
  "peerDependencies": {