@getuserfeedback/react-native 1.3.12 → 1.3.14
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 +86 -188
- package/dist/provider-command-transport.d.ts +54 -0
- package/dist/provider-command-transport.js +153 -0
- package/dist/provider-widget-host-lifecycle.d.ts +46 -0
- package/dist/provider-widget-host-lifecycle.js +82 -0
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -14,9 +14,9 @@ import { parseWebViewTransportNativeMessage } from "@getuserfeedback/protocol/we
|
|
|
14
14
|
import { createContext, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
|
|
15
15
|
import { useResolvedHostViewport } from "./host-viewport.js";
|
|
16
16
|
import { toCommandFlowId, toCommandSettlementError, toRetryWithoutFlowHandle, } from "./provider-command-helpers.js";
|
|
17
|
+
import { useProviderCommandTransport } from "./provider-command-transport.js";
|
|
17
18
|
import { clearProviderFlowHandleCache, createProviderFlowHandleCache, deleteCachedProviderFlowHandleId, deleteCachedProviderFlowId, getCachedProviderFlowHandleId, snapshotProviderFlowCommand, writeSettledProviderFlowHandleId, } from "./provider-flow-handle-cache.js";
|
|
18
|
-
import {
|
|
19
|
-
import { cancelProviderStartupCommands, clearProviderPendingCommands, createProviderPendingCommandRegistry, getProviderPendingCommand, getProviderPendingCommandEntries, getProviderPendingCommands, hasDeliveredProviderPendingCommands, isProviderPendingMessageStartup, registerProviderPendingCommand, reissueProviderPendingCommand, takeProviderPendingCommand, } from "./provider-pending-commands.js";
|
|
19
|
+
import { createProviderWidgetHostLifecycleController, HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY, } from "./provider-widget-host-lifecycle.js";
|
|
20
20
|
import { ProviderWidgetHostOverlay, toProviderWidgetHostStyle, toProviderWidgetSheetHostViewport, } from "./provider-widget-host-overlay.js";
|
|
21
21
|
import { REACT_NATIVE_SDK_VERSION } from "./version.js";
|
|
22
22
|
import { WidgetHost, } from "./widget-host.js";
|
|
@@ -33,12 +33,6 @@ const CLIENT_META = {
|
|
|
33
33
|
loader: "sdk",
|
|
34
34
|
transport: "loader",
|
|
35
35
|
};
|
|
36
|
-
const HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY = {
|
|
37
|
-
hostSourceVersion: null,
|
|
38
|
-
isVisible: false,
|
|
39
|
-
readySequence: null,
|
|
40
|
-
sourceKey: null,
|
|
41
|
-
};
|
|
42
36
|
const createUniqueId = (prefix) => {
|
|
43
37
|
if (typeof globalThis.crypto !== "undefined" &&
|
|
44
38
|
typeof globalThis.crypto.randomUUID === "function") {
|
|
@@ -118,15 +112,10 @@ const toIdentifyCommandPayload = (identifyInput, traitsOrOptions, options) => {
|
|
|
118
112
|
};
|
|
119
113
|
};
|
|
120
114
|
export function GetUserFeedbackProvider({ autoInit = true, children, commandTimeoutMs = DEFAULT_COMMAND_TIMEOUT_MS, configureOptions, hostViewport, instanceId: instanceIdProp, initOptions, loaderUrl, onCommandError, onInvalidWebMessage, onWebMessage, source, webViewComponent, webViewProps, }) {
|
|
121
|
-
var _a, _b;
|
|
122
115
|
const { View: NativeView } = useMemo(resolveReactNativeComponents, []);
|
|
123
116
|
const [instanceId] = useState(() => { var _a; return (_a = normalizeOptionalString(instanceIdProp)) !== null && _a !== void 0 ? _a : createUniqueId("rn"); });
|
|
124
|
-
const [nativeMessages, setNativeMessages] = useState([]);
|
|
125
117
|
const [widgetHostVisibility, setWidgetHostVisibility] = useState(HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY);
|
|
126
118
|
const resolvedHostViewport = useResolvedHostViewport(hostViewport);
|
|
127
|
-
const nativeMessagesRef = useRef([]);
|
|
128
|
-
const pendingCommandsRef = useRef(createProviderPendingCommandRegistry());
|
|
129
|
-
const hostEpochRef = useRef(0);
|
|
130
119
|
const flowHandleCacheRef = useRef(createProviderFlowHandleCache());
|
|
131
120
|
const initOptionsRef = useRef(initOptions);
|
|
132
121
|
const configureOptionsRef = useRef(configureOptions);
|
|
@@ -135,28 +124,23 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
135
124
|
const hostSourceKey = useMemo(() => toJsonKey({ loaderUrl: loaderUrl !== null && loaderUrl !== void 0 ? loaderUrl : null, source: source !== null && source !== void 0 ? source : null }), [loaderUrl, source]);
|
|
136
125
|
const startupOptionsKey = useMemo(() => toJsonKey({ configureOptionsKey, initOptionsKey }), [configureOptionsKey, initOptionsKey]);
|
|
137
126
|
const startupIdempotencyKey = useMemo(() => toStableHash({ configureOptionsKey, initOptionsKey }), [configureOptionsKey, initOptionsKey]);
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
pendingCommand.timeout = null;
|
|
152
|
-
}
|
|
153
|
-
lastReadyRef.current = null;
|
|
154
|
-
startupQueuedKeyRef.current = null;
|
|
127
|
+
const widgetHostLifecycleRef = useRef(createProviderWidgetHostLifecycleController(hostSourceKey));
|
|
128
|
+
const widgetHostLifecycle = widgetHostLifecycleRef.current;
|
|
129
|
+
const { clearFlowHandleFromVisibility, getCurrentHostEpoch, isWidgetHostVisible: resolveIsWidgetHostVisible, markNotReady, markReady, syncHostSourceKey, toFlowStateVisibility, toReadyVisibility, } = widgetHostLifecycle;
|
|
130
|
+
const createCommandTimeoutError = useCallback((requestId) => new CommandSettlementTimeoutError(requestId), []);
|
|
131
|
+
const transport = useProviderCommandTransport({
|
|
132
|
+
commandTimeoutMs,
|
|
133
|
+
createTimeoutError: createCommandTimeoutError,
|
|
134
|
+
getCurrentHostEpoch,
|
|
135
|
+
});
|
|
136
|
+
const { nativeMessages, nativeMessagesRef, clearStartupQueuedKey, createPendingCommandPromise, getPendingCommand, getPendingCommandEntries, hasDeliveredPendingCommands, isStartupQueuedKey, pausePendingCommandTimeouts, registerNativeMessage, reissuePendingCommand, removeNativeMessageId, replaceNativeMessages, resetStartupQueuedKeyIfChanged, setStartupQueuedKey, startPendingCommandTimeouts, takePendingCommand, cancelStartupCommands, dispose: disposeCommandTransport, } = transport;
|
|
137
|
+
if (syncHostSourceKey(hostSourceKey)) {
|
|
138
|
+
pausePendingCommandTimeouts();
|
|
139
|
+
clearStartupQueuedKey();
|
|
155
140
|
clearProviderFlowHandleCache(flowHandleCacheRef.current);
|
|
156
141
|
}
|
|
157
142
|
initOptionsRef.current = initOptions;
|
|
158
143
|
configureOptionsRef.current = configureOptions;
|
|
159
|
-
nativeMessagesRef.current = nativeMessages;
|
|
160
144
|
const reportCommandError = useCallback((error) => {
|
|
161
145
|
if (error.message === PROVIDER_UNMOUNTED_ERROR_MESSAGE ||
|
|
162
146
|
error.message === STARTUP_COMMAND_REPLACED_ERROR_MESSAGE) {
|
|
@@ -170,45 +154,6 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
170
154
|
throw error;
|
|
171
155
|
}, 0);
|
|
172
156
|
}, [onCommandError]);
|
|
173
|
-
const rejectPendingCommand = useCallback((requestId, pendingCommand, error) => {
|
|
174
|
-
takeProviderPendingCommand(pendingCommandsRef.current, requestId);
|
|
175
|
-
if (pendingCommand.timeout) {
|
|
176
|
-
clearTimeout(pendingCommand.timeout);
|
|
177
|
-
pendingCommand.timeout = null;
|
|
178
|
-
}
|
|
179
|
-
if (pendingCommand.isStartup) {
|
|
180
|
-
startupQueuedKeyRef.current = null;
|
|
181
|
-
}
|
|
182
|
-
setNativeMessages((messages) => removeProviderNativeMessageId(messages, pendingCommand.messageId));
|
|
183
|
-
pendingCommand.reject(error);
|
|
184
|
-
}, []);
|
|
185
|
-
const startPendingCommandTimeout = useCallback((requestId, pendingCommand) => {
|
|
186
|
-
var _a, _b;
|
|
187
|
-
pendingCommand.hostEpoch = (_b = (_a = lastReadyRef.current) === null || _a === void 0 ? void 0 : _a.hostEpoch) !== null && _b !== void 0 ? _b : null;
|
|
188
|
-
if (commandTimeoutMs <= 0) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
if (pendingCommand.timeout) {
|
|
192
|
-
clearTimeout(pendingCommand.timeout);
|
|
193
|
-
}
|
|
194
|
-
pendingCommand.timeout = setTimeout(() => {
|
|
195
|
-
rejectPendingCommand(requestId, pendingCommand, new CommandSettlementTimeoutError(requestId));
|
|
196
|
-
}, commandTimeoutMs);
|
|
197
|
-
}, [commandTimeoutMs, rejectPendingCommand]);
|
|
198
|
-
const startPendingCommandTimeouts = useCallback(() => {
|
|
199
|
-
for (const [requestId, pendingCommand] of getProviderPendingCommandEntries(pendingCommandsRef.current)) {
|
|
200
|
-
startPendingCommandTimeout(requestId, pendingCommand);
|
|
201
|
-
}
|
|
202
|
-
}, [startPendingCommandTimeout]);
|
|
203
|
-
const pausePendingCommandTimeouts = useCallback(() => {
|
|
204
|
-
for (const pendingCommand of getProviderPendingCommands(pendingCommandsRef.current)) {
|
|
205
|
-
if (!pendingCommand.timeout) {
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
clearTimeout(pendingCommand.timeout);
|
|
209
|
-
pendingCommand.timeout = null;
|
|
210
|
-
}
|
|
211
|
-
}, []);
|
|
212
157
|
const enqueueTransportCommand = useCallback((command, options, { isStartup = false, prioritizeStartup = false, } = {}) => {
|
|
213
158
|
var _a;
|
|
214
159
|
const requestId = createCommandRequestId();
|
|
@@ -232,7 +177,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
232
177
|
}
|
|
233
178
|
catch (error) {
|
|
234
179
|
if (isStartup) {
|
|
235
|
-
|
|
180
|
+
clearStartupQueuedKey();
|
|
236
181
|
}
|
|
237
182
|
return Promise.reject(error instanceof Error ? error : new Error(String(error)));
|
|
238
183
|
}
|
|
@@ -241,35 +186,26 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
241
186
|
message: validatedMessage,
|
|
242
187
|
};
|
|
243
188
|
const flowCommandSnapshot = snapshotProviderFlowCommand(flowHandleCacheRef.current, validatedMessage.envelope.command);
|
|
244
|
-
const promise =
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
flowHandleCacheEpoch: flowCommandSnapshot.flowHandleCacheEpoch,
|
|
248
|
-
hostEpoch: null,
|
|
249
|
-
isStartup,
|
|
250
|
-
messageId: validatedMessage.id,
|
|
251
|
-
reject,
|
|
252
|
-
resolve,
|
|
253
|
-
result,
|
|
254
|
-
timeout: null,
|
|
255
|
-
};
|
|
256
|
-
registerProviderPendingCommand(pendingCommandsRef.current, requestId, pendingCommand);
|
|
257
|
-
if (lastReadyRef.current !== null) {
|
|
258
|
-
startPendingCommandTimeout(requestId, pendingCommand);
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
setNativeMessages((messages) => enqueueProviderNativeMessage(messages, {
|
|
189
|
+
const promise = createPendingCommandPromise({
|
|
190
|
+
flowCommandSequence: flowCommandSnapshot.flowCommandSequence,
|
|
191
|
+
flowHandleCacheEpoch: flowCommandSnapshot.flowHandleCacheEpoch,
|
|
262
192
|
isStartup,
|
|
263
|
-
isStartupMessage: (entry) => isProviderPendingMessageStartup(pendingCommandsRef.current, entry.envelope.requestId),
|
|
264
193
|
message: validatedMessage,
|
|
265
|
-
|
|
266
|
-
|
|
194
|
+
requestId,
|
|
195
|
+
result,
|
|
196
|
+
});
|
|
197
|
+
registerNativeMessage(validatedMessage, { isStartup, prioritizeStartup });
|
|
267
198
|
return promise;
|
|
268
|
-
}, [
|
|
199
|
+
}, [
|
|
200
|
+
clearStartupQueuedKey,
|
|
201
|
+
createPendingCommandPromise,
|
|
202
|
+
instanceId,
|
|
203
|
+
registerNativeMessage,
|
|
204
|
+
]);
|
|
269
205
|
const reissueDeliveredPendingActionCommands = useCallback(() => {
|
|
270
206
|
var _a;
|
|
271
207
|
const replacements = new Map();
|
|
272
|
-
for (const [requestId, pendingCommand] of
|
|
208
|
+
for (const [requestId, pendingCommand] of getPendingCommandEntries()) {
|
|
273
209
|
if (pendingCommand.isStartup || pendingCommand.hostEpoch === null) {
|
|
274
210
|
continue;
|
|
275
211
|
}
|
|
@@ -284,9 +220,9 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
284
220
|
id: createTransportMessageId(),
|
|
285
221
|
envelope: nextEnvelope,
|
|
286
222
|
});
|
|
287
|
-
const reissuedCommand =
|
|
223
|
+
const reissuedCommand = reissuePendingCommand({
|
|
288
224
|
flowHandleCacheEpoch: flowHandleCacheRef.current.epoch,
|
|
289
|
-
|
|
225
|
+
nextMessage,
|
|
290
226
|
nextRequestId: nextEnvelope.requestId,
|
|
291
227
|
nextResult: {
|
|
292
228
|
envelope: nextMessage.envelope,
|
|
@@ -302,34 +238,21 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
302
238
|
if (replacements.size === 0) {
|
|
303
239
|
return false;
|
|
304
240
|
}
|
|
305
|
-
|
|
241
|
+
replaceNativeMessages(replacements);
|
|
306
242
|
return true;
|
|
307
|
-
}, []);
|
|
308
|
-
const cancelPendingStartupCommands = useCallback(() => {
|
|
309
|
-
const canceled = cancelProviderStartupCommands(pendingCommandsRef.current);
|
|
310
|
-
for (const pendingCommand of canceled.commands) {
|
|
311
|
-
if (pendingCommand.timeout) {
|
|
312
|
-
clearTimeout(pendingCommand.timeout);
|
|
313
|
-
}
|
|
314
|
-
pendingCommand.reject(new Error(STARTUP_COMMAND_REPLACED_ERROR_MESSAGE));
|
|
315
|
-
}
|
|
316
|
-
if (canceled.messageIds.size === 0) {
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
setNativeMessages((messages) => removeProviderNativeMessageIds(messages, canceled.messageIds));
|
|
320
|
-
}, []);
|
|
243
|
+
}, [getPendingCommandEntries, reissuePendingCommand, replaceNativeMessages]);
|
|
321
244
|
const enqueueStartupCommands = useCallback(({ force = false } = {}) => {
|
|
322
245
|
if (!autoInit) {
|
|
323
246
|
return;
|
|
324
247
|
}
|
|
325
|
-
if (!force &&
|
|
248
|
+
if (!force && isStartupQueuedKey(startupOptionsKey)) {
|
|
326
249
|
return;
|
|
327
250
|
}
|
|
328
|
-
const isReplacingStartup = force ||
|
|
251
|
+
const isReplacingStartup = force || !isStartupQueuedKey(startupOptionsKey);
|
|
329
252
|
if (isReplacingStartup) {
|
|
330
|
-
|
|
253
|
+
cancelStartupCommands(new Error(STARTUP_COMMAND_REPLACED_ERROR_MESSAGE));
|
|
331
254
|
}
|
|
332
|
-
|
|
255
|
+
setStartupQueuedKey(startupOptionsKey);
|
|
333
256
|
enqueueTransportCommand({ kind: "init", opts: initOptionsRef.current }, { idempotencyKey: `${instanceId}:init:${startupIdempotencyKey}` }, { isStartup: true, prioritizeStartup: isReplacingStartup }).catch(reportCommandError);
|
|
334
257
|
if (configureOptionsRef.current === undefined) {
|
|
335
258
|
return;
|
|
@@ -337,10 +260,12 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
337
260
|
enqueueTransportCommand({ kind: "configure", opts: configureOptionsRef.current }, { idempotencyKey: `${instanceId}:configure:${startupIdempotencyKey}` }, { isStartup: true, prioritizeStartup: isReplacingStartup }).catch(reportCommandError);
|
|
338
261
|
}, [
|
|
339
262
|
autoInit,
|
|
340
|
-
|
|
263
|
+
cancelStartupCommands,
|
|
341
264
|
enqueueTransportCommand,
|
|
342
265
|
instanceId,
|
|
266
|
+
isStartupQueuedKey,
|
|
343
267
|
reportCommandError,
|
|
268
|
+
setStartupQueuedKey,
|
|
344
269
|
startupIdempotencyKey,
|
|
345
270
|
startupOptionsKey,
|
|
346
271
|
]);
|
|
@@ -349,36 +274,30 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
349
274
|
return enqueueTransportCommand(command, options);
|
|
350
275
|
}, [enqueueStartupCommands, enqueueTransportCommand]);
|
|
351
276
|
const handleWidgetReady = useCallback((event) => {
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
if (alreadySeen) {
|
|
277
|
+
const readyResult = markReady(event, {
|
|
278
|
+
hasDeliveredPendingCommands: hasDeliveredPendingCommands(),
|
|
279
|
+
});
|
|
280
|
+
if (readyResult.alreadySeen) {
|
|
356
281
|
return false;
|
|
357
282
|
}
|
|
358
|
-
const hasDeliveredPendingCommands = hasDeliveredProviderPendingCommands(pendingCommandsRef.current);
|
|
359
283
|
let didReissueDeliveredCommands = false;
|
|
360
|
-
if (
|
|
361
|
-
|
|
362
|
-
startupQueuedKeyRef.current = null;
|
|
284
|
+
if (readyResult.didResetHostEpoch) {
|
|
285
|
+
clearStartupQueuedKey();
|
|
363
286
|
clearProviderFlowHandleCache(flowHandleCacheRef.current);
|
|
364
287
|
didReissueDeliveredCommands = reissueDeliveredPendingActionCommands();
|
|
365
288
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
if (!visibility.isVisible ||
|
|
369
|
-
visibility.sourceKey !== event.sourceKey ||
|
|
370
|
-
visibility.hostSourceVersion !== hostSourceVersionRef.current) {
|
|
371
|
-
return visibility;
|
|
372
|
-
}
|
|
373
|
-
return Object.assign(Object.assign({}, visibility), { readySequence: event.readySequence });
|
|
374
|
-
});
|
|
375
|
-
enqueueStartupCommands({ force: previous !== null });
|
|
289
|
+
setWidgetHostVisibility((visibility) => toReadyVisibility(visibility, event));
|
|
290
|
+
enqueueStartupCommands({ force: readyResult.previousReady !== null });
|
|
376
291
|
startPendingCommandTimeouts();
|
|
377
292
|
return didReissueDeliveredCommands;
|
|
378
293
|
}, [
|
|
379
294
|
enqueueStartupCommands,
|
|
295
|
+
clearStartupQueuedKey,
|
|
296
|
+
hasDeliveredPendingCommands,
|
|
297
|
+
markReady,
|
|
380
298
|
reissueDeliveredPendingActionCommands,
|
|
381
299
|
startPendingCommandTimeouts,
|
|
300
|
+
toReadyVisibility,
|
|
382
301
|
]);
|
|
383
302
|
const handleWidgetReadyStateChange = useCallback((event) => {
|
|
384
303
|
if (event.isReady) {
|
|
@@ -390,17 +309,18 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
390
309
|
deferNativeMessageInjection: didReissueDeliveredCommands,
|
|
391
310
|
};
|
|
392
311
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
312
|
+
const notReadyResult = markNotReady();
|
|
313
|
+
if (notReadyResult.wasReady) {
|
|
314
|
+
clearStartupQueuedKey();
|
|
396
315
|
clearProviderFlowHandleCache(flowHandleCacheRef.current);
|
|
397
316
|
reissueDeliveredPendingActionCommands();
|
|
398
317
|
}
|
|
399
|
-
lastReadyRef.current = null;
|
|
400
318
|
setWidgetHostVisibility(HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY);
|
|
401
319
|
pausePendingCommandTimeouts();
|
|
402
320
|
}, [
|
|
321
|
+
clearStartupQueuedKey,
|
|
403
322
|
handleWidgetReady,
|
|
323
|
+
markNotReady,
|
|
404
324
|
pausePendingCommandTimeouts,
|
|
405
325
|
reissueDeliveredPendingActionCommands,
|
|
406
326
|
]);
|
|
@@ -409,29 +329,16 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
409
329
|
}, []);
|
|
410
330
|
const handleFlowHandleInvalidated = useCallback((flowHandleId) => {
|
|
411
331
|
deleteCachedFlowHandleId(flowHandleId);
|
|
412
|
-
setWidgetHostVisibility((visibility) => visibility
|
|
413
|
-
|
|
414
|
-
}, [deleteCachedFlowHandleId]);
|
|
332
|
+
setWidgetHostVisibility((visibility) => clearFlowHandleFromVisibility(visibility, flowHandleId));
|
|
333
|
+
}, [clearFlowHandleFromVisibility, deleteCachedFlowHandleId]);
|
|
415
334
|
const handleInstanceFlowStateChanged = useCallback((detail) => {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
}
|
|
419
|
-
const readyState = lastReadyRef.current;
|
|
420
|
-
if (!readyState) {
|
|
335
|
+
const visibility = toFlowStateVisibility(detail, instanceId);
|
|
336
|
+
if (!visibility) {
|
|
421
337
|
return;
|
|
422
338
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
flowHeight: detail.height,
|
|
426
|
-
flowHandleId: detail.flowHandleId,
|
|
427
|
-
hostSourceVersion: hostSourceVersionRef.current,
|
|
428
|
-
isVisible,
|
|
429
|
-
readySequence: readyState.readySequence,
|
|
430
|
-
sourceKey: readyState.sourceKey,
|
|
431
|
-
});
|
|
432
|
-
}, [instanceId]);
|
|
339
|
+
setWidgetHostVisibility(visibility);
|
|
340
|
+
}, [instanceId, toFlowStateVisibility]);
|
|
433
341
|
const handleWebMessage = useCallback((message) => {
|
|
434
|
-
var _a;
|
|
435
342
|
if (message.kind === "hostEvent" &&
|
|
436
343
|
message.event.name === "instance:handle:invalidated" &&
|
|
437
344
|
message.event.detail.handleKind === "flow") {
|
|
@@ -444,22 +351,22 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
444
351
|
if (message.kind === "hostEvent" &&
|
|
445
352
|
message.event.name === "instance:command:settled") {
|
|
446
353
|
const requestId = message.event.detail.requestId;
|
|
447
|
-
const pendingCommand =
|
|
354
|
+
const pendingCommand = getPendingCommand(requestId);
|
|
448
355
|
if (pendingCommand) {
|
|
449
356
|
if (pendingCommand.hostEpoch !== null &&
|
|
450
|
-
pendingCommand.hostEpoch !== (
|
|
357
|
+
pendingCommand.hostEpoch !== getCurrentHostEpoch()) {
|
|
451
358
|
onWebMessage === null || onWebMessage === void 0 ? void 0 : onWebMessage(message);
|
|
452
359
|
return;
|
|
453
360
|
}
|
|
454
|
-
|
|
455
|
-
|
|
361
|
+
takePendingCommand(requestId);
|
|
362
|
+
removeNativeMessageId(pendingCommand.messageId);
|
|
456
363
|
if (pendingCommand.timeout) {
|
|
457
364
|
clearTimeout(pendingCommand.timeout);
|
|
458
365
|
}
|
|
459
366
|
const error = toCommandSettlementError(message.event);
|
|
460
367
|
if (error) {
|
|
461
368
|
if (pendingCommand.isStartup) {
|
|
462
|
-
|
|
369
|
+
clearStartupQueuedKey();
|
|
463
370
|
}
|
|
464
371
|
const flowId = toCommandFlowId(pendingCommand.result.envelope.command);
|
|
465
372
|
const isStaleFlowHandleError = error.code === "STALE_HANDLE" ||
|
|
@@ -496,30 +403,23 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
496
403
|
onWebMessage === null || onWebMessage === void 0 ? void 0 : onWebMessage(message);
|
|
497
404
|
}, [
|
|
498
405
|
enqueueTransportCommand,
|
|
406
|
+
clearStartupQueuedKey,
|
|
407
|
+
getCurrentHostEpoch,
|
|
408
|
+
getPendingCommand,
|
|
499
409
|
handleInstanceFlowStateChanged,
|
|
500
410
|
handleFlowHandleInvalidated,
|
|
501
411
|
onWebMessage,
|
|
412
|
+
removeNativeMessageId,
|
|
413
|
+
takePendingCommand,
|
|
502
414
|
]);
|
|
503
415
|
useEffect(() => () => {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
}
|
|
508
|
-
pendingCommand.reject(new Error(PROVIDER_UNMOUNTED_ERROR_MESSAGE));
|
|
509
|
-
}
|
|
510
|
-
clearProviderPendingCommands(pendingCommandsRef.current);
|
|
511
|
-
}, []);
|
|
512
|
-
useEffect(() => {
|
|
513
|
-
if (visibilitySourceKeyRef.current === hostSourceKey) {
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
visibilitySourceKeyRef.current = hostSourceKey;
|
|
517
|
-
setWidgetHostVisibility(HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY);
|
|
518
|
-
}, [hostSourceKey]);
|
|
416
|
+
disposeCommandTransport(new Error(PROVIDER_UNMOUNTED_ERROR_MESSAGE));
|
|
417
|
+
}, [disposeCommandTransport]);
|
|
418
|
+
const getNativeMessages = useCallback(() => nativeMessagesRef.current, [nativeMessagesRef]);
|
|
519
419
|
const contextValue = useMemo(() => ({
|
|
520
420
|
instanceId,
|
|
521
421
|
get nativeMessages() {
|
|
522
|
-
return
|
|
422
|
+
return getNativeMessages();
|
|
523
423
|
},
|
|
524
424
|
enqueueCommand,
|
|
525
425
|
configure: (opts, options) => enqueueCommand({ kind: "configure", opts }, options),
|
|
@@ -570,22 +470,20 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
570
470
|
updateHostContext: (context, options) => enqueueCommand({ kind: "updateHostContext", context }, options),
|
|
571
471
|
emitHostSignal: (name, data, options) => enqueueCommand(Object.assign({ kind: "emitHostSignal", name: resolveRequiredString("name", name) }, (data === undefined ? {} : { data })), options),
|
|
572
472
|
handleWebMessage,
|
|
573
|
-
}), [enqueueCommand, handleWebMessage, instanceId]);
|
|
473
|
+
}), [enqueueCommand, getNativeMessages, handleWebMessage, instanceId]);
|
|
574
474
|
useEffect(() => {
|
|
575
|
-
|
|
576
|
-
startupQueuedKeyRef.current = null;
|
|
577
|
-
}
|
|
475
|
+
resetStartupQueuedKeyIfChanged(startupOptionsKey);
|
|
578
476
|
enqueueStartupCommands();
|
|
579
|
-
}, [
|
|
477
|
+
}, [
|
|
478
|
+
enqueueStartupCommands,
|
|
479
|
+
resetStartupQueuedKeyIfChanged,
|
|
480
|
+
startupOptionsKey,
|
|
481
|
+
]);
|
|
580
482
|
const providerHostViewport = hostViewport !== null && hostViewport !== void 0 ? hostViewport : resolvedHostViewport;
|
|
581
483
|
const sheetHostViewport = toProviderWidgetSheetHostViewport(providerHostViewport, {
|
|
582
484
|
height: widgetHostVisibility.flowHeight,
|
|
583
485
|
});
|
|
584
|
-
const isWidgetHostVisible = widgetHostVisibility
|
|
585
|
-
sheetHostViewport !== undefined &&
|
|
586
|
-
widgetHostVisibility.hostSourceVersion === hostSourceVersionRef.current &&
|
|
587
|
-
widgetHostVisibility.sourceKey === ((_a = lastReadyRef.current) === null || _a === void 0 ? void 0 : _a.sourceKey) &&
|
|
588
|
-
widgetHostVisibility.readySequence === ((_b = lastReadyRef.current) === null || _b === void 0 ? void 0 : _b.readySequence);
|
|
486
|
+
const isWidgetHostVisible = resolveIsWidgetHostVisible(widgetHostVisibility, sheetHostViewport !== undefined);
|
|
589
487
|
const widgetHostViewport = providerHostViewport;
|
|
590
488
|
const composedWebViewStyle = toProviderWidgetHostStyle({
|
|
591
489
|
isVisible: isWidgetHostVisible,
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
export type ProviderPendingCommandRegistration<Result> = {
|
|
9
|
+
flowCommandSequence: number | null;
|
|
10
|
+
flowHandleCacheEpoch: number;
|
|
11
|
+
isStartup: boolean;
|
|
12
|
+
message: WebViewTransportNativeMessage;
|
|
13
|
+
requestId: string;
|
|
14
|
+
result: Result;
|
|
15
|
+
};
|
|
16
|
+
export type ProviderPendingCommandReissue<Result> = {
|
|
17
|
+
flowHandleCacheEpoch: number;
|
|
18
|
+
nextMessage: WebViewTransportNativeMessage;
|
|
19
|
+
nextRequestId: string;
|
|
20
|
+
nextResult: Result;
|
|
21
|
+
requestId: string;
|
|
22
|
+
};
|
|
23
|
+
export type ProviderCommandTransport<Result> = {
|
|
24
|
+
clearStartupQueuedKey: () => void;
|
|
25
|
+
createPendingCommandPromise: (input: ProviderPendingCommandRegistration<Result>) => Promise<Result>;
|
|
26
|
+
dispose: (error: Error) => void;
|
|
27
|
+
getPendingCommand: (requestId: string) => ProviderPendingCommand<Result> | undefined;
|
|
28
|
+
getPendingCommandEntries: () => Array<[
|
|
29
|
+
string,
|
|
30
|
+
ProviderPendingCommand<Result>
|
|
31
|
+
]>;
|
|
32
|
+
hasDeliveredPendingCommands: () => boolean;
|
|
33
|
+
isStartupQueuedKey: (key: string) => boolean;
|
|
34
|
+
nativeMessages: WebViewTransportNativeMessage[];
|
|
35
|
+
nativeMessagesRef: {
|
|
36
|
+
current: WebViewTransportNativeMessage[];
|
|
37
|
+
};
|
|
38
|
+
pausePendingCommandTimeouts: () => void;
|
|
39
|
+
registerNativeMessage: (message: WebViewTransportNativeMessage, options: {
|
|
40
|
+
isStartup: boolean;
|
|
41
|
+
prioritizeStartup: boolean;
|
|
42
|
+
}) => void;
|
|
43
|
+
reissuePendingCommand: (input: ProviderPendingCommandReissue<Result>) => {
|
|
44
|
+
previousMessageId: string;
|
|
45
|
+
} | null;
|
|
46
|
+
removeNativeMessageId: (messageId: string) => void;
|
|
47
|
+
replaceNativeMessages: (replacements: ReadonlyMap<string, WebViewTransportNativeMessage>) => void;
|
|
48
|
+
resetStartupQueuedKeyIfChanged: (key: string) => void;
|
|
49
|
+
setStartupQueuedKey: (key: string) => void;
|
|
50
|
+
startPendingCommandTimeouts: () => void;
|
|
51
|
+
takePendingCommand: (requestId: string) => ProviderPendingCommand<Result> | undefined;
|
|
52
|
+
cancelStartupCommands: (error: Error) => void;
|
|
53
|
+
};
|
|
54
|
+
export declare function useProviderCommandTransport<Result>({ commandTimeoutMs, createTimeoutError, getCurrentHostEpoch, }: ProviderCommandTransportOptions): ProviderCommandTransport<Result>;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { useCallback, useRef, useState } from "react";
|
|
2
|
+
import { enqueueProviderNativeMessage, removeProviderNativeMessageId, removeProviderNativeMessageIds, replaceProviderNativeMessages, } from "./provider-message-queue.js";
|
|
3
|
+
import { cancelProviderStartupCommands, clearProviderPendingCommands, createProviderPendingCommandRegistry, getProviderPendingCommand, getProviderPendingCommandEntries, getProviderPendingCommands, hasDeliveredProviderPendingCommands, isProviderPendingMessageStartup, registerProviderPendingCommand, reissueProviderPendingCommand, takeProviderPendingCommand, } from "./provider-pending-commands.js";
|
|
4
|
+
export function useProviderCommandTransport({ commandTimeoutMs, createTimeoutError, getCurrentHostEpoch, }) {
|
|
5
|
+
const [nativeMessages, setNativeMessages] = useState([]);
|
|
6
|
+
const nativeMessagesRef = useRef([]);
|
|
7
|
+
const pendingCommandsRef = useRef(createProviderPendingCommandRegistry());
|
|
8
|
+
const startupQueuedKeyRef = useRef(null);
|
|
9
|
+
nativeMessagesRef.current = nativeMessages;
|
|
10
|
+
const removeNativeMessageId = useCallback((messageId) => {
|
|
11
|
+
setNativeMessages((messages) => removeProviderNativeMessageId(messages, messageId));
|
|
12
|
+
}, []);
|
|
13
|
+
const removeNativeMessageIds = useCallback((messageIds) => {
|
|
14
|
+
setNativeMessages((messages) => removeProviderNativeMessageIds(messages, messageIds));
|
|
15
|
+
}, []);
|
|
16
|
+
const rejectPendingCommand = useCallback((requestId, pendingCommand, error) => {
|
|
17
|
+
takeProviderPendingCommand(pendingCommandsRef.current, requestId);
|
|
18
|
+
if (pendingCommand.timeout) {
|
|
19
|
+
clearTimeout(pendingCommand.timeout);
|
|
20
|
+
pendingCommand.timeout = null;
|
|
21
|
+
}
|
|
22
|
+
if (pendingCommand.isStartup) {
|
|
23
|
+
startupQueuedKeyRef.current = null;
|
|
24
|
+
}
|
|
25
|
+
removeNativeMessageId(pendingCommand.messageId);
|
|
26
|
+
pendingCommand.reject(error);
|
|
27
|
+
}, [removeNativeMessageId]);
|
|
28
|
+
const startPendingCommandTimeout = useCallback((requestId, pendingCommand) => {
|
|
29
|
+
pendingCommand.hostEpoch = getCurrentHostEpoch();
|
|
30
|
+
if (commandTimeoutMs <= 0) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (pendingCommand.timeout) {
|
|
34
|
+
clearTimeout(pendingCommand.timeout);
|
|
35
|
+
}
|
|
36
|
+
pendingCommand.timeout = setTimeout(() => {
|
|
37
|
+
rejectPendingCommand(requestId, pendingCommand, createTimeoutError(requestId));
|
|
38
|
+
}, commandTimeoutMs);
|
|
39
|
+
}, [
|
|
40
|
+
commandTimeoutMs,
|
|
41
|
+
createTimeoutError,
|
|
42
|
+
getCurrentHostEpoch,
|
|
43
|
+
rejectPendingCommand,
|
|
44
|
+
]);
|
|
45
|
+
const startPendingCommandTimeouts = useCallback(() => {
|
|
46
|
+
for (const [requestId, pendingCommand] of getProviderPendingCommandEntries(pendingCommandsRef.current)) {
|
|
47
|
+
startPendingCommandTimeout(requestId, pendingCommand);
|
|
48
|
+
}
|
|
49
|
+
}, [startPendingCommandTimeout]);
|
|
50
|
+
const pausePendingCommandTimeouts = useCallback(() => {
|
|
51
|
+
for (const pendingCommand of getProviderPendingCommands(pendingCommandsRef.current)) {
|
|
52
|
+
if (!pendingCommand.timeout) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
clearTimeout(pendingCommand.timeout);
|
|
56
|
+
pendingCommand.timeout = null;
|
|
57
|
+
}
|
|
58
|
+
}, []);
|
|
59
|
+
const createPendingCommandPromise = useCallback(({ flowCommandSequence, flowHandleCacheEpoch, isStartup, message, requestId, result, }) => new Promise((resolve, reject) => {
|
|
60
|
+
const pendingCommand = {
|
|
61
|
+
flowCommandSequence,
|
|
62
|
+
flowHandleCacheEpoch,
|
|
63
|
+
hostEpoch: null,
|
|
64
|
+
isStartup,
|
|
65
|
+
messageId: message.id,
|
|
66
|
+
reject,
|
|
67
|
+
resolve,
|
|
68
|
+
result,
|
|
69
|
+
timeout: null,
|
|
70
|
+
};
|
|
71
|
+
registerProviderPendingCommand(pendingCommandsRef.current, requestId, pendingCommand);
|
|
72
|
+
if (getCurrentHostEpoch() !== null) {
|
|
73
|
+
startPendingCommandTimeout(requestId, pendingCommand);
|
|
74
|
+
}
|
|
75
|
+
}), [getCurrentHostEpoch, startPendingCommandTimeout]);
|
|
76
|
+
const registerNativeMessage = useCallback((message, options) => {
|
|
77
|
+
setNativeMessages((messages) => enqueueProviderNativeMessage(messages, Object.assign(Object.assign({}, options), { isStartupMessage: (entry) => isProviderPendingMessageStartup(pendingCommandsRef.current, entry.envelope.requestId), message })));
|
|
78
|
+
}, []);
|
|
79
|
+
const replaceNativeMessages = useCallback((replacements) => {
|
|
80
|
+
setNativeMessages((messages) => replaceProviderNativeMessages(messages, replacements));
|
|
81
|
+
}, []);
|
|
82
|
+
const reissuePendingCommand = useCallback(({ flowHandleCacheEpoch, nextMessage, nextRequestId, nextResult, requestId, }) => {
|
|
83
|
+
const reissuedCommand = reissueProviderPendingCommand(pendingCommandsRef.current, {
|
|
84
|
+
flowHandleCacheEpoch,
|
|
85
|
+
nextMessageId: nextMessage.id,
|
|
86
|
+
nextRequestId,
|
|
87
|
+
nextResult,
|
|
88
|
+
requestId,
|
|
89
|
+
});
|
|
90
|
+
return reissuedCommand
|
|
91
|
+
? { previousMessageId: reissuedCommand.previousMessageId }
|
|
92
|
+
: null;
|
|
93
|
+
}, []);
|
|
94
|
+
const cancelStartupCommands = useCallback((error) => {
|
|
95
|
+
const canceled = cancelProviderStartupCommands(pendingCommandsRef.current);
|
|
96
|
+
for (const pendingCommand of canceled.commands) {
|
|
97
|
+
if (pendingCommand.timeout) {
|
|
98
|
+
clearTimeout(pendingCommand.timeout);
|
|
99
|
+
}
|
|
100
|
+
pendingCommand.reject(error);
|
|
101
|
+
}
|
|
102
|
+
if (canceled.messageIds.size > 0) {
|
|
103
|
+
removeNativeMessageIds(canceled.messageIds);
|
|
104
|
+
}
|
|
105
|
+
}, [removeNativeMessageIds]);
|
|
106
|
+
const dispose = useCallback((error) => {
|
|
107
|
+
for (const pendingCommand of getProviderPendingCommands(pendingCommandsRef.current)) {
|
|
108
|
+
if (pendingCommand.timeout) {
|
|
109
|
+
clearTimeout(pendingCommand.timeout);
|
|
110
|
+
}
|
|
111
|
+
pendingCommand.reject(error);
|
|
112
|
+
}
|
|
113
|
+
clearProviderPendingCommands(pendingCommandsRef.current);
|
|
114
|
+
startupQueuedKeyRef.current = null;
|
|
115
|
+
}, []);
|
|
116
|
+
const clearStartupQueuedKey = useCallback(() => {
|
|
117
|
+
startupQueuedKeyRef.current = null;
|
|
118
|
+
}, []);
|
|
119
|
+
const getPendingCommand = useCallback((requestId) => getProviderPendingCommand(pendingCommandsRef.current, requestId), []);
|
|
120
|
+
const getPendingCommandEntries = useCallback(() => getProviderPendingCommandEntries(pendingCommandsRef.current), []);
|
|
121
|
+
const hasDeliveredPendingCommands = useCallback(() => hasDeliveredProviderPendingCommands(pendingCommandsRef.current), []);
|
|
122
|
+
const isStartupQueuedKey = useCallback((key) => startupQueuedKeyRef.current === key, []);
|
|
123
|
+
const resetStartupQueuedKeyIfChanged = useCallback((key) => {
|
|
124
|
+
if (startupQueuedKeyRef.current !== key) {
|
|
125
|
+
startupQueuedKeyRef.current = null;
|
|
126
|
+
}
|
|
127
|
+
}, []);
|
|
128
|
+
const setStartupQueuedKey = useCallback((key) => {
|
|
129
|
+
startupQueuedKeyRef.current = key;
|
|
130
|
+
}, []);
|
|
131
|
+
const takePendingCommand = useCallback((requestId) => takeProviderPendingCommand(pendingCommandsRef.current, requestId), []);
|
|
132
|
+
return {
|
|
133
|
+
cancelStartupCommands,
|
|
134
|
+
clearStartupQueuedKey,
|
|
135
|
+
createPendingCommandPromise,
|
|
136
|
+
dispose,
|
|
137
|
+
getPendingCommand,
|
|
138
|
+
getPendingCommandEntries,
|
|
139
|
+
hasDeliveredPendingCommands,
|
|
140
|
+
isStartupQueuedKey,
|
|
141
|
+
nativeMessages,
|
|
142
|
+
nativeMessagesRef,
|
|
143
|
+
pausePendingCommandTimeouts,
|
|
144
|
+
registerNativeMessage,
|
|
145
|
+
reissuePendingCommand,
|
|
146
|
+
removeNativeMessageId,
|
|
147
|
+
replaceNativeMessages,
|
|
148
|
+
resetStartupQueuedKeyIfChanged,
|
|
149
|
+
setStartupQueuedKey,
|
|
150
|
+
startPendingCommandTimeouts,
|
|
151
|
+
takePendingCommand,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export type ProviderWidgetHostReadyState = {
|
|
2
|
+
hostEpoch: number;
|
|
3
|
+
readySequence: number;
|
|
4
|
+
sourceKey: string;
|
|
5
|
+
};
|
|
6
|
+
export type ProviderWidgetHostVisibility = {
|
|
7
|
+
flowHeight?: number;
|
|
8
|
+
flowHandleId?: string;
|
|
9
|
+
hostSourceVersion: number | null;
|
|
10
|
+
isVisible: boolean;
|
|
11
|
+
readySequence: number | null;
|
|
12
|
+
sourceKey: string | null;
|
|
13
|
+
};
|
|
14
|
+
export type ProviderWidgetHostFlowState = {
|
|
15
|
+
height?: number;
|
|
16
|
+
flowHandleId?: string;
|
|
17
|
+
instanceId: string;
|
|
18
|
+
isLoading: boolean;
|
|
19
|
+
isOpen: boolean;
|
|
20
|
+
};
|
|
21
|
+
export declare const HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY: ProviderWidgetHostVisibility;
|
|
22
|
+
export type ProviderWidgetHostLifecycleController = {
|
|
23
|
+
clearFlowHandleFromVisibility: (visibility: ProviderWidgetHostVisibility, flowHandleId: string) => ProviderWidgetHostVisibility;
|
|
24
|
+
getCurrentHostEpoch: () => number | null;
|
|
25
|
+
isWidgetHostVisible: (visibility: ProviderWidgetHostVisibility, hasSheetHostViewport: boolean) => boolean;
|
|
26
|
+
markNotReady: () => {
|
|
27
|
+
wasReady: boolean;
|
|
28
|
+
};
|
|
29
|
+
markReady: (event: {
|
|
30
|
+
readySequence: number;
|
|
31
|
+
sourceKey: string;
|
|
32
|
+
}, options: {
|
|
33
|
+
hasDeliveredPendingCommands: boolean;
|
|
34
|
+
}) => {
|
|
35
|
+
alreadySeen: boolean;
|
|
36
|
+
didResetHostEpoch: boolean;
|
|
37
|
+
previousReady: ProviderWidgetHostReadyState | null;
|
|
38
|
+
};
|
|
39
|
+
syncHostSourceKey: (hostSourceKey: string) => boolean;
|
|
40
|
+
toFlowStateVisibility: (detail: ProviderWidgetHostFlowState, instanceId: string) => ProviderWidgetHostVisibility | null;
|
|
41
|
+
toReadyVisibility: (visibility: ProviderWidgetHostVisibility, event: {
|
|
42
|
+
readySequence: number;
|
|
43
|
+
sourceKey: string;
|
|
44
|
+
}) => ProviderWidgetHostVisibility;
|
|
45
|
+
};
|
|
46
|
+
export declare function createProviderWidgetHostLifecycleController(initialHostSourceKey: string): ProviderWidgetHostLifecycleController;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export const HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY = {
|
|
2
|
+
hostSourceVersion: null,
|
|
3
|
+
isVisible: false,
|
|
4
|
+
readySequence: null,
|
|
5
|
+
sourceKey: null,
|
|
6
|
+
};
|
|
7
|
+
export function createProviderWidgetHostLifecycleController(initialHostSourceKey) {
|
|
8
|
+
let hostEpoch = 0;
|
|
9
|
+
let hostSourceKey = initialHostSourceKey;
|
|
10
|
+
let hostSourceVersion = 0;
|
|
11
|
+
let lastReady = null;
|
|
12
|
+
return {
|
|
13
|
+
clearFlowHandleFromVisibility: (visibility, flowHandleId) => visibility.flowHandleId === flowHandleId
|
|
14
|
+
? Object.assign(Object.assign({}, visibility), { flowHandleId: undefined }) : visibility,
|
|
15
|
+
getCurrentHostEpoch: () => { var _a; return (_a = lastReady === null || lastReady === void 0 ? void 0 : lastReady.hostEpoch) !== null && _a !== void 0 ? _a : null; },
|
|
16
|
+
isWidgetHostVisible: (visibility, hasSheetHostViewport) => visibility.isVisible &&
|
|
17
|
+
hasSheetHostViewport &&
|
|
18
|
+
visibility.hostSourceVersion === hostSourceVersion &&
|
|
19
|
+
visibility.sourceKey === (lastReady === null || lastReady === void 0 ? void 0 : lastReady.sourceKey) &&
|
|
20
|
+
visibility.readySequence === (lastReady === null || lastReady === void 0 ? void 0 : lastReady.readySequence),
|
|
21
|
+
markNotReady: () => {
|
|
22
|
+
const wasReady = lastReady !== null;
|
|
23
|
+
if (wasReady) {
|
|
24
|
+
hostEpoch += 1;
|
|
25
|
+
}
|
|
26
|
+
lastReady = null;
|
|
27
|
+
return { wasReady };
|
|
28
|
+
},
|
|
29
|
+
markReady: (event, { hasDeliveredPendingCommands }) => {
|
|
30
|
+
const previousReady = lastReady;
|
|
31
|
+
const alreadySeen = (previousReady === null || previousReady === void 0 ? void 0 : previousReady.sourceKey) === event.sourceKey &&
|
|
32
|
+
previousReady.readySequence === event.readySequence;
|
|
33
|
+
if (alreadySeen) {
|
|
34
|
+
return {
|
|
35
|
+
alreadySeen: true,
|
|
36
|
+
didResetHostEpoch: false,
|
|
37
|
+
previousReady,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const didResetHostEpoch = previousReady !== null || hasDeliveredPendingCommands;
|
|
41
|
+
if (didResetHostEpoch) {
|
|
42
|
+
hostEpoch += 1;
|
|
43
|
+
}
|
|
44
|
+
lastReady = Object.assign(Object.assign({}, event), { hostEpoch });
|
|
45
|
+
return {
|
|
46
|
+
alreadySeen: false,
|
|
47
|
+
didResetHostEpoch,
|
|
48
|
+
previousReady,
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
syncHostSourceKey: (nextHostSourceKey) => {
|
|
52
|
+
if (hostSourceKey === nextHostSourceKey) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
hostSourceKey = nextHostSourceKey;
|
|
56
|
+
hostSourceVersion += 1;
|
|
57
|
+
lastReady = null;
|
|
58
|
+
return true;
|
|
59
|
+
},
|
|
60
|
+
toFlowStateVisibility: (detail, instanceId) => {
|
|
61
|
+
if (detail.instanceId !== instanceId || lastReady === null) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
flowHeight: detail.height,
|
|
66
|
+
flowHandleId: detail.flowHandleId,
|
|
67
|
+
hostSourceVersion,
|
|
68
|
+
isVisible: detail.isOpen || detail.isLoading,
|
|
69
|
+
readySequence: lastReady.readySequence,
|
|
70
|
+
sourceKey: lastReady.sourceKey,
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
toReadyVisibility: (visibility, event) => {
|
|
74
|
+
if (!visibility.isVisible ||
|
|
75
|
+
visibility.sourceKey !== event.sourceKey ||
|
|
76
|
+
visibility.hostSourceVersion !== hostSourceVersion) {
|
|
77
|
+
return visibility;
|
|
78
|
+
}
|
|
79
|
+
return Object.assign(Object.assign({}, visibility), { readySequence: event.readySequence });
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
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 : "1.3.
|
|
6
|
+
export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "1.3.14";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getuserfeedback/react-native",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.14",
|
|
4
4
|
"description": "getuserfeedback React Native SDK",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"getuserfeedback",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"lint": "ultracite check ."
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@getuserfeedback/protocol": "^
|
|
48
|
-
"@getuserfeedback/sdk": "^0.7.
|
|
47
|
+
"@getuserfeedback/protocol": "^2.0.0",
|
|
48
|
+
"@getuserfeedback/sdk": "^0.7.7",
|
|
49
49
|
"robot3": "^1.2.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|