@wise/dynamic-flow-client 5.6.0 → 5.6.2

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.mjs CHANGED
@@ -386,7 +386,7 @@ var ja_default = {
386
386
  "dynamicFlows.FileUploadSchema.maxFileSizeError": "\u5927\u5909\u7533\u3057\u8A33\u3054\u3056\u3044\u307E\u305B\u3093\u304C\u3001\u30D5\u30A1\u30A4\u30EB\u304C\u5927\u304D\u3059\u304E\u307E\u3059\u3002\u3053\u308C\u3088\u308A\u5C0F\u3055\u3044\u30D5\u30A1\u30A4\u30EB\u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
387
387
  "dynamicFlows.FileUploadSchema.wrongFileTypeError": "\u305D\u306E\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\u5225\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
388
388
  "dynamicFlows.Help.ariaLabel": "\u8A73\u7D30\u306F\u3053\u3061\u3089\u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
389
- "dynamicFlows.MultiSelect.summary": "{first}\u3068\u305D\u306E\u4ED6{count}",
389
+ "dynamicFlows.MultiSelect.summary": "{first}\u3068\u305D\u306E\u4ED6{count}\u30AA\u30D7\u30B7\u30E7\u30F3",
390
390
  "dynamicFlows.MultipleFileUploadSchema.maxFileSizeError": "\u5927\u5909\u7533\u3057\u8A33\u3054\u3056\u3044\u307E\u305B\u3093\u304C\u3001\u30D5\u30A1\u30A4\u30EB\u304C\u5927\u304D\u3059\u304E\u307E\u3059\u3002\u3053\u308C\u3088\u308A\u5C0F\u3055\u3044\u30D5\u30A1\u30A4\u30EB\u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
391
391
  "dynamicFlows.MultipleFileUploadSchema.maxItemsError": "{maxItems}\u500B\u4EE5\u4E0B\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
392
392
  "dynamicFlows.MultipleFileUploadSchema.minItemsError": "{minItems}\u500B\u4EE5\u4E0A\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
@@ -2287,6 +2287,35 @@ var modalToComponent = (uid, { content, title }, mapperProps, schemaComponents)
2287
2287
  mapperProps.onComponentUpdate
2288
2288
  );
2289
2289
 
2290
+ // src/domain/components/step/ExternalConfirmationComponent.ts
2291
+ var createExternalConfirmation = (uid, url, onComponentUpdate) => {
2292
+ const update = getInputUpdateFunction(onComponentUpdate);
2293
+ return {
2294
+ type: "external-confirmation",
2295
+ kind: "layout",
2296
+ uid,
2297
+ url,
2298
+ status: "initial",
2299
+ onSuccess() {
2300
+ update(this, (draft) => {
2301
+ draft.status = "success";
2302
+ });
2303
+ },
2304
+ onFailure() {
2305
+ if (this.status === "initial") {
2306
+ update(this, (draft) => {
2307
+ draft.status = "failure";
2308
+ });
2309
+ }
2310
+ },
2311
+ onCancel() {
2312
+ update(this, (draft) => {
2313
+ draft.status = "dismissed";
2314
+ });
2315
+ }
2316
+ };
2317
+ };
2318
+
2290
2319
  // src/utils/recursiveMerge.ts
2291
2320
  function recursiveMerge(valueA, valueB) {
2292
2321
  if (valueA === null) {
@@ -2326,526 +2355,162 @@ function mergeArrays(valueA, valueB) {
2326
2355
  );
2327
2356
  }
2328
2357
 
2329
- // src/controller/getErrorMessage.ts
2330
- var getErrorMessage = (error) => {
2331
- return error instanceof Error ? error.message : typeof error === "string" ? error : `Unknown Error: type is ${typeof error}`;
2332
- };
2358
+ // src/utils/component-utils.ts
2359
+ var getSubmittableData = async (components) => Promise.all(components.map(async (component) => component.getSubmittableValue())).then(
2360
+ (values) => values.reduce((acc, value) => recursiveMerge(acc, value), null)
2361
+ );
2362
+ var getSubmittableDataSync = (components) => components.map((component) => component.getSubmittableValueSync()).reduce((acc, value) => recursiveMerge(acc, value), null);
2363
+ var getLocalValues = (components) => components.map((component) => component.getLocalValue()).reduce((acc, value) => recursiveMerge(acc, value), null);
2333
2364
 
2334
- // src/controller/response-utils.ts
2335
- import { validateActionResponse, validateSubflowResponse } from "@wise/dynamic-flow-types/spec";
2336
- var parseResponseBodyAsJsonElement = async (response) => {
2337
- assertResponseIsValid(response);
2338
- try {
2339
- return await response.json();
2340
- } catch (e) {
2341
- return null;
2342
- }
2343
- };
2344
- var parseResponseBodyAsText = async (response) => {
2345
- try {
2346
- return await response.text();
2347
- } catch (e) {
2348
- return null;
2349
- }
2365
+ // src/domain/components/step/StepDomainComponent.ts
2366
+ var createStepComponent = (stepProps) => {
2367
+ const _a = stepProps, { uid, stepPolling, stepRefreshAfter, stepPrefetch, onComponentUpdate } = _a, rest = __objRest(_a, ["uid", "stepPolling", "stepRefreshAfter", "stepPrefetch", "onComponentUpdate"]);
2368
+ const update = getInputUpdateFunction(onComponentUpdate);
2369
+ const component = __spreadProps(__spreadValues({
2370
+ uid
2371
+ }, rest), {
2372
+ type: "step",
2373
+ kind: "step",
2374
+ modals: [],
2375
+ requestCache: stepPrefetch.requestCache,
2376
+ dismissModal() {
2377
+ var _a2;
2378
+ (_a2 = this.modals.at(-1)) == null ? void 0 : _a2.close();
2379
+ },
2380
+ dismissAllModals() {
2381
+ this._update((draft) => {
2382
+ draft.modals = draft.modals.map((m) => __spreadProps(__spreadValues({}, m), { open: false }));
2383
+ });
2384
+ },
2385
+ showModal(modal) {
2386
+ this._update((draft) => {
2387
+ draft.modals = [...draft.modals, modal];
2388
+ });
2389
+ },
2390
+ _update(updateFn) {
2391
+ update(this, updateFn);
2392
+ },
2393
+ getChildren() {
2394
+ return this.externalConfirmation ? [...this.layoutComponents, this.externalConfirmation] : this.layoutComponents;
2395
+ },
2396
+ getModals() {
2397
+ return this.modals;
2398
+ },
2399
+ async getSubmittableValue() {
2400
+ return getSubmittableData(this.schemaComponents);
2401
+ },
2402
+ getSubmittableValueSync() {
2403
+ return getSubmittableDataSync(this.schemaComponents);
2404
+ },
2405
+ getLocalValue() {
2406
+ return getLocalValues(this.schemaComponents);
2407
+ },
2408
+ validate() {
2409
+ return this.schemaComponents.every(
2410
+ (inputComponent) => inputComponent.isSchemaReferencedInStep ? inputComponent.validate() : true
2411
+ );
2412
+ },
2413
+ setLoadingState(loadingState) {
2414
+ this._update((draft) => {
2415
+ draft.loadingState = loadingState;
2416
+ });
2417
+ },
2418
+ start() {
2419
+ stepPolling == null ? void 0 : stepPolling.start();
2420
+ stepRefreshAfter == null ? void 0 : stepRefreshAfter.start();
2421
+ stepPrefetch.start(this.getSubmittableValueSync());
2422
+ },
2423
+ stop() {
2424
+ stepPolling == null ? void 0 : stepPolling.stop();
2425
+ stepRefreshAfter == null ? void 0 : stepRefreshAfter.stop();
2426
+ stepPrefetch.stop();
2427
+ this._update((draft) => {
2428
+ draft.modals = [];
2429
+ });
2430
+ }
2431
+ });
2432
+ return component;
2350
2433
  };
2351
- function isActionResponseBody(body) {
2352
- return validateActionResponse(body).valid;
2353
- }
2354
- function assertActionResponseBody(body) {
2355
- if (!isObject(body) || !isObject(body.action)) {
2356
- throw new Error(
2357
- "Incorrect response body in action response. Expected an object satisfying the type { action: Action }."
2358
- );
2434
+
2435
+ // src/domain/features/polling/getStepPolling.ts
2436
+ var getStepPolling = ({
2437
+ pollingConfig,
2438
+ logEvent,
2439
+ onBehavior,
2440
+ onPoll,
2441
+ registerSubmissionBehavior
2442
+ }) => {
2443
+ const { interval, delay = interval, maxAttempts, url, onError } = pollingConfig;
2444
+ let abortController = new AbortController();
2445
+ let intervalRef = null;
2446
+ if (delay == null) {
2447
+ throw new Error("Polling configuration must include delay or interval");
2359
2448
  }
2360
- }
2361
- function assertModalResponseBody(body) {
2362
- if (isObject(body)) {
2363
- if ("content" in body && isArray(body.content)) {
2449
+ const onErrorBehavior = getDomainLayerBehavior(onError, [], registerSubmissionBehavior);
2450
+ let attempts = 0;
2451
+ const poll = () => {
2452
+ attempts += 1;
2453
+ abortController.abort();
2454
+ abortController = new AbortController();
2455
+ const { signal } = abortController;
2456
+ onPoll(url, onErrorBehavior, signal).then((result) => {
2457
+ if (result) {
2458
+ stop();
2459
+ return;
2460
+ }
2461
+ if (attempts >= maxAttempts && !signal.aborted) {
2462
+ void onBehavior(onErrorBehavior);
2463
+ stop();
2464
+ }
2465
+ }).catch(() => {
2466
+ });
2467
+ };
2468
+ const start = () => {
2469
+ attempts = 0;
2470
+ intervalRef = setInterval(poll, delay * 1e3);
2471
+ poll();
2472
+ };
2473
+ const stop = () => {
2474
+ if (!intervalRef) {
2475
+ logEvent("warning", "Attempted to stop polling but it was not started");
2364
2476
  return;
2365
2477
  }
2366
- }
2367
- throw new Error(
2368
- "Incorrect response body in modal response. Expected an object satisfying the type { title?: string, components: Layout[] }."
2369
- );
2370
- }
2371
- function assertSubflowResponseBody(body) {
2372
- const { valid } = validateSubflowResponse(body);
2373
- if (valid) {
2374
- return;
2375
- }
2376
- throw new Error("Incorrect response body in subflow response.");
2377
- }
2378
- function isErrorResponseBody(body) {
2379
- return Boolean(
2380
- isObject(body) && (body.refreshFormUrl || body.refreshUrl || body.validation || body.error || body.analytics)
2381
- );
2382
- }
2383
- function assertStepResponseBody(body) {
2384
- if (!isObject(body)) {
2385
- throw new Error("Incorrect response body in step response. Expected an object.");
2386
- }
2387
- }
2388
- var assertResponseIsValid = (response) => {
2389
- if (!isResponse(response)) {
2390
- throw new Error("Incorrect type of response from fetch. Expected object of type Response.");
2391
- }
2392
- if (response.bodyUsed) {
2393
- throw new Error(
2394
- "The body of the provided Response object has already been used. Every request must respond with a new Response object."
2395
- );
2396
- }
2478
+ clearTimeout(intervalRef);
2479
+ abortController.abort();
2480
+ };
2481
+ return { start, stop };
2397
2482
  };
2398
- var isResponse = (response) => typeof response === "object" && response !== null && "clone" in response && "bodyUsed" in response;
2399
2483
 
2400
- // src/controller/handleErrorResponse.ts
2401
- var handleErrorResponse = async (response, actionId, trackEvent) => {
2402
- const body = await parseResponseBodyAsJsonElement(response.clone());
2403
- if (isErrorResponseBody(body)) {
2404
- const refreshUrl = body.refreshUrl || body.refreshFormUrl;
2405
- const { error, validation, analytics } = body;
2406
- trackEvent("Action Failed", __spreadProps(__spreadValues({}, analytics), { actionId, statusCode: response.status }));
2407
- const errors = { error, validation };
2408
- return refreshUrl ? { type: "refresh", body: { refreshUrl, errors } } : {
2409
- type: "error",
2410
- body: { errors, analytics },
2411
- httpError: { statusCode: response.status }
2412
- };
2484
+ // src/domain/features/refreshAfter/getStepRefreshAfter.ts
2485
+ var ONE_SECOND = 1e3;
2486
+ var getStepRefreshAfter = ({
2487
+ refreshAfter,
2488
+ logEvent,
2489
+ onBehavior
2490
+ }) => {
2491
+ let timeout = null;
2492
+ const targetTime = new Date(refreshAfter).getTime();
2493
+ if (typeof refreshAfter !== "string" || Number.isNaN(targetTime)) {
2494
+ throw new Error(`Invalid refreshAfter value: ${String(refreshAfter)}`);
2413
2495
  }
2414
- trackEvent("Action Failed", { actionId, statusCode: response.status });
2415
- const errorMessage = await parseResponseBodyAsText(response);
2496
+ const start = () => {
2497
+ const timeLeft = Math.max(targetTime - Date.now(), ONE_SECOND);
2498
+ timeout = setTimeout(() => {
2499
+ void onBehavior({ type: "refresh", analytics: { schema: "refreshAfter" } });
2500
+ }, timeLeft);
2501
+ };
2416
2502
  return {
2417
- type: "error",
2418
- httpError: {
2419
- message: errorMessage || void 0,
2420
- statusCode: response.status
2503
+ start,
2504
+ stop: () => {
2505
+ if (!timeout) {
2506
+ logEvent("warning", "Attempted to stop refreshAfter but it was not started");
2507
+ return;
2508
+ }
2509
+ clearTimeout(timeout);
2421
2510
  }
2422
2511
  };
2423
2512
  };
2424
2513
 
2425
- // src/controller/getResponseType.ts
2426
- var responseTypes = ["step", "action", "exit", "modal", "subflow"];
2427
- var getResponseType = (headers, body) => {
2428
- const headerResponseType = getResponseTypeFromHeader(headers);
2429
- if (headerResponseType) {
2430
- return headerResponseType;
2431
- }
2432
- if (isObject(body) && body.action) {
2433
- return "action";
2434
- }
2435
- return "step";
2436
- };
2437
- var getResponseTypeFromHeader = (headers) => {
2438
- if (headers == null ? void 0 : headers.has("X-Df-Response-Type")) {
2439
- const type = headers.get("X-Df-Response-Type");
2440
- assertDFResponseType(type);
2441
- return type;
2442
- }
2443
- if (headers == null ? void 0 : headers.has("X-Df-Exit")) {
2444
- return "exit";
2445
- }
2446
- return void 0;
2447
- };
2448
- function assertDFResponseType(type) {
2449
- if (!responseTypes.includes(type)) {
2450
- throw new Error(
2451
- "Unsupported X-Df-Response-Type. Allowed values are 'step', 'action', 'exit', 'error', 'modal', 'subflow'."
2452
- );
2453
- }
2454
- }
2455
-
2456
- // src/controller/makeSafeHttpClient.ts
2457
- var makeSafeHttpClient = (httpClient) => async (...props) => {
2458
- try {
2459
- return await httpClient(...props);
2460
- } catch (e) {
2461
- return null;
2462
- }
2463
- };
2464
-
2465
- // src/controller/executeRequest.ts
2466
- var executeRequest = async (props) => {
2467
- const { exit, request, requestCache, httpClient, trackEvent, logEvent } = props;
2468
- const { url, method, body } = request;
2469
- const response = await getCachedOrFetch(
2470
- [
2471
- url,
2472
- {
2473
- method,
2474
- body: body ? JSON.stringify(body) : void 0,
2475
- headers: { "Content-Type": "application/json" }
2476
- }
2477
- ],
2478
- requestCache,
2479
- httpClient
2480
- );
2481
- if (!response) {
2482
- const extra = { errorMessage: "Network Error" };
2483
- trackEvent("Request Failed", extra);
2484
- logEvent("error", "Dynamic Flow - Request Failed Unexpectedly", extra);
2485
- return { type: "error" };
2486
- }
2487
- if (!response.ok) {
2488
- return handleErrorResponse(response, void 0, trackEvent);
2489
- }
2490
- const responseBody = await parseResponseBodyAsJsonElement(response);
2491
- const responseType = getResponseType(response.headers, responseBody);
2492
- if (exit) {
2493
- return { type: "complete", result: responseBody };
2494
- }
2495
- switch (responseType) {
2496
- case "step": {
2497
- const etag = response.headers.get("etag") || null;
2498
- assertStepResponseBody(responseBody);
2499
- return { type: "replace-step", step: responseBody, etag };
2500
- }
2501
- case "exit": {
2502
- return { type: "complete", result: responseBody };
2503
- }
2504
- case "action": {
2505
- assertActionResponseBody(responseBody);
2506
- return {
2507
- type: "behavior",
2508
- behavior: {
2509
- type: "action",
2510
- action: responseBody.action
2511
- }
2512
- };
2513
- }
2514
- case "subflow": {
2515
- assertSubflowResponseBody(responseBody);
2516
- return {
2517
- type: "behavior",
2518
- behavior: __spreadProps(__spreadValues({}, responseBody), {
2519
- type: "subflow",
2520
- onCompletion: responseBody.onCompletion ? normaliseBehavior(responseBody.onCompletion, []) : void 0,
2521
- onError: responseBody.onError ? normaliseBehavior(responseBody.onError, []) : void 0
2522
- })
2523
- };
2524
- }
2525
- case "modal": {
2526
- assertModalResponseBody(responseBody);
2527
- return { type: "behavior", behavior: __spreadProps(__spreadValues({}, responseBody), { type: "modal" }) };
2528
- }
2529
- default: {
2530
- throw new Error(`Unsupported response type: ${String(responseType)}`);
2531
- }
2532
- }
2533
- };
2534
- var getCachedOrFetch = async (requestParams, requestCache, httpClient) => {
2535
- const cachedPromise = requestCache.get(requestParams);
2536
- if (cachedPromise) {
2537
- const cachedResponse = await cachedPromise;
2538
- if (cachedResponse == null ? void 0 : cachedResponse.ok) {
2539
- return cachedResponse;
2540
- }
2541
- }
2542
- return makeSafeHttpClient(httpClient)(...requestParams);
2543
- };
2544
-
2545
- // src/controller/executeSubmission.ts
2546
- var executeSubmission = async (props) => {
2547
- const { httpClient, requestCache, trackEvent, logEvent } = props;
2548
- const triggerAction = async (action, model, isInitial) => {
2549
- var _a, _b;
2550
- const { exit, url, result = null, id: actionId } = action;
2551
- const trackSubmissionEvent = !isInitial ? trackEvent : () => {
2552
- };
2553
- trackSubmissionEvent("Action Triggered", { actionId });
2554
- if (exit && !url) {
2555
- trackSubmissionEvent("Action Succeeded", { actionId });
2556
- return { type: "complete", result };
2557
- }
2558
- try {
2559
- const command = await executeRequest({
2560
- exit,
2561
- request: createRequestFromAction(action, model),
2562
- requestCache,
2563
- httpClient,
2564
- trackEvent: (name, properties) => {
2565
- trackSubmissionEvent(name, __spreadProps(__spreadValues({}, properties), { actionId }));
2566
- },
2567
- logEvent
2568
- });
2569
- switch (command.type) {
2570
- case "error": {
2571
- trackSubmissionEvent("Action Failed", __spreadValues({
2572
- actionId,
2573
- statusCode: (_a = command.httpError) == null ? void 0 : _a.statusCode
2574
- }, (_b = command.body) == null ? void 0 : _b.analytics));
2575
- return command;
2576
- }
2577
- case "behavior": {
2578
- if (command.behavior.type === "action") {
2579
- trackSubmissionEvent("Action Succeeded", { actionId });
2580
- return await executeRequest({
2581
- request: createRequestFromAction(command.behavior.action, null),
2582
- requestCache,
2583
- httpClient,
2584
- trackEvent,
2585
- logEvent
2586
- });
2587
- }
2588
- trackSubmissionEvent("Action Succeeded", { actionId });
2589
- return command;
2590
- }
2591
- case "complete": {
2592
- trackSubmissionEvent("Action Succeeded", { actionId });
2593
- return __spreadProps(__spreadValues({}, command), { result: recursiveMerge(command.result, result) });
2594
- }
2595
- default: {
2596
- trackSubmissionEvent("Action Succeeded", { actionId });
2597
- return command;
2598
- }
2599
- }
2600
- } catch (error) {
2601
- const errorMessage = getErrorMessage(error);
2602
- trackSubmissionEvent("Action Failed", { actionId, errorMessage });
2603
- logEvent("error", "Dynamic Flow - Action Failed Unexpectedly", { actionId, errorMessage });
2604
- throw error;
2605
- }
2606
- };
2607
- return triggerAction(props.action, props.model, props.isInitial);
2608
- };
2609
- var createRequestFromAction = (action, model) => {
2610
- var _a, _b, _c;
2611
- return __spreadProps(__spreadValues({}, action), {
2612
- url: (_a = action.url) != null ? _a : "",
2613
- method: (_b = action.method) != null ? _b : "POST",
2614
- body: action.method === "GET" ? void 0 : recursiveMerge(model, (_c = action.data) != null ? _c : null)
2615
- });
2616
- };
2617
-
2618
- // src/domain/components/step/ExternalConfirmationComponent.ts
2619
- var createExternalConfirmation = (uid, url, onComponentUpdate) => {
2620
- const update = getInputUpdateFunction(onComponentUpdate);
2621
- return {
2622
- type: "external-confirmation",
2623
- kind: "layout",
2624
- uid,
2625
- url,
2626
- status: "initial",
2627
- onSuccess() {
2628
- update(this, (draft) => {
2629
- draft.status = "success";
2630
- });
2631
- },
2632
- onFailure() {
2633
- if (this.status === "initial") {
2634
- update(this, (draft) => {
2635
- draft.status = "failure";
2636
- });
2637
- }
2638
- },
2639
- onCancel() {
2640
- update(this, (draft) => {
2641
- draft.status = "dismissed";
2642
- });
2643
- }
2644
- };
2645
- };
2646
-
2647
- // src/utils/component-utils.ts
2648
- var getSubmittableData = async (components) => Promise.all(components.map(async (component) => component.getSubmittableValue())).then(
2649
- (values) => values.reduce((acc, value) => recursiveMerge(acc, value), null)
2650
- );
2651
- var getSubmittableDataSync = (components) => components.map((component) => component.getSubmittableValueSync()).reduce((acc, value) => recursiveMerge(acc, value), null);
2652
- var getLocalValues = (components) => components.map((component) => component.getLocalValue()).reduce((acc, value) => recursiveMerge(acc, value), null);
2653
-
2654
- // src/domain/components/step/StepDomainComponent.ts
2655
- var createStepComponent = (stepProps) => {
2656
- const _a = stepProps, { uid, stepPolling, stepRefreshAfter, onComponentUpdate } = _a, rest = __objRest(_a, ["uid", "stepPolling", "stepRefreshAfter", "onComponentUpdate"]);
2657
- const update = getInputUpdateFunction(onComponentUpdate);
2658
- const component = __spreadProps(__spreadValues({
2659
- uid
2660
- }, rest), {
2661
- type: "step",
2662
- kind: "step",
2663
- modals: [],
2664
- dismissModal() {
2665
- var _a2;
2666
- (_a2 = this.modals.at(-1)) == null ? void 0 : _a2.close();
2667
- },
2668
- dismissAllModals() {
2669
- this._update((draft) => {
2670
- draft.modals = draft.modals.map((m) => __spreadProps(__spreadValues({}, m), { open: false }));
2671
- });
2672
- },
2673
- showModal(modal) {
2674
- this._update((draft) => {
2675
- draft.modals = [...draft.modals, modal];
2676
- });
2677
- },
2678
- _update(updateFn) {
2679
- update(this, updateFn);
2680
- },
2681
- getChildren() {
2682
- return this.externalConfirmation ? [...this.layoutComponents, this.externalConfirmation] : this.layoutComponents;
2683
- },
2684
- getModals() {
2685
- return this.modals;
2686
- },
2687
- async getSubmittableValue() {
2688
- return getSubmittableData(this.schemaComponents);
2689
- },
2690
- getSubmittableValueSync() {
2691
- return getSubmittableDataSync(this.schemaComponents);
2692
- },
2693
- getLocalValue() {
2694
- return getLocalValues(this.schemaComponents);
2695
- },
2696
- validate() {
2697
- return this.schemaComponents.every(
2698
- (inputComponent) => inputComponent.isSchemaReferencedInStep ? inputComponent.validate() : true
2699
- );
2700
- },
2701
- setLoadingState(loadingState) {
2702
- this._update((draft) => {
2703
- draft.loadingState = loadingState;
2704
- });
2705
- },
2706
- start() {
2707
- stepPolling == null ? void 0 : stepPolling.start();
2708
- stepRefreshAfter == null ? void 0 : stepRefreshAfter.start();
2709
- },
2710
- stop() {
2711
- stepPolling == null ? void 0 : stepPolling.stop();
2712
- stepRefreshAfter == null ? void 0 : stepRefreshAfter.stop();
2713
- this._update((draft) => {
2714
- draft.modals = [];
2715
- });
2716
- }
2717
- });
2718
- return component;
2719
- };
2720
-
2721
- // src/domain/features/polling/getStepPolling.ts
2722
- var getStepPolling = ({
2723
- pollingConfig,
2724
- logEvent,
2725
- onBehavior,
2726
- onPoll,
2727
- registerSubmissionBehavior
2728
- }) => {
2729
- const { interval, delay = interval, maxAttempts, url, onError } = pollingConfig;
2730
- let abortController = new AbortController();
2731
- let intervalRef = null;
2732
- if (delay == null) {
2733
- throw new Error("Polling configuration must include delay or interval");
2734
- }
2735
- const onErrorBehavior = getDomainLayerBehavior(onError, [], registerSubmissionBehavior);
2736
- let attempts = 0;
2737
- const poll = () => {
2738
- attempts += 1;
2739
- abortController.abort();
2740
- abortController = new AbortController();
2741
- const { signal } = abortController;
2742
- onPoll(url, onErrorBehavior, signal).then((result) => {
2743
- if (result) {
2744
- stop();
2745
- return;
2746
- }
2747
- if (attempts >= maxAttempts && !signal.aborted) {
2748
- void onBehavior(onErrorBehavior);
2749
- stop();
2750
- }
2751
- }).catch(() => {
2752
- });
2753
- };
2754
- const start = () => {
2755
- attempts = 0;
2756
- intervalRef = setInterval(poll, delay * 1e3);
2757
- poll();
2758
- };
2759
- const stop = () => {
2760
- if (!intervalRef) {
2761
- logEvent("warning", "Attempted to stop polling but it was not started");
2762
- return;
2763
- }
2764
- clearTimeout(intervalRef);
2765
- abortController.abort();
2766
- };
2767
- return { start, stop };
2768
- };
2769
-
2770
- // src/domain/features/refreshAfter/getStepRefreshAfter.ts
2771
- var ONE_SECOND = 1e3;
2772
- var getStepRefreshAfter = ({
2773
- refreshAfter,
2774
- logEvent,
2775
- onBehavior
2776
- }) => {
2777
- let timeout = null;
2778
- const targetTime = new Date(refreshAfter).getTime();
2779
- if (typeof refreshAfter !== "string" || Number.isNaN(targetTime)) {
2780
- throw new Error(`Invalid refreshAfter value: ${String(refreshAfter)}`);
2781
- }
2782
- const start = () => {
2783
- const timeLeft = Math.max(targetTime - Date.now(), ONE_SECOND);
2784
- timeout = setTimeout(() => {
2785
- void onBehavior({ type: "refresh", analytics: { schema: "refreshAfter" } });
2786
- }, timeLeft);
2787
- };
2788
- return {
2789
- start,
2790
- stop: () => {
2791
- if (!timeout) {
2792
- logEvent("warning", "Attempted to stop refreshAfter but it was not started");
2793
- return;
2794
- }
2795
- clearTimeout(timeout);
2796
- }
2797
- };
2798
- };
2799
-
2800
- // src/domain/prefetching/request-cache.ts
2801
- var makeRequestCacheWithParent = (parent) => {
2802
- const map = /* @__PURE__ */ new Map();
2803
- const cache = {
2804
- get: (requestParams) => {
2805
- var _a;
2806
- const key = makeKey(requestParams);
2807
- const promise = (_a = map.get(key)) != null ? _a : parent == null ? void 0 : parent.get(requestParams);
2808
- map.delete(key);
2809
- return promise;
2810
- },
2811
- set: (requestParams, responsePromise) => {
2812
- return map.set(makeKey(requestParams), responsePromise);
2813
- }
2814
- };
2815
- return cache;
2816
- };
2817
- var makeRequestCache = (initialValues = []) => {
2818
- const cache = makeRequestCacheWithParent(void 0);
2819
- initialValues.forEach(([requestParams, responsePromise]) => {
2820
- cache.set(requestParams, responsePromise);
2821
- });
2822
- return cache;
2823
- };
2824
- var normaliseRequestCache = (cache) => {
2825
- if (cache === void 0) {
2826
- return makeRequestCache();
2827
- }
2828
- if (isRequestCacheInstance(cache)) {
2829
- return cache;
2830
- }
2831
- return makeRequestCache(cache);
2832
- };
2833
- var isRequestCacheInstance = (cache) => {
2834
- return !cache || !Array.isArray(cache);
2835
- };
2836
- var makeKey = (requestParams) => {
2837
- var _a, _b;
2838
- const [input, init] = requestParams;
2839
- const url = typeof input === "string" || input instanceof URL ? input.toString() : input.url;
2840
- const key = JSON.stringify({
2841
- url,
2842
- method: (_a = init == null ? void 0 : init.method) != null ? _a : "GET",
2843
- headers: (init == null ? void 0 : init.headers) ? Array.from(new Headers(init.headers).entries()) : [],
2844
- body: (_b = init == null ? void 0 : init.body) != null ? _b : null
2845
- });
2846
- return key;
2847
- };
2848
-
2849
2514
  // src/domain/components/utils/isOrWasValid.ts
2850
2515
  var isOrWasValid = (getErrors, previous, current) => {
2851
2516
  const wasValid = getErrors(previous).length === 0 && previous !== null;
@@ -3324,6 +2989,72 @@ var getInitialValidationAsyncState = () => ({
3324
2989
  messages: {}
3325
2990
  });
3326
2991
 
2992
+ // src/controller/response-utils.ts
2993
+ import { validateActionResponse, validateSubflowResponse } from "@wise/dynamic-flow-types/spec";
2994
+ var parseResponseBodyAsJsonElement = async (response) => {
2995
+ assertResponseIsValid(response);
2996
+ try {
2997
+ return await response.json();
2998
+ } catch (e) {
2999
+ return null;
3000
+ }
3001
+ };
3002
+ var parseResponseBodyAsText = async (response) => {
3003
+ try {
3004
+ return await response.text();
3005
+ } catch (e) {
3006
+ return null;
3007
+ }
3008
+ };
3009
+ function isActionResponseBody(body) {
3010
+ return validateActionResponse(body).valid;
3011
+ }
3012
+ function assertActionResponseBody(body) {
3013
+ if (!isObject(body) || !isObject(body.action)) {
3014
+ throw new Error(
3015
+ "Incorrect response body in action response. Expected an object satisfying the type { action: Action }."
3016
+ );
3017
+ }
3018
+ }
3019
+ function assertModalResponseBody(body) {
3020
+ if (isObject(body)) {
3021
+ if ("content" in body && isArray(body.content)) {
3022
+ return;
3023
+ }
3024
+ }
3025
+ throw new Error(
3026
+ "Incorrect response body in modal response. Expected an object satisfying the type { title?: string, components: Layout[] }."
3027
+ );
3028
+ }
3029
+ function assertSubflowResponseBody(body) {
3030
+ const { valid } = validateSubflowResponse(body);
3031
+ if (valid) {
3032
+ return;
3033
+ }
3034
+ throw new Error("Incorrect response body in subflow response.");
3035
+ }
3036
+ function isErrorResponseBody(body) {
3037
+ return Boolean(
3038
+ isObject(body) && (body.refreshFormUrl || body.refreshUrl || body.validation || body.error || body.analytics)
3039
+ );
3040
+ }
3041
+ function assertStepResponseBody(body) {
3042
+ if (!isObject(body)) {
3043
+ throw new Error("Incorrect response body in step response. Expected an object.");
3044
+ }
3045
+ }
3046
+ var assertResponseIsValid = (response) => {
3047
+ if (!isResponse(response)) {
3048
+ throw new Error("Incorrect type of response from fetch. Expected object of type Response.");
3049
+ }
3050
+ if (response.bodyUsed) {
3051
+ throw new Error(
3052
+ "The body of the provided Response object has already been used. Every request must respond with a new Response object."
3053
+ );
3054
+ }
3055
+ };
3056
+ var isResponse = (response) => typeof response === "object" && response !== null && "clone" in response && "bodyUsed" in response;
3057
+
3327
3058
  // src/domain/features/utils/response-utils.ts
3328
3059
  var getAnalyticsFromErrorResponse = (json) => {
3329
3060
  if (!isErrorResponseBody(json)) {
@@ -5646,6 +5377,7 @@ var mapStringSchemaSuggestions = (suggestions, logEvent) => {
5646
5377
 
5647
5378
  // src/domain/mappers/schema/stringSchemaToComponent/stringSchemaToDateInputComponent.ts
5648
5379
  var stringSchemaToDateInputComponent = (schemaMapperProps, mapperProps) => {
5380
+ var _a;
5649
5381
  const { schema, localValue, model, required = false, onPersistAsync } = schemaMapperProps;
5650
5382
  const {
5651
5383
  autocompleteHint,
@@ -5661,7 +5393,7 @@ var stringSchemaToDateInputComponent = (schemaMapperProps, mapperProps) => {
5661
5393
  mapperProps
5662
5394
  );
5663
5395
  const validLocalValue = isString(localValue) ? localValue : null;
5664
- const validModel = isString(model) ? model : defaultValue != null ? defaultValue : null;
5396
+ const validModel = (_a = getValidDate(model)) != null ? _a : getValidDate(defaultValue != null ? defaultValue : null);
5665
5397
  const value = onPersistAsync ? validLocalValue : validModel;
5666
5398
  return createDateInputComponent(
5667
5399
  __spreadProps(__spreadValues({}, mapCommonSchemaProps(schemaMapperProps)), {
@@ -5684,6 +5416,21 @@ var stringSchemaToDateInputComponent = (schemaMapperProps, mapperProps) => {
5684
5416
  onComponentUpdate
5685
5417
  );
5686
5418
  };
5419
+ var getValidDate = (model) => {
5420
+ if (!isString(model)) {
5421
+ return null;
5422
+ }
5423
+ if (/^\d{4}-\d{2}$/.test(model)) {
5424
+ return model;
5425
+ }
5426
+ try {
5427
+ const date = new Date(model);
5428
+ const stringDate = date.toISOString();
5429
+ return stringDate.split("T")[0];
5430
+ } catch (e) {
5431
+ return null;
5432
+ }
5433
+ };
5687
5434
 
5688
5435
  // src/domain/mappers/schema/stringSchemaToComponent/stringSchemaToUploadInputComponent.ts
5689
5436
  var stringSchemaToUploadInputComponent = (schemaMapperProps, mapperProps) => {
@@ -5799,235 +5546,544 @@ var createTextInputComponent = (textInputProps, onComponentUpdate) => {
5799
5546
  this._update((draft) => {
5800
5547
  draft.errors = errors;
5801
5548
  });
5802
- return errors.length === 0;
5803
- }
5804
- }, rest);
5805
- return inputComponent;
5549
+ return errors.length === 0;
5550
+ }
5551
+ }, rest);
5552
+ return inputComponent;
5553
+ };
5554
+
5555
+ // src/domain/mappers/schema/stringSchemaToComponent/stringSchemaToTextInputComponent.ts
5556
+ var stringSchemaToTextInputComponent = (schemaMapperProps, mapperProps) => {
5557
+ const { schema, localValue, model, required = false, onPersistAsync } = schemaMapperProps;
5558
+ const {
5559
+ autocapitalization,
5560
+ autocompleteHint,
5561
+ control,
5562
+ default: defaultValue,
5563
+ displayFormat,
5564
+ format,
5565
+ maxLength,
5566
+ minLength,
5567
+ suggestions,
5568
+ validationMessages
5569
+ } = schema;
5570
+ const { getErrorMessageFunctions, onComponentUpdate, onBehavior, onValueChange, logEvent } = mapperProps;
5571
+ const controlForLegacyFormat = getControlForLegacyFormat(format);
5572
+ const errorMessageFunctions = getErrorMessageFunctions(validationMessages);
5573
+ const { performValidationAsync, validationAsyncState } = getValidationAsyncInitialState(
5574
+ schemaMapperProps,
5575
+ mapperProps
5576
+ );
5577
+ const validLocalValue = isString(localValue) ? localValue : null;
5578
+ const validModel = isString(model) ? model : defaultValue != null ? defaultValue : null;
5579
+ const value = onPersistAsync ? validLocalValue : validModel;
5580
+ return createTextInputComponent(
5581
+ __spreadProps(__spreadValues({}, mapCommonSchemaProps(schemaMapperProps)), {
5582
+ autocapitalization,
5583
+ autoComplete: getAutocompleteString(autocompleteHint),
5584
+ checks: schema.hidden ? [] : [
5585
+ getRequiredCheck(required, errorMessageFunctions),
5586
+ getAboveMaxLengthCheck(schema, errorMessageFunctions),
5587
+ getBelowMinLengthCheck(schema, errorMessageFunctions),
5588
+ getNotAdheringToPatternCheck(schema, errorMessageFunctions, { logEvent })
5589
+ ],
5590
+ control: control != null ? control : controlForLegacyFormat,
5591
+ displayFormat,
5592
+ maxLength,
5593
+ minLength,
5594
+ suggestions: mapStringSchemaSuggestions(suggestions, mapperProps.logEvent),
5595
+ value,
5596
+ validationAsyncState,
5597
+ schemaOnChange: getSchemaOnChange(schema, onBehavior),
5598
+ performValidationAsync,
5599
+ onValueChange
5600
+ }),
5601
+ onComponentUpdate
5602
+ );
5603
+ };
5604
+ var getControlForLegacyFormat = (format) => {
5605
+ if (format && ["numeric", "phone-number", "email", "password"].includes(format)) {
5606
+ return format;
5607
+ }
5608
+ return void 0;
5609
+ };
5610
+
5611
+ // src/domain/mappers/schema/stringSchemaToComponent/stringSchemaToComponent.ts
5612
+ var stringSchemaToComponent = (schemaMapperProps, mapperProps) => {
5613
+ const { schema } = schemaMapperProps;
5614
+ if (isStringSchemaWithBase64(schema)) {
5615
+ return stringSchemaToUploadInputComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5616
+ }
5617
+ switch (schema.format) {
5618
+ case "date":
5619
+ return stringSchemaToDateInputComponent(schemaMapperProps, mapperProps);
5620
+ default:
5621
+ return stringSchemaToTextInputComponent(schemaMapperProps, mapperProps);
5622
+ }
5623
+ };
5624
+ var isStringSchemaWithBase64 = (schema) => {
5625
+ return schema.format === "base64url" && !("persistAsync" in schema);
5626
+ };
5627
+
5628
+ // src/domain/mappers/mapSchemaToComponent.ts
5629
+ var mapSchemaToComponent = (schemaMapperProps, mapperProps) => {
5630
+ const { uid, schema } = schemaMapperProps;
5631
+ if (isConstSchema(schema)) {
5632
+ return constSchemaToComponent(uid, __spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5633
+ }
5634
+ if (isSchemaWithPersistAsync(schema)) {
5635
+ return persistAsyncSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5636
+ }
5637
+ if (isAllOfSchema(schema)) {
5638
+ return allOfSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5639
+ }
5640
+ if (isOneOfSchema(schema)) {
5641
+ return oneOfSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5642
+ }
5643
+ if (isBooleanSchema(schema)) {
5644
+ return booleanSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5645
+ }
5646
+ if (isObjectSchema(schema)) {
5647
+ const { format } = schema;
5648
+ if (format === "money") {
5649
+ return objectSchemaToMoneyInputComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5650
+ }
5651
+ if (format != null && Object.keys(schema.properties).length === 0) {
5652
+ return objectSchemaToFormattedValueComponent(
5653
+ __spreadProps(__spreadValues({}, schemaMapperProps), { schema: __spreadProps(__spreadValues({}, schema), { format }) }),
5654
+ mapperProps
5655
+ );
5656
+ }
5657
+ return objectSchemaToObjectComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5658
+ }
5659
+ if (isIntegerSchema(schema)) {
5660
+ return integerSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5661
+ }
5662
+ if (isNumberSchema(schema)) {
5663
+ return numberSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5664
+ }
5665
+ if (isStringSchema(schema)) {
5666
+ return stringSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5667
+ }
5668
+ if (isArraySchema(schema)) {
5669
+ return arraySchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5670
+ }
5671
+ if (isBlobSchema(schema)) {
5672
+ if (!schemaMapperProps.onPersistAsync) {
5673
+ throw new Error(
5674
+ "Blob schemas can only be used as the schema of a persist async configuration."
5675
+ );
5676
+ }
5677
+ return blobSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5678
+ }
5679
+ throw new Error("Not yet supported");
5680
+ };
5681
+
5682
+ // src/domain/mappers/mapStepSchemas.ts
5683
+ var mapStepSchemas = (uid, step, stepLocalValue, mapperProps, referencedSchemaIds) => {
5684
+ const isReferenced = (schemaId) => schemaId != null && referencedSchemaIds.includes(schemaId);
5685
+ return step.schemas.map((schema, i) => {
5686
+ var _a, _b;
5687
+ const schemaComponent = mapSchemaToComponent(
5688
+ {
5689
+ uid: `${uid}.schemas-${i}.${schema.$id}`,
5690
+ schemaId: schema.$id,
5691
+ schema,
5692
+ model: (_a = step.model) != null ? _a : null,
5693
+ localValue: stepLocalValue,
5694
+ validationErrors: (_b = step.errors) == null ? void 0 : _b.validation,
5695
+ required: true
5696
+ },
5697
+ mapperProps
5698
+ );
5699
+ return __spreadProps(__spreadValues({}, schemaComponent), {
5700
+ isSchemaReferencedInStep: isReferenced(schema.$id)
5701
+ });
5702
+ });
5703
+ };
5704
+
5705
+ // src/domain/mappers/mapToolbarToComponent.ts
5706
+ var mapToolbarToComponent = (uid, toolbar, mapperProps) => {
5707
+ if (!toolbar) {
5708
+ return void 0;
5709
+ }
5710
+ const { onBehavior } = mapperProps;
5711
+ return __spreadProps(__spreadValues({}, toolbar), {
5712
+ type: "toolbar",
5713
+ uid: `${uid}.toolbar`,
5714
+ tags: toolbar.tags,
5715
+ items: toolbar.items.map((item) => {
5716
+ const context = item.context ? mapLegacyContext(item.context) : void 0;
5717
+ const behavior = getDomainLayerBehavior(
5718
+ { behavior: item.behavior },
5719
+ [],
5720
+ mapperProps.registerSubmissionBehavior
5721
+ );
5722
+ return __spreadProps(__spreadValues({}, item), {
5723
+ context: context ? mapLegacyContext(context) : void 0,
5724
+ disabled: !!item.disabled,
5725
+ tags: item.tags,
5726
+ onClick: () => {
5727
+ void onBehavior(behavior);
5728
+ }
5729
+ });
5730
+ })
5731
+ });
5806
5732
  };
5807
5733
 
5808
- // src/domain/mappers/schema/stringSchemaToComponent/stringSchemaToTextInputComponent.ts
5809
- var stringSchemaToTextInputComponent = (schemaMapperProps, mapperProps) => {
5810
- const { schema, localValue, model, required = false, onPersistAsync } = schemaMapperProps;
5811
- const {
5812
- autocapitalization,
5813
- autocompleteHint,
5814
- control,
5815
- default: defaultValue,
5816
- displayFormat,
5817
- format,
5818
- maxLength,
5819
- minLength,
5820
- suggestions,
5821
- validationMessages
5822
- } = schema;
5823
- const { getErrorMessageFunctions, onComponentUpdate, onBehavior, onValueChange, logEvent } = mapperProps;
5824
- const controlForLegacyFormat = getControlForLegacyFormat(format);
5825
- const errorMessageFunctions = getErrorMessageFunctions(validationMessages);
5826
- const { performValidationAsync, validationAsyncState } = getValidationAsyncInitialState(
5827
- schemaMapperProps,
5828
- mapperProps
5829
- );
5830
- const validLocalValue = isString(localValue) ? localValue : null;
5831
- const validModel = isString(model) ? model : defaultValue != null ? defaultValue : null;
5832
- const value = onPersistAsync ? validLocalValue : validModel;
5833
- return createTextInputComponent(
5834
- __spreadProps(__spreadValues({}, mapCommonSchemaProps(schemaMapperProps)), {
5835
- autocapitalization,
5836
- autoComplete: getAutocompleteString(autocompleteHint),
5837
- checks: schema.hidden ? [] : [
5838
- getRequiredCheck(required, errorMessageFunctions),
5839
- getAboveMaxLengthCheck(schema, errorMessageFunctions),
5840
- getBelowMinLengthCheck(schema, errorMessageFunctions),
5841
- getNotAdheringToPatternCheck(schema, errorMessageFunctions, { logEvent })
5842
- ],
5843
- control: control != null ? control : controlForLegacyFormat,
5844
- displayFormat,
5845
- maxLength,
5846
- minLength,
5847
- suggestions: mapStringSchemaSuggestions(suggestions, mapperProps.logEvent),
5848
- value,
5849
- validationAsyncState,
5850
- schemaOnChange: getSchemaOnChange(schema, onBehavior),
5851
- performValidationAsync,
5852
- onValueChange
5853
- }),
5854
- onComponentUpdate
5855
- );
5734
+ // src/domain/mappers/utils/groupLayoutByPinned.ts
5735
+ var groupLayoutByPinned = (layouts) => {
5736
+ return layouts.reduce(groupLayout, { pinned: [], nonPinned: [] });
5856
5737
  };
5857
- var getControlForLegacyFormat = (format) => {
5858
- if (format && ["numeric", "phone-number", "email", "password"].includes(format)) {
5859
- return format;
5738
+ var groupLayout = (acc, layout) => {
5739
+ if (layout.type === "button" && layout.pinOrder !== void 0) {
5740
+ return {
5741
+ pinned: [...acc.pinned, layout],
5742
+ nonPinned: acc.nonPinned
5743
+ };
5860
5744
  }
5861
- return void 0;
5745
+ if (hasColumns(layout)) {
5746
+ const leftChildren = groupLayoutByPinned(layout.left);
5747
+ const rightChildren = groupLayoutByPinned(layout.right);
5748
+ return {
5749
+ pinned: [...acc.pinned, ...leftChildren.pinned, ...rightChildren.pinned],
5750
+ nonPinned: [
5751
+ ...acc.nonPinned,
5752
+ __spreadProps(__spreadValues({}, layout), {
5753
+ left: leftChildren.nonPinned,
5754
+ right: rightChildren.nonPinned
5755
+ })
5756
+ ]
5757
+ };
5758
+ }
5759
+ if (hasChildren(layout)) {
5760
+ const childComponents = groupLayoutByPinned(layout.components);
5761
+ return {
5762
+ pinned: [...acc.pinned, ...childComponents.pinned],
5763
+ nonPinned: [
5764
+ ...acc.nonPinned,
5765
+ __spreadProps(__spreadValues({}, layout), {
5766
+ components: childComponents.nonPinned
5767
+ })
5768
+ ]
5769
+ };
5770
+ }
5771
+ return {
5772
+ pinned: [...acc.pinned],
5773
+ nonPinned: [...acc.nonPinned, layout]
5774
+ };
5862
5775
  };
5776
+ var hasChildren = (component) => "components" in component;
5777
+ var hasColumns = (component) => "right" in component && "left" in component;
5863
5778
 
5864
- // src/domain/mappers/schema/stringSchemaToComponent/stringSchemaToComponent.ts
5865
- var stringSchemaToComponent = (schemaMapperProps, mapperProps) => {
5866
- const { schema } = schemaMapperProps;
5867
- if (isStringSchemaWithBase64(schema)) {
5868
- return stringSchemaToUploadInputComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5779
+ // src/controller/getErrorMessage.ts
5780
+ var getErrorMessage = (error) => {
5781
+ return error instanceof Error ? error.message : typeof error === "string" ? error : `Unknown Error: type is ${typeof error}`;
5782
+ };
5783
+
5784
+ // src/controller/handleErrorResponse.ts
5785
+ var handleErrorResponse = async (response, actionId, trackEvent) => {
5786
+ const body = await parseResponseBodyAsJsonElement(response.clone());
5787
+ if (isErrorResponseBody(body)) {
5788
+ const refreshUrl = body.refreshUrl || body.refreshFormUrl;
5789
+ const { error, validation, analytics } = body;
5790
+ trackEvent("Action Failed", __spreadProps(__spreadValues({}, analytics), { actionId, statusCode: response.status }));
5791
+ const errors = { error, validation };
5792
+ return refreshUrl ? { type: "refresh", body: { refreshUrl, errors } } : {
5793
+ type: "error",
5794
+ body: { errors, analytics },
5795
+ httpError: { statusCode: response.status }
5796
+ };
5869
5797
  }
5870
- switch (schema.format) {
5871
- case "date":
5872
- return stringSchemaToDateInputComponent(schemaMapperProps, mapperProps);
5873
- default:
5874
- return stringSchemaToTextInputComponent(schemaMapperProps, mapperProps);
5798
+ trackEvent("Action Failed", { actionId, statusCode: response.status });
5799
+ const errorMessage = await parseResponseBodyAsText(response);
5800
+ return {
5801
+ type: "error",
5802
+ httpError: {
5803
+ message: errorMessage || void 0,
5804
+ statusCode: response.status
5805
+ }
5806
+ };
5807
+ };
5808
+
5809
+ // src/controller/getResponseType.ts
5810
+ var responseTypes = ["step", "action", "exit", "modal", "subflow"];
5811
+ var getResponseType = (headers, body) => {
5812
+ const headerResponseType = getResponseTypeFromHeader(headers);
5813
+ if (headerResponseType) {
5814
+ return headerResponseType;
5815
+ }
5816
+ if (isObject(body) && body.action) {
5817
+ return "action";
5875
5818
  }
5819
+ return "step";
5876
5820
  };
5877
- var isStringSchemaWithBase64 = (schema) => {
5878
- return schema.format === "base64url" && !("persistAsync" in schema);
5821
+ var getResponseTypeFromHeader = (headers) => {
5822
+ if (headers == null ? void 0 : headers.has("X-Df-Response-Type")) {
5823
+ const type = headers.get("X-Df-Response-Type");
5824
+ assertDFResponseType(type);
5825
+ return type;
5826
+ }
5827
+ if (headers == null ? void 0 : headers.has("X-Df-Exit")) {
5828
+ return "exit";
5829
+ }
5830
+ return void 0;
5879
5831
  };
5880
-
5881
- // src/domain/mappers/mapSchemaToComponent.ts
5882
- var mapSchemaToComponent = (schemaMapperProps, mapperProps) => {
5883
- const { uid, schema } = schemaMapperProps;
5884
- if (isConstSchema(schema)) {
5885
- return constSchemaToComponent(uid, __spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5832
+ function assertDFResponseType(type) {
5833
+ if (!responseTypes.includes(type)) {
5834
+ throw new Error(
5835
+ "Unsupported X-Df-Response-Type. Allowed values are 'step', 'action', 'exit', 'error', 'modal', 'subflow'."
5836
+ );
5886
5837
  }
5887
- if (isSchemaWithPersistAsync(schema)) {
5888
- return persistAsyncSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5838
+ }
5839
+
5840
+ // src/controller/makeSafeHttpClient.ts
5841
+ var makeSafeHttpClient = (httpClient) => async (...props) => {
5842
+ try {
5843
+ return await httpClient(...props);
5844
+ } catch (e) {
5845
+ return null;
5889
5846
  }
5890
- if (isAllOfSchema(schema)) {
5891
- return allOfSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5847
+ };
5848
+
5849
+ // src/controller/executeRequest.ts
5850
+ var executeRequest = async (props) => {
5851
+ const { exit, request, requestCache, httpClient, trackEvent, logEvent } = props;
5852
+ const { url, method, body } = request;
5853
+ const response = await getCachedOrFetch(
5854
+ [
5855
+ url,
5856
+ {
5857
+ method,
5858
+ body: body ? JSON.stringify(body) : void 0,
5859
+ headers: { "Content-Type": "application/json" }
5860
+ }
5861
+ ],
5862
+ requestCache,
5863
+ httpClient
5864
+ );
5865
+ if (!response) {
5866
+ const extra = { errorMessage: "Network Error" };
5867
+ trackEvent("Request Failed", extra);
5868
+ logEvent("error", "Dynamic Flow - Request Failed Unexpectedly", extra);
5869
+ return { type: "error" };
5892
5870
  }
5893
- if (isOneOfSchema(schema)) {
5894
- return oneOfSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5871
+ if (!response.ok) {
5872
+ return handleErrorResponse(response, void 0, trackEvent);
5895
5873
  }
5896
- if (isBooleanSchema(schema)) {
5897
- return booleanSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5874
+ const responseBody = await parseResponseBodyAsJsonElement(response);
5875
+ const responseType = getResponseType(response.headers, responseBody);
5876
+ if (exit) {
5877
+ return { type: "complete", result: responseBody };
5898
5878
  }
5899
- if (isObjectSchema(schema)) {
5900
- const { format } = schema;
5901
- if (format === "money") {
5902
- return objectSchemaToMoneyInputComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5879
+ switch (responseType) {
5880
+ case "step": {
5881
+ const etag = response.headers.get("etag") || null;
5882
+ assertStepResponseBody(responseBody);
5883
+ return { type: "replace-step", step: responseBody, etag };
5884
+ }
5885
+ case "exit": {
5886
+ return { type: "complete", result: responseBody };
5887
+ }
5888
+ case "action": {
5889
+ assertActionResponseBody(responseBody);
5890
+ return {
5891
+ type: "behavior",
5892
+ behavior: {
5893
+ type: "action",
5894
+ action: responseBody.action
5895
+ }
5896
+ };
5897
+ }
5898
+ case "subflow": {
5899
+ assertSubflowResponseBody(responseBody);
5900
+ return {
5901
+ type: "behavior",
5902
+ behavior: __spreadProps(__spreadValues({}, responseBody), {
5903
+ type: "subflow",
5904
+ onCompletion: responseBody.onCompletion ? normaliseBehavior(responseBody.onCompletion, []) : void 0,
5905
+ onError: responseBody.onError ? normaliseBehavior(responseBody.onError, []) : void 0
5906
+ })
5907
+ };
5908
+ }
5909
+ case "modal": {
5910
+ assertModalResponseBody(responseBody);
5911
+ return { type: "behavior", behavior: __spreadProps(__spreadValues({}, responseBody), { type: "modal" }) };
5903
5912
  }
5904
- if (format != null && Object.keys(schema.properties).length === 0) {
5905
- return objectSchemaToFormattedValueComponent(
5906
- __spreadProps(__spreadValues({}, schemaMapperProps), { schema: __spreadProps(__spreadValues({}, schema), { format }) }),
5907
- mapperProps
5908
- );
5913
+ default: {
5914
+ throw new Error(`Unsupported response type: ${String(responseType)}`);
5909
5915
  }
5910
- return objectSchemaToObjectComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5911
- }
5912
- if (isIntegerSchema(schema)) {
5913
- return integerSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5914
- }
5915
- if (isNumberSchema(schema)) {
5916
- return numberSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5917
- }
5918
- if (isStringSchema(schema)) {
5919
- return stringSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5920
5916
  }
5921
- if (isArraySchema(schema)) {
5922
- return arraySchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5923
- }
5924
- if (isBlobSchema(schema)) {
5925
- if (!schemaMapperProps.onPersistAsync) {
5926
- throw new Error(
5927
- "Blob schemas can only be used as the schema of a persist async configuration."
5928
- );
5917
+ };
5918
+ var getCachedOrFetch = async (requestParams, requestCache, httpClient) => {
5919
+ const cachedPromise = requestCache.get(requestParams);
5920
+ if (cachedPromise) {
5921
+ const cachedResponse = await cachedPromise;
5922
+ if (cachedResponse == null ? void 0 : cachedResponse.ok) {
5923
+ return cachedResponse;
5929
5924
  }
5930
- return blobSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
5931
5925
  }
5932
- throw new Error("Not yet supported");
5926
+ return makeSafeHttpClient(httpClient)(...requestParams);
5933
5927
  };
5934
5928
 
5935
- // src/domain/mappers/mapStepSchemas.ts
5936
- var mapStepSchemas = (uid, step, stepLocalValue, mapperProps, referencedSchemaIds) => {
5937
- const isReferenced = (schemaId) => schemaId != null && referencedSchemaIds.includes(schemaId);
5938
- return step.schemas.map((schema, i) => {
5929
+ // src/controller/executeSubmission.ts
5930
+ var executeSubmission = async (props) => {
5931
+ const { httpClient, requestCache, trackEvent, logEvent } = props;
5932
+ const triggerAction = async (action, model, isInitial) => {
5939
5933
  var _a, _b;
5940
- const schemaComponent = mapSchemaToComponent(
5941
- {
5942
- uid: `${uid}.schemas-${i}.${schema.$id}`,
5943
- schemaId: schema.$id,
5944
- schema,
5945
- model: (_a = step.model) != null ? _a : null,
5946
- localValue: stepLocalValue,
5947
- validationErrors: (_b = step.errors) == null ? void 0 : _b.validation,
5948
- required: true
5949
- },
5950
- mapperProps
5951
- );
5952
- return __spreadProps(__spreadValues({}, schemaComponent), {
5953
- isSchemaReferencedInStep: isReferenced(schema.$id)
5954
- });
5955
- });
5956
- };
5957
-
5958
- // src/domain/mappers/mapToolbarToComponent.ts
5959
- var mapToolbarToComponent = (uid, toolbar, mapperProps) => {
5960
- if (!toolbar) {
5961
- return void 0;
5962
- }
5963
- const { onBehavior } = mapperProps;
5964
- return __spreadProps(__spreadValues({}, toolbar), {
5965
- type: "toolbar",
5966
- uid: `${uid}.toolbar`,
5967
- tags: toolbar.tags,
5968
- items: toolbar.items.map((item) => {
5969
- const context = item.context ? mapLegacyContext(item.context) : void 0;
5970
- const behavior = getDomainLayerBehavior(
5971
- { behavior: item.behavior },
5972
- [],
5973
- mapperProps.registerSubmissionBehavior
5974
- );
5975
- return __spreadProps(__spreadValues({}, item), {
5976
- context: context ? mapLegacyContext(context) : void 0,
5977
- disabled: !!item.disabled,
5978
- tags: item.tags,
5979
- onClick: () => {
5980
- void onBehavior(behavior);
5981
- }
5934
+ const { exit, url, result = null, id: actionId } = action;
5935
+ const trackSubmissionEvent = !isInitial ? trackEvent : () => {
5936
+ };
5937
+ trackSubmissionEvent("Action Triggered", { actionId });
5938
+ if (exit && !url) {
5939
+ trackSubmissionEvent("Action Succeeded", { actionId });
5940
+ return { type: "complete", result };
5941
+ }
5942
+ try {
5943
+ const command = await executeRequest({
5944
+ exit,
5945
+ request: createRequestFromAction(action, model),
5946
+ requestCache,
5947
+ httpClient,
5948
+ trackEvent: (name, properties) => {
5949
+ trackSubmissionEvent(name, __spreadProps(__spreadValues({}, properties), { actionId }));
5950
+ },
5951
+ logEvent
5982
5952
  });
5983
- })
5953
+ switch (command.type) {
5954
+ case "error": {
5955
+ trackSubmissionEvent("Action Failed", __spreadValues({
5956
+ actionId,
5957
+ statusCode: (_a = command.httpError) == null ? void 0 : _a.statusCode
5958
+ }, (_b = command.body) == null ? void 0 : _b.analytics));
5959
+ return command;
5960
+ }
5961
+ case "behavior": {
5962
+ if (command.behavior.type === "action") {
5963
+ trackSubmissionEvent("Action Succeeded", { actionId });
5964
+ return await executeSubmission({
5965
+ action: command.behavior.action,
5966
+ isInitial: false,
5967
+ model: null,
5968
+ requestCache,
5969
+ httpClient,
5970
+ trackEvent,
5971
+ logEvent
5972
+ });
5973
+ }
5974
+ trackSubmissionEvent("Action Succeeded", { actionId });
5975
+ return command;
5976
+ }
5977
+ case "complete": {
5978
+ trackSubmissionEvent("Action Succeeded", { actionId });
5979
+ return __spreadProps(__spreadValues({}, command), { result: recursiveMerge(command.result, result) });
5980
+ }
5981
+ default: {
5982
+ trackSubmissionEvent("Action Succeeded", { actionId });
5983
+ return command;
5984
+ }
5985
+ }
5986
+ } catch (error) {
5987
+ const errorMessage = getErrorMessage(error);
5988
+ trackSubmissionEvent("Action Failed", { actionId, errorMessage });
5989
+ logEvent("error", "Dynamic Flow - Action Failed Unexpectedly", { actionId, errorMessage });
5990
+ throw error;
5991
+ }
5992
+ };
5993
+ return triggerAction(props.action, props.model, props.isInitial);
5994
+ };
5995
+ var createRequestFromAction = (action, model) => {
5996
+ var _a, _b, _c;
5997
+ return __spreadProps(__spreadValues({}, action), {
5998
+ url: (_a = action.url) != null ? _a : "",
5999
+ method: (_b = action.method) != null ? _b : "POST",
6000
+ body: action.method === "GET" ? void 0 : recursiveMerge(model, (_c = action.data) != null ? _c : null)
5984
6001
  });
5985
6002
  };
5986
6003
 
5987
- // src/domain/mappers/utils/groupLayoutByPinned.ts
5988
- var groupLayoutByPinned = (layouts) => {
5989
- return layouts.reduce(groupLayout, { pinned: [], nonPinned: [] });
6004
+ // src/domain/features/prefetch/request-cache.ts
6005
+ var makeRequestCacheWithParent = (parent) => {
6006
+ const map = /* @__PURE__ */ new Map();
6007
+ const cache = {
6008
+ get: (requestParams) => {
6009
+ var _a;
6010
+ const key = makeRequestCacheKey(requestParams);
6011
+ const promise = (_a = map.get(key)) != null ? _a : parent == null ? void 0 : parent.get(requestParams);
6012
+ map.delete(key);
6013
+ return promise;
6014
+ },
6015
+ set: (requestParams, responsePromise) => {
6016
+ return map.set(makeRequestCacheKey(requestParams), responsePromise);
6017
+ }
6018
+ };
6019
+ return cache;
5990
6020
  };
5991
- var groupLayout = (acc, layout) => {
5992
- if (layout.type === "button" && layout.pinOrder !== void 0) {
5993
- return {
5994
- pinned: [...acc.pinned, layout],
5995
- nonPinned: acc.nonPinned
5996
- };
5997
- }
5998
- if (hasColumns(layout)) {
5999
- const leftChildren = groupLayoutByPinned(layout.left);
6000
- const rightChildren = groupLayoutByPinned(layout.right);
6001
- return {
6002
- pinned: [...acc.pinned, ...leftChildren.pinned, ...rightChildren.pinned],
6003
- nonPinned: [
6004
- ...acc.nonPinned,
6005
- __spreadProps(__spreadValues({}, layout), {
6006
- left: leftChildren.nonPinned,
6007
- right: rightChildren.nonPinned
6008
- })
6009
- ]
6010
- };
6021
+ var makeRequestCache = (initialValues = []) => {
6022
+ const cache = makeRequestCacheWithParent(void 0);
6023
+ initialValues.forEach(([requestParams, responsePromise]) => {
6024
+ cache.set(requestParams, responsePromise);
6025
+ });
6026
+ return cache;
6027
+ };
6028
+ var normaliseRequestCache = (cache) => {
6029
+ if (cache === void 0) {
6030
+ return makeRequestCache();
6011
6031
  }
6012
- if (hasChildren(layout)) {
6013
- const childComponents = groupLayoutByPinned(layout.components);
6014
- return {
6015
- pinned: [...acc.pinned, ...childComponents.pinned],
6016
- nonPinned: [
6017
- ...acc.nonPinned,
6018
- __spreadProps(__spreadValues({}, layout), {
6019
- components: childComponents.nonPinned
6020
- })
6021
- ]
6022
- };
6032
+ if (isRequestCacheInstance(cache)) {
6033
+ return cache;
6023
6034
  }
6024
- return {
6025
- pinned: [...acc.pinned],
6026
- nonPinned: [...acc.nonPinned, layout]
6035
+ return makeRequestCache(cache);
6036
+ };
6037
+ var isRequestCacheInstance = (cache) => {
6038
+ return !cache || !Array.isArray(cache);
6039
+ };
6040
+ var makeRequestCacheKey = (requestParams) => {
6041
+ var _a, _b;
6042
+ const [input, init] = requestParams;
6043
+ const url = typeof input === "string" || input instanceof URL ? input.toString() : input.url;
6044
+ const key = JSON.stringify({
6045
+ url,
6046
+ method: (_a = init == null ? void 0 : init.method) != null ? _a : "GET",
6047
+ headers: (init == null ? void 0 : init.headers) ? Array.from(new Headers(init.headers).entries()) : [],
6048
+ body: (_b = init == null ? void 0 : init.body) != null ? _b : null
6049
+ });
6050
+ return key;
6051
+ };
6052
+
6053
+ // src/domain/features/prefetch/getStepPrefetch.ts
6054
+ var getStepPrefetch = (httpClient, flowRequestCache, submissionBehaviors) => {
6055
+ const requestCache = makeRequestCacheWithParent(flowRequestCache);
6056
+ const keys = /* @__PURE__ */ new Set();
6057
+ const start = (model) => {
6058
+ if (keys.size > 0) {
6059
+ return;
6060
+ }
6061
+ submissionBehaviors.forEach((behavior) => {
6062
+ const request = behavior.type === "action" ? createRequestFromAction(behavior.action, model) : behavior.launchConfig.request;
6063
+ const requestParams = [
6064
+ request.url,
6065
+ {
6066
+ body: JSON.stringify(request.body),
6067
+ method: request.method,
6068
+ headers: { "Content-Type": "application/json" }
6069
+ }
6070
+ ];
6071
+ try {
6072
+ const key = makeRequestCacheKey(requestParams);
6073
+ if (keys.has(key)) {
6074
+ return;
6075
+ }
6076
+ const responsePromise = httpClient(...requestParams).catch(() => null);
6077
+ requestCache.set(requestParams, responsePromise);
6078
+ keys.add(key);
6079
+ } catch (e) {
6080
+ }
6081
+ });
6027
6082
  };
6083
+ const stop = () => {
6084
+ };
6085
+ return { requestCache, start, stop };
6028
6086
  };
6029
- var hasChildren = (component) => "components" in component;
6030
- var hasColumns = (component) => "right" in component && "left" in component;
6031
6087
 
6032
6088
  // src/domain/mappers/mapStepToComponent.ts
6033
6089
  var mapStepToComponent = (_a) => {
@@ -6061,7 +6117,6 @@ var mapStepToComponent = (_a) => {
6061
6117
  title,
6062
6118
  tags
6063
6119
  } = step;
6064
- const requestCache = makeRequestCacheWithParent(flowRequestCache);
6065
6120
  const submissionBehaviors = [];
6066
6121
  const registerSubmissionBehavior = (behavior) => {
6067
6122
  if (behavior.type === "action" && behavior.action.prefetch) {
@@ -6085,6 +6140,7 @@ var mapStepToComponent = (_a) => {
6085
6140
  registerSubmissionBehavior
6086
6141
  }) : void 0;
6087
6142
  const stepRefreshAfter = refreshAfter ? getStepRefreshAfter({ refreshAfter, logEvent, onBehavior }) : void 0;
6143
+ const stepPrefetch = getStepPrefetch(restProps.httpClient, flowRequestCache, submissionBehaviors);
6088
6144
  const externalConfirmation = (external == null ? void 0 : external.url) ? createExternalConfirmation(`${uid}-external-confirmation`, external == null ? void 0 : external.url, onComponentUpdate) : void 0;
6089
6145
  const mapperProps = __spreadProps(__spreadValues({}, restProps), { trackEvent, onBehavior, registerSubmissionBehavior });
6090
6146
  const referencedSchemaIds = getReferencedSchemaId(step);
@@ -6121,18 +6177,12 @@ var mapStepToComponent = (_a) => {
6121
6177
  title,
6122
6178
  tags,
6123
6179
  stackBehavior: (_a2 = navigation == null ? void 0 : navigation.stackBehavior) != null ? _a2 : "default",
6124
- requestCache,
6180
+ stepPrefetch,
6125
6181
  step,
6126
6182
  onComponentUpdate,
6127
6183
  trackEvent,
6128
6184
  onBehavior
6129
6185
  });
6130
- executePrefetch({
6131
- httpClient: mapperProps.httpClient,
6132
- model: stepComponent.getSubmittableValueSync(),
6133
- behaviors: submissionBehaviors,
6134
- requestCache
6135
- });
6136
6186
  return stepComponent;
6137
6187
  };
6138
6188
  var getReferencedSchemaId = (step) => {
@@ -6153,25 +6203,6 @@ var mapBackNavigation = (navigation, onBehavior, isNativeBackEnabled) => {
6153
6203
  }
6154
6204
  } : void 0;
6155
6205
  };
6156
- var executePrefetch = (props) => {
6157
- const { httpClient, behaviors: submissionBehaviors, model, requestCache } = props;
6158
- submissionBehaviors.forEach((behavior) => {
6159
- const request = behavior.type === "action" ? createRequestFromAction(behavior.action, model) : behavior.launchConfig.request;
6160
- const requestParams = [
6161
- request.url,
6162
- {
6163
- body: JSON.stringify(request.body),
6164
- method: request.method,
6165
- headers: { "Content-Type": "application/json" }
6166
- }
6167
- ];
6168
- try {
6169
- const responsePromise = httpClient(...requestParams).catch(() => null);
6170
- requestCache.set(requestParams, responsePromise);
6171
- } catch (e) {
6172
- }
6173
- });
6174
- };
6175
6206
  var getLayoutAndFooter = (step, features) => {
6176
6207
  var _a;
6177
6208
  if (step.footer) {
@@ -6777,21 +6808,24 @@ var createFlowController = (props) => {
6777
6808
  return false;
6778
6809
  }
6779
6810
  };
6780
- let isInitialised = false;
6811
+ let initState = "initial";
6781
6812
  if (initialStep) {
6782
- isInitialised = true;
6813
+ initState = "created";
6783
6814
  trackEvent("Initiated");
6784
6815
  createStep(initialStep, null);
6785
6816
  trackEvent("Step Shown", { isFirstStep: true });
6786
6817
  }
6787
6818
  const start = () => {
6788
- if (!isInitialised && initialAction) {
6789
- isInitialised = true;
6819
+ if (initState === "initial" && initialAction) {
6820
+ initState = "created";
6790
6821
  trackEvent("Initiated");
6791
6822
  rootComponent.setLoadingState("submitting");
6792
6823
  void onAction(__spreadValues({ method: "GET" }, initialAction), null);
6793
6824
  }
6794
- rootComponent.start();
6825
+ if (initState === "created") {
6826
+ initState = "started";
6827
+ rootComponent.start();
6828
+ }
6795
6829
  };
6796
6830
  return {
6797
6831
  rootComponent,