@getuserfeedback/react-native 5.15.4 → 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 +4 -7
- package/dist/core-webview-bridge-adapter.js +1 -1
- package/dist/flow-container.js +2 -2
- package/dist/native-flow-container-context.d.ts +5 -4
- package/dist/native-flow-content.js +27 -11
- package/dist/native-host-action-rpc.js +1 -0
- package/dist/native-link-router-rpc.js +1 -0
- package/dist/native-provider-client-controller.d.ts +2 -1
- package/dist/native-provider-client-controller.js +12 -5
- package/dist/native-provider-client.js +3 -2
- package/dist/native-provider-command-controller.d.ts +1 -0
- package/dist/native-provider-command-controller.js +4 -1
- package/dist/native-provider.d.ts +1 -1
- package/dist/native-provider.js +15 -36
- package/dist/native-radio-decisions.d.ts +5 -0
- package/dist/native-radio-decisions.js +29 -0
- package/dist/native-runtime-endpoints.d.ts +1 -1
- package/dist/native-runtime-endpoints.js +1 -1
- package/dist/native-runtime-root.d.ts +1 -1
- package/dist/native-view-host-projection.d.ts +1 -8
- package/dist/native-view-host-projection.js +1 -1
- package/dist/native-view-record-controller.js +40 -7
- package/dist/native-widget-frame-shadow-support.js +4 -1
- package/dist/provider-command-helpers.js +2 -1
- package/dist/screen-tracking.d.ts +2 -2
- package/dist/version.js +1 -1
- package/dist/webview-document-host.js +1 -0
- package/package.json +4 -5
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AppEventExternalId, PublicCommandPayload } from "@getuserfeedback/protocol";
|
|
2
|
-
import type { ActionRegistration, ActionsConfig,
|
|
3
|
-
export type { ActionsConfig,
|
|
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" | "
|
|
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-
|
|
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";
|
package/dist/flow-container.js
CHANGED
|
@@ -10,7 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { createElement, useCallback, useContext, useLayoutEffect, useRef, useSyncExternalStore, } from "react";
|
|
13
|
-
import { NativeFlowContainerContext } from "./native-flow-container-context.js";
|
|
13
|
+
import { NativeFlowContainerContext, } from "./native-flow-container-context.js";
|
|
14
14
|
import { NativeViewHostProjection, } from "./native-view-host-projection.js";
|
|
15
15
|
const EMPTY_RECORDS = Object.freeze([]);
|
|
16
16
|
const subscribeNoop = () => () => { };
|
|
@@ -63,7 +63,7 @@ export function FlowContent() {
|
|
|
63
63
|
throw new Error("FlowContent must be used inside GetUserFeedbackProvider");
|
|
64
64
|
}
|
|
65
65
|
const ownerRef = useRef(null);
|
|
66
|
-
(_a = ownerRef.current) !== null && _a !== void 0 ? _a : (ownerRef.current =
|
|
66
|
+
(_a = ownerRef.current) !== null && _a !== void 0 ? _a : (ownerRef.current = Symbol("native FlowContent owner"));
|
|
67
67
|
const owner = ownerRef.current;
|
|
68
68
|
useLayoutEffect(() => context.registerContent(owner), [context.registerContent, owner]);
|
|
69
69
|
return context.contentOwner === owner
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import type { Client } from "./client.js";
|
|
2
2
|
import type { NativeProviderFlowRegistry } from "./native-provider-flow-registry.js";
|
|
3
3
|
import type { NativeViewProjection } from "./native-view-host-projection.js";
|
|
4
|
+
export type NativeFlowContentOwner = symbol;
|
|
4
5
|
export type NativeFlowContainerContextValue = Readonly<{
|
|
5
6
|
client: Client;
|
|
6
|
-
contentOwner:
|
|
7
|
+
contentOwner: NativeFlowContentOwner | null;
|
|
7
8
|
flowRegistry: NativeProviderFlowRegistry;
|
|
8
9
|
projection: NativeViewProjection | null;
|
|
9
|
-
registerContent: (owner:
|
|
10
|
+
registerContent: (owner: NativeFlowContentOwner) => () => void;
|
|
10
11
|
}>;
|
|
11
12
|
export declare const NativeFlowContainerContext: import("react").Context<Readonly<{
|
|
12
13
|
client: Client;
|
|
13
|
-
contentOwner:
|
|
14
|
+
contentOwner: NativeFlowContentOwner | null;
|
|
14
15
|
flowRegistry: NativeProviderFlowRegistry;
|
|
15
16
|
projection: NativeViewProjection | null;
|
|
16
|
-
registerContent: (owner:
|
|
17
|
+
registerContent: (owner: NativeFlowContentOwner) => () => void;
|
|
17
18
|
}> | null>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createElement, useLayoutEffect, useRef, useState, } from "react";
|
|
2
2
|
import { useNativeColorScheme } from "./native-color-scheme.js";
|
|
3
|
+
import { resolveNativeRadioErrors, resolveNativeRadioIntent, } from "./native-radio-decisions.js";
|
|
3
4
|
/** Thin native editor: drafts only. Core owns validation, navigation and submission. */
|
|
4
5
|
export function NativeFlowContent({ controller, presentationMode = "overlay", record, }) {
|
|
5
6
|
const flow = record.nativeFlow;
|
|
@@ -62,8 +63,27 @@ export function NativeFlowContent({ controller, presentationMode = "overlay", re
|
|
|
62
63
|
draft: Object.assign({}, rawDraft.current),
|
|
63
64
|
});
|
|
64
65
|
const disabled = interaction === "action" || !record.isActive;
|
|
65
|
-
const
|
|
66
|
-
|
|
66
|
+
const fields = projection.blocks.filter((block) => block.kind !== "statement");
|
|
67
|
+
// Match web usePageStatus: whitespace and nonempty arrays count as filled.
|
|
68
|
+
const isValueEmpty = (value) => value === null ||
|
|
69
|
+
value === undefined ||
|
|
70
|
+
(typeof value === "string" && value.length === 0) ||
|
|
71
|
+
(Array.isArray(value) && value.length === 0);
|
|
72
|
+
const hasEmptyRequired = fields.some((field) => field.required && isValueEmpty(draft[field.key]));
|
|
73
|
+
const localIntent = resolveNativeRadioIntent(projection, draft);
|
|
74
|
+
const errors = resolveNativeRadioErrors(projection, draft);
|
|
75
|
+
const primaryIntent = localIntent !== null && localIntent !== void 0 ? localIntent : (projection.status === "ready-to-submit" ? "submit" : "continue");
|
|
76
|
+
const showSubmit = primaryIntent === "submit";
|
|
77
|
+
const actionsWaiting = interaction !== "idle" && !(localIntent && interaction === "draft");
|
|
78
|
+
const showSkip = fields.length > 0 &&
|
|
79
|
+
fields.every((field) => !field.required && isValueEmpty(draft[field.key]));
|
|
80
|
+
const primaryLabel = showSubmit ? "Submit" : showSkip ? "Skip" : "Continue";
|
|
81
|
+
const primaryDisabled = actionsWaiting ||
|
|
82
|
+
!record.isActive ||
|
|
83
|
+
hasEmptyRequired ||
|
|
84
|
+
(showSubmit && fields.some((field) => Boolean(errors[field.key])));
|
|
85
|
+
const button = (label, onPress, buttonDisabled = actionsWaiting || !record.isActive, key = label) => createElement(Pressable, {
|
|
86
|
+
key,
|
|
67
87
|
accessibilityRole: "button",
|
|
68
88
|
accessibilityLabel: label,
|
|
69
89
|
disabled: buttonDisabled,
|
|
@@ -152,8 +172,8 @@ export function NativeFlowContent({ controller, presentationMode = "overlay", re
|
|
|
152
172
|
style: {
|
|
153
173
|
color: disabled ? palette.disabledText : palette.text,
|
|
154
174
|
},
|
|
155
|
-
}, `${selected === option.value ? "●" : "○"} ${option.label}`)))),
|
|
156
|
-
? createElement(Text, { accessibilityRole: "alert", style: { color: palette.error } },
|
|
175
|
+
}, `${selected === option.value ? "●" : "○"} ${option.label}`)))), errors[block.key]
|
|
176
|
+
? createElement(Text, { accessibilityRole: "alert", style: { color: palette.error } }, errors[block.key])
|
|
157
177
|
: null);
|
|
158
178
|
}), ...projection.formErrors.map((text, index) => createElement(Text, {
|
|
159
179
|
key: `error-${index}`,
|
|
@@ -164,15 +184,11 @@ export function NativeFlowContent({ controller, presentationMode = "overlay", re
|
|
|
164
184
|
? createElement(Text, { testID: "native-flow-complete", style: { color: palette.text } }, projection.mode === "simulated"
|
|
165
185
|
? "SIMULATED completion — nothing saved"
|
|
166
186
|
: "Thank you")
|
|
167
|
-
: null,
|
|
187
|
+
: null, interaction === "draft-failed"
|
|
168
188
|
? button("Retry refresh", () => interact("draft"), !record.isActive)
|
|
169
189
|
: null, projection.status !== "succeeded"
|
|
170
|
-
? button(
|
|
171
|
-
|
|
172
|
-
: projection.status === "ready-to-submit"
|
|
173
|
-
? "Submit"
|
|
174
|
-
: "Continue", () => interact(projection.status === "ready-to-submit" ? "submit" : "continue"))
|
|
175
|
-
: null, projection.canClose
|
|
190
|
+
? button(primaryLabel, () => interact(primaryIntent), primaryDisabled, "primary-action")
|
|
191
|
+
: null, projection.canGoBack ? button("Back", () => interact("back")) : null, projection.canClose
|
|
176
192
|
? createElement(Pressable, {
|
|
177
193
|
accessibilityRole: "button",
|
|
178
194
|
accessibilityLabel: "Close",
|
|
@@ -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(
|
|
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();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { assertNoSegmentExternalIdsInValueArgument } from "@getuserfeedback/protocol/host";
|
|
2
2
|
import { buildCustomerOccurrenceCommand } from "@getuserfeedback/sdk/internal/customer-occurrence-command";
|
|
3
|
+
import { toGraphRelationshipProperties } from "@getuserfeedback/sdk/internal/graph-relationship-properties";
|
|
3
4
|
import { createOpenRequestDispatcher, } from "@getuserfeedback/sdk/internal/open-request-dispatcher";
|
|
4
5
|
export const parseRequiredString = (name, value) => {
|
|
5
6
|
const normalized = value === null || value === void 0 ? void 0 : value.trim();
|
|
@@ -57,8 +58,8 @@ export function createNativeProviderClient({ dispatchCommand, flow, instanceId,
|
|
|
57
58
|
track,
|
|
58
59
|
screen,
|
|
59
60
|
graph: {
|
|
60
|
-
connect: (relationship) => track("gx.graph.relationship.connected", relationship),
|
|
61
|
-
disconnect: (relationship) => track("gx.graph.relationship.disconnected", relationship),
|
|
61
|
+
connect: (relationship) => track("gx.graph.relationship.connected", toGraphRelationshipProperties(relationship)),
|
|
62
|
+
disconnect: (relationship) => track("gx.graph.relationship.disconnected", toGraphRelationshipProperties(relationship)),
|
|
62
63
|
},
|
|
63
64
|
flow,
|
|
64
65
|
close: () => dispatchCommand({ kind: "close" }),
|
|
@@ -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
|
-
|
|
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,
|
|
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";
|
package/dist/native-provider.js
CHANGED
|
@@ -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,
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { NativeFlowInteraction, NativeFlowProjection } from "@getuserfeedback/protocol/internal/native-flow-session";
|
|
2
|
+
/** Exact lookup only. Core owns normalization, branching and action validation. */
|
|
3
|
+
export declare function resolveNativeRadioIntent(projection: NativeFlowProjection, draft: NativeFlowInteraction["draft"]): "continue" | "submit" | undefined;
|
|
4
|
+
/** Feedback belongs to the answer Core validated, not a later local choice. */
|
|
5
|
+
export declare function resolveNativeRadioErrors(projection: NativeFlowProjection, draft: NativeFlowInteraction["draft"]): Record<string, string>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Exact lookup only. Core owns normalization, branching and action validation. */
|
|
2
|
+
export function resolveNativeRadioIntent(projection, draft) {
|
|
3
|
+
var _a;
|
|
4
|
+
const table = projection.radioDecisions;
|
|
5
|
+
if (!table ||
|
|
6
|
+
Object.keys(draft).length !== 1 ||
|
|
7
|
+
!Object.hasOwn(draft, table.fieldKey))
|
|
8
|
+
return undefined;
|
|
9
|
+
const value = draft[table.fieldKey];
|
|
10
|
+
if (value !== null && typeof value !== "string")
|
|
11
|
+
return undefined;
|
|
12
|
+
return (_a = table.entries.find((entry) => entry.value === value)) === null || _a === void 0 ? void 0 : _a.intent;
|
|
13
|
+
}
|
|
14
|
+
/** Feedback belongs to the answer Core validated, not a later local choice. */
|
|
15
|
+
export function resolveNativeRadioErrors(projection, draft) {
|
|
16
|
+
const field = projection.blocks.find((block) => block.kind === "radio");
|
|
17
|
+
if (!resolveNativeRadioIntent(projection, draft) || (field === null || field === void 0 ? void 0 : field.kind) !== "radio")
|
|
18
|
+
return projection.errors;
|
|
19
|
+
const value = draft[field.key];
|
|
20
|
+
// Core certifies literal options (including authored empty strings) unchanged
|
|
21
|
+
// by normalization. Other values retain the asynchronous feedback policy.
|
|
22
|
+
if (typeof value !== "string" ||
|
|
23
|
+
!field.options.some((option) => option.value === value) ||
|
|
24
|
+
value === projection.answers[field.key])
|
|
25
|
+
return projection.errors;
|
|
26
|
+
const errors = Object.assign({}, projection.errors);
|
|
27
|
+
delete errors[field.key];
|
|
28
|
+
return errors;
|
|
29
|
+
}
|
|
@@ -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/
|
|
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/
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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;
|
|
@@ -6,6 +6,7 @@ import { buildRpcRequest, rpcRequestSchema, rpcResponseSchema, } from "@getuserf
|
|
|
6
6
|
import { actionRequestCloseViewSchema, actionViewConnectSchema, buildEventLayoutTransactionCommitted, buildEventViewSize, eventViewSizeSchema, } from "@getuserfeedback/protocol/internal/view-host-control-messages";
|
|
7
7
|
import { buildEventViewActivated, buildEventViewActivationDecided, buildEventViewAllocationFailed, buildEventViewClosed, buildEventViewCloseFailed, buildEventViewPrerendered, } from "@getuserfeedback/protocol/internal/view-host-lifecycle-events-v3";
|
|
8
8
|
import { bindViewHostControlEnvelope, bindViewToCoreRelayEnvelope, parseCoreToViewRelayEnvelope, } from "@getuserfeedback/protocol/internal/view-relay-contract";
|
|
9
|
+
import { resolveNativeRadioErrors, resolveNativeRadioIntent, } from "./native-radio-decisions.js";
|
|
9
10
|
import { createViewPreparationReadinessRegistry, createViewPreparationRegistry, } from "./view-orchestration-runtime.js";
|
|
10
11
|
// RPC IDs are UUIDs, unlike command IDs whose non-WebCrypto fallback is prefixed.
|
|
11
12
|
// This is live request correlation, not an authentication token.
|
|
@@ -272,7 +273,10 @@ export function createNativeViewRecordController(input) {
|
|
|
272
273
|
}
|
|
273
274
|
nextAllocationId += 1;
|
|
274
275
|
const entry = Object.assign(Object.assign({}, (action.t === "getuserfeedback:action:prerenderNativeFlow"
|
|
275
|
-
? {
|
|
276
|
+
? {
|
|
277
|
+
nativeProjection: action.projection,
|
|
278
|
+
nativeRadioProjections: new WeakSet([action.projection]),
|
|
279
|
+
}
|
|
276
280
|
: {})), { allocationId: nextAllocationId, flowId: ((_a = action.openRequest) === null || _a === void 0 ? void 0 : _a.source) === "command"
|
|
277
281
|
? ((_b = action.openRequest.flowId) !== null && _b !== void 0 ? _b : null)
|
|
278
282
|
: null, generation: action.gen, flowRunId: action.flowRunId, instanceId: action.instanceId, isActive: false, isClosing: false, isPreparationCommitted: false, isPresentationAcknowledged: false, isViewConnected: false, isViewRelayDraining: false, layoutReportRevision: 0, pendingCoreToViewMessages: [], preparation, retainedSize: null, size: null, srcdoc, committedLayoutReportOccurrence: null, viewConnection: null, viewConnectionDetach: null, viewId: action.viewId });
|
|
@@ -391,6 +395,7 @@ export function createNativeViewRecordController(input) {
|
|
|
391
395
|
drainCoreToViewMessages(entry);
|
|
392
396
|
};
|
|
393
397
|
const handleCoreMessage = (value) => {
|
|
398
|
+
var _a;
|
|
394
399
|
if (coreConnectionFailed || disposed) {
|
|
395
400
|
return;
|
|
396
401
|
}
|
|
@@ -421,8 +426,13 @@ export function createNativeViewRecordController(input) {
|
|
|
421
426
|
return;
|
|
422
427
|
}
|
|
423
428
|
clearTimeout(interaction.timeout);
|
|
429
|
+
if (interaction.kind !== "draft" ||
|
|
430
|
+
entry.nativeProjection.nodeId !== result.data.nodeId) {
|
|
431
|
+
entry.nativeRadioProjections = new WeakSet();
|
|
432
|
+
}
|
|
424
433
|
entry.nativeInteraction = undefined;
|
|
425
434
|
entry.nativeProjection = result.data;
|
|
435
|
+
(_a = entry.nativeRadioProjections) === null || _a === void 0 ? void 0 : _a.add(result.data);
|
|
426
436
|
notify();
|
|
427
437
|
return;
|
|
428
438
|
}
|
|
@@ -560,8 +570,14 @@ export function createNativeViewRecordController(input) {
|
|
|
560
570
|
return binding;
|
|
561
571
|
},
|
|
562
572
|
interactNativeFlow({ allocationId, viewId, projection, intent, draft }) {
|
|
563
|
-
var _a, _b;
|
|
573
|
+
var _a, _b, _c, _d, _e;
|
|
564
574
|
const entry = entries.get(viewId);
|
|
575
|
+
const current = entry === null || entry === void 0 ? void 0 : entry.nativeProjection;
|
|
576
|
+
const currentIntent = current && resolveNativeRadioIntent(current, draft);
|
|
577
|
+
const presentedIntent = resolveNativeRadioIntent(projection, draft);
|
|
578
|
+
const local = currentIntent !== undefined && presentedIntent !== undefined;
|
|
579
|
+
const radioLifetime = !(projection.radioDecisions || (current === null || current === void 0 ? void 0 : current.radioDecisions)) ||
|
|
580
|
+
((_a = entry === null || entry === void 0 ? void 0 : entry.nativeRadioProjections) === null || _a === void 0 ? void 0 : _a.has(projection));
|
|
565
581
|
if (disposed ||
|
|
566
582
|
coreConnectionFailed ||
|
|
567
583
|
!entry ||
|
|
@@ -571,11 +587,15 @@ export function createNativeViewRecordController(input) {
|
|
|
571
587
|
!entry.isPreparationCommitted ||
|
|
572
588
|
!entry.nativeContentBinding ||
|
|
573
589
|
!entry.nativeProjection ||
|
|
590
|
+
!radioLifetime ||
|
|
574
591
|
(intent === "draft"
|
|
575
|
-
? ((
|
|
592
|
+
? ((_b = entry.nativeInteraction) === null || _b === void 0 ? void 0 : _b.kind) === "action" ||
|
|
576
593
|
entry.nativeProjection.nodeId !== projection.nodeId
|
|
577
|
-
:
|
|
578
|
-
entry.
|
|
594
|
+
: local
|
|
595
|
+
? ((_c = entry.nativeInteraction) === null || _c === void 0 ? void 0 : _c.kind) === "action" ||
|
|
596
|
+
((_d = entry.nativeInteraction) === null || _d === void 0 ? void 0 : _d.kind) === "draft-failed"
|
|
597
|
+
: entry.nativeInteraction !== undefined ||
|
|
598
|
+
entry.nativeProjection !== projection))
|
|
579
599
|
return false;
|
|
580
600
|
const parsed = nativeFlowInteractionSchema.safeParse({
|
|
581
601
|
flowRunId: entry.flowRunId,
|
|
@@ -585,9 +605,21 @@ export function createNativeViewRecordController(input) {
|
|
|
585
605
|
});
|
|
586
606
|
if (!parsed.success)
|
|
587
607
|
return false;
|
|
608
|
+
if (local && intent !== "draft" && intent !== "back") {
|
|
609
|
+
const field = entry.nativeProjection.blocks.find((block) => block.kind === "radio");
|
|
610
|
+
if (intent !== currentIntent ||
|
|
611
|
+
intent !== presentedIntent ||
|
|
612
|
+
((field === null || field === void 0 ? void 0 : field.kind) === "radio" &&
|
|
613
|
+
field.required &&
|
|
614
|
+
(draft[field.key] === null || draft[field.key] === ""))) {
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
588
618
|
const rpcId = createNativeInteractionRpcId();
|
|
589
619
|
const currentProjection = entry.nativeProjection;
|
|
590
|
-
if (
|
|
620
|
+
if (intent !== "draft")
|
|
621
|
+
entry.nativeRadioProjections = new WeakSet();
|
|
622
|
+
if (((_e = entry.nativeInteraction) === null || _e === void 0 ? void 0 : _e.kind) === "draft")
|
|
591
623
|
clearTimeout(entry.nativeInteraction.timeout);
|
|
592
624
|
// Match the ordinary RPC budget. Correlation already rejects late replies;
|
|
593
625
|
// Timeout or a failed reply restores editing for an explicit manual retry.
|
|
@@ -601,7 +633,8 @@ export function createNativeViewRecordController(input) {
|
|
|
601
633
|
clearTimeout(entry.nativeInteraction.timeout);
|
|
602
634
|
entry.nativeInteraction =
|
|
603
635
|
intent === "draft" ? { kind: "draft-failed" } : undefined;
|
|
604
|
-
entry.nativeProjection = Object.assign(Object.assign({}, currentProjection), { answers: Object.assign(Object.assign({}, currentProjection.answers), parsed.data.draft), formErrors: ["Something went wrong. Please try again."] });
|
|
636
|
+
entry.nativeProjection = Object.assign(Object.assign({}, currentProjection), { errors: resolveNativeRadioErrors(currentProjection, parsed.data.draft), answers: Object.assign(Object.assign({}, currentProjection.answers), parsed.data.draft), formErrors: ["Something went wrong. Please try again."] });
|
|
637
|
+
entry.nativeRadioProjections = new WeakSet([entry.nativeProjection]);
|
|
605
638
|
notify();
|
|
606
639
|
};
|
|
607
640
|
entry.nativeInteraction = {
|
|
@@ -38,7 +38,10 @@ export function resolveNativeWidgetBoxShadowSupport() {
|
|
|
38
38
|
const reactNativeModule = require("react-native");
|
|
39
39
|
// React Native exposes renderer capability to JavaScript process-wide.
|
|
40
40
|
// There is no stable public API for querying the renderer of one View.
|
|
41
|
-
const
|
|
41
|
+
const runtimeGlobal = globalThis;
|
|
42
|
+
const fabricUIManager = "nativeFabricUIManager" in runtimeGlobal
|
|
43
|
+
? runtimeGlobal.nativeFabricUIManager
|
|
44
|
+
: undefined;
|
|
42
45
|
return toNativeWidgetBoxShadowSupport({
|
|
43
46
|
hasFabricUIManager: fabricUIManager !== undefined && fabricUIManager !== null,
|
|
44
47
|
platform: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createCommandRequestId, REACT_NATIVE_WEBVIEW_TRANSPORT_CAPABILITIES, } from "@getuserfeedback/protocol/host";
|
|
2
|
-
import { NATIVE_FLOW_SESSION_PROTOCOL } from "@getuserfeedback/protocol/internal/native-flow-session";
|
|
2
|
+
import { NATIVE_FLOW_RADIO_DECISIONS_PROTOCOL, NATIVE_FLOW_SESSION_PROTOCOL, } from "@getuserfeedback/protocol/internal/native-flow-session";
|
|
3
3
|
import { REACT_NATIVE_SDK_VERSION } from "./version.js";
|
|
4
4
|
export const REACT_NATIVE_CLIENT_META = {
|
|
5
5
|
clientName: "@getuserfeedback/react-native",
|
|
@@ -7,6 +7,7 @@ export const REACT_NATIVE_CLIENT_META = {
|
|
|
7
7
|
loader: "sdk",
|
|
8
8
|
protocolCapabilities: [
|
|
9
9
|
NATIVE_FLOW_SESSION_PROTOCOL,
|
|
10
|
+
NATIVE_FLOW_RADIO_DECISIONS_PROTOCOL,
|
|
10
11
|
REACT_NATIVE_WEBVIEW_TRANSPORT_CAPABILITIES.LAYOUT_TRANSITION_POLICY,
|
|
11
12
|
REACT_NATIVE_WEBVIEW_TRANSPORT_CAPABILITIES.LAYOUT_TRANSITION_SCHEDULE,
|
|
12
13
|
],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
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:
|
|
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.
|
|
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.
|
|
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
|
-
"
|
|
54
|
-
"lint": "biome check ."
|
|
53
|
+
"lint": "oxlint --threads=2 -c ../../oxlint.config.ts ."
|
|
55
54
|
},
|
|
56
55
|
"dependencies": {
|
|
57
|
-
"@getuserfeedback/protocol": "^
|
|
58
|
-
"@getuserfeedback/sdk": "^0.
|
|
56
|
+
"@getuserfeedback/protocol": "^7.0.0",
|
|
57
|
+
"@getuserfeedback/sdk": "^0.20.0",
|
|
59
58
|
"robot3": "^1.2.0"
|
|
60
59
|
},
|
|
61
60
|
"peerDependencies": {
|