@adapty/capacitor 3.17.1 → 4.0.0-beta.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.
Files changed (75) hide show
  1. package/Package.swift +1 -1
  2. package/README.md +8 -0
  3. package/android/build.gradle +2 -2
  4. package/dist/esm/adapty-instance.d.ts +7 -0
  5. package/dist/esm/adapty-instance.js +8 -0
  6. package/dist/esm/adapty-instance.js.map +1 -0
  7. package/dist/esm/adapty.d.ts +112 -59
  8. package/dist/esm/adapty.js +132 -69
  9. package/dist/esm/adapty.js.map +1 -1
  10. package/dist/esm/coders/parse-flow.d.ts +3 -0
  11. package/dist/esm/coders/parse-flow.js +4 -0
  12. package/dist/esm/coders/parse-flow.js.map +1 -0
  13. package/dist/esm/default-configs.js +2 -2
  14. package/dist/esm/default-configs.js.map +1 -1
  15. package/dist/esm/index.d.ts +4 -4
  16. package/dist/esm/index.js +3 -3
  17. package/dist/esm/index.js.map +1 -1
  18. package/dist/esm/types/adapty-plugin.d.ts +31 -17
  19. package/dist/esm/types/adapty-plugin.js.map +1 -1
  20. package/dist/esm/types/configs.d.ts +12 -14
  21. package/dist/esm/types/configs.js.map +1 -1
  22. package/dist/esm/types/flow-events.d.ts +1 -0
  23. package/dist/esm/types/flow-events.js +2 -0
  24. package/dist/esm/types/flow-events.js.map +1 -0
  25. package/dist/esm/types/index.d.ts +2 -2
  26. package/dist/esm/types/index.js +1 -1
  27. package/dist/esm/types/index.js.map +1 -1
  28. package/dist/esm/types/inputs.d.ts +1 -1
  29. package/dist/esm/types/inputs.js.map +1 -1
  30. package/dist/esm/ui-builder/base-view-emitter.d.ts +6 -0
  31. package/dist/esm/ui-builder/base-view-emitter.js +12 -0
  32. package/dist/esm/ui-builder/base-view-emitter.js.map +1 -1
  33. package/dist/esm/ui-builder/create-flow-view.d.ts +14 -0
  34. package/dist/esm/ui-builder/create-flow-view.js +16 -0
  35. package/dist/esm/ui-builder/create-flow-view.js.map +1 -0
  36. package/dist/esm/ui-builder/create-onboarding-view.d.ts +2 -0
  37. package/dist/esm/ui-builder/create-onboarding-view.js +2 -0
  38. package/dist/esm/ui-builder/create-onboarding-view.js.map +1 -1
  39. package/dist/esm/ui-builder/{paywall-view-controller.d.ts → flow-view-controller.d.ts} +37 -37
  40. package/dist/esm/ui-builder/{paywall-view-controller.js → flow-view-controller.js} +54 -51
  41. package/dist/esm/ui-builder/flow-view-controller.js.map +1 -0
  42. package/dist/esm/ui-builder/flow-view-emitter.d.ts +38 -0
  43. package/dist/esm/ui-builder/flow-view-emitter.js +151 -0
  44. package/dist/esm/ui-builder/flow-view-emitter.js.map +1 -0
  45. package/dist/esm/ui-builder/index.d.ts +5 -5
  46. package/dist/esm/ui-builder/index.js +3 -2
  47. package/dist/esm/ui-builder/index.js.map +1 -1
  48. package/dist/esm/ui-builder/onboarding-view-controller.d.ts +7 -5
  49. package/dist/esm/ui-builder/onboarding-view-controller.js +7 -5
  50. package/dist/esm/ui-builder/onboarding-view-controller.js.map +1 -1
  51. package/dist/esm/ui-builder/types.d.ts +11 -358
  52. package/dist/esm/ui-builder/types.js +52 -22
  53. package/dist/esm/ui-builder/types.js.map +1 -1
  54. package/dist/esm/version.d.ts +1 -1
  55. package/dist/esm/version.js +1 -1
  56. package/dist/esm/version.js.map +1 -1
  57. package/dist/plugin.cjs.js +903 -679
  58. package/dist/plugin.cjs.js.map +1 -1
  59. package/dist/plugin.js +903 -679
  60. package/dist/plugin.js.map +1 -1
  61. package/package.json +3 -5
  62. package/AdaptyCapacitor.podspec +0 -20
  63. package/dist/esm/coders/parse-paywall.d.ts +0 -3
  64. package/dist/esm/coders/parse-paywall.js +0 -4
  65. package/dist/esm/coders/parse-paywall.js.map +0 -1
  66. package/dist/esm/types/paywall-events.d.ts +0 -1
  67. package/dist/esm/types/paywall-events.js +0 -2
  68. package/dist/esm/types/paywall-events.js.map +0 -1
  69. package/dist/esm/ui-builder/create-paywall-view.d.ts +0 -25
  70. package/dist/esm/ui-builder/create-paywall-view.js +0 -29
  71. package/dist/esm/ui-builder/create-paywall-view.js.map +0 -1
  72. package/dist/esm/ui-builder/paywall-view-controller.js.map +0 -1
  73. package/dist/esm/ui-builder/paywall-view-emitter.d.ts +0 -16
  74. package/dist/esm/ui-builder/paywall-view-emitter.js +0 -114
  75. package/dist/esm/ui-builder/paywall-view-emitter.js.map +0 -1
@@ -2,49 +2,52 @@ import { AdaptyError } from '@adapty/core';
2
2
  import { coderFactory } from '../coders/factory';
3
3
  import { LogContext, Log } from '../logger';
4
4
  import { mapValues, withErrorContext } from '../utils';
5
- import { PaywallViewEmitter } from './paywall-view-emitter';
6
- import { DEFAULT_EVENT_HANDLERS } from './types';
5
+ import { FlowViewEmitter } from './flow-view-emitter';
6
+ import { DEFAULT_FLOW_EVENT_HANDLERS } from './types';
7
7
  const DEFAULT_PARAMS = {
8
8
  prefetchProducts: true,
9
9
  loadTimeoutMs: 5000,
10
+ android: {
11
+ enableSafeArea: true,
12
+ },
10
13
  };
11
14
  /**
12
- * Controller for managing paywall views.
15
+ * Controller for managing flow views.
13
16
  *
14
17
  * @remarks
15
- * This class provides methods to present, dismiss, and handle events for paywall views
16
- * created with the Paywall Builder. Create instances using the {@link createPaywallView} function
18
+ * This class provides methods to present, dismiss, and handle events for flow views
19
+ * created with the Flow Builder. Create instances using the {@link createFlowView} function
17
20
  * rather than directly constructing this class.
18
21
  *
19
22
  * @public
20
23
  */
21
- export class PaywallViewController {
24
+ export class FlowViewController {
22
25
  /**
23
26
  * Intended way to create a ViewController instance.
24
27
  * It prepares a native controller to be presented
25
28
  * and creates reference between native controller and JS instance
26
29
  * @internal
27
30
  */
28
- static async create(paywall, params, adaptyPlugin) {
29
- const controller = new PaywallViewController(adaptyPlugin);
31
+ static async create(flow, params, adaptyPlugin) {
32
+ const controller = new FlowViewController(adaptyPlugin);
30
33
  const ctx = new LogContext();
31
- const methodKey = 'adapty_ui_create_paywall_view';
34
+ const methodKey = 'adapty_ui_create_flow_view';
32
35
  const log = ctx.call({ methodName: methodKey });
33
- log.start(() => ({ paywall, params }));
34
- const paywallCoder = coderFactory.createPaywallCoder();
35
- const paramsCoder = coderFactory.createUiCreatePaywallViewParamsCoder();
36
+ log.start(() => ({ flow, params }));
37
+ const flowCoder = coderFactory.createFlowCoder();
38
+ const paramsCoder = coderFactory.createUiCreateFlowViewParamsCoder();
36
39
  const paramsWithDefaults = Object.assign(Object.assign({}, DEFAULT_PARAMS), params);
37
- const data = Object.assign({ method: methodKey, paywall: paywallCoder.encode(paywall) }, paramsCoder.encode(paramsWithDefaults));
40
+ const data = Object.assign({ method: methodKey, flow: flowCoder.encode(flow) }, paramsCoder.encode(paramsWithDefaults));
38
41
  const result = (await controller.adaptyPlugin.handleMethodCall(methodKey, JSON.stringify(data), ctx, log));
39
42
  controller.id = result.id;
40
- controller.viewEmitter = new PaywallViewEmitter(controller.id);
41
- await controller.setEventHandlers(DEFAULT_EVENT_HANDLERS);
43
+ controller.viewEmitter = new FlowViewEmitter(controller.id, controller.adaptyPlugin);
44
+ await controller.setEventHandlers(DEFAULT_FLOW_EVENT_HANDLERS);
42
45
  return controller;
43
46
  }
44
47
  /**
45
48
  * Since constructors in JS cannot be async, it is not
46
49
  * preferred to create ViewControllers in direct way.
47
- * Consider using @link{ViewController.create} instead
50
+ * Consider using {@link FlowViewController.create} instead
48
51
  *
49
52
  * @internal
50
53
  */
@@ -56,31 +59,31 @@ export class PaywallViewController {
56
59
  await this.dismiss();
57
60
  }
58
61
  catch (error) {
59
- Log.warn('setEventHandlers', () => 'Failed to dismiss paywall', () => ({ error }));
62
+ Log.warn('setEventHandlers', () => 'Failed to dismiss flow', () => ({ error }));
60
63
  }
61
64
  };
62
65
  this.adaptyPlugin = adaptyPlugin;
63
66
  }
64
67
  /**
65
- * Presents the paywall view as a modal screen.
68
+ * Presents the flow view as a modal screen.
66
69
  *
67
70
  * @remarks
68
- * Calling `present` on an already visible paywall view will result in an error.
69
- * The paywall will be displayed with the configured presentation style on iOS.
70
- * On Android, the paywall is always presented as a full-screen activity.
71
+ * Calling `present` on an already visible flow view will result in an error.
72
+ * The flow will be displayed with the configured presentation style on iOS.
73
+ * On Android, the flow is always presented as a full-screen activity.
71
74
  *
72
75
  * @param options - Optional presentation options
73
76
  * @param options.iosPresentationStyle - iOS presentation style. Available options: `'full_screen'` (default) or `'page_sheet'`. Only affects iOS platform.
74
- * @returns A promise that resolves when the paywall is presented.
77
+ * @returns A promise that resolves when the flow is presented.
75
78
  * @throws {@link AdaptyError} if the view reference is invalid or the view is already presented.
76
79
  *
77
80
  * @example
78
81
  * Present with default full-screen style
79
82
  * ```typescript
80
- * import { adapty, createPaywallView } from '@adapty/capacitor';
83
+ * import { adapty, createFlowView } from '@adapty/capacitor';
81
84
  *
82
- * const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID' });
83
- * const view = await createPaywallView(paywall);
85
+ * const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' });
86
+ * const view = await createFlowView(flow);
84
87
  * await view.present();
85
88
  * ```
86
89
  *
@@ -93,7 +96,7 @@ export class PaywallViewController {
93
96
  async present(options = {}) {
94
97
  var _a;
95
98
  const ctx = new LogContext();
96
- const methodKey = 'adapty_ui_present_paywall_view';
99
+ const methodKey = 'adapty_ui_present_flow_view';
97
100
  const log = ctx.call({ methodName: methodKey });
98
101
  log.start(() => ({ _id: this.id, iosPresentationStyle: options.iosPresentationStyle }));
99
102
  if (this.id === null) {
@@ -110,20 +113,20 @@ export class PaywallViewController {
110
113
  await this.adaptyPlugin.handleMethodCall(methodKey, JSON.stringify(data), ctx, log);
111
114
  }
112
115
  /**
113
- * Dismisses the paywall view.
116
+ * Dismisses the flow view.
114
117
  *
115
118
  * @remarks
116
- * This method closes the paywall and cleans up associated resources.
119
+ * This method closes the flow and cleans up associated resources.
117
120
  * After dismissing, the view controller instance cannot be reused.
118
121
  *
119
- * @returns A promise that resolves when the paywall is dismissed.
122
+ * @returns A promise that resolves when the flow is dismissed.
120
123
  * @throws {@link AdaptyError} if the view reference is invalid.
121
124
  *
122
125
  * @example
123
126
  * ```typescript
124
- * import { createPaywallView } from '@adapty/capacitor';
127
+ * import { createFlowView } from '@adapty/capacitor';
125
128
  *
126
- * const view = await createPaywallView(paywall);
129
+ * const view = await createFlowView(flow);
127
130
  * await view.present();
128
131
  * // ... later
129
132
  * await view.dismiss();
@@ -131,7 +134,7 @@ export class PaywallViewController {
131
134
  */
132
135
  async dismiss() {
133
136
  const ctx = new LogContext();
134
- const methodKey = 'adapty_ui_dismiss_paywall_view';
137
+ const methodKey = 'adapty_ui_dismiss_flow_view';
135
138
  const log = ctx.call({ methodName: methodKey });
136
139
  log.start(() => ({ _id: this.id }));
137
140
  if (this.id === null) {
@@ -152,7 +155,7 @@ export class PaywallViewController {
152
155
  * Displays a dialog to the user.
153
156
  *
154
157
  * @remarks
155
- * Use this method to show custom dialogs within the paywall flow.
158
+ * Use this method to show custom dialogs within the flow.
156
159
  * If you provide two actions in the config, the primary action should cancel the operation
157
160
  * and leave things unchanged, while the secondary action should confirm the operation.
158
161
  *
@@ -204,20 +207,20 @@ export class PaywallViewController {
204
207
  return await this.adaptyPlugin.handleMethodCall(methodKey, JSON.stringify(data), ctx, log);
205
208
  }
206
209
  /**
207
- * Registers event handlers for paywall UI events.
210
+ * Registers event handlers for flow UI events.
208
211
  *
209
212
  * @remarks
210
213
  * Each event type can have only one handler — new handlers replace existing ones.
211
- * Default handlers are registered automatically in {@link createPaywallView} and provide standard closing behavior:
212
- * - `onCloseButtonPress` - closes the paywall
213
- * - `onAndroidSystemBack` - closes the paywall (Android only)
214
- * - `onRestoreCompleted` - closes the paywall after successful restore
215
- * - `onRenderingFailed` - closes the paywall when rendering fails
216
- * - `onPurchaseCompleted` - closes the paywall after successful purchase
214
+ * Default handlers are registered automatically in {@link createFlowView} (see `DEFAULT_FLOW_EVENT_HANDLERS`).
215
+ * Only two defaults close the view; all others keep it open:
216
+ * - `onCloseButtonPress` - closes the view (returns `true`)
217
+ * - `onError` - closes the view (returns `true`)
218
+ * - all other handlers keep the view open by default (return `false`),
219
+ * including `onAndroidSystemBack`, `onRestoreCompleted`, and `onPurchaseCompleted`
217
220
  *
218
- * If you want to override these listeners, we strongly recommend returning `true`
219
- * (or `purchaseResult.type !== 'user_cancelled'` in case of `onPurchaseCompleted`)
220
- * from your custom listener to retain default closing behavior.
221
+ * Returning `true` from a handler closes the view; returning `false` keeps it open.
222
+ * To retain default behavior in a custom listener, return the same value as the default
223
+ * implementation (only `onCloseButtonPress` and `onError` close the view by default).
221
224
  *
222
225
  * Calling this method multiple times will replace previously registered handlers for provided events.
223
226
  *
@@ -229,9 +232,9 @@ export class PaywallViewController {
229
232
  * @example
230
233
  * Register custom event handlers
231
234
  * ```typescript
232
- * import { createPaywallView } from '@adapty/capacitor';
235
+ * import { createFlowView } from '@adapty/capacitor';
233
236
  *
234
- * const view = await createPaywallView(paywall);
237
+ * const view = await createFlowView(flow);
235
238
  *
236
239
  * const unsubscribe = await view.setEventHandlers({
237
240
  * onPurchaseStarted: (product) => {
@@ -239,7 +242,7 @@ export class PaywallViewController {
239
242
  * },
240
243
  * onPurchaseCompleted: (result) => {
241
244
  * console.log('Purchase completed:', result.type);
242
- * // Return true to keep default closing behavior
245
+ * // Return true to close the view after purchase (default keeps it open)
243
246
  * return result.type !== 'user_cancelled';
244
247
  * },
245
248
  * onPurchaseFailed: (error) => {
@@ -265,13 +268,13 @@ export class PaywallViewController {
265
268
  });
266
269
  }
267
270
  Log.verbose('setEventHandlers', () => 'Registering event handlers for view', () => ({ id: this.id }));
268
- const viewEmitter = (_a = this.viewEmitter) !== null && _a !== void 0 ? _a : new PaywallViewEmitter(this.id);
271
+ const viewEmitter = (_a = this.viewEmitter) !== null && _a !== void 0 ? _a : new FlowViewEmitter(this.id, this.adaptyPlugin);
269
272
  this.viewEmitter = viewEmitter;
270
273
  const wrappedErrorLogEventHandlers = mapValues(eventHandlers, (handler, eventName) => handler && typeof handler === 'function'
271
- ? withErrorContext(handler, eventName, 'PaywallViewController')
274
+ ? withErrorContext(handler, eventName, 'FlowViewController')
272
275
  : undefined);
273
276
  // Merge with defaults to ensure default behavior is preserved after unsubscribe/resubscribe cycles
274
- const finalEventHandlers = Object.assign(Object.assign({}, DEFAULT_EVENT_HANDLERS), wrappedErrorLogEventHandlers);
277
+ const finalEventHandlers = Object.assign(Object.assign({}, DEFAULT_FLOW_EVENT_HANDLERS), wrappedErrorLogEventHandlers);
275
278
  for (const [eventName, handler] of Object.entries(finalEventHandlers)) {
276
279
  if (handler && typeof handler === 'function') {
277
280
  try {
@@ -305,7 +308,7 @@ export class PaywallViewController {
305
308
  *
306
309
  * @example
307
310
  * ```typescript
308
- * const view = await createPaywallView(paywall);
311
+ * const view = await createFlowView(flow);
309
312
  * await view.setEventHandlers({ onPurchaseCompleted: handlePurchase });
310
313
  *
311
314
  * // Later, clear all handlers
@@ -320,4 +323,4 @@ export class PaywallViewController {
320
323
  }
321
324
  }
322
325
  }
323
- //# sourceMappingURL=paywall-view-controller.js.map
326
+ //# sourceMappingURL=flow-view-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-view-controller.js","sourceRoot":"","sources":["../../../src/ui-builder/flow-view-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { AdaptyError } from '@adapty/core';\n\nimport type { Adapty } from '../adapty';\nimport { coderFactory } from '../coders/factory';\nimport { LogContext, Log } from '../logger';\nimport type { AdaptyFlow } from '../types';\nimport type { components } from '../types/api';\nimport { mapValues, withErrorContext } from '../utils';\n\nimport { FlowViewEmitter } from './flow-view-emitter';\nimport type {\n AdaptyUiView,\n CreateFlowViewParamsInput,\n AdaptyUiDialogConfig,\n AdaptyUiDialogActionType,\n FlowEventHandlers,\n AdaptyIOSPresentationStyle,\n} from './types';\nimport { DEFAULT_FLOW_EVENT_HANDLERS } from './types';\n\ntype Req = components['requests'];\n\nconst DEFAULT_PARAMS: CreateFlowViewParamsInput = {\n prefetchProducts: true,\n loadTimeoutMs: 5000,\n android: {\n enableSafeArea: true,\n },\n};\n\n/**\n * Controller for managing flow views.\n *\n * @remarks\n * This class provides methods to present, dismiss, and handle events for flow views\n * created with the Flow Builder. Create instances using the {@link createFlowView} function\n * rather than directly constructing this class.\n *\n * @public\n */\nexport class FlowViewController {\n private id: string | null = null;\n private adaptyPlugin: Adapty;\n private viewEmitter: FlowViewEmitter | null = null;\n\n /**\n * Intended way to create a ViewController instance.\n * It prepares a native controller to be presented\n * and creates reference between native controller and JS instance\n * @internal\n */\n static async create(\n flow: AdaptyFlow,\n params: CreateFlowViewParamsInput,\n adaptyPlugin: Adapty,\n ): Promise<FlowViewController> {\n const controller = new FlowViewController(adaptyPlugin);\n\n const ctx = new LogContext();\n const methodKey = 'adapty_ui_create_flow_view';\n const log = ctx.call({ methodName: methodKey });\n log.start(() => ({ flow, params }));\n\n const flowCoder = coderFactory.createFlowCoder();\n const paramsCoder = coderFactory.createUiCreateFlowViewParamsCoder();\n const paramsWithDefaults: CreateFlowViewParamsInput = {\n ...DEFAULT_PARAMS,\n ...params,\n };\n\n const data: Req['AdaptyUICreateFlowView.Request'] = {\n method: methodKey,\n flow: flowCoder.encode(flow),\n ...paramsCoder.encode(paramsWithDefaults),\n };\n\n const result = (await controller.adaptyPlugin.handleMethodCall(\n methodKey,\n JSON.stringify(data),\n ctx,\n log,\n )) as AdaptyUiView;\n controller.id = result.id;\n controller.viewEmitter = new FlowViewEmitter(controller.id, controller.adaptyPlugin);\n\n await controller.setEventHandlers(DEFAULT_FLOW_EVENT_HANDLERS);\n\n return controller;\n }\n\n /**\n * Since constructors in JS cannot be async, it is not\n * preferred to create ViewControllers in direct way.\n * Consider using {@link FlowViewController.create} instead\n *\n * @internal\n */\n private constructor(adaptyPlugin: Adapty) {\n this.adaptyPlugin = adaptyPlugin;\n }\n\n /**\n * Presents the flow view as a modal screen.\n *\n * @remarks\n * Calling `present` on an already visible flow view will result in an error.\n * The flow will be displayed with the configured presentation style on iOS.\n * On Android, the flow is always presented as a full-screen activity.\n *\n * @param options - Optional presentation options\n * @param options.iosPresentationStyle - iOS presentation style. Available options: `'full_screen'` (default) or `'page_sheet'`. Only affects iOS platform.\n * @returns A promise that resolves when the flow is presented.\n * @throws {@link AdaptyError} if the view reference is invalid or the view is already presented.\n *\n * @example\n * Present with default full-screen style\n * ```typescript\n * import { adapty, createFlowView } from '@adapty/capacitor';\n *\n * const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' });\n * const view = await createFlowView(flow);\n * await view.present();\n * ```\n *\n * @example\n * Present with page sheet style on iOS\n * ```typescript\n * await view.present({ iosPresentationStyle: 'page_sheet' });\n * ```\n */\n public async present(options: { iosPresentationStyle?: AdaptyIOSPresentationStyle } = {}): Promise<void> {\n const ctx = new LogContext();\n const methodKey = 'adapty_ui_present_flow_view';\n const log = ctx.call({ methodName: methodKey });\n log.start(() => ({ _id: this.id, iosPresentationStyle: options.iosPresentationStyle }));\n\n if (this.id === null) {\n throw new AdaptyError({\n adaptyCode: 2002,\n message: 'No view reference',\n });\n }\n\n const data: Req['AdaptyUIPresentFlowView.Request'] = {\n method: methodKey,\n id: this.id,\n ios_presentation_style: options.iosPresentationStyle ?? 'full_screen',\n };\n\n await this.adaptyPlugin.handleMethodCall(methodKey, JSON.stringify(data), ctx, log);\n }\n\n /**\n * Dismisses the flow view.\n *\n * @remarks\n * This method closes the flow and cleans up associated resources.\n * After dismissing, the view controller instance cannot be reused.\n *\n * @returns A promise that resolves when the flow is dismissed.\n * @throws {@link AdaptyError} if the view reference is invalid.\n *\n * @example\n * ```typescript\n * import { createFlowView } from '@adapty/capacitor';\n *\n * const view = await createFlowView(flow);\n * await view.present();\n * // ... later\n * await view.dismiss();\n * ```\n */\n public async dismiss(): Promise<void> {\n const ctx = new LogContext();\n const methodKey = 'adapty_ui_dismiss_flow_view';\n const log = ctx.call({ methodName: methodKey });\n log.start(() => ({ _id: this.id }));\n\n if (this.id === null) {\n throw new AdaptyError({\n adaptyCode: 2002,\n message: 'No view reference',\n });\n }\n\n const data: Req['AdaptyUIDismissFlowView.Request'] = {\n method: methodKey,\n id: this.id,\n destroy: true,\n };\n\n await this.adaptyPlugin.handleMethodCall(methodKey, JSON.stringify(data), ctx, log);\n this.clearEventHandlers();\n }\n\n /**\n * Displays a dialog to the user.\n *\n * @remarks\n * Use this method to show custom dialogs within the flow.\n * If you provide two actions in the config, the primary action should cancel the operation\n * and leave things unchanged, while the secondary action should confirm the operation.\n *\n * @param config - Configuration for the dialog.\n * @param config.title - The dialog title.\n * @param config.content - The dialog message content.\n * @param config.primaryActionTitle - The title for the primary (default) action button.\n * @param config.secondaryActionTitle - Optional. The title for the secondary action button.\n * @returns A promise that resolves to the action type that the user selected: `'primary'` or `'secondary'`.\n * @throws {@link AdaptyError} if the view reference is invalid.\n *\n * @example\n * Show confirmation dialog\n * ```typescript\n * const action = await view.showDialog({\n * title: 'Confirm Purchase',\n * content: 'Are you sure you want to proceed with this purchase?',\n * primaryActionTitle: 'Cancel',\n * secondaryActionTitle: 'Continue'\n * });\n *\n * if (action === 'secondary') {\n * console.log('User confirmed');\n * }\n * ```\n */\n public async showDialog(config: AdaptyUiDialogConfig): Promise<AdaptyUiDialogActionType> {\n const ctx = new LogContext();\n const methodKey = 'adapty_ui_show_dialog';\n const log = ctx.call({ methodName: methodKey });\n log.start(() => ({ _id: this.id }));\n\n if (this.id === null) {\n throw new AdaptyError({\n adaptyCode: 2002,\n message: 'No view reference',\n });\n }\n\n const dialogConfig = {\n default_action_title: config.primaryActionTitle,\n secondary_action_title: config.secondaryActionTitle,\n title: config.title,\n content: config.content,\n };\n\n const data: Req['AdaptyUIShowDialog.Request'] = {\n method: methodKey,\n id: this.id,\n configuration: dialogConfig,\n };\n\n return await this.adaptyPlugin.handleMethodCall(methodKey, JSON.stringify(data), ctx, log);\n }\n\n private onRequestClose = async () => {\n try {\n await this.dismiss();\n } catch (error) {\n Log.warn(\n 'setEventHandlers',\n () => 'Failed to dismiss flow',\n () => ({ error }),\n );\n }\n };\n\n /**\n * Registers event handlers for flow UI events.\n *\n * @remarks\n * Each event type can have only one handler — new handlers replace existing ones.\n * Default handlers are registered automatically in {@link createFlowView} (see `DEFAULT_FLOW_EVENT_HANDLERS`).\n * Only two defaults close the view; all others keep it open:\n * - `onCloseButtonPress` - closes the view (returns `true`)\n * - `onError` - closes the view (returns `true`)\n * - all other handlers keep the view open by default (return `false`),\n * including `onAndroidSystemBack`, `onRestoreCompleted`, and `onPurchaseCompleted`\n *\n * Returning `true` from a handler closes the view; returning `false` keeps it open.\n * To retain default behavior in a custom listener, return the same value as the default\n * implementation (only `onCloseButtonPress` and `onError` close the view by default).\n *\n * Calling this method multiple times will replace previously registered handlers for provided events.\n *\n * @see {@link https://adapty.io/docs/capacitor-handling-events | Handling View Events}\n *\n * @param eventHandlers - Set of event handling callbacks. Only provided handlers will be registered or updated.\n * @returns A promise that resolves to an unsubscribe function that removes all registered listeners.\n *\n * @example\n * Register custom event handlers\n * ```typescript\n * import { createFlowView } from '@adapty/capacitor';\n *\n * const view = await createFlowView(flow);\n *\n * const unsubscribe = await view.setEventHandlers({\n * onPurchaseStarted: (product) => {\n * console.log('Purchase started:', product.vendorProductId);\n * },\n * onPurchaseCompleted: (result) => {\n * console.log('Purchase completed:', result.type);\n * // Return true to close the view after purchase (default keeps it open)\n * return result.type !== 'user_cancelled';\n * },\n * onPurchaseFailed: (error) => {\n * console.error('Purchase failed:', error);\n * }\n * });\n *\n * await view.present();\n *\n * // Later, unsubscribe all handlers\n * unsubscribe();\n * ```\n */\n public async setEventHandlers(eventHandlers: Partial<FlowEventHandlers> = {}): Promise<() => void> {\n const ctx = new LogContext();\n const log = ctx.call({ methodName: 'setEventHandlers' });\n log.start(() => ({ _id: this.id }));\n\n if (this.id === null) {\n throw new AdaptyError({\n adaptyCode: 2002,\n message: 'No view reference',\n });\n }\n\n Log.verbose(\n 'setEventHandlers',\n () => 'Registering event handlers for view',\n () => ({ id: this.id }),\n );\n\n const viewEmitter = this.viewEmitter ?? new FlowViewEmitter(this.id, this.adaptyPlugin);\n this.viewEmitter = viewEmitter;\n\n const wrappedErrorLogEventHandlers = mapValues(eventHandlers, (handler, eventName) =>\n handler && typeof handler === 'function'\n ? withErrorContext(handler, eventName as string, 'FlowViewController')\n : undefined,\n );\n\n // Merge with defaults to ensure default behavior is preserved after unsubscribe/resubscribe cycles\n const finalEventHandlers: FlowEventHandlers = {\n ...DEFAULT_FLOW_EVENT_HANDLERS,\n ...wrappedErrorLogEventHandlers,\n };\n\n for (const [eventName, handler] of Object.entries(finalEventHandlers)) {\n if (handler && typeof handler === 'function') {\n try {\n await viewEmitter.addListener(eventName as keyof FlowEventHandlers, handler, this.onRequestClose);\n Log.verbose(\n 'setEventHandlers',\n () => 'Registered handler for',\n () => ({ eventName }),\n );\n } catch (error) {\n Log.error(\n 'setEventHandlers',\n () => `Failed to register handler for ${eventName}`,\n () => ({ error }),\n );\n }\n }\n }\n\n // Return unsubscribe function\n const unsubscribe = () => {\n Log.info(\n 'setEventHandlers',\n () => 'Unsubscribing event handlers for view',\n () => ({ id: this.id }),\n );\n if (this.viewEmitter) {\n this.viewEmitter.removeAllListeners();\n this.viewEmitter = null;\n }\n };\n\n return unsubscribe;\n }\n\n /**\n * Clears all registered event handlers.\n *\n * @remarks\n * This method removes all previously registered event handlers.\n * After calling this method, no event handlers will be active\n * until you call {@link setEventHandlers} again.\n *\n * Use this after dismiss to remove all event handlers\n *\n * @example\n * ```typescript\n * const view = await createFlowView(flow);\n * await view.setEventHandlers({ onPurchaseCompleted: handlePurchase });\n *\n * // Later, clear all handlers\n * view.clearEventHandlers();\n * ```\n */\n public clearEventHandlers(): void {\n Log.info(\n 'clearEventHandlers',\n () => 'Clearing all event handlers for view',\n () => ({ id: this.id }),\n );\n\n if (this.viewEmitter) {\n this.viewEmitter.removeAllListeners();\n this.viewEmitter = null;\n }\n }\n}\n"]}
@@ -0,0 +1,38 @@
1
+ import type { FlowEventIdType, ParsedFlowEvent } from '@adapty/core';
2
+ import type { Adapty } from '../adapty';
3
+ import { LogContext } from '../logger';
4
+ import { BaseViewEmitter } from './base-view-emitter';
5
+ import type { FlowEventHandlers } from './types';
6
+ /**
7
+ * FlowViewEmitter manages event handlers for flow view events.
8
+ * Each event type can have only one handler - new handlers replace existing ones.
9
+ *
10
+ * In addition to the standard synchronous dispatch inherited from
11
+ * {@link BaseViewEmitter}, this emitter handles three asynchronous round-trip
12
+ * events that must reply back to native:
13
+ * - `onRequestPermission` — awaits the async handler, then replies with the status.
14
+ * - `onObserverPurchaseInitiated` — injects start/finish callbacks (observer mode).
15
+ * - `onObserverRestoreInitiated` — injects start/finish callbacks (observer mode).
16
+ */
17
+ export declare class FlowViewEmitter extends BaseViewEmitter<FlowEventHandlers, ParsedFlowEvent, FlowEventIdType> {
18
+ private adapty;
19
+ constructor(viewId: string, adapty: Adapty);
20
+ protected parseEventData(rawEventData: string, ctx: LogContext): ParsedFlowEvent;
21
+ protected getNativeEventForHandler(event: keyof FlowEventHandlers): FlowEventIdType | null;
22
+ protected getHandlerForNativeEvent(nativeEvent: FlowEventIdType, eventData: ParsedFlowEvent): keyof FlowEventHandlers | null;
23
+ protected extractCallbackArgs(handlerName: keyof FlowEventHandlers, eventData: ParsedFlowEvent): unknown[];
24
+ protected getEventViewId(eventData: ParsedFlowEvent): string | null;
25
+ protected getEmitterName(): string;
26
+ /**
27
+ * Routes the three asynchronous round-trip events to their dedicated
28
+ * handlers, bypassing the standard synchronous boolean/close dispatch.
29
+ */
30
+ protected handleSpecialEvent(handlerName: keyof FlowEventHandlers, eventData: ParsedFlowEvent): boolean;
31
+ /**
32
+ * Permission is an async round-trip: await the client handler, then reply to
33
+ * native with the resulting status (defaults to `denied` on error/no handler).
34
+ */
35
+ private handlePermissionRequest;
36
+ private handleObserverPurchase;
37
+ private handleObserverRestore;
38
+ }
@@ -0,0 +1,151 @@
1
+ import { FlowEventId, HANDLER_TO_NATIVE_EVENT, NATIVE_EVENT_RESOLVER, extractFlowCallbackArgs, filterUndefined, } from '@adapty/core';
2
+ import { parseFlowEvent } from '../coders/parse-flow';
3
+ import { Log, LogContext } from '../logger';
4
+ import { BaseViewEmitter } from './base-view-emitter';
5
+ /**
6
+ * FlowViewEmitter manages event handlers for flow view events.
7
+ * Each event type can have only one handler - new handlers replace existing ones.
8
+ *
9
+ * In addition to the standard synchronous dispatch inherited from
10
+ * {@link BaseViewEmitter}, this emitter handles three asynchronous round-trip
11
+ * events that must reply back to native:
12
+ * - `onRequestPermission` — awaits the async handler, then replies with the status.
13
+ * - `onObserverPurchaseInitiated` — injects start/finish callbacks (observer mode).
14
+ * - `onObserverRestoreInitiated` — injects start/finish callbacks (observer mode).
15
+ */
16
+ export class FlowViewEmitter extends BaseViewEmitter {
17
+ constructor(viewId, adapty) {
18
+ super(viewId);
19
+ this.adapty = adapty;
20
+ }
21
+ parseEventData(rawEventData, ctx) {
22
+ const result = parseFlowEvent(rawEventData, ctx);
23
+ if (!result) {
24
+ throw new Error('Failed to parse flow event');
25
+ }
26
+ return result;
27
+ }
28
+ getNativeEventForHandler(event) {
29
+ return HANDLER_TO_NATIVE_EVENT[event];
30
+ }
31
+ getHandlerForNativeEvent(nativeEvent, eventData) {
32
+ var _a, _b;
33
+ return (_b = (_a = NATIVE_EVENT_RESOLVER[nativeEvent]) === null || _a === void 0 ? void 0 : _a.call(NATIVE_EVENT_RESOLVER, eventData)) !== null && _b !== void 0 ? _b : null;
34
+ }
35
+ extractCallbackArgs(handlerName, eventData) {
36
+ return extractFlowCallbackArgs(handlerName, eventData);
37
+ }
38
+ getEventViewId(eventData) {
39
+ var _a, _b;
40
+ return (_b = (_a = eventData === null || eventData === void 0 ? void 0 : eventData.view) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null;
41
+ }
42
+ getEmitterName() {
43
+ return 'FlowViewEmitter';
44
+ }
45
+ /**
46
+ * Routes the three asynchronous round-trip events to their dedicated
47
+ * handlers, bypassing the standard synchronous boolean/close dispatch.
48
+ */
49
+ handleSpecialEvent(handlerName, eventData) {
50
+ if (handlerName === 'onRequestPermission' && eventData.id === FlowEventId.DidAskPermission) {
51
+ void this.handlePermissionRequest(eventData);
52
+ return true;
53
+ }
54
+ if (handlerName === 'onObserverPurchaseInitiated' && eventData.id === FlowEventId.ObserverDidInitiatePurchase) {
55
+ this.handleObserverPurchase(eventData);
56
+ return true;
57
+ }
58
+ if (handlerName === 'onObserverRestoreInitiated' && eventData.id === FlowEventId.ObserverDidInitiateRestore) {
59
+ this.handleObserverRestore(eventData);
60
+ return true;
61
+ }
62
+ return false;
63
+ }
64
+ /**
65
+ * Permission is an async round-trip: await the client handler, then reply to
66
+ * native with the resulting status (defaults to `denied` on error/no handler).
67
+ */
68
+ async handlePermissionRequest(event) {
69
+ const handlerData = this.handlers.get('onRequestPermission');
70
+ let status = 'denied';
71
+ let detail;
72
+ if (handlerData) {
73
+ try {
74
+ const handler = handlerData.handler;
75
+ const response = await handler(event.permission, event.customArgs);
76
+ status = response.status;
77
+ detail = response.detail;
78
+ }
79
+ catch (error) {
80
+ status = 'denied';
81
+ Log.warn('flow_view_did_answer_permission', () => `onRequestPermission handler threw; replying denied: ${error}`);
82
+ }
83
+ }
84
+ const method = 'flow_view_did_answer_permission';
85
+ const ctx = new LogContext();
86
+ const log = ctx.call({ methodName: method });
87
+ const body = JSON.stringify(filterUndefined({
88
+ method,
89
+ event_id: event.eventId,
90
+ status,
91
+ detail,
92
+ }));
93
+ await this.adapty
94
+ .handleMethodCall(method, body, ctx, log)
95
+ .catch((error) => Log.warn(method, () => `Failed to reply to permission request: ${error}`));
96
+ }
97
+ // Pass a fully-typed request object into `send` so each literal is checked
98
+ // against its own `Req[...]` arm (a `satisfies` on a method-union body cannot
99
+ // narrow, so we type per-call instead).
100
+ handleObserverPurchase(event) {
101
+ const handlerData = this.handlers.get('onObserverPurchaseInitiated');
102
+ if (!handlerData)
103
+ return;
104
+ const { handler, onRequestClose } = handlerData;
105
+ const send = (body) => {
106
+ const ctx = new LogContext();
107
+ const log = ctx.call({ methodName: body.method });
108
+ void this.adapty
109
+ .handleMethodCall(body.method, JSON.stringify(body), ctx, log)
110
+ .catch((error) => Log.warn(body.method, () => `Failed observer purchase signal: ${error}`));
111
+ };
112
+ const purchaseHandler = handler;
113
+ try {
114
+ // The observer's documented way to close the view after driving the
115
+ // purchase: returning `true` requests dismissal (close-on-`true`).
116
+ const shouldClose = purchaseHandler(event.product, () => send({ method: 'observer_purchase_did_start', event_id: event.eventId }), () => send({ method: 'observer_purchase_did_finish', event_id: event.eventId }));
117
+ if (shouldClose) {
118
+ onRequestClose().catch((error) => Log.warn('observer_purchase_did_initiate', () => `Failed to close view after observer purchase: ${error}`, () => ({ error })));
119
+ }
120
+ }
121
+ catch (error) {
122
+ Log.warn('observer_purchase_handler_failed', () => `onObserverPurchaseInitiated handler threw: ${error}`, () => ({ error }));
123
+ }
124
+ }
125
+ handleObserverRestore(event) {
126
+ const handlerData = this.handlers.get('onObserverRestoreInitiated');
127
+ if (!handlerData)
128
+ return;
129
+ const { handler, onRequestClose } = handlerData;
130
+ const send = (body) => {
131
+ const ctx = new LogContext();
132
+ const log = ctx.call({ methodName: body.method });
133
+ void this.adapty
134
+ .handleMethodCall(body.method, JSON.stringify(body), ctx, log)
135
+ .catch((error) => Log.warn(body.method, () => `Failed observer restore signal: ${error}`));
136
+ };
137
+ const restoreHandler = handler;
138
+ try {
139
+ // The observer's documented way to close the view after driving the
140
+ // restore: returning `true` requests dismissal (close-on-`true`).
141
+ const shouldClose = restoreHandler(() => send({ method: 'observer_restore_did_start', event_id: event.eventId }), () => send({ method: 'observer_restore_did_finish', event_id: event.eventId }));
142
+ if (shouldClose) {
143
+ onRequestClose().catch((error) => Log.warn('observer_restore_did_initiate', () => `Failed to close view after observer restore: ${error}`, () => ({ error })));
144
+ }
145
+ }
146
+ catch (error) {
147
+ Log.warn('observer_restore_handler_failed', () => `onObserverRestoreInitiated handler threw: ${error}`, () => ({ error }));
148
+ }
149
+ }
150
+ }
151
+ //# sourceMappingURL=flow-view-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-view-emitter.js","sourceRoot":"","sources":["../../../src/ui-builder/flow-view-emitter.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n FlowEventId,\n HANDLER_TO_NATIVE_EVENT,\n NATIVE_EVENT_RESOLVER,\n extractFlowCallbackArgs,\n filterUndefined,\n} from '@adapty/core';\nimport type { FlowEventIdType, ParsedFlowEvent, FlowPermissionStatus } from '@adapty/core';\n\nimport type { Adapty } from '../adapty';\nimport { parseFlowEvent } from '../coders/parse-flow';\nimport { Log, LogContext } from '../logger';\nimport type { components } from '../types/api';\n\nimport { BaseViewEmitter } from './base-view-emitter';\nimport type { FlowEventHandlers } from './types';\n\ntype Req = components['requests'];\n\n/**\n * FlowViewEmitter manages event handlers for flow view events.\n * Each event type can have only one handler - new handlers replace existing ones.\n *\n * In addition to the standard synchronous dispatch inherited from\n * {@link BaseViewEmitter}, this emitter handles three asynchronous round-trip\n * events that must reply back to native:\n * - `onRequestPermission` — awaits the async handler, then replies with the status.\n * - `onObserverPurchaseInitiated` — injects start/finish callbacks (observer mode).\n * - `onObserverRestoreInitiated` — injects start/finish callbacks (observer mode).\n */\nexport class FlowViewEmitter extends BaseViewEmitter<FlowEventHandlers, ParsedFlowEvent, FlowEventIdType> {\n private adapty: Adapty;\n\n constructor(viewId: string, adapty: Adapty) {\n super(viewId);\n this.adapty = adapty;\n }\n\n protected parseEventData(rawEventData: string, ctx: LogContext): ParsedFlowEvent {\n const result = parseFlowEvent(rawEventData, ctx);\n if (!result) {\n throw new Error('Failed to parse flow event');\n }\n return result;\n }\n\n protected getNativeEventForHandler(event: keyof FlowEventHandlers): FlowEventIdType | null {\n return HANDLER_TO_NATIVE_EVENT[event];\n }\n\n protected getHandlerForNativeEvent(\n nativeEvent: FlowEventIdType,\n eventData: ParsedFlowEvent,\n ): keyof FlowEventHandlers | null {\n return NATIVE_EVENT_RESOLVER[nativeEvent]?.(eventData) ?? null;\n }\n\n protected extractCallbackArgs(handlerName: keyof FlowEventHandlers, eventData: ParsedFlowEvent): unknown[] {\n return extractFlowCallbackArgs(handlerName, eventData);\n }\n\n protected getEventViewId(eventData: ParsedFlowEvent): string | null {\n return eventData?.view?.id ?? null;\n }\n\n protected getEmitterName(): string {\n return 'FlowViewEmitter';\n }\n\n /**\n * Routes the three asynchronous round-trip events to their dedicated\n * handlers, bypassing the standard synchronous boolean/close dispatch.\n */\n protected override handleSpecialEvent(handlerName: keyof FlowEventHandlers, eventData: ParsedFlowEvent): boolean {\n if (handlerName === 'onRequestPermission' && eventData.id === FlowEventId.DidAskPermission) {\n void this.handlePermissionRequest(eventData);\n return true;\n }\n if (handlerName === 'onObserverPurchaseInitiated' && eventData.id === FlowEventId.ObserverDidInitiatePurchase) {\n this.handleObserverPurchase(eventData);\n return true;\n }\n if (handlerName === 'onObserverRestoreInitiated' && eventData.id === FlowEventId.ObserverDidInitiateRestore) {\n this.handleObserverRestore(eventData);\n return true;\n }\n return false;\n }\n\n /**\n * Permission is an async round-trip: await the client handler, then reply to\n * native with the resulting status (defaults to `denied` on error/no handler).\n */\n private async handlePermissionRequest(\n event: Extract<ParsedFlowEvent, { id: typeof FlowEventId.DidAskPermission }>,\n ): Promise<void> {\n const handlerData = this.handlers.get('onRequestPermission');\n let status: FlowPermissionStatus = 'denied';\n let detail: string | undefined;\n if (handlerData) {\n try {\n const handler = handlerData.handler as FlowEventHandlers['onRequestPermission'];\n const response = await handler(event.permission, event.customArgs);\n status = response.status;\n detail = response.detail;\n } catch (error) {\n status = 'denied';\n Log.warn(\n 'flow_view_did_answer_permission',\n () => `onRequestPermission handler threw; replying denied: ${error}`,\n );\n }\n }\n const method = 'flow_view_did_answer_permission';\n const ctx = new LogContext();\n const log = ctx.call({ methodName: method });\n const body = JSON.stringify(\n filterUndefined({\n method,\n event_id: event.eventId,\n status,\n detail,\n } satisfies Req['FlowViewDidAnswerPermission.Request']),\n );\n await this.adapty\n .handleMethodCall(method, body, ctx, log)\n .catch((error) => Log.warn(method, () => `Failed to reply to permission request: ${error}`));\n }\n\n // Pass a fully-typed request object into `send` so each literal is checked\n // against its own `Req[...]` arm (a `satisfies` on a method-union body cannot\n // narrow, so we type per-call instead).\n private handleObserverPurchase(\n event: Extract<ParsedFlowEvent, { id: typeof FlowEventId.ObserverDidInitiatePurchase }>,\n ): void {\n const handlerData = this.handlers.get('onObserverPurchaseInitiated');\n if (!handlerData) return;\n const { handler, onRequestClose } = handlerData;\n const send = (body: Req['ObserverPurchaseDidStart.Request'] | Req['ObserverPurchaseDidFinish.Request']) => {\n const ctx = new LogContext();\n const log = ctx.call({ methodName: body.method });\n void this.adapty\n .handleMethodCall(body.method, JSON.stringify(body), ctx, log)\n .catch((error) => Log.warn(body.method, () => `Failed observer purchase signal: ${error}`));\n };\n const purchaseHandler = handler as FlowEventHandlers['onObserverPurchaseInitiated'];\n try {\n // The observer's documented way to close the view after driving the\n // purchase: returning `true` requests dismissal (close-on-`true`).\n const shouldClose = purchaseHandler(\n event.product,\n () => send({ method: 'observer_purchase_did_start', event_id: event.eventId }),\n () => send({ method: 'observer_purchase_did_finish', event_id: event.eventId }),\n );\n if (shouldClose) {\n onRequestClose().catch((error) =>\n Log.warn(\n 'observer_purchase_did_initiate',\n () => `Failed to close view after observer purchase: ${error}`,\n () => ({ error }),\n ),\n );\n }\n } catch (error) {\n Log.warn(\n 'observer_purchase_handler_failed',\n () => `onObserverPurchaseInitiated handler threw: ${error}`,\n () => ({ error }),\n );\n }\n }\n\n private handleObserverRestore(\n event: Extract<ParsedFlowEvent, { id: typeof FlowEventId.ObserverDidInitiateRestore }>,\n ): void {\n const handlerData = this.handlers.get('onObserverRestoreInitiated');\n if (!handlerData) return;\n const { handler, onRequestClose } = handlerData;\n const send = (body: Req['ObserverRestoreDidStart.Request'] | Req['ObserverRestoreDidFinish.Request']) => {\n const ctx = new LogContext();\n const log = ctx.call({ methodName: body.method });\n void this.adapty\n .handleMethodCall(body.method, JSON.stringify(body), ctx, log)\n .catch((error) => Log.warn(body.method, () => `Failed observer restore signal: ${error}`));\n };\n const restoreHandler = handler as FlowEventHandlers['onObserverRestoreInitiated'];\n try {\n // The observer's documented way to close the view after driving the\n // restore: returning `true` requests dismissal (close-on-`true`).\n const shouldClose = restoreHandler(\n () => send({ method: 'observer_restore_did_start', event_id: event.eventId }),\n () => send({ method: 'observer_restore_did_finish', event_id: event.eventId }),\n );\n if (shouldClose) {\n onRequestClose().catch((error) =>\n Log.warn(\n 'observer_restore_did_initiate',\n () => `Failed to close view after observer restore: ${error}`,\n () => ({ error }),\n ),\n );\n }\n } catch (error) {\n Log.warn(\n 'observer_restore_handler_failed',\n () => `onObserverRestoreInitiated handler threw: ${error}`,\n () => ({ error }),\n );\n }\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
- export { PaywallViewController } from './paywall-view-controller';
1
+ export { FlowViewController } from './flow-view-controller';
2
2
  export { OnboardingViewController } from './onboarding-view-controller';
3
- export type { CreatePaywallViewParamsInput, CreateOnboardingViewParamsInput } from './types';
4
- export type { AdaptyCustomAsset, AdaptyUiView, AdaptyUiDialogConfig, AdaptyUiDialogActionType, AdaptyIOSPresentationStyle, EventHandlers, } from './types';
5
- export type { OnboardingEventHandlers } from './types';
6
- export { createPaywallView } from './create-paywall-view';
3
+ export type { CreateFlowViewParamsInput, CreateOnboardingViewParamsInput } from './types';
4
+ export type { AdaptyCustomAsset, AdaptyUiView, AdaptyUiDialogConfig, AdaptyIOSPresentationStyle, FlowEventHandlers, OnboardingEventHandlers, AdaptyPermission, FlowPermissionResponse, FlowPermissionStatus, } from './types';
5
+ export { AdaptyUiDialogActionType } from './types';
6
+ export { createFlowView } from './create-flow-view';
7
7
  export { createOnboardingView } from './create-onboarding-view';
@@ -1,6 +1,7 @@
1
1
  // Export UI types and classes for convenience
2
- export { PaywallViewController } from './paywall-view-controller';
2
+ export { FlowViewController } from './flow-view-controller';
3
3
  export { OnboardingViewController } from './onboarding-view-controller';
4
- export { createPaywallView } from './create-paywall-view';
4
+ export { AdaptyUiDialogActionType } from './types';
5
+ export { createFlowView } from './create-flow-view';
5
6
  export { createOnboardingView } from './create-onboarding-view';
6
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui-builder/index.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAYxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC","sourcesContent":["// Export UI types and classes for convenience\nexport { PaywallViewController } from './paywall-view-controller';\nexport { OnboardingViewController } from './onboarding-view-controller';\nexport type { CreatePaywallViewParamsInput, CreateOnboardingViewParamsInput } from './types';\nexport type {\n AdaptyCustomAsset,\n AdaptyUiView,\n AdaptyUiDialogConfig,\n AdaptyUiDialogActionType,\n AdaptyIOSPresentationStyle,\n EventHandlers,\n} from './types';\nexport type { OnboardingEventHandlers } from './types';\n\nexport { createPaywallView } from './create-paywall-view';\nexport { createOnboardingView } from './create-onboarding-view';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui-builder/index.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAaxE,OAAO,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAEnD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC","sourcesContent":["// Export UI types and classes for convenience\nexport { FlowViewController } from './flow-view-controller';\nexport { OnboardingViewController } from './onboarding-view-controller';\nexport type { CreateFlowViewParamsInput, CreateOnboardingViewParamsInput } from './types';\nexport type {\n AdaptyCustomAsset,\n AdaptyUiView,\n AdaptyUiDialogConfig,\n AdaptyIOSPresentationStyle,\n FlowEventHandlers,\n OnboardingEventHandlers,\n AdaptyPermission,\n FlowPermissionResponse,\n FlowPermissionStatus,\n} from './types';\nexport { AdaptyUiDialogActionType } from './types';\n\nexport { createFlowView } from './create-flow-view';\nexport { createOnboardingView } from './create-onboarding-view';\n"]}
@@ -5,6 +5,8 @@ export declare const DEFAULT_ONBOARDING_PARAMS: CreateOnboardingViewParamsInput;
5
5
  /**
6
6
  * Controller for managing onboarding views.
7
7
  *
8
+ * @deprecated Since 4.0.0. Migrate onboardings to the Flow Builder API.
9
+ *
8
10
  * @remarks
9
11
  * This class provides methods to present, dismiss, and handle events for onboarding views
10
12
  * created with the Onboarding Builder. Create instances using the {@link createOnboardingView} function
@@ -26,7 +28,7 @@ export declare class OnboardingViewController {
26
28
  /**
27
29
  * Since constructors in JS cannot be async, it is not
28
30
  * preferred to create ViewControllers in direct way.
29
- * Consider using @link{OnboardingViewController.create} instead
31
+ * Consider using {@link OnboardingViewController.create} instead
30
32
  *
31
33
  * @internal
32
34
  */
@@ -116,11 +118,11 @@ export declare class OnboardingViewController {
116
118
  * // Return true to keep default closing behavior
117
119
  * return true;
118
120
  * },
119
- * onActionPerformed: (action) => {
120
- * console.log('Action performed:', action.name);
121
+ * onCustom: (actionId, meta) => {
122
+ * console.log('Custom action:', actionId, meta);
121
123
  * },
122
- * onProductSelected: (product) => {
123
- * console.log('Product selected:', product.vendorProductId);
124
+ * onStateUpdated: (action, meta) => {
125
+ * console.log('State updated:', action, meta);
124
126
  * }
125
127
  * });
126
128
  *
@@ -11,6 +11,8 @@ export const DEFAULT_ONBOARDING_PARAMS = {
11
11
  /**
12
12
  * Controller for managing onboarding views.
13
13
  *
14
+ * @deprecated Since 4.0.0. Migrate onboardings to the Flow Builder API.
15
+ *
14
16
  * @remarks
15
17
  * This class provides methods to present, dismiss, and handle events for onboarding views
16
18
  * created with the Onboarding Builder. Create instances using the {@link createOnboardingView} function
@@ -43,7 +45,7 @@ export class OnboardingViewController {
43
45
  /**
44
46
  * Since constructors in JS cannot be async, it is not
45
47
  * preferred to create ViewControllers in direct way.
46
- * Consider using @link{OnboardingViewController.create} instead
48
+ * Consider using {@link OnboardingViewController.create} instead
47
49
  *
48
50
  * @internal
49
51
  */
@@ -172,11 +174,11 @@ export class OnboardingViewController {
172
174
  * // Return true to keep default closing behavior
173
175
  * return true;
174
176
  * },
175
- * onActionPerformed: (action) => {
176
- * console.log('Action performed:', action.name);
177
+ * onCustom: (actionId, meta) => {
178
+ * console.log('Custom action:', actionId, meta);
177
179
  * },
178
- * onProductSelected: (product) => {
179
- * console.log('Product selected:', product.vendorProductId);
180
+ * onStateUpdated: (action, meta) => {
181
+ * console.log('State updated:', action, meta);
180
182
  * }
181
183
  * });
182
184
  *