@getuserfeedback/react-native 4.0.21 → 4.0.22

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.
@@ -10,7 +10,7 @@ function NativeViewHostProjectionEntry({ controller, nativeViewComponent, onInva
10
10
  detach === null || detach === void 0 ? void 0 : detach();
11
11
  }, []);
12
12
  const handleConnected = useCallback((connection) => {
13
- const controllerDetach = controller.attachViewReadinessConnection({
13
+ const controllerDetach = controller.attachViewConnection({
14
14
  allocationId: record.allocationId,
15
15
  connection,
16
16
  });
@@ -15,7 +15,7 @@ export type NativeViewRecord = Readonly<{
15
15
  viewId: string;
16
16
  }>;
17
17
  export type NativeViewRecordController = {
18
- attachViewReadinessConnection(input: {
18
+ attachViewConnection(input: {
19
19
  allocationId: number;
20
20
  connection: ViewWebViewHostConnection;
21
21
  }): (() => void) | null;
@@ -1,6 +1,7 @@
1
1
  import { coreViewHostActionSchema, } from "@getuserfeedback/protocol/internal/core-view-host-actions";
2
- import { actionRequestCloseViewSchema, buildEventLayoutTransactionCommitted, buildEventViewSize, eventViewSizeSchema, } from "@getuserfeedback/protocol/internal/view-host-control-messages";
2
+ import { actionRequestCloseViewSchema, actionViewConnectSchema, buildEventLayoutTransactionCommitted, buildEventViewSize, eventViewSizeSchema, } from "@getuserfeedback/protocol/internal/view-host-control-messages";
3
3
  import { buildEventViewClosed, buildEventViewPrerendered, } from "@getuserfeedback/protocol/internal/view-host-lifecycle-events";
4
+ import { bindViewHostControlEnvelope, bindViewToCoreRelayEnvelope, parseCoreToViewRelayEnvelope, } from "@getuserfeedback/protocol/internal/view-relay-contract";
4
5
  import { createViewPreparationReadinessRegistry, createViewPreparationRegistry, } from "./view-orchestration-runtime.js";
5
6
  const createNativeViewReadinessRegistry = () => createViewPreparationReadinessRegistry();
6
7
  export function createNativeViewRecordController(input) {
@@ -41,9 +42,9 @@ export function createNativeViewRecordController(input) {
41
42
  if (entries.get(entry.viewId) !== entry) {
42
43
  return false;
43
44
  }
44
- const detachViewReadiness = entry.viewReadinessDetach;
45
- entry.viewReadinessDetach = null;
46
- detachViewReadiness === null || detachViewReadiness === void 0 ? void 0 : detachViewReadiness();
45
+ const detachViewConnection = entry.viewConnectionDetach;
46
+ entry.viewConnectionDetach = null;
47
+ detachViewConnection === null || detachViewConnection === void 0 ? void 0 : detachViewConnection();
47
48
  entries.delete(entry.viewId);
48
49
  if (!disposed) {
49
50
  notify();
@@ -74,14 +75,17 @@ export function createNativeViewRecordController(input) {
74
75
  isActive: false,
75
76
  isClosing: false,
76
77
  isPreparationCommitted: false,
78
+ isViewConnected: false,
79
+ isViewRelayDraining: false,
77
80
  layoutReportRevision: 0,
78
81
  openRequest: toOpenRequestMetadata(action.openRequest),
82
+ pendingCoreToViewMessages: [],
79
83
  preparation,
80
84
  size: null,
81
85
  srcdoc: action.srcdoc,
82
86
  committedLayoutReportOccurrence: null,
83
87
  viewConnection: null,
84
- viewReadinessDetach: null,
88
+ viewConnectionDetach: null,
85
89
  viewId: action.viewId,
86
90
  };
87
91
  entries.set(action.viewId, entry);
@@ -109,25 +113,65 @@ export function createNativeViewRecordController(input) {
109
113
  closeEntry(entry);
110
114
  }
111
115
  };
116
+ const drainCoreToViewMessages = (entry) => {
117
+ if (coreConnectionFailed ||
118
+ disposed ||
119
+ entry.isViewRelayDraining ||
120
+ !entry.isViewConnected ||
121
+ !entry.viewConnection ||
122
+ entries.get(entry.viewId) !== entry) {
123
+ return;
124
+ }
125
+ entry.isViewRelayDraining = true;
126
+ try {
127
+ while (!coreConnectionFailed &&
128
+ !disposed &&
129
+ entry.isViewConnected &&
130
+ entry.viewConnection !== null &&
131
+ entries.get(entry.viewId) === entry &&
132
+ entry.pendingCoreToViewMessages.length > 0) {
133
+ const message = entry.pendingCoreToViewMessages.shift();
134
+ entry.viewConnection.transport.postMessage(message);
135
+ }
136
+ }
137
+ catch (error) {
138
+ failCoreConnection(error, "Native Core-to-View relay delivery failed");
139
+ }
140
+ finally {
141
+ entry.isViewRelayDraining = false;
142
+ }
143
+ };
144
+ const enqueueCoreToViewMessage = (entry, message) => {
145
+ entry.pendingCoreToViewMessages.push(message);
146
+ drainCoreToViewMessages(entry);
147
+ };
112
148
  const handleCoreMessage = (value) => {
113
149
  if (coreConnectionFailed || disposed) {
114
150
  return;
115
151
  }
116
- const parsed = coreViewHostActionSchema.safeParse(value);
117
- if (!parsed.success ||
118
- parsed.data.gen !== input.coreConnection.generation) {
152
+ const action = coreViewHostActionSchema.safeParse(value);
153
+ if (action.success && action.data.gen === input.coreConnection.generation) {
154
+ switch (action.data.t) {
155
+ case "getuserfeedback:action:prerenderView":
156
+ handlePrerender(action.data);
157
+ break;
158
+ case "getuserfeedback:action:activateView":
159
+ handleActivate(action.data);
160
+ break;
161
+ case "getuserfeedback:action:closeView":
162
+ handleClose(action.data);
163
+ break;
164
+ }
119
165
  return;
120
166
  }
121
- switch (parsed.data.t) {
122
- case "getuserfeedback:action:prerenderView":
123
- handlePrerender(parsed.data);
124
- break;
125
- case "getuserfeedback:action:activateView":
126
- handleActivate(parsed.data);
127
- break;
128
- case "getuserfeedback:action:closeView":
129
- handleClose(parsed.data);
130
- break;
167
+ const relay = parseCoreToViewRelayEnvelope(value, {
168
+ generation: input.coreConnection.generation,
169
+ });
170
+ if (relay) {
171
+ const entry = entries.get(relay.viewId);
172
+ if (entry) {
173
+ enqueueCoreToViewMessage(entry, relay.message);
174
+ }
131
175
  }
132
176
  };
133
177
  const completeConnectionReadiness = (entry, size) => {
@@ -205,7 +249,7 @@ export function createNativeViewRecordController(input) {
205
249
  failCoreConnection(error, "Native view layout commit delivery failed");
206
250
  }
207
251
  },
208
- attachViewReadinessConnection({ allocationId, connection }) {
252
+ attachViewConnection({ allocationId, connection }) {
209
253
  if (coreConnectionFailed || disposed) {
210
254
  return null;
211
255
  }
@@ -216,7 +260,7 @@ export function createNativeViewRecordController(input) {
216
260
  connection.generation !== input.coreConnection.generation) {
217
261
  return null;
218
262
  }
219
- const previousDetach = entry.viewReadinessDetach;
263
+ const previousDetach = entry.viewConnectionDetach;
220
264
  const connectionReadiness = createNativeViewReadinessRegistry().begin(viewId);
221
265
  let detached = false;
222
266
  let subscribed = false;
@@ -229,9 +273,10 @@ export function createNativeViewRecordController(input) {
229
273
  detached = true;
230
274
  unsubscribe();
231
275
  connectionReadiness.release();
232
- if (entry.viewReadinessDetach === detach) {
233
- entry.viewReadinessDetach = null;
276
+ if (entry.viewConnectionDetach === detach) {
277
+ entry.viewConnectionDetach = null;
234
278
  entry.viewConnection = null;
279
+ entry.isViewConnected = false;
235
280
  entry.committedLayoutReportOccurrence = null;
236
281
  if (entry.size !== null) {
237
282
  entry.size = null;
@@ -246,7 +291,7 @@ export function createNativeViewRecordController(input) {
246
291
  detached ||
247
292
  disposed ||
248
293
  entries.get(viewId) !== entry ||
249
- entry.viewReadinessDetach !== detach) {
294
+ entry.viewConnectionDetach !== detach) {
250
295
  return;
251
296
  }
252
297
  try {
@@ -261,22 +306,50 @@ export function createNativeViewRecordController(input) {
261
306
  detached ||
262
307
  disposed ||
263
308
  entries.get(viewId) !== entry ||
264
- entry.viewReadinessDetach !== detach) {
309
+ entry.viewConnectionDetach !== detach) {
310
+ return;
311
+ }
312
+ const connected = actionViewConnectSchema.safeParse(value);
313
+ if (connected.success) {
314
+ if (connected.data.gen === input.coreConnection.generation &&
315
+ connected.data.viewId === viewId) {
316
+ entry.isViewConnected = true;
317
+ drainCoreToViewMessages(entry);
318
+ }
265
319
  return;
266
320
  }
267
- const closeRequest = actionRequestCloseViewSchema.safeParse(value);
268
- if (closeRequest.success) {
269
- if (closeRequest.data.gen === input.coreConnection.generation &&
270
- (closeRequest.data.viewId === undefined ||
271
- closeRequest.data.viewId === viewId)) {
321
+ const control = bindViewHostControlEnvelope(value, {
322
+ generation: input.coreConnection.generation,
323
+ viewId,
324
+ });
325
+ if ((control === null || control === void 0 ? void 0 : control.t) === "getuserfeedback:action:viewConnect") {
326
+ return;
327
+ }
328
+ if ((control === null || control === void 0 ? void 0 : control.t) === "getuserfeedback:action:requestCloseView") {
329
+ const closeRequest = actionRequestCloseViewSchema.safeParse(control);
330
+ if (closeRequest.success) {
272
331
  closeViewFromRequest(entry, closeRequest.data);
273
332
  }
274
333
  return;
275
334
  }
276
- const parsed = eventViewSizeSchema.safeParse(value);
335
+ const parsed = eventViewSizeSchema.safeParse(control);
277
336
  if (!parsed.success ||
278
- parsed.data.gen !== input.coreConnection.generation ||
279
- (parsed.data.viewId !== undefined && parsed.data.viewId !== viewId)) {
337
+ parsed.data.gen !== input.coreConnection.generation) {
338
+ if (!entry.isViewConnected) {
339
+ return;
340
+ }
341
+ const relay = bindViewToCoreRelayEnvelope(value, {
342
+ generation: input.coreConnection.generation,
343
+ viewId,
344
+ });
345
+ if (relay) {
346
+ try {
347
+ input.coreConnection.transport.postMessage(relay);
348
+ }
349
+ catch (error) {
350
+ failCoreConnection(error, "Native View-to-Core relay delivery failed");
351
+ }
352
+ }
280
353
  return;
281
354
  }
282
355
  const size = toViewSizeReport(parsed.data);
@@ -304,7 +377,7 @@ export function createNativeViewRecordController(input) {
304
377
  }
305
378
  catch (error) {
306
379
  connectionReadiness.release();
307
- reportError(error, "Native view readiness subscription failed");
380
+ reportError(error, "Native view connection subscription failed");
308
381
  return null;
309
382
  }
310
383
  unsubscribe = subscribedUnsubscribe;
@@ -313,8 +386,9 @@ export function createNativeViewRecordController(input) {
313
386
  connectionReadiness.release();
314
387
  return null;
315
388
  }
316
- entry.viewReadinessDetach = detach;
389
+ entry.viewConnectionDetach = detach;
317
390
  entry.viewConnection = connection;
391
+ entry.isViewConnected = false;
318
392
  entry.committedLayoutReportOccurrence = null;
319
393
  previousDetach === null || previousDetach === void 0 ? void 0 : previousDetach();
320
394
  if (entry.size !== null) {
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 : "4.0.21";
6
+ export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "4.0.22";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/react-native",
3
- "version": "4.0.21",
3
+ "version": "4.0.22",
4
4
  "description": "getuserfeedback React Native SDK",
5
5
  "keywords": [
6
6
  "getuserfeedback",