@getuserfeedback/react-native 3.0.80 → 3.0.90
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/index.js +29 -89
- package/dist/native-direct-command-session-controller.d.ts +9 -0
- package/dist/native-direct-command-session-controller.js +78 -0
- package/dist/native-direct-command-session.js +2 -2
- package/dist/native-provider-client.d.ts +64 -0
- package/dist/native-provider-client.js +76 -0
- package/dist/native-runtime-root.d.ts +5 -3
- package/dist/native-runtime-root.js +31 -7
- package/dist/native-view-host-projection.d.ts +2 -1
- package/dist/native-view-host-projection.js +13 -9
- package/dist/native-view-presentation-surface.d.ts +7 -0
- package/dist/native-view-presentation-surface.js +82 -0
- package/dist/native-view-record-controller.d.ts +2 -0
- package/dist/native-view-record-controller.js +58 -8
- package/dist/native-widget-corner-radii.d.ts +10 -0
- package/dist/native-widget-corner-radii.js +54 -0
- package/dist/native-widget-frame-border.d.ts +7 -0
- package/dist/native-widget-frame-border.js +21 -0
- package/dist/native-widget-frame-shadow.d.ts +30 -0
- package/dist/native-widget-frame-shadow.js +49 -0
- package/dist/provider-widget-border-radius.js +5 -18
- package/dist/provider-widget-frame-appearance.d.ts +5 -34
- package/dist/provider-widget-frame-appearance.js +10 -69
- package/dist/provider-widget-host-overlay.d.ts +2 -1
- package/dist/provider-widget-host-overlay.js +7 -6
- package/dist/use-native-direct-command-session-controller.d.ts +2 -0
- package/dist/use-native-direct-command-session-controller.js +21 -0
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -9,10 +9,11 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import {
|
|
12
|
+
import { CommandSettlementError, CommandSettlementTimeoutError, createFlowCommandHandleController, getFlowHandleFromSettlementDetail, getWidgetLayoutPlanNowMs, } from "@getuserfeedback/protocol/host";
|
|
13
13
|
import { parseWebViewTransportNativeMessage } from "@getuserfeedback/protocol/webview-transport";
|
|
14
14
|
import { createContext, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
|
|
15
15
|
import { useResolvedHostViewport } from "./host-viewport.js";
|
|
16
|
+
import { createNativeProviderClient, parseRequiredString, } from "./native-provider-client.js";
|
|
16
17
|
import { createProviderCommandEnvelope, REACT_NATIVE_LOADER_CLIENT_META, toCommandSettlementError, toReactNativeOneShotCommand, } from "./provider-command-helpers.js";
|
|
17
18
|
import { useProviderCommandTransport } from "./provider-command-transport.js";
|
|
18
19
|
import { createProviderWidgetHostLifecycleController, HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY, } from "./provider-widget-host-lifecycle.js";
|
|
@@ -136,13 +137,6 @@ const normalizeOptionalString = (value) => {
|
|
|
136
137
|
const normalized = value.trim();
|
|
137
138
|
return normalized.length > 0 ? normalized : undefined;
|
|
138
139
|
};
|
|
139
|
-
const resolveRequiredString = (name, value) => {
|
|
140
|
-
const normalized = normalizeOptionalString(value);
|
|
141
|
-
if (normalized === undefined) {
|
|
142
|
-
throw new Error(`${name} must be a non-empty string`);
|
|
143
|
-
}
|
|
144
|
-
return normalized;
|
|
145
|
-
};
|
|
146
140
|
const toJsonKey = (value) => JSON.stringify(value);
|
|
147
141
|
const toStableHash = (value) => {
|
|
148
142
|
const json = toJsonKey(value);
|
|
@@ -171,33 +165,6 @@ function resolveReactNativeComponents() {
|
|
|
171
165
|
};
|
|
172
166
|
}
|
|
173
167
|
}
|
|
174
|
-
const toIdentifyCommandPayload = (identifyInput, traitsOrOptions, options) => {
|
|
175
|
-
if (typeof identifyInput === "string") {
|
|
176
|
-
assertNoSegmentExternalIdsInValueArgument({
|
|
177
|
-
argument: traitsOrOptions,
|
|
178
|
-
commandName: "identify",
|
|
179
|
-
valueArgumentName: "traits",
|
|
180
|
-
callShape: "identify(userId, traits, { externalIds })",
|
|
181
|
-
});
|
|
182
|
-
return {
|
|
183
|
-
kind: "identify",
|
|
184
|
-
userId: resolveRequiredString("userId", identifyInput),
|
|
185
|
-
traits: traitsOrOptions,
|
|
186
|
-
options,
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
assertNoSegmentExternalIdsInValueArgument({
|
|
190
|
-
argument: identifyInput,
|
|
191
|
-
commandName: "identify",
|
|
192
|
-
valueArgumentName: "traits",
|
|
193
|
-
callShape: "identify(traits, { externalIds })",
|
|
194
|
-
});
|
|
195
|
-
return {
|
|
196
|
-
kind: "identify",
|
|
197
|
-
traits: identifyInput,
|
|
198
|
-
options: options !== null && options !== void 0 ? options : traitsOrOptions,
|
|
199
|
-
};
|
|
200
|
-
};
|
|
201
168
|
export function GetUserFeedbackProvider({ autoInit = true, children, commandTimeoutMs = DEFAULT_COMMAND_TIMEOUT_MS, configureOptions, hostViewport, instanceId: instanceIdProp, initOptions, loaderUrl, onCommandError, onInvalidWebMessage, onWebMessage, source, webViewComponent, webViewProps, }) {
|
|
202
169
|
var _a;
|
|
203
170
|
const { View: NativeView } = useMemo(resolveReactNativeComponents, []);
|
|
@@ -383,7 +350,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
383
350
|
reportCommandError,
|
|
384
351
|
};
|
|
385
352
|
const flow = useCallback((flowId) => {
|
|
386
|
-
const normalizedFlowId =
|
|
353
|
+
const normalizedFlowId = parseRequiredString("flowId", flowId);
|
|
387
354
|
const existing = flowRunsRef.current.get(normalizedFlowId);
|
|
388
355
|
if (existing) {
|
|
389
356
|
return existing;
|
|
@@ -541,59 +508,32 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
541
508
|
disposeCommandTransport(new Error(PROVIDER_UNMOUNTED_ERROR_MESSAGE));
|
|
542
509
|
}, [disposeCommandTransport]);
|
|
543
510
|
const getNativeMessages = useCallback(() => nativeMessagesRef.current, [nativeMessagesRef]);
|
|
544
|
-
const contextValue = useMemo(() =>
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
},
|
|
571
|
-
prefetch: (flowId, options) => {
|
|
572
|
-
const normalizedFlowId = resolveRequiredString("flowId", flowId);
|
|
573
|
-
return enqueueCommand({
|
|
574
|
-
kind: "prefetch",
|
|
575
|
-
flowId: normalizedFlowId,
|
|
576
|
-
}, options);
|
|
577
|
-
},
|
|
578
|
-
prerender: (flowId, options, commandOptions) => {
|
|
579
|
-
const normalizedFlowId = resolveRequiredString("flowId", flowId);
|
|
580
|
-
return enqueueCommand({
|
|
581
|
-
kind: "prerender",
|
|
582
|
-
flowId: normalizedFlowId,
|
|
583
|
-
hideCloseButton: options === null || options === void 0 ? void 0 : options.hideCloseButton,
|
|
584
|
-
}, commandOptions);
|
|
585
|
-
},
|
|
586
|
-
flow,
|
|
587
|
-
close: (flowHandleId, options) => enqueueCommand(Object.assign({ kind: "close" }, (flowHandleId === undefined
|
|
588
|
-
? {}
|
|
589
|
-
: {
|
|
590
|
-
flowHandleId: resolveRequiredString("flowHandleId", flowHandleId),
|
|
591
|
-
})), options),
|
|
592
|
-
reset: (options) => enqueueCommand({ kind: "reset" }, options),
|
|
593
|
-
updateHostContext: (context, options) => enqueueCommand({ kind: "updateHostContext", context }, options),
|
|
594
|
-
emitHostSignal: (name, data, options) => enqueueCommand(Object.assign({ kind: "emitHostSignal", name: resolveRequiredString("name", name) }, (data === undefined ? {} : { data })), options),
|
|
595
|
-
handleWebMessage,
|
|
596
|
-
}), [enqueueCommand, flow, getNativeMessages, handleWebMessage, instanceId]);
|
|
511
|
+
const contextValue = useMemo(() => {
|
|
512
|
+
const client = createNativeProviderClient({
|
|
513
|
+
dispatchCommand: enqueueCommand,
|
|
514
|
+
flow,
|
|
515
|
+
instanceId,
|
|
516
|
+
});
|
|
517
|
+
return {
|
|
518
|
+
close: client.close,
|
|
519
|
+
configure: client.configure,
|
|
520
|
+
emitHostSignal: client.emitHostSignal,
|
|
521
|
+
enqueueCommand,
|
|
522
|
+
flow: client.flow,
|
|
523
|
+
handleWebMessage,
|
|
524
|
+
identify: client.identify,
|
|
525
|
+
instanceId: client.instanceId,
|
|
526
|
+
get nativeMessages() {
|
|
527
|
+
return getNativeMessages();
|
|
528
|
+
},
|
|
529
|
+
open: client.open,
|
|
530
|
+
prefetch: client.prefetch,
|
|
531
|
+
prerender: client.prerender,
|
|
532
|
+
reset: client.reset,
|
|
533
|
+
track: client.track,
|
|
534
|
+
updateHostContext: client.updateHostContext,
|
|
535
|
+
};
|
|
536
|
+
}, [enqueueCommand, flow, getNativeMessages, handleWebMessage, instanceId]);
|
|
597
537
|
const previousSheetHostLayoutUpdateRef = useRef(undefined);
|
|
598
538
|
const consumedTransitionPolicySequenceRef = useRef(undefined);
|
|
599
539
|
useEffect(() => {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { NativeDirectCommandSession } from "./native-direct-command-session.js";
|
|
2
|
+
export type NativeDirectCommandSessionController = {
|
|
3
|
+
attach: (session: NativeDirectCommandSession) => void;
|
|
4
|
+
detach: (session: NativeDirectCommandSession) => void;
|
|
5
|
+
dispose: (error: Error) => void;
|
|
6
|
+
rejectUntilAttached: (error: Error) => void;
|
|
7
|
+
session: NativeDirectCommandSession;
|
|
8
|
+
};
|
|
9
|
+
export declare function createNativeDirectCommandSessionController(): NativeDirectCommandSessionController;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export function createNativeDirectCommandSessionController() {
|
|
2
|
+
let attachedSession = null;
|
|
3
|
+
let disposed = false;
|
|
4
|
+
let disposalError;
|
|
5
|
+
let pendingCommands = [];
|
|
6
|
+
let unavailableError;
|
|
7
|
+
const dispatchThrough = (session, envelope) => {
|
|
8
|
+
try {
|
|
9
|
+
return Promise.resolve(session.dispatch(envelope));
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
return Promise.reject(error);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const session = {
|
|
16
|
+
dispatch: (envelope) => {
|
|
17
|
+
if (disposed) {
|
|
18
|
+
return Promise.reject(disposalError);
|
|
19
|
+
}
|
|
20
|
+
if (attachedSession !== null) {
|
|
21
|
+
return dispatchThrough(attachedSession, envelope);
|
|
22
|
+
}
|
|
23
|
+
if (unavailableError !== undefined) {
|
|
24
|
+
return Promise.reject(unavailableError);
|
|
25
|
+
}
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
pendingCommands.push({ envelope, reject, resolve });
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
const dispose = (error) => {
|
|
32
|
+
if (disposed) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
disposed = true;
|
|
36
|
+
disposalError = error;
|
|
37
|
+
attachedSession = null;
|
|
38
|
+
const queuedCommands = pendingCommands;
|
|
39
|
+
pendingCommands = [];
|
|
40
|
+
for (const command of queuedCommands) {
|
|
41
|
+
command.reject(error);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
attach: (nextSession) => {
|
|
46
|
+
if (disposed) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
attachedSession = nextSession;
|
|
50
|
+
unavailableError = undefined;
|
|
51
|
+
const queuedCommands = pendingCommands;
|
|
52
|
+
pendingCommands = [];
|
|
53
|
+
for (const command of queuedCommands) {
|
|
54
|
+
if (disposed) {
|
|
55
|
+
command.reject(disposalError);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
void dispatchThrough(nextSession, command.envelope).then(command.resolve, command.reject);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
detach: (sessionToDetach) => {
|
|
62
|
+
if (attachedSession === sessionToDetach) {
|
|
63
|
+
attachedSession = null;
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
dispose,
|
|
67
|
+
rejectUntilAttached: (error) => {
|
|
68
|
+
attachedSession = null;
|
|
69
|
+
unavailableError = error;
|
|
70
|
+
const queuedCommands = pendingCommands;
|
|
71
|
+
pendingCommands = [];
|
|
72
|
+
for (const command of queuedCommands) {
|
|
73
|
+
command.reject(error);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
session,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getFlowHandleFromSettlementDetail } from "@getuserfeedback/protocol/host";
|
|
2
2
|
import { toCoreCommandPayload, } from "@getuserfeedback/protocol/internal/public-core-command";
|
|
3
|
-
// TODO(migration): Route the public provider client through this core-ordered direct session.
|
|
4
|
-
// [from=native-
|
|
3
|
+
// TODO(migration): Route the public provider client through this core-ordered direct session after native per-view presentation is complete.
|
|
4
|
+
// [from=native-view-presentation-behavior] [to=native-provider-direct-session] [scope=slice] [principle=core-owned-flow-lifecycle] [priority=high] [impact=high] [risk=high] [epic=runtime-neutral-view-host-orchestration] [epic_order=190]
|
|
5
5
|
export function createNativeDirectCommandSession(input) {
|
|
6
6
|
const dispatchToCore = (envelope, command) => {
|
|
7
7
|
const coreEnvelope = Object.assign(Object.assign({}, envelope), { command: toCoreCommandPayload(command) });
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { AppEventExternalId, AppEventJsonValue, PublicCommandPayload } from "@getuserfeedback/protocol";
|
|
2
|
+
import type { ConfigureOptions } from "@getuserfeedback/sdk";
|
|
3
|
+
type IdentifyTraits = Record<string, unknown>;
|
|
4
|
+
type TrackProperties = Record<string, AppEventJsonValue>;
|
|
5
|
+
type OpenCommand = Extract<PublicCommandPayload, {
|
|
6
|
+
kind: "open";
|
|
7
|
+
}>;
|
|
8
|
+
type PrerenderCommand = Extract<PublicCommandPayload, {
|
|
9
|
+
kind: "prerender";
|
|
10
|
+
}>;
|
|
11
|
+
type NativeProviderClientCommand = Exclude<Extract<PublicCommandPayload, {
|
|
12
|
+
kind: "configure" | "identify" | "track" | "open" | "prefetch" | "prerender" | "close" | "reset" | "updateHostContext" | "emitHostSignal";
|
|
13
|
+
}>, OpenCommand> | (Omit<OpenCommand, "container"> & {
|
|
14
|
+
container?: never;
|
|
15
|
+
});
|
|
16
|
+
type IdentifyOptions = {
|
|
17
|
+
externalIds?: AppEventExternalId[];
|
|
18
|
+
};
|
|
19
|
+
type TrackOptions = {
|
|
20
|
+
externalIds?: AppEventExternalId[];
|
|
21
|
+
};
|
|
22
|
+
type OpenOptions = Pick<OpenCommand, "hideCloseButton">;
|
|
23
|
+
type PrerenderOptions = Pick<PrerenderCommand, "hideCloseButton">;
|
|
24
|
+
type OpenFlowOptions = Pick<OpenCommand, "hideCloseButton" | "metadata">;
|
|
25
|
+
type PrerenderFlowOptions = Pick<PrerenderCommand, "hideCloseButton">;
|
|
26
|
+
type HostContext = Extract<PublicCommandPayload, {
|
|
27
|
+
kind: "updateHostContext";
|
|
28
|
+
}>["context"];
|
|
29
|
+
interface NativeProviderCommandOptions {
|
|
30
|
+
idempotencyKey?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ReactNativeFlowRun {
|
|
33
|
+
readonly flowId: string;
|
|
34
|
+
open: (options?: OpenFlowOptions) => Promise<void>;
|
|
35
|
+
prefetch: () => Promise<void>;
|
|
36
|
+
prerender: (options?: PrerenderFlowOptions) => Promise<void>;
|
|
37
|
+
close: () => Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export interface NativeProviderClient<TResult> {
|
|
40
|
+
readonly instanceId: string;
|
|
41
|
+
configure: (opts: ConfigureOptions, options?: NativeProviderCommandOptions) => Promise<TResult>;
|
|
42
|
+
identify: {
|
|
43
|
+
(userId: string, traits?: IdentifyTraits, options?: IdentifyOptions): Promise<TResult>;
|
|
44
|
+
(traits: IdentifyTraits, placeholder: undefined, options?: IdentifyOptions): Promise<TResult>;
|
|
45
|
+
(traits: IdentifyTraits, options?: IdentifyOptions): Promise<TResult>;
|
|
46
|
+
};
|
|
47
|
+
track: (eventName: string, properties?: TrackProperties, options?: TrackOptions) => Promise<TResult>;
|
|
48
|
+
open: (flowId: string, options?: OpenOptions, commandOptions?: NativeProviderCommandOptions) => Promise<TResult>;
|
|
49
|
+
prefetch: (flowId: string, options?: NativeProviderCommandOptions) => Promise<TResult>;
|
|
50
|
+
prerender: (flowId: string, options?: PrerenderOptions, commandOptions?: NativeProviderCommandOptions) => Promise<TResult>;
|
|
51
|
+
flow: (flowId: string) => ReactNativeFlowRun;
|
|
52
|
+
close: (flowHandleId?: string, options?: NativeProviderCommandOptions) => Promise<TResult>;
|
|
53
|
+
reset: (options?: NativeProviderCommandOptions) => Promise<TResult>;
|
|
54
|
+
updateHostContext: (context: HostContext, options?: NativeProviderCommandOptions) => Promise<TResult>;
|
|
55
|
+
emitHostSignal: (name: string, data?: unknown, options?: NativeProviderCommandOptions) => Promise<TResult>;
|
|
56
|
+
}
|
|
57
|
+
type NativeProviderClientOptions<TResult> = {
|
|
58
|
+
dispatchCommand: (command: NativeProviderClientCommand, options?: NativeProviderCommandOptions) => Promise<TResult>;
|
|
59
|
+
flow: (flowId: string) => ReactNativeFlowRun;
|
|
60
|
+
instanceId: string;
|
|
61
|
+
};
|
|
62
|
+
export declare const parseRequiredString: (name: string, value?: string) => string;
|
|
63
|
+
export declare function createNativeProviderClient<TResult>({ dispatchCommand, flow, instanceId, }: NativeProviderClientOptions<TResult>): NativeProviderClient<TResult>;
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { assertNoSegmentExternalIdsInValueArgument } from "@getuserfeedback/protocol/host";
|
|
2
|
+
export const parseRequiredString = (name, value) => {
|
|
3
|
+
const normalized = value === null || value === void 0 ? void 0 : value.trim();
|
|
4
|
+
if (!normalized) {
|
|
5
|
+
throw new Error(`${name} must be a non-empty string`);
|
|
6
|
+
}
|
|
7
|
+
return normalized;
|
|
8
|
+
};
|
|
9
|
+
const toIdentifyCommandPayload = (identifyInput, traitsOrOptions, options) => {
|
|
10
|
+
if (typeof identifyInput === "string") {
|
|
11
|
+
assertNoSegmentExternalIdsInValueArgument({
|
|
12
|
+
argument: traitsOrOptions,
|
|
13
|
+
commandName: "identify",
|
|
14
|
+
valueArgumentName: "traits",
|
|
15
|
+
callShape: "identify(userId, traits, { externalIds })",
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
kind: "identify",
|
|
19
|
+
userId: parseRequiredString("userId", identifyInput),
|
|
20
|
+
traits: traitsOrOptions,
|
|
21
|
+
options,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
assertNoSegmentExternalIdsInValueArgument({
|
|
25
|
+
argument: identifyInput,
|
|
26
|
+
commandName: "identify",
|
|
27
|
+
valueArgumentName: "traits",
|
|
28
|
+
callShape: "identify(traits, { externalIds })",
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
kind: "identify",
|
|
32
|
+
traits: identifyInput,
|
|
33
|
+
options: options !== null && options !== void 0 ? options : traitsOrOptions,
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export function createNativeProviderClient({ dispatchCommand, flow, instanceId, }) {
|
|
37
|
+
return {
|
|
38
|
+
instanceId,
|
|
39
|
+
configure: (opts, options) => dispatchCommand({ kind: "configure", opts }, options),
|
|
40
|
+
identify: ((identifyInput, traitsOrOptions, options) => dispatchCommand(toIdentifyCommandPayload(identifyInput, traitsOrOptions, options))),
|
|
41
|
+
track: (eventName, properties, options) => {
|
|
42
|
+
assertNoSegmentExternalIdsInValueArgument({
|
|
43
|
+
argument: properties,
|
|
44
|
+
commandName: "track",
|
|
45
|
+
valueArgumentName: "properties",
|
|
46
|
+
callShape: "track(eventName, properties, { externalIds })",
|
|
47
|
+
});
|
|
48
|
+
return dispatchCommand(Object.assign(Object.assign({ kind: "track", origin: "customer", event: parseRequiredString("eventName", eventName) }, (properties === undefined ? {} : { properties })), ((options === null || options === void 0 ? void 0 : options.externalIds) === undefined
|
|
49
|
+
? {}
|
|
50
|
+
: { context: { externalIds: options.externalIds } })));
|
|
51
|
+
},
|
|
52
|
+
open: (flowId, options, commandOptions) => dispatchCommand({
|
|
53
|
+
kind: "open",
|
|
54
|
+
flowId: parseRequiredString("flowId", flowId),
|
|
55
|
+
hideCloseButton: options === null || options === void 0 ? void 0 : options.hideCloseButton,
|
|
56
|
+
}, commandOptions),
|
|
57
|
+
prefetch: (flowId, options) => dispatchCommand({
|
|
58
|
+
kind: "prefetch",
|
|
59
|
+
flowId: parseRequiredString("flowId", flowId),
|
|
60
|
+
}, options),
|
|
61
|
+
prerender: (flowId, options, commandOptions) => dispatchCommand({
|
|
62
|
+
kind: "prerender",
|
|
63
|
+
flowId: parseRequiredString("flowId", flowId),
|
|
64
|
+
hideCloseButton: options === null || options === void 0 ? void 0 : options.hideCloseButton,
|
|
65
|
+
}, commandOptions),
|
|
66
|
+
flow,
|
|
67
|
+
close: (flowHandleId, options) => dispatchCommand(Object.assign({ kind: "close" }, (flowHandleId === undefined
|
|
68
|
+
? {}
|
|
69
|
+
: {
|
|
70
|
+
flowHandleId: parseRequiredString("flowHandleId", flowHandleId),
|
|
71
|
+
})), options),
|
|
72
|
+
reset: (options) => dispatchCommand({ kind: "reset" }, options),
|
|
73
|
+
updateHostContext: (context, options) => dispatchCommand({ kind: "updateHostContext", context }, options),
|
|
74
|
+
emitHostSignal: (name, data, options) => dispatchCommand(Object.assign({ kind: "emitHostSignal", name: parseRequiredString("name", name) }, (data === undefined ? {} : { data })), options),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -13,7 +13,9 @@ export type NativeRuntimeRootProps = {
|
|
|
13
13
|
onCommandSessionChange?: (session: NativeCoreCommandSession | null) => void;
|
|
14
14
|
onError?: (error: Error) => void;
|
|
15
15
|
onInvalidMessage?: (error: Error, value: unknown) => void;
|
|
16
|
+
onStartupTerminalError?: (error: Error) => void;
|
|
16
17
|
startupCommandSettlementTimeoutMs?: number;
|
|
18
|
+
viewNativeViewComponent?: NativeViewHostProjectionProps["nativeViewComponent"];
|
|
17
19
|
viewWebViewComponent?: NativeViewHostProjectionProps["webViewComponent"];
|
|
18
20
|
viewWebViewProps?: NativeViewHostProjectionProps["webViewProps"];
|
|
19
21
|
};
|
|
@@ -28,12 +30,12 @@ type NativeRuntimeConfigureCommand = Omit<CoreCommandEnvelope, "command"> & {
|
|
|
28
30
|
}>;
|
|
29
31
|
};
|
|
30
32
|
type NativeRuntimeStartupCommands = readonly [NativeRuntimeInitCommand] | readonly [NativeRuntimeInitCommand, NativeRuntimeConfigureCommand];
|
|
31
|
-
type NativeProviderRuntimeProps = Omit<NativeRuntimeRootProps, "onCommandSessionChange" | "startupCommands"> & {
|
|
33
|
+
type NativeProviderRuntimeProps = Omit<NativeRuntimeRootProps, "onCommandSessionChange" | "onStartupTerminalError" | "startupCommands"> & {
|
|
32
34
|
initialConfigureOptions?: ConfigureOptions;
|
|
33
35
|
initOptions: InitOptions;
|
|
34
36
|
instanceId: string;
|
|
35
37
|
onCommandSessionChange?: (session: NativeDirectCommandSession | null) => void;
|
|
36
38
|
};
|
|
37
|
-
export declare function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewProps, onCommandSessionChange, onError, onInvalidMessage, startupCommandSettlementTimeoutMs, startupCommands, viewWebViewComponent, viewWebViewProps, }: NativeRuntimeRootProps): ReactElement;
|
|
38
|
-
export declare function NativeProviderRuntime({ initOptions, initialConfigureOptions, instanceId, onCommandSessionChange, ...runtimeProps }: NativeProviderRuntimeProps): ReactElement;
|
|
39
|
+
export declare function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewProps, onCommandSessionChange, onError, onInvalidMessage, onStartupTerminalError, startupCommandSettlementTimeoutMs, startupCommands, viewNativeViewComponent, viewWebViewComponent, viewWebViewProps, }: NativeRuntimeRootProps): ReactElement;
|
|
40
|
+
export declare function NativeProviderRuntime({ initOptions, initialConfigureOptions, instanceId, onCommandSessionChange, onError, ...runtimeProps }: NativeProviderRuntimeProps): ReactElement;
|
|
39
41
|
export {};
|
|
@@ -18,6 +18,7 @@ import { createNativeDirectCommandSession, } from "./native-direct-command-sessi
|
|
|
18
18
|
import { NativeViewHostProjection, } from "./native-view-host-projection.js";
|
|
19
19
|
import { createNativeViewRecordController, } from "./native-view-record-controller.js";
|
|
20
20
|
import { createProviderCommandEnvelope, REACT_NATIVE_CLIENT_META, } from "./provider-command-helpers.js";
|
|
21
|
+
import { useNativeDirectCommandSessionController } from "./use-native-direct-command-session-controller.js";
|
|
21
22
|
const DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS = 30000;
|
|
22
23
|
function dispatchStartupCommand(input) {
|
|
23
24
|
let timeoutId;
|
|
@@ -42,7 +43,7 @@ async function dispatchStartupCommands(input) {
|
|
|
42
43
|
});
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
|
-
export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewProps, onCommandSessionChange, onError, onInvalidMessage, startupCommandSettlementTimeoutMs = DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS, startupCommands, viewWebViewComponent, viewWebViewProps, }) {
|
|
46
|
+
export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewProps, onCommandSessionChange, onError, onInvalidMessage, onStartupTerminalError, startupCommandSettlementTimeoutMs = DEFAULT_STARTUP_COMMAND_SETTLEMENT_TIMEOUT_MS, startupCommands, viewNativeViewComponent, viewWebViewComponent, viewWebViewProps, }) {
|
|
46
47
|
const [coreHostRevision, setCoreHostRevision] = useState(0);
|
|
47
48
|
const [session, setSession] = useState(null);
|
|
48
49
|
const sessionRef = useRef(null);
|
|
@@ -54,6 +55,8 @@ export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewPr
|
|
|
54
55
|
onCommandSessionChangeRef.current = onCommandSessionChange;
|
|
55
56
|
const onInvalidMessageRef = useRef(onInvalidMessage);
|
|
56
57
|
onInvalidMessageRef.current = onInvalidMessage;
|
|
58
|
+
const onStartupTerminalErrorRef = useRef(onStartupTerminalError);
|
|
59
|
+
onStartupTerminalErrorRef.current = onStartupTerminalError;
|
|
57
60
|
const startupCommandsRef = useRef(startupCommands);
|
|
58
61
|
startupCommandsRef.current = startupCommands;
|
|
59
62
|
const reportError = useCallback((error) => {
|
|
@@ -124,6 +127,7 @@ export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewPr
|
|
|
124
127
|
})
|
|
125
128
|
.then(commitSession)
|
|
126
129
|
.catch((error) => {
|
|
130
|
+
var _a;
|
|
127
131
|
if (sessionRef.current !== nextSession) {
|
|
128
132
|
return;
|
|
129
133
|
}
|
|
@@ -131,11 +135,21 @@ export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewPr
|
|
|
131
135
|
commandSessionOwner.dispose();
|
|
132
136
|
commandChannelOwner.dispose();
|
|
133
137
|
controller.dispose();
|
|
134
|
-
|
|
135
|
-
!startupRetryAttemptedRef.current
|
|
138
|
+
const shouldRetry = !(error instanceof CommandSettlementError) &&
|
|
139
|
+
!startupRetryAttemptedRef.current;
|
|
140
|
+
if (shouldRetry) {
|
|
136
141
|
startupRetryAttemptedRef.current = true;
|
|
137
142
|
setCoreHostRevision((revision) => revision + 1);
|
|
138
143
|
}
|
|
144
|
+
else {
|
|
145
|
+
startupRetryAttemptedRef.current = false;
|
|
146
|
+
try {
|
|
147
|
+
(_a = onStartupTerminalErrorRef.current) === null || _a === void 0 ? void 0 : _a.call(onStartupTerminalErrorRef, error instanceof Error ? error : new Error(String(error)));
|
|
148
|
+
}
|
|
149
|
+
catch (observerError) {
|
|
150
|
+
reportError(observerError);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
139
153
|
reportError(error);
|
|
140
154
|
});
|
|
141
155
|
return;
|
|
@@ -199,17 +213,26 @@ export function NativeRuntimeRoot({ coreUrl, coreWebViewComponent, coreWebViewPr
|
|
|
199
213
|
: createElement(NativeViewHostProjection, {
|
|
200
214
|
controller: session.controller,
|
|
201
215
|
key: session.key,
|
|
216
|
+
nativeViewComponent: viewNativeViewComponent,
|
|
202
217
|
onInvalidMessage,
|
|
203
218
|
webViewComponent: viewWebViewComponent,
|
|
204
219
|
webViewProps: viewWebViewProps,
|
|
205
220
|
}));
|
|
206
221
|
}
|
|
207
222
|
export function NativeProviderRuntime(_a) {
|
|
208
|
-
var { initOptions, initialConfigureOptions, instanceId, onCommandSessionChange } = _a, runtimeProps = __rest(_a, ["initOptions", "initialConfigureOptions", "instanceId", "onCommandSessionChange"]);
|
|
223
|
+
var { initOptions, initialConfigureOptions, instanceId, onCommandSessionChange, onError } = _a, runtimeProps = __rest(_a, ["initOptions", "initialConfigureOptions", "instanceId", "onCommandSessionChange", "onError"]);
|
|
224
|
+
const directSessionController = useNativeDirectCommandSessionController();
|
|
209
225
|
const directSessionRef = useRef(null);
|
|
226
|
+
const handleStartupTerminalError = useCallback((error) => {
|
|
227
|
+
directSessionController.rejectUntilAttached(error);
|
|
228
|
+
}, [directSessionController]);
|
|
210
229
|
const handleCommandSessionChange = useCallback((session) => {
|
|
211
230
|
var _a;
|
|
212
231
|
if (session === null) {
|
|
232
|
+
if (directSessionRef.current !== null) {
|
|
233
|
+
directSessionController.detach(directSessionRef.current.directSession);
|
|
234
|
+
directSessionRef.current = null;
|
|
235
|
+
}
|
|
213
236
|
onCommandSessionChange === null || onCommandSessionChange === void 0 ? void 0 : onCommandSessionChange(null);
|
|
214
237
|
return;
|
|
215
238
|
}
|
|
@@ -220,9 +243,10 @@ export function NativeProviderRuntime(_a) {
|
|
|
220
243
|
coreSession: session,
|
|
221
244
|
}),
|
|
222
245
|
};
|
|
246
|
+
directSessionController.attach(directSessionRef.current.directSession);
|
|
223
247
|
}
|
|
224
|
-
onCommandSessionChange === null || onCommandSessionChange === void 0 ? void 0 : onCommandSessionChange(
|
|
225
|
-
}, [onCommandSessionChange]);
|
|
248
|
+
onCommandSessionChange === null || onCommandSessionChange === void 0 ? void 0 : onCommandSessionChange(directSessionController.session);
|
|
249
|
+
}, [directSessionController, onCommandSessionChange]);
|
|
226
250
|
const startupCommands = useMemo(() => {
|
|
227
251
|
const initCommand = createProviderCommandEnvelope({
|
|
228
252
|
clientMeta: REACT_NATIVE_CLIENT_META,
|
|
@@ -240,5 +264,5 @@ export function NativeProviderRuntime(_a) {
|
|
|
240
264
|
}),
|
|
241
265
|
];
|
|
242
266
|
}, [initialConfigureOptions, initOptions, instanceId]);
|
|
243
|
-
return createElement(NativeRuntimeRoot, Object.assign(Object.assign({}, runtimeProps), { onCommandSessionChange: handleCommandSessionChange, startupCommands }));
|
|
267
|
+
return createElement(NativeRuntimeRoot, Object.assign(Object.assign({}, runtimeProps), { onCommandSessionChange: handleCommandSessionChange, onError, onStartupTerminalError: handleStartupTerminalError, startupCommands }));
|
|
244
268
|
}
|
|
@@ -3,7 +3,8 @@ import type { NativeViewRecordController } from "./native-view-record-controller
|
|
|
3
3
|
export type NativeViewHostProjectionProps = {
|
|
4
4
|
controller: NativeViewRecordController;
|
|
5
5
|
onInvalidMessage?: (error: Error, value: unknown) => void;
|
|
6
|
+
nativeViewComponent?: ComponentType<Record<string, unknown>>;
|
|
6
7
|
webViewComponent?: ComponentType<Record<string, unknown>>;
|
|
7
8
|
webViewProps?: Record<string, unknown>;
|
|
8
9
|
};
|
|
9
|
-
export declare function NativeViewHostProjection({ controller, onInvalidMessage, webViewComponent, webViewProps, }: NativeViewHostProjectionProps): ReactElement;
|
|
10
|
+
export declare function NativeViewHostProjection({ controller, nativeViewComponent, onInvalidMessage, webViewComponent, webViewProps, }: NativeViewHostProjectionProps): ReactElement;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { createElement, Fragment, useCallback, useEffect, useRef, useSyncExternalStore, } from "react";
|
|
1
|
+
import { createElement, Fragment, useCallback, useEffect, useMemo, useRef, useSyncExternalStore, } from "react";
|
|
2
|
+
import { NativeViewPresentationSurface } from "./native-view-presentation-surface.js";
|
|
2
3
|
import { ViewWebViewHost } from "./view-webview-host.js";
|
|
3
|
-
function NativeViewHostProjectionEntry({ controller, onInvalidMessage, record, webViewComponent, webViewProps, }) {
|
|
4
|
+
function NativeViewHostProjectionEntry({ controller, nativeViewComponent, onInvalidMessage, record, webViewComponent, webViewProps, }) {
|
|
4
5
|
const detachConnectionRef = useRef(null);
|
|
5
6
|
const detachConnection = useCallback(() => {
|
|
6
7
|
const detach = detachConnectionRef.current;
|
|
@@ -8,15 +9,17 @@ function NativeViewHostProjectionEntry({ controller, onInvalidMessage, record, w
|
|
|
8
9
|
detach === null || detach === void 0 ? void 0 : detach();
|
|
9
10
|
}, []);
|
|
10
11
|
const handleConnected = useCallback((connection) => {
|
|
11
|
-
detachConnection();
|
|
12
12
|
const controllerDetach = controller.attachViewReadinessConnection({
|
|
13
13
|
allocationId: record.allocationId,
|
|
14
14
|
connection,
|
|
15
15
|
});
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
if (controllerDetach) {
|
|
17
|
+
detachConnectionRef.current = controllerDetach;
|
|
18
|
+
}
|
|
19
|
+
}, [controller, record.allocationId]);
|
|
20
|
+
const presentedWebViewProps = useMemo(() => (Object.assign(Object.assign({}, webViewProps), { style: [webViewProps === null || webViewProps === void 0 ? void 0 : webViewProps.style, { flex: 1 }] })), [webViewProps]);
|
|
18
21
|
useEffect(() => detachConnection, [detachConnection]);
|
|
19
|
-
return createElement(ViewWebViewHost, {
|
|
22
|
+
return createElement(NativeViewPresentationSurface, { nativeViewComponent, record }, createElement(ViewWebViewHost, {
|
|
20
23
|
generation: record.generation,
|
|
21
24
|
onConnected: handleConnected,
|
|
22
25
|
onDisconnected: detachConnection,
|
|
@@ -24,13 +27,14 @@ function NativeViewHostProjectionEntry({ controller, onInvalidMessage, record, w
|
|
|
24
27
|
srcdoc: record.srcdoc,
|
|
25
28
|
viewId: record.viewId,
|
|
26
29
|
webViewComponent,
|
|
27
|
-
webViewProps,
|
|
28
|
-
});
|
|
30
|
+
webViewProps: presentedWebViewProps,
|
|
31
|
+
}));
|
|
29
32
|
}
|
|
30
|
-
export function NativeViewHostProjection({ controller, onInvalidMessage, webViewComponent, webViewProps, }) {
|
|
33
|
+
export function NativeViewHostProjection({ controller, nativeViewComponent, onInvalidMessage, webViewComponent, webViewProps, }) {
|
|
31
34
|
const records = useSyncExternalStore(controller.subscribe, controller.getSnapshot, controller.getSnapshot);
|
|
32
35
|
return createElement(Fragment, null, records.map((record) => createElement(NativeViewHostProjectionEntry, {
|
|
33
36
|
controller,
|
|
37
|
+
nativeViewComponent,
|
|
34
38
|
onInvalidMessage,
|
|
35
39
|
record,
|
|
36
40
|
webViewComponent,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ComponentType, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
import type { NativeViewRecord } from "./native-view-record-controller.js";
|
|
3
|
+
export declare function NativeViewPresentationSurface({ children, nativeViewComponent, record, }: {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
nativeViewComponent?: ComponentType<Record<string, unknown>>;
|
|
6
|
+
record: NativeViewRecord;
|
|
7
|
+
}): ReactElement;
|