@getuserfeedback/react-native 5.15.12 → 5.16.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.
package/dist/client.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { AppEventExternalId, PublicCommandPayload } from "@getuserfeedback/protocol";
2
- import type { ActionRegistration, ActionsConfig, CapabilitiesInput, ConfigureOptions, EventOptions, EventProperties, FlagsInput, GraphOperations, InitOptions, LinksConfig, OpenRequestedCallback } from "@getuserfeedback/sdk";
3
- export type { ActionsConfig, CapabilitiesInput, ConfigureOptions, EventOptions, EventProperties, FlagsInput, GraphEndpointIdentity, GraphOperations, GraphRelationship, GraphRelationshipRef, LinkRequest, LinkRouter, LinksConfig, OpenRequestedCallback, OpenRequestedEvent, TrackOptions, } from "@getuserfeedback/sdk";
2
+ import type { ActionRegistration, ActionsConfig, ConfigureOptions as SdkConfigureOptions, EventOptions, EventProperties, GraphOperations, InitOptions, LinksConfig, OpenRequestedCallback } from "@getuserfeedback/sdk";
3
+ export type { ActionsConfig, EventOptions, EventProperties, GraphEndpointIdentity, GraphOperations, GraphRelationship, GraphRelationshipRef, LinkRequest, LinkRouter, LinksConfig, OpenRequestedCallback, RuntimeProperties, OpenRequestedEvent, TrackOptions, } from "@getuserfeedback/sdk";
4
+ export type ConfigureOptions = Pick<SdkConfigureOptions, "auth" | "consent" | "colorScheme" | "properties">;
4
5
  type IdentifyTraits = Record<string, unknown>;
5
6
  type OpenCommand = Extract<PublicCommandPayload, {
6
7
  kind: "open";
@@ -25,7 +26,7 @@ export type NativeActionRegistration = Extract<ActionRegistration, {
25
26
  kind: "custom";
26
27
  }>;
27
28
  /** React Native provider initialization options. */
28
- export type ClientOptions = Omit<InitOptions, "capabilities" | "clientMeta" | "flags" | "hostActions" | "hostCapabilities" | "runtimeEndpoints"> & {
29
+ export type ClientOptions = Omit<InitOptions, "capabilities" | "clientMeta" | "hostActions" | "hostCapabilities" | "runtimeEndpoints"> & {
29
30
  /** Routes authored HTTP(S) links through the native app. */
30
31
  links?: LinksConfig | undefined;
31
32
  /**
@@ -33,10 +34,6 @@ export type ClientOptions = Omit<InitOptions, "capabilities" | "clientMeta" | "f
33
34
  * configuration; the registration array remains for compatibility.
34
35
  */
35
36
  actions?: ActionsConfig | NativeActionRegistration[] | undefined;
36
- /** Capabilities supported by the current app version. */
37
- capabilities?: CapabilitiesInput | undefined;
38
- /** Feature flag evaluations supplied during initialization. */
39
- flags?: FlagsInput | undefined;
40
37
  /**
41
38
  * @deprecated Omit this option. The provider stamps canonical React Native
42
39
  * client metadata.
@@ -1,4 +1,4 @@
1
- import { CORE_HOST_BOOTSTRAP_GLOBAL_KEY, CORE_HOST_BOOTSTRAP_PROTOCOL_VERSION, CORE_HOST_BOOTSTRAP_READY_EVENT_NAME, CORE_HOST_BOOTSTRAP_REQUIRED_FRAGMENT, } from "@getuserfeedback/protocol/internal/core-host-bootstrap-v3";
1
+ import { CORE_HOST_BOOTSTRAP_GLOBAL_KEY, CORE_HOST_BOOTSTRAP_PROTOCOL_VERSION, CORE_HOST_BOOTSTRAP_READY_EVENT_NAME, CORE_HOST_BOOTSTRAP_REQUIRED_FRAGMENT, } from "@getuserfeedback/protocol/internal/core-host-bootstrap-v4";
2
2
  import { parseWebViewConnectionBridgeMessage, } from "./webview-connection-bridge-message.js";
3
3
  import { buildWebViewConnectionBridgeScript, } from "./webview-connection-bridge-script.js";
4
4
  import { buildWebViewConnectionHostMessageScript, serializeForJavaScript, } from "./webview-connection-host-message-script.js";
@@ -125,6 +125,7 @@ export const createNativeHostActionRpcHandler = (input) => {
125
125
  return;
126
126
  try {
127
127
  postToCore(buildEventFlowActionSucceeded({
128
+ runtimeContext: seed.runtimeContext,
128
129
  event: buildFlowActionSucceededV1({
129
130
  actionInvocationId: execution.invocationId,
130
131
  actionKey: execution.params.definition.key,
@@ -42,6 +42,7 @@ export const createNativeLinkRouterRpcHandler = (input) => {
42
42
  return;
43
43
  try {
44
44
  postToCore(buildEventFlowActionSucceeded({
45
+ runtimeContext: seed.runtimeContext,
45
46
  event: buildFlowActionSucceededV1({
46
47
  actionInvocationId: invocationId,
47
48
  actionKey: definition.key,
@@ -1,10 +1,11 @@
1
1
  import type { EventHandleInvalidated } from "@getuserfeedback/protocol/internal/core-handle-invalidation";
2
- import type { ConfigureOptions } from "@getuserfeedback/sdk";
3
2
  import { type OpenRequestDispatcher } from "@getuserfeedback/sdk/internal/open-request-dispatcher";
3
+ import type { ConfigureOptions } from "./client.js";
4
4
  export declare function createNativeProviderClientController(input: {
5
5
  instanceId: string;
6
6
  onError?: (error: Error) => void;
7
7
  initialColorScheme?: ConfigureOptions["colorScheme"];
8
+ initialProperties?: ConfigureOptions["properties"];
8
9
  }): {
9
10
  client: import("./client.js").Client;
10
11
  directSessionController: import("./native-direct-command-session-controller.js").NativeDirectCommandSessionController;
@@ -7,15 +7,22 @@ export function createNativeProviderClientController(input) {
7
7
  // Presentation belongs to this client, independently of Core acknowledgement.
8
8
  let nativeColorScheme = input.initialColorScheme;
9
9
  const colorSchemeListeners = new Set();
10
- let runtimeConfiguration = {};
10
+ let runtimeConfiguration = input.initialProperties === undefined
11
+ ? {}
12
+ : { properties: input.initialProperties };
11
13
  const updateRuntimeConfiguration = (updates) => {
12
- runtimeConfiguration = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, runtimeConfiguration), (updates.auth === undefined ? {} : { auth: updates.auth })), (updates.capabilities === undefined
13
- ? {}
14
- : { capabilities: updates.capabilities })), (updates.colorScheme === undefined
14
+ runtimeConfiguration = Object.assign(Object.assign(Object.assign(Object.assign({}, runtimeConfiguration), (updates.auth === undefined ? {} : { auth: updates.auth })), (updates.colorScheme === undefined
15
15
  ? {}
16
16
  : { colorScheme: updates.colorScheme })), (updates.consent === undefined ? {} : { consent: updates.consent }));
17
17
  };
18
- const commands = createNativeProviderCommandController(input);
18
+ const commands = createNativeProviderCommandController(Object.assign(Object.assign({}, input), { onHandOff: (command) => {
19
+ if (command.kind === "reset" &&
20
+ runtimeConfiguration.properties !== undefined)
21
+ runtimeConfiguration.properties = {};
22
+ else if (command.kind === "configure" &&
23
+ command.opts.properties !== undefined)
24
+ runtimeConfiguration.properties = command.opts.properties;
25
+ } }));
19
26
  const flows = createNativeProviderFlowRegistry(commands);
20
27
  const session = commands.directSessionController;
21
28
  const openRequestDispatcher = createOpenRequestDispatcher();
@@ -9,6 +9,7 @@ type RunOperation = <T>(run: (dispatch: Dispatch) => Promise<T>, options?: Comma
9
9
  export declare function createNativeProviderCommandController(input: {
10
10
  instanceId: string;
11
11
  onError?: (error: Error) => void;
12
+ onHandOff?: (command: Command) => void;
12
13
  }): {
13
14
  directSessionController: import("./native-direct-command-session-controller.js").NativeDirectCommandSessionController;
14
15
  dispose: () => void;
@@ -26,13 +26,16 @@ export function createNativeProviderCommandController(input) {
26
26
  };
27
27
  const observe = (promise) => promise.catch((error) => Promise.reject(report(error)));
28
28
  const dispatch = (command, idempotencyKey) => {
29
+ var _a;
29
30
  const envelope = createCommandEnvelopeWithInstanceId({
30
31
  clientMeta: REACT_NATIVE_CLIENT_META,
31
32
  command: parsePublicCommand(command),
32
33
  idempotencyKey,
33
34
  instanceId: input.instanceId,
34
35
  });
35
- return directSessionController.session.dispatch(envelope);
36
+ const settlement = directSessionController.session.dispatch(envelope);
37
+ (_a = input.onHandOff) === null || _a === void 0 ? void 0 : _a.call(input, envelope.command);
38
+ return settlement;
36
39
  };
37
40
  const runOperation = (run, options) => {
38
41
  let idempotencyKey;
@@ -1,6 +1,6 @@
1
1
  import { type ComponentType, type ReactElement, type ReactNode } from "react";
2
2
  import type { Client, ClientOptions } from "./client.js";
3
- export type { ActionsConfig, CapabilitiesInput, Client, ClientOptions, ConfigureOptions, EventOptions, EventProperties, FlagsInput, FlowRun, GraphEndpointIdentity, GraphOperations, GraphRelationship, GraphRelationshipRef, LinkRequest, LinkRouter, LinksConfig, NativeActionRegistration, OpenFlowOptions, OpenRequestedCallback, OpenRequestedEvent, PrerenderFlowOptions, TrackOptions, } from "./client.js";
3
+ export type { ActionsConfig, Client, ClientOptions, ConfigureOptions, EventOptions, EventProperties, FlowRun, GraphEndpointIdentity, GraphOperations, GraphRelationship, GraphRelationshipRef, LinkRequest, LinkRouter, LinksConfig, NativeActionRegistration, OpenFlowOptions, OpenRequestedCallback, OpenRequestedEvent, PrerenderFlowOptions, RuntimeProperties, TrackOptions, } from "./client.js";
4
4
  export type { UseFlowContainerReturn } from "./flow-container.js";
5
5
  export { FlowContent, useFlowContainer } from "./flow-container.js";
6
6
  export type { UseFlowOpenOptions, UseFlowOptions, UseFlowReturn, } from "./use-flow.js";
@@ -37,7 +37,6 @@ const toClientOptionsKey = (value) => {
37
37
  .map((key) => `${JSON.stringify(key)}:${toClientOptionsKey(record[key])}`)
38
38
  .join(",")}}`;
39
39
  };
40
- const compareClientOptionsKeys = (left, right) => left < right ? -1 : left > right ? 1 : 0;
41
40
  const haveSameActionRegistrations = (left, right) => left.length === right.length &&
42
41
  left.every((identity, index) => identity === right[index]);
43
42
  const useNativeLinkRouter = (links) => {
@@ -74,40 +73,12 @@ const useNativeActionRegistry = (actions) => {
74
73
  const getHandler = useCallback((definition) => { var _a; return (_a = registryRef.current) === null || _a === void 0 ? void 0 : _a.getHandler(definition); }, []);
75
74
  return { definitions: nextRegistry.listDefinitions(), getHandler };
76
75
  };
77
- const toInitFlags = (flags) => {
78
- if (flags === undefined) {
79
- return undefined;
80
- }
81
- const normalizedFlags = Array.isArray(flags)
82
- ? flags.map((flag) => (Object.assign({}, flag)))
83
- : Object.entries(flags)
84
- .sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey))
85
- .map(([key, value]) => ({ key, value }));
86
- return normalizedFlags.length === 0 ? undefined : normalizedFlags;
87
- };
88
76
  const parseNativeInitOptions = (_a, hostActions) => {
89
- var { actions: _actions, capabilities, flags, links: _links } = _a, clientOptions = __rest(_a, ["actions", "capabilities", "flags", "links"]);
90
- const normalizedFlags = toInitFlags(flags);
91
- const initInput = Object.assign({}, clientOptions);
92
- if (normalizedFlags !== undefined) {
93
- initInput.flags = normalizedFlags;
94
- }
95
- if (hostActions !== undefined && hostActions.length > 0) {
96
- initInput.hostActions = hostActions;
97
- }
98
- if (capabilities !== undefined) {
99
- initInput.hostCapabilities = capabilities.map((capability) => typeof capability === "string" ? { key: capability } : Object.assign({}, capability));
100
- }
101
- const initOptions = parseInitOptions(initInput);
102
- const hostCapabilities = initOptions.hostCapabilities;
103
- const normalizedHostCapabilities = hostCapabilities === null || hostCapabilities === void 0 ? void 0 : hostCapabilities.map((capability) => ({
104
- capability,
105
- key: toClientOptionsKey(capability),
106
- })).sort((left, right) => compareClientOptionsKeys(left.key, right.key)).filter((entry, index, entries) => { var _a; return ((_a = entries[index - 1]) === null || _a === void 0 ? void 0 : _a.key) !== entry.key; }).map(({ capability }) => capability);
107
- return Object.assign(Object.assign({}, initOptions), { hostCapabilities: normalizedHostCapabilities === undefined ||
108
- normalizedHostCapabilities.length === 0
109
- ? undefined
110
- : normalizedHostCapabilities });
77
+ var { actions: _actions, links: _links } = _a, clientOptions = __rest(_a, ["actions", "links"]);
78
+ const opts = Object.assign({}, clientOptions);
79
+ if (hostActions === null || hostActions === void 0 ? void 0 : hostActions.length)
80
+ opts.hostActions = hostActions;
81
+ return parseInitOptions(opts);
111
82
  };
112
83
  export function GetUserFeedbackProvider({ children, clientOptions, instanceId: instanceIdProp, onError, webViewComponent, }) {
113
84
  var _a;
@@ -124,7 +95,7 @@ export function GetUserFeedbackProvider({ children, clientOptions, instanceId: i
124
95
  const actionRegistry = useNativeActionRegistry(clientOptions.actions);
125
96
  const linkRouter = useNativeLinkRouter(clientOptions.links);
126
97
  const normalizedClientOptions = parseNativeInitOptions(clientOptions, actionRegistry.definitions);
127
- const { colorScheme } = normalizedClientOptions, runtimeIdentityOptions = __rest(normalizedClientOptions, ["colorScheme"]);
98
+ const { colorScheme, properties } = normalizedClientOptions, runtimeIdentityOptions = __rest(normalizedClientOptions, ["colorScheme", "properties"]);
128
99
  const clientOptionsKey = toClientOptionsKey(runtimeIdentityOptions);
129
100
  const colorSchemePropKey = toClientOptionsKey(colorScheme);
130
101
  const coreUrl = (_b = (_a = normalizedClientOptions.runtimeEndpoints) === null || _a === void 0 ? void 0 : _a.coreUrl) !== null && _b !== void 0 ? _b : REACT_NATIVE_PINNED_CORE_URL;
@@ -141,7 +112,6 @@ export function GetUserFeedbackProvider({ children, clientOptions, instanceId: i
141
112
  }, []);
142
113
  const clientIdentityKey = toClientOptionsKey({
143
114
  apiKey: normalizedClientOptions.apiKey,
144
- hostCapabilities: normalizedClientOptions.hostCapabilities,
145
115
  });
146
116
  const createControllerOwner = () => ({
147
117
  identityKey: clientIdentityKey,
@@ -150,6 +120,7 @@ export function GetUserFeedbackProvider({ children, clientOptions, instanceId: i
150
120
  instanceId,
151
121
  onError: reportError,
152
122
  initialColorScheme: colorScheme,
123
+ initialProperties: properties,
153
124
  }),
154
125
  });
155
126
  let [controllerOwner, setControllerOwner] = useState(createControllerOwner);
@@ -177,6 +148,14 @@ export function GetUserFeedbackProvider({ children, clientOptions, instanceId: i
177
148
  // The controller reports remote failures; local appearance is retained.
178
149
  });
179
150
  }, [colorScheme, colorSchemePropKey, controller, controllerOwner]);
151
+ useLayoutEffect(() => {
152
+ if (properties === undefined)
153
+ return;
154
+ // Like the web provider, supplied context is reapplied when the provider renders.
155
+ void controller.client.configure({ properties }).catch(() => {
156
+ // Command failures are already reported by the controller.
157
+ });
158
+ });
180
159
  const attachViewProjection = useCallback((nextProjection) => {
181
160
  setProjection(nextProjection);
182
161
  return () => setProjection((current) => current === nextProjection ? null : current);
@@ -5,4 +5,4 @@
5
5
  * docs/specs/2026-08-02-flow-interaction-model.md (Projection protocol and
6
6
  * rollout).
7
7
  */
8
- export declare const REACT_NATIVE_PINNED_CORE_URL: "https://cdn.getuserfeedback.com/widget/core/v6/core.html";
8
+ export declare const REACT_NATIVE_PINNED_CORE_URL: "https://cdn.getuserfeedback.com/widget/core/v7/core.html";
@@ -5,4 +5,4 @@
5
5
  * docs/specs/2026-08-02-flow-interaction-model.md (Projection protocol and
6
6
  * rollout).
7
7
  */
8
- export const REACT_NATIVE_PINNED_CORE_URL = "https://cdn.getuserfeedback.com/widget/core/v6/core.html";
8
+ export const REACT_NATIVE_PINNED_CORE_URL = "https://cdn.getuserfeedback.com/widget/core/v7/core.html";
@@ -10,7 +10,7 @@ import { type NativeCoreCommandSession } from "./native-core-command-session.js"
10
10
  import { type NativeDirectCommandSession } from "./native-direct-command-session.js";
11
11
  import type { NativeDirectCommandSessionController } from "./native-direct-command-session-controller.js";
12
12
  import { type NativeViewHostProjectionProps, type NativeViewProjection } from "./native-view-host-projection.js";
13
- export type NativeRuntimeRootProps = {
13
+ type NativeRuntimeRootProps = {
14
14
  coreUrl: string;
15
15
  coreWebViewComponent?: CoreWebViewHostProps["webViewComponent"];
16
16
  createStartupCommand?: () => NativeRuntimeInitCommand;
@@ -1,6 +1,6 @@
1
1
  import { type ComponentType, type ReactElement } from "react";
2
2
  import type { NativeViewPresentationMode } from "./native-view-presentation-surface.js";
3
- import type { NativeViewRecord, NativeViewRecordController } from "./native-view-record-controller.js";
3
+ import type { NativeViewRecordController } from "./native-view-record-controller.js";
4
4
  export type NativeViewHostProjectionProps = {
5
5
  controller: NativeViewRecordController;
6
6
  onInvalidMessage?: (error: Error, value: unknown) => void;
@@ -11,11 +11,4 @@ export type NativeViewHostProjectionProps = {
11
11
  export type NativeViewProjection = Readonly<Omit<NativeViewHostProjectionProps, "presentationMode"> & {
12
12
  key: number;
13
13
  }>;
14
- export declare function NativeProjectedViewContent({ controller, onInvalidMessage, presentationMode, record, webViewComponent, }: {
15
- controller: NativeViewRecordController;
16
- onInvalidMessage?: (error: Error, value: unknown) => void;
17
- presentationMode?: NativeViewPresentationMode;
18
- record: NativeViewRecord;
19
- webViewComponent?: ComponentType<Record<string, unknown>>;
20
- }): ReactElement;
21
14
  export declare function NativeViewHostProjection({ controller, nativeViewComponent, onInvalidMessage, presentationMode, webViewComponent, }: NativeViewHostProjectionProps): ReactElement;
@@ -2,7 +2,7 @@ import { createElement, Fragment, useCallback, useEffect, useLayoutEffect, useRe
2
2
  import { NativeFlowContent } from "./native-flow-content.js";
3
3
  import { NativeViewPresentationSurface } from "./native-view-presentation-surface.js";
4
4
  import { ViewWebViewHost } from "./view-webview-host.js";
5
- export function NativeProjectedViewContent({ controller, onInvalidMessage, presentationMode, record, webViewComponent, }) {
5
+ function NativeProjectedViewContent({ controller, onInvalidMessage, presentationMode, record, webViewComponent, }) {
6
6
  const detachConnectionRef = useRef(null);
7
7
  const detachConnection = useCallback(() => {
8
8
  const detach = detachConnectionRef.current;
@@ -1,4 +1,4 @@
1
- import { type MutableRefObject } from "react";
1
+ import { type RefObject } from "react";
2
2
  import type { Client, EventProperties } from "./client.js";
3
3
  type ScreenTrackingScreen = {
4
4
  name: string;
@@ -16,7 +16,7 @@ type LastReportedScreen = {
16
16
  export declare const reportScreenOccurrence: (input: {
17
17
  client: Client;
18
18
  observation: ScreenTrackingObservation;
19
- lastReportedRef: MutableRefObject<LastReportedScreen | null>;
19
+ lastReportedRef: RefObject<LastReportedScreen | null>;
20
20
  onError?: ScreenTrackingErrorHandler;
21
21
  }) => void;
22
22
  export declare const useScreenOccurrenceReporter: (onError?: ScreenTrackingErrorHandler) => ((observation: ScreenTrackingObservation) => void);
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.15.12";
6
+ export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "5.16.0";
@@ -17,6 +17,7 @@ const resolveWebViewComponent = () => {
17
17
  }
18
18
  return WebView;
19
19
  };
20
+ // oxlint-disable-next-line anti-slop/no-unknown-returns -- WebView data crosses an untrusted bridge; its parser validates the envelope and preserves nested payloads as unknown.
20
21
  const toMessageData = (value) => {
21
22
  if (typeof value !== "string") {
22
23
  return value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/react-native",
3
- "version": "5.15.12",
3
+ "version": "5.16.0",
4
4
  "description": "getuserfeedback React Native SDK",
5
5
  "keywords": [
6
6
  "getuserfeedback",
@@ -50,12 +50,11 @@
50
50
  "build": "bun scripts/build.ts",
51
51
  "typecheck": "tsc -p tsconfig.json --noEmit --composite false --incremental false && tsc -p tsconfig-scripts.json --noEmit --composite false --incremental false",
52
52
  "test": "bun test --dots",
53
- "test:changed": "bun test --changed=${TEST_CHANGED_BASE:-HEAD} --pass-with-no-tests --dots",
54
- "lint": "biome check ."
53
+ "lint": "oxlint --threads=2 -c ../../oxlint.config.ts ."
55
54
  },
56
55
  "dependencies": {
57
- "@getuserfeedback/protocol": "^6.1.1",
58
- "@getuserfeedback/sdk": "^0.19.12",
56
+ "@getuserfeedback/protocol": "^7.0.0",
57
+ "@getuserfeedback/sdk": "^0.20.0",
59
58
  "robot3": "^1.2.0"
60
59
  },
61
60
  "peerDependencies": {