@amalaika/form-sdk-package 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +193 -233
  2. package/dist/cjs/client/index.d.ts +42 -3
  3. package/dist/cjs/client/index.d.ts.map +1 -1
  4. package/dist/cjs/client/index.js +274 -73
  5. package/dist/cjs/client/index.js.map +1 -1
  6. package/dist/cjs/i18n/en.json +7 -0
  7. package/dist/cjs/i18n/fr.json +7 -0
  8. package/dist/cjs/i18n/index.d.ts +2 -0
  9. package/dist/cjs/i18n/index.d.ts.map +1 -0
  10. package/dist/cjs/i18n/index.js +15 -0
  11. package/dist/cjs/i18n/index.js.map +1 -0
  12. package/dist/cjs/i18n/rw.json +7 -0
  13. package/dist/cjs/index.d.ts +4 -2
  14. package/dist/cjs/index.d.ts.map +1 -1
  15. package/dist/cjs/index.js +10 -1
  16. package/dist/cjs/index.js.map +1 -1
  17. package/dist/cjs/integrations/checkout-script.d.ts +10 -0
  18. package/dist/cjs/integrations/checkout-script.d.ts.map +1 -0
  19. package/dist/cjs/integrations/checkout-script.js +38 -0
  20. package/dist/cjs/integrations/checkout-script.js.map +1 -0
  21. package/dist/cjs/integrations/index.d.ts +5 -0
  22. package/dist/cjs/integrations/index.d.ts.map +1 -0
  23. package/dist/cjs/integrations/index.js +49 -0
  24. package/dist/cjs/integrations/index.js.map +1 -0
  25. package/dist/cjs/integrations/mastercard.d.ts +11 -0
  26. package/dist/cjs/integrations/mastercard.d.ts.map +1 -0
  27. package/dist/cjs/integrations/mastercard.js +100 -0
  28. package/dist/cjs/integrations/mastercard.js.map +1 -0
  29. package/dist/cjs/integrations/types.d.ts +31 -0
  30. package/dist/cjs/integrations/types.d.ts.map +1 -0
  31. package/dist/cjs/{types.js.map → integrations/types.js.map} +1 -1
  32. package/dist/cjs/state/index.d.ts +29 -0
  33. package/dist/cjs/state/index.d.ts.map +1 -0
  34. package/dist/cjs/state/index.js +97 -0
  35. package/dist/cjs/state/index.js.map +1 -0
  36. package/dist/cjs/types/index.d.ts +80 -2
  37. package/dist/cjs/types/index.d.ts.map +1 -1
  38. package/dist/cjs/utils/index.d.ts +14 -1
  39. package/dist/cjs/utils/index.d.ts.map +1 -1
  40. package/dist/cjs/utils/index.js +122 -4
  41. package/dist/cjs/utils/index.js.map +1 -1
  42. package/dist/esm/client/index.d.ts +42 -3
  43. package/dist/esm/client/index.d.ts.map +1 -1
  44. package/dist/esm/client/index.js +274 -73
  45. package/dist/esm/client/index.js.map +1 -1
  46. package/dist/esm/i18n/en.json +7 -0
  47. package/dist/esm/i18n/fr.json +7 -0
  48. package/dist/esm/i18n/index.d.ts +2 -0
  49. package/dist/esm/i18n/index.d.ts.map +1 -0
  50. package/dist/esm/i18n/index.js +9 -0
  51. package/dist/esm/i18n/index.js.map +1 -0
  52. package/dist/esm/i18n/rw.json +7 -0
  53. package/dist/esm/index.d.ts +4 -2
  54. package/dist/esm/index.d.ts.map +1 -1
  55. package/dist/esm/index.js +3 -1
  56. package/dist/esm/index.js.map +1 -1
  57. package/dist/esm/integrations/checkout-script.d.ts +10 -0
  58. package/dist/esm/integrations/checkout-script.d.ts.map +1 -0
  59. package/dist/esm/integrations/checkout-script.js +35 -0
  60. package/dist/esm/integrations/checkout-script.js.map +1 -0
  61. package/dist/esm/integrations/index.d.ts +5 -0
  62. package/dist/esm/integrations/index.d.ts.map +1 -0
  63. package/dist/esm/integrations/index.js +11 -0
  64. package/dist/esm/integrations/index.js.map +1 -0
  65. package/dist/esm/integrations/mastercard.d.ts +11 -0
  66. package/dist/esm/integrations/mastercard.d.ts.map +1 -0
  67. package/dist/esm/integrations/mastercard.js +97 -0
  68. package/dist/esm/integrations/mastercard.js.map +1 -0
  69. package/dist/esm/integrations/types.d.ts +31 -0
  70. package/dist/esm/integrations/types.d.ts.map +1 -0
  71. package/dist/esm/{types.js.map → integrations/types.js.map} +1 -1
  72. package/dist/esm/state/index.d.ts +29 -0
  73. package/dist/esm/state/index.d.ts.map +1 -0
  74. package/dist/esm/state/index.js +93 -0
  75. package/dist/esm/state/index.js.map +1 -0
  76. package/dist/esm/types/index.d.ts +80 -2
  77. package/dist/esm/types/index.d.ts.map +1 -1
  78. package/dist/esm/utils/index.d.ts +14 -1
  79. package/dist/esm/utils/index.d.ts.map +1 -1
  80. package/dist/esm/utils/index.js +117 -4
  81. package/dist/esm/utils/index.js.map +1 -1
  82. package/package.json +2 -4
  83. package/dist/cjs/client/__tests__/client.spec.d.ts +0 -2
  84. package/dist/cjs/client/__tests__/client.spec.d.ts.map +0 -1
  85. package/dist/cjs/client/__tests__/client.spec.js +0 -300
  86. package/dist/cjs/client/__tests__/client.spec.js.map +0 -1
  87. package/dist/cjs/client.d.ts +0 -22
  88. package/dist/cjs/client.d.ts.map +0 -1
  89. package/dist/cjs/client.js +0 -111
  90. package/dist/cjs/client.js.map +0 -1
  91. package/dist/cjs/types.d.ts +0 -78
  92. package/dist/cjs/types.d.ts.map +0 -1
  93. package/dist/cjs/utils/__tests__/utils.spec.d.ts +0 -2
  94. package/dist/cjs/utils/__tests__/utils.spec.d.ts.map +0 -1
  95. package/dist/cjs/utils/__tests__/utils.spec.js +0 -172
  96. package/dist/cjs/utils/__tests__/utils.spec.js.map +0 -1
  97. package/dist/cjs/utils.d.ts +0 -5
  98. package/dist/cjs/utils.d.ts.map +0 -1
  99. package/dist/cjs/utils.js +0 -45
  100. package/dist/cjs/utils.js.map +0 -1
  101. package/dist/esm/client/__tests__/client.spec.d.ts +0 -2
  102. package/dist/esm/client/__tests__/client.spec.d.ts.map +0 -1
  103. package/dist/esm/client/__tests__/client.spec.js +0 -355
  104. package/dist/esm/client/__tests__/client.spec.js.map +0 -1
  105. package/dist/esm/client.d.ts +0 -22
  106. package/dist/esm/client.d.ts.map +0 -1
  107. package/dist/esm/client.js +0 -107
  108. package/dist/esm/client.js.map +0 -1
  109. package/dist/esm/types.d.ts +0 -78
  110. package/dist/esm/types.d.ts.map +0 -1
  111. package/dist/esm/utils/__tests__/utils.spec.d.ts +0 -2
  112. package/dist/esm/utils/__tests__/utils.spec.d.ts.map +0 -1
  113. package/dist/esm/utils/__tests__/utils.spec.js +0 -182
  114. package/dist/esm/utils/__tests__/utils.spec.js.map +0 -1
  115. package/dist/esm/utils.d.ts +0 -5
  116. package/dist/esm/utils.d.ts.map +0 -1
  117. package/dist/esm/utils.js +0 -40
  118. package/dist/esm/utils.js.map +0 -1
  119. /package/dist/cjs/{types.js → integrations/types.js} +0 -0
  120. /package/dist/esm/{types.js → integrations/types.js} +0 -0
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @amalaika/form-sdk-package
2
2
 
3
- Framework-agnostic SDK for integrating the event registration form system. Handles data fetching, conditional visibility, file uploads, and form submission — no UI rendering included.
3
+ Framework-agnostic SDK for event form integration fetch forms, handle visibility, upload files, submit, and process payments.
4
4
 
5
- Works with React, Vue, Angular, Svelte, vanilla JS, or any environment with the Fetch API.
5
+ **Zero runtime dependencies.** Works with any JavaScript framework or vanilla JS.
6
6
 
7
7
  ## Installation
8
8
 
@@ -10,333 +10,293 @@ Works with React, Vue, Angular, Svelte, vanilla JS, or any environment with the
10
10
  npm install @amalaika/form-sdk-package
11
11
  ```
12
12
 
13
- For local development (monorepo):
14
-
15
- ```json
16
- {
17
- "dependencies": {
18
- "@amalaika/form-sdk-package": "file:../form-sdk-package"
19
- }
20
- }
21
- ```
22
-
23
13
  ## Quick Start
24
14
 
25
15
  ```ts
26
- import { EventFormClient, getAllFields, isFieldVisible } from "@amalaika/form-sdk-package";
16
+ import { EventFormClient, FormStateManager, validateForm, getAllFields } from "@amalaika/form-sdk-package";
27
17
 
18
+ // 1. Create a client
28
19
  const client = new EventFormClient({
29
- apiKey: "Am_550e8400-e29b-41d4-a716-446655440000",
20
+ apiKey: "Am_550e8400-...",
30
21
  resourceType: "ticketing",
31
- locale: "en", // default locale for all requests
32
22
  });
33
23
 
34
- // All calls automatically use "en" — no locale param needed
24
+ // 2. Fetch tickets and forms
35
25
  const tickets = await client.fetchTickets();
36
26
  const form = await client.fetchForm(tickets[0].id);
37
- const fields = getAllFields(form.schema);
38
27
 
39
- // Switch language without reinstantiating
40
- client.setLocale("fr");
41
- const ticketsFr = await client.fetchTickets(); // now uses "fr"
42
- ```
43
-
44
- ## API Reference
45
-
46
- ### Constructor
47
-
48
- ```ts
49
- const client = new EventFormClient(config: EventFormConfig);
28
+ // 3. Manage form state
29
+ const fields = getAllFields(form.schema);
30
+ const state = new FormStateManager(fields);
31
+ state.setValue("email", "user@example.com");
32
+
33
+ // 4. Validate and submit
34
+ const errors = validateForm(fields, state.getValues());
35
+ const allValid = Object.values(errors).every((r) => r.valid);
36
+
37
+ if (allValid) {
38
+ const { submission, integrations } = await client.submitForm(form, state.getSubmissionData(), {
39
+ resourceId: tickets[0].id,
40
+ attendanceType: "PHYSICAL",
41
+ });
42
+ }
50
43
  ```
51
44
 
52
- | Parameter | Type | Required | Description |
53
- |-----------|------|----------|-------------|
54
- | `apiKey` | `string` | Yes | Event API key (e.g. `"Am_550e8400-..."`) |
55
- | `resourceType` | `"ticketing" \| "accommodation" \| "exhibition"` | Yes | Resource type for submissions |
56
- | `apiBaseUrl` | `string` | No | API base URL. Defaults to `"https://api.eventsfactory.rw/api"` |
57
- | `locale` | `string` | No | Default locale for all requests. Can be changed later via `setLocale()` |
58
- | `errorMessages` | `Partial<ErrorMessages>` | No | Custom error messages — override any or all defaults |
59
-
60
- ### Locale Management
61
-
62
- Set a default locale on the constructor so you don't have to pass it on every method call:
45
+ ## Configuration
63
46
 
64
47
  ```ts
65
48
  const client = new EventFormClient({
49
+ // Required
66
50
  apiKey: "Am_550e8400-...",
67
- resourceType: "ticketing",
68
- locale: "fr",
51
+ resourceType: "ticketing", // "ticketing" | "accommodation" | "exhibition"
52
+
53
+ // Optional
54
+ apiBaseUrl: "https://api.example.com", // defaults to production
55
+ locale: "en", // default locale for requests
56
+ origin: "https://myapp.com", // Origin header
57
+ timeout: 30000, // request timeout (ms)
58
+ noCache: false, // send Cache-Control: no-cache
59
+ mastercardCheckoutUrl: "https://...", // checkout script URL override
60
+ merchantName: "My Event", // shown in payment UI
61
+
62
+ // Retry failed requests
63
+ retry: { maxRetries: 3, delay: 1000 },
64
+
65
+ // Cache GET responses
66
+ cache: { enabled: true, ttl: 60000 },
67
+
68
+ // Custom error messages
69
+ errorMessages: {
70
+ fetchTickets: "Could not load tickets",
71
+ submitForm: "Submission failed",
72
+ },
73
+
74
+ // Interceptors
75
+ interceptors: {
76
+ request: (config) => { /* modify request */ return config; },
77
+ response: (data) => { /* transform response */ return data; },
78
+ error: (err) => { /* handle error */ return err; },
79
+ },
69
80
  });
70
-
71
- // All calls automatically use "fr" — no need to pass locale
72
- const tickets = await client.fetchTickets();
73
- const form = await client.fetchForm(tickets[0].id);
74
81
  ```
75
82
 
76
- Switch locale at any time without reinstantiating:
83
+ ## Client Methods
77
84
 
78
- ```ts
79
- client.setLocale("en");
80
- // All subsequent calls now use "en"
81
- ```
82
-
83
- Read the current locale:
85
+ ### Tickets
84
86
 
85
87
  ```ts
86
- client.getLocale(); // "en"
87
- ```
88
+ // Fetch all tickets (with optional locale/name filter)
89
+ const tickets = await client.fetchTickets({ locale: "fr", name: "VIP" });
88
90
 
89
- Per-call locale still overrides the default when needed:
91
+ // Fetch a single ticket by ID
92
+ const ticket = await client.fetchTicketById(42);
90
93
 
91
- ```ts
92
- // Uses "de" for this call only, default remains "en"
93
- const tickets = await client.fetchTickets({ locale: "de" });
94
+ // Fetch a public ticket (no auth required)
95
+ const publicTicket = await client.fetchPublicTicket(42, "en");
94
96
  ```
95
97
 
96
- ### Methods
97
-
98
- #### `client.fetchTickets(options?)`
99
-
100
- Fetch all published tickets for the event.
98
+ ### Languages & Forms
101
99
 
102
100
  ```ts
103
- const tickets = await client.fetchTickets({ locale: "fr", name: "VIP" });
104
- ```
105
-
106
- | Option | Type | Description |
107
- |--------|------|-------------|
108
- | `locale` | `string` | Locale code for translations (also sent as `Accept-Language`) |
109
- | `name` | `string` | Filter tickets by name |
110
-
111
- Returns `Promise<Ticket[]>`.
112
-
113
- ---
101
+ // Fetch available languages
102
+ const languages = await client.fetchLanguages(); // ["en", "fr", "rw"]
114
103
 
115
- #### `client.fetchTicketById(id, locale?)`
116
-
117
- Fetch a single ticket by ID.
118
-
119
- ```ts
120
- const ticket = await client.fetchTicketById(42, "en");
104
+ // Fetch form schema for a ticket
105
+ const form = await client.fetchForm(ticketId, "en");
121
106
  ```
122
107
 
123
- Returns `Promise<Ticket>`.
124
-
125
- ---
126
-
127
- #### `client.fetchLanguages()`
128
-
129
- Fetch available languages for the event. Returns codes sorted with the default language first.
108
+ ### File Uploads
130
109
 
131
110
  ```ts
132
- const languages = await client.fetchLanguages();
133
- // ["en", "fr", "ar"]
111
+ // Two-step upload: authorize, then upload
112
+ const token = await client.authorizeUpload(formId, fieldId, file);
113
+ const fileUrl = await client.uploadFile(formId, token, file);
134
114
  ```
135
115
 
136
- Returns `Promise<string[]>`.
137
-
138
- ---
139
-
140
- #### `client.fetchForm(ticketId, locale?)`
141
-
142
- Fetch the form linked to a ticket.
116
+ ### Form Submission
143
117
 
144
118
  ```ts
145
- const form = await client.fetchForm(1, "fr");
119
+ const { submission, integrations } = await client.submitForm(
120
+ form,
121
+ formValues,
122
+ {
123
+ resourceId: ticketId,
124
+ attendanceType: "PHYSICAL", // "VIRTUAL" | "PHYSICAL" | "HYBRID"
125
+ containerId: "#payment-container", // CSS selector for payment UI
126
+ },
127
+ );
128
+
129
+ // submission: SubmissionResponse with id, formId, payment info, etc.
130
+ // integrations: IntegrationResult[] from any payment handlers
146
131
  ```
147
132
 
148
- Returns `Promise<FormData>`. The `form.schema` contains the field definitions used to render the form.
149
-
150
- ---
151
-
152
- #### `client.authorizeUpload(formId, fieldId, file, locale?)`
153
-
154
- Step 1 of file upload — request an upload token.
133
+ ### Locale & Cache
155
134
 
156
135
  ```ts
157
- const token = await client.authorizeUpload(form.id, "resume", file);
136
+ client.setLocale("fr");
137
+ client.getLocale(); // "fr"
138
+ client.clearCache();
158
139
  ```
159
140
 
160
- Returns `Promise<string>` (the upload token).
161
-
162
- ---
163
-
164
- #### `client.uploadFile(formId, token, file, locale?)`
165
-
166
- Step 2 of file upload — upload the file using the token.
141
+ ### Payment
167
142
 
168
143
  ```ts
169
- const fileUrl = await client.uploadFile(form.id, token, file);
144
+ // Preload the Mastercard checkout script before it's needed
145
+ await client.preloadCheckoutScript();
170
146
  ```
171
147
 
172
- Returns `Promise<string>` (the uploaded file URL to include in submission data).
148
+ ## FormStateManager
173
149
 
174
- ---
175
-
176
- #### `client.submitForm(formId, data, context)`
177
-
178
- Submit form data.
150
+ Manages form field values, dirty/touched tracking, visibility, and change subscriptions.
179
151
 
180
152
  ```ts
181
- await client.submitForm(form.id, submissionData, {
182
- eventId: form.eventId,
183
- ticketId: 1,
184
- locale: "en",
185
- });
186
- ```
153
+ import { FormStateManager, getAllFields } from "@amalaika/form-sdk-package";
187
154
 
188
- | Context Field | Type | Required | Description |
189
- |---------------|------|----------|-------------|
190
- | `eventId` | `number` | Yes | Event ID (from `form.eventId`) |
191
- | `ticketId` | `number` | Yes | Ticket ID used to fetch the form |
192
- | `locale` | `string` | No | Locale for `Accept-Language` header |
155
+ const fields = getAllFields(form.schema);
156
+ const state = new FormStateManager(fields);
193
157
 
194
- The `resourceType` is automatically sent from the constructor config.
158
+ // Get/set values
159
+ state.setValue("name", "Alice");
160
+ state.getValue("name"); // "Alice"
161
+ state.setValues({ name: "Alice", email: "alice@example.com" });
162
+ state.getValues(); // { name: "Alice", email: "alice@example.com" }
195
163
 
196
- Returns `Promise<void>`.
164
+ // Track user interaction
165
+ state.touchField("email");
166
+ state.isTouched("email"); // true
167
+ state.isDirty(); // true
168
+ state.getDirtyFields(); // Set(["name", "email"])
197
169
 
198
- ### Utility Functions
170
+ // Visibility-aware submission data (excludes hidden fields)
171
+ const data = state.getSubmissionData();
199
172
 
200
- Pure functions for working with form schemas and conditional visibility. Import directly:
173
+ // Get visible field IDs based on conditional logic
174
+ const visible = state.getVisibleFieldIds();
201
175
 
202
- ```ts
203
- import { getAllFields, isFieldVisible, getVisibleFieldIds } from "@amalaika/form-sdk-package";
204
- ```
176
+ // Resolve active payment integrations
177
+ const integrations = state.getActiveIntegrations();
205
178
 
206
- #### `getAllFields(schema)`
207
-
208
- Extracts all fields from a `FormSchema`, whether flat or stepped.
179
+ // Subscribe to changes
180
+ const unsubscribe = state.onChange(({ fieldId, value, values }) => {
181
+ console.log(`${fieldId} changed to`, value);
182
+ });
209
183
 
210
- ```ts
211
- const fields = getAllFields(form.schema);
184
+ // Reset to initial state
185
+ state.reset();
212
186
  ```
213
187
 
214
- Returns `FieldDefinition[]`.
215
-
216
- ---
217
-
218
- #### `isFieldVisible(field, formValues, allFields)`
219
-
220
- Checks whether a field should be visible based on the current form values. Supports cascading visibility (if a parent field is hidden, its dependents are too).
188
+ ## Validation
221
189
 
222
190
  ```ts
223
- if (isFieldVisible(field, currentValues, allFields)) {
224
- // render this field
225
- }
226
- ```
227
-
228
- Returns `boolean`.
191
+ import { validateField, validateForm, getAllFields } from "@amalaika/form-sdk-package";
229
192
 
230
- **Supported operators:**
193
+ // Validate a single field
194
+ const result = validateField(field, value);
195
+ // { valid: true } or { valid: false, error: "This field is required" }
231
196
 
232
- | Operator | Visible when |
233
- |----------|-------------|
234
- | `equals` | `formValues[dependsOn] === value` |
235
- | `not_equals` | `formValues[dependsOn] !== value` |
236
- | `in` | Any overlap between selected values and target values |
237
-
238
- ---
239
-
240
- #### `getVisibleFieldIds(allFields, formValues)`
241
-
242
- Returns the set of field IDs that are currently visible. Use this to filter submission data — only submit visible fields.
243
-
244
- ```ts
245
- const visibleIds = getVisibleFieldIds(allFields, formValues);
246
-
247
- const submissionData = {};
248
- for (const [key, val] of Object.entries(formValues)) {
249
- if (visibleIds.has(key)) submissionData[key] = val;
250
- }
197
+ // Validate all visible fields at once
198
+ const results = validateForm(fields, values);
199
+ // { fieldId: { valid: boolean, error?: string }, ... }
251
200
  ```
252
201
 
253
- Returns `Set<string>`.
202
+ Supports: `required`, `minLength`, `maxLength`, `min`, `max`, `pattern`, `accept` (file types), `maxSize` (file size).
254
203
 
255
- ## Full Example
204
+ ## Utility Functions
256
205
 
257
206
  ```ts
258
207
  import {
259
- EventFormClient,
260
208
  getAllFields,
209
+ isFieldVisible,
261
210
  getVisibleFieldIds,
211
+ hasIntegration,
212
+ getIntegrationMethod,
213
+ resolveIntegrations,
262
214
  } from "@amalaika/form-sdk-package";
263
215
 
264
- const client = new EventFormClient({
265
- apiKey: "Am_550e8400-e29b-41d4-a716-446655440000",
266
- resourceType: "ticketing",
267
- locale: "en",
268
- });
216
+ // Flatten fields from schema (handles flat and step-based layouts)
217
+ const fields = getAllFields(form.schema);
269
218
 
270
- // 1. Fetch tickets and pick one (uses default locale "en")
271
- const tickets = await client.fetchTickets();
272
- const ticket = tickets[0];
273
-
274
- // 2. Fetch the form (uses default locale "en")
275
- const form = await client.fetchForm(ticket.id);
276
- const allFields = getAllFields(form.schema);
277
-
278
- // 3. Collect user input into formValues (your UI handles this)
279
- const formValues: Record<string, unknown> = {
280
- first_name: "Jane",
281
- last_name: "Doe",
282
- email: "jane@example.com",
283
- role: "speaker",
284
- talk_title: "Building Dynamic Forms",
285
- };
286
-
287
- // 4. Filter to visible fields only
288
- const visibleIds = getVisibleFieldIds(allFields, formValues);
289
- const submissionData: Record<string, unknown> = {};
290
- for (const [key, val] of Object.entries(formValues)) {
291
- if (visibleIds.has(key)) submissionData[key] = val;
292
- }
219
+ // Conditional visibility
220
+ const visible = isFieldVisible(field, formValues, allFields);
221
+ const visibleIds = getVisibleFieldIds(fields, formValues);
293
222
 
294
- // 5. Handle file uploads (if any)
295
- const resumeFile = new File(["..."], "resume.pdf", { type: "application/pdf" });
296
- const token = await client.authorizeUpload(form.id, "resume", resumeFile);
297
- const fileUrl = await client.uploadFile(form.id, token, resumeFile);
298
- submissionData["resume"] = fileUrl;
223
+ // Payment integrations
224
+ const hasPay = hasIntegration(field);
225
+ const method = getIntegrationMethod(field, "CARD"); // "mastercard_payment_gateway"
226
+ const active = resolveIntegrations(fields, formValues);
227
+ ```
228
+
229
+ ## Mastercard Payment Integration
230
+
231
+ The SDK handles Mastercard Hosted Checkout via an embedded page flow:
232
+
233
+ 1. Submit the form — the API returns a `payment` object with `session_id` and `order_id`
234
+ 2. The SDK loads the Mastercard checkout script and renders the embedded payment UI in a container element
235
+ 3. On successful payment, the SDK confirms the payment with the backend
236
+ 4. The result is returned as part of the `integrations` array
299
237
 
300
- // 6. Submit (locale comes from constructor default)
301
- await client.submitForm(form.id, submissionData, {
302
- eventId: form.eventId!,
303
- ticketId: ticket.id,
238
+ ```ts
239
+ // Provide a container element for the payment UI
240
+ const { submission, integrations } = await client.submitForm(form, values, {
241
+ resourceId: ticketId,
242
+ attendanceType: "PHYSICAL",
243
+ containerId: "#payment-container", // must exist in the DOM
304
244
  });
245
+
246
+ // Check payment result
247
+ for (const result of integrations) {
248
+ if (result.success) {
249
+ // Payment completed
250
+ } else {
251
+ // result.error contains the error message
252
+ // result.data may contain additional details
253
+ }
254
+ }
305
255
  ```
306
256
 
307
- ## Exported Types
257
+ ## TypeScript
258
+
259
+ All types are exported:
308
260
 
309
261
  ```ts
310
262
  import type {
311
- ErrorMessages,
312
263
  EventFormConfig,
313
- FieldOption,
264
+ FormData,
265
+ FormSchema,
314
266
  FieldDefinition,
267
+ FieldOption,
315
268
  StepDefinition,
316
- FormSchema,
317
- FormData,
318
- ApiResponse,
319
- TicketTranslation,
320
269
  Ticket,
270
+ TicketTranslation,
271
+ ValidationResult,
272
+ SubmissionResponse,
273
+ PaymentInfo,
274
+ IntegrationResult,
275
+ ResolvedIntegration,
276
+ ApiResponse,
277
+ ErrorMessages,
321
278
  } from "@amalaika/form-sdk-package";
322
279
  ```
323
280
 
324
- ## Development
281
+ ## i18n
325
282
 
326
- ```bash
327
- # Install dependencies
328
- npm install
283
+ The SDK supports `en`, `fr`, and `rw` locales for error messages. Pass a locale to the client constructor or to individual methods:
284
+
285
+ ```ts
286
+ const client = new EventFormClient({ apiKey: "...", resourceType: "ticketing", locale: "fr" });
287
+ // or per-request:
288
+ const tickets = await client.fetchTickets({ locale: "rw" });
289
+ ```
329
290
 
330
- # Build (ESM + CJS)
331
- npm run build
291
+ ## Build
332
292
 
333
- # Run tests
334
- npm test
293
+ The package ships ESM and CJS builds with TypeScript declarations:
335
294
 
336
- # Lint
337
- npm run lint
295
+ ```bash
296
+ npm run build # Build both ESM and CJS
297
+ npm test # Run tests (212 tests, 100% coverage)
338
298
  ```
339
299
 
340
300
  ## License
341
301
 
342
- MIT
302
+ ISC
@@ -1,26 +1,65 @@
1
- import type { EventFormConfig, FormData, Ticket } from "../types/index.js";
1
+ import type { EventFormConfig, FormData, IntegrationResult, ResolvedIntegration, SubmissionResponse, Ticket } from "../types/index.js";
2
2
  export declare class EventFormClient {
3
3
  private readonly apiBase;
4
4
  private readonly apiKey;
5
5
  private readonly resourceType;
6
6
  private readonly messages;
7
+ private readonly origin;
8
+ private readonly timeout;
9
+ private readonly retryConfig;
10
+ private readonly cacheConfig;
11
+ private readonly noCache;
12
+ private readonly interceptors;
13
+ private readonly mastercardCheckoutUrl;
14
+ private readonly merchantName;
15
+ private readonly cache;
7
16
  private locale;
8
17
  constructor(config: EventFormConfig);
9
18
  setLocale(locale: string): void;
10
19
  getLocale(): string | undefined;
20
+ /**
21
+ * Preload the Mastercard Checkout.js script so it's ready when payment starts.
22
+ * Call this early (e.g. on page load) to avoid skeleton delay.
23
+ */
24
+ preloadCheckoutScript(): Promise<void>;
25
+ clearCache(): void;
26
+ private getCached;
27
+ private setCache;
28
+ private applyRequestInterceptor;
29
+ private applyResponseInterceptor;
30
+ private applyErrorInterceptor;
31
+ private throwMapped;
32
+ private cachedGet;
33
+ private isRetryable;
34
+ private executeRequest;
11
35
  fetchTickets(options?: {
12
36
  locale?: string;
13
37
  name?: string;
14
38
  }): Promise<Ticket[]>;
15
39
  fetchTicketById(id: number, locale?: string): Promise<Ticket>;
40
+ fetchPublicTicket(id: number, locale?: string): Promise<Ticket>;
16
41
  fetchLanguages(): Promise<string[]>;
17
42
  fetchForm(ticketId: number, locale?: string): Promise<FormData>;
18
43
  authorizeUpload(formId: number, fieldId: string, file: File, locale?: string): Promise<string>;
19
44
  uploadFile(formId: number, token: string, file: File, locale?: string): Promise<string>;
20
- submitForm(formId: number, data: Record<string, unknown>, context: {
45
+ /**
46
+ * Submits the form to the backend first, then conditionally runs payment
47
+ * integrations if the response indicates payment is required.
48
+ *
49
+ * If an integration fails after submission, the failure is returned in the
50
+ * result (not thrown), since the submission is already saved on the backend.
51
+ */
52
+ submitForm(form: FormData, data: Record<string, unknown>, context: {
21
53
  eventId: number;
22
54
  ticketId: number;
23
55
  locale?: string;
24
- }): Promise<void>;
56
+ attendanceType?: "HYBRID" | "PHYSICAL" | "VIRTUAL" | null;
57
+ containerId?: string;
58
+ }): Promise<{
59
+ submission: SubmissionResponse;
60
+ integrations: Array<ResolvedIntegration & {
61
+ result: IntegrationResult;
62
+ }>;
63
+ }>;
25
64
  }
26
65
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,eAAe,EACf,QAAQ,EACR,MAAM,EACP,MAAM,mBAAmB,CAAC;AAmC3B,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,MAAM,CAAqB;gBAEvB,MAAM,EAAE,eAAe;IAQnC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,SAAS,IAAI,MAAM,GAAG,SAAS;IAIzB,YAAY,CAAC,OAAO,CAAC,EAAE;QAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAuBf,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiB7D,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAoBnC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAiB/D,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC;IAyBZ,UAAU,CACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC;IAqBZ,UAAU,CACd,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GACA,OAAO,CAAC,IAAI,CAAC;CAuBjB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"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"}