bitsnap-checkout
Version:
This is Bitsnap Checkout React library for easy integration with any website which is using React framework
1,240 lines (1,215 loc) • 55.7 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
Bitsnap: () => Bitsnap,
BitsnapCheckout: () => BitsnapCart_default,
addProductToCart: () => addProductToCart,
createCheckout: () => createCheckout,
createPaymentURL: () => createPaymentURL,
handleWebhook: () => handleWebhook,
handleWebhookSignature: () => handleWebhookSignature,
hideCart: () => hideCart,
injectReferenceToRequestIfNeeded: () => injectReferenceToRequestIfNeeded,
setCustomHost: () => setCustomHost,
setProjectID: () => setProjectID,
showCart: () => showCart
});
module.exports = __toCommonJS(src_exports);
// src/components/checkout/BitsnapCart.tsx
var import_react7 = require("react");
var import_zod2 = __toESM(require("zod"));
// src/components/checkout/CartComponent.tsx
var import_react6 = require("@formkit/auto-animate/react");
var import_react_dom = require("react-dom");
// src/components/checkout/CartComponentContent.tsx
var import_react4 = require("@formkit/auto-animate/react");
var import_react5 = __toESM(require("react"));
var import_react_query2 = require("react-query");
// src/components/checkout/CartProvider.tsx
var import_react = require("react");
var import_react_query = require("react-query");
var import_zod = __toESM(require("zod"));
// src/components/checkout/constants.ts
var HOST = "https://bitsnap.pl";
function setCustomHost(host) {
HOST = host;
}
// src/components/checkout/helper.methods.ts
function buildURL(projectID, path) {
return `${HOST}/api/integrations/${projectID}/public-commerce${path}`;
}
// src/components/checkout/lib/err.ts
function isErr(x) {
return typeof x === "object" && x != null && "ERR" in x;
}
function Err(message, type) {
return { ERR: true, error: message, type };
}
// src/components/checkout/state.ts
var import_zustand = require("zustand");
var useCheckoutStore = (0, import_zustand.create)((set) => ({
isCartVisible: false,
showCart: () => set((state) => ({ ...state, isCartVisible: true })),
hideCart: () => set((state) => ({ ...state, isCartVisible: false }))
}));
// src/components/checkout/methods.ts
async function addProductToCart(id, quantity = 1, metadata) {
return Bitsnap.addProductToCart(id, quantity, metadata);
}
function showCart() {
return Bitsnap.showCart();
}
function hideCart() {
return Bitsnap.hideCart();
}
var Bitsnap;
((Bitsnap2) => {
async function addProductToCart2(id, quantity = 1, metadata) {
const projectID = getProjectID();
if (projectID == null) {
throw new Error("No project ID found");
}
const methods = getCheckoutMethods(projectID);
const err = await methods.addProduct({
productID: id,
quantity,
metadata
});
if (err != null) {
return err;
}
return void 0;
}
Bitsnap2.addProductToCart = addProductToCart2;
function showCart2() {
useCheckoutStore.setState({ isCartVisible: true });
}
Bitsnap2.showCart = showCart2;
function hideCart2() {
useCheckoutStore.setState({ isCartVisible: false });
}
Bitsnap2.hideCart = hideCart2;
})(Bitsnap || (Bitsnap = {}));
async function createPaymentURL(request) {
const projectID = getProjectID();
if (projectID == null) {
throw new Error("No project ID found");
}
request = injectReferenceToRequestIfNeeded(request);
const result = await fetch(buildURL(projectID, "/buy"), {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(request)
});
if (result.status != 200) {
console.warn(
"result",
await result.text(),
result.status,
result.statusText
);
return Err("internal-error", "internal");
}
const response = await result.json();
return {
url: response.url
};
}
async function createCheckout(request) {
const projectID = getProjectID();
if (projectID == null) {
throw new Error("No project ID found");
}
const headers = {
"Content-Type": "application/json",
...request.apiKey != null ? { Authorization: `Bearer ${request.apiKey}` } : {}
};
const path = request.testMode ? `/api/payment/link/auto/${projectID}/test` : `/api/payment/link/auto/${projectID}`;
delete request.apiKey;
delete request.testMode;
const response = await fetch(HOST + path, {
method: "POST",
headers,
body: JSON.stringify(request)
});
const payload = await response.json();
return {
status: "ok",
redirectURL: payload.url
};
}
function getReferenceIfPossible() {
if (typeof localStorage == "undefined") {
return void 0;
}
const refLink = localStorage.getItem("bitsnap-ref");
if (refLink == null) {
return void 0;
}
return refLink;
}
function injectReferenceToRequestIfNeeded(request) {
const ref = getReferenceIfPossible();
if (ref == null) {
return request;
}
if (request.metadata == null) {
request.metadata = {};
}
request.metadata["ref"] = ref;
return request;
}
// src/components/checkout/CartProvider.tsx
var import_jsx_runtime = require("react/jsx-runtime");
var MARKETING_AGREEMENT_ID = "__m_a";
var CartProviderContext = (0, import_react.createContext)(void 0);
var bitsnapProjectID = void 0;
function setProjectID(projectID) {
bitsnapProjectID = projectID;
}
function getProjectID() {
if (bitsnapProjectID != null) {
return bitsnapProjectID;
}
const me = document.querySelector(
'script[data-id][data-name="internal-cart"]'
);
const projectID = me == null ? void 0 : me.getAttribute("data-id");
return projectID != null ? projectID : void 0;
}
function getNewHostIfExist() {
const me = document.querySelector(
'script[data-id][data-name="internal-cart"]'
);
const customHost = me == null ? void 0 : me.getAttribute("data-custom-host");
return customHost != null ? customHost : void 0;
}
var CartProvider = ({ children }) => {
const queryClient = new import_react_query.QueryClient();
const projectID = getProjectID();
if (projectID == null) {
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {});
}
const checkoutMethods = getCheckoutMethods(projectID);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_query.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CartProviderContext.Provider, { value: checkoutMethods, children }) });
};
var useCartProvider = () => {
const context = (0, import_react.useContext)(CartProviderContext);
if (context === void 0) {
throw new Error("useCartProvider must be used within a CartProvider");
}
return context;
};
var CartProvider_default = CartProvider;
var checkoutSchema = import_zod.default.object({
country: import_zod.default.string().optional(),
products: import_zod.default.array(
import_zod.default.object({
id: import_zod.default.string(),
productID: import_zod.default.string(),
quantity: import_zod.default.number(),
metadata: import_zod.default.record(import_zod.default.string(), import_zod.default.string().optional()).optional()
})
).optional()
});
var emptyCheckout = {
country: void 0,
products: []
};
var checkoutKey = "checkout";
function getCheckout() {
try {
const value = localStorage.getItem(checkoutKey);
if (value == null) {
return emptyCheckout;
}
return checkoutSchema.parse(JSON.parse(value));
} catch (e) {
return emptyCheckout;
}
}
function saveCheckout(model) {
localStorage.setItem(checkoutKey, JSON.stringify(model));
}
var getCheckoutMethods = (projectID) => {
const newHost = getNewHostIfExist();
if (newHost != null) {
setCustomHost(newHost);
}
return {
async clearCart() {
var _a;
const empty = structuredClone(emptyCheckout);
empty.country = (_a = getCheckout()) == null ? void 0 : _a.country;
saveCheckout(empty);
},
async getAvailableCountries() {
const result = await fetch(buildURL(projectID, "/countries"), {
method: "GET"
});
if (result.status != 200) {
return [];
}
try {
return import_zod.default.array(
import_zod.default.object({
name: import_zod.default.string(),
code: import_zod.default.string()
})
).parse(await result.json());
} catch (e) {
return Err(e.toString(), "internal");
}
},
async getCountry() {
var _a;
let country = (_a = getCheckout()) == null ? void 0 : _a.country;
if (country == null) {
country = "PL";
const checkout = getCheckout();
checkout.country = country;
saveCheckout(checkout);
}
return country;
},
async getNumberOfElementsInCart() {
var _a, _b, _c;
return (_c = (_b = (_a = getCheckout()) == null ? void 0 : _a.products) == null ? void 0 : _b.reduce(
(acc, product) => acc + product.quantity,
0
)) != null ? _c : 0;
},
async getProducts() {
var _a, _b;
const products = (_b = (_a = getCheckout()) == null ? void 0 : _a.products) != null ? _b : [];
const productIds = Array.from(
new Set(products.map((product) => product.productID))
);
const params = new URLSearchParams();
params.set("ids", productIds.join(","));
const result = await fetch(
buildURL(projectID, `/products?${params.toString()}`),
{
method: "GET"
}
);
if (result.status != 200) {
return [];
}
const payload = await result.json();
products.forEach((product) => {
var _a2;
product["details"] = (_a2 = payload.result) == null ? void 0 : _a2.find((el) => {
if (el.id === product.productID) {
return true;
}
if (el.variants != null && el.variants.length > 0) {
const index = el.variants.findIndex(
(variant) => variant.id === product.productID
);
return index !== -1;
}
return false;
});
});
return products.filter((el) => "details" in el).map((el) => {
el.details = resolveProductDetailsFromSingleProduct(
el.productID,
el.details
);
return el;
});
},
async removeProductFromCart(args) {
var _a;
const checkout = getCheckout();
const newCheckout = {
...checkout,
products: (_a = checkout == null ? void 0 : checkout.products) == null ? void 0 : _a.filter(
(product) => product.id !== args.id
)
};
saveCheckout(newCheckout);
},
async setCountry(country) {
const checkout = getCheckout();
checkout.country = country;
saveCheckout(checkout);
},
async addProduct(args) {
const checkout = getCheckout();
if (checkout.products == null) {
checkout.products = [];
}
checkout.products.push({
id: Math.random().toString(36).substring(7),
productID: args.productID,
quantity: args.quantity,
metadata: args.metadata
});
saveCheckout(checkout);
},
async updateQuantity(args) {
var _a;
const checkout = getCheckout();
checkout.products = (_a = checkout.products) == null ? void 0 : _a.map((product) => {
if (product.id === args.id) {
product.quantity = args.quantity;
}
return product;
});
saveCheckout(checkout);
},
async redirectToNextStep() {
const checkout = getCheckout();
if (checkout.products == null || checkout.products.length == 0) {
return Err("cart-is-empty", "badInput");
}
const mergedMetadata = checkout.products.reduce(
(acc, product) => {
if (product.metadata != null) {
Object.keys(product.metadata).forEach((key) => {
var _a;
const value = (_a = product.metadata) == null ? void 0 : _a[key];
if (value != null) {
acc[key] = value;
}
});
}
return acc;
},
{}
);
const payload = {
items: checkout.products.map((el) => {
return {
id: el.productID,
quantity: el.quantity
};
}),
askForNote: true,
countries: checkout.country ? [checkout.country] : void 0,
metadata: mergedMetadata
};
const paymentResponse = await createPaymentURL(payload);
if (isErr(paymentResponse)) {
console.warn("cannot create payment URL", paymentResponse.error);
return paymentResponse;
}
return {
url: paymentResponse.url
};
},
async justRedirectToPayment(args) {
let payload = {
items: [
{
id: args.productID,
quantity: 1
}
],
askForNote: false,
details: args.email || args.name ? {
name: args.name,
email: args.email
} : void 0
};
payload = injectReferenceToRequestIfNeeded(payload);
if (args.country == null) {
args.country = "pl";
}
if (payload.details == null) {
payload.details = {};
}
if (payload.details.address == null) {
payload.details.address = {};
}
payload.details.address.country = args.country;
if (args.marketingAgreement === true) {
payload.additionalAgreements = [
{
id: MARKETING_AGREEMENT_ID,
name: "",
required: true,
answer: true
}
];
}
const result = await fetch(buildURL(projectID, "/buy"), {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
console.log("CODE", result.status);
if (result.status != 200) {
console.warn(
"result",
await result.text(),
result.status,
result.statusText
);
return Err("internal-error", "internal");
}
const response = await result.json();
console.log(response.url);
return {
url: response.url
};
}
};
};
function resolveProductDetailsFromSingleProduct(id, product) {
var _a, _b;
if (id == product.id) {
return product;
}
const variant = (_a = product.variants) == null ? void 0 : _a.find((v) => v.id === id);
if (variant == null) {
return product;
}
return {
...product,
id: variant.id,
name: product.name + " " + variant.name,
price: variant.price,
currency: variant.currency,
metadata: product.metadata,
availableQuantity: variant.availableQuantity,
isDeliverable: variant.isDeliverable,
images: (_b = variant.images) != null ? _b : product.images
};
}
// src/components/checkout/CountrySelector.tsx
var import_framer_motion = require("framer-motion");
var import_react2 = require("react");
var import_jsx_runtime2 = require("react/jsx-runtime");
function CountrySelector({
id,
open,
disabled = false,
onToggle,
onChange,
selectedValue,
countries
}) {
var _a;
const ref = (0, import_react2.useRef)(null);
(0, import_react2.useEffect)(() => {
const mutableRef = ref;
const handleClickOutside = (event) => {
if (mutableRef.current && // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
!mutableRef.current.contains(event.target) && open) {
onToggle();
setQuery("");
}
};
window.document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref]);
(0, import_react2.useEffect)(() => {
if (selectedValue == null && countries.length > 0) {
onChange(countries[0].code);
}
}, []);
const [query, setQuery] = (0, import_react2.useState)("");
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "relative", children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
"button",
{
type: "button",
className: `${disabled ? "ics-bg-neutral-100" : "ics-bg-extra-light-white"} ics-relative ics-w-full ics-rounded-2xl ics-shadow-sm ics-pl-8 ics-pr-10 ics-py-3 ics-text-left ics-cursor-default focus:ics-outline-none focus:ics-ring-1 focus:ics-ring-blue-500 focus:ics-border-blue-500 sm:ics-text-sm`,
"aria-haspopup": "listbox",
"aria-expanded": "true",
"aria-labelledby": "listbox-label",
onClick: onToggle,
disabled,
children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "ics-truncate ics-flex ics-items-center", children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"img",
{
alt: `${selectedValue}`,
src: `https://purecatamphetamine.github.io/country-flag-icons/3x2/${selectedValue}.svg`,
className: "ics-inline ics-mr-2 ics-h-4 ics-rounded-sm"
}
),
(_a = countries.find((el) => el.code === selectedValue)) == null ? void 0 : _a.name
] }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"span",
{
className: `ics-absolute ics-inset-y-0 ics-right-0 ics-flex ics-items-center ics-pr-2 ics-pointer-events-none ${disabled ? "ics-hidden" : ""}`,
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"svg",
{
className: "h-5 w-5 text-light-purple",
xmlns: "http://www.w3.org/2000/svg",
viewBox: "0 0 20 20",
fill: "currentColor",
"aria-hidden": "true",
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"path",
{
fillRule: "evenodd",
d: "M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z",
clipRule: "evenodd"
}
)
}
)
}
)
]
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_framer_motion.AnimatePresence, { children: open && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
import_framer_motion.motion.ul,
{
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 },
transition: { duration: 0.1 },
className: "ics-absolute ics-z-10 -ics-mt-80 ics-w-full dark:ics-bg-neutral-800 ics-bg-white ics-shadow-lg ics-max-h-80 ics-rounded-md ics-text-body-regular ics-ring-1 ics-ring-black ics-ring-opacity-5 focus:ics-outline-none sm:ics-text-body-regular",
tabIndex: -1,
role: "listbox",
"aria-labelledby": "listbox-label",
"aria-activedescendant": "listbox-option-3",
children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ics-sticky ics-top-0 ics-z-10 ics-bg-white dark:ics-bg-neutral-800", children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { className: "dark:ics-text-neutral-200 ics-text-neutral-900 ics-cursor-default ics-select-none ics-relative ics-py-2 ics-px-3", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"input",
{
type: "search",
name: "search",
autoComplete: "off",
className: "ics-block ics-w-full ics-outline-none sm:ics-text-body-regular dark:ics-text-neutral-400 ics-text-dark-blue ics-bg-transparent ics-border-light-purple ics-rounded-md placeholder:ics-text-light-purple",
placeholder: "Znajd\u017A kraj",
onChange: (e) => setQuery(e.target.value)
}
) }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("hr", {})
] }),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"div",
{
className: "ics-max-h-64 ics-scrollbar ics-scrollbar-track-gray-100 ics-scrollbar-thumb-gray-300 hover:ics-scrollbar-thumb-gray-600 ics-scrollbar-thumb-rounded ics-scrollbar-thin ics-overflow-y-scroll",
children: countries.filter(
(country) => country.name.toLowerCase().startsWith(query.toLowerCase())
).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { className: "ics-text-light-purple ics-cursor-default ics-select-none ics-relative ics-py-2 ics-pl-3 ics-pr-9", children: "No countries found" }) : countries.filter(
(country) => country.name.toLowerCase().startsWith(query.toLowerCase())
).map((value, index) => {
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
"li",
{
className: "ics-text-dark-blue ics-cursor-default ics-select-none ics-relative ics-py-2 ics-pl-3 ics-pr-9 ics-flex ics-items-center hover:ics-bg-extra-light-white ics-transition",
id: "listbox-option-0",
role: "option",
onClick: () => {
onChange(value.code);
setQuery("");
onToggle();
},
children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"img",
{
alt: `${value.code}`,
src: `https://purecatamphetamine.github.io/country-flag-icons/3x2/${value.code}.svg`,
className: "ics-inline ics-mr-2 ics-h-4 ics-rounded-sm"
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ics-font-normal ics-truncate", children: value.name }),
value.code === selectedValue ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"span",
{
className: "ics-text-blue-600 ics-absolute ics-inset-y-0 ics-right-0 ics-flex ics-items-center ics-pr-8",
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"svg",
{
className: "h-5 w-5",
xmlns: "http://www.w3.org/2000/svg",
viewBox: "0 0 20 20",
fill: "currentColor",
"aria-hidden": "true",
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"path",
{
fillRule: "evenodd",
d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",
clipRule: "evenodd"
}
)
}
)
}
) : null
]
},
`${id}-${index}`
);
})
}
)
]
}
) })
] }) });
}
var CountrySelector_default = CountrySelector;
// src/components/checkout/lib/round.number.ts
function formatCurrency(amount, currency) {
const formatter = Intl.NumberFormat(navigator.language, {
style: "currency",
currency,
currencyDisplay: "symbol"
});
return formatter.format(amount / 100);
}
// src/components/checkout/LoadingIndicator.tsx
var import_jsx_runtime3 = require("react/jsx-runtime");
var LoadingIndicator = ({ className }) => {
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LoadingSpinner, { className: className != null ? className : "" });
};
var LoadingIndicator_default = LoadingIndicator;
var LoadingSpinner = ({ size, color, className }) => {
const spinnerStyle = {
borderTop: `4px solid ${color}`,
borderLeft: `4px solid ${color}`,
borderBottom: `4px solid ${color}`,
borderRight: "4px solid transparent",
width: size != null ? size : "30px",
height: size != null ? size : "30px",
borderRadius: "50%"
};
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: className + " animate-spin", style: spinnerStyle });
};
// src/components/checkout/SingleProduct.tsx
var import_react3 = require("react");
var import_jsx_runtime4 = require("react/jsx-runtime");
var SingleProduct = ({ quantity, details, shouldUpdate }) => {
var _a;
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ics-flex ics-items-center ics-gap-3", children: [
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { className: "ics-aspect-auto ics-max-w-[30%]", src: (_a = details.image_url) != null ? _a : "", alt: details.name }),
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ics-flex ics-flex-col", children: [
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "ics-font-medium", children: details.name }),
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "ics-text-sm", children: formatCurrency(details.price, details.currency) }),
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ics-flex ics-justify-between", children: [
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QuantityComponent, { className: "", quantity, shouldUpdate }),
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "ics-text-sm ics-font-medium", onClick: () => shouldUpdate(0), children: "Usu\u0144" })
] })
] })
] });
};
var SingleProduct_default = SingleProduct;
var QuantityComponent = ({
quantity,
shouldUpdate,
className
}) => {
const [quantityString, setQuantityString] = (0, import_react3.useState)(quantity.toString());
const [quantityValue, setQuantityValue] = (0, import_react3.useState)(quantity);
(0, import_react3.useEffect)(() => {
shouldUpdate(quantityValue);
}, [quantityValue]);
function setNewQuantity(newQuantity) {
setQuantityString(newQuantity);
if (newQuantity.length == 0) {
return;
}
const parsedInt = parseInt(newQuantity);
if (isNaN(parsedInt)) {
setQuantityValue(1);
setQuantityString("");
return;
}
if (parsedInt == 0 || parsedInt < 0) {
setQuantityValue(1);
setQuantityString("1");
return;
}
setQuantityValue(parsedInt);
setQuantityString(parsedInt.toString());
}
function increaseQuantity() {
setQuantityValue(quantity + 1);
setQuantityString((quantity + 1).toString());
}
function decreaseQuantity() {
if (quantity > 1) {
setQuantityString((quantity - 1).toString());
setQuantityValue(quantity - 1);
return;
}
setQuantityString(quantity.toString());
setQuantityValue(quantity);
}
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `ics-flex ${className} ics-items-center ics-border dark:ics-border-neutral-400 ics-border-neutral-700 ics-rounded-md ics-my-1`, children: [
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: decreaseQuantity, className: "ics-px-2 ics-py-1", children: "-" }),
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
"input",
{
className: "ics-w-8 ics-bg-transparent ics-text-center",
value: quantityString,
onInput: (e) => {
setNewQuantity(e.currentTarget.value);
},
type: "text"
}
),
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: increaseQuantity, className: "ics-px-2 ics-py-1", children: "+" })
] });
};
// src/components/checkout/CartComponentContent.tsx
var import_jsx_runtime5 = require("react/jsx-runtime");
var CartComponentContent = ({ className }) => {
var _a, _b, _c, _d, _e;
const provider = useCartProvider();
const { mutateAsync: removeProduct } = (0, import_react_query2.useMutation)(
provider.removeProductFromCart
);
const { mutateAsync: updateQuantity } = (0, import_react_query2.useMutation)(provider.updateQuantity);
const { mutateAsync: setCountryAsync } = (0, import_react_query2.useMutation)(provider.setCountry);
const { mutateAsync: clearCart } = (0, import_react_query2.useMutation)(provider.clearCart);
const [errMsg, setErrMsg] = import_react5.default.useState("");
const [isCountryOpen, setIsCountryOpen] = import_react5.default.useState(false);
const {
mutateAsync: continueToCheckoutAsync,
isLoading: isContinueToCheckoutLoading
} = (0, import_react_query2.useMutation)(provider.redirectToNextStep);
const { data: availableCountries } = (0, import_react_query2.useQuery)(
"cart-available-countries",
provider.getAvailableCountries
);
const { data, isLoading, refetch } = (0, import_react_query2.useQuery)("cart", provider.getProducts);
const { data: countryData, refetch: refetchCountry } = (0, import_react_query2.useQuery)(
"cart-country",
provider.getCountry
);
const [productsParent] = (0, import_react4.useAutoAnimate)(
/* optional config */
);
const products = isErr(data) ? void 0 : data;
const countries = isErr(availableCountries) ? [] : availableCountries;
const sumOfProducts = (_a = products == null ? void 0 : products.reduce((prev, curr) => {
if (curr.details == null) {
return prev;
}
return prev + curr.details.price * curr.quantity;
}, 0)) != null ? _a : 0;
const currency = (_d = (_c = (_b = products == null ? void 0 : products[0]) == null ? void 0 : _b.details) == null ? void 0 : _c.currency) != null ? _d : "PLN";
const isSomeProductDeliverable = (_e = products == null ? void 0 : products.some((product) => {
var _a2;
return ((_a2 = product.details) == null ? void 0 : _a2.isDeliverable) === true;
})) != null ? _e : false;
const selectedCountry = countryData != null && !isErr(countryData) && countryData != "" ? countryData : void 0;
async function shouldUpdate(id, newQuantity) {
if (newQuantity != null) {
if (newQuantity <= 0) {
await removeProduct({ id });
await refetch();
return;
}
await updateQuantity({
id,
quantity: newQuantity
});
await refetch();
return;
}
}
async function continueToCheckout() {
try {
setErrMsg("");
const response = await continueToCheckoutAsync();
if (isErr(response)) {
setErrMsg(`${response.error}`);
return;
}
await clearCart();
window.location.href = response.url;
} catch (e) {
setErrMsg(`${e}`);
}
}
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `${className} ics-flex ics-flex-col`, ref: productsParent, children: [
isLoading && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ics-flex ics-w-full ics-justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LoadingIndicator_default, {}) }),
!isLoading && (products == null || products.length == 0) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ics-flex ics-flex-col ics-gap-4 ics-p-4", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dark:ics-text-neutral-400 ics-text-neutral-700", children: "Brak produkt\xF3w w koszyku." }) }),
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
"div",
{
className: "ics-max-h-[70vh] ics-overflow-clip ics-overflow-y-scroll",
children: products != null && products.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "ics-mt-5", children: products.map((product) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react5.default.Fragment, { children: product.details != null && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { className: "mb-3", children: [
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
SingleProduct_default,
{
quantity: product.quantity,
details: product.details,
shouldUpdate: (newQuantity) => {
shouldUpdate(product.id, newQuantity).then().catch();
}
}
),
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("hr", { className: "ics-h-1 dark:ics-border-neutral-700 ics-border-neutral-400" })
] }) }, product.id)) })
}
),
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "grow" }),
sumOfProducts > 0 && currency != null && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ics-mx-3 ics-flex ics-flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
"div",
{
className: "ics-flex ics-flex-row ics-justify-between ics-text-lg",
children: [
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
"p",
{
className: "dark:ics-text-neutral-200 ics-text-neutral-800 ics-text-xl",
children: "Suma:"
}
),
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ics-flex ics-flex-col ics-items-end", children: [
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
"p",
{
className: "dark:ics-text-neutral-200 ics-text-neutral-800 ics-font-medium",
children: formatCurrency(sumOfProducts, currency)
}
),
isSomeProductDeliverable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ics-opacity-70 ics-text-right ics-text-base", children: "+ dostawa" })
] })
]
}
) }),
countries && (countries == null ? void 0 : countries.length) > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
"h4",
{
className: "ics-ml-3 ics-text-sm dark:ics-text-neutral-400 ics-text-neutral-700",
children: "Wybierz kraj"
}
),
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
CountrySelector_default,
{
id: Math.random().toString(),
open: isCountryOpen,
onToggle: () => {
setIsCountryOpen(!isCountryOpen);
},
onChange: (newValue) => {
setCountryAsync(newValue).then(() => {
refetchCountry().then().catch();
});
},
selectedValue: selectedCountry != null ? selectedCountry : "",
countries
}
)
] }),
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ics-mb-3 ics-flex ics-flex-col", children: [
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
"button",
{
onClick: continueToCheckout,
disabled: isLoading || isContinueToCheckoutLoading || selectedCountry == null,
className: "ics-px-3 ics-py-2 ics-my-2 ics-mx-2 ics-rounded-md disabled:ics-opacity-40 disabled:ics-cursor-not-allowed dark:ics-bg-neutral-300 dark:hover:ics-bg-neutral-100 dark:ics-text-neutral-800 hover:ics-bg-neutral-900 ics-text-neutral-200 ics-bg-neutral-800 ics-transition ics-font-bold",
children: isContinueToCheckoutLoading ? "\u0141adowanie..." : "Nast\u0119pny krok"
}
),
errMsg.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ics-text-red-500 ics-text-sm ics-text-center", children: errMsg })
] })
] })
] });
};
var CartComponentContent_default = CartComponentContent;
// src/components/checkout/CartComponent.tsx
var import_jsx_runtime6 = require("react/jsx-runtime");
function CartComponent({ isVisible, shouldHide }) {
const [parent] = (0, import_react6.useAutoAnimate)(
/* optional config */
);
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: parent, className: "ics-z-[999999]", children: isVisible && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
"div",
{
className: "ics-fixed ics-top-0 ics-right-0 ics-left-0 ics-bottom-0 ics-bg-black/30 ics-cursor-pointer",
onClick: shouldHide
}
),
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
"div",
{
className: "ics-fixed ics-top-0 ics-right-0 ics-bottom-0 ics-w-full md:ics-w-[350px] xl:ics-w-[420px] dark:ics-bg-neutral-900 ics-bg-neutral-300 dark:ics-text-neutral-200 ics-text-neutral-900 ics-flex ics-flex-col",
children: [
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
"div",
{
className: "ics-mx-3 ics-mt-7 ics-flex ics-justify-between ics-items-center",
children: [
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { className: "text-2xl font-medium", children: "Koszyk" }),
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
"button",
{
className: "ics-rounded-full dark:hover:ics-bg-neutral-700 hover:ics-bg-neutral-400 ics-p-2 ics-transition",
onClick: shouldHide,
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
width: "24",
height: "24",
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round",
className: "lucide lucide-x",
children: [
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
]
}
)
}
)
]
}
),
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CartComponentContent_default, { className: "grow" })
]
}
)
] }) });
}
var WrapperCartComponent = (props) => {
if (typeof window === "undefined") {
return null;
}
return (0, import_react_dom.createPortal)(
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CartProvider_default, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CartComponent, { ...props }) }),
document.body
);
};
var CartComponent_default = WrapperCartComponent;
// src/components/checkout/BitsnapCart.tsx
var import_jsx_runtime7 = require("react/jsx-runtime");
var cartAddToCartSchema = import_zod2.default.object({
id: import_zod2.default.string(),
isSubscription: import_zod2.default.boolean().default(false),
quantity: import_zod2.default.number(),
metadata: import_zod2.default.record(import_zod2.default.string(), import_zod2.default.string().optional()).optional()
});
function BitsnapCart({
projectID,
children,
onVisibleChange,
className
}) {
const { isCartVisible, showCart: showCart2, hideCart: hideCart2 } = useCheckoutStore();
function sentPostMessageToIframe(msg) {
const iframes = document.querySelectorAll("iframe");
iframes.forEach((iframe) => {
var _a;
(_a = iframe.contentWindow) == null ? void 0 : _a.postMessage(msg, "*");
});
}
(0, import_react7.useEffect)(() => {
onVisibleChange == null ? void 0 : onVisibleChange(isCartVisible);
}, [isCartVisible]);
(0, import_react7.useEffect)(() => {
setProjectID(projectID);
}, [projectID]);
(0, import_react7.useEffect)(() => {
if (!("cart" in window)) {
const projectID2 = getProjectID();
if (projectID2 == null) {
console.warn("There is no project ID configured.");
return;
}
window["cart"] = {
buyProduct: async (args) => {
try {
const payload = import_zod2.default.object({
productID: import_zod2.default.string(),
email: import_zod2.default.string().optional(),
name: import_zod2.default.string().optional(),
country: import_zod2.default.string().optional(),
marketingAgreement: import_zod2.default.boolean().optional()
}).parse(args);
const methods = getCheckoutMethods(projectID2);
const result = await methods.justRedirectToPayment(payload);
console.log("result", result);
if (isErr(result) == false) {
window.location.href = result.url;
} else {
alert(
"Nie uda\u0142o si\u0119 przekierowa\u0107 do p\u0142atno\u015Bci. Spr\xF3buj ponownie p\xF3\u017Aniej."
);
}
} catch (e) {
console.warn(e);
}
}
};
}
}, []);
async function handleAddingToCart(id, payload) {
const projectID2 = getProjectID();
if (projectID2 == null) {
console.warn("There is no project ID configured.");
return;
}
try {
const data = cartAddToCartSchema.parse(payload);
if (data.isSubscription) {
await handleAddingSubscriptionToCart(projectID2, data);
return;
}
const methods = getCheckoutMethods(projectID2);
await methods.addProduct({
productID: data.id,
quantity: data.quantity,
metadata: data.metadata
});
sentPostMessageToIframe({
id,
type: "ADD_TO_CART" /* ADD_TO_CART */,
success: true
});
showCart2();
} catch (e) {
console.warn("cannot add item to cart", e);
}
}
async function handleAddingSubscriptionToCart(projectID2, event) {
alert(
`TODO, nie jest to jeszcze zrobione ${projectID2} ${event.id} ${event.quantity}`
);
}
function setupEventListener() {
if ("__cart_is_listening" in window) {
return;
}
window["__cart_is_listening"] = true;
window.addEventListener("message", (event) => {
if (typeof event.data["id"] != "undefined" && typeof event.data["type"] != "undefined") {
const { id, type } = event.data;
switch (type) {
case "ADD_TO_CART" /* ADD_TO_CART */.toString():
handleAddingToCart(id, event.data["payload"]).then().catch();
break;
default:
break;
}
}
});
}
(0, import_react7.useEffect)(() => {
var _a;
setupEventListener();
if (typeof window !== "undefined") {
try {
const parsedParams = new URLSearchParams(window.location.search);
const refLink = (_a = parsedParams.get("ref")) != null ? _a : parsedParams.get("utm-source");
if (typeof localStorage != "undefined" && refLink && refLink.length > 0) {
localStorage.setItem("bitsnap-ref", refLink);
}
} catch (e) {
return;
}
}
}, []);
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
"button",
{
onClick: () => isCartVisible ? hideCart2() : showCart2(),
className: className != null ? className : "ics-rounded-full hover:ics-bg-neutral-300 ics-transition ics-p-1",
children: children ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
width: "24",
height: "24",
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round",
className: "lucide lucide-shopping-cart",
children: [
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "8", cy: "21", r: "1" }),
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "19", cy: "21", r: "1" }),
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12" })
]
}
)
}
),
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
CartComponent_default,
{
isVisible: isCartVisible,
shouldHide: () => {
hideCart2();
}
}
)
] });
}
var BitsnapCart_default = BitsnapCart;
// src/components/webhook.handler.ts
var import_protobuf = require("@bufbuild/protobuf");
var import_crypto = __toESM(require("crypto"));
// src/gen/proto/jobs/v1/integration_event_job_pb.ts
var import_codegenv15 = require("@bufbuild/protobuf/codegenv1");
// src/gen/proto/common/v1/environment_pb.ts
var import_codegenv1 = require("@bufbuild/protobuf/codegenv1");
var file_common_v1_environment = /* @__PURE__ */ (0, import_codegenv1.fileDesc)("Chtjb21tb24vdjEvZW52aXJvbm1lbnQucHJvdG8SCWNvbW1vbi52MSonCgtFbnZpcm9ubWVudBIOCgpQUk9EVUNUSU9OEAASCAoEVEVTVBABQk5aTGdpdGh1Yi5jb20vZW1tZW1zL3N1cGVyLWNhcnQvYXBwcy9zcnYtd29ya2VyL3V0aWxzL21vZGVscy9jb21tb24vdjE7Y29tbW9udjFiBnByb3RvMw");
// src/gen/proto/integrations/v1/event_data_pb.ts
var import_codegenv14 = require("@bufbuild/protobuf/codegenv1");
// src/gen/proto/integrations/v1/order_pb.ts
var import_codegenv13 = require("@bufbuild/protobuf/codegenv1");
// src/gen/proto/common/v1/gateway_pb.ts
var import_codegenv12 = require("@bufbuild/protobuf/codegenv1");
var file_common_v1_gateway = /* @__PURE__ */ (0, import_codegenv12.fileDesc)("Chdjb21tb24vdjEvZ2F0ZXdheS5wcm90bxIJY29tbW9uLnYxKokBCgdHYXRld2F5Eg8KC0dBVEVXQVlfQUxMEAASFwoTR0FURVdBWV9QUlpFTEVXWV8yNBABEhIKDkdBVEVXQVlfU1RSSVBFEAISEAoMR0FURVdBWV9UUEFZEAMSHAoYR0FURVdBWV9DQVNIX09OX0RFTElWRVJZEAQSEAoMR0FURVdBWV9GUkVFEAVCTlpMZ2l0aHViLmNvbS9lbW1lbXMvc3VwZXItY2FydC9hcHBzL3Nydi13b3JrZXIvdXRpbHMvbW9kZWxzL2NvbW1vbi92MTtjb21tb252MWIGcHJvdG8z");
// src/gen/proto/integrations/v1/order_pb.ts
var import_wkt = require("@bufbuild/protobuf/wkt");
var file_integrations_v1_order = /* @__PURE__ */ (0, import_codegenv13.fileDesc)("ChtpbnRlZ3JhdGlvbnMvdjEvb3JkZXIucHJvdG8SD2ludGVncmF0aW9ucy52MSKHBAoFT3JkZXISCgoCaWQYASABKAkSLAoGc3RhdHVzGAIgASgOMhwuaW50ZWdyYXRpb25zLnYxLk9yZGVyU3RhdHVzEisKC2Vudmlyb25tZW50GAMgASgOMhYuY29tbW9uLnYxLkVudmlyb25tZW50EikKBWl0ZW1zGAQgAygLMhouaW50ZWdyYXRpb25zLnYxLk9yZGVySXRlbRIbChNhdmFpbGFibGVfY291bnRyaWVzGAUgAygJEj0KD2JpbGxpbmdfYWRkcmVzcxgGIAEoCzIfLmludGVncmF0aW9ucy52MS5CaWxsaW5nQWRkcmVzc0gAiAEBEjcKEHNoaXBwaW5nX2FkZHJlc3MYByABKAsyGC5pbnRlZ3JhdGlvbnMudjEuQWRkcmVzc0gBiAEBEjMKB2RldGFpbHMYCCABKAsyHS5pbnRlZ3JhdGlvbnMudjEuT3JkZXJEZXRhaWxzSAKIAQESMAoIY3VzdG9tZXIYCSABKAsyGS5pbnRlZ3JhdGlvbnMudjEuQ3VzdG9tZXJIA4gBARIuCgpjcmVhdGVkX2F0GAogASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEISChBfYmlsbGluZ19hZGRyZXNzQhMKEV9zaGlwcGluZ19hZGRyZXNzQgoKCF9kZXRhaWxzQgsKCV9jdXN0b21lciKLBwoMT3JkZXJEZXRhaWxzEiMKB2dhdGV3YXkYASABKA4yEi5jb21tb24udjEuR2F0ZXdheRI5ChBkZWxpdmVyeV9tZXRob2RzGAIgAygLMh8uaW50ZWdyYXRpb25zLnYxLkRlbGl2ZXJ5TWV0aG9kEiIKFWRlbGl2ZXJ5X21ldGhvZF9wcmljZRgDIAEoA0gAiAEBEhwKD2RlbGl2ZXJ5X21ldGhvZBgEIAEoCUgBiAEBEhUKDWFza19mb3JfcGhvbmUYBiABKAgSFAoMYXNrX2Zvcl9ub3RlGAcgASgIEhMKC2Fza19mb3JfbmlwGAggASgIEhgKC2NvdXBvbl9jb2RlGAkgASgJSAKIAQESIwoWY291cG9uX2Rpc2NvdW50X2Ftb3VudBgKIAEoA0gDiAEBEiUKGGNvdXBvbl9kaXNjb3VudF9jdXJyZW5jeRgLIAEoCUgEiAEBEiEKFGNvdXBvbl9kaXNjb3VudF90eXBlGAwgASgJSAWIAQESJQoYY291cG9uX2luY2x1ZGVzX2RlbGl2ZXJ5GA0gASgISAaIAQESGAoLc3VjY2Vzc191cmwYDiABKAlIB4gBARIXCgpjYW5jZWxfdXJsGA8gASgJSAiIAQESHwoScGF5bWVudF9nYXRld2F5X2lkGBAgASgJSAmIAQESPQoIbWV0YWRhdGEYESADKAsyKy5pbnRlZ3JhdGlvbnMudjEuT3JkZXJEZXRhaWxzLk1ldGFkYXRhRW50cnkSQQoVYWRkaXRpb25hbF9hZ3JlZW1lbnRzGBIgAygLMiIuaW50ZWdyYXRpb25zLnYxLkNoZWNrb3V0QWd