@wise/dynamic-flow-client 5.5.1 → 5.6.1

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/build/main.js CHANGED
@@ -1337,9 +1337,10 @@ var createBoxComponent = (boxProps) => __spreadProps(__spreadValues({}, boxProps
1337
1337
  });
1338
1338
 
1339
1339
  // src/domain/mappers/utils/layout-utils.ts
1340
- var removeMarginFromLayout = (component) => {
1341
- return __spreadProps(__spreadValues({}, component), {
1342
- margin: "xs"
1340
+ var normaliseMarginInLastComponent = (container) => {
1341
+ return container.map((component, index) => {
1342
+ const shouldRemoveMargin = index === container.length - 1 && component.margin === void 0;
1343
+ return shouldRemoveMargin ? __spreadProps(__spreadValues({}, component), { margin: "xs" }) : component;
1343
1344
  });
1344
1345
  };
1345
1346
 
@@ -1352,16 +1353,9 @@ var boxLayoutToComponent = (uid, { border = false, components, control, margin,
1352
1353
  margin: margin != null ? margin : "md",
1353
1354
  width: width != null ? width : "xl",
1354
1355
  tags,
1355
- components: components.map((component, index) => {
1356
- const shouldRemoveMargin = index === components.length - 1 && component.margin === void 0;
1357
- const componentWithAdjustedMargin = shouldRemoveMargin ? removeMarginFromLayout(component) : component;
1358
- return mapLayoutToComponent(
1359
- `${uid}.box-${index}`,
1360
- componentWithAdjustedMargin,
1361
- mapperProps,
1362
- schemaComponents
1363
- );
1364
- })
1356
+ components: normaliseMarginInLastComponent(components).map(
1357
+ (component, index) => mapLayoutToComponent(`${uid}.box-${index}`, component, mapperProps, schemaComponents)
1358
+ )
1365
1359
  });
1366
1360
 
1367
1361
  // src/domain/components/ButtonComponent.ts
@@ -2323,6 +2317,35 @@ var modalToComponent = (uid, { content, title }, mapperProps, schemaComponents)
2323
2317
  mapperProps.onComponentUpdate
2324
2318
  );
2325
2319
 
2320
+ // src/domain/components/step/ExternalConfirmationComponent.ts
2321
+ var createExternalConfirmation = (uid, url, onComponentUpdate) => {
2322
+ const update = getInputUpdateFunction(onComponentUpdate);
2323
+ return {
2324
+ type: "external-confirmation",
2325
+ kind: "layout",
2326
+ uid,
2327
+ url,
2328
+ status: "initial",
2329
+ onSuccess() {
2330
+ update(this, (draft) => {
2331
+ draft.status = "success";
2332
+ });
2333
+ },
2334
+ onFailure() {
2335
+ if (this.status === "initial") {
2336
+ update(this, (draft) => {
2337
+ draft.status = "failure";
2338
+ });
2339
+ }
2340
+ },
2341
+ onCancel() {
2342
+ update(this, (draft) => {
2343
+ draft.status = "dismissed";
2344
+ });
2345
+ }
2346
+ };
2347
+ };
2348
+
2326
2349
  // src/utils/recursiveMerge.ts
2327
2350
  function recursiveMerge(valueA, valueB) {
2328
2351
  if (valueA === null) {
@@ -2362,526 +2385,162 @@ function mergeArrays(valueA, valueB) {
2362
2385
  );
2363
2386
  }
2364
2387
 
2365
- // src/controller/getErrorMessage.ts
2366
- var getErrorMessage = (error) => {
2367
- return error instanceof Error ? error.message : typeof error === "string" ? error : `Unknown Error: type is ${typeof error}`;
2368
- };
2388
+ // src/utils/component-utils.ts
2389
+ var getSubmittableData = async (components) => Promise.all(components.map(async (component) => component.getSubmittableValue())).then(
2390
+ (values) => values.reduce((acc, value) => recursiveMerge(acc, value), null)
2391
+ );
2392
+ var getSubmittableDataSync = (components) => components.map((component) => component.getSubmittableValueSync()).reduce((acc, value) => recursiveMerge(acc, value), null);
2393
+ var getLocalValues = (components) => components.map((component) => component.getLocalValue()).reduce((acc, value) => recursiveMerge(acc, value), null);
2369
2394
 
2370
- // src/controller/response-utils.ts
2371
- var import_spec = require("@wise/dynamic-flow-types/spec");
2372
- var parseResponseBodyAsJsonElement = async (response) => {
2373
- assertResponseIsValid(response);
2374
- try {
2375
- return await response.json();
2376
- } catch (e) {
2377
- return null;
2378
- }
2379
- };
2380
- var parseResponseBodyAsText = async (response) => {
2381
- try {
2382
- return await response.text();
2383
- } catch (e) {
2384
- return null;
2385
- }
2395
+ // src/domain/components/step/StepDomainComponent.ts
2396
+ var createStepComponent = (stepProps) => {
2397
+ const _a = stepProps, { uid, stepPolling, stepRefreshAfter, stepPrefetch, onComponentUpdate } = _a, rest = __objRest(_a, ["uid", "stepPolling", "stepRefreshAfter", "stepPrefetch", "onComponentUpdate"]);
2398
+ const update = getInputUpdateFunction(onComponentUpdate);
2399
+ const component = __spreadProps(__spreadValues({
2400
+ uid
2401
+ }, rest), {
2402
+ type: "step",
2403
+ kind: "step",
2404
+ modals: [],
2405
+ requestCache: stepPrefetch.requestCache,
2406
+ dismissModal() {
2407
+ var _a2;
2408
+ (_a2 = this.modals.at(-1)) == null ? void 0 : _a2.close();
2409
+ },
2410
+ dismissAllModals() {
2411
+ this._update((draft) => {
2412
+ draft.modals = draft.modals.map((m) => __spreadProps(__spreadValues({}, m), { open: false }));
2413
+ });
2414
+ },
2415
+ showModal(modal) {
2416
+ this._update((draft) => {
2417
+ draft.modals = [...draft.modals, modal];
2418
+ });
2419
+ },
2420
+ _update(updateFn) {
2421
+ update(this, updateFn);
2422
+ },
2423
+ getChildren() {
2424
+ return this.externalConfirmation ? [...this.layoutComponents, this.externalConfirmation] : this.layoutComponents;
2425
+ },
2426
+ getModals() {
2427
+ return this.modals;
2428
+ },
2429
+ async getSubmittableValue() {
2430
+ return getSubmittableData(this.schemaComponents);
2431
+ },
2432
+ getSubmittableValueSync() {
2433
+ return getSubmittableDataSync(this.schemaComponents);
2434
+ },
2435
+ getLocalValue() {
2436
+ return getLocalValues(this.schemaComponents);
2437
+ },
2438
+ validate() {
2439
+ return this.schemaComponents.every(
2440
+ (inputComponent) => inputComponent.isSchemaReferencedInStep ? inputComponent.validate() : true
2441
+ );
2442
+ },
2443
+ setLoadingState(loadingState) {
2444
+ this._update((draft) => {
2445
+ draft.loadingState = loadingState;
2446
+ });
2447
+ },
2448
+ start() {
2449
+ stepPolling == null ? void 0 : stepPolling.start();
2450
+ stepRefreshAfter == null ? void 0 : stepRefreshAfter.start();
2451
+ stepPrefetch.start(this.getSubmittableValueSync());
2452
+ },
2453
+ stop() {
2454
+ stepPolling == null ? void 0 : stepPolling.stop();
2455
+ stepRefreshAfter == null ? void 0 : stepRefreshAfter.stop();
2456
+ stepPrefetch.stop();
2457
+ this._update((draft) => {
2458
+ draft.modals = [];
2459
+ });
2460
+ }
2461
+ });
2462
+ return component;
2386
2463
  };
2387
- function isActionResponseBody(body) {
2388
- return (0, import_spec.validateActionResponse)(body).valid;
2389
- }
2390
- function assertActionResponseBody(body) {
2391
- if (!isObject(body) || !isObject(body.action)) {
2392
- throw new Error(
2393
- "Incorrect response body in action response. Expected an object satisfying the type { action: Action }."
2394
- );
2464
+
2465
+ // src/domain/features/polling/getStepPolling.ts
2466
+ var getStepPolling = ({
2467
+ pollingConfig,
2468
+ logEvent,
2469
+ onBehavior,
2470
+ onPoll,
2471
+ registerSubmissionBehavior
2472
+ }) => {
2473
+ const { interval, delay = interval, maxAttempts, url, onError } = pollingConfig;
2474
+ let abortController = new AbortController();
2475
+ let intervalRef = null;
2476
+ if (delay == null) {
2477
+ throw new Error("Polling configuration must include delay or interval");
2395
2478
  }
2396
- }
2397
- function assertModalResponseBody(body) {
2398
- if (isObject(body)) {
2399
- if ("content" in body && isArray(body.content)) {
2479
+ const onErrorBehavior = getDomainLayerBehavior(onError, [], registerSubmissionBehavior);
2480
+ let attempts = 0;
2481
+ const poll = () => {
2482
+ attempts += 1;
2483
+ abortController.abort();
2484
+ abortController = new AbortController();
2485
+ const { signal } = abortController;
2486
+ onPoll(url, onErrorBehavior, signal).then((result) => {
2487
+ if (result) {
2488
+ stop();
2489
+ return;
2490
+ }
2491
+ if (attempts >= maxAttempts && !signal.aborted) {
2492
+ void onBehavior(onErrorBehavior);
2493
+ stop();
2494
+ }
2495
+ }).catch(() => {
2496
+ });
2497
+ };
2498
+ const start = () => {
2499
+ attempts = 0;
2500
+ intervalRef = setInterval(poll, delay * 1e3);
2501
+ poll();
2502
+ };
2503
+ const stop = () => {
2504
+ if (!intervalRef) {
2505
+ logEvent("warning", "Attempted to stop polling but it was not started");
2400
2506
  return;
2401
2507
  }
2402
- }
2403
- throw new Error(
2404
- "Incorrect response body in modal response. Expected an object satisfying the type { title?: string, components: Layout[] }."
2405
- );
2406
- }
2407
- function assertSubflowResponseBody(body) {
2408
- const { valid } = (0, import_spec.validateSubflowResponse)(body);
2409
- if (valid) {
2410
- return;
2411
- }
2412
- throw new Error("Incorrect response body in subflow response.");
2413
- }
2414
- function isErrorResponseBody(body) {
2415
- return Boolean(
2416
- isObject(body) && (body.refreshFormUrl || body.refreshUrl || body.validation || body.error || body.analytics)
2417
- );
2418
- }
2419
- function assertStepResponseBody(body) {
2420
- if (!isObject(body)) {
2421
- throw new Error("Incorrect response body in step response. Expected an object.");
2422
- }
2423
- }
2424
- var assertResponseIsValid = (response) => {
2425
- if (!isResponse(response)) {
2426
- throw new Error("Incorrect type of response from fetch. Expected object of type Response.");
2427
- }
2428
- if (response.bodyUsed) {
2429
- throw new Error(
2430
- "The body of the provided Response object has already been used. Every request must respond with a new Response object."
2431
- );
2432
- }
2508
+ clearTimeout(intervalRef);
2509
+ abortController.abort();
2510
+ };
2511
+ return { start, stop };
2433
2512
  };
2434
- var isResponse = (response) => typeof response === "object" && response !== null && "clone" in response && "bodyUsed" in response;
2435
2513
 
2436
- // src/controller/handleErrorResponse.ts
2437
- var handleErrorResponse = async (response, actionId, trackEvent) => {
2438
- const body = await parseResponseBodyAsJsonElement(response.clone());
2439
- if (isErrorResponseBody(body)) {
2440
- const refreshUrl = body.refreshUrl || body.refreshFormUrl;
2441
- const { error, validation, analytics } = body;
2442
- trackEvent("Action Failed", __spreadProps(__spreadValues({}, analytics), { actionId, statusCode: response.status }));
2443
- const errors = { error, validation };
2444
- return refreshUrl ? { type: "refresh", body: { refreshUrl, errors } } : {
2445
- type: "error",
2446
- body: { errors, analytics },
2447
- httpError: { statusCode: response.status }
2448
- };
2514
+ // src/domain/features/refreshAfter/getStepRefreshAfter.ts
2515
+ var ONE_SECOND = 1e3;
2516
+ var getStepRefreshAfter = ({
2517
+ refreshAfter,
2518
+ logEvent,
2519
+ onBehavior
2520
+ }) => {
2521
+ let timeout = null;
2522
+ const targetTime = new Date(refreshAfter).getTime();
2523
+ if (typeof refreshAfter !== "string" || Number.isNaN(targetTime)) {
2524
+ throw new Error(`Invalid refreshAfter value: ${String(refreshAfter)}`);
2449
2525
  }
2450
- trackEvent("Action Failed", { actionId, statusCode: response.status });
2451
- const errorMessage = await parseResponseBodyAsText(response);
2526
+ const start = () => {
2527
+ const timeLeft = Math.max(targetTime - Date.now(), ONE_SECOND);
2528
+ timeout = setTimeout(() => {
2529
+ void onBehavior({ type: "refresh", analytics: { schema: "refreshAfter" } });
2530
+ }, timeLeft);
2531
+ };
2452
2532
  return {
2453
- type: "error",
2454
- httpError: {
2455
- message: errorMessage || void 0,
2456
- statusCode: response.status
2533
+ start,
2534
+ stop: () => {
2535
+ if (!timeout) {
2536
+ logEvent("warning", "Attempted to stop refreshAfter but it was not started");
2537
+ return;
2538
+ }
2539
+ clearTimeout(timeout);
2457
2540
  }
2458
2541
  };
2459
2542
  };
2460
2543
 
2461
- // src/controller/getResponseType.ts
2462
- var responseTypes = ["step", "action", "exit", "modal", "subflow"];
2463
- var getResponseType = (headers, body) => {
2464
- const headerResponseType = getResponseTypeFromHeader(headers);
2465
- if (headerResponseType) {
2466
- return headerResponseType;
2467
- }
2468
- if (isObject(body) && body.action) {
2469
- return "action";
2470
- }
2471
- return "step";
2472
- };
2473
- var getResponseTypeFromHeader = (headers) => {
2474
- if (headers == null ? void 0 : headers.has("X-Df-Response-Type")) {
2475
- const type = headers.get("X-Df-Response-Type");
2476
- assertDFResponseType(type);
2477
- return type;
2478
- }
2479
- if (headers == null ? void 0 : headers.has("X-Df-Exit")) {
2480
- return "exit";
2481
- }
2482
- return void 0;
2483
- };
2484
- function assertDFResponseType(type) {
2485
- if (!responseTypes.includes(type)) {
2486
- throw new Error(
2487
- "Unsupported X-Df-Response-Type. Allowed values are 'step', 'action', 'exit', 'error', 'modal', 'subflow'."
2488
- );
2489
- }
2490
- }
2491
-
2492
- // src/controller/makeSafeHttpClient.ts
2493
- var makeSafeHttpClient = (httpClient) => async (...props) => {
2494
- try {
2495
- return await httpClient(...props);
2496
- } catch (e) {
2497
- return null;
2498
- }
2499
- };
2500
-
2501
- // src/controller/executeRequest.ts
2502
- var executeRequest = async (props) => {
2503
- const { exit, request, requestCache, httpClient, trackEvent, logEvent } = props;
2504
- const { url, method, body } = request;
2505
- const response = await getCachedOrFetch(
2506
- [
2507
- url,
2508
- {
2509
- method,
2510
- body: body ? JSON.stringify(body) : void 0,
2511
- headers: { "Content-Type": "application/json" }
2512
- }
2513
- ],
2514
- requestCache,
2515
- httpClient
2516
- );
2517
- if (!response) {
2518
- const extra = { errorMessage: "Network Error" };
2519
- trackEvent("Request Failed", extra);
2520
- logEvent("error", "Dynamic Flow - Request Failed Unexpectedly", extra);
2521
- return { type: "error" };
2522
- }
2523
- if (!response.ok) {
2524
- return handleErrorResponse(response, void 0, trackEvent);
2525
- }
2526
- const responseBody = await parseResponseBodyAsJsonElement(response);
2527
- const responseType = getResponseType(response.headers, responseBody);
2528
- if (exit) {
2529
- return { type: "complete", result: responseBody };
2530
- }
2531
- switch (responseType) {
2532
- case "step": {
2533
- const etag = response.headers.get("etag") || null;
2534
- assertStepResponseBody(responseBody);
2535
- return { type: "replace-step", step: responseBody, etag };
2536
- }
2537
- case "exit": {
2538
- return { type: "complete", result: responseBody };
2539
- }
2540
- case "action": {
2541
- assertActionResponseBody(responseBody);
2542
- return {
2543
- type: "behavior",
2544
- behavior: {
2545
- type: "action",
2546
- action: responseBody.action
2547
- }
2548
- };
2549
- }
2550
- case "subflow": {
2551
- assertSubflowResponseBody(responseBody);
2552
- return {
2553
- type: "behavior",
2554
- behavior: __spreadProps(__spreadValues({}, responseBody), {
2555
- type: "subflow",
2556
- onCompletion: responseBody.onCompletion ? normaliseBehavior(responseBody.onCompletion, []) : void 0,
2557
- onError: responseBody.onError ? normaliseBehavior(responseBody.onError, []) : void 0
2558
- })
2559
- };
2560
- }
2561
- case "modal": {
2562
- assertModalResponseBody(responseBody);
2563
- return { type: "behavior", behavior: __spreadProps(__spreadValues({}, responseBody), { type: "modal" }) };
2564
- }
2565
- default: {
2566
- throw new Error(`Unsupported response type: ${String(responseType)}`);
2567
- }
2568
- }
2569
- };
2570
- var getCachedOrFetch = async (requestParams, requestCache, httpClient) => {
2571
- const cachedPromise = requestCache.get(requestParams);
2572
- if (cachedPromise) {
2573
- const cachedResponse = await cachedPromise;
2574
- if (cachedResponse == null ? void 0 : cachedResponse.ok) {
2575
- return cachedResponse;
2576
- }
2577
- }
2578
- return makeSafeHttpClient(httpClient)(...requestParams);
2579
- };
2580
-
2581
- // src/controller/executeSubmission.ts
2582
- var executeSubmission = async (props) => {
2583
- const { httpClient, requestCache, trackEvent, logEvent } = props;
2584
- const triggerAction = async (action, model, isInitial) => {
2585
- var _a, _b;
2586
- const { exit, url, result = null, id: actionId } = action;
2587
- const trackSubmissionEvent = !isInitial ? trackEvent : () => {
2588
- };
2589
- trackSubmissionEvent("Action Triggered", { actionId });
2590
- if (exit && !url) {
2591
- trackSubmissionEvent("Action Succeeded", { actionId });
2592
- return { type: "complete", result };
2593
- }
2594
- try {
2595
- const command = await executeRequest({
2596
- exit,
2597
- request: createRequestFromAction(action, model),
2598
- requestCache,
2599
- httpClient,
2600
- trackEvent: (name, properties) => {
2601
- trackSubmissionEvent(name, __spreadProps(__spreadValues({}, properties), { actionId }));
2602
- },
2603
- logEvent
2604
- });
2605
- switch (command.type) {
2606
- case "error": {
2607
- trackSubmissionEvent("Action Failed", __spreadValues({
2608
- actionId,
2609
- statusCode: (_a = command.httpError) == null ? void 0 : _a.statusCode
2610
- }, (_b = command.body) == null ? void 0 : _b.analytics));
2611
- return command;
2612
- }
2613
- case "behavior": {
2614
- if (command.behavior.type === "action") {
2615
- trackSubmissionEvent("Action Succeeded", { actionId });
2616
- return await executeRequest({
2617
- request: createRequestFromAction(command.behavior.action, null),
2618
- requestCache,
2619
- httpClient,
2620
- trackEvent,
2621
- logEvent
2622
- });
2623
- }
2624
- trackSubmissionEvent("Action Succeeded", { actionId });
2625
- return command;
2626
- }
2627
- case "complete": {
2628
- trackSubmissionEvent("Action Succeeded", { actionId });
2629
- return __spreadProps(__spreadValues({}, command), { result: recursiveMerge(command.result, result) });
2630
- }
2631
- default: {
2632
- trackSubmissionEvent("Action Succeeded", { actionId });
2633
- return command;
2634
- }
2635
- }
2636
- } catch (error) {
2637
- const errorMessage = getErrorMessage(error);
2638
- trackSubmissionEvent("Action Failed", { actionId, errorMessage });
2639
- logEvent("error", "Dynamic Flow - Action Failed Unexpectedly", { actionId, errorMessage });
2640
- throw error;
2641
- }
2642
- };
2643
- return triggerAction(props.action, props.model, props.isInitial);
2644
- };
2645
- var createRequestFromAction = (action, model) => {
2646
- var _a, _b, _c;
2647
- return __spreadProps(__spreadValues({}, action), {
2648
- url: (_a = action.url) != null ? _a : "",
2649
- method: (_b = action.method) != null ? _b : "POST",
2650
- body: action.method === "GET" ? void 0 : recursiveMerge(model, (_c = action.data) != null ? _c : null)
2651
- });
2652
- };
2653
-
2654
- // src/domain/components/step/ExternalConfirmationComponent.ts
2655
- var createExternalConfirmation = (uid, url, onComponentUpdate) => {
2656
- const update = getInputUpdateFunction(onComponentUpdate);
2657
- return {
2658
- type: "external-confirmation",
2659
- kind: "layout",
2660
- uid,
2661
- url,
2662
- status: "initial",
2663
- onSuccess() {
2664
- update(this, (draft) => {
2665
- draft.status = "success";
2666
- });
2667
- },
2668
- onFailure() {
2669
- if (this.status === "initial") {
2670
- update(this, (draft) => {
2671
- draft.status = "failure";
2672
- });
2673
- }
2674
- },
2675
- onCancel() {
2676
- update(this, (draft) => {
2677
- draft.status = "dismissed";
2678
- });
2679
- }
2680
- };
2681
- };
2682
-
2683
- // src/utils/component-utils.ts
2684
- var getSubmittableData = async (components) => Promise.all(components.map(async (component) => component.getSubmittableValue())).then(
2685
- (values) => values.reduce((acc, value) => recursiveMerge(acc, value), null)
2686
- );
2687
- var getSubmittableDataSync = (components) => components.map((component) => component.getSubmittableValueSync()).reduce((acc, value) => recursiveMerge(acc, value), null);
2688
- var getLocalValues = (components) => components.map((component) => component.getLocalValue()).reduce((acc, value) => recursiveMerge(acc, value), null);
2689
-
2690
- // src/domain/components/step/StepDomainComponent.ts
2691
- var createStepComponent = (stepProps) => {
2692
- const _a = stepProps, { uid, stepPolling, stepRefreshAfter, onComponentUpdate } = _a, rest = __objRest(_a, ["uid", "stepPolling", "stepRefreshAfter", "onComponentUpdate"]);
2693
- const update = getInputUpdateFunction(onComponentUpdate);
2694
- const component = __spreadProps(__spreadValues({
2695
- uid
2696
- }, rest), {
2697
- type: "step",
2698
- kind: "step",
2699
- modals: [],
2700
- dismissModal() {
2701
- var _a2;
2702
- (_a2 = this.modals.at(-1)) == null ? void 0 : _a2.close();
2703
- },
2704
- dismissAllModals() {
2705
- this._update((draft) => {
2706
- draft.modals = draft.modals.map((m) => __spreadProps(__spreadValues({}, m), { open: false }));
2707
- });
2708
- },
2709
- showModal(modal) {
2710
- this._update((draft) => {
2711
- draft.modals = [...draft.modals, modal];
2712
- });
2713
- },
2714
- _update(updateFn) {
2715
- update(this, updateFn);
2716
- },
2717
- getChildren() {
2718
- return this.externalConfirmation ? [...this.layoutComponents, this.externalConfirmation] : this.layoutComponents;
2719
- },
2720
- getModals() {
2721
- return this.modals;
2722
- },
2723
- async getSubmittableValue() {
2724
- return getSubmittableData(this.schemaComponents);
2725
- },
2726
- getSubmittableValueSync() {
2727
- return getSubmittableDataSync(this.schemaComponents);
2728
- },
2729
- getLocalValue() {
2730
- return getLocalValues(this.schemaComponents);
2731
- },
2732
- validate() {
2733
- return this.schemaComponents.every(
2734
- (inputComponent) => inputComponent.isSchemaReferencedInStep ? inputComponent.validate() : true
2735
- );
2736
- },
2737
- setLoadingState(loadingState) {
2738
- this._update((draft) => {
2739
- draft.loadingState = loadingState;
2740
- });
2741
- },
2742
- start() {
2743
- stepPolling == null ? void 0 : stepPolling.start();
2744
- stepRefreshAfter == null ? void 0 : stepRefreshAfter.start();
2745
- },
2746
- stop() {
2747
- stepPolling == null ? void 0 : stepPolling.stop();
2748
- stepRefreshAfter == null ? void 0 : stepRefreshAfter.stop();
2749
- this._update((draft) => {
2750
- draft.modals = [];
2751
- });
2752
- }
2753
- });
2754
- return component;
2755
- };
2756
-
2757
- // src/domain/features/polling/getStepPolling.ts
2758
- var getStepPolling = ({
2759
- pollingConfig,
2760
- logEvent,
2761
- onBehavior,
2762
- onPoll,
2763
- registerSubmissionBehavior
2764
- }) => {
2765
- const { interval, delay = interval, maxAttempts, url, onError } = pollingConfig;
2766
- let abortController = new AbortController();
2767
- let intervalRef = null;
2768
- if (delay == null) {
2769
- throw new Error("Polling configuration must include delay or interval");
2770
- }
2771
- const onErrorBehavior = getDomainLayerBehavior(onError, [], registerSubmissionBehavior);
2772
- let attempts = 0;
2773
- const poll = () => {
2774
- attempts += 1;
2775
- abortController.abort();
2776
- abortController = new AbortController();
2777
- const { signal } = abortController;
2778
- onPoll(url, onErrorBehavior, signal).then((result) => {
2779
- if (result) {
2780
- stop();
2781
- return;
2782
- }
2783
- if (attempts >= maxAttempts && !signal.aborted) {
2784
- void onBehavior(onErrorBehavior);
2785
- stop();
2786
- }
2787
- }).catch(() => {
2788
- });
2789
- };
2790
- const start = () => {
2791
- attempts = 0;
2792
- intervalRef = setInterval(poll, delay * 1e3);
2793
- poll();
2794
- };
2795
- const stop = () => {
2796
- if (!intervalRef) {
2797
- logEvent("warning", "Attempted to stop polling but it was not started");
2798
- return;
2799
- }
2800
- clearTimeout(intervalRef);
2801
- abortController.abort();
2802
- };
2803
- return { start, stop };
2804
- };
2805
-
2806
- // src/domain/features/refreshAfter/getStepRefreshAfter.ts
2807
- var ONE_SECOND = 1e3;
2808
- var getStepRefreshAfter = ({
2809
- refreshAfter,
2810
- logEvent,
2811
- onBehavior
2812
- }) => {
2813
- let timeout = null;
2814
- const targetTime = new Date(refreshAfter).getTime();
2815
- if (typeof refreshAfter !== "string" || Number.isNaN(targetTime)) {
2816
- throw new Error(`Invalid refreshAfter value: ${String(refreshAfter)}`);
2817
- }
2818
- const start = () => {
2819
- const timeLeft = Math.max(targetTime - Date.now(), ONE_SECOND);
2820
- timeout = setTimeout(() => {
2821
- void onBehavior({ type: "refresh", analytics: { schema: "refreshAfter" } });
2822
- }, timeLeft);
2823
- };
2824
- return {
2825
- start,
2826
- stop: () => {
2827
- if (!timeout) {
2828
- logEvent("warning", "Attempted to stop refreshAfter but it was not started");
2829
- return;
2830
- }
2831
- clearTimeout(timeout);
2832
- }
2833
- };
2834
- };
2835
-
2836
- // src/domain/prefetching/request-cache.ts
2837
- var makeRequestCacheWithParent = (parent) => {
2838
- const map = /* @__PURE__ */ new Map();
2839
- const cache = {
2840
- get: (requestParams) => {
2841
- var _a;
2842
- const key = makeKey(requestParams);
2843
- const promise = (_a = map.get(key)) != null ? _a : parent == null ? void 0 : parent.get(requestParams);
2844
- map.delete(key);
2845
- return promise;
2846
- },
2847
- set: (requestParams, responsePromise) => {
2848
- return map.set(makeKey(requestParams), responsePromise);
2849
- }
2850
- };
2851
- return cache;
2852
- };
2853
- var makeRequestCache = (initialValues = []) => {
2854
- const cache = makeRequestCacheWithParent(void 0);
2855
- initialValues.forEach(([requestParams, responsePromise]) => {
2856
- cache.set(requestParams, responsePromise);
2857
- });
2858
- return cache;
2859
- };
2860
- var normaliseRequestCache = (cache) => {
2861
- if (cache === void 0) {
2862
- return makeRequestCache();
2863
- }
2864
- if (isRequestCacheInstance(cache)) {
2865
- return cache;
2866
- }
2867
- return makeRequestCache(cache);
2868
- };
2869
- var isRequestCacheInstance = (cache) => {
2870
- return !cache || !Array.isArray(cache);
2871
- };
2872
- var makeKey = (requestParams) => {
2873
- var _a, _b;
2874
- const [input, init] = requestParams;
2875
- const url = typeof input === "string" || input instanceof URL ? input.toString() : input.url;
2876
- const key = JSON.stringify({
2877
- url,
2878
- method: (_a = init == null ? void 0 : init.method) != null ? _a : "GET",
2879
- headers: (init == null ? void 0 : init.headers) ? Array.from(new Headers(init.headers).entries()) : [],
2880
- body: (_b = init == null ? void 0 : init.body) != null ? _b : null
2881
- });
2882
- return key;
2883
- };
2884
-
2885
2544
  // src/domain/components/utils/isOrWasValid.ts
2886
2545
  var isOrWasValid = (getErrors, previous, current) => {
2887
2546
  const wasValid = getErrors(previous).length === 0 && previous !== null;
@@ -3360,6 +3019,72 @@ var getInitialValidationAsyncState = () => ({
3360
3019
  messages: {}
3361
3020
  });
3362
3021
 
3022
+ // src/controller/response-utils.ts
3023
+ var import_spec = require("@wise/dynamic-flow-types/spec");
3024
+ var parseResponseBodyAsJsonElement = async (response) => {
3025
+ assertResponseIsValid(response);
3026
+ try {
3027
+ return await response.json();
3028
+ } catch (e) {
3029
+ return null;
3030
+ }
3031
+ };
3032
+ var parseResponseBodyAsText = async (response) => {
3033
+ try {
3034
+ return await response.text();
3035
+ } catch (e) {
3036
+ return null;
3037
+ }
3038
+ };
3039
+ function isActionResponseBody(body) {
3040
+ return (0, import_spec.validateActionResponse)(body).valid;
3041
+ }
3042
+ function assertActionResponseBody(body) {
3043
+ if (!isObject(body) || !isObject(body.action)) {
3044
+ throw new Error(
3045
+ "Incorrect response body in action response. Expected an object satisfying the type { action: Action }."
3046
+ );
3047
+ }
3048
+ }
3049
+ function assertModalResponseBody(body) {
3050
+ if (isObject(body)) {
3051
+ if ("content" in body && isArray(body.content)) {
3052
+ return;
3053
+ }
3054
+ }
3055
+ throw new Error(
3056
+ "Incorrect response body in modal response. Expected an object satisfying the type { title?: string, components: Layout[] }."
3057
+ );
3058
+ }
3059
+ function assertSubflowResponseBody(body) {
3060
+ const { valid } = (0, import_spec.validateSubflowResponse)(body);
3061
+ if (valid) {
3062
+ return;
3063
+ }
3064
+ throw new Error("Incorrect response body in subflow response.");
3065
+ }
3066
+ function isErrorResponseBody(body) {
3067
+ return Boolean(
3068
+ isObject(body) && (body.refreshFormUrl || body.refreshUrl || body.validation || body.error || body.analytics)
3069
+ );
3070
+ }
3071
+ function assertStepResponseBody(body) {
3072
+ if (!isObject(body)) {
3073
+ throw new Error("Incorrect response body in step response. Expected an object.");
3074
+ }
3075
+ }
3076
+ var assertResponseIsValid = (response) => {
3077
+ if (!isResponse(response)) {
3078
+ throw new Error("Incorrect type of response from fetch. Expected object of type Response.");
3079
+ }
3080
+ if (response.bodyUsed) {
3081
+ throw new Error(
3082
+ "The body of the provided Response object has already been used. Every request must respond with a new Response object."
3083
+ );
3084
+ }
3085
+ };
3086
+ var isResponse = (response) => typeof response === "object" && response !== null && "clone" in response && "bodyUsed" in response;
3087
+
3363
3088
  // src/domain/features/utils/response-utils.ts
3364
3089
  var getAnalyticsFromErrorResponse = (json) => {
3365
3090
  if (!isErrorResponseBody(json)) {
@@ -5841,229 +5566,529 @@ var createTextInputComponent = (textInputProps, onComponentUpdate) => {
5841
5566
  return inputComponent;
5842
5567
  };
5843
5568
 
5844
- // src/domain/mappers/schema/stringSchemaToComponent/stringSchemaToTextInputComponent.ts
5845
- var stringSchemaToTextInputComponent = (schemaMapperProps, mapperProps) => {
5846
- const { schema, localValue, model, required = false, onPersistAsync } = schemaMapperProps;
5847
- const {
5848
- autocapitalization,
5849
- autocompleteHint,
5850
- control,
5851
- default: defaultValue,
5852
- displayFormat,
5853
- format,
5854
- maxLength,
5855
- minLength,
5856
- suggestions,
5857
- validationMessages
5858
- } = schema;
5859
- const { getErrorMessageFunctions, onComponentUpdate, onBehavior, onValueChange, logEvent } = mapperProps;
5860
- const controlForLegacyFormat = getControlForLegacyFormat(format);
5861
- const errorMessageFunctions = getErrorMessageFunctions(validationMessages);
5862
- const { performValidationAsync, validationAsyncState } = getValidationAsyncInitialState(
5863
- schemaMapperProps,
5864
- mapperProps
5865
- );
5866
- const validLocalValue = isString(localValue) ? localValue : null;
5867
- const validModel = isString(model) ? model : defaultValue != null ? defaultValue : null;
5868
- const value = onPersistAsync ? validLocalValue : validModel;
5869
- return createTextInputComponent(
5870
- __spreadProps(__spreadValues({}, mapCommonSchemaProps(schemaMapperProps)), {
5871
- autocapitalization,
5872
- autoComplete: getAutocompleteString(autocompleteHint),
5873
- checks: schema.hidden ? [] : [
5874
- getRequiredCheck(required, errorMessageFunctions),
5875
- getAboveMaxLengthCheck(schema, errorMessageFunctions),
5876
- getBelowMinLengthCheck(schema, errorMessageFunctions),
5877
- getNotAdheringToPatternCheck(schema, errorMessageFunctions, { logEvent })
5878
- ],
5879
- control: control != null ? control : controlForLegacyFormat,
5880
- displayFormat,
5881
- maxLength,
5882
- minLength,
5883
- suggestions: mapStringSchemaSuggestions(suggestions, mapperProps.logEvent),
5884
- value,
5885
- validationAsyncState,
5886
- schemaOnChange: getSchemaOnChange(schema, onBehavior),
5887
- performValidationAsync,
5888
- onValueChange
5889
- }),
5890
- onComponentUpdate
5891
- );
5569
+ // src/domain/mappers/schema/stringSchemaToComponent/stringSchemaToTextInputComponent.ts
5570
+ var stringSchemaToTextInputComponent = (schemaMapperProps, mapperProps) => {
5571
+ const { schema, localValue, model, required = false, onPersistAsync } = schemaMapperProps;
5572
+ const {
5573
+ autocapitalization,
5574
+ autocompleteHint,
5575
+ control,
5576
+ default: defaultValue,
5577
+ displayFormat,
5578
+ format,
5579
+ maxLength,
5580
+ minLength,
5581
+ suggestions,
5582
+ validationMessages
5583
+ } = schema;
5584
+ const { getErrorMessageFunctions, onComponentUpdate, onBehavior, onValueChange, logEvent } = mapperProps;
5585
+ const controlForLegacyFormat = getControlForLegacyFormat(format);
5586
+ const errorMessageFunctions = getErrorMessageFunctions(validationMessages);
5587
+ const { performValidationAsync, validationAsyncState } = getValidationAsyncInitialState(
5588
+ schemaMapperProps,
5589
+ mapperProps
5590
+ );
5591
+ const validLocalValue = isString(localValue) ? localValue : null;
5592
+ const validModel = isString(model) ? model : defaultValue != null ? defaultValue : null;
5593
+ const value = onPersistAsync ? validLocalValue : validModel;
5594
+ return createTextInputComponent(
5595
+ __spreadProps(__spreadValues({}, mapCommonSchemaProps(schemaMapperProps)), {
5596
+ autocapitalization,
5597
+ autoComplete: getAutocompleteString(autocompleteHint),
5598
+ checks: schema.hidden ? [] : [
5599
+ getRequiredCheck(required, errorMessageFunctions),
5600
+ getAboveMaxLengthCheck(schema, errorMessageFunctions),
5601
+ getBelowMinLengthCheck(schema, errorMessageFunctions),
5602
+ getNotAdheringToPatternCheck(schema, errorMessageFunctions, { logEvent })
5603
+ ],
5604
+ control: control != null ? control : controlForLegacyFormat,
5605
+ displayFormat,
5606
+ maxLength,
5607
+ minLength,
5608
+ suggestions: mapStringSchemaSuggestions(suggestions, mapperProps.logEvent),
5609
+ value,
5610
+ validationAsyncState,
5611
+ schemaOnChange: getSchemaOnChange(schema, onBehavior),
5612
+ performValidationAsync,
5613
+ onValueChange
5614
+ }),
5615
+ onComponentUpdate
5616
+ );
5617
+ };
5618
+ var getControlForLegacyFormat = (format) => {
5619
+ if (format && ["numeric", "phone-number", "email", "password"].includes(format)) {
5620
+ return format;
5621
+ }
5622
+ return void 0;
5623
+ };
5624
+
5625
+ // src/domain/mappers/schema/stringSchemaToComponent/stringSchemaToComponent.ts
5626
+ var stringSchemaToComponent = (schemaMapperProps, mapperProps) => {
5627
+ const { schema } = schemaMapperProps;
5628
+ if (isStringSchemaWithBase64(schema)) {
5629
+ return stringSchemaToUploadInputComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5630
+ }
5631
+ switch (schema.format) {
5632
+ case "date":
5633
+ return stringSchemaToDateInputComponent(schemaMapperProps, mapperProps);
5634
+ default:
5635
+ return stringSchemaToTextInputComponent(schemaMapperProps, mapperProps);
5636
+ }
5637
+ };
5638
+ var isStringSchemaWithBase64 = (schema) => {
5639
+ return schema.format === "base64url" && !("persistAsync" in schema);
5640
+ };
5641
+
5642
+ // src/domain/mappers/mapSchemaToComponent.ts
5643
+ var mapSchemaToComponent = (schemaMapperProps, mapperProps) => {
5644
+ const { uid, schema } = schemaMapperProps;
5645
+ if (isConstSchema(schema)) {
5646
+ return constSchemaToComponent(uid, __spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5647
+ }
5648
+ if (isSchemaWithPersistAsync(schema)) {
5649
+ return persistAsyncSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5650
+ }
5651
+ if (isAllOfSchema(schema)) {
5652
+ return allOfSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5653
+ }
5654
+ if (isOneOfSchema(schema)) {
5655
+ return oneOfSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5656
+ }
5657
+ if (isBooleanSchema(schema)) {
5658
+ return booleanSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5659
+ }
5660
+ if (isObjectSchema(schema)) {
5661
+ const { format } = schema;
5662
+ if (format === "money") {
5663
+ return objectSchemaToMoneyInputComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5664
+ }
5665
+ if (format != null && Object.keys(schema.properties).length === 0) {
5666
+ return objectSchemaToFormattedValueComponent(
5667
+ __spreadProps(__spreadValues({}, schemaMapperProps), { schema: __spreadProps(__spreadValues({}, schema), { format }) }),
5668
+ mapperProps
5669
+ );
5670
+ }
5671
+ return objectSchemaToObjectComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5672
+ }
5673
+ if (isIntegerSchema(schema)) {
5674
+ return integerSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5675
+ }
5676
+ if (isNumberSchema(schema)) {
5677
+ return numberSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5678
+ }
5679
+ if (isStringSchema(schema)) {
5680
+ return stringSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5681
+ }
5682
+ if (isArraySchema(schema)) {
5683
+ return arraySchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5684
+ }
5685
+ if (isBlobSchema(schema)) {
5686
+ if (!schemaMapperProps.onPersistAsync) {
5687
+ throw new Error(
5688
+ "Blob schemas can only be used as the schema of a persist async configuration."
5689
+ );
5690
+ }
5691
+ return blobSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5692
+ }
5693
+ throw new Error("Not yet supported");
5694
+ };
5695
+
5696
+ // src/domain/mappers/mapStepSchemas.ts
5697
+ var mapStepSchemas = (uid, step, stepLocalValue, mapperProps, referencedSchemaIds) => {
5698
+ const isReferenced = (schemaId) => schemaId != null && referencedSchemaIds.includes(schemaId);
5699
+ return step.schemas.map((schema, i) => {
5700
+ var _a, _b;
5701
+ const schemaComponent = mapSchemaToComponent(
5702
+ {
5703
+ uid: `${uid}.schemas-${i}.${schema.$id}`,
5704
+ schemaId: schema.$id,
5705
+ schema,
5706
+ model: (_a = step.model) != null ? _a : null,
5707
+ localValue: stepLocalValue,
5708
+ validationErrors: (_b = step.errors) == null ? void 0 : _b.validation,
5709
+ required: true
5710
+ },
5711
+ mapperProps
5712
+ );
5713
+ return __spreadProps(__spreadValues({}, schemaComponent), {
5714
+ isSchemaReferencedInStep: isReferenced(schema.$id)
5715
+ });
5716
+ });
5717
+ };
5718
+
5719
+ // src/domain/mappers/mapToolbarToComponent.ts
5720
+ var mapToolbarToComponent = (uid, toolbar, mapperProps) => {
5721
+ if (!toolbar) {
5722
+ return void 0;
5723
+ }
5724
+ const { onBehavior } = mapperProps;
5725
+ return __spreadProps(__spreadValues({}, toolbar), {
5726
+ type: "toolbar",
5727
+ uid: `${uid}.toolbar`,
5728
+ tags: toolbar.tags,
5729
+ items: toolbar.items.map((item) => {
5730
+ const context = item.context ? mapLegacyContext(item.context) : void 0;
5731
+ const behavior = getDomainLayerBehavior(
5732
+ { behavior: item.behavior },
5733
+ [],
5734
+ mapperProps.registerSubmissionBehavior
5735
+ );
5736
+ return __spreadProps(__spreadValues({}, item), {
5737
+ context: context ? mapLegacyContext(context) : void 0,
5738
+ disabled: !!item.disabled,
5739
+ tags: item.tags,
5740
+ onClick: () => {
5741
+ void onBehavior(behavior);
5742
+ }
5743
+ });
5744
+ })
5745
+ });
5746
+ };
5747
+
5748
+ // src/domain/mappers/utils/groupLayoutByPinned.ts
5749
+ var groupLayoutByPinned = (layouts) => {
5750
+ return layouts.reduce(groupLayout, { pinned: [], nonPinned: [] });
5892
5751
  };
5893
- var getControlForLegacyFormat = (format) => {
5894
- if (format && ["numeric", "phone-number", "email", "password"].includes(format)) {
5895
- return format;
5752
+ var groupLayout = (acc, layout) => {
5753
+ if (layout.type === "button" && layout.pinOrder !== void 0) {
5754
+ return {
5755
+ pinned: [...acc.pinned, layout],
5756
+ nonPinned: acc.nonPinned
5757
+ };
5896
5758
  }
5897
- return void 0;
5759
+ if (hasColumns(layout)) {
5760
+ const leftChildren = groupLayoutByPinned(layout.left);
5761
+ const rightChildren = groupLayoutByPinned(layout.right);
5762
+ return {
5763
+ pinned: [...acc.pinned, ...leftChildren.pinned, ...rightChildren.pinned],
5764
+ nonPinned: [
5765
+ ...acc.nonPinned,
5766
+ __spreadProps(__spreadValues({}, layout), {
5767
+ left: leftChildren.nonPinned,
5768
+ right: rightChildren.nonPinned
5769
+ })
5770
+ ]
5771
+ };
5772
+ }
5773
+ if (hasChildren(layout)) {
5774
+ const childComponents = groupLayoutByPinned(layout.components);
5775
+ return {
5776
+ pinned: [...acc.pinned, ...childComponents.pinned],
5777
+ nonPinned: [
5778
+ ...acc.nonPinned,
5779
+ __spreadProps(__spreadValues({}, layout), {
5780
+ components: childComponents.nonPinned
5781
+ })
5782
+ ]
5783
+ };
5784
+ }
5785
+ return {
5786
+ pinned: [...acc.pinned],
5787
+ nonPinned: [...acc.nonPinned, layout]
5788
+ };
5898
5789
  };
5790
+ var hasChildren = (component) => "components" in component;
5791
+ var hasColumns = (component) => "right" in component && "left" in component;
5899
5792
 
5900
- // src/domain/mappers/schema/stringSchemaToComponent/stringSchemaToComponent.ts
5901
- var stringSchemaToComponent = (schemaMapperProps, mapperProps) => {
5902
- const { schema } = schemaMapperProps;
5903
- if (isStringSchemaWithBase64(schema)) {
5904
- return stringSchemaToUploadInputComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5793
+ // src/controller/getErrorMessage.ts
5794
+ var getErrorMessage = (error) => {
5795
+ return error instanceof Error ? error.message : typeof error === "string" ? error : `Unknown Error: type is ${typeof error}`;
5796
+ };
5797
+
5798
+ // src/controller/handleErrorResponse.ts
5799
+ var handleErrorResponse = async (response, actionId, trackEvent) => {
5800
+ const body = await parseResponseBodyAsJsonElement(response.clone());
5801
+ if (isErrorResponseBody(body)) {
5802
+ const refreshUrl = body.refreshUrl || body.refreshFormUrl;
5803
+ const { error, validation, analytics } = body;
5804
+ trackEvent("Action Failed", __spreadProps(__spreadValues({}, analytics), { actionId, statusCode: response.status }));
5805
+ const errors = { error, validation };
5806
+ return refreshUrl ? { type: "refresh", body: { refreshUrl, errors } } : {
5807
+ type: "error",
5808
+ body: { errors, analytics },
5809
+ httpError: { statusCode: response.status }
5810
+ };
5905
5811
  }
5906
- switch (schema.format) {
5907
- case "date":
5908
- return stringSchemaToDateInputComponent(schemaMapperProps, mapperProps);
5909
- default:
5910
- return stringSchemaToTextInputComponent(schemaMapperProps, mapperProps);
5812
+ trackEvent("Action Failed", { actionId, statusCode: response.status });
5813
+ const errorMessage = await parseResponseBodyAsText(response);
5814
+ return {
5815
+ type: "error",
5816
+ httpError: {
5817
+ message: errorMessage || void 0,
5818
+ statusCode: response.status
5819
+ }
5820
+ };
5821
+ };
5822
+
5823
+ // src/controller/getResponseType.ts
5824
+ var responseTypes = ["step", "action", "exit", "modal", "subflow"];
5825
+ var getResponseType = (headers, body) => {
5826
+ const headerResponseType = getResponseTypeFromHeader(headers);
5827
+ if (headerResponseType) {
5828
+ return headerResponseType;
5911
5829
  }
5830
+ if (isObject(body) && body.action) {
5831
+ return "action";
5832
+ }
5833
+ return "step";
5912
5834
  };
5913
- var isStringSchemaWithBase64 = (schema) => {
5914
- return schema.format === "base64url" && !("persistAsync" in schema);
5835
+ var getResponseTypeFromHeader = (headers) => {
5836
+ if (headers == null ? void 0 : headers.has("X-Df-Response-Type")) {
5837
+ const type = headers.get("X-Df-Response-Type");
5838
+ assertDFResponseType(type);
5839
+ return type;
5840
+ }
5841
+ if (headers == null ? void 0 : headers.has("X-Df-Exit")) {
5842
+ return "exit";
5843
+ }
5844
+ return void 0;
5915
5845
  };
5916
-
5917
- // src/domain/mappers/mapSchemaToComponent.ts
5918
- var mapSchemaToComponent = (schemaMapperProps, mapperProps) => {
5919
- const { uid, schema } = schemaMapperProps;
5920
- if (isConstSchema(schema)) {
5921
- return constSchemaToComponent(uid, __spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5846
+ function assertDFResponseType(type) {
5847
+ if (!responseTypes.includes(type)) {
5848
+ throw new Error(
5849
+ "Unsupported X-Df-Response-Type. Allowed values are 'step', 'action', 'exit', 'error', 'modal', 'subflow'."
5850
+ );
5922
5851
  }
5923
- if (isSchemaWithPersistAsync(schema)) {
5924
- return persistAsyncSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5852
+ }
5853
+
5854
+ // src/controller/makeSafeHttpClient.ts
5855
+ var makeSafeHttpClient = (httpClient) => async (...props) => {
5856
+ try {
5857
+ return await httpClient(...props);
5858
+ } catch (e) {
5859
+ return null;
5925
5860
  }
5926
- if (isAllOfSchema(schema)) {
5927
- return allOfSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5861
+ };
5862
+
5863
+ // src/controller/executeRequest.ts
5864
+ var executeRequest = async (props) => {
5865
+ const { exit, request, requestCache, httpClient, trackEvent, logEvent } = props;
5866
+ const { url, method, body } = request;
5867
+ const response = await getCachedOrFetch(
5868
+ [
5869
+ url,
5870
+ {
5871
+ method,
5872
+ body: body ? JSON.stringify(body) : void 0,
5873
+ headers: { "Content-Type": "application/json" }
5874
+ }
5875
+ ],
5876
+ requestCache,
5877
+ httpClient
5878
+ );
5879
+ if (!response) {
5880
+ const extra = { errorMessage: "Network Error" };
5881
+ trackEvent("Request Failed", extra);
5882
+ logEvent("error", "Dynamic Flow - Request Failed Unexpectedly", extra);
5883
+ return { type: "error" };
5928
5884
  }
5929
- if (isOneOfSchema(schema)) {
5930
- return oneOfSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5885
+ if (!response.ok) {
5886
+ return handleErrorResponse(response, void 0, trackEvent);
5931
5887
  }
5932
- if (isBooleanSchema(schema)) {
5933
- return booleanSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5888
+ const responseBody = await parseResponseBodyAsJsonElement(response);
5889
+ const responseType = getResponseType(response.headers, responseBody);
5890
+ if (exit) {
5891
+ return { type: "complete", result: responseBody };
5934
5892
  }
5935
- if (isObjectSchema(schema)) {
5936
- const { format } = schema;
5937
- if (format === "money") {
5938
- return objectSchemaToMoneyInputComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5893
+ switch (responseType) {
5894
+ case "step": {
5895
+ const etag = response.headers.get("etag") || null;
5896
+ assertStepResponseBody(responseBody);
5897
+ return { type: "replace-step", step: responseBody, etag };
5939
5898
  }
5940
- if (format != null && Object.keys(schema.properties).length === 0) {
5941
- return objectSchemaToFormattedValueComponent(
5942
- __spreadProps(__spreadValues({}, schemaMapperProps), { schema: __spreadProps(__spreadValues({}, schema), { format }) }),
5943
- mapperProps
5944
- );
5899
+ case "exit": {
5900
+ return { type: "complete", result: responseBody };
5901
+ }
5902
+ case "action": {
5903
+ assertActionResponseBody(responseBody);
5904
+ return {
5905
+ type: "behavior",
5906
+ behavior: {
5907
+ type: "action",
5908
+ action: responseBody.action
5909
+ }
5910
+ };
5911
+ }
5912
+ case "subflow": {
5913
+ assertSubflowResponseBody(responseBody);
5914
+ return {
5915
+ type: "behavior",
5916
+ behavior: __spreadProps(__spreadValues({}, responseBody), {
5917
+ type: "subflow",
5918
+ onCompletion: responseBody.onCompletion ? normaliseBehavior(responseBody.onCompletion, []) : void 0,
5919
+ onError: responseBody.onError ? normaliseBehavior(responseBody.onError, []) : void 0
5920
+ })
5921
+ };
5922
+ }
5923
+ case "modal": {
5924
+ assertModalResponseBody(responseBody);
5925
+ return { type: "behavior", behavior: __spreadProps(__spreadValues({}, responseBody), { type: "modal" }) };
5926
+ }
5927
+ default: {
5928
+ throw new Error(`Unsupported response type: ${String(responseType)}`);
5945
5929
  }
5946
- return objectSchemaToObjectComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5947
- }
5948
- if (isIntegerSchema(schema)) {
5949
- return integerSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5950
- }
5951
- if (isNumberSchema(schema)) {
5952
- return numberSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5953
- }
5954
- if (isStringSchema(schema)) {
5955
- return stringSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5956
- }
5957
- if (isArraySchema(schema)) {
5958
- return arraySchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5959
5930
  }
5960
- if (isBlobSchema(schema)) {
5961
- if (!schemaMapperProps.onPersistAsync) {
5962
- throw new Error(
5963
- "Blob schemas can only be used as the schema of a persist async configuration."
5964
- );
5931
+ };
5932
+ var getCachedOrFetch = async (requestParams, requestCache, httpClient) => {
5933
+ const cachedPromise = requestCache.get(requestParams);
5934
+ if (cachedPromise) {
5935
+ const cachedResponse = await cachedPromise;
5936
+ if (cachedResponse == null ? void 0 : cachedResponse.ok) {
5937
+ return cachedResponse;
5965
5938
  }
5966
- return blobSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5967
5939
  }
5968
- throw new Error("Not yet supported");
5940
+ return makeSafeHttpClient(httpClient)(...requestParams);
5969
5941
  };
5970
5942
 
5971
- // src/domain/mappers/mapStepSchemas.ts
5972
- var mapStepSchemas = (uid, step, stepLocalValue, mapperProps, referencedSchemaIds) => {
5973
- const isReferenced = (schemaId) => schemaId != null && referencedSchemaIds.includes(schemaId);
5974
- return step.schemas.map((schema, i) => {
5943
+ // src/controller/executeSubmission.ts
5944
+ var executeSubmission = async (props) => {
5945
+ const { httpClient, requestCache, trackEvent, logEvent } = props;
5946
+ const triggerAction = async (action, model, isInitial) => {
5975
5947
  var _a, _b;
5976
- const schemaComponent = mapSchemaToComponent(
5977
- {
5978
- uid: `${uid}.schemas-${i}.${schema.$id}`,
5979
- schemaId: schema.$id,
5980
- schema,
5981
- model: (_a = step.model) != null ? _a : null,
5982
- localValue: stepLocalValue,
5983
- validationErrors: (_b = step.errors) == null ? void 0 : _b.validation,
5984
- required: true
5985
- },
5986
- mapperProps
5987
- );
5988
- return __spreadProps(__spreadValues({}, schemaComponent), {
5989
- isSchemaReferencedInStep: isReferenced(schema.$id)
5990
- });
5991
- });
5992
- };
5993
-
5994
- // src/domain/mappers/mapToolbarToComponent.ts
5995
- var mapToolbarToComponent = (uid, toolbar, mapperProps) => {
5996
- if (!toolbar) {
5997
- return void 0;
5998
- }
5999
- const { onBehavior } = mapperProps;
6000
- return __spreadProps(__spreadValues({}, toolbar), {
6001
- type: "toolbar",
6002
- uid: `${uid}.toolbar`,
6003
- tags: toolbar.tags,
6004
- items: toolbar.items.map((item) => {
6005
- const context = item.context ? mapLegacyContext(item.context) : void 0;
6006
- const behavior = getDomainLayerBehavior(
6007
- { behavior: item.behavior },
6008
- [],
6009
- mapperProps.registerSubmissionBehavior
6010
- );
6011
- return __spreadProps(__spreadValues({}, item), {
6012
- context: context ? mapLegacyContext(context) : void 0,
6013
- disabled: !!item.disabled,
6014
- tags: item.tags,
6015
- onClick: () => {
6016
- void onBehavior(behavior);
6017
- }
5948
+ const { exit, url, result = null, id: actionId } = action;
5949
+ const trackSubmissionEvent = !isInitial ? trackEvent : () => {
5950
+ };
5951
+ trackSubmissionEvent("Action Triggered", { actionId });
5952
+ if (exit && !url) {
5953
+ trackSubmissionEvent("Action Succeeded", { actionId });
5954
+ return { type: "complete", result };
5955
+ }
5956
+ try {
5957
+ const command = await executeRequest({
5958
+ exit,
5959
+ request: createRequestFromAction(action, model),
5960
+ requestCache,
5961
+ httpClient,
5962
+ trackEvent: (name, properties) => {
5963
+ trackSubmissionEvent(name, __spreadProps(__spreadValues({}, properties), { actionId }));
5964
+ },
5965
+ logEvent
6018
5966
  });
6019
- })
5967
+ switch (command.type) {
5968
+ case "error": {
5969
+ trackSubmissionEvent("Action Failed", __spreadValues({
5970
+ actionId,
5971
+ statusCode: (_a = command.httpError) == null ? void 0 : _a.statusCode
5972
+ }, (_b = command.body) == null ? void 0 : _b.analytics));
5973
+ return command;
5974
+ }
5975
+ case "behavior": {
5976
+ if (command.behavior.type === "action") {
5977
+ trackSubmissionEvent("Action Succeeded", { actionId });
5978
+ return await executeSubmission({
5979
+ action: command.behavior.action,
5980
+ isInitial: false,
5981
+ model: null,
5982
+ requestCache,
5983
+ httpClient,
5984
+ trackEvent,
5985
+ logEvent
5986
+ });
5987
+ }
5988
+ trackSubmissionEvent("Action Succeeded", { actionId });
5989
+ return command;
5990
+ }
5991
+ case "complete": {
5992
+ trackSubmissionEvent("Action Succeeded", { actionId });
5993
+ return __spreadProps(__spreadValues({}, command), { result: recursiveMerge(command.result, result) });
5994
+ }
5995
+ default: {
5996
+ trackSubmissionEvent("Action Succeeded", { actionId });
5997
+ return command;
5998
+ }
5999
+ }
6000
+ } catch (error) {
6001
+ const errorMessage = getErrorMessage(error);
6002
+ trackSubmissionEvent("Action Failed", { actionId, errorMessage });
6003
+ logEvent("error", "Dynamic Flow - Action Failed Unexpectedly", { actionId, errorMessage });
6004
+ throw error;
6005
+ }
6006
+ };
6007
+ return triggerAction(props.action, props.model, props.isInitial);
6008
+ };
6009
+ var createRequestFromAction = (action, model) => {
6010
+ var _a, _b, _c;
6011
+ return __spreadProps(__spreadValues({}, action), {
6012
+ url: (_a = action.url) != null ? _a : "",
6013
+ method: (_b = action.method) != null ? _b : "POST",
6014
+ body: action.method === "GET" ? void 0 : recursiveMerge(model, (_c = action.data) != null ? _c : null)
6020
6015
  });
6021
6016
  };
6022
6017
 
6023
- // src/domain/mappers/utils/groupLayoutByPinned.ts
6024
- var groupLayoutByPinned = (layouts) => {
6025
- return layouts.reduce(groupLayout, { pinned: [], nonPinned: [] });
6018
+ // src/domain/features/prefetch/request-cache.ts
6019
+ var makeRequestCacheWithParent = (parent) => {
6020
+ const map = /* @__PURE__ */ new Map();
6021
+ const cache = {
6022
+ get: (requestParams) => {
6023
+ var _a;
6024
+ const key = makeKey(requestParams);
6025
+ const promise = (_a = map.get(key)) != null ? _a : parent == null ? void 0 : parent.get(requestParams);
6026
+ map.delete(key);
6027
+ return promise;
6028
+ },
6029
+ set: (requestParams, responsePromise) => {
6030
+ return map.set(makeKey(requestParams), responsePromise);
6031
+ }
6032
+ };
6033
+ return cache;
6026
6034
  };
6027
- var groupLayout = (acc, layout) => {
6028
- if (layout.type === "button" && layout.pinOrder !== void 0) {
6029
- return {
6030
- pinned: [...acc.pinned, layout],
6031
- nonPinned: acc.nonPinned
6032
- };
6033
- }
6034
- if (hasColumns(layout)) {
6035
- const leftChildren = groupLayoutByPinned(layout.left);
6036
- const rightChildren = groupLayoutByPinned(layout.right);
6037
- return {
6038
- pinned: [...acc.pinned, ...leftChildren.pinned, ...rightChildren.pinned],
6039
- nonPinned: [
6040
- ...acc.nonPinned,
6041
- __spreadProps(__spreadValues({}, layout), {
6042
- left: leftChildren.nonPinned,
6043
- right: rightChildren.nonPinned
6044
- })
6045
- ]
6046
- };
6035
+ var makeRequestCache = (initialValues = []) => {
6036
+ const cache = makeRequestCacheWithParent(void 0);
6037
+ initialValues.forEach(([requestParams, responsePromise]) => {
6038
+ cache.set(requestParams, responsePromise);
6039
+ });
6040
+ return cache;
6041
+ };
6042
+ var normaliseRequestCache = (cache) => {
6043
+ if (cache === void 0) {
6044
+ return makeRequestCache();
6047
6045
  }
6048
- if (hasChildren(layout)) {
6049
- const childComponents = groupLayoutByPinned(layout.components);
6050
- return {
6051
- pinned: [...acc.pinned, ...childComponents.pinned],
6052
- nonPinned: [
6053
- ...acc.nonPinned,
6054
- __spreadProps(__spreadValues({}, layout), {
6055
- components: childComponents.nonPinned
6056
- })
6057
- ]
6058
- };
6046
+ if (isRequestCacheInstance(cache)) {
6047
+ return cache;
6059
6048
  }
6060
- return {
6061
- pinned: [...acc.pinned],
6062
- nonPinned: [...acc.nonPinned, layout]
6049
+ return makeRequestCache(cache);
6050
+ };
6051
+ var isRequestCacheInstance = (cache) => {
6052
+ return !cache || !Array.isArray(cache);
6053
+ };
6054
+ var makeKey = (requestParams) => {
6055
+ var _a, _b;
6056
+ const [input, init] = requestParams;
6057
+ const url = typeof input === "string" || input instanceof URL ? input.toString() : input.url;
6058
+ const key = JSON.stringify({
6059
+ url,
6060
+ method: (_a = init == null ? void 0 : init.method) != null ? _a : "GET",
6061
+ headers: (init == null ? void 0 : init.headers) ? Array.from(new Headers(init.headers).entries()) : [],
6062
+ body: (_b = init == null ? void 0 : init.body) != null ? _b : null
6063
+ });
6064
+ return key;
6065
+ };
6066
+
6067
+ // src/domain/features/prefetch/getStepPrefetch.ts
6068
+ var getStepPrefetch = (httpClient, flowRequestCache, submissionBehaviors) => {
6069
+ const requestCache = makeRequestCacheWithParent(flowRequestCache);
6070
+ const start = (model) => {
6071
+ submissionBehaviors.forEach((behavior) => {
6072
+ const request = behavior.type === "action" ? createRequestFromAction(behavior.action, model) : behavior.launchConfig.request;
6073
+ const requestParams = [
6074
+ request.url,
6075
+ {
6076
+ body: JSON.stringify(request.body),
6077
+ method: request.method,
6078
+ headers: { "Content-Type": "application/json" }
6079
+ }
6080
+ ];
6081
+ try {
6082
+ const responsePromise = httpClient(...requestParams).catch(() => null);
6083
+ requestCache.set(requestParams, responsePromise);
6084
+ } catch (e) {
6085
+ }
6086
+ });
6087
+ };
6088
+ const stop = () => {
6063
6089
  };
6090
+ return { requestCache, start, stop };
6064
6091
  };
6065
- var hasChildren = (component) => "components" in component;
6066
- var hasColumns = (component) => "right" in component && "left" in component;
6067
6092
 
6068
6093
  // src/domain/mappers/mapStepToComponent.ts
6069
6094
  var mapStepToComponent = (_a) => {
@@ -6091,14 +6116,12 @@ var mapStepToComponent = (_a) => {
6091
6116
  errors,
6092
6117
  external,
6093
6118
  key,
6094
- layout = [],
6095
6119
  navigation,
6096
6120
  polling,
6097
6121
  refreshAfter,
6098
6122
  title,
6099
6123
  tags
6100
6124
  } = step;
6101
- const requestCache = makeRequestCacheWithParent(flowRequestCache);
6102
6125
  const submissionBehaviors = [];
6103
6126
  const registerSubmissionBehavior = (behavior) => {
6104
6127
  if (behavior.type === "action" && behavior.action.prefetch) {
@@ -6122,6 +6145,7 @@ var mapStepToComponent = (_a) => {
6122
6145
  registerSubmissionBehavior
6123
6146
  }) : void 0;
6124
6147
  const stepRefreshAfter = refreshAfter ? getStepRefreshAfter({ refreshAfter, logEvent, onBehavior }) : void 0;
6148
+ const stepPrefetch = getStepPrefetch(restProps.httpClient, flowRequestCache, submissionBehaviors);
6125
6149
  const externalConfirmation = (external == null ? void 0 : external.url) ? createExternalConfirmation(`${uid}-external-confirmation`, external == null ? void 0 : external.url, onComponentUpdate) : void 0;
6126
6150
  const mapperProps = __spreadProps(__spreadValues({}, restProps), { trackEvent, onBehavior, registerSubmissionBehavior });
6127
6151
  const referencedSchemaIds = getReferencedSchemaId(step);
@@ -6132,21 +6156,12 @@ var mapStepToComponent = (_a) => {
6132
6156
  mapperProps,
6133
6157
  referencedSchemaIds
6134
6158
  );
6135
- const shouldPinButtons = features.isEnabled("pinnedButtons");
6136
- const { pinned, nonPinned } = shouldPinButtons ? groupLayoutByPinned(layout) : { pinned: [], nonPinned: layout };
6137
- const layoutComponents = nonPinned.map(
6159
+ const { layout, footer } = getLayoutAndFooter(step, features);
6160
+ const layoutComponents = layout.map(
6138
6161
  (layoutComponent, index) => mapLayoutToComponent(`${uid}.layout-${index}`, layoutComponent, mapperProps, schemaComponents)
6139
6162
  );
6140
- const footerComponents = pinned.map((footerComponent, index) => {
6141
- const shouldRemoveMargin = index === pinned.length - 1 && footerComponent.margin === void 0;
6142
- return shouldRemoveMargin ? removeMarginFromLayout(footerComponent) : footerComponent;
6143
- }).map(
6144
- (footerComponent, index) => mapLayoutToComponent(
6145
- `${uid}.footer-${index}`,
6146
- footerComponent,
6147
- mapperProps,
6148
- schemaComponents
6149
- )
6163
+ const footerComponents = normaliseMarginInLastComponent(footer).map(
6164
+ (footerComponent, index) => mapLayoutToComponent(`${uid}.footer-${index}`, footerComponent, mapperProps, schemaComponents)
6150
6165
  );
6151
6166
  const toolbar = mapToolbarToComponent(uid, step.toolbar, mapperProps);
6152
6167
  const stepComponent = createStepComponent({
@@ -6167,18 +6182,12 @@ var mapStepToComponent = (_a) => {
6167
6182
  title,
6168
6183
  tags,
6169
6184
  stackBehavior: (_a2 = navigation == null ? void 0 : navigation.stackBehavior) != null ? _a2 : "default",
6170
- requestCache,
6185
+ stepPrefetch,
6171
6186
  step,
6172
6187
  onComponentUpdate,
6173
6188
  trackEvent,
6174
6189
  onBehavior
6175
6190
  });
6176
- executePrefetch({
6177
- httpClient: mapperProps.httpClient,
6178
- model: stepComponent.getSubmittableValueSync(),
6179
- behaviors: submissionBehaviors,
6180
- requestCache
6181
- });
6182
6191
  return stepComponent;
6183
6192
  };
6184
6193
  var getReferencedSchemaId = (step) => {
@@ -6199,24 +6208,18 @@ var mapBackNavigation = (navigation, onBehavior, isNativeBackEnabled) => {
6199
6208
  }
6200
6209
  } : void 0;
6201
6210
  };
6202
- var executePrefetch = (props) => {
6203
- const { httpClient, behaviors: submissionBehaviors, model, requestCache } = props;
6204
- submissionBehaviors.forEach((behavior) => {
6205
- const request = behavior.type === "action" ? createRequestFromAction(behavior.action, model) : behavior.launchConfig.request;
6206
- const requestParams = [
6207
- request.url,
6208
- {
6209
- body: JSON.stringify(request.body),
6210
- method: request.method,
6211
- headers: { "Content-Type": "application/json" }
6212
- }
6213
- ];
6214
- try {
6215
- const responsePromise = httpClient(...requestParams).catch(() => null);
6216
- requestCache.set(requestParams, responsePromise);
6217
- } catch (e) {
6218
- }
6219
- });
6211
+ var getLayoutAndFooter = (step, features) => {
6212
+ var _a;
6213
+ if (step.footer) {
6214
+ const { layout: layout2 = [], footer = [] } = step;
6215
+ return { layout: layout2, footer };
6216
+ }
6217
+ if (features.isEnabled("pinnedButtons")) {
6218
+ const { pinned: footer, nonPinned: layout2 } = groupLayoutByPinned((_a = step.layout) != null ? _a : []);
6219
+ return { layout: layout2, footer };
6220
+ }
6221
+ const { layout = [] } = step;
6222
+ return { layout, footer: [] };
6220
6223
  };
6221
6224
 
6222
6225
  // src/getSubflowCallbacks.ts
@@ -6810,17 +6813,28 @@ var createFlowController = (props) => {
6810
6813
  return false;
6811
6814
  }
6812
6815
  };
6813
- trackEvent("Initiated");
6816
+ let initState = "initial";
6814
6817
  if (initialStep) {
6818
+ initState = "created";
6819
+ trackEvent("Initiated");
6815
6820
  createStep(initialStep, null);
6816
6821
  trackEvent("Step Shown", { isFirstStep: true });
6817
- } else if (initialAction) {
6818
- rootComponent.setLoadingState("submitting");
6819
- void onAction(__spreadValues({ method: "GET" }, initialAction), null);
6820
6822
  }
6821
- rootComponent.start();
6823
+ const start = () => {
6824
+ if (initState === "initial" && initialAction) {
6825
+ initState = "created";
6826
+ trackEvent("Initiated");
6827
+ rootComponent.setLoadingState("submitting");
6828
+ void onAction(__spreadValues({ method: "GET" }, initialAction), null);
6829
+ }
6830
+ if (initState === "created") {
6831
+ initState = "started";
6832
+ rootComponent.start();
6833
+ }
6834
+ };
6822
6835
  return {
6823
6836
  rootComponent,
6837
+ start,
6824
6838
  cancel: closeWithCancellation
6825
6839
  };
6826
6840
  };
@@ -8218,7 +8232,10 @@ var useRerender = () => {
8218
8232
  };
8219
8233
  var useFlowController = (props) => {
8220
8234
  const df = (0, import_react3.useMemo)(() => createFlowController(props), []);
8221
- (0, import_react3.useEffect)(() => () => df.rootComponent.stop(), []);
8235
+ (0, import_react3.useEffect)(() => {
8236
+ df.start();
8237
+ return () => df.rootComponent.stop();
8238
+ }, []);
8222
8239
  return df;
8223
8240
  };
8224
8241