From d840907c1f27c0115d04b63c213c934a7b96a324 Mon Sep 17 00:00:00 2001
From: Mamavee001 <307202201+Mamavee001@users.noreply.github.com>
Date: Fri, 28 Aug 2026 17:57:53 +0100
Subject: [PATCH] fix(web,widget): embed checkout styles and no silent host
fallback (issue 5.10)
- globals.css: real .shell--embed / .panel--embed rules - no page-level
max-width/centering/32-80px padding inside the widget's 440x680 iframe
(the outer modal
in packages/widget/src/modal.ts already supplies
the rounded corners/border/shadow, so the page inside only needs to
fill the frame). Added .checkout--embed overrides tightening heading
scale, QR wrap margins, memo-note spacing, and the status-rail/icon
sizes specifically for the narrower embed context - checked against
the "active - waiting for payment" render, the tallest of the states.
- CheckoutClient now takes an `embed` prop (threaded from
pay/[id]/page.tsx's existing isEmbed flag) so it can apply the
.checkout--embed class and use a smaller QR size (140px vs 180px) -
the one thing CSS alone can't resize, since it's a real prop on
QRCodeSVG, not a stylable dimension.
- packages/widget/src/modal.ts: deleted the DEFAULT_HOST fallback
(https://quay-web.vercel.app - the maintainer's own deployment).
openModal() now resolves the host via an explicit `host` option or the
widget's own
```
+**Self-hosting the widget?** Point the script tag at your own deployment and
+the widget infers the host from its own `
+
+ `;
+
Quay.init();
const btn = document.getElementById("pay-btn")!;
@@ -53,13 +59,14 @@ describe("Quay Widget SDK", () => {
expect(modal).not.toBeNull();
const iframe = document.getElementById("quay-checkout-iframe") as HTMLIFrameElement;
expect(iframe.src).toContain("/pay/lnk_btn_456?embed=true");
+ expect(iframe.src).toContain(TEST_HOST);
});
it("subscribes to events with Quay.on()", () => {
const onPaid = vi.fn();
const unsubscribe = Quay.on("quay:paid", onPaid);
- Quay.open("lnk_test_123");
+ Quay.open({ linkId: "lnk_test_123", host: TEST_HOST });
const event = new MessageEvent("message", {
data: { type: "quay:paid", linkId: "lnk_test_123", link: { id: "lnk_test_123" } },
@@ -75,4 +82,56 @@ describe("Quay Widget SDK", () => {
unsubscribe();
});
+
+ // ---------------------------------------------------------------------------
+ // Host resolution (issue 5.10) - no silent fallback to someone else's deployment.
+ // ---------------------------------------------------------------------------
+
+ describe("host resolution", () => {
+ it("throws a clear error when no host can be determined - no explicit host and no widget.js script tag", () => {
+ expect(() => Quay.open("lnk_test_123")).toThrow(/could not determine which Quay deployment/i);
+ // A failed open() must be a true no-op - nothing left in the DOM.
+ expect(document.getElementById("quay-checkout-modal")).toBeNull();
+ });
+
+ it("does not fall back to https://quay-web.vercel.app or any other hardcoded host", () => {
+ try {
+ Quay.open("lnk_test_123");
+ } catch {
+ /* expected */
+ }
+ expect(document.getElementById("quay-checkout-iframe")).toBeNull();
+ });
+
+ it("uses the explicit host option when given, even with no script tag present", () => {
+ Quay.open({ linkId: "lnk_test_123", host: TEST_HOST });
+ const iframe = document.getElementById("quay-checkout-iframe") as HTMLIFrameElement;
+ expect(iframe.src.startsWith(TEST_HOST)).toBe(true);
+ });
+
+ it("infers the host from the widget's own script tag when no explicit host is given", () => {
+ document.body.innerHTML = ``;
+ Quay.open("lnk_test_123");
+ const iframe = document.getElementById("quay-checkout-iframe") as HTMLIFrameElement;
+ expect(iframe.src.startsWith(TEST_HOST)).toBe(true);
+ });
+
+ it("an explicit host option takes precedence over a detected script tag", () => {
+ document.body.innerHTML = ``;
+ Quay.open({ linkId: "lnk_test_123", host: TEST_HOST });
+ const iframe = document.getElementById("quay-checkout-iframe") as HTMLIFrameElement;
+ expect(iframe.src.startsWith(TEST_HOST)).toBe(true);
+ });
+
+ it("a failed open() does not disturb a modal that was already open", () => {
+ Quay.open({ linkId: "lnk_already_open", host: TEST_HOST });
+ expect(document.getElementById("quay-checkout-modal")).not.toBeNull();
+
+ expect(() => Quay.open("lnk_no_host")).toThrow();
+
+ // The original modal, for the original link, is untouched.
+ const iframe = document.getElementById("quay-checkout-iframe") as HTMLIFrameElement;
+ expect(iframe.src).toContain("lnk_already_open");
+ });
+ });
});