medusa-paystack-plugin 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ const jsxRuntime = require("react/jsx-runtime");
3
+ const react = require("react");
4
+ const adminSdk = require("@medusajs/admin-sdk");
5
+ const ui = require("@medusajs/ui");
6
+ const reactQuery = require("@tanstack/react-query");
7
+ const Medusa = require("@medusajs/js-sdk");
8
+ const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
9
+ const Medusa__default = /* @__PURE__ */ _interopDefault(Medusa);
10
+ const PAYSTACK_PUBLISHABLE_KEY_METADATA = "paystack_publishable_key";
11
+ const sdk = new Medusa__default.default({
12
+ auth: {
13
+ type: "session"
14
+ },
15
+ baseUrl: "/",
16
+ debug: false
17
+ });
18
+ const queryKeyForStore = (storeId) => [["paystack-store", storeId]];
19
+ const StorePaystackSettingsWidget = ({
20
+ data: store
21
+ }) => {
22
+ const queryClient = reactQuery.useQueryClient();
23
+ const [publishableKey, setPublishableKey] = react.useState("");
24
+ const [errorMessage, setErrorMessage] = react.useState(null);
25
+ const { data, isLoading } = reactQuery.useQuery({
26
+ queryFn: async () => sdk.admin.store.retrieve(store.id),
27
+ queryKey: queryKeyForStore(store.id)
28
+ });
29
+ react.useEffect(() => {
30
+ var _a;
31
+ const savedKey = (_a = data == null ? void 0 : data.store.metadata) == null ? void 0 : _a[PAYSTACK_PUBLISHABLE_KEY_METADATA];
32
+ if (typeof savedKey === "string") {
33
+ setPublishableKey(savedKey);
34
+ return;
35
+ }
36
+ setPublishableKey("");
37
+ }, [data == null ? void 0 : data.store.metadata]);
38
+ const mutation = reactQuery.useMutation({
39
+ mutationFn: async (value) => {
40
+ const nextValue = value.trim();
41
+ const currentMetadata = (data == null ? void 0 : data.store.metadata) ?? {};
42
+ return sdk.admin.store.update(store.id, {
43
+ metadata: {
44
+ ...currentMetadata,
45
+ [PAYSTACK_PUBLISHABLE_KEY_METADATA]: nextValue || null
46
+ }
47
+ });
48
+ },
49
+ onError: (error) => {
50
+ setErrorMessage(
51
+ error instanceof Error ? error.message : "Unable to update the Paystack key."
52
+ );
53
+ },
54
+ onSuccess: async () => {
55
+ setErrorMessage(null);
56
+ await queryClient.invalidateQueries({
57
+ queryKey: queryKeyForStore(store.id)
58
+ });
59
+ }
60
+ });
61
+ const handleSave = async () => {
62
+ const nextValue = publishableKey.trim();
63
+ if (nextValue && !nextValue.startsWith("pk_")) {
64
+ setErrorMessage("Paystack publishable keys must start with pk_.");
65
+ return;
66
+ }
67
+ await mutation.mutateAsync(nextValue);
68
+ };
69
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
70
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
71
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: "Paystack" }),
72
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle mt-1", size: "small", children: "Configure the public Paystack key used by storefront and mobile webview flows." })
73
+ ] }) }),
74
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 px-6 py-4", children: [
75
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
76
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "paystack-publishable-key", children: "Publishable key" }),
77
+ /* @__PURE__ */ jsxRuntime.jsx(
78
+ ui.Input,
79
+ {
80
+ autoComplete: "off",
81
+ id: "paystack-publishable-key",
82
+ onChange: (event) => setPublishableKey(event.target.value),
83
+ placeholder: "pk_test_xxxxxxxxxxxxx",
84
+ value: publishableKey
85
+ }
86
+ ),
87
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", size: "small", children: "Leave this blank to remove the stored key for this store." })
88
+ ] }),
89
+ errorMessage ? /* @__PURE__ */ jsxRuntime.jsx(ui.Alert, { variant: "error", children: errorMessage }) : null,
90
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
91
+ /* @__PURE__ */ jsxRuntime.jsx(
92
+ ui.Button,
93
+ {
94
+ disabled: isLoading || mutation.isPending,
95
+ isLoading: mutation.isPending,
96
+ onClick: handleSave,
97
+ size: "small",
98
+ children: "Save key"
99
+ }
100
+ ),
101
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", size: "small", children: isLoading ? "Loading current store settings…" : "Changes are stored in store metadata." })
102
+ ] })
103
+ ] })
104
+ ] });
105
+ };
106
+ adminSdk.defineWidgetConfig({
107
+ zone: "store.details.after"
108
+ });
109
+ const i18nTranslations0 = {};
110
+ const widgetModule = { widgets: [
111
+ {
112
+ Component: StorePaystackSettingsWidget,
113
+ zone: ["store.details.after"]
114
+ }
115
+ ] };
116
+ const routeModule = {
117
+ routes: []
118
+ };
119
+ const menuItemModule = {
120
+ menuItems: []
121
+ };
122
+ const formModule = { customFields: {} };
123
+ const displayModule = {
124
+ displays: {}
125
+ };
126
+ const i18nModule = { resources: i18nTranslations0 };
127
+ const plugin = {
128
+ widgetModule,
129
+ routeModule,
130
+ menuItemModule,
131
+ formModule,
132
+ displayModule,
133
+ i18nModule
134
+ };
135
+ module.exports = plugin;
@@ -0,0 +1,134 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useState, useEffect } from "react";
3
+ import { defineWidgetConfig } from "@medusajs/admin-sdk";
4
+ import { Container, Heading, Text, Label, Input, Alert, Button } from "@medusajs/ui";
5
+ import { useQueryClient, useQuery, useMutation } from "@tanstack/react-query";
6
+ import Medusa from "@medusajs/js-sdk";
7
+ const PAYSTACK_PUBLISHABLE_KEY_METADATA = "paystack_publishable_key";
8
+ const sdk = new Medusa({
9
+ auth: {
10
+ type: "session"
11
+ },
12
+ baseUrl: "/",
13
+ debug: false
14
+ });
15
+ const queryKeyForStore = (storeId) => [["paystack-store", storeId]];
16
+ const StorePaystackSettingsWidget = ({
17
+ data: store
18
+ }) => {
19
+ const queryClient = useQueryClient();
20
+ const [publishableKey, setPublishableKey] = useState("");
21
+ const [errorMessage, setErrorMessage] = useState(null);
22
+ const { data, isLoading } = useQuery({
23
+ queryFn: async () => sdk.admin.store.retrieve(store.id),
24
+ queryKey: queryKeyForStore(store.id)
25
+ });
26
+ useEffect(() => {
27
+ var _a;
28
+ const savedKey = (_a = data == null ? void 0 : data.store.metadata) == null ? void 0 : _a[PAYSTACK_PUBLISHABLE_KEY_METADATA];
29
+ if (typeof savedKey === "string") {
30
+ setPublishableKey(savedKey);
31
+ return;
32
+ }
33
+ setPublishableKey("");
34
+ }, [data == null ? void 0 : data.store.metadata]);
35
+ const mutation = useMutation({
36
+ mutationFn: async (value) => {
37
+ const nextValue = value.trim();
38
+ const currentMetadata = (data == null ? void 0 : data.store.metadata) ?? {};
39
+ return sdk.admin.store.update(store.id, {
40
+ metadata: {
41
+ ...currentMetadata,
42
+ [PAYSTACK_PUBLISHABLE_KEY_METADATA]: nextValue || null
43
+ }
44
+ });
45
+ },
46
+ onError: (error) => {
47
+ setErrorMessage(
48
+ error instanceof Error ? error.message : "Unable to update the Paystack key."
49
+ );
50
+ },
51
+ onSuccess: async () => {
52
+ setErrorMessage(null);
53
+ await queryClient.invalidateQueries({
54
+ queryKey: queryKeyForStore(store.id)
55
+ });
56
+ }
57
+ });
58
+ const handleSave = async () => {
59
+ const nextValue = publishableKey.trim();
60
+ if (nextValue && !nextValue.startsWith("pk_")) {
61
+ setErrorMessage("Paystack publishable keys must start with pk_.");
62
+ return;
63
+ }
64
+ await mutation.mutateAsync(nextValue);
65
+ };
66
+ return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
67
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-6 py-4", children: /* @__PURE__ */ jsxs("div", { children: [
68
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Paystack" }),
69
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle mt-1", size: "small", children: "Configure the public Paystack key used by storefront and mobile webview flows." })
70
+ ] }) }),
71
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 px-6 py-4", children: [
72
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
73
+ /* @__PURE__ */ jsx(Label, { htmlFor: "paystack-publishable-key", children: "Publishable key" }),
74
+ /* @__PURE__ */ jsx(
75
+ Input,
76
+ {
77
+ autoComplete: "off",
78
+ id: "paystack-publishable-key",
79
+ onChange: (event) => setPublishableKey(event.target.value),
80
+ placeholder: "pk_test_xxxxxxxxxxxxx",
81
+ value: publishableKey
82
+ }
83
+ ),
84
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", size: "small", children: "Leave this blank to remove the stored key for this store." })
85
+ ] }),
86
+ errorMessage ? /* @__PURE__ */ jsx(Alert, { variant: "error", children: errorMessage }) : null,
87
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
88
+ /* @__PURE__ */ jsx(
89
+ Button,
90
+ {
91
+ disabled: isLoading || mutation.isPending,
92
+ isLoading: mutation.isPending,
93
+ onClick: handleSave,
94
+ size: "small",
95
+ children: "Save key"
96
+ }
97
+ ),
98
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", size: "small", children: isLoading ? "Loading current store settings…" : "Changes are stored in store metadata." })
99
+ ] })
100
+ ] })
101
+ ] });
102
+ };
103
+ defineWidgetConfig({
104
+ zone: "store.details.after"
105
+ });
106
+ const i18nTranslations0 = {};
107
+ const widgetModule = { widgets: [
108
+ {
109
+ Component: StorePaystackSettingsWidget,
110
+ zone: ["store.details.after"]
111
+ }
112
+ ] };
113
+ const routeModule = {
114
+ routes: []
115
+ };
116
+ const menuItemModule = {
117
+ menuItems: []
118
+ };
119
+ const formModule = { customFields: {} };
120
+ const displayModule = {
121
+ displays: {}
122
+ };
123
+ const i18nModule = { resources: i18nTranslations0 };
124
+ const plugin = {
125
+ widgetModule,
126
+ routeModule,
127
+ menuItemModule,
128
+ formModule,
129
+ displayModule,
130
+ i18nModule
131
+ };
132
+ export {
133
+ plugin as default
134
+ };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const http_1 = require("@medusajs/framework/http");
4
+ const middlewares_1 = require("./store/paystack/config/middlewares");
5
+ const middlewares_2 = require("./store/paystack/webview/middlewares");
6
+ exports.default = (0, http_1.defineMiddlewares)({
7
+ routes: [...middlewares_1.paystackConfigMiddlewares, ...middlewares_2.paystackWebviewMiddlewares],
8
+ });
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYXBpL21pZGRsZXdhcmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsbURBQTREO0FBRTVELHFFQUErRTtBQUMvRSxzRUFBaUY7QUFFakYsa0JBQWUsSUFBQSx3QkFBaUIsRUFBQztJQUMvQixNQUFNLEVBQUUsQ0FBQyxHQUFHLHVDQUF5QixFQUFFLEdBQUcsd0NBQTBCLENBQUM7Q0FDdEUsQ0FBQyxDQUFBIn0=
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.paystackConfigMiddlewares = void 0;
4
+ const http_1 = require("@medusajs/framework/http");
5
+ const validators_1 = require("../validators");
6
+ exports.paystackConfigMiddlewares = [
7
+ {
8
+ matcher: "/store/paystack/config",
9
+ method: "GET",
10
+ middlewares: [(0, http_1.validateAndTransformQuery)(validators_1.GetPaystackConfigQuery, {})],
11
+ },
12
+ ];
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL3BheXN0YWNrL2NvbmZpZy9taWRkbGV3YXJlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSxtREFBb0U7QUFFcEUsOENBQXNEO0FBRXpDLFFBQUEseUJBQXlCLEdBQXNCO0lBQzFEO1FBQ0UsT0FBTyxFQUFFLHdCQUF3QjtRQUNqQyxNQUFNLEVBQUUsS0FBSztRQUNiLFdBQVcsRUFBRSxDQUFDLElBQUEsZ0NBQXlCLEVBQUMsbUNBQXNCLEVBQUUsRUFBRSxDQUFDLENBQUM7S0FDckU7Q0FDRixDQUFBIn0=
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = GET;
4
+ const store_1 = require("../../../../lib/store");
5
+ const plugin_config_1 = require("../../../../lib/plugin-config");
6
+ async function GET(req, res) {
7
+ const store = await (0, store_1.resolveStore)(req.scope, req.validatedQuery.store_id);
8
+ const configModule = req.scope.resolve("configModule");
9
+ res.status(200).json({
10
+ publishable_key: (0, store_1.getStorePublishableKey)(store),
11
+ store_id: store.id,
12
+ verified_mode_enabled: (0, plugin_config_1.isVerifiedModeEnabled)(configModule),
13
+ });
14
+ }
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL3BheXN0YWNrL2NvbmZpZy9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQVVBLGtCQVNDO0FBakJELGlEQUE0RTtBQUM1RSxpRUFBcUU7QUFPOUQsS0FBSyxVQUFVLEdBQUcsQ0FBQyxHQUE4QixFQUFFLEdBQW1CO0lBQzNFLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBQSxvQkFBWSxFQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsQ0FBQTtJQUN4RSxNQUFNLFlBQVksR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQTtJQUV0RCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUNuQixlQUFlLEVBQUUsSUFBQSw4QkFBc0IsRUFBQyxLQUFLLENBQUM7UUFDOUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxFQUFFO1FBQ2xCLHFCQUFxQixFQUFFLElBQUEscUNBQXFCLEVBQUMsWUFBWSxDQUFDO0tBQzNELENBQUMsQ0FBQTtBQUNKLENBQUMifQ==
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GetPaystackWebviewQuery = exports.GetPaystackConfigQuery = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.GetPaystackConfigQuery = zod_1.z.object({
6
+ store_id: zod_1.z.string().optional(),
7
+ });
8
+ exports.GetPaystackWebviewQuery = zod_1.z.object({
9
+ amount: zod_1.z.preprocess((value) => {
10
+ if (typeof value === "string") {
11
+ return Number(value);
12
+ }
13
+ return value;
14
+ }, zod_1.z.number().positive()),
15
+ callback_url: zod_1.z.string().url().optional(),
16
+ channels: zod_1.z.string().optional(),
17
+ currency: zod_1.z
18
+ .string()
19
+ .min(3)
20
+ .max(3)
21
+ .transform((value) => value.toUpperCase()),
22
+ email: zod_1.z.string().email(),
23
+ first_name: zod_1.z.string().optional(),
24
+ last_name: zod_1.z.string().optional(),
25
+ metadata: zod_1.z.string().optional(),
26
+ phone: zod_1.z.string().optional(),
27
+ reference: zod_1.z
28
+ .string()
29
+ .regex(/^[A-Za-z0-9.\-=]+$/)
30
+ .optional(),
31
+ store_id: zod_1.z.string().optional(),
32
+ });
33
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvc3RvcmUvcGF5c3RhY2svdmFsaWRhdG9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2QkFBdUI7QUFFVixRQUFBLHNCQUFzQixHQUFHLE9BQUMsQ0FBQyxNQUFNLENBQUM7SUFDN0MsUUFBUSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7Q0FDaEMsQ0FBQyxDQUFBO0FBRVcsUUFBQSx1QkFBdUIsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUFDO0lBQzlDLE1BQU0sRUFBRSxPQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7UUFDN0IsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUM5QixPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUN0QixDQUFDO1FBRUQsT0FBTyxLQUFLLENBQUE7SUFDZCxDQUFDLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ3pCLFlBQVksRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ3pDLFFBQVEsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQy9CLFFBQVEsRUFBRSxPQUFDO1NBQ1IsTUFBTSxFQUFFO1NBQ1IsR0FBRyxDQUFDLENBQUMsQ0FBQztTQUNOLEdBQUcsQ0FBQyxDQUFDLENBQUM7U0FDTixTQUFTLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUM1QyxLQUFLLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEtBQUssRUFBRTtJQUN6QixVQUFVLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUNqQyxTQUFTLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUNoQyxRQUFRLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMvQixLQUFLLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM1QixTQUFTLEVBQUUsT0FBQztTQUNULE1BQU0sRUFBRTtTQUNSLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQztTQUMzQixRQUFRLEVBQUU7SUFDYixRQUFRLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtDQUNoQyxDQUFDLENBQUEifQ==
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildPaystackWebviewHtml = buildPaystackWebviewHtml;
4
+ const constants_1 = require("../../../../constants");
5
+ const paystack_utils_1 = require("../../../../lib/paystack-utils");
6
+ function escapeInlineScriptJson(value) {
7
+ return value
8
+ .replace(/</g, "\\u003C")
9
+ .replace(/>/g, "\\u003E")
10
+ .replace(/&/g, "\\u0026")
11
+ .replace(/\u2028/g, "\\u2028")
12
+ .replace(/\u2029/g, "\\u2029");
13
+ }
14
+ function buildPaystackWebviewHtml(input) {
15
+ const config = escapeInlineScriptJson(JSON.stringify({
16
+ amount: input.amount,
17
+ callbackUrl: input.callbackUrl,
18
+ channels: input.channels,
19
+ currency: input.currency,
20
+ email: input.email,
21
+ firstName: input.firstName,
22
+ key: input.key,
23
+ lastName: input.lastName,
24
+ metadata: input.metadata,
25
+ phone: input.phone,
26
+ reference: input.reference,
27
+ }));
28
+ return `<!DOCTYPE html>
29
+ <html lang="en">
30
+ <head>
31
+ <meta charset="utf-8" />
32
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
33
+ <title>Paystack Checkout</title>
34
+ <style>
35
+ :root {
36
+ color-scheme: light;
37
+ font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
38
+ }
39
+
40
+ body {
41
+ align-items: center;
42
+ background: linear-gradient(160deg, #f6fff6 0%, #eef7ff 100%);
43
+ color: #0f172a;
44
+ display: flex;
45
+ justify-content: center;
46
+ margin: 0;
47
+ min-height: 100vh;
48
+ padding: 24px;
49
+ }
50
+
51
+ .shell {
52
+ background: rgba(255, 255, 255, 0.92);
53
+ border: 1px solid rgba(15, 23, 42, 0.08);
54
+ border-radius: 20px;
55
+ box-shadow: 0 24px 80px rgba(15, 23, 42, 0.12);
56
+ max-width: 420px;
57
+ padding: 28px 24px;
58
+ text-align: center;
59
+ width: 100%;
60
+ }
61
+
62
+ .status {
63
+ font-size: 14px;
64
+ line-height: 1.6;
65
+ margin: 0;
66
+ }
67
+ </style>
68
+ <script src="${constants_1.PAYSTACK_INLINE_SCRIPT_URL}"></script>
69
+ </head>
70
+ <body>
71
+ <div class="shell">
72
+ <p class="status" id="status">Opening Paystack checkout…</p>
73
+ </div>
74
+ <script>
75
+ const config = ${config};
76
+ const statusNode = document.getElementById("status");
77
+
78
+ const updateStatus = (message) => {
79
+ if (statusNode) {
80
+ statusNode.textContent = message;
81
+ }
82
+ };
83
+
84
+ const postResult = (type, payload) => {
85
+ const message = {
86
+ payload,
87
+ source: "${constants_1.PAYSTACK_WEBVIEW_SOURCE}",
88
+ type,
89
+ };
90
+
91
+ if (window.ReactNativeWebView && typeof window.ReactNativeWebView.postMessage === "function") {
92
+ window.ReactNativeWebView.postMessage(JSON.stringify(message));
93
+ }
94
+
95
+ if (window.parent && window.parent !== window) {
96
+ window.parent.postMessage(message, "*");
97
+ }
98
+
99
+ if (window.opener && typeof window.opener.postMessage === "function") {
100
+ window.opener.postMessage(message, "*");
101
+ }
102
+ };
103
+
104
+ const redirectWithStatus = (status, payload) => {
105
+ if (!config.callbackUrl) {
106
+ const labels = {
107
+ cancel: "Checkout was cancelled.",
108
+ error: "Checkout failed to load.",
109
+ success: "Payment completed. You can return to the previous screen.",
110
+ };
111
+
112
+ updateStatus(labels[status] || "Checkout finished.");
113
+ return;
114
+ }
115
+
116
+ const url = new URL(config.callbackUrl);
117
+ url.searchParams.set("paystack_status", status);
118
+ url.searchParams.set("paystack_payload", ${JSON.stringify((0, paystack_utils_1.serializePayload)(undefined))});
119
+
120
+ if (payload) {
121
+ url.searchParams.set("paystack_payload", JSON.stringify(payload));
122
+
123
+ if (payload.reference) {
124
+ url.searchParams.set("reference", payload.reference);
125
+ }
126
+ }
127
+
128
+ window.location.replace(url.toString());
129
+ };
130
+
131
+ try {
132
+ if (typeof window.PaystackPop !== "function") {
133
+ throw new Error("Unable to load Paystack checkout.");
134
+ }
135
+
136
+ const paystack = new window.PaystackPop();
137
+
138
+ paystack.newTransaction({
139
+ key: config.key,
140
+ email: config.email,
141
+ amount: config.amount,
142
+ currency: config.currency,
143
+ reference: config.reference,
144
+ metadata: config.metadata,
145
+ channels: config.channels,
146
+ firstName: config.firstName,
147
+ lastName: config.lastName,
148
+ phone: config.phone,
149
+ onCancel: () => {
150
+ postResult("cancel", { reference: config.reference });
151
+ redirectWithStatus("cancel", { reference: config.reference });
152
+ },
153
+ onError: (error) => {
154
+ const payload = {
155
+ message: error && error.message ? error.message : "Unable to launch Paystack checkout.",
156
+ reference: config.reference,
157
+ };
158
+ postResult("error", payload);
159
+ redirectWithStatus("error", payload);
160
+ },
161
+ onSuccess: (transaction) => {
162
+ postResult("success", transaction);
163
+ redirectWithStatus("success", transaction);
164
+ },
165
+ });
166
+ } catch (error) {
167
+ const payload = {
168
+ message: error instanceof Error ? error.message : "Unable to initialize Paystack checkout.",
169
+ reference: config.reference,
170
+ };
171
+ postResult("error", payload);
172
+ redirectWithStatus("error", payload);
173
+ }
174
+ </script>
175
+ </body>
176
+ </html>`;
177
+ }
178
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHRtbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvc3RvcmUvcGF5c3RhY2svd2Vidmlldy9odG1sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBNkJBLDREQXNLQztBQW5NRCxxREFHOEI7QUFDOUIsbUVBQWlFO0FBZ0JqRSxTQUFTLHNCQUFzQixDQUFDLEtBQWE7SUFDM0MsT0FBTyxLQUFLO1NBQ1QsT0FBTyxDQUFDLElBQUksRUFBRSxTQUFTLENBQUM7U0FDeEIsT0FBTyxDQUFDLElBQUksRUFBRSxTQUFTLENBQUM7U0FDeEIsT0FBTyxDQUFDLElBQUksRUFBRSxTQUFTLENBQUM7U0FDeEIsT0FBTyxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUM7U0FDN0IsT0FBTyxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQTtBQUNsQyxDQUFDO0FBRUQsU0FBZ0Isd0JBQXdCLENBQUMsS0FBNEI7SUFDbkUsTUFBTSxNQUFNLEdBQUcsc0JBQXNCLENBQ25DLElBQUksQ0FBQyxTQUFTLENBQUM7UUFDYixNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07UUFDcEIsV0FBVyxFQUFFLEtBQUssQ0FBQyxXQUFXO1FBQzlCLFFBQVEsRUFBRSxLQUFLLENBQUMsUUFBUTtRQUN4QixRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVE7UUFDeEIsS0FBSyxFQUFFLEtBQUssQ0FBQyxLQUFLO1FBQ2xCLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUztRQUMxQixHQUFHLEVBQUUsS0FBSyxDQUFDLEdBQUc7UUFDZCxRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVE7UUFDeEIsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRO1FBQ3hCLEtBQUssRUFBRSxLQUFLLENBQUMsS0FBSztRQUNsQixTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVM7S0FDM0IsQ0FBQyxDQUNILENBQUE7SUFFRCxPQUFPOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O21CQXdDVSxzQ0FBMEI7Ozs7Ozs7dUJBT3RCLE1BQU07Ozs7Ozs7Ozs7OztxQkFZUixtQ0FBdUI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7bURBK0JPLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBQSxpQ0FBZ0IsRUFBQyxTQUFTLENBQUMsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztRQTBEdEYsQ0FBQTtBQUNSLENBQUMifQ==
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.paystackWebviewMiddlewares = void 0;
4
+ const http_1 = require("@medusajs/framework/http");
5
+ const validators_1 = require("../validators");
6
+ exports.paystackWebviewMiddlewares = [
7
+ {
8
+ matcher: "/store/paystack/webview",
9
+ method: "GET",
10
+ middlewares: [(0, http_1.validateAndTransformQuery)(validators_1.GetPaystackWebviewQuery, {})],
11
+ },
12
+ ];
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL3BheXN0YWNrL3dlYnZpZXcvbWlkZGxld2FyZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQ0EsbURBQW9FO0FBRXBFLDhDQUF1RDtBQUUxQyxRQUFBLDBCQUEwQixHQUFzQjtJQUMzRDtRQUNFLE9BQU8sRUFBRSx5QkFBeUI7UUFDbEMsTUFBTSxFQUFFLEtBQUs7UUFDYixXQUFXLEVBQUUsQ0FBQyxJQUFBLGdDQUF5QixFQUFDLG9DQUF1QixFQUFFLEVBQUUsQ0FBQyxDQUFDO0tBQ3RFO0NBQ0YsQ0FBQSJ9
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = GET;
4
+ const html_1 = require("./html");
5
+ const paystack_utils_1 = require("../../../../lib/paystack-utils");
6
+ const store_1 = require("../../../../lib/store");
7
+ async function GET(req, res) {
8
+ const { amount, callback_url, channels, currency, email, first_name, last_name, metadata, phone, reference, store_id, } = req.validatedQuery;
9
+ const store = await (0, store_1.resolveStore)(req.scope, store_id);
10
+ const publishableKey = (0, store_1.getStorePublishableKey)(store);
11
+ const html = (0, html_1.buildPaystackWebviewHtml)({
12
+ amount: (0, paystack_utils_1.toPaystackSubunit)(amount),
13
+ callbackUrl: callback_url,
14
+ channels: (0, paystack_utils_1.parseChannels)(channels),
15
+ currency,
16
+ email,
17
+ firstName: first_name,
18
+ key: publishableKey,
19
+ lastName: last_name,
20
+ metadata: (0, paystack_utils_1.parseMetadataParam)(metadata),
21
+ phone,
22
+ reference: reference ?? (0, paystack_utils_1.buildPaystackReference)(),
23
+ });
24
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
25
+ res.status(200).send(html);
26
+ }
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL3BheXN0YWNrL3dlYnZpZXcvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFnQkEsa0JBa0NDO0FBaERELGlDQUFpRDtBQUNqRCxtRUFLdUM7QUFDdkMsaURBQTRFO0FBT3JFLEtBQUssVUFBVSxHQUFHLENBQUMsR0FBOEIsRUFBRSxHQUFtQjtJQUMzRSxNQUFNLEVBQ0osTUFBTSxFQUNOLFlBQVksRUFDWixRQUFRLEVBQ1IsUUFBUSxFQUNSLEtBQUssRUFDTCxVQUFVLEVBQ1YsU0FBUyxFQUNULFFBQVEsRUFDUixLQUFLLEVBQ0wsU0FBUyxFQUNULFFBQVEsR0FDVCxHQUFHLEdBQUcsQ0FBQyxjQUFjLENBQUE7SUFFdEIsTUFBTSxLQUFLLEdBQUcsTUFBTSxJQUFBLG9CQUFZLEVBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQTtJQUNyRCxNQUFNLGNBQWMsR0FBRyxJQUFBLDhCQUFzQixFQUFDLEtBQUssQ0FBQyxDQUFBO0lBRXBELE1BQU0sSUFBSSxHQUFHLElBQUEsK0JBQXdCLEVBQUM7UUFDcEMsTUFBTSxFQUFFLElBQUEsa0NBQWlCLEVBQUMsTUFBTSxDQUFDO1FBQ2pDLFdBQVcsRUFBRSxZQUFZO1FBQ3pCLFFBQVEsRUFBRSxJQUFBLDhCQUFhLEVBQUMsUUFBUSxDQUFDO1FBQ2pDLFFBQVE7UUFDUixLQUFLO1FBQ0wsU0FBUyxFQUFFLFVBQVU7UUFDckIsR0FBRyxFQUFFLGNBQWM7UUFDbkIsUUFBUSxFQUFFLFNBQVM7UUFDbkIsUUFBUSxFQUFFLElBQUEsbUNBQWtCLEVBQUMsUUFBUSxDQUFDO1FBQ3RDLEtBQUs7UUFDTCxTQUFTLEVBQUUsU0FBUyxJQUFJLElBQUEsdUNBQXNCLEdBQUU7S0FDakQsQ0FBQyxDQUFBO0lBRUYsR0FBRyxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsMEJBQTBCLENBQUMsQ0FBQTtJQUN6RCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtBQUM1QixDQUFDIn0=
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PAYSTACK_WEBVIEW_SOURCE = exports.PAYSTACK_PUBLISHABLE_KEY_METADATA = exports.PAYSTACK_PROVIDER_IDENTIFIER = exports.PAYSTACK_API_BASE_URL = exports.PAYSTACK_INLINE_SCRIPT_URL = void 0;
4
+ exports.PAYSTACK_INLINE_SCRIPT_URL = "https://js.paystack.co/v2/inline.js";
5
+ exports.PAYSTACK_API_BASE_URL = "https://api.paystack.co";
6
+ exports.PAYSTACK_PROVIDER_IDENTIFIER = "paystack";
7
+ exports.PAYSTACK_PUBLISHABLE_KEY_METADATA = "paystack_publishable_key";
8
+ exports.PAYSTACK_WEBVIEW_SOURCE = "medusa-paystack-webview";
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbnN0YW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBYSxRQUFBLDBCQUEwQixHQUFHLHFDQUFxQyxDQUFBO0FBQ2xFLFFBQUEscUJBQXFCLEdBQUcseUJBQXlCLENBQUE7QUFDakQsUUFBQSw0QkFBNEIsR0FBRyxVQUFVLENBQUE7QUFDekMsUUFBQSxpQ0FBaUMsR0FBRywwQkFBMEIsQ0FBQTtBQUM5RCxRQUFBLHVCQUF1QixHQUFHLHlCQUF5QixDQUFBIn0=