@getuserfeedback/react-native 5.4.0 → 5.5.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,5 +1,5 @@
1
1
  import type { AppEventExternalId, PublicCommandPayload } from "@getuserfeedback/protocol";
2
- import type { CapabilitiesInput, ConfigureOptions, EventOptions, EventProperties, GraphOperations, InitOptions, OpenRequestedCallback } from "@getuserfeedback/sdk";
2
+ import type { ActionRegistration, CapabilitiesInput, ConfigureOptions, EventOptions, EventProperties, GraphOperations, InitOptions, OpenRequestedCallback } from "@getuserfeedback/sdk";
3
3
  export type { EventOptions, EventProperties, OpenRequestedCallback, OpenRequestedEvent, TrackOptions, } from "@getuserfeedback/sdk";
4
4
  type IdentifyTraits = Record<string, unknown>;
5
5
  type OpenCommand = Extract<PublicCommandPayload, {
@@ -19,8 +19,14 @@ type HostContext = Extract<PublicCommandPayload, {
19
19
  type CommandOptions = {
20
20
  idempotencyKey?: string;
21
21
  };
22
+ /** A customer-defined action implemented by the React Native host app. */
23
+ export type NativeActionRegistration = Extract<ActionRegistration, {
24
+ kind: "custom";
25
+ }>;
22
26
  /** React Native provider initialization options. */
23
- export type ClientOptions = Omit<InitOptions, "capabilities" | "hostCapabilities"> & {
27
+ export type ClientOptions = Omit<InitOptions, "capabilities" | "hostActions" | "hostCapabilities"> & {
28
+ /** Widget actions implemented by the current app version. */
29
+ actions?: NativeActionRegistration[] | undefined;
24
30
  /** Capabilities supported by the current app version. */
25
31
  capabilities?: CapabilitiesInput | undefined;
26
32
  };
@@ -2,6 +2,7 @@ import { type CoreCommandEnvelope } from "@getuserfeedback/protocol";
2
2
  import { type EventHandleInvalidated } from "@getuserfeedback/protocol/internal/core-handle-invalidation";
3
3
  import { type EventCommandSettled } from "@getuserfeedback/protocol/internal/core-host-command-settlement";
4
4
  import type { CoreWebViewHostConnection } from "./core-webview-host-controller.js";
5
+ import { createNativeHostActionRpcHandler } from "./native-host-action-rpc.js";
5
6
  export type NativeCoreCommandChannel = {
6
7
  post: (envelope: CoreCommandEnvelope) => void;
7
8
  subscribe: (listener: (message: EventCommandSettled) => void) => () => void;
@@ -12,7 +13,14 @@ type OwnedNativeCoreCommandChannel = {
12
13
  };
13
14
  export declare function createNativeCoreCommandChannel(input: {
14
15
  coreConnection: CoreWebViewHostConnection;
16
+ hostActions?: {
17
+ getHandler: Parameters<typeof createNativeHostActionRpcHandler>[0]["getHandler"];
18
+ getActiveViewIds: () => readonly string[];
19
+ instanceId: string;
20
+ subscribeToViewActivity: (listener: () => void) => () => void;
21
+ };
15
22
  onHandleInvalidated?: (message: EventHandleInvalidated) => void;
23
+ onHostActionError?: (error: Error) => void;
16
24
  onInvalidMessage?: (error: Error, value: unknown) => void;
17
25
  onSessionFailure?: (error: Error) => void;
18
26
  }): OwnedNativeCoreCommandChannel;
@@ -3,11 +3,34 @@ import { eventHandleInvalidatedSchema, } from "@getuserfeedback/protocol/interna
3
3
  import { eventCommandSettledSchema, } from "@getuserfeedback/protocol/internal/core-host-command-settlement";
4
4
  import { CORE_SESSION_FAILED_CODE, eventCoreSessionFailedSchema, } from "@getuserfeedback/protocol/internal/core-session-failure";
5
5
  import { buildRpcResponse, rpcRequestSchema, } from "@getuserfeedback/protocol/internal/v3-rpc-messages";
6
+ import { createNativeHostActionRpcHandler } from "./native-host-action-rpc.js";
6
7
  const DISPOSED_MESSAGE = "Core command channel is disposed";
7
8
  const isRecord = (value) => typeof value === "object" && value !== null;
8
9
  export function createNativeCoreCommandChannel(input) {
10
+ var _a;
9
11
  const listeners = new Set();
10
12
  let disposed = false;
13
+ const hostActions = input.hostActions;
14
+ const hostActionRpcHandler = hostActions
15
+ ? createNativeHostActionRpcHandler({
16
+ generation: input.coreConnection.generation,
17
+ getHandler: hostActions.getHandler,
18
+ instanceId: hostActions.instanceId,
19
+ isViewActive: (viewId) => hostActions.getActiveViewIds().includes(viewId),
20
+ onError: input.onHostActionError,
21
+ postToCore: input.coreConnection.transport.postMessage,
22
+ })
23
+ : null;
24
+ let activeViewIds = new Set((_a = hostActions === null || hostActions === void 0 ? void 0 : hostActions.getActiveViewIds()) !== null && _a !== void 0 ? _a : []);
25
+ const unsubscribeViewActivity = hostActions === null || hostActions === void 0 ? void 0 : hostActions.subscribeToViewActivity(() => {
26
+ const nextActiveViewIds = new Set(hostActions.getActiveViewIds());
27
+ for (const viewId of activeViewIds) {
28
+ if (!nextActiveViewIds.has(viewId)) {
29
+ hostActionRpcHandler === null || hostActionRpcHandler === void 0 ? void 0 : hostActionRpcHandler.releaseView(viewId);
30
+ }
31
+ }
32
+ activeViewIds = nextActiveViewIds;
33
+ });
11
34
  const handleMessage = (value) => {
12
35
  var _a, _b, _c, _d, _e, _f;
13
36
  if (disposed || !isRecord(value)) {
@@ -19,6 +42,9 @@ export function createNativeCoreCommandChannel(input) {
19
42
  parsed.data.gen !== input.coreConnection.generation) {
20
43
  return;
21
44
  }
45
+ if (hostActionRpcHandler === null || hostActionRpcHandler === void 0 ? void 0 : hostActionRpcHandler.handle(parsed.data)) {
46
+ return;
47
+ }
22
48
  let result;
23
49
  if (parsed.data.method === TRAFFIC_TELEMETRY_RPC_METHOD) {
24
50
  const params = trafficTelemetryRpcParamsSchema.safeParse(parsed.data.params);
@@ -133,6 +159,8 @@ export function createNativeCoreCommandChannel(input) {
133
159
  return;
134
160
  }
135
161
  disposed = true;
162
+ unsubscribeViewActivity === null || unsubscribeViewActivity === void 0 ? void 0 : unsubscribeViewActivity();
163
+ hostActionRpcHandler === null || hostActionRpcHandler === void 0 ? void 0 : hostActionRpcHandler.dispose();
136
164
  unsubscribeTransport();
137
165
  listeners.clear();
138
166
  },
@@ -0,0 +1,15 @@
1
+ import type { HostActionDefinition } from "@getuserfeedback/protocol/host";
2
+ import { type RpcRequest } from "@getuserfeedback/protocol/internal/v3-rpc-messages";
3
+ export declare const createNativeHostActionRpcHandler: (input: {
4
+ generation: number;
5
+ getHandler: (definition: HostActionDefinition) => (() => void | Promise<void>) | undefined;
6
+ instanceId: string;
7
+ isViewActive: (viewId: string) => boolean;
8
+ now?: () => number;
9
+ onError?: (error: Error) => void;
10
+ postToCore: (message: unknown) => void;
11
+ }) => {
12
+ dispose: () => void;
13
+ handle: (request: RpcRequest) => boolean;
14
+ releaseView: (viewId: string) => void;
15
+ };
@@ -0,0 +1,180 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { buildFlowActionSucceededV1 } from "@getuserfeedback/protocol";
13
+ import { HOST_ACTION_EXECUTE_RPC_METHOD, HOST_ACTION_SETTLEMENT_AVAILABILITY_RPC_METHOD, toHostActionExecuteParams, } from "@getuserfeedback/protocol/internal/host-action-rpc";
14
+ import { buildEventFlowActionSucceeded } from "@getuserfeedback/protocol/internal/host-core-flow-action-succeeded";
15
+ import { buildRpcResponse, } from "@getuserfeedback/protocol/internal/v3-rpc-messages";
16
+ const isSameExecution = (execution, request, params) => execution.attemptId === request.idemKey &&
17
+ execution.params.viewId === params.viewId &&
18
+ execution.params.generation === params.generation &&
19
+ execution.params.instanceId === params.instanceId &&
20
+ execution.params.definition.key === params.definition.key &&
21
+ execution.params.definition.version === params.definition.version;
22
+ export const createNativeHostActionRpcHandler = (input) => {
23
+ let disposed = false;
24
+ const executions = new Map();
25
+ const reportError = (error) => {
26
+ var _a;
27
+ try {
28
+ (_a = input.onError) === null || _a === void 0 ? void 0 : _a.call(input, error instanceof Error ? error : new Error(String(error)));
29
+ }
30
+ catch (_b) {
31
+ // Diagnostics cannot change host action settlement.
32
+ }
33
+ };
34
+ const postToCore = (message) => {
35
+ try {
36
+ input.postToCore(message);
37
+ }
38
+ catch (error) {
39
+ reportError(error);
40
+ }
41
+ };
42
+ const respond = (request, outcome) => {
43
+ postToCore(buildRpcResponse({
44
+ gen: request.gen,
45
+ ok: true,
46
+ result: outcome
47
+ ? { handled: outcome === "success", outcome }
48
+ : { handled: false },
49
+ rpcId: request.rpcId,
50
+ viewId: request.viewId,
51
+ }));
52
+ };
53
+ return {
54
+ dispose: () => {
55
+ disposed = true;
56
+ for (const execution of executions.values()) {
57
+ execution.active = false;
58
+ execution.waiters.splice(0);
59
+ }
60
+ executions.clear();
61
+ },
62
+ handle: (request) => {
63
+ var _a;
64
+ if (request.method === HOST_ACTION_SETTLEMENT_AVAILABILITY_RPC_METHOD) {
65
+ postToCore(buildRpcResponse({
66
+ gen: request.gen,
67
+ ok: true,
68
+ result: { close: true, link: false, remain: true },
69
+ rpcId: request.rpcId,
70
+ viewId: request.viewId,
71
+ }));
72
+ return true;
73
+ }
74
+ if (request.method !== HOST_ACTION_EXECUTE_RPC_METHOD) {
75
+ return false;
76
+ }
77
+ const parsedParams = toHostActionExecuteParams(request.params);
78
+ const params = parsedParams
79
+ ? Object.assign(Object.assign({}, parsedParams), { invocationId: (_a = parsedParams.invocationId) !== null && _a !== void 0 ? _a : request.idemKey }) : null;
80
+ const existing = params ? executions.get(params.invocationId) : undefined;
81
+ if (params && existing) {
82
+ if (existing.released || !isSameExecution(existing, request, params)) {
83
+ respond(request, null);
84
+ }
85
+ else if (existing.outcome) {
86
+ respond(request, existing.outcome);
87
+ }
88
+ else {
89
+ existing.waiters.push(request);
90
+ }
91
+ return true;
92
+ }
93
+ if (params === null ||
94
+ params.generation !== input.generation ||
95
+ params.instanceId !== input.instanceId ||
96
+ !input.isViewActive(params.viewId)) {
97
+ respond(request, null);
98
+ return true;
99
+ }
100
+ const { invocationId: _invocationId } = params, boundParams = __rest(params, ["invocationId"]);
101
+ const execution = {
102
+ active: true,
103
+ attemptId: request.idemKey,
104
+ hasExplicitInvocationId: typeof (parsedParams === null || parsedParams === void 0 ? void 0 : parsedParams.invocationId) === "string",
105
+ invocationId: params.invocationId,
106
+ outcome: null,
107
+ params: Object.assign(Object.assign({}, boundParams), { definition: Object.assign({}, boundParams.definition) }),
108
+ released: false,
109
+ started: false,
110
+ waiters: [request],
111
+ };
112
+ executions.set(execution.invocationId, execution);
113
+ const settle = (outcome) => {
114
+ var _a;
115
+ if (disposed || !execution.active || execution.outcome)
116
+ return;
117
+ execution.outcome = outcome;
118
+ for (const waiter of execution.waiters.splice(0)) {
119
+ respond(waiter, outcome);
120
+ }
121
+ const seed = execution.params.flowActionSucceededSeed;
122
+ if (outcome !== "success" ||
123
+ seed === undefined ||
124
+ !execution.hasExplicitInvocationId)
125
+ return;
126
+ try {
127
+ postToCore(buildEventFlowActionSucceeded({
128
+ event: buildFlowActionSucceededV1({
129
+ actionInvocationId: execution.invocationId,
130
+ actionKey: execution.params.definition.key,
131
+ actionKind: seed.actionKind,
132
+ actionPlacementId: seed.actionPlacementId,
133
+ actionVersion: execution.params.definition.version,
134
+ flowId: seed.flowId,
135
+ flowRunId: seed.flowRunId,
136
+ flowSurface: "widget",
137
+ flowVersionId: seed.flowVersionId,
138
+ flowVersionNumber: seed.flowVersionNumber,
139
+ }),
140
+ gen: request.gen,
141
+ instanceId: execution.params.instanceId,
142
+ timestamp: ((_a = input.now) !== null && _a !== void 0 ? _a : Date.now)(),
143
+ }));
144
+ }
145
+ catch (error) {
146
+ reportError(error);
147
+ }
148
+ };
149
+ const handler = input.getHandler(params.definition);
150
+ if (handler === undefined) {
151
+ settle("unavailable");
152
+ return true;
153
+ }
154
+ void Promise.resolve()
155
+ .then(() => {
156
+ if (!execution.active || !input.isViewActive(params.viewId))
157
+ return;
158
+ execution.started = true;
159
+ return handler();
160
+ })
161
+ .then(() => {
162
+ if (execution.started)
163
+ settle("success");
164
+ }, () => settle("failure"));
165
+ return true;
166
+ },
167
+ releaseView: (viewId) => {
168
+ for (const [invocationId, execution] of executions) {
169
+ if (execution.params.viewId !== viewId)
170
+ continue;
171
+ execution.released = true;
172
+ execution.waiters.splice(0);
173
+ if (execution.started || execution.outcome !== null)
174
+ continue;
175
+ execution.active = false;
176
+ executions.delete(invocationId);
177
+ }
178
+ },
179
+ };
180
+ };
@@ -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 { Client, ClientOptions, EventOptions, EventProperties, FlowRun, OpenRequestedCallback, OpenRequestedEvent, TrackOptions, } from "./client.js";
3
+ export type { Client, ClientOptions, EventOptions, EventProperties, FlowRun, NativeActionRegistration, OpenRequestedCallback, OpenRequestedEvent, TrackOptions, } from "./client.js";
4
4
  export type { UseFlowContainerReturn } from "./flow-container.js";
5
5
  export { FlowContent, useFlowContainer } from "./flow-container.js";
6
6
  /**
@@ -11,7 +11,8 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  };
12
12
  import { parseInitOptions } from "@getuserfeedback/protocol";
13
13
  import { createUniqueId } from "@getuserfeedback/protocol/host";
14
- import { createContext, createElement, Fragment, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
14
+ import { createActionRegistry, } from "@getuserfeedback/sdk/internal/action-registry";
15
+ import { createContext, createElement, Fragment, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
15
16
  import { NativeStandardFlowContainer } from "./flow-container.js";
16
17
  import { NativeFlowContainerContext, } from "./native-flow-container-context.js";
17
18
  import { createNativeProviderClientController } from "./native-provider-client-controller.js";
@@ -34,9 +35,33 @@ const toClientOptionsKey = (value) => {
34
35
  .join(",")}}`;
35
36
  };
36
37
  const compareClientOptionsKeys = (left, right) => left < right ? -1 : left > right ? 1 : 0;
37
- const parseNativeInitOptions = (_a) => {
38
- var { capabilities } = _a, clientOptions = __rest(_a, ["capabilities"]);
39
- const initOptions = parseInitOptions(Object.assign(Object.assign({}, clientOptions), (capabilities !== undefined
38
+ const haveSameActionRegistrations = (left, right) => left.length === right.length &&
39
+ left.every((identity, index) => identity === right[index]);
40
+ const useNativeActionRegistry = (actions) => {
41
+ const nextRegistry = createActionRegistry(actions);
42
+ if (nextRegistry.getOpenUrlHandler() !== undefined) {
43
+ throw new TypeError('React Native actions support only registrations with kind "custom"');
44
+ }
45
+ const registryRef = useRef(null);
46
+ const currentRegistry = registryRef.current;
47
+ if (currentRegistry !== null &&
48
+ !haveSameActionRegistrations(currentRegistry.listRegistrationIdentities(), nextRegistry.listRegistrationIdentities())) {
49
+ throw new Error("actions definitions cannot be changed after widget init; keeping original registrations");
50
+ }
51
+ if (currentRegistry === null) {
52
+ registryRef.current = nextRegistry;
53
+ }
54
+ useLayoutEffect(() => {
55
+ registryRef.current = nextRegistry;
56
+ }, [nextRegistry]);
57
+ const getHandler = useCallback((definition) => { var _a; return (_a = registryRef.current) === null || _a === void 0 ? void 0 : _a.getHandler(definition); }, []);
58
+ return { definitions: nextRegistry.listDefinitions(), getHandler };
59
+ };
60
+ const parseNativeInitOptions = (_a, hostActions) => {
61
+ var { actions: _actions, capabilities } = _a, clientOptions = __rest(_a, ["actions", "capabilities"]);
62
+ const initOptions = parseInitOptions(Object.assign(Object.assign(Object.assign({}, clientOptions), (hostActions !== undefined && hostActions.length > 0
63
+ ? { hostActions }
64
+ : {})), (capabilities !== undefined
40
65
  ? {
41
66
  hostCapabilities: capabilities.map((capability) => typeof capability === "string"
42
67
  ? { key: capability }
@@ -64,7 +89,8 @@ export function GetUserFeedbackProvider({ children, clientOptions, instanceId: i
64
89
  const [contentOwner, setContentOwner] = useState(null);
65
90
  const [projection, setProjection] = useState(null);
66
91
  const contentOwnerRef = useRef(null);
67
- const normalizedClientOptions = parseNativeInitOptions(clientOptions);
92
+ const actionRegistry = useNativeActionRegistry(clientOptions.actions);
93
+ const normalizedClientOptions = parseNativeInitOptions(clientOptions, actionRegistry.definitions);
68
94
  const clientOptionsKey = toClientOptionsKey(normalizedClientOptions);
69
95
  const coreUrl = (_b = (_a = normalizedClientOptions.runtimeEndpoints) === null || _a === void 0 ? void 0 : _a.coreUrl) !== null && _b !== void 0 ? _b : REACT_NATIVE_PINNED_CORE_URL;
70
96
  const onErrorRef = useRef(onError);
@@ -143,6 +169,7 @@ export function GetUserFeedbackProvider({ children, clientOptions, instanceId: i
143
169
  instanceId,
144
170
  key: clientOptionsKey,
145
171
  getRuntimeConfiguration,
172
+ getHostActionHandler: actionRegistry.getHandler,
146
173
  onCommandSessionChange: handleCommandSessionChange,
147
174
  onError: reportError,
148
175
  onHandleInvalidated: handleHandleInvalidated,
@@ -1,6 +1,7 @@
1
1
  import type { CoreCommandEnvelope } from "@getuserfeedback/protocol";
2
2
  import type { EventHandleInvalidated } from "@getuserfeedback/protocol/internal/core-handle-invalidation";
3
3
  import type { ConfigureOptions, InitOptions } from "@getuserfeedback/sdk";
4
+ import type { ActionRegistry } from "@getuserfeedback/sdk/internal/action-registry";
4
5
  import type { OpenRequestDispatcher } from "@getuserfeedback/sdk/internal/open-request-dispatcher";
5
6
  import { type ReactElement } from "react";
6
7
  import { type CoreWebViewHostProps } from "./core-webview-host.js";
@@ -12,6 +13,10 @@ export type NativeRuntimeRootProps = {
12
13
  coreUrl: string;
13
14
  coreWebViewComponent?: CoreWebViewHostProps["webViewComponent"];
14
15
  createStartupCommand?: () => NativeRuntimeInitCommand;
16
+ hostActions?: {
17
+ getHandler: ActionRegistry["getHandler"];
18
+ instanceId: string;
19
+ };
15
20
  onCommandSessionChange?: (session: NativeCoreCommandSession | null) => void;
16
21
  onError?: (error: Error) => void;
17
22
  onHandleInvalidated?: (message: EventHandleInvalidated) => void;
@@ -34,8 +39,9 @@ type NativeProviderRuntimeProps = Omit<NativeRuntimeRootProps, "createStartupCom
34
39
  initOptions: InitOptions;
35
40
  instanceId: string;
36
41
  getRuntimeConfiguration?: () => ConfigureOptions;
42
+ getHostActionHandler?: ActionRegistry["getHandler"];
37
43
  onCommandSessionChange?: (session: NativeDirectCommandSession | null) => void;
38
44
  };
39
- export declare function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewComponent, createStartupCommand, onCommandSessionChange, onError, onHandleInvalidated, onInvalidMessage, observeOpenRequest, onStartupTerminalError, startupCommandSettlementTimeoutMs, viewNativeViewComponent, viewWebViewComponent, }: NativeRuntimeRootProps): ReactElement;
40
- export declare function NativeProviderRuntime({ directSessionController, getRuntimeConfiguration, initOptions, instanceId, onCommandSessionChange, onError, ...runtimeProps }: NativeProviderRuntimeProps): ReactElement;
45
+ export declare function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewComponent, createStartupCommand, hostActions, onCommandSessionChange, onError, onHandleInvalidated, onInvalidMessage, observeOpenRequest, onStartupTerminalError, startupCommandSettlementTimeoutMs, viewNativeViewComponent, viewWebViewComponent, }: NativeRuntimeRootProps): ReactElement;
46
+ export declare function NativeProviderRuntime({ directSessionController, getHostActionHandler, getRuntimeConfiguration, initOptions, instanceId, onCommandSessionChange, onError, ...runtimeProps }: NativeProviderRuntimeProps): ReactElement;
41
47
  export {};
@@ -20,7 +20,7 @@ import { createNativeViewRecordController, } from "./native-view-record-controll
20
20
  import { createProviderCommandEnvelope, REACT_NATIVE_CLIENT_META, } from "./provider-command-helpers.js";
21
21
  const DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS = 30000;
22
22
  const getEmptyRuntimeConfiguration = () => ({});
23
- export function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewComponent, createStartupCommand, onCommandSessionChange, onError, onHandleInvalidated, onInvalidMessage, observeOpenRequest, onStartupTerminalError, startupCommandSettlementTimeoutMs = DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS, viewNativeViewComponent, viewWebViewComponent, }) {
23
+ export function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewComponent, createStartupCommand, hostActions, onCommandSessionChange, onError, onHandleInvalidated, onInvalidMessage, observeOpenRequest, onStartupTerminalError, startupCommandSettlementTimeoutMs = DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS, viewNativeViewComponent, viewWebViewComponent, }) {
24
24
  const [coreHostRevision, setCoreHostRevision] = useState(0);
25
25
  const [session, setSession] = useState(null);
26
26
  const sessionRef = useRef(null);
@@ -40,6 +40,8 @@ export function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewCo
40
40
  onStartupTerminalErrorRef.current = onStartupTerminalError;
41
41
  const createStartupCommandRef = useRef(createStartupCommand);
42
42
  createStartupCommandRef.current = createStartupCommand;
43
+ const hostActionsRef = useRef(hostActions);
44
+ hostActionsRef.current = hostActions;
43
45
  const reportError = useCallback((error) => {
44
46
  var _a;
45
47
  try {
@@ -87,6 +89,18 @@ export function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewCo
87
89
  });
88
90
  const commandChannelOwner = createNativeCoreCommandChannel({
89
91
  coreConnection,
92
+ hostActions: hostActionsRef.current
93
+ ? {
94
+ getHandler: (definition) => { var _a; return (_a = hostActionsRef.current) === null || _a === void 0 ? void 0 : _a.getHandler(definition); },
95
+ getActiveViewIds: () => controller
96
+ .getSnapshot()
97
+ .filter((record) => record.isActive)
98
+ .map((record) => record.viewId),
99
+ instanceId: hostActionsRef.current.instanceId,
100
+ subscribeToViewActivity: controller.subscribe,
101
+ }
102
+ : undefined,
103
+ onHostActionError: reportError,
90
104
  onSessionFailure: (error) => {
91
105
  reportError(error);
92
106
  coreConnection.disconnect();
@@ -243,7 +257,7 @@ export function NativeRuntimeRoot({ attachViewProjection, coreUrl, coreWebViewCo
243
257
  }));
244
258
  }
245
259
  export function NativeProviderRuntime(_a) {
246
- var { directSessionController, getRuntimeConfiguration = getEmptyRuntimeConfiguration, initOptions, instanceId, onCommandSessionChange, onError } = _a, runtimeProps = __rest(_a, ["directSessionController", "getRuntimeConfiguration", "initOptions", "instanceId", "onCommandSessionChange", "onError"]);
260
+ var { directSessionController, getHostActionHandler, getRuntimeConfiguration = getEmptyRuntimeConfiguration, initOptions, instanceId, onCommandSessionChange, onError } = _a, runtimeProps = __rest(_a, ["directSessionController", "getHostActionHandler", "getRuntimeConfiguration", "initOptions", "instanceId", "onCommandSessionChange", "onError"]);
247
261
  const directSessionRef = useRef(null);
248
262
  useLayoutEffect(() => {
249
263
  directSessionController.beginAttachmentAttempt();
@@ -282,5 +296,7 @@ export function NativeProviderRuntime(_a) {
282
296
  instanceId,
283
297
  });
284
298
  }, [getRuntimeConfiguration, initOptions, instanceId]);
285
- return createElement(NativeRuntimeRoot, Object.assign(Object.assign({}, runtimeProps), { onCommandSessionChange: handleCommandSessionChange, onError, onStartupTerminalError: handleStartupTerminalError, createStartupCommand }));
299
+ return createElement(NativeRuntimeRoot, Object.assign(Object.assign({}, runtimeProps), { hostActions: getHostActionHandler
300
+ ? { getHandler: getHostActionHandler, instanceId }
301
+ : undefined, onCommandSessionChange: handleCommandSessionChange, onError, onStartupTerminalError: handleStartupTerminalError, createStartupCommand }));
286
302
  }
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.4.0";
6
+ export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "5.5.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/react-native",
3
- "version": "5.4.0",
3
+ "version": "5.5.0",
4
4
  "description": "getuserfeedback React Native SDK",
5
5
  "keywords": [
6
6
  "getuserfeedback",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@getuserfeedback/protocol": "^5.4.0",
48
- "@getuserfeedback/sdk": "^0.16.2",
48
+ "@getuserfeedback/sdk": "^0.17.0",
49
49
  "robot3": "^1.2.0"
50
50
  },
51
51
  "peerDependencies": {