orderopia-ordering-api-client-vue 0.0.3 → 0.0.5
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/dist/index.cjs +9 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -55,6 +55,7 @@ function useBasket() {
|
|
|
55
55
|
var import_vue2 = require("vue");
|
|
56
56
|
|
|
57
57
|
// src/opayo/opayo3dsManager.ts
|
|
58
|
+
var import_orderopia_ordering_api_client2 = require("orderopia-ordering-api-client");
|
|
58
59
|
function isBrowser() {
|
|
59
60
|
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
60
61
|
}
|
|
@@ -126,6 +127,9 @@ function hiddenInput(name, value) {
|
|
|
126
127
|
inp.value = value == null ? "" : String(value);
|
|
127
128
|
return inp;
|
|
128
129
|
}
|
|
130
|
+
function getChallengeRedirectUri() {
|
|
131
|
+
return (0, import_orderopia_ordering_api_client2.isOrderopiaDevMode)() ? "https://api-test.orderopia.com/Transactions/3ds/Challenge" : "https://api.orderopia.com/Transactions/3ds/Challenge";
|
|
132
|
+
}
|
|
129
133
|
var onOpayoCancelled;
|
|
130
134
|
function initializeIframe(responseType, acsUrl, pReq, cReq, redirectUri, transactionId) {
|
|
131
135
|
if (!isBrowser()) return;
|
|
@@ -177,8 +181,9 @@ function initializeIframe(responseType, acsUrl, pReq, cReq, redirectUri, transac
|
|
|
177
181
|
form.appendChild(hiddenInput("threeDSSessionData", transactionId));
|
|
178
182
|
}
|
|
179
183
|
} else {
|
|
184
|
+
const termUrl = redirectUri || "";
|
|
180
185
|
form.appendChild(hiddenInput("PaReq", pReq || ""));
|
|
181
|
-
form.appendChild(hiddenInput("TermUrl",
|
|
186
|
+
form.appendChild(hiddenInput("TermUrl", termUrl));
|
|
182
187
|
form.appendChild(hiddenInput("MD", transactionId || ""));
|
|
183
188
|
}
|
|
184
189
|
form.submit();
|
|
@@ -187,7 +192,7 @@ function initializeIframe(responseType, acsUrl, pReq, cReq, redirectUri, transac
|
|
|
187
192
|
document.body.removeChild(form);
|
|
188
193
|
} catch {
|
|
189
194
|
}
|
|
190
|
-
},
|
|
195
|
+
}, 1e6);
|
|
191
196
|
}
|
|
192
197
|
function closeOpayoIframe() {
|
|
193
198
|
if (!isBrowser()) return;
|
|
@@ -240,7 +245,8 @@ function run3DSecure(args) {
|
|
|
240
245
|
onOpened?.();
|
|
241
246
|
} catch {
|
|
242
247
|
}
|
|
243
|
-
|
|
248
|
+
const termUrl = redirectUri ?? getChallengeRedirectUri();
|
|
249
|
+
initializeIframe(responseType, acsUrl, pReq, cReq, termUrl, transactionId);
|
|
244
250
|
});
|
|
245
251
|
}
|
|
246
252
|
function receiveOpayoResponse(message) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/composables/useBasket.ts","../src/composables/useOpayo3ds.ts","../src/opayo/opayo3dsManager.ts","../src/install.ts"],"sourcesContent":["// src/index.ts\r\nexport { useBasket } from './composables/useBasket'\r\nexport { useOpayo3ds } from './composables/useOpayo3ds'\r\nexport { receiveOpayoResponse } from './opayo/opayo3dsManager'\r\nexport { OrderopiaVuePlugin } from './install'\r\n","// src/composables/useBasket.ts\r\nimport { ref, computed, onScopeDispose } from 'vue'\r\nimport {\r\n basketManager,\r\n type BasketState\r\n} from 'orderopia-ordering-api-client'\r\n\r\nexport function useBasket() {\r\n // Start with current basket immediately\r\n const basket = ref<BasketState>(basketManager.getBasket())\r\n\r\n // Subscribe immediately (NOT in onMounted)\r\n const unsubscribe = basketManager.subscribe(state => {\r\n basket.value = state\r\n })\r\n\r\n // Auto-cleanup when the component/composable scope is destroyed\r\n onScopeDispose(() => {\r\n unsubscribe()\r\n })\r\n\r\n const totalQuantity = computed(() =>\r\n basket.value.items.reduce((sum, i) => sum + (i.quantity ?? 0), 0)\r\n )\r\n\r\n return {\r\n basket,\r\n totalQuantity,\r\n\r\n // pass-through helpers (nice DX)\r\n addToBasket: basketManager.addToBasket.bind(basketManager),\r\n removeFromBasket: basketManager.removeFromBasket.bind(basketManager),\r\n clearBasket: basketManager.clearBasket.bind(basketManager)\r\n }\r\n}\r\n","// src/composables/useOpayo3ds.ts\r\nimport { ref, onScopeDispose } from 'vue'\r\nimport { run3DSecure, closeOpayoIframe, type Run3DSecureArgs } from '../opayo/opayo3dsManager'\r\n\r\nexport function useOpayo3ds() {\r\n const isOpen = ref(false)\r\n const isRunning = ref(false)\r\n\r\n let disposed = false\r\n\r\n onScopeDispose(() => {\r\n disposed = true\r\n isOpen.value = false\r\n isRunning.value = false\r\n closeOpayoIframe()\r\n })\r\n\r\n async function run(args: Run3DSecureArgs) {\r\n if (disposed) return false\r\n\r\n isOpen.value = true\r\n isRunning.value = true\r\n\r\n try {\r\n const result = await run3DSecure({\r\n ...args,\r\n onOpened: () => {\r\n if (disposed) return\r\n isOpen.value = true\r\n args.onOpened?.()\r\n },\r\n onClosed: () => {\r\n if (disposed) return\r\n isOpen.value = false\r\n args.onClosed?.()\r\n },\r\n onCancelled: () => {\r\n if (disposed) return\r\n isOpen.value = false\r\n args.onCancelled?.()\r\n }\r\n })\r\n\r\n return result\r\n } finally {\r\n if (!disposed) {\r\n isRunning.value = false\r\n }\r\n }\r\n }\r\n\r\n function close() {\r\n isOpen.value = false\r\n isRunning.value = false\r\n closeOpayoIframe()\r\n }\r\n\r\n return {\r\n isOpen,\r\n isRunning,\r\n run,\r\n close\r\n }\r\n}\r\n","// src/opayo/opayo3dsManager.ts\r\ntype ResponseType = 'CHALLENGE' | 'FALLBACK'\r\n\r\nfunction isBrowser() {\r\n return typeof window !== 'undefined' && typeof document !== 'undefined'\r\n}\r\n\r\nfunction ensureThreedsContainer() {\r\n if (!isBrowser()) return null\r\n\r\n let el = document.getElementById('threeds-container') as HTMLDivElement | null\r\n if (!el) {\r\n el = document.createElement('div')\r\n el.id = 'threeds-container'\r\n el.style.position = 'fixed'\r\n el.style.inset = '0'\r\n el.style.display = 'none'\r\n el.style.background = 'rgba(0,0,0,0.35)'\r\n el.style.zIndex = '99999'\r\n document.body.appendChild(el)\r\n }\r\n return el\r\n}\r\n\r\n// UTF-8 -> Base64URL (no padding)\r\nfunction utf8ToBase64Url(str: string) {\r\n const bytes = new TextEncoder().encode(str)\r\n let bin = ''\r\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i])\r\n const b64 = btoa(bin)\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '')\r\n}\r\n\r\n// Base64URL -> Base64 (and add padding)\r\nfunction toStdBase64(b64url: string) {\r\n let s = b64url.replace(/-/g, '+').replace(/_/g, '/')\r\n const pad = s.length % 4\r\n if (pad) s += '==='.slice(pad - 1)\r\n return s\r\n}\r\n\r\nfunction safeAtobMaybeJson(b64ish: string) {\r\n try {\r\n return atob(toStdBase64(b64ish))\r\n } catch {\r\n return null\r\n }\r\n}\r\n\r\n// Normalize creq to Base64URL without padding.\r\nfunction normalizeCreq(input: unknown) {\r\n if (input == null) return ''\r\n\r\n // Object -> JSON\r\n if (typeof input === 'object') {\r\n try {\r\n return utf8ToBase64Url(JSON.stringify(input))\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n let creq = String(input).trim()\r\n\r\n // If obviously JSON text\r\n if (/^\\s*\\{[\\s\\S]*\\}\\s*$/.test(creq)) {\r\n return utf8ToBase64Url(creq)\r\n }\r\n\r\n // If it looks URL-encoded, attempt a decode\r\n if (/%[0-9A-Fa-f]{2}/.test(creq) || creq.includes('%')) {\r\n try {\r\n creq = decodeURIComponent(creq)\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n // Remove whitespace, convert spaces to '+'\r\n creq = creq.replace(/\\s+/g, '').replace(/ /g, '+')\r\n\r\n // If decodes to JSON, re-encode properly as UTF-8 base64url\r\n const maybe = safeAtobMaybeJson(creq)\r\n if (maybe && maybe.charCodeAt(0) === 123 /* '{' */) {\r\n return utf8ToBase64Url(maybe)\r\n }\r\n\r\n // Otherwise normalize to base64url and strip padding\r\n creq = creq.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '')\r\n return creq\r\n}\r\n\r\nfunction hiddenInput(name: string, value: unknown) {\r\n const inp = document.createElement('input')\r\n inp.type = 'hidden'\r\n inp.name = name\r\n inp.value = value == null ? '' : String(value)\r\n return inp\r\n}\r\n\r\nexport type Run3DSecureArgs = {\r\n responseType: ResponseType\r\n acsUrl: string\r\n pReq?: string | null\r\n cReq?: unknown\r\n redirectUri?: string | null\r\n transactionId?: string | null\r\n\r\n onCancelled?: () => void\r\n onOpened?: () => void\r\n onClosed?: () => void\r\n}\r\n\r\nlet onOpayoCancelled: (() => void) | undefined\r\n\r\nfunction initializeIframe(\r\n responseType: ResponseType,\r\n acsUrl: string,\r\n pReq?: string | null,\r\n cReq?: unknown,\r\n redirectUri?: string | null,\r\n transactionId?: string | null\r\n) {\r\n if (!isBrowser()) return\r\n\r\n const container = ensureThreedsContainer()\r\n if (!container) return\r\n\r\n container.style.display = 'block'\r\n container.textContent = ''\r\n\r\n const panel = document.createElement('div')\r\n panel.style.position = 'absolute'\r\n panel.style.top = '50%'\r\n panel.style.left = '50%'\r\n panel.style.transform = 'translate(-50%, -50%)'\r\n panel.style.width = 'min(100%, 500px)'\r\n panel.style.height = 'min(100%, 600px)'\r\n panel.style.background = 'var(--background, #fff)'\r\n panel.style.borderRadius = '10px'\r\n panel.style.boxShadow = '0 10px 30px rgba(0,0,0,0.2)'\r\n panel.style.display = 'flex'\r\n panel.style.flexDirection = 'column'\r\n panel.style.overflow = 'hidden'\r\n container.appendChild(panel)\r\n\r\n const msg = document.createElement('div')\r\n msg.style.padding = '16px'\r\n msg.style.fontFamily = 'sans-serif'\r\n msg.style.textAlign = 'center'\r\n msg.innerHTML =\r\n '<div style=\"font-weight:600;\">We’re redirecting you to your bank to complete the payment.</div>' +\r\n '<div style=\"margin-top:6px;\">This will only take a moment. Please <u>do not</u> refresh the page.</div>'\r\n panel.appendChild(msg)\r\n\r\n const iframeWrap = document.createElement('div')\r\n iframeWrap.style.flex = '1'\r\n iframeWrap.style.borderTop = '1px solid rgba(0,0,0,0.06)'\r\n panel.appendChild(iframeWrap)\r\n\r\n const iframeName = 'threeds_frame_' + Math.random().toString(36).slice(2)\r\n const iframe = document.createElement('iframe')\r\n iframe.name = iframeName\r\n iframe.title = '3-D Secure Authentication'\r\n iframe.style.width = '100%'\r\n iframe.style.height = '100%'\r\n iframe.style.border = '0'\r\n iframeWrap.appendChild(iframe)\r\n\r\n const form = document.createElement('form')\r\n form.style.display = 'none'\r\n form.method = 'POST'\r\n form.action = acsUrl\r\n form.target = iframeName\r\n document.body.appendChild(form)\r\n\r\n if (responseType === 'CHALLENGE') {\r\n // 3DS v2\r\n form.appendChild(hiddenInput('creq', normalizeCreq(cReq)))\r\n if (transactionId) {\r\n // Optional echo field (send as-is)\r\n form.appendChild(hiddenInput('threeDSSessionData', transactionId))\r\n }\r\n } else {\r\n // 3DS v1 fallback\r\n form.appendChild(hiddenInput('PaReq', pReq || ''))\r\n form.appendChild(hiddenInput('TermUrl', redirectUri || ''))\r\n form.appendChild(hiddenInput('MD', transactionId || ''))\r\n }\r\n\r\n form.submit()\r\n\r\n setTimeout(() => {\r\n try {\r\n document.body.removeChild(form)\r\n } catch {\r\n // ignore\r\n }\r\n }, 1000)\r\n}\r\n\r\nexport function closeOpayoIframe() {\r\n if (!isBrowser()) return\r\n const container = document.getElementById('threeds-container') as HTMLDivElement | null\r\n if (!container) return\r\n\r\n container.innerHTML = ''\r\n container.style.display = 'none'\r\n\r\n try {\r\n onOpayoCancelled?.()\r\n } catch {\r\n // ignore\r\n }\r\n}\r\n\r\nexport function run3DSecure(args: Run3DSecureArgs) {\r\n if (!isBrowser()) return Promise.resolve(false)\r\n\r\n const {\r\n responseType,\r\n acsUrl,\r\n pReq,\r\n cReq,\r\n redirectUri,\r\n transactionId,\r\n onCancelled,\r\n onOpened,\r\n onClosed\r\n } = args\r\n\r\n onOpayoCancelled = onCancelled\r\n\r\n return new Promise<boolean>((resolve) => {\r\n const handleMessage = (event: MessageEvent) => {\r\n const msg = String((event as any).data || '')\r\n\r\n if (msg === 'OPAYO_CALLBACK_SUCCESS') {\r\n closeOpayoIframe()\r\n window.removeEventListener('message', handleMessage)\r\n try {\r\n onClosed?.()\r\n } catch {\r\n // ignore\r\n }\r\n resolve(true)\r\n } else if (msg === 'OPAYO_CALLBACK_FAILED') {\r\n closeOpayoIframe()\r\n window.removeEventListener('message', handleMessage)\r\n try {\r\n onClosed?.()\r\n } catch {\r\n // ignore\r\n }\r\n resolve(false)\r\n }\r\n }\r\n\r\n window.addEventListener('message', handleMessage)\r\n\r\n try {\r\n onOpened?.()\r\n } catch {\r\n // ignore\r\n }\r\n\r\n initializeIframe(responseType, acsUrl, pReq, cReq, redirectUri, transactionId)\r\n })\r\n}\r\n\r\n// Call this from your callback/return page.\r\n// It posts a signal back to the parent checkout window.\r\nexport function receiveOpayoResponse(message: unknown) {\r\n if (!isBrowser()) return\r\n\r\n const m = String(message || '')\r\n if (m === 'OPAYO_CALLBACK_FAILED' || m === 'OPAYO_CALLBACK_SUCCESS') {\r\n try {\r\n window.top?.postMessage(m, '*')\r\n } catch {\r\n // ignore\r\n }\r\n\r\n try {\r\n onOpayoCancelled?.()\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n}\r\n","// src/install.ts\r\nimport type { App } from 'vue'\r\n\r\nexport function OrderopiaVuePlugin() {\r\n return {\r\n install(app: App) {\r\n // nothing yet, but future-proof\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["import_vue"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/composables/useBasket.ts","../src/composables/useOpayo3ds.ts","../src/opayo/opayo3dsManager.ts","../src/install.ts"],"sourcesContent":["// src/index.ts\r\nexport { useBasket } from './composables/useBasket'\r\nexport { useOpayo3ds } from './composables/useOpayo3ds'\r\nexport { receiveOpayoResponse } from './opayo/opayo3dsManager'\r\nexport { OrderopiaVuePlugin } from './install'\r\n","// src/composables/useBasket.ts\r\nimport { ref, computed, onScopeDispose } from 'vue'\r\nimport {\r\n basketManager,\r\n type BasketState\r\n} from 'orderopia-ordering-api-client'\r\n\r\nexport function useBasket() {\r\n // Start with current basket immediately\r\n const basket = ref<BasketState>(basketManager.getBasket())\r\n\r\n // Subscribe immediately (NOT in onMounted)\r\n const unsubscribe = basketManager.subscribe(state => {\r\n basket.value = state\r\n })\r\n\r\n // Auto-cleanup when the component/composable scope is destroyed\r\n onScopeDispose(() => {\r\n unsubscribe()\r\n })\r\n\r\n const totalQuantity = computed(() =>\r\n basket.value.items.reduce((sum, i) => sum + (i.quantity ?? 0), 0)\r\n )\r\n\r\n return {\r\n basket,\r\n totalQuantity,\r\n\r\n // pass-through helpers (nice DX)\r\n addToBasket: basketManager.addToBasket.bind(basketManager),\r\n removeFromBasket: basketManager.removeFromBasket.bind(basketManager),\r\n clearBasket: basketManager.clearBasket.bind(basketManager)\r\n }\r\n}\r\n","// src/composables/useOpayo3ds.ts\r\nimport { ref, onScopeDispose } from 'vue'\r\nimport { run3DSecure, closeOpayoIframe, type Run3DSecureArgs } from '../opayo/opayo3dsManager'\r\n\r\nexport function useOpayo3ds() {\r\n const isOpen = ref(false)\r\n const isRunning = ref(false)\r\n\r\n let disposed = false\r\n\r\n onScopeDispose(() => {\r\n disposed = true\r\n isOpen.value = false\r\n isRunning.value = false\r\n closeOpayoIframe()\r\n })\r\n\r\n async function run(args: Run3DSecureArgs) {\r\n if (disposed) return false\r\n\r\n isOpen.value = true\r\n isRunning.value = true\r\n\r\n try {\r\n const result = await run3DSecure({\r\n ...args,\r\n onOpened: () => {\r\n if (disposed) return\r\n isOpen.value = true\r\n args.onOpened?.()\r\n },\r\n onClosed: () => {\r\n if (disposed) return\r\n isOpen.value = false\r\n args.onClosed?.()\r\n },\r\n onCancelled: () => {\r\n if (disposed) return\r\n isOpen.value = false\r\n args.onCancelled?.()\r\n }\r\n })\r\n\r\n return result\r\n } finally {\r\n if (!disposed) {\r\n isRunning.value = false\r\n }\r\n }\r\n }\r\n\r\n function close() {\r\n isOpen.value = false\r\n isRunning.value = false\r\n closeOpayoIframe()\r\n }\r\n\r\n return {\r\n isOpen,\r\n isRunning,\r\n run,\r\n close\r\n }\r\n}\r\n","// src/opayo/opayo3dsManager.ts\r\n\r\ntype ResponseType = 'CHALLENGE' | 'FALLBACK'\r\n\r\nfunction isBrowser() {\r\n return typeof window !== 'undefined' && typeof document !== 'undefined'\r\n}\r\n\r\nfunction ensureThreedsContainer() {\r\n if (!isBrowser()) return null\r\n\r\n let el = document.getElementById('threeds-container') as HTMLDivElement | null\r\n if (!el) {\r\n el = document.createElement('div')\r\n el.id = 'threeds-container'\r\n el.style.position = 'fixed'\r\n el.style.inset = '0'\r\n el.style.display = 'none'\r\n el.style.background = 'rgba(0,0,0,0.35)'\r\n el.style.zIndex = '99999'\r\n document.body.appendChild(el)\r\n }\r\n return el\r\n}\r\n\r\n// UTF-8 -> Base64URL (no padding)\r\nfunction utf8ToBase64Url(str: string) {\r\n const bytes = new TextEncoder().encode(str)\r\n let bin = ''\r\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i])\r\n const b64 = btoa(bin)\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '')\r\n}\r\n\r\n// Base64URL -> Base64 (and add padding)\r\nfunction toStdBase64(b64url: string) {\r\n let s = b64url.replace(/-/g, '+').replace(/_/g, '/')\r\n const pad = s.length % 4\r\n if (pad) s += '==='.slice(pad - 1)\r\n return s\r\n}\r\n\r\nfunction safeAtobMaybeJson(b64ish: string) {\r\n try {\r\n return atob(toStdBase64(b64ish))\r\n } catch {\r\n return null\r\n }\r\n}\r\n\r\n// Normalize creq to Base64URL without padding.\r\nfunction normalizeCreq(input: unknown) {\r\n if (input == null) return ''\r\n\r\n // Object -> JSON\r\n if (typeof input === 'object') {\r\n try {\r\n return utf8ToBase64Url(JSON.stringify(input))\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n let creq = String(input).trim()\r\n\r\n // If obviously JSON text\r\n if (/^\\s*\\{[\\s\\S]*\\}\\s*$/.test(creq)) {\r\n return utf8ToBase64Url(creq)\r\n }\r\n\r\n // If it looks URL-encoded, attempt a decode\r\n if (/%[0-9A-Fa-f]{2}/.test(creq) || creq.includes('%')) {\r\n try {\r\n creq = decodeURIComponent(creq)\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n // Remove whitespace, convert spaces to '+'\r\n creq = creq.replace(/\\s+/g, '').replace(/ /g, '+')\r\n\r\n // If decodes to JSON, re-encode properly as UTF-8 base64url\r\n const maybe = safeAtobMaybeJson(creq)\r\n if (maybe && maybe.charCodeAt(0) === 123 /* '{' */) {\r\n return utf8ToBase64Url(maybe)\r\n }\r\n\r\n // Otherwise normalize to base64url and strip padding\r\n creq = creq.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '')\r\n return creq\r\n}\r\n\r\nfunction hiddenInput(name: string, value: unknown) {\r\n const inp = document.createElement('input')\r\n inp.type = 'hidden'\r\n inp.name = name\r\n inp.value = value == null ? '' : String(value)\r\n return inp\r\n}\r\n\r\n/**\r\n * ✅ Pull env from the core client (prod/dev toggle you built)\r\n * NOTE: Adjust the import path to whatever you export publicly from the client package.\r\n */\r\nimport { isOrderopiaDevMode } from 'orderopia-ordering-api-client'\r\n\r\nfunction getChallengeRedirectUri(): string {\r\n // TEMP values for now (your ask) — but environment-aware.\r\n // Replace these when you confirm the final endpoint paths.\r\n return isOrderopiaDevMode()\r\n ? 'https://api-test.orderopia.com/Transactions/3ds/Challenge'\r\n : 'https://api.orderopia.com/Transactions/3ds/Challenge'\r\n}\r\n\r\nexport type Run3DSecureArgs = {\r\n responseType: ResponseType\r\n acsUrl: string\r\n pReq?: string | null\r\n cReq?: unknown\r\n redirectUri?: string | null\r\n transactionId?: string | null\r\n\r\n onCancelled?: () => void\r\n onOpened?: () => void\r\n onClosed?: () => void\r\n}\r\n\r\nlet onOpayoCancelled: (() => void) | undefined\r\n\r\nfunction initializeIframe(\r\n responseType: ResponseType,\r\n acsUrl: string,\r\n pReq?: string | null,\r\n cReq?: unknown,\r\n redirectUri?: string | null,\r\n transactionId?: string | null\r\n) {\r\n if (!isBrowser()) return\r\n\r\n const container = ensureThreedsContainer()\r\n if (!container) return\r\n\r\n container.style.display = 'block'\r\n container.textContent = ''\r\n\r\n const panel = document.createElement('div')\r\n panel.style.position = 'absolute'\r\n panel.style.top = '50%'\r\n panel.style.left = '50%'\r\n panel.style.transform = 'translate(-50%, -50%)'\r\n panel.style.width = 'min(100%, 500px)'\r\n panel.style.height = 'min(100%, 600px)'\r\n panel.style.background = 'var(--background, #fff)'\r\n panel.style.borderRadius = '10px'\r\n panel.style.boxShadow = '0 10px 30px rgba(0,0,0,0.2)'\r\n panel.style.display = 'flex'\r\n panel.style.flexDirection = 'column'\r\n panel.style.overflow = 'hidden'\r\n container.appendChild(panel)\r\n\r\n const msg = document.createElement('div')\r\n msg.style.padding = '16px'\r\n msg.style.fontFamily = 'sans-serif'\r\n msg.style.textAlign = 'center'\r\n msg.innerHTML =\r\n '<div style=\"font-weight:600;\">We’re redirecting you to your bank to complete the payment.</div>' +\r\n '<div style=\"margin-top:6px;\">This will only take a moment. Please <u>do not</u> refresh the page.</div>'\r\n panel.appendChild(msg)\r\n\r\n const iframeWrap = document.createElement('div')\r\n iframeWrap.style.flex = '1'\r\n iframeWrap.style.borderTop = '1px solid rgba(0,0,0,0.06)'\r\n panel.appendChild(iframeWrap)\r\n\r\n const iframeName = 'threeds_frame_' + Math.random().toString(36).slice(2)\r\n const iframe = document.createElement('iframe')\r\n iframe.name = iframeName\r\n iframe.title = '3-D Secure Authentication'\r\n iframe.style.width = '100%'\r\n iframe.style.height = '100%'\r\n iframe.style.border = '0'\r\n iframeWrap.appendChild(iframe)\r\n\r\n const form = document.createElement('form')\r\n form.style.display = 'none'\r\n form.method = 'POST'\r\n form.action = acsUrl\r\n form.target = iframeName\r\n document.body.appendChild(form)\r\n\r\n if (responseType === 'CHALLENGE') {\r\n // 3DS v2\r\n form.appendChild(hiddenInput('creq', normalizeCreq(cReq)))\r\n if (transactionId) {\r\n // Optional echo field (send as-is)\r\n form.appendChild(hiddenInput('threeDSSessionData', transactionId))\r\n }\r\n } else {\r\n // 3DS v1 fallback\r\n const termUrl = redirectUri || ''\r\n form.appendChild(hiddenInput('PaReq', pReq || ''))\r\n form.appendChild(hiddenInput('TermUrl', termUrl))\r\n form.appendChild(hiddenInput('MD', transactionId || ''))\r\n }\r\n\r\n form.submit()\r\n\r\n setTimeout(() => {\r\n try {\r\n document.body.removeChild(form)\r\n } catch {\r\n // ignore\r\n }\r\n }, 1000000)\r\n}\r\n\r\nexport function closeOpayoIframe() {\r\n if (!isBrowser()) return\r\n const container = document.getElementById('threeds-container') as HTMLDivElement | null\r\n if (!container) return\r\n\r\n container.innerHTML = ''\r\n container.style.display = 'none'\r\n\r\n try {\r\n onOpayoCancelled?.()\r\n } catch {\r\n // ignore\r\n }\r\n}\r\n\r\nexport function run3DSecure(args: Run3DSecureArgs) {\r\n if (!isBrowser()) return Promise.resolve(false)\r\n\r\n const {\r\n responseType,\r\n acsUrl,\r\n pReq,\r\n cReq,\r\n redirectUri,\r\n transactionId,\r\n onCancelled,\r\n onOpened,\r\n onClosed\r\n } = args\r\n\r\n onOpayoCancelled = onCancelled\r\n\r\n return new Promise<boolean>((resolve) => {\r\n const handleMessage = (event: MessageEvent) => {\r\n const msg = String((event as any).data || '')\r\n\r\n if (msg === 'OPAYO_CALLBACK_SUCCESS') {\r\n closeOpayoIframe()\r\n window.removeEventListener('message', handleMessage)\r\n try {\r\n onClosed?.()\r\n } catch {\r\n // ignore\r\n }\r\n resolve(true)\r\n } else if (msg === 'OPAYO_CALLBACK_FAILED') {\r\n closeOpayoIframe()\r\n window.removeEventListener('message', handleMessage)\r\n try {\r\n onClosed?.()\r\n } catch {\r\n // ignore\r\n }\r\n resolve(false)\r\n }\r\n }\r\n\r\n window.addEventListener('message', handleMessage)\r\n\r\n try {\r\n onOpened?.()\r\n } catch {\r\n // ignore\r\n }\r\n\r\n const termUrl = redirectUri ?? getChallengeRedirectUri()\r\n\r\n initializeIframe(responseType, acsUrl, pReq, cReq, termUrl, transactionId)\r\n })\r\n}\r\n\r\n// Call this from your callback/return page.\r\n// It posts a signal back to the parent checkout window.\r\nexport function receiveOpayoResponse(message: unknown) {\r\n if (!isBrowser()) return\r\n\r\n const m = String(message || '')\r\n if (m === 'OPAYO_CALLBACK_FAILED' || m === 'OPAYO_CALLBACK_SUCCESS') {\r\n try {\r\n window.top?.postMessage(m, '*')\r\n } catch {\r\n // ignore\r\n }\r\n\r\n try {\r\n onOpayoCancelled?.()\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n}\r\n","// src/install.ts\r\nimport type { App } from 'vue'\r\n\r\nexport function OrderopiaVuePlugin() {\r\n return {\r\n install(app: App) {\r\n // nothing yet, but future-proof\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,iBAA8C;AAC9C,2CAGO;AAEA,SAAS,YAAY;AAE1B,QAAM,aAAS,gBAAiB,mDAAc,UAAU,CAAC;AAGzD,QAAM,cAAc,mDAAc,UAAU,WAAS;AACnD,WAAO,QAAQ;AAAA,EACjB,CAAC;AAGD,iCAAe,MAAM;AACnB,gBAAY;AAAA,EACd,CAAC;AAED,QAAM,oBAAgB;AAAA,IAAS,MAC7B,OAAO,MAAM,MAAM,OAAO,CAAC,KAAK,MAAM,OAAO,EAAE,YAAY,IAAI,CAAC;AAAA,EAClE;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA;AAAA,IAGA,aAAa,mDAAc,YAAY,KAAK,kDAAa;AAAA,IACzD,kBAAkB,mDAAc,iBAAiB,KAAK,kDAAa;AAAA,IACnE,aAAa,mDAAc,YAAY,KAAK,kDAAa;AAAA,EAC3D;AACF;;;ACjCA,IAAAA,cAAoC;;;ACwGpC,IAAAC,wCAAmC;AArGnC,SAAS,YAAY;AACnB,SAAO,OAAO,WAAW,eAAe,OAAO,aAAa;AAC9D;AAEA,SAAS,yBAAyB;AAChC,MAAI,CAAC,UAAU,EAAG,QAAO;AAEzB,MAAI,KAAK,SAAS,eAAe,mBAAmB;AACpD,MAAI,CAAC,IAAI;AACP,SAAK,SAAS,cAAc,KAAK;AACjC,OAAG,KAAK;AACR,OAAG,MAAM,WAAW;AACpB,OAAG,MAAM,QAAQ;AACjB,OAAG,MAAM,UAAU;AACnB,OAAG,MAAM,aAAa;AACtB,OAAG,MAAM,SAAS;AAClB,aAAS,KAAK,YAAY,EAAE;AAAA,EAC9B;AACA,SAAO;AACT;AAGA,SAAS,gBAAgB,KAAa;AACpC,QAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,GAAG;AAC1C,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,QAAO,OAAO,aAAa,MAAM,CAAC,CAAC;AAC1E,QAAM,MAAM,KAAK,GAAG;AACpB,SAAO,IAAI,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AACvE;AAGA,SAAS,YAAY,QAAgB;AACnC,MAAI,IAAI,OAAO,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AACnD,QAAM,MAAM,EAAE,SAAS;AACvB,MAAI,IAAK,MAAK,MAAM,MAAM,MAAM,CAAC;AACjC,SAAO;AACT;AAEA,SAAS,kBAAkB,QAAgB;AACzC,MAAI;AACF,WAAO,KAAK,YAAY,MAAM,CAAC;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,SAAS,cAAc,OAAgB;AACrC,MAAI,SAAS,KAAM,QAAO;AAG1B,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI;AACF,aAAO,gBAAgB,KAAK,UAAU,KAAK,CAAC;AAAA,IAC9C,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,OAAO,OAAO,KAAK,EAAE,KAAK;AAG9B,MAAI,sBAAsB,KAAK,IAAI,GAAG;AACpC,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAGA,MAAI,kBAAkB,KAAK,IAAI,KAAK,KAAK,SAAS,GAAG,GAAG;AACtD,QAAI;AACF,aAAO,mBAAmB,IAAI;AAAA,IAChC,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,SAAO,KAAK,QAAQ,QAAQ,EAAE,EAAE,QAAQ,MAAM,GAAG;AAGjD,QAAM,QAAQ,kBAAkB,IAAI;AACpC,MAAI,SAAS,MAAM,WAAW,CAAC,MAAM,KAAe;AAClD,WAAO,gBAAgB,KAAK;AAAA,EAC9B;AAGA,SAAO,KAAK,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AACtE,SAAO;AACT;AAEA,SAAS,YAAY,MAAc,OAAgB;AACjD,QAAM,MAAM,SAAS,cAAc,OAAO;AAC1C,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,QAAQ,SAAS,OAAO,KAAK,OAAO,KAAK;AAC7C,SAAO;AACT;AAQA,SAAS,0BAAkC;AAGzC,aAAO,0DAAmB,IACtB,8DACA;AACN;AAeA,IAAI;AAEJ,SAAS,iBACP,cACA,QACA,MACA,MACA,aACA,eACA;AACA,MAAI,CAAC,UAAU,EAAG;AAElB,QAAM,YAAY,uBAAuB;AACzC,MAAI,CAAC,UAAW;AAEhB,YAAU,MAAM,UAAU;AAC1B,YAAU,cAAc;AAExB,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,MAAM,WAAW;AACvB,QAAM,MAAM,MAAM;AAClB,QAAM,MAAM,OAAO;AACnB,QAAM,MAAM,YAAY;AACxB,QAAM,MAAM,QAAQ;AACpB,QAAM,MAAM,SAAS;AACrB,QAAM,MAAM,aAAa;AACzB,QAAM,MAAM,eAAe;AAC3B,QAAM,MAAM,YAAY;AACxB,QAAM,MAAM,UAAU;AACtB,QAAM,MAAM,gBAAgB;AAC5B,QAAM,MAAM,WAAW;AACvB,YAAU,YAAY,KAAK;AAE3B,QAAM,MAAM,SAAS,cAAc,KAAK;AACxC,MAAI,MAAM,UAAU;AACpB,MAAI,MAAM,aAAa;AACvB,MAAI,MAAM,YAAY;AACtB,MAAI,YACF;AAEF,QAAM,YAAY,GAAG;AAErB,QAAM,aAAa,SAAS,cAAc,KAAK;AAC/C,aAAW,MAAM,OAAO;AACxB,aAAW,MAAM,YAAY;AAC7B,QAAM,YAAY,UAAU;AAE5B,QAAM,aAAa,mBAAmB,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC;AACxE,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,OAAO;AACd,SAAO,QAAQ;AACf,SAAO,MAAM,QAAQ;AACrB,SAAO,MAAM,SAAS;AACtB,SAAO,MAAM,SAAS;AACtB,aAAW,YAAY,MAAM;AAE7B,QAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,OAAK,MAAM,UAAU;AACrB,OAAK,SAAS;AACd,OAAK,SAAS;AACd,OAAK,SAAS;AACd,WAAS,KAAK,YAAY,IAAI;AAE9B,MAAI,iBAAiB,aAAa;AAEhC,SAAK,YAAY,YAAY,QAAQ,cAAc,IAAI,CAAC,CAAC;AACzD,QAAI,eAAe;AAEjB,WAAK,YAAY,YAAY,sBAAsB,aAAa,CAAC;AAAA,IACnE;AAAA,EACF,OAAO;AAEL,UAAM,UAAU,eAAe;AAC/B,SAAK,YAAY,YAAY,SAAS,QAAQ,EAAE,CAAC;AACjD,SAAK,YAAY,YAAY,WAAW,OAAO,CAAC;AAChD,SAAK,YAAY,YAAY,MAAM,iBAAiB,EAAE,CAAC;AAAA,EACzD;AAEA,OAAK,OAAO;AAEZ,aAAW,MAAM;AACf,QAAI;AACF,eAAS,KAAK,YAAY,IAAI;AAAA,IAChC,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,GAAO;AACZ;AAEO,SAAS,mBAAmB;AACjC,MAAI,CAAC,UAAU,EAAG;AAClB,QAAM,YAAY,SAAS,eAAe,mBAAmB;AAC7D,MAAI,CAAC,UAAW;AAEhB,YAAU,YAAY;AACtB,YAAU,MAAM,UAAU;AAE1B,MAAI;AACF,uBAAmB;AAAA,EACrB,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,YAAY,MAAuB;AACjD,MAAI,CAAC,UAAU,EAAG,QAAO,QAAQ,QAAQ,KAAK;AAE9C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,qBAAmB;AAEnB,SAAO,IAAI,QAAiB,CAAC,YAAY;AACvC,UAAM,gBAAgB,CAAC,UAAwB;AAC7C,YAAM,MAAM,OAAQ,MAAc,QAAQ,EAAE;AAE5C,UAAI,QAAQ,0BAA0B;AACpC,yBAAiB;AACjB,eAAO,oBAAoB,WAAW,aAAa;AACnD,YAAI;AACF,qBAAW;AAAA,QACb,QAAQ;AAAA,QAER;AACA,gBAAQ,IAAI;AAAA,MACd,WAAW,QAAQ,yBAAyB;AAC1C,yBAAiB;AACjB,eAAO,oBAAoB,WAAW,aAAa;AACnD,YAAI;AACF,qBAAW;AAAA,QACb,QAAQ;AAAA,QAER;AACA,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAEhD,QAAI;AACF,iBAAW;AAAA,IACb,QAAQ;AAAA,IAER;AAEA,UAAM,UAAU,eAAe,wBAAwB;AAEvD,qBAAiB,cAAc,QAAQ,MAAM,MAAM,SAAS,aAAa;AAAA,EAC3E,CAAC;AACH;AAIO,SAAS,qBAAqB,SAAkB;AACrD,MAAI,CAAC,UAAU,EAAG;AAElB,QAAM,IAAI,OAAO,WAAW,EAAE;AAC9B,MAAI,MAAM,2BAA2B,MAAM,0BAA0B;AACnE,QAAI;AACF,aAAO,KAAK,YAAY,GAAG,GAAG;AAAA,IAChC,QAAQ;AAAA,IAER;AAEA,QAAI;AACF,yBAAmB;AAAA,IACrB,QAAQ;AAAA,IAER;AAAA,EACF;AACF;;;AD/SO,SAAS,cAAc;AAC5B,QAAM,aAAS,iBAAI,KAAK;AACxB,QAAM,gBAAY,iBAAI,KAAK;AAE3B,MAAI,WAAW;AAEf,kCAAe,MAAM;AACnB,eAAW;AACX,WAAO,QAAQ;AACf,cAAU,QAAQ;AAClB,qBAAiB;AAAA,EACnB,CAAC;AAED,iBAAe,IAAI,MAAuB;AACxC,QAAI,SAAU,QAAO;AAErB,WAAO,QAAQ;AACf,cAAU,QAAQ;AAElB,QAAI;AACF,YAAM,SAAS,MAAM,YAAY;AAAA,QAC/B,GAAG;AAAA,QACH,UAAU,MAAM;AACd,cAAI,SAAU;AACd,iBAAO,QAAQ;AACf,eAAK,WAAW;AAAA,QAClB;AAAA,QACA,UAAU,MAAM;AACd,cAAI,SAAU;AACd,iBAAO,QAAQ;AACf,eAAK,WAAW;AAAA,QAClB;AAAA,QACA,aAAa,MAAM;AACjB,cAAI,SAAU;AACd,iBAAO,QAAQ;AACf,eAAK,cAAc;AAAA,QACrB;AAAA,MACF,CAAC;AAED,aAAO;AAAA,IACT,UAAE;AACA,UAAI,CAAC,UAAU;AACb,kBAAU,QAAQ;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAEA,WAAS,QAAQ;AACf,WAAO,QAAQ;AACf,cAAU,QAAQ;AAClB,qBAAiB;AAAA,EACnB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AE5DO,SAAS,qBAAqB;AACnC,SAAO;AAAA,IACL,QAAQ,KAAU;AAAA,IAElB;AAAA,EACF;AACF;","names":["import_vue","import_orderopia_ordering_api_client"]}
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ function useBasket() {
|
|
|
28
28
|
import { ref as ref2, onScopeDispose as onScopeDispose2 } from "vue";
|
|
29
29
|
|
|
30
30
|
// src/opayo/opayo3dsManager.ts
|
|
31
|
+
import { isOrderopiaDevMode } from "orderopia-ordering-api-client";
|
|
31
32
|
function isBrowser() {
|
|
32
33
|
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
33
34
|
}
|
|
@@ -99,6 +100,9 @@ function hiddenInput(name, value) {
|
|
|
99
100
|
inp.value = value == null ? "" : String(value);
|
|
100
101
|
return inp;
|
|
101
102
|
}
|
|
103
|
+
function getChallengeRedirectUri() {
|
|
104
|
+
return isOrderopiaDevMode() ? "https://api-test.orderopia.com/Transactions/3ds/Challenge" : "https://api.orderopia.com/Transactions/3ds/Challenge";
|
|
105
|
+
}
|
|
102
106
|
var onOpayoCancelled;
|
|
103
107
|
function initializeIframe(responseType, acsUrl, pReq, cReq, redirectUri, transactionId) {
|
|
104
108
|
if (!isBrowser()) return;
|
|
@@ -150,8 +154,9 @@ function initializeIframe(responseType, acsUrl, pReq, cReq, redirectUri, transac
|
|
|
150
154
|
form.appendChild(hiddenInput("threeDSSessionData", transactionId));
|
|
151
155
|
}
|
|
152
156
|
} else {
|
|
157
|
+
const termUrl = redirectUri || "";
|
|
153
158
|
form.appendChild(hiddenInput("PaReq", pReq || ""));
|
|
154
|
-
form.appendChild(hiddenInput("TermUrl",
|
|
159
|
+
form.appendChild(hiddenInput("TermUrl", termUrl));
|
|
155
160
|
form.appendChild(hiddenInput("MD", transactionId || ""));
|
|
156
161
|
}
|
|
157
162
|
form.submit();
|
|
@@ -160,7 +165,7 @@ function initializeIframe(responseType, acsUrl, pReq, cReq, redirectUri, transac
|
|
|
160
165
|
document.body.removeChild(form);
|
|
161
166
|
} catch {
|
|
162
167
|
}
|
|
163
|
-
},
|
|
168
|
+
}, 1e6);
|
|
164
169
|
}
|
|
165
170
|
function closeOpayoIframe() {
|
|
166
171
|
if (!isBrowser()) return;
|
|
@@ -213,7 +218,8 @@ function run3DSecure(args) {
|
|
|
213
218
|
onOpened?.();
|
|
214
219
|
} catch {
|
|
215
220
|
}
|
|
216
|
-
|
|
221
|
+
const termUrl = redirectUri ?? getChallengeRedirectUri();
|
|
222
|
+
initializeIframe(responseType, acsUrl, pReq, cReq, termUrl, transactionId);
|
|
217
223
|
});
|
|
218
224
|
}
|
|
219
225
|
function receiveOpayoResponse(message) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/composables/useBasket.ts","../src/composables/useOpayo3ds.ts","../src/opayo/opayo3dsManager.ts","../src/install.ts"],"sourcesContent":["// src/composables/useBasket.ts\r\nimport { ref, computed, onScopeDispose } from 'vue'\r\nimport {\r\n basketManager,\r\n type BasketState\r\n} from 'orderopia-ordering-api-client'\r\n\r\nexport function useBasket() {\r\n // Start with current basket immediately\r\n const basket = ref<BasketState>(basketManager.getBasket())\r\n\r\n // Subscribe immediately (NOT in onMounted)\r\n const unsubscribe = basketManager.subscribe(state => {\r\n basket.value = state\r\n })\r\n\r\n // Auto-cleanup when the component/composable scope is destroyed\r\n onScopeDispose(() => {\r\n unsubscribe()\r\n })\r\n\r\n const totalQuantity = computed(() =>\r\n basket.value.items.reduce((sum, i) => sum + (i.quantity ?? 0), 0)\r\n )\r\n\r\n return {\r\n basket,\r\n totalQuantity,\r\n\r\n // pass-through helpers (nice DX)\r\n addToBasket: basketManager.addToBasket.bind(basketManager),\r\n removeFromBasket: basketManager.removeFromBasket.bind(basketManager),\r\n clearBasket: basketManager.clearBasket.bind(basketManager)\r\n }\r\n}\r\n","// src/composables/useOpayo3ds.ts\r\nimport { ref, onScopeDispose } from 'vue'\r\nimport { run3DSecure, closeOpayoIframe, type Run3DSecureArgs } from '../opayo/opayo3dsManager'\r\n\r\nexport function useOpayo3ds() {\r\n const isOpen = ref(false)\r\n const isRunning = ref(false)\r\n\r\n let disposed = false\r\n\r\n onScopeDispose(() => {\r\n disposed = true\r\n isOpen.value = false\r\n isRunning.value = false\r\n closeOpayoIframe()\r\n })\r\n\r\n async function run(args: Run3DSecureArgs) {\r\n if (disposed) return false\r\n\r\n isOpen.value = true\r\n isRunning.value = true\r\n\r\n try {\r\n const result = await run3DSecure({\r\n ...args,\r\n onOpened: () => {\r\n if (disposed) return\r\n isOpen.value = true\r\n args.onOpened?.()\r\n },\r\n onClosed: () => {\r\n if (disposed) return\r\n isOpen.value = false\r\n args.onClosed?.()\r\n },\r\n onCancelled: () => {\r\n if (disposed) return\r\n isOpen.value = false\r\n args.onCancelled?.()\r\n }\r\n })\r\n\r\n return result\r\n } finally {\r\n if (!disposed) {\r\n isRunning.value = false\r\n }\r\n }\r\n }\r\n\r\n function close() {\r\n isOpen.value = false\r\n isRunning.value = false\r\n closeOpayoIframe()\r\n }\r\n\r\n return {\r\n isOpen,\r\n isRunning,\r\n run,\r\n close\r\n }\r\n}\r\n","// src/opayo/opayo3dsManager.ts\r\ntype ResponseType = 'CHALLENGE' | 'FALLBACK'\r\n\r\nfunction isBrowser() {\r\n return typeof window !== 'undefined' && typeof document !== 'undefined'\r\n}\r\n\r\nfunction ensureThreedsContainer() {\r\n if (!isBrowser()) return null\r\n\r\n let el = document.getElementById('threeds-container') as HTMLDivElement | null\r\n if (!el) {\r\n el = document.createElement('div')\r\n el.id = 'threeds-container'\r\n el.style.position = 'fixed'\r\n el.style.inset = '0'\r\n el.style.display = 'none'\r\n el.style.background = 'rgba(0,0,0,0.35)'\r\n el.style.zIndex = '99999'\r\n document.body.appendChild(el)\r\n }\r\n return el\r\n}\r\n\r\n// UTF-8 -> Base64URL (no padding)\r\nfunction utf8ToBase64Url(str: string) {\r\n const bytes = new TextEncoder().encode(str)\r\n let bin = ''\r\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i])\r\n const b64 = btoa(bin)\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '')\r\n}\r\n\r\n// Base64URL -> Base64 (and add padding)\r\nfunction toStdBase64(b64url: string) {\r\n let s = b64url.replace(/-/g, '+').replace(/_/g, '/')\r\n const pad = s.length % 4\r\n if (pad) s += '==='.slice(pad - 1)\r\n return s\r\n}\r\n\r\nfunction safeAtobMaybeJson(b64ish: string) {\r\n try {\r\n return atob(toStdBase64(b64ish))\r\n } catch {\r\n return null\r\n }\r\n}\r\n\r\n// Normalize creq to Base64URL without padding.\r\nfunction normalizeCreq(input: unknown) {\r\n if (input == null) return ''\r\n\r\n // Object -> JSON\r\n if (typeof input === 'object') {\r\n try {\r\n return utf8ToBase64Url(JSON.stringify(input))\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n let creq = String(input).trim()\r\n\r\n // If obviously JSON text\r\n if (/^\\s*\\{[\\s\\S]*\\}\\s*$/.test(creq)) {\r\n return utf8ToBase64Url(creq)\r\n }\r\n\r\n // If it looks URL-encoded, attempt a decode\r\n if (/%[0-9A-Fa-f]{2}/.test(creq) || creq.includes('%')) {\r\n try {\r\n creq = decodeURIComponent(creq)\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n // Remove whitespace, convert spaces to '+'\r\n creq = creq.replace(/\\s+/g, '').replace(/ /g, '+')\r\n\r\n // If decodes to JSON, re-encode properly as UTF-8 base64url\r\n const maybe = safeAtobMaybeJson(creq)\r\n if (maybe && maybe.charCodeAt(0) === 123 /* '{' */) {\r\n return utf8ToBase64Url(maybe)\r\n }\r\n\r\n // Otherwise normalize to base64url and strip padding\r\n creq = creq.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '')\r\n return creq\r\n}\r\n\r\nfunction hiddenInput(name: string, value: unknown) {\r\n const inp = document.createElement('input')\r\n inp.type = 'hidden'\r\n inp.name = name\r\n inp.value = value == null ? '' : String(value)\r\n return inp\r\n}\r\n\r\nexport type Run3DSecureArgs = {\r\n responseType: ResponseType\r\n acsUrl: string\r\n pReq?: string | null\r\n cReq?: unknown\r\n redirectUri?: string | null\r\n transactionId?: string | null\r\n\r\n onCancelled?: () => void\r\n onOpened?: () => void\r\n onClosed?: () => void\r\n}\r\n\r\nlet onOpayoCancelled: (() => void) | undefined\r\n\r\nfunction initializeIframe(\r\n responseType: ResponseType,\r\n acsUrl: string,\r\n pReq?: string | null,\r\n cReq?: unknown,\r\n redirectUri?: string | null,\r\n transactionId?: string | null\r\n) {\r\n if (!isBrowser()) return\r\n\r\n const container = ensureThreedsContainer()\r\n if (!container) return\r\n\r\n container.style.display = 'block'\r\n container.textContent = ''\r\n\r\n const panel = document.createElement('div')\r\n panel.style.position = 'absolute'\r\n panel.style.top = '50%'\r\n panel.style.left = '50%'\r\n panel.style.transform = 'translate(-50%, -50%)'\r\n panel.style.width = 'min(100%, 500px)'\r\n panel.style.height = 'min(100%, 600px)'\r\n panel.style.background = 'var(--background, #fff)'\r\n panel.style.borderRadius = '10px'\r\n panel.style.boxShadow = '0 10px 30px rgba(0,0,0,0.2)'\r\n panel.style.display = 'flex'\r\n panel.style.flexDirection = 'column'\r\n panel.style.overflow = 'hidden'\r\n container.appendChild(panel)\r\n\r\n const msg = document.createElement('div')\r\n msg.style.padding = '16px'\r\n msg.style.fontFamily = 'sans-serif'\r\n msg.style.textAlign = 'center'\r\n msg.innerHTML =\r\n '<div style=\"font-weight:600;\">We’re redirecting you to your bank to complete the payment.</div>' +\r\n '<div style=\"margin-top:6px;\">This will only take a moment. Please <u>do not</u> refresh the page.</div>'\r\n panel.appendChild(msg)\r\n\r\n const iframeWrap = document.createElement('div')\r\n iframeWrap.style.flex = '1'\r\n iframeWrap.style.borderTop = '1px solid rgba(0,0,0,0.06)'\r\n panel.appendChild(iframeWrap)\r\n\r\n const iframeName = 'threeds_frame_' + Math.random().toString(36).slice(2)\r\n const iframe = document.createElement('iframe')\r\n iframe.name = iframeName\r\n iframe.title = '3-D Secure Authentication'\r\n iframe.style.width = '100%'\r\n iframe.style.height = '100%'\r\n iframe.style.border = '0'\r\n iframeWrap.appendChild(iframe)\r\n\r\n const form = document.createElement('form')\r\n form.style.display = 'none'\r\n form.method = 'POST'\r\n form.action = acsUrl\r\n form.target = iframeName\r\n document.body.appendChild(form)\r\n\r\n if (responseType === 'CHALLENGE') {\r\n // 3DS v2\r\n form.appendChild(hiddenInput('creq', normalizeCreq(cReq)))\r\n if (transactionId) {\r\n // Optional echo field (send as-is)\r\n form.appendChild(hiddenInput('threeDSSessionData', transactionId))\r\n }\r\n } else {\r\n // 3DS v1 fallback\r\n form.appendChild(hiddenInput('PaReq', pReq || ''))\r\n form.appendChild(hiddenInput('TermUrl', redirectUri || ''))\r\n form.appendChild(hiddenInput('MD', transactionId || ''))\r\n }\r\n\r\n form.submit()\r\n\r\n setTimeout(() => {\r\n try {\r\n document.body.removeChild(form)\r\n } catch {\r\n // ignore\r\n }\r\n }, 1000)\r\n}\r\n\r\nexport function closeOpayoIframe() {\r\n if (!isBrowser()) return\r\n const container = document.getElementById('threeds-container') as HTMLDivElement | null\r\n if (!container) return\r\n\r\n container.innerHTML = ''\r\n container.style.display = 'none'\r\n\r\n try {\r\n onOpayoCancelled?.()\r\n } catch {\r\n // ignore\r\n }\r\n}\r\n\r\nexport function run3DSecure(args: Run3DSecureArgs) {\r\n if (!isBrowser()) return Promise.resolve(false)\r\n\r\n const {\r\n responseType,\r\n acsUrl,\r\n pReq,\r\n cReq,\r\n redirectUri,\r\n transactionId,\r\n onCancelled,\r\n onOpened,\r\n onClosed\r\n } = args\r\n\r\n onOpayoCancelled = onCancelled\r\n\r\n return new Promise<boolean>((resolve) => {\r\n const handleMessage = (event: MessageEvent) => {\r\n const msg = String((event as any).data || '')\r\n\r\n if (msg === 'OPAYO_CALLBACK_SUCCESS') {\r\n closeOpayoIframe()\r\n window.removeEventListener('message', handleMessage)\r\n try {\r\n onClosed?.()\r\n } catch {\r\n // ignore\r\n }\r\n resolve(true)\r\n } else if (msg === 'OPAYO_CALLBACK_FAILED') {\r\n closeOpayoIframe()\r\n window.removeEventListener('message', handleMessage)\r\n try {\r\n onClosed?.()\r\n } catch {\r\n // ignore\r\n }\r\n resolve(false)\r\n }\r\n }\r\n\r\n window.addEventListener('message', handleMessage)\r\n\r\n try {\r\n onOpened?.()\r\n } catch {\r\n // ignore\r\n }\r\n\r\n initializeIframe(responseType, acsUrl, pReq, cReq, redirectUri, transactionId)\r\n })\r\n}\r\n\r\n// Call this from your callback/return page.\r\n// It posts a signal back to the parent checkout window.\r\nexport function receiveOpayoResponse(message: unknown) {\r\n if (!isBrowser()) return\r\n\r\n const m = String(message || '')\r\n if (m === 'OPAYO_CALLBACK_FAILED' || m === 'OPAYO_CALLBACK_SUCCESS') {\r\n try {\r\n window.top?.postMessage(m, '*')\r\n } catch {\r\n // ignore\r\n }\r\n\r\n try {\r\n onOpayoCancelled?.()\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n}\r\n","// src/install.ts\r\nimport type { App } from 'vue'\r\n\r\nexport function OrderopiaVuePlugin() {\r\n return {\r\n install(app: App) {\r\n // nothing yet, but future-proof\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["ref","onScopeDispose","ref","onScopeDispose"]}
|
|
1
|
+
{"version":3,"sources":["../src/composables/useBasket.ts","../src/composables/useOpayo3ds.ts","../src/opayo/opayo3dsManager.ts","../src/install.ts"],"sourcesContent":["// src/composables/useBasket.ts\r\nimport { ref, computed, onScopeDispose } from 'vue'\r\nimport {\r\n basketManager,\r\n type BasketState\r\n} from 'orderopia-ordering-api-client'\r\n\r\nexport function useBasket() {\r\n // Start with current basket immediately\r\n const basket = ref<BasketState>(basketManager.getBasket())\r\n\r\n // Subscribe immediately (NOT in onMounted)\r\n const unsubscribe = basketManager.subscribe(state => {\r\n basket.value = state\r\n })\r\n\r\n // Auto-cleanup when the component/composable scope is destroyed\r\n onScopeDispose(() => {\r\n unsubscribe()\r\n })\r\n\r\n const totalQuantity = computed(() =>\r\n basket.value.items.reduce((sum, i) => sum + (i.quantity ?? 0), 0)\r\n )\r\n\r\n return {\r\n basket,\r\n totalQuantity,\r\n\r\n // pass-through helpers (nice DX)\r\n addToBasket: basketManager.addToBasket.bind(basketManager),\r\n removeFromBasket: basketManager.removeFromBasket.bind(basketManager),\r\n clearBasket: basketManager.clearBasket.bind(basketManager)\r\n }\r\n}\r\n","// src/composables/useOpayo3ds.ts\r\nimport { ref, onScopeDispose } from 'vue'\r\nimport { run3DSecure, closeOpayoIframe, type Run3DSecureArgs } from '../opayo/opayo3dsManager'\r\n\r\nexport function useOpayo3ds() {\r\n const isOpen = ref(false)\r\n const isRunning = ref(false)\r\n\r\n let disposed = false\r\n\r\n onScopeDispose(() => {\r\n disposed = true\r\n isOpen.value = false\r\n isRunning.value = false\r\n closeOpayoIframe()\r\n })\r\n\r\n async function run(args: Run3DSecureArgs) {\r\n if (disposed) return false\r\n\r\n isOpen.value = true\r\n isRunning.value = true\r\n\r\n try {\r\n const result = await run3DSecure({\r\n ...args,\r\n onOpened: () => {\r\n if (disposed) return\r\n isOpen.value = true\r\n args.onOpened?.()\r\n },\r\n onClosed: () => {\r\n if (disposed) return\r\n isOpen.value = false\r\n args.onClosed?.()\r\n },\r\n onCancelled: () => {\r\n if (disposed) return\r\n isOpen.value = false\r\n args.onCancelled?.()\r\n }\r\n })\r\n\r\n return result\r\n } finally {\r\n if (!disposed) {\r\n isRunning.value = false\r\n }\r\n }\r\n }\r\n\r\n function close() {\r\n isOpen.value = false\r\n isRunning.value = false\r\n closeOpayoIframe()\r\n }\r\n\r\n return {\r\n isOpen,\r\n isRunning,\r\n run,\r\n close\r\n }\r\n}\r\n","// src/opayo/opayo3dsManager.ts\r\n\r\ntype ResponseType = 'CHALLENGE' | 'FALLBACK'\r\n\r\nfunction isBrowser() {\r\n return typeof window !== 'undefined' && typeof document !== 'undefined'\r\n}\r\n\r\nfunction ensureThreedsContainer() {\r\n if (!isBrowser()) return null\r\n\r\n let el = document.getElementById('threeds-container') as HTMLDivElement | null\r\n if (!el) {\r\n el = document.createElement('div')\r\n el.id = 'threeds-container'\r\n el.style.position = 'fixed'\r\n el.style.inset = '0'\r\n el.style.display = 'none'\r\n el.style.background = 'rgba(0,0,0,0.35)'\r\n el.style.zIndex = '99999'\r\n document.body.appendChild(el)\r\n }\r\n return el\r\n}\r\n\r\n// UTF-8 -> Base64URL (no padding)\r\nfunction utf8ToBase64Url(str: string) {\r\n const bytes = new TextEncoder().encode(str)\r\n let bin = ''\r\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i])\r\n const b64 = btoa(bin)\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '')\r\n}\r\n\r\n// Base64URL -> Base64 (and add padding)\r\nfunction toStdBase64(b64url: string) {\r\n let s = b64url.replace(/-/g, '+').replace(/_/g, '/')\r\n const pad = s.length % 4\r\n if (pad) s += '==='.slice(pad - 1)\r\n return s\r\n}\r\n\r\nfunction safeAtobMaybeJson(b64ish: string) {\r\n try {\r\n return atob(toStdBase64(b64ish))\r\n } catch {\r\n return null\r\n }\r\n}\r\n\r\n// Normalize creq to Base64URL without padding.\r\nfunction normalizeCreq(input: unknown) {\r\n if (input == null) return ''\r\n\r\n // Object -> JSON\r\n if (typeof input === 'object') {\r\n try {\r\n return utf8ToBase64Url(JSON.stringify(input))\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n let creq = String(input).trim()\r\n\r\n // If obviously JSON text\r\n if (/^\\s*\\{[\\s\\S]*\\}\\s*$/.test(creq)) {\r\n return utf8ToBase64Url(creq)\r\n }\r\n\r\n // If it looks URL-encoded, attempt a decode\r\n if (/%[0-9A-Fa-f]{2}/.test(creq) || creq.includes('%')) {\r\n try {\r\n creq = decodeURIComponent(creq)\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n // Remove whitespace, convert spaces to '+'\r\n creq = creq.replace(/\\s+/g, '').replace(/ /g, '+')\r\n\r\n // If decodes to JSON, re-encode properly as UTF-8 base64url\r\n const maybe = safeAtobMaybeJson(creq)\r\n if (maybe && maybe.charCodeAt(0) === 123 /* '{' */) {\r\n return utf8ToBase64Url(maybe)\r\n }\r\n\r\n // Otherwise normalize to base64url and strip padding\r\n creq = creq.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '')\r\n return creq\r\n}\r\n\r\nfunction hiddenInput(name: string, value: unknown) {\r\n const inp = document.createElement('input')\r\n inp.type = 'hidden'\r\n inp.name = name\r\n inp.value = value == null ? '' : String(value)\r\n return inp\r\n}\r\n\r\n/**\r\n * ✅ Pull env from the core client (prod/dev toggle you built)\r\n * NOTE: Adjust the import path to whatever you export publicly from the client package.\r\n */\r\nimport { isOrderopiaDevMode } from 'orderopia-ordering-api-client'\r\n\r\nfunction getChallengeRedirectUri(): string {\r\n // TEMP values for now (your ask) — but environment-aware.\r\n // Replace these when you confirm the final endpoint paths.\r\n return isOrderopiaDevMode()\r\n ? 'https://api-test.orderopia.com/Transactions/3ds/Challenge'\r\n : 'https://api.orderopia.com/Transactions/3ds/Challenge'\r\n}\r\n\r\nexport type Run3DSecureArgs = {\r\n responseType: ResponseType\r\n acsUrl: string\r\n pReq?: string | null\r\n cReq?: unknown\r\n redirectUri?: string | null\r\n transactionId?: string | null\r\n\r\n onCancelled?: () => void\r\n onOpened?: () => void\r\n onClosed?: () => void\r\n}\r\n\r\nlet onOpayoCancelled: (() => void) | undefined\r\n\r\nfunction initializeIframe(\r\n responseType: ResponseType,\r\n acsUrl: string,\r\n pReq?: string | null,\r\n cReq?: unknown,\r\n redirectUri?: string | null,\r\n transactionId?: string | null\r\n) {\r\n if (!isBrowser()) return\r\n\r\n const container = ensureThreedsContainer()\r\n if (!container) return\r\n\r\n container.style.display = 'block'\r\n container.textContent = ''\r\n\r\n const panel = document.createElement('div')\r\n panel.style.position = 'absolute'\r\n panel.style.top = '50%'\r\n panel.style.left = '50%'\r\n panel.style.transform = 'translate(-50%, -50%)'\r\n panel.style.width = 'min(100%, 500px)'\r\n panel.style.height = 'min(100%, 600px)'\r\n panel.style.background = 'var(--background, #fff)'\r\n panel.style.borderRadius = '10px'\r\n panel.style.boxShadow = '0 10px 30px rgba(0,0,0,0.2)'\r\n panel.style.display = 'flex'\r\n panel.style.flexDirection = 'column'\r\n panel.style.overflow = 'hidden'\r\n container.appendChild(panel)\r\n\r\n const msg = document.createElement('div')\r\n msg.style.padding = '16px'\r\n msg.style.fontFamily = 'sans-serif'\r\n msg.style.textAlign = 'center'\r\n msg.innerHTML =\r\n '<div style=\"font-weight:600;\">We’re redirecting you to your bank to complete the payment.</div>' +\r\n '<div style=\"margin-top:6px;\">This will only take a moment. Please <u>do not</u> refresh the page.</div>'\r\n panel.appendChild(msg)\r\n\r\n const iframeWrap = document.createElement('div')\r\n iframeWrap.style.flex = '1'\r\n iframeWrap.style.borderTop = '1px solid rgba(0,0,0,0.06)'\r\n panel.appendChild(iframeWrap)\r\n\r\n const iframeName = 'threeds_frame_' + Math.random().toString(36).slice(2)\r\n const iframe = document.createElement('iframe')\r\n iframe.name = iframeName\r\n iframe.title = '3-D Secure Authentication'\r\n iframe.style.width = '100%'\r\n iframe.style.height = '100%'\r\n iframe.style.border = '0'\r\n iframeWrap.appendChild(iframe)\r\n\r\n const form = document.createElement('form')\r\n form.style.display = 'none'\r\n form.method = 'POST'\r\n form.action = acsUrl\r\n form.target = iframeName\r\n document.body.appendChild(form)\r\n\r\n if (responseType === 'CHALLENGE') {\r\n // 3DS v2\r\n form.appendChild(hiddenInput('creq', normalizeCreq(cReq)))\r\n if (transactionId) {\r\n // Optional echo field (send as-is)\r\n form.appendChild(hiddenInput('threeDSSessionData', transactionId))\r\n }\r\n } else {\r\n // 3DS v1 fallback\r\n const termUrl = redirectUri || ''\r\n form.appendChild(hiddenInput('PaReq', pReq || ''))\r\n form.appendChild(hiddenInput('TermUrl', termUrl))\r\n form.appendChild(hiddenInput('MD', transactionId || ''))\r\n }\r\n\r\n form.submit()\r\n\r\n setTimeout(() => {\r\n try {\r\n document.body.removeChild(form)\r\n } catch {\r\n // ignore\r\n }\r\n }, 1000000)\r\n}\r\n\r\nexport function closeOpayoIframe() {\r\n if (!isBrowser()) return\r\n const container = document.getElementById('threeds-container') as HTMLDivElement | null\r\n if (!container) return\r\n\r\n container.innerHTML = ''\r\n container.style.display = 'none'\r\n\r\n try {\r\n onOpayoCancelled?.()\r\n } catch {\r\n // ignore\r\n }\r\n}\r\n\r\nexport function run3DSecure(args: Run3DSecureArgs) {\r\n if (!isBrowser()) return Promise.resolve(false)\r\n\r\n const {\r\n responseType,\r\n acsUrl,\r\n pReq,\r\n cReq,\r\n redirectUri,\r\n transactionId,\r\n onCancelled,\r\n onOpened,\r\n onClosed\r\n } = args\r\n\r\n onOpayoCancelled = onCancelled\r\n\r\n return new Promise<boolean>((resolve) => {\r\n const handleMessage = (event: MessageEvent) => {\r\n const msg = String((event as any).data || '')\r\n\r\n if (msg === 'OPAYO_CALLBACK_SUCCESS') {\r\n closeOpayoIframe()\r\n window.removeEventListener('message', handleMessage)\r\n try {\r\n onClosed?.()\r\n } catch {\r\n // ignore\r\n }\r\n resolve(true)\r\n } else if (msg === 'OPAYO_CALLBACK_FAILED') {\r\n closeOpayoIframe()\r\n window.removeEventListener('message', handleMessage)\r\n try {\r\n onClosed?.()\r\n } catch {\r\n // ignore\r\n }\r\n resolve(false)\r\n }\r\n }\r\n\r\n window.addEventListener('message', handleMessage)\r\n\r\n try {\r\n onOpened?.()\r\n } catch {\r\n // ignore\r\n }\r\n\r\n const termUrl = redirectUri ?? getChallengeRedirectUri()\r\n\r\n initializeIframe(responseType, acsUrl, pReq, cReq, termUrl, transactionId)\r\n })\r\n}\r\n\r\n// Call this from your callback/return page.\r\n// It posts a signal back to the parent checkout window.\r\nexport function receiveOpayoResponse(message: unknown) {\r\n if (!isBrowser()) return\r\n\r\n const m = String(message || '')\r\n if (m === 'OPAYO_CALLBACK_FAILED' || m === 'OPAYO_CALLBACK_SUCCESS') {\r\n try {\r\n window.top?.postMessage(m, '*')\r\n } catch {\r\n // ignore\r\n }\r\n\r\n try {\r\n onOpayoCancelled?.()\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n}\r\n","// src/install.ts\r\nimport type { App } from 'vue'\r\n\r\nexport function OrderopiaVuePlugin() {\r\n return {\r\n install(app: App) {\r\n // nothing yet, but future-proof\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["ref","onScopeDispose","ref","onScopeDispose"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orderopia-ordering-api-client-vue",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Vue bindings for Orderopia Ordering API Client",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"vue": "^3.3.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"orderopia-ordering-api-client": "^0.
|
|
36
|
+
"orderopia-ordering-api-client": "^0.1.6"
|
|
37
37
|
}
|
|
38
38
|
}
|