@wise/dynamic-flow-client 5.0.1-exp-css-28d60ea → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/README.md +7 -2
  2. package/build/main.js +220 -108
  3. package/build/main.mjs +220 -108
  4. package/build/types/domain/components/step/StepDomainComponent.d.ts +4 -2
  5. package/build/types/domain/features/polling/getStepPolling.d.ts +3 -2
  6. package/build/types/domain/mappers/layout/alertLayoutToComponent.d.ts +1 -1
  7. package/build/types/domain/mappers/layout/decisionLayoutToComponent.d.ts +1 -1
  8. package/build/types/domain/mappers/layout/reviewLayoutToComponent.d.ts +1 -1
  9. package/build/types/domain/mappers/layout/statusListLayoutToComponent.d.ts +1 -1
  10. package/build/types/domain/mappers/mapStepToComponent.d.ts +1 -1
  11. package/build/types/domain/mappers/schema/types.d.ts +2 -1
  12. package/build/types/domain/mappers/utils/behavior-utils.d.ts +5 -2
  13. package/build/types/domain/mappers/utils/call-to-action-utils.d.ts +3 -2
  14. package/build/types/domain/mappers/utils/utils.d.ts +3 -2
  15. package/build/types/domain/prefetching/request-cache.d.ts +9 -0
  16. package/build/types/flow/executeSubmission.d.ts +4 -1
  17. package/build/types/flow/makeSafeHttpClient.d.ts +2 -0
  18. package/build/types/flow/makeSubmissionRequest.d.ts +3 -0
  19. package/package.json +26 -36
  20. package/build/types/domain/mappers/schema/tests/test-utils.d.ts +0 -34
  21. package/build/types/test-utils/NeptuneProviders.d.ts +0 -5
  22. package/build/types/test-utils/getRandomId.d.ts +0 -1
  23. package/build/types/test-utils/index.d.ts +0 -2
  24. package/build/types/test-utils/rtl-utils.d.ts +0 -2
  25. package/build/types/tests/renderers/TextInputRenderer.test.d.ts +0 -1
package/README.md CHANGED
@@ -36,9 +36,14 @@ pnpm install @transferwise/components @transferwise/formatting @transferwise/ico
36
36
  ```
37
37
  **Note:** Keep in mind that some of these dependencies have their own peer dependencies. Don't forget to install those, for instance: `@transferwise/components` needs `@wise/art` and `@wise/components-theming`.
38
38
 
39
+ 3. In addition to the design system styles, you need to import the DynamicFlow styles once into your application. You can do this either via JavaScript or CSS.
40
+
39
41
  ```js
40
- // Should be imported once in your application
41
- import '@wise/dynamic-flow-client/build/main.css';
42
+ import '@wise/dynamic-flow-client/main.css'; // JavaScript
43
+ ```
44
+
45
+ ```css
46
+ @import url('@wise/dynamic-flow-client/build/main.css'); /* CSS */
42
47
  ```
43
48
 
44
49
  The `DynamicFlow` component must be wraped in a Neptune `Provider` to support localisation, a `ThemeProvider` to provide theming, and a `SnackbarProvider` to ensure snackbars display correctly. Translations should be imported from both components and dynamic flows, merged, and passed to the `Provider` component (as below).
package/build/main.js CHANGED
@@ -1175,15 +1175,16 @@ var createAlertComponent = (alertProps) => __spreadValues({
1175
1175
  }, alertProps);
1176
1176
 
1177
1177
  // src/domain/mappers/utils/behavior-utils.ts
1178
- var getDomainLayerBehavior = ({
1179
- action,
1180
- behavior
1181
- }, stepActions) => {
1182
- if (behavior) {
1183
- return normaliseBehavior(behavior, stepActions);
1178
+ var getDomainLayerBehavior = ({ action, behavior: specBehavior }, stepActions, registerSubmissionBehavior) => {
1179
+ if (specBehavior) {
1180
+ const behavior = normaliseBehavior(specBehavior, stepActions);
1181
+ registerSubmissionBehavior == null ? void 0 : registerSubmissionBehavior(behavior);
1182
+ return behavior;
1184
1183
  }
1185
1184
  if (action) {
1186
- return actionToBehavior(action, stepActions);
1185
+ const behavior = actionToBehavior(action, stepActions);
1186
+ registerSubmissionBehavior == null ? void 0 : registerSubmissionBehavior(behavior);
1187
+ return behavior;
1187
1188
  }
1188
1189
  return { type: "none" };
1189
1190
  };
@@ -1213,14 +1214,17 @@ var getActionByReference = ($ref, actions = []) => {
1213
1214
  };
1214
1215
 
1215
1216
  // src/domain/mappers/utils/call-to-action-utils.ts
1216
- var getDomainLayerCallToAction = (callToAction, onBehavior, stepActions) => {
1217
+ var getDomainLayerCallToAction = (callToAction, mapperProps) => {
1218
+ var _a;
1217
1219
  if (!callToAction) {
1218
1220
  return void 0;
1219
1221
  }
1222
+ const { step, onBehavior, registerSubmissionBehavior } = mapperProps;
1223
+ const stepActions = (_a = step.actions) != null ? _a : [];
1220
1224
  const { title = "", accessibilityDescription, action, behavior } = callToAction;
1221
1225
  return getCallToAction(
1222
1226
  { title, accessibilityDescription },
1223
- getDomainLayerBehavior({ action, behavior }, stepActions),
1227
+ getDomainLayerBehavior({ action, behavior }, stepActions, registerSubmissionBehavior),
1224
1228
  onBehavior
1225
1229
  );
1226
1230
  };
@@ -1314,9 +1318,8 @@ var alertLayoutToComponent = (uid, {
1314
1318
  callToAction,
1315
1319
  analyticsId,
1316
1320
  tags
1317
- }, { onBehavior, step }) => {
1318
- var _a;
1319
- const cta = callToAction ? getDomainLayerCallToAction(callToAction, onBehavior, (_a = step.actions) != null ? _a : []) : void 0;
1321
+ }, mapperProps) => {
1322
+ const cta = callToAction ? getDomainLayerCallToAction(callToAction, mapperProps) : void 0;
1320
1323
  return createAlertComponent({
1321
1324
  uid,
1322
1325
  analyticsId,
@@ -1405,7 +1408,11 @@ var buttonLayoutToComponentWithBehavior = (uid, button, mapperProps) => {
1405
1408
  analyticsId,
1406
1409
  tags
1407
1410
  } = button;
1408
- const behavior = getDomainLayerBehavior(button, (_a = mapperProps.step.actions) != null ? _a : []);
1411
+ const behavior = getDomainLayerBehavior(
1412
+ button,
1413
+ (_a = mapperProps.step.actions) != null ? _a : [],
1414
+ mapperProps.registerSubmissionBehavior
1415
+ );
1409
1416
  const onClick = () => {
1410
1417
  void onBehavior(behavior);
1411
1418
  };
@@ -1549,9 +1556,10 @@ var mapInlineAlert = (alert) => {
1549
1556
  context: alert.context ? mapLegacyContext(alert.context) : "neutral"
1550
1557
  } : void 0;
1551
1558
  };
1552
- var mapAdditionalInfo = (info, onBehavior) => {
1559
+ var mapAdditionalInfo = (info, mapperProps) => {
1560
+ const { onBehavior, registerSubmissionBehavior } = mapperProps;
1553
1561
  if (info) {
1554
- const behavior = getDomainLayerBehavior(info, []);
1562
+ const behavior = getDomainLayerBehavior(info, [], registerSubmissionBehavior);
1555
1563
  return {
1556
1564
  text: info.text,
1557
1565
  href: behavior.type === "link" ? behavior.url : void 0,
@@ -1578,20 +1586,21 @@ var decisionLayoutToComponent = (uid, {
1578
1586
  options,
1579
1587
  tags,
1580
1588
  title
1581
- }, { onBehavior, step }) => createDecisionComponent({
1589
+ }, mapperProps) => createDecisionComponent({
1582
1590
  uid,
1583
1591
  analyticsId,
1584
1592
  control,
1585
1593
  margin,
1586
- options: options.map((option) => mapOption(option, onBehavior, step.actions)),
1594
+ options: options.map((option) => mapOption(option, mapperProps)),
1587
1595
  tags,
1588
1596
  title
1589
1597
  });
1590
- var mapOption = (option, onBehavior, stepActions = []) => {
1591
- var _a;
1592
- const behavior = getDomainLayerBehavior(option, stepActions);
1598
+ var mapOption = (option, mapperProps) => {
1599
+ var _a, _b;
1600
+ const { step, onBehavior, registerSubmissionBehavior } = mapperProps;
1601
+ const behavior = getDomainLayerBehavior(option, (_a = step.actions) != null ? _a : [], registerSubmissionBehavior);
1593
1602
  return __spreadProps(__spreadValues({}, option), {
1594
- disabled: (_a = option.disabled) != null ? _a : false,
1603
+ disabled: (_b = option.disabled) != null ? _b : false,
1595
1604
  href: behavior.type === "link" ? behavior.url : void 0,
1596
1605
  media: getDomainLayerMedia(option),
1597
1606
  inlineAlert: mapInlineAlert(option.inlineAlert),
@@ -1780,21 +1789,18 @@ var createListComponent = (listProps) => __spreadValues({
1780
1789
 
1781
1790
  // src/domain/mappers/layout/listLayoutToComponent.ts
1782
1791
  var listLayoutToComponent = (uid, { analyticsId, callToAction, control, items, margin = "md", tags, title }, mapperProps) => {
1783
- var _a;
1784
- const { step, onBehavior } = mapperProps;
1785
1792
  return createListComponent({
1786
1793
  uid,
1787
1794
  analyticsId,
1788
1795
  control,
1789
1796
  items: items.map((item) => mapItem(item, mapperProps)),
1790
- callToAction: getDomainLayerCallToAction(callToAction, onBehavior, (_a = step.actions) != null ? _a : []),
1797
+ callToAction: getDomainLayerCallToAction(callToAction, mapperProps),
1791
1798
  margin,
1792
1799
  tags,
1793
1800
  title
1794
1801
  });
1795
1802
  };
1796
1803
  var mapItem = (item, mapperProps) => {
1797
- var _b;
1798
1804
  const _a = item, {
1799
1805
  value,
1800
1806
  subvalue,
@@ -1818,14 +1824,13 @@ var mapItem = (item, mapperProps) => {
1818
1824
  "additionalInfo",
1819
1825
  "inlineAlert"
1820
1826
  ]);
1821
- const { step, onBehavior } = mapperProps;
1822
1827
  return __spreadProps(__spreadValues({}, rest), {
1823
1828
  description: description != null ? description : subtitle,
1824
1829
  media: getDomainLayerMedia({ icon, image, media }),
1825
1830
  supportingValues: mapSupportingValues(item),
1826
- additionalInfo: mapAdditionalInfo(additionalInfo, onBehavior),
1831
+ additionalInfo: mapAdditionalInfo(additionalInfo, mapperProps),
1827
1832
  inlineAlert: mapInlineAlert(inlineAlert),
1828
- callToAction: getDomainLayerCallToAction(callToAction, onBehavior, (_b = step.actions) != null ? _b : []),
1833
+ callToAction: getDomainLayerCallToAction(callToAction, mapperProps),
1829
1834
  tags: mapTags(rest)
1830
1835
  });
1831
1836
  };
@@ -1937,31 +1942,30 @@ var reviewLayoutToComponent = (uid, {
1937
1942
  tags,
1938
1943
  orientation,
1939
1944
  action
1940
- }, { onBehavior, step }) => createReviewComponent({
1945
+ }, mapperProps) => createReviewComponent({
1941
1946
  uid,
1942
1947
  analyticsId,
1943
- callToAction: getCallToAction2({ onBehavior, callToAction, action, stepActions: step.actions }),
1948
+ callToAction: getCallToAction2({ mapperProps, callToAction, action }),
1944
1949
  control: getOrientationControl({ control, orientation }),
1945
- fields: fields.map((field) => mapReviewField(field, { onBehavior, step })),
1950
+ fields: fields.map((field) => mapReviewField(field, mapperProps)),
1946
1951
  margin,
1947
1952
  tags,
1948
1953
  title
1949
1954
  });
1950
1955
  var getCallToAction2 = ({
1951
- onBehavior,
1952
1956
  callToAction,
1953
1957
  action,
1954
- stepActions = []
1958
+ mapperProps
1955
1959
  }) => {
1956
1960
  if (callToAction) {
1957
- return getDomainLayerCallToAction(callToAction, onBehavior, stepActions);
1961
+ return getDomainLayerCallToAction(callToAction, mapperProps);
1958
1962
  }
1959
1963
  if (action == null ? void 0 : action.title) {
1960
1964
  return {
1961
1965
  type: "action",
1962
1966
  title: action.title,
1963
1967
  onClick: () => {
1964
- void onBehavior({ type: "action", action });
1968
+ void mapperProps.onBehavior({ type: "action", action });
1965
1969
  }
1966
1970
  };
1967
1971
  }
@@ -1979,17 +1983,16 @@ var getOrientationControl = ({
1979
1983
  }
1980
1984
  return void 0;
1981
1985
  };
1982
- var mapReviewField = (field, { onBehavior, step }) => {
1983
- var _a, _b;
1986
+ var mapReviewField = (field, mapperProps) => {
1987
+ var _a;
1984
1988
  return __spreadProps(__spreadValues({}, field), {
1985
1989
  media: getDomainLayerMedia(field),
1986
1990
  help: (_a = field.help) == null ? void 0 : _a.markdown,
1987
1991
  inlineAlert: mapInlineAlert(field.inlineAlert),
1988
- additionalInfo: mapAdditionalInfo(field.additionalInfo, onBehavior),
1992
+ additionalInfo: mapAdditionalInfo(field.additionalInfo, mapperProps),
1989
1993
  callToAction: getCallToAction2({
1990
- onBehavior,
1991
1994
  callToAction: field.callToAction,
1992
- stepActions: (_b = step.actions) != null ? _b : []
1995
+ mapperProps
1993
1996
  }),
1994
1997
  tags: mapTags(field)
1995
1998
  });
@@ -2186,17 +2189,12 @@ var searchLayoutToComponent = (uid, {
2186
2189
  };
2187
2190
 
2188
2191
  // src/domain/mappers/layout/statusListLayoutToComponent.ts
2189
- var statusListLayoutToComponent = (uid, { analyticsId, control, items, margin = "md", tags, title }, { onBehavior, step }) => createStatusListComponent({
2192
+ var statusListLayoutToComponent = (uid, { analyticsId, control, items, margin = "md", tags, title }, mapperProps) => createStatusListComponent({
2190
2193
  uid,
2191
2194
  analyticsId,
2192
2195
  control,
2193
2196
  items: items.map((item) => {
2194
- var _a;
2195
- const callToAction = getDomainLayerCallToAction(
2196
- item.callToAction,
2197
- onBehavior,
2198
- (_a = step.actions) != null ? _a : []
2199
- );
2197
+ const callToAction = getDomainLayerCallToAction(item.callToAction, mapperProps);
2200
2198
  return __spreadProps(__spreadValues({}, item), { callToAction, tags: mapTags(item) });
2201
2199
  }),
2202
2200
  margin,
@@ -2217,7 +2215,6 @@ var createSectionComponent = (props) => {
2217
2215
 
2218
2216
  // src/domain/mappers/layout/sectionLayoutToComponent.ts
2219
2217
  var sectionLayoutToComponent = (uid, { analyticsId, control, title, components, callToAction, margin = "md", tags }, mapperProps, schemaComponents) => {
2220
- var _a;
2221
2218
  return createSectionComponent({
2222
2219
  uid,
2223
2220
  analyticsId,
@@ -2227,11 +2224,7 @@ var sectionLayoutToComponent = (uid, { analyticsId, control, title, components,
2227
2224
  (component, index) => mapLayoutToComponent(`${uid}.section-${index}`, component, mapperProps, schemaComponents)
2228
2225
  ),
2229
2226
  margin,
2230
- callToAction: getDomainLayerCallToAction(
2231
- callToAction,
2232
- mapperProps.onBehavior,
2233
- (_a = mapperProps.step.actions) != null ? _a : []
2234
- ),
2227
+ callToAction: getDomainLayerCallToAction(callToAction, mapperProps),
2235
2228
  tags
2236
2229
  });
2237
2230
  };
@@ -2360,34 +2353,39 @@ var modalToComponent = (uid, { content, title }, mapperProps, schemaComponents)
2360
2353
  mapperProps.updateComponent
2361
2354
  );
2362
2355
 
2363
- // src/domain/components/step/ExternalConfirmationComponent.ts
2364
- var createExternalConfirmation = (uid, url, updateComponent) => {
2365
- const update = getInputUpdateFunction(updateComponent);
2356
+ // src/domain/prefetching/request-cache.ts
2357
+ var makeRequestCache = () => {
2358
+ const cache = /* @__PURE__ */ new Map();
2366
2359
  return {
2367
- type: "external-confirmation",
2368
- kind: "layout",
2369
- uid,
2370
- url,
2371
- status: "initial",
2372
- onSuccess() {
2373
- update(this, (draft) => {
2374
- draft.status = "success";
2375
- });
2360
+ has: (...requestParams) => {
2361
+ return cache.has(makeKey(...requestParams));
2376
2362
  },
2377
- onFailure() {
2378
- if (this.status === "initial") {
2379
- update(this, (draft) => {
2380
- draft.status = "failure";
2381
- });
2382
- }
2363
+ get: (...requestParams) => {
2364
+ return cache.get(makeKey(...requestParams));
2383
2365
  },
2384
- onCancel() {
2385
- update(this, (draft) => {
2386
- draft.status = "dismissed";
2387
- });
2366
+ delete: (...requestParams) => {
2367
+ return cache.delete(makeKey(...requestParams));
2368
+ },
2369
+ set: (...[input, init, response]) => {
2370
+ return cache.set(makeKey(input, init), response);
2371
+ },
2372
+ clear: () => {
2373
+ cache.clear();
2388
2374
  }
2389
2375
  };
2390
2376
  };
2377
+ var makeKey = (...requestParams) => {
2378
+ var _a, _b;
2379
+ const [input, init] = requestParams;
2380
+ const url = typeof input === "string" || input instanceof URL ? input.toString() : input.url;
2381
+ const key = JSON.stringify({
2382
+ url,
2383
+ method: (_a = init == null ? void 0 : init.method) != null ? _a : "GET",
2384
+ headers: (init == null ? void 0 : init.headers) ? Array.from(new Headers(init.headers).entries()) : [],
2385
+ body: (_b = init == null ? void 0 : init.body) != null ? _b : null
2386
+ });
2387
+ return key;
2388
+ };
2391
2389
 
2392
2390
  // src/utils/recursiveMerge.ts
2393
2391
  function recursiveMerge(valueA, valueB) {
@@ -2428,6 +2426,57 @@ function mergeArrays(valueA, valueB) {
2428
2426
  );
2429
2427
  }
2430
2428
 
2429
+ // src/flow/makeSubmissionRequest.ts
2430
+ var makeSubmissionRequest = (action, model) => {
2431
+ var _a, _b;
2432
+ return [
2433
+ (_a = action.url) != null ? _a : "",
2434
+ {
2435
+ method: (_b = action.method) != null ? _b : "POST",
2436
+ body: makeRequestBody(action, model),
2437
+ headers: { "Content-Type": "application/json" }
2438
+ }
2439
+ ];
2440
+ };
2441
+ var makeRequestBody = (action, model) => {
2442
+ var _a, _b;
2443
+ const method = (_a = action.method) != null ? _a : "POST";
2444
+ if (method === "GET") {
2445
+ return void 0;
2446
+ }
2447
+ const payload = recursiveMerge(model, (_b = action.data) != null ? _b : null);
2448
+ return payload !== null ? JSON.stringify(payload) : null;
2449
+ };
2450
+
2451
+ // src/domain/components/step/ExternalConfirmationComponent.ts
2452
+ var createExternalConfirmation = (uid, url, updateComponent) => {
2453
+ const update = getInputUpdateFunction(updateComponent);
2454
+ return {
2455
+ type: "external-confirmation",
2456
+ kind: "layout",
2457
+ uid,
2458
+ url,
2459
+ status: "initial",
2460
+ onSuccess() {
2461
+ update(this, (draft) => {
2462
+ draft.status = "success";
2463
+ });
2464
+ },
2465
+ onFailure() {
2466
+ if (this.status === "initial") {
2467
+ update(this, (draft) => {
2468
+ draft.status = "failure";
2469
+ });
2470
+ }
2471
+ },
2472
+ onCancel() {
2473
+ update(this, (draft) => {
2474
+ draft.status = "dismissed";
2475
+ });
2476
+ }
2477
+ };
2478
+ };
2479
+
2431
2480
  // src/utils/component-utils.ts
2432
2481
  var getSubmittableData = async (components) => Promise.all(components.map(async (component) => component.getSubmittableValue())).then(
2433
2482
  (values) => values.reduce((acc, value) => recursiveMerge(acc, value), null)
@@ -2507,7 +2556,8 @@ var getStepPolling = ({
2507
2556
  pollingConfig,
2508
2557
  logEvent,
2509
2558
  onBehavior,
2510
- onPoll
2559
+ onPoll,
2560
+ registerSubmissionBehavior
2511
2561
  }) => {
2512
2562
  const { interval, delay = interval, maxAttempts, url, onError } = pollingConfig;
2513
2563
  let abortController = new AbortController();
@@ -2515,7 +2565,7 @@ var getStepPolling = ({
2515
2565
  if (delay == null) {
2516
2566
  throw new Error("Polling configuration must include delay or interval");
2517
2567
  }
2518
- const onErrorBehavior = getDomainLayerBehavior(onError, []);
2568
+ const onErrorBehavior = getDomainLayerBehavior(onError, [], registerSubmissionBehavior);
2519
2569
  let attempts = 0;
2520
2570
  const poll = () => {
2521
2571
  attempts += 1;
@@ -4830,11 +4880,12 @@ var objectSchemaToMoneyInputComponent = (schemaMapperProps, mapperProps) => {
4830
4880
  );
4831
4881
  };
4832
4882
  var createMoneyInputSubComponents = (schemaMapperProps, mapperProps) => {
4833
- const { schema: objectSchema } = schemaMapperProps;
4883
+ const { schema: objectSchema, model } = schemaMapperProps;
4834
4884
  const amountKey = getAmountSchemaKey(objectSchema, mapperProps);
4835
4885
  const currencyKey = getCurrencySchemaKey(objectSchema, mapperProps);
4836
4886
  const currencySchema = objectSchema.properties[currencyKey];
4837
4887
  const customSchemaMapperProps = __spreadProps(__spreadValues({}, schemaMapperProps), {
4888
+ model: getSanitizedModel(amountKey, model),
4838
4889
  schema: isOneOfSchema(currencySchema) ? objectSchema : replaceKeyInObjectSchema(objectSchema, currencyKey, { oneOf: [currencySchema] })
4839
4890
  });
4840
4891
  const componentMap = createComponentMap(customSchemaMapperProps, mapperProps, "money");
@@ -4846,6 +4897,18 @@ var createMoneyInputSubComponents = (schemaMapperProps, mapperProps) => {
4846
4897
  const checks = getMinMaxChecks(objectSchema, amountKey, mapperProps);
4847
4898
  return { amountKey, amountComponent, currencyKey, currencyComponent, extraValues, checks };
4848
4899
  };
4900
+ var isNumberString = (value) => {
4901
+ return typeof value === "string" && !Number.isNaN(Number.parseFloat(value)) && /^\d*(?:\.\d*)?$/.test(value);
4902
+ };
4903
+ var getSanitizedModel = (key, value) => {
4904
+ if (isObject(value)) {
4905
+ const amount = value[key];
4906
+ if (!isNumberString(amount)) {
4907
+ return __spreadProps(__spreadValues({}, value), { [key]: null });
4908
+ }
4909
+ }
4910
+ return value;
4911
+ };
4849
4912
  var getAmountSchemaKey = ({ displayOrder, properties }, mapperProps) => {
4850
4913
  var _a;
4851
4914
  const entry = displayOrder.map((key) => ({ key, schema: properties[key] })).find(({ schema }) => isAmountSchema(schema));
@@ -5647,7 +5710,11 @@ var mapToolbarToComponent = (uid, toolbar, mapperProps) => {
5647
5710
  tags: toolbar.tags,
5648
5711
  items: toolbar.items.map((item) => {
5649
5712
  const context = item.context ? mapLegacyContext(item.context) : void 0;
5650
- const behavior = getDomainLayerBehavior({ behavior: item.behavior }, []);
5713
+ const behavior = getDomainLayerBehavior(
5714
+ { behavior: item.behavior },
5715
+ [],
5716
+ mapperProps.registerSubmissionBehavior
5717
+ );
5651
5718
  return __spreadProps(__spreadValues({}, item), {
5652
5719
  context: context ? mapLegacyContext(context) : void 0,
5653
5720
  disabled: !!item.disabled,
@@ -5743,16 +5810,29 @@ var mapStepToComponent = (_a) => {
5743
5810
  title,
5744
5811
  tags
5745
5812
  } = step;
5813
+ const submissionRequestsCache = makeRequestCache();
5814
+ const submissionBehaviors = [];
5815
+ const registerSubmissionBehavior = (behavior) => {
5816
+ if (behavior.type === "action" && behavior.action.prefetch) {
5817
+ submissionBehaviors.push(behavior);
5818
+ }
5819
+ };
5746
5820
  const back = mapBackNavigation(navigation, onBehavior, Boolean(features.nativeBack));
5747
5821
  const stepId = id || key;
5748
5822
  if (stepId === void 0) {
5749
5823
  throw new Error("Step must have an id or a key");
5750
5824
  }
5751
5825
  const uid = `${rootUid}.${stepId != null ? stepId : "step"}`;
5752
- const stepPolling = polling ? getStepPolling({ pollingConfig: polling, logEvent, onBehavior, onPoll }) : void 0;
5826
+ const stepPolling = polling ? getStepPolling({
5827
+ pollingConfig: polling,
5828
+ logEvent,
5829
+ onBehavior,
5830
+ onPoll,
5831
+ registerSubmissionBehavior
5832
+ }) : void 0;
5753
5833
  const stepRefreshAfter = refreshAfter ? getStepRefreshAfter({ refreshAfter, logEvent, onBehavior }) : void 0;
5754
5834
  const externalConfirmation = (external == null ? void 0 : external.url) ? createExternalConfirmation(`${uid}-external-confirmation`, external == null ? void 0 : external.url, updateComponent) : void 0;
5755
- const mapperProps = __spreadProps(__spreadValues({}, restProps), { trackEvent, onBehavior });
5835
+ const mapperProps = __spreadProps(__spreadValues({}, restProps), { trackEvent, onBehavior, registerSubmissionBehavior });
5756
5836
  const referencedSchemaIds = getReferencedSchemaId(step);
5757
5837
  const schemaComponents = mapStepSchemas(
5758
5838
  uid,
@@ -5796,11 +5876,18 @@ var mapStepToComponent = (_a) => {
5796
5876
  title: !features.hideStepTitle ? title : void 0,
5797
5877
  tags,
5798
5878
  stackBehavior: (_a2 = navigation == null ? void 0 : navigation.stackBehavior) != null ? _a2 : "default",
5879
+ submissionRequestsCache,
5799
5880
  step,
5800
5881
  updateComponent,
5801
5882
  trackEvent,
5802
5883
  onBehavior
5803
5884
  });
5885
+ executePrefetch({
5886
+ httpClient: mapperProps.httpClient,
5887
+ model: stepComponent.getSubmittableValueSync(),
5888
+ behaviors: submissionBehaviors,
5889
+ requestsCache: submissionRequestsCache
5890
+ });
5804
5891
  return stepComponent;
5805
5892
  };
5806
5893
  var getReferencedSchemaId = (step) => {
@@ -5821,6 +5908,22 @@ var mapBackNavigation = (navigation, onBehavior, isNativeBackEnabled) => {
5821
5908
  }
5822
5909
  } : void 0;
5823
5910
  };
5911
+ var executePrefetch = (props) => {
5912
+ const {
5913
+ httpClient,
5914
+ behaviors: submissionBehaviors,
5915
+ model,
5916
+ requestsCache: submissionRequestsCache
5917
+ } = props;
5918
+ submissionBehaviors.forEach((behavior) => {
5919
+ const requestParams = makeSubmissionRequest(behavior.action, model);
5920
+ try {
5921
+ const responsePromise = httpClient(...requestParams).catch(() => null);
5922
+ submissionRequestsCache.set(...requestParams, responsePromise);
5923
+ } catch (e) {
5924
+ }
5925
+ });
5926
+ };
5824
5927
 
5825
5928
  // src/flow/getResponseType.ts
5826
5929
  var responseTypes = ["step", "action", "exit", "modal"];
@@ -5949,11 +6052,20 @@ var executeRefresh = async (props) => {
5949
6052
  }
5950
6053
  };
5951
6054
 
6055
+ // src/flow/makeSafeHttpClient.ts
6056
+ var makeSafeHttpClient = (httpClient) => async (...props) => {
6057
+ try {
6058
+ return await httpClient(...props);
6059
+ } catch (e) {
6060
+ return null;
6061
+ }
6062
+ };
6063
+
5952
6064
  // src/flow/executeSubmission.ts
5953
6065
  var executeSubmission = async (props) => {
5954
- const { httpClient, trackEvent, logEvent } = props;
6066
+ const { httpClient, requestCache, trackEvent, logEvent } = props;
5955
6067
  const triggerAction = async (action, model, isInitial) => {
5956
- const { exit, url, method = "POST", result = null, id: actionId } = action;
6068
+ const { exit, url, result = null, id: actionId } = action;
5957
6069
  const trackSubmissionEvent = !isInitial ? trackEvent : () => {
5958
6070
  };
5959
6071
  trackSubmissionEvent("Action Triggered", { actionId });
@@ -5961,19 +6073,8 @@ var executeSubmission = async (props) => {
5961
6073
  trackSubmissionEvent("Action Succeeded", { actionId });
5962
6074
  return { type: "complete", result };
5963
6075
  }
5964
- const makeRequestBody = () => {
5965
- var _a;
5966
- if (method === "GET") {
5967
- return void 0;
5968
- }
5969
- const payload = recursiveMerge(model, (_a = action.data) != null ? _a : null);
5970
- return payload !== null ? JSON.stringify(payload) : null;
5971
- };
5972
- const response = await getSafeHttpClient(httpClient)(url != null ? url : "", {
5973
- method,
5974
- body: makeRequestBody(),
5975
- headers: { "Content-Type": "application/json" }
5976
- });
6076
+ const requestParams = makeSubmissionRequest(action, model);
6077
+ const response = await getCachedOrFetch(requestParams, requestCache, httpClient);
5977
6078
  if (!response) {
5978
6079
  const extra = { actionId, errorMessage: "Network Error" };
5979
6080
  trackEvent("Action Failed", extra);
@@ -6046,12 +6147,18 @@ var executeSubmission = async (props) => {
6046
6147
  };
6047
6148
  return triggerAction(props.action, props.model, props.isInitial);
6048
6149
  };
6049
- var getSafeHttpClient = (httpClient) => async (input, init) => {
6050
- try {
6051
- return await httpClient(input, init);
6052
- } catch (e) {
6053
- return null;
6150
+ var getCachedOrFetch = async (requestParams, requestCache, httpClient) => {
6151
+ if (requestCache == null ? void 0 : requestCache.has(...requestParams)) {
6152
+ const cachedPromise = requestCache.get(...requestParams);
6153
+ requestCache.delete(...requestParams);
6154
+ if (cachedPromise) {
6155
+ const cachedResponse = await cachedPromise;
6156
+ if (cachedResponse == null ? void 0 : cachedResponse.ok) {
6157
+ return cachedResponse;
6158
+ }
6159
+ }
6054
6160
  }
6161
+ return makeSafeHttpClient(httpClient)(...requestParams);
6055
6162
  };
6056
6163
 
6057
6164
  // src/renderers/getSchemaErrorMessageFunction.ts
@@ -6503,10 +6610,14 @@ function useDynamicFlowCore(props) {
6503
6610
  modalToComponent(
6504
6611
  rootComponentRef.current.uid,
6505
6612
  behavior,
6506
- __spreadValues({
6613
+ __spreadProps(__spreadValues({
6507
6614
  step: currentStep,
6508
6615
  stepLocalValue: rootComponentRef.current.getLocalValue()
6509
- }, getMapperProps()),
6616
+ }, getMapperProps()), {
6617
+ registerSubmissionBehavior: () => {
6618
+ }
6619
+ // this means actions in modal responses won't have prefetching
6620
+ }),
6510
6621
  rootComponentRef.current.getSchemaComponents()
6511
6622
  )
6512
6623
  );
@@ -6525,13 +6636,14 @@ function useDynamicFlowCore(props) {
6525
6636
  }, []);
6526
6637
  const onAction = (0, import_react3.useCallback)(
6527
6638
  async (action, model) => {
6528
- var _a2, _b, _c, _d, _e, _f, _g, _h;
6639
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
6529
6640
  try {
6530
6641
  rootComponentRef.current.setLoadingState("submitting");
6531
6642
  const command = await executeSubmission({
6532
6643
  action,
6533
6644
  model,
6534
6645
  isInitial: !rootComponentRef.current.hasStep(),
6646
+ requestCache: (_a2 = rootComponentRef.current.getStep()) == null ? void 0 : _a2.submissionRequestsCache,
6535
6647
  httpClient,
6536
6648
  trackEvent: trackCoreEvent,
6537
6649
  logEvent
@@ -6552,7 +6664,7 @@ function useDynamicFlowCore(props) {
6552
6664
  case "error": {
6553
6665
  rootComponentRef.current.setLoadingState("idle");
6554
6666
  const genericErrorMessage = getErrorMessageFunctions().genericErrorWithRetry();
6555
- const errors = (_b = (_a2 = command.body) == null ? void 0 : _a2.errors) != null ? _b : { error: genericErrorMessage };
6667
+ const errors = (_c = (_b = command.body) == null ? void 0 : _b.errors) != null ? _c : { error: genericErrorMessage };
6556
6668
  const currentStep = rootComponentRef.current.getStep();
6557
6669
  if (currentStep) {
6558
6670
  updateStep(
@@ -6566,16 +6678,16 @@ function useDynamicFlowCore(props) {
6566
6678
  external: void 0
6567
6679
  // and no external, to avoid retriggering it
6568
6680
  }),
6569
- (_d = (_c = rootComponentRef.current.getStep()) == null ? void 0 : _c.etag) != null ? _d : null
6681
+ (_e = (_d = rootComponentRef.current.getStep()) == null ? void 0 : _d.etag) != null ? _e : null
6570
6682
  );
6571
6683
  } else {
6572
- const errorMessage = ((_f = (_e = command.body) == null ? void 0 : _e.errors) == null ? void 0 : _f.error) || ((_g = command.httpError) == null ? void 0 : _g.message) || "Initial request failed";
6684
+ const errorMessage = ((_g = (_f = command.body) == null ? void 0 : _f.errors) == null ? void 0 : _g.error) || ((_h = command.httpError) == null ? void 0 : _h.message) || "Initial request failed";
6573
6685
  closeWithError(
6574
6686
  new Error(errorMessage, {
6575
6687
  cause: `method: ${action.method}, url: ${action.url}`
6576
6688
  }),
6577
6689
  {},
6578
- (_h = command.httpError) == null ? void 0 : _h.statusCode
6690
+ (_i = command.httpError) == null ? void 0 : _i.statusCode
6579
6691
  );
6580
6692
  }
6581
6693
  break;