@getuserfeedback/react-native 4.0.29 → 5.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +12 -150
  2. package/dist/client.d.ts +64 -0
  3. package/dist/client.js +1 -0
  4. package/dist/core-webview-host.d.ts +0 -1
  5. package/dist/core-webview-host.js +2 -12
  6. package/dist/native-core-command-channel.d.ts +1 -0
  7. package/dist/native-core-command-channel.js +20 -4
  8. package/dist/native-provider-client-controller.d.ts +11 -0
  9. package/dist/native-provider-client-controller.js +38 -0
  10. package/dist/native-provider-client.d.ts +3 -17
  11. package/dist/native-provider-command-controller.d.ts +19 -0
  12. package/dist/native-provider-command-controller.js +79 -0
  13. package/dist/native-provider-flow-registry.d.ts +7 -0
  14. package/dist/native-provider-flow-registry.js +70 -0
  15. package/dist/native-provider.d.ts +32 -0
  16. package/dist/native-provider.js +88 -0
  17. package/dist/native-runtime-root.d.ts +2 -4
  18. package/dist/native-runtime-root.js +6 -3
  19. package/dist/native-view-host-projection.d.ts +1 -2
  20. package/dist/native-view-host-projection.js +22 -6
  21. package/dist/native-view-presentation-surface.js +6 -1
  22. package/dist/native-view-record-controller.d.ts +9 -3
  23. package/dist/native-view-record-controller.js +276 -50
  24. package/dist/native-widget-corner-radii.d.ts +1 -2
  25. package/dist/native-widget-corner-radii.js +1 -1
  26. package/dist/provider-command-helpers.d.ts +1 -11
  27. package/dist/provider-command-helpers.js +1 -38
  28. package/dist/public-api.d.ts +2 -1
  29. package/dist/public-api.js +2 -1
  30. package/dist/runtime-endpoints.d.ts +2 -0
  31. package/dist/runtime-endpoints.js +2 -0
  32. package/dist/version.js +1 -1
  33. package/dist/view-orchestration-runtime.js +11 -43
  34. package/dist/view-webview-host-controller.d.ts +1 -0
  35. package/dist/view-webview-host-controller.js +1 -0
  36. package/dist/view-webview-host.d.ts +1 -1
  37. package/dist/view-webview-host.js +3 -7
  38. package/dist/webview-document-host.d.ts +2 -3
  39. package/dist/webview-document-host.js +32 -35
  40. package/package.json +3 -3
  41. package/dist/host-viewport.d.ts +0 -3
  42. package/dist/host-viewport.js +0 -69
  43. package/dist/index.d.ts +0 -91
  44. package/dist/index.js +0 -613
  45. package/dist/provider-command-transport.d.ts +0 -52
  46. package/dist/provider-command-transport.js +0 -150
  47. package/dist/provider-message-queue.d.ts +0 -11
  48. package/dist/provider-message-queue.js +0 -23
  49. package/dist/provider-pending-commands.d.ts +0 -34
  50. package/dist/provider-pending-commands.js +0 -58
  51. package/dist/provider-widget-border-radius.d.ts +0 -11
  52. package/dist/provider-widget-border-radius.js +0 -102
  53. package/dist/provider-widget-frame-appearance.d.ts +0 -17
  54. package/dist/provider-widget-frame-appearance.js +0 -43
  55. package/dist/provider-widget-host-lifecycle.d.ts +0 -46
  56. package/dist/provider-widget-host-lifecycle.js +0 -138
  57. package/dist/provider-widget-host-overlay.d.ts +0 -58
  58. package/dist/provider-widget-host-overlay.js +0 -616
  59. package/dist/use-native-direct-command-session-controller.d.ts +0 -2
  60. package/dist/use-native-direct-command-session-controller.js +0 -21
  61. package/dist/webview-bridge-script.d.ts +0 -16
  62. package/dist/webview-bridge-script.js +0 -283
  63. package/dist/widget-host-lifecycle-machine.d.ts +0 -35
  64. package/dist/widget-host-lifecycle-machine.js +0 -37
  65. package/dist/widget-host.d.ts +0 -38
  66. package/dist/widget-host.js +0 -327
package/dist/index.js DELETED
@@ -1,613 +0,0 @@
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 { CommandSettlementError, CommandSettlementTimeoutError, createFlowCommandHandleController, getFlowHandleFromSettlementDetail, getWidgetLayoutPlanNowMs, } from "@getuserfeedback/protocol/host";
13
- import { parseWebViewTransportNativeMessage } from "@getuserfeedback/protocol/webview-transport";
14
- import { createContext, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
15
- import { useResolvedHostViewport } from "./host-viewport.js";
16
- import { createNativeProviderClient, parseRequiredString, } from "./native-provider-client.js";
17
- import { createProviderCommandEnvelope, REACT_NATIVE_LOADER_CLIENT_META, toCommandSettlementError, toReactNativeOneShotCommand, } from "./provider-command-helpers.js";
18
- import { useProviderCommandTransport } from "./provider-command-transport.js";
19
- import { createProviderWidgetHostLifecycleController, HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY, } from "./provider-widget-host-lifecycle.js";
20
- import { ProviderWidgetHostOverlay, toProviderWidgetHostStyle, toProviderWidgetSheetHostLayoutPlan, } from "./provider-widget-host-overlay.js";
21
- import { WidgetHost, } from "./widget-host.js";
22
- export { REACT_NATIVE_SDK_VERSION } from "./version.js";
23
- export { buildNativeMessageInjectionScript, buildWebViewBridgeScript, } from "./webview-bridge-script.js";
24
- export { WidgetHost };
25
- const GetUserFeedbackNativeContext = createContext(null);
26
- const DEFAULT_COMMAND_TIMEOUT_MS = 30000;
27
- const PROVIDER_UNMOUNTED_ERROR_MESSAGE = "GetUserFeedbackProvider unmounted before command settled";
28
- const STARTUP_COMMAND_REPLACED_ERROR_MESSAGE = "GetUserFeedbackProvider replaced startup command before settlement";
29
- const STALE_HANDLE_ERROR_CODE = "STALE_HANDLE";
30
- const isStaleHandleError = (error) => {
31
- if (error instanceof CommandSettlementError) {
32
- return error.code === STALE_HANDLE_ERROR_CODE;
33
- }
34
- if (!(error instanceof Error)) {
35
- return false;
36
- }
37
- return error.message.includes("flowHandleId is stale");
38
- };
39
- const toFlowHandleIdFromResult = (result) => {
40
- if (!result.settlement) {
41
- return undefined;
42
- }
43
- const handle = getFlowHandleFromSettlementDetail(result.settlement);
44
- return handle === null || handle === void 0 ? void 0 : handle.flowHandleId;
45
- };
46
- const createReactNativeFlowRunController = (flowId, { enqueueFlowCommand, enqueueScopedClose, reportCommandError, }) => {
47
- const handleClient = createFlowCommandHandleController({
48
- getHandleIdFromSettlement: toFlowHandleIdFromResult,
49
- isStaleHandleError,
50
- onClearResolvedHandle: () => { },
51
- });
52
- const reportAsyncCommandError = (promise) => promise.catch((error) => {
53
- reportCommandError(error instanceof Error ? error : new Error(String(error)));
54
- throw error;
55
- });
56
- const reset = () => {
57
- handleClient.reset();
58
- };
59
- const resetIdleHandle = () => {
60
- if (handleClient.hasPendingCommands()) {
61
- return;
62
- }
63
- reset();
64
- };
65
- const enqueueAndWaitForSettlement = async (buildPayload) => {
66
- await handleClient.runCommand(buildPayload, enqueueFlowCommand);
67
- };
68
- return {
69
- flowId,
70
- open: (options) => reportAsyncCommandError(enqueueAndWaitForSettlement((flowHandleId) => ({
71
- kind: "open",
72
- flowId,
73
- flowHandleId,
74
- metadata: options === null || options === void 0 ? void 0 : options.metadata,
75
- hideCloseButton: options === null || options === void 0 ? void 0 : options.hideCloseButton,
76
- }))),
77
- prefetch: () => reportAsyncCommandError(enqueueAndWaitForSettlement((flowHandleId) => ({
78
- kind: "prefetch",
79
- flowId,
80
- flowHandleId,
81
- }))),
82
- prerender: (options) => reportAsyncCommandError(enqueueAndWaitForSettlement((flowHandleId) => ({
83
- kind: "prerender",
84
- flowId,
85
- flowHandleId,
86
- hideCloseButton: options === null || options === void 0 ? void 0 : options.hideCloseButton,
87
- }))),
88
- close: () => {
89
- return reportAsyncCommandError(handleClient.runResolvedHandleCommand((flowHandleId) => flowHandleId, enqueueScopedClose));
90
- },
91
- hasFlowHandleId: (flowHandleId) => handleClient.getHandleId() === flowHandleId,
92
- invalidateResolvedHandle: (flowHandleId) => {
93
- handleClient.invalidateResolvedHandle(flowHandleId);
94
- },
95
- reset,
96
- resetIdleHandle,
97
- };
98
- };
99
- const createUniqueId = (prefix) => {
100
- if (typeof globalThis.crypto !== "undefined" &&
101
- typeof globalThis.crypto.randomUUID === "function") {
102
- return `${prefix}_${globalThis.crypto.randomUUID()}`;
103
- }
104
- return `${prefix}_${Date.now()}_${Math.random().toString(16).slice(2)}`;
105
- };
106
- const createTransportMessageId = () => createUniqueId("native");
107
- const normalizeOptionalString = (value) => {
108
- if (value === undefined) {
109
- return undefined;
110
- }
111
- const normalized = value.trim();
112
- return normalized.length > 0 ? normalized : undefined;
113
- };
114
- const toJsonKey = (value) => JSON.stringify(value);
115
- const toStableHash = (value) => {
116
- const json = toJsonKey(value);
117
- let hash = 0x811c9dc5;
118
- for (let index = 0; index < json.length; index += 1) {
119
- hash ^= json.charCodeAt(index);
120
- hash = Math.imul(hash, 0x01000193);
121
- }
122
- return (hash >>> 0).toString(16);
123
- };
124
- const FallbackNativeView = (_a) => {
125
- var { children } = _a, props = __rest(_a, ["children"]);
126
- return createElement("div", props, children);
127
- };
128
- function resolveReactNativeComponents() {
129
- var _a;
130
- try {
131
- const reactNativeModule = require("react-native");
132
- return {
133
- View: (_a = reactNativeModule.View) !== null && _a !== void 0 ? _a : FallbackNativeView,
134
- };
135
- }
136
- catch (_b) {
137
- return {
138
- View: FallbackNativeView,
139
- };
140
- }
141
- }
142
- export function GetUserFeedbackProvider({ autoInit = true, children, commandTimeoutMs = DEFAULT_COMMAND_TIMEOUT_MS, configureOptions, hostViewport, instanceId: instanceIdProp, initOptions, loaderUrl, onCommandError, onInvalidWebMessage, onWebMessage, source, webViewComponent, webViewProps, }) {
143
- var _a;
144
- const { View: NativeView } = useMemo(resolveReactNativeComponents, []);
145
- const [instanceId] = useState(() => { var _a; return (_a = normalizeOptionalString(instanceIdProp)) !== null && _a !== void 0 ? _a : createUniqueId("rn"); });
146
- const [widgetHostVisibility, setWidgetHostVisibility] = useState(HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY);
147
- const resolvedHostViewport = useResolvedHostViewport(hostViewport);
148
- const initOptionsRef = useRef(initOptions);
149
- const configureOptionsRef = useRef(configureOptions);
150
- const initOptionsKey = useMemo(() => toJsonKey(initOptions), [initOptions]);
151
- const configureOptionsKey = useMemo(() => (configureOptions === undefined ? null : toJsonKey(configureOptions)), [configureOptions]);
152
- const hostSourceKey = useMemo(() => toJsonKey({ loaderUrl: loaderUrl !== null && loaderUrl !== void 0 ? loaderUrl : null, source: source !== null && source !== void 0 ? source : null }), [loaderUrl, source]);
153
- const startupOptionsKey = useMemo(() => toJsonKey({ configureOptionsKey, initOptionsKey }), [configureOptionsKey, initOptionsKey]);
154
- const startupIdempotencyKey = useMemo(() => toStableHash({ configureOptionsKey, initOptionsKey }), [configureOptionsKey, initOptionsKey]);
155
- const widgetHostLifecycleRef = useRef(createProviderWidgetHostLifecycleController(hostSourceKey));
156
- const flowRunsRef = useRef(new Map());
157
- const flowRunControllerOptionsRef = useRef(null);
158
- const widgetHostLifecycle = widgetHostLifecycleRef.current;
159
- const { clearFlowHandleFromVisibility, getCurrentHostEpoch, isWidgetHostVisible: resolveIsWidgetHostVisible, markNotReady, markReady, replaceViewHostSnapshots, syncHostSourceKey, toReadyVisibility, } = widgetHostLifecycle;
160
- const createCommandTimeoutError = useCallback((requestId) => new CommandSettlementTimeoutError(requestId), []);
161
- const transport = useProviderCommandTransport({
162
- commandTimeoutMs,
163
- createTimeoutError: createCommandTimeoutError,
164
- getCurrentHostEpoch,
165
- });
166
- const { nativeMessages, nativeMessagesRef, clearStartupQueuedKey, createPendingCommandPromise, getPendingCommand, getPendingCommandEntries, hasDeliveredPendingCommands, isStartupQueuedKey, pausePendingCommandTimeouts, registerNativeMessage, reissuePendingCommand, removeNativeMessageId, replaceNativeMessages, resetStartupQueuedKeyIfChanged, setStartupQueuedKey, startPendingCommandTimeouts, takePendingCommand, cancelStartupCommands, dispose: disposeCommandTransport, } = transport;
167
- const clearIdleFlowHandles = useCallback(() => {
168
- for (const flowRun of flowRunsRef.current.values()) {
169
- flowRun.resetIdleHandle();
170
- }
171
- }, []);
172
- const resetFlowRuns = useCallback(() => {
173
- for (const flowRun of flowRunsRef.current.values()) {
174
- flowRun.reset();
175
- }
176
- }, []);
177
- if (syncHostSourceKey(hostSourceKey)) {
178
- pausePendingCommandTimeouts();
179
- clearStartupQueuedKey();
180
- clearIdleFlowHandles();
181
- }
182
- initOptionsRef.current = initOptions;
183
- configureOptionsRef.current = configureOptions;
184
- const reportCommandError = useCallback((error) => {
185
- if (error.message === PROVIDER_UNMOUNTED_ERROR_MESSAGE ||
186
- error.message === STARTUP_COMMAND_REPLACED_ERROR_MESSAGE) {
187
- return;
188
- }
189
- if (onCommandError) {
190
- onCommandError(error);
191
- return;
192
- }
193
- setTimeout(() => {
194
- throw error;
195
- }, 0);
196
- }, [onCommandError]);
197
- const enqueueTransportCommand = useCallback((command, options, { isStartup = false, preserveFlowHandle = false, prioritizeStartup = false, } = {}) => {
198
- const envelope = createProviderCommandEnvelope({
199
- clientMeta: REACT_NATIVE_LOADER_CLIENT_META,
200
- command: preserveFlowHandle
201
- ? command
202
- : toReactNativeOneShotCommand(command),
203
- idempotencyKey: options === null || options === void 0 ? void 0 : options.idempotencyKey,
204
- instanceId,
205
- });
206
- const { requestId } = envelope;
207
- const message = {
208
- kind: "enqueueCommand",
209
- id: createTransportMessageId(),
210
- envelope,
211
- };
212
- let validatedMessage;
213
- try {
214
- validatedMessage = parseWebViewTransportNativeMessage(message);
215
- }
216
- catch (error) {
217
- if (isStartup) {
218
- clearStartupQueuedKey();
219
- }
220
- return Promise.reject(error instanceof Error ? error : new Error(String(error)));
221
- }
222
- const result = {
223
- envelope: validatedMessage.envelope,
224
- message: validatedMessage,
225
- };
226
- const promise = createPendingCommandPromise({
227
- isStartup,
228
- message: validatedMessage,
229
- requestId,
230
- result,
231
- });
232
- registerNativeMessage(validatedMessage, { isStartup, prioritizeStartup });
233
- return promise;
234
- }, [
235
- clearStartupQueuedKey,
236
- createPendingCommandPromise,
237
- instanceId,
238
- registerNativeMessage,
239
- ]);
240
- const reissueDeliveredPendingActionCommands = useCallback(() => {
241
- const replacements = new Map();
242
- for (const [requestId, pendingCommand] of getPendingCommandEntries()) {
243
- if (pendingCommand.isStartup || pendingCommand.hostEpoch === null) {
244
- continue;
245
- }
246
- if (pendingCommand.timeout) {
247
- clearTimeout(pendingCommand.timeout);
248
- pendingCommand.timeout = null;
249
- }
250
- const previousEnvelope = pendingCommand.result.envelope;
251
- const nextEnvelope = createProviderCommandEnvelope({
252
- clientMeta: previousEnvelope.clientMeta,
253
- command: toReactNativeOneShotCommand(previousEnvelope.command),
254
- idempotencyKey: previousEnvelope.idempotencyKey,
255
- instanceId: previousEnvelope.instanceId,
256
- });
257
- const nextMessage = parseWebViewTransportNativeMessage({
258
- kind: "enqueueCommand",
259
- id: createTransportMessageId(),
260
- envelope: nextEnvelope,
261
- });
262
- const reissuedCommand = reissuePendingCommand({
263
- nextMessage,
264
- nextRequestId: nextEnvelope.requestId,
265
- nextResult: {
266
- envelope: nextMessage.envelope,
267
- message: nextMessage,
268
- },
269
- requestId,
270
- });
271
- if (!reissuedCommand) {
272
- continue;
273
- }
274
- replacements.set(reissuedCommand.previousMessageId, nextMessage);
275
- }
276
- if (replacements.size === 0) {
277
- return false;
278
- }
279
- replaceNativeMessages(replacements);
280
- return true;
281
- }, [getPendingCommandEntries, reissuePendingCommand, replaceNativeMessages]);
282
- const enqueueStartupCommands = useCallback(({ force = false } = {}) => {
283
- if (!autoInit) {
284
- return;
285
- }
286
- if (!force && isStartupQueuedKey(startupOptionsKey)) {
287
- return;
288
- }
289
- const isReplacingStartup = force || !isStartupQueuedKey(startupOptionsKey);
290
- if (isReplacingStartup) {
291
- cancelStartupCommands(new Error(STARTUP_COMMAND_REPLACED_ERROR_MESSAGE));
292
- }
293
- setStartupQueuedKey(startupOptionsKey);
294
- enqueueTransportCommand({ kind: "init", opts: initOptionsRef.current }, { idempotencyKey: `${instanceId}:init:${startupIdempotencyKey}` }, { isStartup: true, prioritizeStartup: isReplacingStartup }).catch(reportCommandError);
295
- if (configureOptionsRef.current === undefined) {
296
- return;
297
- }
298
- enqueueTransportCommand({ kind: "configure", opts: configureOptionsRef.current }, { idempotencyKey: `${instanceId}:configure:${startupIdempotencyKey}` }, { isStartup: true, prioritizeStartup: isReplacingStartup }).catch(reportCommandError);
299
- }, [
300
- autoInit,
301
- cancelStartupCommands,
302
- enqueueTransportCommand,
303
- instanceId,
304
- isStartupQueuedKey,
305
- reportCommandError,
306
- setStartupQueuedKey,
307
- startupIdempotencyKey,
308
- startupOptionsKey,
309
- ]);
310
- const enqueueCommand = useCallback((command, options) => {
311
- enqueueStartupCommands();
312
- return enqueueTransportCommand(command, options);
313
- }, [enqueueStartupCommands, enqueueTransportCommand]);
314
- const enqueueFlowCommand = useCallback((command) => {
315
- enqueueStartupCommands();
316
- return enqueueTransportCommand(command, undefined, {
317
- preserveFlowHandle: true,
318
- });
319
- }, [enqueueStartupCommands, enqueueTransportCommand]);
320
- const enqueueScopedFlowClose = useCallback((flowHandleId) => enqueueCommand({ kind: "close", flowHandleId }).then(() => { }), [enqueueCommand]);
321
- flowRunControllerOptionsRef.current = {
322
- enqueueFlowCommand,
323
- enqueueScopedClose: enqueueScopedFlowClose,
324
- reportCommandError,
325
- };
326
- const flow = useCallback((flowId) => {
327
- const normalizedFlowId = parseRequiredString("flowId", flowId);
328
- const existing = flowRunsRef.current.get(normalizedFlowId);
329
- if (existing) {
330
- return existing;
331
- }
332
- const created = createReactNativeFlowRunController(normalizedFlowId, {
333
- enqueueFlowCommand: (command) => {
334
- const currentOptions = flowRunControllerOptionsRef.current;
335
- if (!currentOptions) {
336
- return Promise.reject(new Error(PROVIDER_UNMOUNTED_ERROR_MESSAGE));
337
- }
338
- return currentOptions.enqueueFlowCommand(command);
339
- },
340
- enqueueScopedClose: (flowHandleId) => {
341
- const currentOptions = flowRunControllerOptionsRef.current;
342
- if (!currentOptions) {
343
- return Promise.reject(new Error(PROVIDER_UNMOUNTED_ERROR_MESSAGE));
344
- }
345
- return currentOptions.enqueueScopedClose(flowHandleId);
346
- },
347
- reportCommandError: (error) => {
348
- const currentOptions = flowRunControllerOptionsRef.current;
349
- if (!currentOptions) {
350
- return;
351
- }
352
- currentOptions.reportCommandError(error);
353
- },
354
- });
355
- flowRunsRef.current.set(normalizedFlowId, created);
356
- return created;
357
- }, []);
358
- const handleWidgetReady = useCallback((event) => {
359
- const readyResult = markReady(event, {
360
- hasDeliveredPendingCommands: hasDeliveredPendingCommands(),
361
- });
362
- if (readyResult.alreadySeen) {
363
- return false;
364
- }
365
- let didReissueDeliveredCommands = false;
366
- if (readyResult.didResetHostEpoch) {
367
- clearStartupQueuedKey();
368
- clearIdleFlowHandles();
369
- didReissueDeliveredCommands = reissueDeliveredPendingActionCommands();
370
- }
371
- setWidgetHostVisibility((visibility) => readyResult.didResetHostEpoch
372
- ? HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY
373
- : toReadyVisibility(visibility, event));
374
- enqueueStartupCommands({ force: readyResult.previousReady !== null });
375
- startPendingCommandTimeouts();
376
- return didReissueDeliveredCommands;
377
- }, [
378
- enqueueStartupCommands,
379
- clearStartupQueuedKey,
380
- clearIdleFlowHandles,
381
- hasDeliveredPendingCommands,
382
- markReady,
383
- reissueDeliveredPendingActionCommands,
384
- startPendingCommandTimeouts,
385
- toReadyVisibility,
386
- ]);
387
- const handleWidgetReadyStateChange = useCallback((event) => {
388
- if (event.isReady) {
389
- const didReissueDeliveredCommands = handleWidgetReady({
390
- readySequence: event.readySequence,
391
- sourceKey: event.sourceKey,
392
- });
393
- return {
394
- deferNativeMessageInjection: didReissueDeliveredCommands,
395
- };
396
- }
397
- const notReadyResult = markNotReady();
398
- if (notReadyResult.wasReady) {
399
- clearStartupQueuedKey();
400
- clearIdleFlowHandles();
401
- reissueDeliveredPendingActionCommands();
402
- }
403
- setWidgetHostVisibility(HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY);
404
- pausePendingCommandTimeouts();
405
- }, [
406
- clearStartupQueuedKey,
407
- clearIdleFlowHandles,
408
- handleWidgetReady,
409
- markNotReady,
410
- pausePendingCommandTimeouts,
411
- reissueDeliveredPendingActionCommands,
412
- ]);
413
- const handleFlowHandleInvalidated = useCallback((flowHandleId) => {
414
- for (const flowRun of flowRunsRef.current.values()) {
415
- if (flowRun.hasFlowHandleId(flowHandleId)) {
416
- flowRun.invalidateResolvedHandle(flowHandleId);
417
- }
418
- }
419
- setWidgetHostVisibility((visibility) => clearFlowHandleFromVisibility(visibility, flowHandleId));
420
- }, [clearFlowHandleFromVisibility]);
421
- const handleWebMessage = useCallback((message) => {
422
- if (message.kind === "hostEvent" &&
423
- message.event.name === "instance:handle:invalidated" &&
424
- message.event.detail.handleKind === "flow") {
425
- handleFlowHandleInvalidated(message.event.detail.handleId);
426
- }
427
- if (message.kind === "hostEvent" &&
428
- message.event.name === "instance:view-host:snapshots-changed") {
429
- const visibility = replaceViewHostSnapshots(message.event.detail, instanceId);
430
- if (visibility) {
431
- setWidgetHostVisibility(visibility);
432
- }
433
- }
434
- if (message.kind === "hostEvent" &&
435
- message.event.name === "instance:command:settled") {
436
- const requestId = message.event.detail.requestId;
437
- const pendingCommand = getPendingCommand(requestId);
438
- if (pendingCommand) {
439
- if (pendingCommand.hostEpoch !== null &&
440
- pendingCommand.hostEpoch !== getCurrentHostEpoch()) {
441
- onWebMessage === null || onWebMessage === void 0 ? void 0 : onWebMessage(message);
442
- return;
443
- }
444
- takePendingCommand(requestId);
445
- removeNativeMessageId(pendingCommand.messageId);
446
- if (pendingCommand.timeout) {
447
- clearTimeout(pendingCommand.timeout);
448
- }
449
- const error = toCommandSettlementError(message.event);
450
- if (error) {
451
- if (pendingCommand.isStartup) {
452
- clearStartupQueuedKey();
453
- }
454
- pendingCommand.reject(error);
455
- }
456
- else {
457
- const settlement = message.event
458
- .detail;
459
- if (pendingCommand.result.envelope.command.kind === "reset") {
460
- resetFlowRuns();
461
- }
462
- const settledResult = Object.assign(Object.assign({}, pendingCommand.result), { settlement, settlementResult: settlement.result });
463
- pendingCommand.resolve(settledResult);
464
- }
465
- }
466
- }
467
- onWebMessage === null || onWebMessage === void 0 ? void 0 : onWebMessage(message);
468
- }, [
469
- clearStartupQueuedKey,
470
- resetFlowRuns,
471
- getCurrentHostEpoch,
472
- getPendingCommand,
473
- handleFlowHandleInvalidated,
474
- instanceId,
475
- onWebMessage,
476
- replaceViewHostSnapshots,
477
- removeNativeMessageId,
478
- takePendingCommand,
479
- ]);
480
- useEffect(() => () => {
481
- flowRunControllerOptionsRef.current = null;
482
- disposeCommandTransport(new Error(PROVIDER_UNMOUNTED_ERROR_MESSAGE));
483
- }, [disposeCommandTransport]);
484
- const getNativeMessages = useCallback(() => nativeMessagesRef.current, [nativeMessagesRef]);
485
- const contextValue = useMemo(() => {
486
- const client = createNativeProviderClient({
487
- dispatchCommand: enqueueCommand,
488
- flow,
489
- instanceId,
490
- });
491
- return {
492
- close: client.close,
493
- configure: client.configure,
494
- emitHostSignal: client.emitHostSignal,
495
- enqueueCommand,
496
- flow: client.flow,
497
- handleWebMessage,
498
- identify: client.identify,
499
- instanceId: client.instanceId,
500
- get nativeMessages() {
501
- return getNativeMessages();
502
- },
503
- reset: client.reset,
504
- track: client.track,
505
- updateHostContext: client.updateHostContext,
506
- };
507
- }, [enqueueCommand, flow, getNativeMessages, handleWebMessage, instanceId]);
508
- const previousSheetHostLayoutUpdateRef = useRef(undefined);
509
- const consumedTransitionPolicySequenceRef = useRef(undefined);
510
- useEffect(() => {
511
- resetStartupQueuedKeyIfChanged(startupOptionsKey);
512
- enqueueStartupCommands();
513
- }, [
514
- enqueueStartupCommands,
515
- resetStartupQueuedKeyIfChanged,
516
- startupOptionsKey,
517
- ]);
518
- const providerHostViewport = hostViewport !== null && hostViewport !== void 0 ? hostViewport : resolvedHostViewport;
519
- const transitionPolicySequence = widgetHostVisibility.transitionPolicySequence;
520
- const pendingTransitionPolicy = transitionPolicySequence !== undefined &&
521
- consumedTransitionPolicySequenceRef.current !== transitionPolicySequence
522
- ? widgetHostVisibility.transitionPolicy
523
- : undefined;
524
- const sheetHostLayoutPlan = toProviderWidgetSheetHostLayoutPlan({
525
- previous: previousSheetHostLayoutUpdateRef.current,
526
- viewport: providerHostViewport,
527
- flowSize: {
528
- height: widgetHostVisibility.flowHeight,
529
- },
530
- nowMs: getWidgetLayoutPlanNowMs(),
531
- transitionPolicy: pendingTransitionPolicy,
532
- });
533
- useEffect(() => {
534
- if (transitionPolicySequence !== undefined &&
535
- pendingTransitionPolicy !== undefined &&
536
- sheetHostLayoutPlan !== undefined) {
537
- consumedTransitionPolicySequenceRef.current = transitionPolicySequence;
538
- }
539
- }, [pendingTransitionPolicy, sheetHostLayoutPlan, transitionPolicySequence]);
540
- let sheetHostLayoutUpdate;
541
- if (sheetHostLayoutPlan) {
542
- switch (sheetHostLayoutPlan.kind) {
543
- case "unchanged":
544
- sheetHostLayoutUpdate =
545
- (_a = previousSheetHostLayoutUpdateRef.current) !== null && _a !== void 0 ? _a : sheetHostLayoutPlan.update;
546
- break;
547
- case "instant": {
548
- const previousSheetHostLayoutUpdate = previousSheetHostLayoutUpdateRef.current;
549
- sheetHostLayoutUpdate =
550
- pendingTransitionPolicy === undefined &&
551
- (previousSheetHostLayoutUpdate === null || previousSheetHostLayoutUpdate === void 0 ? void 0 : previousSheetHostLayoutUpdate.transition.kind) === "timed" &&
552
- previousSheetHostLayoutUpdate.size.height ===
553
- sheetHostLayoutPlan.size.height
554
- ? Object.assign(Object.assign({}, previousSheetHostLayoutUpdate), { size: sheetHostLayoutPlan.size }) : sheetHostLayoutPlan.update;
555
- break;
556
- }
557
- case "timed":
558
- sheetHostLayoutUpdate = sheetHostLayoutPlan.update;
559
- break;
560
- default: {
561
- const unreachable = sheetHostLayoutPlan;
562
- throw new Error(`Unsupported widget layout transition plan: ${JSON.stringify(unreachable)}`);
563
- }
564
- }
565
- }
566
- const isWidgetHostVisible = resolveIsWidgetHostVisible(widgetHostVisibility, sheetHostLayoutUpdate !== undefined);
567
- useEffect(() => {
568
- previousSheetHostLayoutUpdateRef.current = isWidgetHostVisible
569
- ? sheetHostLayoutUpdate
570
- : undefined;
571
- }, [isWidgetHostVisible, sheetHostLayoutUpdate]);
572
- const widgetHostViewport = providerHostViewport;
573
- const composedWebViewStyle = toProviderWidgetHostStyle({
574
- isVisible: isWidgetHostVisible,
575
- webViewStyle: webViewProps === null || webViewProps === void 0 ? void 0 : webViewProps.style,
576
- });
577
- const widgetHost = createElement(WidgetHost, {
578
- hostViewport: widgetHostViewport,
579
- instanceId,
580
- loaderUrl,
581
- nativeMessages,
582
- onInvalidWebMessage,
583
- onReadyStateChange: handleWidgetReadyStateChange,
584
- onWebMessage: handleWebMessage,
585
- source,
586
- webViewComponent,
587
- webViewProps: Object.assign(Object.assign({}, webViewProps), { pointerEvents: isWidgetHostVisible ? "auto" : "none", style: composedWebViewStyle }),
588
- });
589
- const handleWidgetHostDismiss = useCallback(() => {
590
- enqueueCommand(Object.assign({ kind: "close" }, (widgetHostVisibility.flowHandleId === undefined
591
- ? {}
592
- : { flowHandleId: widgetHostVisibility.flowHandleId }))).catch(reportCommandError);
593
- }, [enqueueCommand, reportCommandError, widgetHostVisibility.flowHandleId]);
594
- return createElement(GetUserFeedbackNativeContext.Provider, {
595
- value: contextValue,
596
- }, children, createElement(ProviderWidgetHostOverlay, {
597
- frameAppearance: widgetHostVisibility.frameAppearance,
598
- isVisible: isWidgetHostVisible,
599
- nativeView: NativeView,
600
- onRequestDismiss: handleWidgetHostDismiss,
601
- sheetHostLayoutUpdate,
602
- transitionSequence: transitionPolicySequence,
603
- transitionSchedule: widgetHostVisibility.transitionSchedule,
604
- }, widgetHost));
605
- }
606
- export function useGetUserFeedbackNative() {
607
- const context = useContext(GetUserFeedbackNativeContext);
608
- if (context === null) {
609
- throw new Error("useGetUserFeedbackNative must be used within GetUserFeedbackProvider");
610
- }
611
- return context;
612
- }
613
- export const useGetUserFeedback = useGetUserFeedbackNative;
@@ -1,52 +0,0 @@
1
- import type { WebViewTransportNativeMessage } from "@getuserfeedback/protocol/webview-transport";
2
- import { type ProviderPendingCommand } from "./provider-pending-commands.js";
3
- export type ProviderCommandTransportOptions = {
4
- commandTimeoutMs: number;
5
- createTimeoutError: (requestId: string) => Error;
6
- getCurrentHostEpoch: () => number | null;
7
- };
8
- type ProviderPendingCommandRegistration<Result> = {
9
- isStartup: boolean;
10
- message: WebViewTransportNativeMessage;
11
- requestId: string;
12
- result: Result;
13
- };
14
- type ProviderPendingCommandReissue<Result> = {
15
- nextMessage: WebViewTransportNativeMessage;
16
- nextRequestId: string;
17
- nextResult: Result;
18
- requestId: string;
19
- };
20
- export type ProviderCommandTransport<Result> = {
21
- clearStartupQueuedKey: () => void;
22
- createPendingCommandPromise: (input: ProviderPendingCommandRegistration<Result>) => Promise<Result>;
23
- dispose: (error: Error) => void;
24
- getPendingCommand: (requestId: string) => ProviderPendingCommand<Result> | undefined;
25
- getPendingCommandEntries: () => Array<[
26
- string,
27
- ProviderPendingCommand<Result>
28
- ]>;
29
- hasDeliveredPendingCommands: () => boolean;
30
- isStartupQueuedKey: (key: string) => boolean;
31
- nativeMessages: WebViewTransportNativeMessage[];
32
- nativeMessagesRef: {
33
- current: WebViewTransportNativeMessage[];
34
- };
35
- pausePendingCommandTimeouts: () => void;
36
- registerNativeMessage: (message: WebViewTransportNativeMessage, options: {
37
- isStartup: boolean;
38
- prioritizeStartup: boolean;
39
- }) => void;
40
- reissuePendingCommand: (input: ProviderPendingCommandReissue<Result>) => {
41
- previousMessageId: string;
42
- } | null;
43
- removeNativeMessageId: (messageId: string) => void;
44
- replaceNativeMessages: (replacements: ReadonlyMap<string, WebViewTransportNativeMessage>) => void;
45
- resetStartupQueuedKeyIfChanged: (key: string) => void;
46
- setStartupQueuedKey: (key: string) => void;
47
- startPendingCommandTimeouts: () => void;
48
- takePendingCommand: (requestId: string) => ProviderPendingCommand<Result> | undefined;
49
- cancelStartupCommands: (error: Error) => void;
50
- };
51
- export declare function useProviderCommandTransport<Result>({ commandTimeoutMs, createTimeoutError, getCurrentHostEpoch, }: ProviderCommandTransportOptions): ProviderCommandTransport<Result>;
52
- export {};