@flopay/vue 0.0.0-stage → 1.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -2
- package/dist/card-setup-entry.cjs +614 -0
- package/dist/card-setup-entry.d.cts +160 -0
- package/dist/card-setup-entry.d.ts +160 -0
- package/dist/card-setup-entry.mjs +10 -0
- package/dist/chunk-2PLBNCM6.mjs +332 -0
- package/dist/chunk-DUU6SMKP.mjs +97 -0
- package/dist/chunk-VXYNYMHI.mjs +833 -0
- package/dist/chunk-W52CQTJI.mjs +527 -0
- package/dist/hosted-setup-jpaaXDFA.d.cts +33 -0
- package/dist/hosted-setup-jpaaXDFA.d.ts +33 -0
- package/dist/index.cjs +4987 -0
- package/dist/index.d.cts +1940 -0
- package/dist/index.d.ts +1940 -0
- package/dist/index.mjs +3196 -0
- package/dist/payment-method-setup-entry.cjs +1809 -0
- package/dist/payment-method-setup-entry.d.cts +156 -0
- package/dist/payment-method-setup-entry.d.ts +156 -0
- package/dist/payment-method-setup-entry.mjs +7 -0
- package/dist/payment-method-setup-paypal-XPSU4CHA.mjs +148 -0
- package/dist/stripe-elements-QGT45VIE.mjs +6 -0
- package/package.json +60 -3
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/card-setup-entry.ts
|
|
21
|
+
var card_setup_entry_exports = {};
|
|
22
|
+
__export(card_setup_entry_exports, {
|
|
23
|
+
FloPayCardSetup: () => FloPayCardSetup,
|
|
24
|
+
FloPayCardSetupError: () => FloPayCardSetupError
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(card_setup_entry_exports);
|
|
27
|
+
|
|
28
|
+
// src/flopay-card-setup.ts
|
|
29
|
+
var import_shared3 = require("@flopay/shared");
|
|
30
|
+
var import_vue4 = require("vue");
|
|
31
|
+
|
|
32
|
+
// src/hosted-setup.ts
|
|
33
|
+
var import_card_setup = require("@flopay/js/card-setup");
|
|
34
|
+
var import_shared = require("@flopay/shared");
|
|
35
|
+
var import_vue2 = require("vue");
|
|
36
|
+
|
|
37
|
+
// src/processing-overlay.ts
|
|
38
|
+
var import_vue = require("vue");
|
|
39
|
+
var PROCESSING_OVERLAY_SUCCESS_DELAY_MS = 600;
|
|
40
|
+
var PROCESSING_OVERLAY_ERROR_DELAY_MS = 400;
|
|
41
|
+
var NEUTRAL_THEME = {
|
|
42
|
+
panel: { background: "white" },
|
|
43
|
+
spinnerTrackColor: "#e5e7eb",
|
|
44
|
+
spinnerAccentColor: "#4A49FF",
|
|
45
|
+
labelColors: { processing: "#374151", success: "#16a34a", error: "#dc2626" },
|
|
46
|
+
noteColor: "#6b7280"
|
|
47
|
+
};
|
|
48
|
+
var KEYFRAMES_ID = "flopay-processing-overlay-keyframes";
|
|
49
|
+
var KEYFRAMES = [
|
|
50
|
+
"@keyframes flopay-spin { to { transform: rotate(360deg); } }",
|
|
51
|
+
"@keyframes flopay-pop { 0% { transform: scale(0); } 100% { transform: scale(1); } }",
|
|
52
|
+
"@keyframes flopay-draw { to { stroke-dashoffset: 0; } }",
|
|
53
|
+
"@keyframes flopay-shake { 0%,100% { transform: translateX(0); } 20%,60% { transform: translateX(-4px); } 40%,80% { transform: translateX(4px); } }"
|
|
54
|
+
].join("\n");
|
|
55
|
+
function ensureKeyframes() {
|
|
56
|
+
if (typeof document === "undefined" || document.getElementById(KEYFRAMES_ID)) return;
|
|
57
|
+
const style = document.createElement("style");
|
|
58
|
+
style.id = KEYFRAMES_ID;
|
|
59
|
+
style.textContent = KEYFRAMES;
|
|
60
|
+
document.head.appendChild(style);
|
|
61
|
+
}
|
|
62
|
+
var SVG = {
|
|
63
|
+
"aria-hidden": "true",
|
|
64
|
+
width: "48",
|
|
65
|
+
height: "48",
|
|
66
|
+
viewBox: "0 0 24 24",
|
|
67
|
+
fill: "none"
|
|
68
|
+
};
|
|
69
|
+
function statusIcon(status, theme) {
|
|
70
|
+
if (status === "processing") {
|
|
71
|
+
return (0, import_vue.h)("svg", { ...SVG, style: { animation: "flopay-spin 0.8s linear infinite" } }, [
|
|
72
|
+
(0, import_vue.h)("circle", {
|
|
73
|
+
cx: "12",
|
|
74
|
+
cy: "12",
|
|
75
|
+
r: "10",
|
|
76
|
+
stroke: theme.spinnerTrackColor,
|
|
77
|
+
"stroke-width": "3"
|
|
78
|
+
}),
|
|
79
|
+
(0, import_vue.h)("path", { d: "M4 12a8 8 0 018-8v3a5 5 0 00-5 5H4z", fill: theme.spinnerAccentColor })
|
|
80
|
+
]);
|
|
81
|
+
}
|
|
82
|
+
if (status === "success") {
|
|
83
|
+
return (0, import_vue.h)("div", { style: { animation: "flopay-pop 0.4s cubic-bezier(0.34,1.56,0.64,1)" } }, [
|
|
84
|
+
(0, import_vue.h)("svg", SVG, [
|
|
85
|
+
(0, import_vue.h)("circle", { cx: "12", cy: "12", r: "11", fill: "#22c55e" }),
|
|
86
|
+
(0, import_vue.h)("path", {
|
|
87
|
+
d: "M7 12.5l3 3 7-7",
|
|
88
|
+
stroke: "white",
|
|
89
|
+
"stroke-width": "2.5",
|
|
90
|
+
"stroke-linecap": "round",
|
|
91
|
+
"stroke-linejoin": "round",
|
|
92
|
+
style: {
|
|
93
|
+
strokeDasharray: 20,
|
|
94
|
+
strokeDashoffset: 20,
|
|
95
|
+
animation: "flopay-draw 0.4s 0.15s ease forwards"
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
])
|
|
99
|
+
]);
|
|
100
|
+
}
|
|
101
|
+
return (0, import_vue.h)("div", { style: { animation: "flopay-shake 0.4s ease" } }, [
|
|
102
|
+
(0, import_vue.h)("svg", SVG, [
|
|
103
|
+
(0, import_vue.h)("circle", { cx: "12", cy: "12", r: "11", fill: "#ef4444" }),
|
|
104
|
+
(0, import_vue.h)("path", {
|
|
105
|
+
d: "M8 8l8 8M16 8l-8 8",
|
|
106
|
+
stroke: "white",
|
|
107
|
+
"stroke-width": "2.5",
|
|
108
|
+
"stroke-linecap": "round",
|
|
109
|
+
style: {
|
|
110
|
+
strokeDasharray: 12,
|
|
111
|
+
strokeDashoffset: 12,
|
|
112
|
+
animation: "flopay-draw 0.3s 0.1s ease forwards"
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
])
|
|
116
|
+
]);
|
|
117
|
+
}
|
|
118
|
+
var ProcessingOverlay = (0, import_vue.defineComponent)({
|
|
119
|
+
name: "FloPayProcessingOverlay",
|
|
120
|
+
props: {
|
|
121
|
+
status: { type: String, required: true },
|
|
122
|
+
errorMessage: { type: String, default: null },
|
|
123
|
+
processingLabel: { type: String, default: "PROCESSING..." },
|
|
124
|
+
successLabel: { type: String, default: "PAYMENT SUCCESSFUL" },
|
|
125
|
+
errorLabel: { type: String, default: "PAYMENT FAILED" },
|
|
126
|
+
/** Success sub-note; `null` omits it (surfaces that do not redirect). */
|
|
127
|
+
successNote: {
|
|
128
|
+
type: String,
|
|
129
|
+
default: "You will be automatically redirected, do not close or navigate away from this window."
|
|
130
|
+
},
|
|
131
|
+
theme: { type: Object, default: void 0 }
|
|
132
|
+
},
|
|
133
|
+
setup(props) {
|
|
134
|
+
(0, import_vue.onMounted)(ensureKeyframes);
|
|
135
|
+
return () => {
|
|
136
|
+
const theme = props.theme ?? NEUTRAL_THEME;
|
|
137
|
+
const noteStyle = {
|
|
138
|
+
fontSize: "13px",
|
|
139
|
+
color: theme.noteColor,
|
|
140
|
+
fontWeight: 400,
|
|
141
|
+
maxWidth: "260px",
|
|
142
|
+
lineHeight: 1.4,
|
|
143
|
+
margin: 0
|
|
144
|
+
};
|
|
145
|
+
const label = {
|
|
146
|
+
processing: props.processingLabel,
|
|
147
|
+
success: props.successLabel,
|
|
148
|
+
error: props.errorLabel
|
|
149
|
+
}[props.status];
|
|
150
|
+
const note = { processing: null, success: props.successNote, error: props.errorMessage }[props.status];
|
|
151
|
+
return (0, import_vue.h)(
|
|
152
|
+
"div",
|
|
153
|
+
{
|
|
154
|
+
"data-testid": "flopay-processing-overlay",
|
|
155
|
+
"data-status": props.status,
|
|
156
|
+
// The attribute the Vue setup surfaces' overlay already carried.
|
|
157
|
+
"data-state": props.status,
|
|
158
|
+
role: "dialog",
|
|
159
|
+
"aria-modal": "true",
|
|
160
|
+
style: {
|
|
161
|
+
position: "fixed",
|
|
162
|
+
inset: 0,
|
|
163
|
+
background: "rgba(0,0,0,0.35)",
|
|
164
|
+
display: "flex",
|
|
165
|
+
alignItems: "center",
|
|
166
|
+
justifyContent: "center",
|
|
167
|
+
zIndex: 1e3,
|
|
168
|
+
backdropFilter: "blur(2px)"
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
[
|
|
172
|
+
(0, import_vue.h)(
|
|
173
|
+
"div",
|
|
174
|
+
{
|
|
175
|
+
"data-testid": "flopay-processing-overlay-panel",
|
|
176
|
+
style: {
|
|
177
|
+
borderRadius: "12px",
|
|
178
|
+
boxShadow: "0 8px 32px rgba(0,0,0,0.18)",
|
|
179
|
+
...theme.panel,
|
|
180
|
+
padding: "2rem 2.5rem",
|
|
181
|
+
textAlign: "center",
|
|
182
|
+
minWidth: "240px",
|
|
183
|
+
display: "flex",
|
|
184
|
+
flexDirection: "column",
|
|
185
|
+
alignItems: "center",
|
|
186
|
+
gap: "16px"
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
[
|
|
190
|
+
(0, import_vue.h)("div", { style: { width: "48px", height: "48px", position: "relative" } }, [
|
|
191
|
+
statusIcon(props.status, theme)
|
|
192
|
+
]),
|
|
193
|
+
(0, import_vue.h)(
|
|
194
|
+
"span",
|
|
195
|
+
{
|
|
196
|
+
"data-testid": "flopay-processing-overlay-label",
|
|
197
|
+
style: {
|
|
198
|
+
fontSize: "14px",
|
|
199
|
+
fontWeight: 600,
|
|
200
|
+
letterSpacing: "0.05em",
|
|
201
|
+
color: theme.labelColors[props.status]
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
label
|
|
205
|
+
),
|
|
206
|
+
note ? (0, import_vue.h)("p", { style: noteStyle }, note) : null
|
|
207
|
+
]
|
|
208
|
+
)
|
|
209
|
+
]
|
|
210
|
+
);
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// src/hosted-setup.ts
|
|
216
|
+
var FloPayCardSetupError = class extends import_shared.FloPayError {
|
|
217
|
+
constructor(message, type, options) {
|
|
218
|
+
super(message, type, options);
|
|
219
|
+
this.name = "FloPayCardSetupError";
|
|
220
|
+
this.retryable = options.retryable;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
function asCardSetupError(error, overrides = {}) {
|
|
224
|
+
const source = error instanceof import_shared.FloPayError ? error : void 0;
|
|
225
|
+
const statusCode = source?.statusCode;
|
|
226
|
+
const retryable = overrides.retryable ?? (source?.type === "network_error" || source?.type === "rate_limit_error" || typeof statusCode === "number" && statusCode >= 500 || source?.code === "vault_capture_timeout" || !source);
|
|
227
|
+
return new FloPayCardSetupError(
|
|
228
|
+
source?.message ?? (error instanceof Error ? error.message : "Failed to load the secure card form."),
|
|
229
|
+
source?.type ?? "api_error",
|
|
230
|
+
{
|
|
231
|
+
code: overrides.code ?? source?.code ?? "card_setup_load_failed",
|
|
232
|
+
retryable,
|
|
233
|
+
...source?.param ? { param: source.param } : {},
|
|
234
|
+
...statusCode === void 0 ? {} : { statusCode }
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
function useCardSetupTheme(source) {
|
|
239
|
+
const resolved = (0, import_vue2.computed)(
|
|
240
|
+
() => (0, import_shared.resolveCardSetupTheme)({
|
|
241
|
+
theme: source.theme ?? "modern-light",
|
|
242
|
+
appearance: source.appearance,
|
|
243
|
+
buttonsStyles: source.buttonsStyles
|
|
244
|
+
})
|
|
245
|
+
);
|
|
246
|
+
const vaultTheme = (0, import_vue2.computed)(() => resolved.value.vaultTheme);
|
|
247
|
+
const surfaceStyle = (0, import_vue2.computed)(
|
|
248
|
+
() => (0, import_shared.mergeCardSetupSurface)(resolved.value.surface, source.containerStyle)
|
|
249
|
+
);
|
|
250
|
+
const overlayTheme = (0, import_vue2.computed)(() => resolved.value.overlayTheme);
|
|
251
|
+
const appearance = (0, import_vue2.computed)(() => resolved.value.appearance);
|
|
252
|
+
return { vaultTheme, surfaceStyle, overlayTheme, appearance };
|
|
253
|
+
}
|
|
254
|
+
function useHostedSetup(props, emitters, options) {
|
|
255
|
+
const capture = (0, import_vue2.shallowRef)(null);
|
|
256
|
+
const vault = (0, import_vue2.shallowRef)(null);
|
|
257
|
+
const session = (0, import_vue2.shallowRef)(null);
|
|
258
|
+
const loadError = (0, import_vue2.ref)(null);
|
|
259
|
+
let active = true;
|
|
260
|
+
let terminal = false;
|
|
261
|
+
let completed = false;
|
|
262
|
+
let submissionInFlight = false;
|
|
263
|
+
let clearTimer = null;
|
|
264
|
+
const offs = [];
|
|
265
|
+
const sessionId = () => props.sessionId ?? "";
|
|
266
|
+
const showOverlay = (state) => {
|
|
267
|
+
if (clearTimer) clearTimeout(clearTimer);
|
|
268
|
+
clearTimer = null;
|
|
269
|
+
emitters.overlay(state);
|
|
270
|
+
};
|
|
271
|
+
const holdFailure = (message) => {
|
|
272
|
+
showOverlay({ status: "error", message });
|
|
273
|
+
clearTimer = setTimeout(() => {
|
|
274
|
+
clearTimer = null;
|
|
275
|
+
if (active) emitters.overlay(null);
|
|
276
|
+
}, PROCESSING_OVERLAY_ERROR_DELAY_MS);
|
|
277
|
+
};
|
|
278
|
+
const bind = (adapter) => {
|
|
279
|
+
submissionInFlight = false;
|
|
280
|
+
offs.push(
|
|
281
|
+
adapter.on("submitting", () => {
|
|
282
|
+
submissionInFlight = true;
|
|
283
|
+
showOverlay({ status: "processing", message: null });
|
|
284
|
+
}),
|
|
285
|
+
adapter.on("complete", (event) => {
|
|
286
|
+
terminal = true;
|
|
287
|
+
submissionInFlight = false;
|
|
288
|
+
showOverlay({ status: "success", message: null });
|
|
289
|
+
setTimeout(() => {
|
|
290
|
+
if (completed) return;
|
|
291
|
+
completed = true;
|
|
292
|
+
(0, import_shared.invokeMerchantCallback)(
|
|
293
|
+
() => emitters.complete({
|
|
294
|
+
status: "succeeded",
|
|
295
|
+
sessionId: sessionId(),
|
|
296
|
+
...event.paymentMethod ? { paymentMethod: event.paymentMethod } : {}
|
|
297
|
+
})
|
|
298
|
+
);
|
|
299
|
+
if (active) emitters.overlay(null);
|
|
300
|
+
}, PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
|
|
301
|
+
}),
|
|
302
|
+
adapter.on("decline", (event) => {
|
|
303
|
+
terminal = true;
|
|
304
|
+
submissionInFlight = false;
|
|
305
|
+
holdFailure(event.message ?? null);
|
|
306
|
+
(0, import_shared.invokeMerchantCallback)(
|
|
307
|
+
() => emitters.decline({
|
|
308
|
+
status: "declined",
|
|
309
|
+
sessionId: sessionId(),
|
|
310
|
+
...event.declineReason ? { reason: event.declineReason } : {},
|
|
311
|
+
...event.message ? { message: event.message } : {}
|
|
312
|
+
})
|
|
313
|
+
);
|
|
314
|
+
}),
|
|
315
|
+
// Closing the bank's authentication window is not an outcome: the hosted
|
|
316
|
+
// form keeps polling and may still report one. Drop the overlay but keep
|
|
317
|
+
// the submission in flight, so a late failure still shows "CARD NOT SAVED".
|
|
318
|
+
adapter.on("challenge_dismissed", () => {
|
|
319
|
+
showOverlay(null);
|
|
320
|
+
})
|
|
321
|
+
);
|
|
322
|
+
};
|
|
323
|
+
(0, import_vue2.onMounted)(async () => {
|
|
324
|
+
const billingApiUrl = (0, import_shared.resolveBillingApiUrl)(props.billingApiUrl);
|
|
325
|
+
const api = new import_card_setup.PaymentAPI(billingApiUrl, { telemetry: props.telemetry });
|
|
326
|
+
try {
|
|
327
|
+
if (!sessionId().trim()) {
|
|
328
|
+
throw new import_shared.FloPayError("A setup surface requires a sessionId.", "validation_error", {
|
|
329
|
+
code: "MissingCheckoutSessionId",
|
|
330
|
+
param: "sessionId"
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
if (!props.nonce?.trim()) {
|
|
334
|
+
throw new import_shared.FloPayError("A setup surface requires a session nonce.", "validation_error", {
|
|
335
|
+
code: "MissingCheckoutSessionToken",
|
|
336
|
+
param: "nonce"
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
const result = await api.getUnifiedCheckoutSession(sessionId(), props.nonce);
|
|
340
|
+
const read = result.data.session;
|
|
341
|
+
if (!read || !(0, import_shared.isCardSetupCheckoutSession)(read)) {
|
|
342
|
+
throw new import_shared.FloPayError(
|
|
343
|
+
"Only a zero-amount, productless setup session is accepted.",
|
|
344
|
+
"validation_error",
|
|
345
|
+
{ code: "InvalidCardSetupSession", param: "sessionId" }
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
if (!active) return;
|
|
349
|
+
session.value = result;
|
|
350
|
+
if (!options.requireVault(result)) return;
|
|
351
|
+
let block = read.vault;
|
|
352
|
+
if (!(0, import_shared.isMountableVaultBlock)(block))
|
|
353
|
+
block = await api.getVaultCapture(sessionId(), props.nonce);
|
|
354
|
+
const mount = (0, import_shared.resolveVaultMountOptions)(block, {
|
|
355
|
+
billingApiUrl,
|
|
356
|
+
sessionId: sessionId(),
|
|
357
|
+
nonce: props.nonce
|
|
358
|
+
});
|
|
359
|
+
if (!mount) {
|
|
360
|
+
throw new import_shared.FloPayError(
|
|
361
|
+
"FloPay: this setup session has no vault card capability. Upgrade the billing backend integration.",
|
|
362
|
+
"api_error",
|
|
363
|
+
{ code: "UnsupportedBackendVaultCapability" }
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
if (!active) return;
|
|
367
|
+
const adapter = new import_card_setup.PciVaultCardCapture({
|
|
368
|
+
sessionId: sessionId(),
|
|
369
|
+
operation: "card_setup",
|
|
370
|
+
telemetry: props.telemetry
|
|
371
|
+
});
|
|
372
|
+
bind(adapter);
|
|
373
|
+
vault.value = mount;
|
|
374
|
+
capture.value = adapter;
|
|
375
|
+
} catch (error) {
|
|
376
|
+
if (!active) return;
|
|
377
|
+
terminal = true;
|
|
378
|
+
const failure = asCardSetupError(error);
|
|
379
|
+
loadError.value = failure;
|
|
380
|
+
(0, import_shared.invokeMerchantCallback)(() => emitters.error(failure));
|
|
381
|
+
} finally {
|
|
382
|
+
api.destroy();
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
(0, import_vue2.onBeforeUnmount)(() => {
|
|
386
|
+
active = false;
|
|
387
|
+
if (clearTimer) clearTimeout(clearTimer);
|
|
388
|
+
clearTimer = null;
|
|
389
|
+
for (const off of offs.splice(0)) off();
|
|
390
|
+
if (!terminal && sessionId()) {
|
|
391
|
+
(0, import_shared.invokeMerchantCallback)(
|
|
392
|
+
() => emitters.cancel({ status: "cancelled", sessionId: sessionId() })
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
return {
|
|
397
|
+
capture,
|
|
398
|
+
vault,
|
|
399
|
+
session,
|
|
400
|
+
loadError,
|
|
401
|
+
settle: () => {
|
|
402
|
+
terminal = true;
|
|
403
|
+
},
|
|
404
|
+
widgetFailed: (message) => {
|
|
405
|
+
if (!submissionInFlight) return;
|
|
406
|
+
submissionInFlight = false;
|
|
407
|
+
holdFailure(message);
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// src/vault-card-fields.ts
|
|
413
|
+
var import_shared2 = require("@flopay/shared");
|
|
414
|
+
var import_vue3 = require("vue");
|
|
415
|
+
var labelledCaptures = /* @__PURE__ */ new WeakSet();
|
|
416
|
+
var VaultCardFields = (0, import_vue3.defineComponent)({
|
|
417
|
+
name: "VaultCardFields",
|
|
418
|
+
props: {
|
|
419
|
+
capture: { type: Object, default: void 0 },
|
|
420
|
+
html: { type: String, default: void 0 },
|
|
421
|
+
messageToken: { type: String, default: void 0 },
|
|
422
|
+
expectedOrigin: { type: String, default: void 0 },
|
|
423
|
+
verificationRequired: { type: Boolean, default: void 0 },
|
|
424
|
+
theme: { type: Object, default: void 0 },
|
|
425
|
+
submitLabel: { type: String, default: void 0 },
|
|
426
|
+
containerStyle: { type: Object, default: void 0 }
|
|
427
|
+
},
|
|
428
|
+
emits: {
|
|
429
|
+
ready: () => true,
|
|
430
|
+
error: (_message) => true,
|
|
431
|
+
validation: (_message) => true
|
|
432
|
+
},
|
|
433
|
+
setup(props, { emit }) {
|
|
434
|
+
const container = (0, import_vue3.ref)(null);
|
|
435
|
+
let teardown = null;
|
|
436
|
+
let appliedLabel;
|
|
437
|
+
let appliedTheme = null;
|
|
438
|
+
const mountWidget = () => {
|
|
439
|
+
teardown?.();
|
|
440
|
+
teardown = null;
|
|
441
|
+
const el = container.value;
|
|
442
|
+
const { capture, html } = props;
|
|
443
|
+
if (!el || !capture || !html) return;
|
|
444
|
+
let active = true;
|
|
445
|
+
let readyEmitted = false;
|
|
446
|
+
const emitReadyOnce = () => {
|
|
447
|
+
if (!active || readyEmitted) return;
|
|
448
|
+
readyEmitted = true;
|
|
449
|
+
(0, import_shared2.invokeMerchantCallback)(() => emit("ready"));
|
|
450
|
+
};
|
|
451
|
+
const offReady = capture.on("ready", emitReadyOnce);
|
|
452
|
+
const offError = capture.on("error", (event) => {
|
|
453
|
+
const message = event.message ?? "There was a problem loading the secure card form.";
|
|
454
|
+
(0, import_shared2.invokeMerchantCallback)(() => emit("error", message));
|
|
455
|
+
});
|
|
456
|
+
const offValidation = capture.on("validation", (event) => {
|
|
457
|
+
(0, import_shared2.invokeMerchantCallback)(() => emit("validation", event.message ?? null));
|
|
458
|
+
});
|
|
459
|
+
const label = props.submitLabel ?? void 0;
|
|
460
|
+
const labelDirective = label ?? (labelledCaptures.has(capture) ? null : void 0);
|
|
461
|
+
appliedLabel = label;
|
|
462
|
+
appliedTheme = props.theme ?? null;
|
|
463
|
+
if (label !== void 0) labelledCaptures.add(capture);
|
|
464
|
+
capture.mount(el, {
|
|
465
|
+
html,
|
|
466
|
+
...props.messageToken ? { messageToken: props.messageToken } : {},
|
|
467
|
+
...props.expectedOrigin ? { expectedOrigin: props.expectedOrigin } : {},
|
|
468
|
+
...props.verificationRequired ? { verificationRequired: true } : {},
|
|
469
|
+
...props.theme ? { theme: props.theme } : {},
|
|
470
|
+
...labelDirective === void 0 ? {} : { submitLabel: labelDirective }
|
|
471
|
+
}).then(emitReadyOnce).catch((error) => {
|
|
472
|
+
if (!active) return;
|
|
473
|
+
const message = error instanceof Error ? error.message : "Failed to load the secure card form.";
|
|
474
|
+
(0, import_shared2.invokeMerchantCallback)(() => emit("error", message));
|
|
475
|
+
});
|
|
476
|
+
teardown = () => {
|
|
477
|
+
active = false;
|
|
478
|
+
offReady();
|
|
479
|
+
offError();
|
|
480
|
+
offValidation();
|
|
481
|
+
capture.unmount();
|
|
482
|
+
};
|
|
483
|
+
};
|
|
484
|
+
(0, import_vue3.onMounted)(() => {
|
|
485
|
+
mountWidget();
|
|
486
|
+
(0, import_vue3.watch)(
|
|
487
|
+
() => [
|
|
488
|
+
props.capture,
|
|
489
|
+
props.html,
|
|
490
|
+
props.messageToken,
|
|
491
|
+
props.expectedOrigin,
|
|
492
|
+
props.verificationRequired
|
|
493
|
+
],
|
|
494
|
+
mountWidget
|
|
495
|
+
);
|
|
496
|
+
(0, import_vue3.watch)(
|
|
497
|
+
() => props.theme,
|
|
498
|
+
(theme) => {
|
|
499
|
+
if (theme === void 0) return;
|
|
500
|
+
if (theme === null && appliedTheme === null) return;
|
|
501
|
+
appliedTheme = theme;
|
|
502
|
+
props.capture?.applyTheme?.(theme);
|
|
503
|
+
}
|
|
504
|
+
);
|
|
505
|
+
(0, import_vue3.watch)(
|
|
506
|
+
() => props.submitLabel ?? void 0,
|
|
507
|
+
(label) => {
|
|
508
|
+
if (!props.capture || label === appliedLabel) return;
|
|
509
|
+
appliedLabel = label;
|
|
510
|
+
if (label !== void 0) labelledCaptures.add(props.capture);
|
|
511
|
+
props.capture.setSubmitLabel?.(label ?? null);
|
|
512
|
+
}
|
|
513
|
+
);
|
|
514
|
+
});
|
|
515
|
+
(0, import_vue3.onBeforeUnmount)(() => {
|
|
516
|
+
teardown?.();
|
|
517
|
+
teardown = null;
|
|
518
|
+
});
|
|
519
|
+
return () => (0, import_vue3.h)("div", {
|
|
520
|
+
ref: container,
|
|
521
|
+
"data-testid": "flopay-vault-card-fields",
|
|
522
|
+
style: props.containerStyle
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
// src/flopay-card-setup.ts
|
|
528
|
+
var FloPayCardSetup = (0, import_vue4.defineComponent)({
|
|
529
|
+
name: "FloPayCardSetup",
|
|
530
|
+
props: {
|
|
531
|
+
sessionId: { type: String, default: void 0 },
|
|
532
|
+
nonce: { type: String, default: void 0 },
|
|
533
|
+
billingApiUrl: { type: String, default: void 0 },
|
|
534
|
+
telemetry: { type: Boolean, default: void 0 },
|
|
535
|
+
theme: {
|
|
536
|
+
type: [String, Object],
|
|
537
|
+
default: "modern-light"
|
|
538
|
+
},
|
|
539
|
+
containerStyle: {
|
|
540
|
+
type: Object,
|
|
541
|
+
default: void 0
|
|
542
|
+
},
|
|
543
|
+
appearance: { type: Object, default: void 0 },
|
|
544
|
+
buttonsStyles: { type: Object, default: void 0 }
|
|
545
|
+
},
|
|
546
|
+
emits: {
|
|
547
|
+
ready: () => true,
|
|
548
|
+
complete: (_event) => true,
|
|
549
|
+
cancel: (_event) => true,
|
|
550
|
+
decline: (_event) => true,
|
|
551
|
+
validation: (_message) => true,
|
|
552
|
+
error: (_error) => true
|
|
553
|
+
},
|
|
554
|
+
setup(props, { emit, slots }) {
|
|
555
|
+
const overlay = (0, import_vue4.shallowRef)(null);
|
|
556
|
+
const setup = useHostedSetup(
|
|
557
|
+
props,
|
|
558
|
+
{
|
|
559
|
+
complete: (event) => emit("complete", event),
|
|
560
|
+
decline: (event) => emit("decline", event),
|
|
561
|
+
cancel: (event) => emit("cancel", event),
|
|
562
|
+
error: (error) => emit("error", error),
|
|
563
|
+
overlay: (state) => {
|
|
564
|
+
overlay.value = state;
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
{ requireVault: () => true }
|
|
568
|
+
);
|
|
569
|
+
const theme = useCardSetupTheme(props);
|
|
570
|
+
return () => {
|
|
571
|
+
if (setup.loadError.value) {
|
|
572
|
+
return (0, import_vue4.h)("div", { role: "alert" }, setup.loadError.value.message);
|
|
573
|
+
}
|
|
574
|
+
const capture = setup.capture.value;
|
|
575
|
+
const vault = setup.vault.value;
|
|
576
|
+
if (!capture || !vault?.html) return slots.loading?.() ?? null;
|
|
577
|
+
const state = overlay.value;
|
|
578
|
+
return [
|
|
579
|
+
state ? (0, import_vue4.h)(ProcessingOverlay, {
|
|
580
|
+
status: state.status,
|
|
581
|
+
errorMessage: state.message,
|
|
582
|
+
...(0, import_shared3.setupOverlayLabels)("card"),
|
|
583
|
+
successNote: null,
|
|
584
|
+
...theme.overlayTheme.value ? { theme: theme.overlayTheme.value } : {}
|
|
585
|
+
}) : null,
|
|
586
|
+
(0, import_vue4.h)(VaultCardFields, {
|
|
587
|
+
capture,
|
|
588
|
+
html: vault.html,
|
|
589
|
+
messageToken: vault.messageToken,
|
|
590
|
+
expectedOrigin: vault.expectedOrigin,
|
|
591
|
+
verificationRequired: vault.verificationRequired,
|
|
592
|
+
theme: theme.vaultTheme.value,
|
|
593
|
+
containerStyle: theme.surfaceStyle.value,
|
|
594
|
+
onReady: () => (0, import_shared3.invokeMerchantCallback)(() => emit("ready")),
|
|
595
|
+
onValidation: (message) => (0, import_shared3.invokeMerchantCallback)(() => emit("validation", message)),
|
|
596
|
+
onError: (message) => {
|
|
597
|
+
if (!message) return;
|
|
598
|
+
setup.widgetFailed(message);
|
|
599
|
+
const error = asCardSetupError(new Error(message), {
|
|
600
|
+
code: "card_setup_widget_failed",
|
|
601
|
+
retryable: true
|
|
602
|
+
});
|
|
603
|
+
(0, import_shared3.invokeMerchantCallback)(() => emit("error", error));
|
|
604
|
+
}
|
|
605
|
+
})
|
|
606
|
+
];
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
611
|
+
0 && (module.exports = {
|
|
612
|
+
FloPayCardSetup,
|
|
613
|
+
FloPayCardSetupError
|
|
614
|
+
});
|