@zuplo/zudoku-plugin-monetization 0.0.2 → 0.0.4
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.mjs +213 -178
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ArrowLeftIcon, CheckIcon, ClockIcon, LockIcon, RefreshCwIcon, ShieldIcon, StarsIcon, Trash2Icon } from "zudoku/icons";
|
|
1
|
+
import { ArrowLeftIcon, CheckIcon, ClockIcon, InfoIcon, LockIcon, RefreshCwIcon, ShieldIcon, StarsIcon, Trash2Icon } from "zudoku/icons";
|
|
2
2
|
import { Link, Outlet, useNavigate, useParams, useSearchParams } from "zudoku/router";
|
|
3
3
|
import { Button, Heading } from "zudoku/components";
|
|
4
4
|
import { useAuth, useZudoku } from "zudoku/hooks";
|
|
5
|
-
import { QueryClient, QueryClientProvider, useMutation, useQuery,
|
|
5
|
+
import { QueryClient, QueryClientProvider, useMutation, useQuery, useSuspenseQuery } from "zudoku/react-query";
|
|
6
6
|
import { Alert, AlertDescription, AlertTitle } from "zudoku/ui/Alert";
|
|
7
7
|
import { Card, CardContent, CardHeader, CardTitle } from "zudoku/ui/Card";
|
|
8
8
|
import { Separator } from "zudoku/ui/Separator";
|
|
@@ -148,6 +148,64 @@ const getPriceFromPlan = (plan) => {
|
|
|
148
148
|
};
|
|
149
149
|
};
|
|
150
150
|
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/ZuploMonetizationWrapper.tsx
|
|
153
|
+
const BASE_URL = "https://api.zuploedge.com";
|
|
154
|
+
const createMutationFn = (url, context, init) => {
|
|
155
|
+
return async (data) => {
|
|
156
|
+
const urlString = typeof url === "function" ? url(data) : url;
|
|
157
|
+
const request = new Request(`${BASE_URL}${urlString}`, {
|
|
158
|
+
method: "POST",
|
|
159
|
+
...init,
|
|
160
|
+
headers: {
|
|
161
|
+
"Content-Type": "application/json",
|
|
162
|
+
...init?.headers
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
const response = await fetch(context ? await context.signRequest(request) : request);
|
|
166
|
+
if (!response.ok) {
|
|
167
|
+
if (response.headers.get("content-type")?.includes("application/problem+json")) {
|
|
168
|
+
const data$1 = await response.json();
|
|
169
|
+
throw new Error(data$1.detail ?? data$1.title);
|
|
170
|
+
}
|
|
171
|
+
const errorText = await response.text();
|
|
172
|
+
throw new Error(`Request failed: ${response.status} ${errorText}`);
|
|
173
|
+
}
|
|
174
|
+
if (response.headers.get("content-type")?.includes("application/json")) return response.json();
|
|
175
|
+
return response.text();
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
const queryClient = new QueryClient({ defaultOptions: {
|
|
179
|
+
queries: {
|
|
180
|
+
retry: false,
|
|
181
|
+
queryFn: async (q) => {
|
|
182
|
+
if (!Array.isArray(q.queryKey)) throw new Error("Query key must be an array");
|
|
183
|
+
if (q.queryKey.length === 0) throw new Error("Query key must be a non-empty array");
|
|
184
|
+
const url = q.queryKey[0];
|
|
185
|
+
if (!url || typeof url !== "string") throw new Error("URL is required");
|
|
186
|
+
const init = q.queryKey[1] ?? {};
|
|
187
|
+
const request = new Request(`${BASE_URL}${url}`, {
|
|
188
|
+
...init,
|
|
189
|
+
headers: {
|
|
190
|
+
"Content-Type": "application/json",
|
|
191
|
+
...init.headers
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
const response = await fetch(q.meta?.context ? await q.meta.context.signRequest(request) : request);
|
|
195
|
+
if (!response.ok) throw new Error("Failed to fetch request");
|
|
196
|
+
return response.json();
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
mutations: { retry: false }
|
|
200
|
+
} });
|
|
201
|
+
const ZuploMonetizationWrapper = () => {
|
|
202
|
+
return /* @__PURE__ */ jsx(QueryClientProvider, {
|
|
203
|
+
client: queryClient,
|
|
204
|
+
children: /* @__PURE__ */ jsx(Outlet, {})
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
var ZuploMonetizationWrapper_default = ZuploMonetizationWrapper;
|
|
208
|
+
|
|
151
209
|
//#endregion
|
|
152
210
|
//#region src/pages/CheckoutConfimPage.tsx
|
|
153
211
|
const formatBillingCycle = (duration) => {
|
|
@@ -161,7 +219,6 @@ const formatBillingCycle = (duration) => {
|
|
|
161
219
|
const CheckoutConfirmPage = ({ environmentName }) => {
|
|
162
220
|
const [search] = useSearchParams();
|
|
163
221
|
const planId = search.get("plan");
|
|
164
|
-
const auth = useAuth();
|
|
165
222
|
const zudoku = useZudoku();
|
|
166
223
|
const navigate = useNavigate();
|
|
167
224
|
const { data: plans } = usePlans(environmentName);
|
|
@@ -171,18 +228,10 @@ const CheckoutConfirmPage = ({ environmentName }) => {
|
|
|
171
228
|
const price = selectedPlan ? getPriceFromPlan(selectedPlan) : null;
|
|
172
229
|
const billingCycle = selectedPlan?.billingCadence ? formatDuration(selectedPlan.billingCadence) : null;
|
|
173
230
|
const createSubscriptionMutation = useMutation({
|
|
174
|
-
mutationFn:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
headers: { "Content-Type": "application/json" },
|
|
179
|
-
body: JSON.stringify({ planId })
|
|
180
|
-
}));
|
|
181
|
-
const response = await fetch(signedRequest);
|
|
182
|
-
const subscription = await response.json();
|
|
183
|
-
if (!response.ok) throw new Error(subscription.message);
|
|
184
|
-
return subscription.id;
|
|
185
|
-
},
|
|
231
|
+
mutationFn: createMutationFn(`/v3/zudoku-metering/${environmentName}/subscriptions`, zudoku, {
|
|
232
|
+
method: "POST",
|
|
233
|
+
body: JSON.stringify({ planId })
|
|
234
|
+
}),
|
|
186
235
|
onSuccess: (subscriptionId) => {
|
|
187
236
|
navigate(`/subscriptions/${subscriptionId}`);
|
|
188
237
|
},
|
|
@@ -197,11 +246,12 @@ const CheckoutConfirmPage = ({ environmentName }) => {
|
|
|
197
246
|
children: [
|
|
198
247
|
/* @__PURE__ */ jsxs("div", {
|
|
199
248
|
className: "flex gap-2 text-muted-foreground text-sm items-center pt-4 pb-4",
|
|
200
|
-
children: [/* @__PURE__ */ jsx(ArrowLeftIcon, { className: "size-4" }), "
|
|
249
|
+
children: [/* @__PURE__ */ jsx(ArrowLeftIcon, { className: "size-4" }), "Back to Payment Details"]
|
|
201
250
|
}),
|
|
202
251
|
" ",
|
|
203
252
|
createSubscriptionMutation.isError && /* @__PURE__ */ jsxs(Alert, {
|
|
204
253
|
className: "mb-4",
|
|
254
|
+
variant: "destructive",
|
|
205
255
|
children: [/* @__PURE__ */ jsx(AlertTitle, { children: "Error" }), /* @__PURE__ */ jsx(AlertDescription, { children: createSubscriptionMutation.error.message })]
|
|
206
256
|
}),
|
|
207
257
|
/* @__PURE__ */ jsxs(Card, {
|
|
@@ -349,12 +399,6 @@ const CheckoutPage = ({ environmentName }) => {
|
|
|
349
399
|
cancelURL: generateUrl(`/checkout-failed`) + `?${planId ? `plan=${planId}` : ""}`
|
|
350
400
|
})
|
|
351
401
|
}));
|
|
352
|
-
console.log({
|
|
353
|
-
email: auth.profile?.email,
|
|
354
|
-
planId,
|
|
355
|
-
successURL: `${generateUrl(`/checkout-confirm`)}?${planId ? `plan=${planId}` : ""}`,
|
|
356
|
-
cancelURL: `${generateUrl(`/checkout-failed`)}?${planId ? `plan=${planId}` : ""}`
|
|
357
|
-
});
|
|
358
402
|
const checkoutRequest = await fetch(request).then((res) => res.json());
|
|
359
403
|
if (checkoutRequest.url) window.location.href = checkoutRequest.url;
|
|
360
404
|
return checkoutRequest;
|
|
@@ -404,7 +448,7 @@ const CheckoutPage = ({ environmentName }) => {
|
|
|
404
448
|
var CheckoutPage_default = CheckoutPage;
|
|
405
449
|
|
|
406
450
|
//#endregion
|
|
407
|
-
//#region src/pages/
|
|
451
|
+
//#region src/pages/pricing/PricingCard.tsx
|
|
408
452
|
const PricingCard = ({ plan, isPopular = false }) => {
|
|
409
453
|
const defaultPhase = plan.phases.at(-1);
|
|
410
454
|
if (!defaultPhase) return null;
|
|
@@ -479,8 +523,11 @@ const PricingCard = ({ plan, isPopular = false }) => {
|
|
|
479
523
|
]
|
|
480
524
|
});
|
|
481
525
|
};
|
|
526
|
+
|
|
527
|
+
//#endregion
|
|
528
|
+
//#region src/pages/PricingPage.tsx
|
|
482
529
|
const PricingPage = ({ environmentName }) => {
|
|
483
|
-
const { data: pricingTableData } =
|
|
530
|
+
const { data: pricingTableData } = useSuspenseQuery({ queryKey: [`/v3/zudoku-metering/${environmentName}/pricing-page`] });
|
|
484
531
|
const planOrder = [
|
|
485
532
|
"developer",
|
|
486
533
|
"startup",
|
|
@@ -532,61 +579,9 @@ const useSubscriptions = (environmentName) => {
|
|
|
532
579
|
});
|
|
533
580
|
};
|
|
534
581
|
|
|
535
|
-
//#endregion
|
|
536
|
-
//#region src/ZuploMonetizationWrapper.tsx
|
|
537
|
-
const BASE_URL = "https://api.zuploedge.com";
|
|
538
|
-
const createMutationFn = (url, context, init) => {
|
|
539
|
-
return async () => {
|
|
540
|
-
const request = new Request(`${BASE_URL}${url}`, {
|
|
541
|
-
method: "POST",
|
|
542
|
-
...init,
|
|
543
|
-
headers: {
|
|
544
|
-
"Content-Type": "application/json",
|
|
545
|
-
...init?.headers
|
|
546
|
-
}
|
|
547
|
-
});
|
|
548
|
-
const response = await fetch(context ? await context.signRequest(request) : request);
|
|
549
|
-
if (!response.ok) {
|
|
550
|
-
const errorText = await response.text();
|
|
551
|
-
throw new Error(`Request failed: ${response.status} ${errorText}`);
|
|
552
|
-
}
|
|
553
|
-
return response.json();
|
|
554
|
-
};
|
|
555
|
-
};
|
|
556
|
-
const client = new QueryClient({ defaultOptions: {
|
|
557
|
-
queries: {
|
|
558
|
-
retry: false,
|
|
559
|
-
queryFn: async (q) => {
|
|
560
|
-
if (!Array.isArray(q.queryKey)) throw new Error("Query key must be an array");
|
|
561
|
-
if (q.queryKey.length === 0) throw new Error("Query key must be a non-empty array");
|
|
562
|
-
const url = q.queryKey[0];
|
|
563
|
-
if (!url || typeof url !== "string") throw new Error("URL is required");
|
|
564
|
-
const init = q.queryKey[1] ?? {};
|
|
565
|
-
const request = new Request(`${BASE_URL}${url}`, {
|
|
566
|
-
...init,
|
|
567
|
-
headers: {
|
|
568
|
-
"Content-Type": "application/json",
|
|
569
|
-
...init.headers
|
|
570
|
-
}
|
|
571
|
-
});
|
|
572
|
-
const response = await fetch(q.meta?.context ? await q.meta.context.signRequest(request) : request);
|
|
573
|
-
if (!response.ok) throw new Error("Failed to fetch request");
|
|
574
|
-
return response.json();
|
|
575
|
-
}
|
|
576
|
-
},
|
|
577
|
-
mutations: { retry: false }
|
|
578
|
-
} });
|
|
579
|
-
const ZuploMonetizationWrapper = () => {
|
|
580
|
-
return /* @__PURE__ */ jsx(QueryClientProvider, {
|
|
581
|
-
client,
|
|
582
|
-
children: /* @__PURE__ */ jsx(Outlet, {})
|
|
583
|
-
});
|
|
584
|
-
};
|
|
585
|
-
var ZuploMonetizationWrapper_default = ZuploMonetizationWrapper;
|
|
586
|
-
|
|
587
582
|
//#endregion
|
|
588
583
|
//#region src/pages/subscriptions/ApiKey.tsx
|
|
589
|
-
const ApiKey = ({ apiKey, createdAt, lastUsed,
|
|
584
|
+
const ApiKey = ({ apiKey, createdAt, lastUsed, expiresOn, isActive = true, label, onDelete }) => {
|
|
590
585
|
const formatDate = (dateString) => {
|
|
591
586
|
if (!dateString) return "";
|
|
592
587
|
return new Date(dateString).toLocaleDateString("en-US", {
|
|
@@ -609,130 +604,170 @@ const ApiKey = ({ apiKey, createdAt, lastUsed, expiresAt, isActive = true, label
|
|
|
609
604
|
if (diffInDays < 30) return `${diffInDays} days ago`;
|
|
610
605
|
return formatDate(dateString);
|
|
611
606
|
};
|
|
612
|
-
const isExpiring =
|
|
613
|
-
const isExpired =
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
className: "flex items-center
|
|
630
|
-
children:
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800",
|
|
635
|
-
children: "Active"
|
|
636
|
-
}) : /* @__PURE__ */ jsx("span", {
|
|
637
|
-
className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800",
|
|
638
|
-
children: "Expiring"
|
|
639
|
-
})]
|
|
640
|
-
})
|
|
641
|
-
}),
|
|
642
|
-
/* @__PURE__ */ jsxs("div", {
|
|
643
|
-
className: "flex items-center gap-1.5 text-sm text-muted-foreground",
|
|
644
|
-
children: [
|
|
645
|
-
/* @__PURE__ */ jsxs("div", {
|
|
646
|
-
className: "flex items-center gap-1.5",
|
|
647
|
-
children: [/* @__PURE__ */ jsx(ClockIcon, { className: "size-3.5" }), /* @__PURE__ */ jsxs("span", { children: ["Created ", formatDate(createdAt)] })]
|
|
648
|
-
}),
|
|
649
|
-
/* @__PURE__ */ jsx("span", { children: "•" }),
|
|
650
|
-
/* @__PURE__ */ jsxs("span", { children: ["Last used ", getTimeAgo(lastUsed)] }),
|
|
651
|
-
expiresAt,
|
|
652
|
-
expiresAt && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", { children: "•" }), /* @__PURE__ */ jsxs("span", {
|
|
653
|
-
className: isExpired ? "text-red-700 font-medium" : isExpiring ? "text-yellow-700 font-medium" : "",
|
|
654
|
-
children: ["Expires ", formatDate(expiresAt)]
|
|
655
|
-
})] })
|
|
656
|
-
]
|
|
657
|
-
}),
|
|
658
|
-
/* @__PURE__ */ jsxs("div", {
|
|
659
|
-
className: "flex items-center gap-2 rounded-md font-mono text-sm",
|
|
660
|
-
children: [/* @__PURE__ */ jsx(Secret, {
|
|
661
|
-
secret: apiKey,
|
|
662
|
-
status: isActive ? "active" : "expiring"
|
|
663
|
-
}), !isActive && /* @__PURE__ */ jsx("button", {
|
|
664
|
-
onClick: handleDelete,
|
|
665
|
-
className: "text-red-500 hover:text-red-700 p-1",
|
|
666
|
-
type: "button",
|
|
667
|
-
"aria-label": "Delete API key",
|
|
668
|
-
children: /* @__PURE__ */ jsx(Trash2Icon, { className: "size-4" })
|
|
607
|
+
const isExpiring = expiresOn && new Date(expiresOn) < new Date(Date.now() + 720 * 60 * 60 * 1e3);
|
|
608
|
+
const isExpired = expiresOn && new Date(expiresOn) < /* @__PURE__ */ new Date();
|
|
609
|
+
return /* @__PURE__ */ jsx(Card, {
|
|
610
|
+
className: isExpiring && !isExpired ? "border-yellow-200 bg-yellow-50" : "",
|
|
611
|
+
children: /* @__PURE__ */ jsx(CardContent, {
|
|
612
|
+
className: "p-6",
|
|
613
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
614
|
+
className: "space-y-4",
|
|
615
|
+
children: [
|
|
616
|
+
/* @__PURE__ */ jsx("div", {
|
|
617
|
+
className: "flex items-center justify-between",
|
|
618
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
619
|
+
className: "flex items-center gap-2",
|
|
620
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
621
|
+
className: "font-semibold text-base",
|
|
622
|
+
children: label || "API Key"
|
|
623
|
+
}), isActive ? /* @__PURE__ */ jsx("span", {
|
|
624
|
+
className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800",
|
|
625
|
+
children: "Active"
|
|
626
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
627
|
+
className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800",
|
|
628
|
+
children: "Expiring"
|
|
669
629
|
})]
|
|
670
630
|
})
|
|
671
|
-
|
|
672
|
-
|
|
631
|
+
}),
|
|
632
|
+
/* @__PURE__ */ jsxs("div", {
|
|
633
|
+
className: "flex items-center gap-1.5 text-sm text-muted-foreground",
|
|
634
|
+
children: [
|
|
635
|
+
/* @__PURE__ */ jsxs("div", {
|
|
636
|
+
className: "flex items-center gap-1.5",
|
|
637
|
+
children: [/* @__PURE__ */ jsx(ClockIcon, { className: "size-3.5" }), /* @__PURE__ */ jsxs("span", { children: ["Created ", formatDate(createdAt)] })]
|
|
638
|
+
}),
|
|
639
|
+
/* @__PURE__ */ jsx("span", { children: "•" }),
|
|
640
|
+
/* @__PURE__ */ jsxs("span", { children: ["Last used ", getTimeAgo(lastUsed)] }),
|
|
641
|
+
expiresOn && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", { children: "•" }), /* @__PURE__ */ jsxs("span", {
|
|
642
|
+
className: isExpired ? "text-red-700 font-medium" : isExpiring ? "text-yellow-700 font-medium" : "",
|
|
643
|
+
children: ["Expires ", formatDate(expiresOn)]
|
|
644
|
+
})] })
|
|
645
|
+
]
|
|
646
|
+
}),
|
|
647
|
+
/* @__PURE__ */ jsxs("div", {
|
|
648
|
+
className: "flex items-center gap-2 rounded-md font-mono text-sm",
|
|
649
|
+
children: [/* @__PURE__ */ jsx(Secret, {
|
|
650
|
+
secret: apiKey,
|
|
651
|
+
status: isActive ? "active" : "expiring"
|
|
652
|
+
}), !isActive && /* @__PURE__ */ jsx("button", {
|
|
653
|
+
onClick: onDelete,
|
|
654
|
+
className: "text-red-500 hover:text-red-700 p-1",
|
|
655
|
+
type: "button",
|
|
656
|
+
"aria-label": "Delete API key",
|
|
657
|
+
children: /* @__PURE__ */ jsx(Trash2Icon, { className: "size-4" })
|
|
658
|
+
})]
|
|
659
|
+
})
|
|
660
|
+
]
|
|
673
661
|
})
|
|
674
662
|
})
|
|
675
663
|
});
|
|
676
664
|
};
|
|
677
665
|
|
|
666
|
+
//#endregion
|
|
667
|
+
//#region src/pages/subscriptions/ApiKeyInfo.tsx
|
|
668
|
+
const ApiKeyInfo = () => {
|
|
669
|
+
return /* @__PURE__ */ jsx("div", {
|
|
670
|
+
className: "rounded-lg bg-muted/50 p-4",
|
|
671
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
672
|
+
className: "flex gap-3",
|
|
673
|
+
children: [/* @__PURE__ */ jsx(InfoIcon, { className: "size-5 shrink-0 text-muted-foreground mt-0.5" }), /* @__PURE__ */ jsxs("div", {
|
|
674
|
+
className: "space-y-2",
|
|
675
|
+
children: [/* @__PURE__ */ jsx("h4", {
|
|
676
|
+
className: "font-medium text-sm",
|
|
677
|
+
children: "How API key management works"
|
|
678
|
+
}), /* @__PURE__ */ jsxs("ul", {
|
|
679
|
+
className: "space-y-1.5 text-sm text-muted-foreground",
|
|
680
|
+
children: [
|
|
681
|
+
/* @__PURE__ */ jsx("li", { children: "• Each subscription includes one active API key automatically" }),
|
|
682
|
+
/* @__PURE__ */ jsx("li", { children: "• Rolling your key creates a new current key and sets the old one to expire in 7 days" }),
|
|
683
|
+
/* @__PURE__ */ jsx("li", { children: "• Expiring keys can be deleted early if you no longer need them" })
|
|
684
|
+
]
|
|
685
|
+
})]
|
|
686
|
+
})]
|
|
687
|
+
})
|
|
688
|
+
});
|
|
689
|
+
};
|
|
690
|
+
|
|
678
691
|
//#endregion
|
|
679
692
|
//#region src/pages/subscriptions/ApiKeysList.tsx
|
|
680
693
|
const ApiKeysList = ({ apiKeys, deploymentName, consumerId }) => {
|
|
681
|
-
const queryClient = useQueryClient();
|
|
682
694
|
const context = useZudoku();
|
|
683
695
|
const rollKeyMutation = useMutation({
|
|
684
696
|
mutationFn: createMutationFn(`/v2/client/${deploymentName}/consumers/${consumerId}/roll-key`, context, {
|
|
685
697
|
method: "POST",
|
|
686
698
|
body: JSON.stringify({})
|
|
687
699
|
}),
|
|
688
|
-
onSuccess: () => {
|
|
689
|
-
queryClient.invalidateQueries(
|
|
700
|
+
onSuccess: async () => {
|
|
701
|
+
await queryClient.invalidateQueries();
|
|
702
|
+
}
|
|
703
|
+
});
|
|
704
|
+
const deleteKeyMutation = useMutation({
|
|
705
|
+
mutationFn: createMutationFn(({ keyId }) => `/v2/client/${deploymentName}/consumers/${consumerId}/keys/${keyId}`, context, {
|
|
706
|
+
method: "DELETE",
|
|
707
|
+
body: JSON.stringify({})
|
|
708
|
+
}),
|
|
709
|
+
onSuccess: async () => {
|
|
710
|
+
await queryClient.invalidateQueries();
|
|
690
711
|
}
|
|
691
712
|
});
|
|
692
713
|
if (!apiKeys || apiKeys.length === 0) return null;
|
|
693
714
|
const sortedKeys = [...apiKeys].sort((a, b) => {
|
|
694
|
-
const aExpired = new Date(a.
|
|
695
|
-
if (aExpired !== new Date(b.
|
|
715
|
+
const aExpired = new Date(a.expiresOn) < /* @__PURE__ */ new Date();
|
|
716
|
+
if (aExpired !== new Date(b.expiresOn) < /* @__PURE__ */ new Date()) return aExpired ? 1 : -1;
|
|
696
717
|
return new Date(b.createdOn).getTime() - new Date(a.createdOn).getTime();
|
|
697
718
|
});
|
|
698
|
-
const activeKey = sortedKeys.find((k) => !k.
|
|
699
|
-
const expiringKeys = sortedKeys.filter((k) =>
|
|
719
|
+
const activeKey = sortedKeys.find((k) => !k.expiresOn);
|
|
720
|
+
const expiringKeys = sortedKeys.filter((k) => typeof k.expiresOn === "string");
|
|
700
721
|
return /* @__PURE__ */ jsxs("div", {
|
|
701
722
|
className: "space-y-4",
|
|
702
|
-
children: [
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
className: "
|
|
706
|
-
children: "
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
723
|
+
children: [
|
|
724
|
+
/* @__PURE__ */ jsx(ApiKeyInfo, {}),
|
|
725
|
+
/* @__PURE__ */ jsxs("div", {
|
|
726
|
+
className: "flex items-center justify-between",
|
|
727
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
728
|
+
className: "text-lg font-semibold",
|
|
729
|
+
children: "API Keys"
|
|
730
|
+
}), /* @__PURE__ */ jsxs(Button$1, {
|
|
731
|
+
onClick: () => rollKeyMutation.mutateAsync(),
|
|
732
|
+
disabled: rollKeyMutation.isPending,
|
|
733
|
+
children: [/* @__PURE__ */ jsx(RefreshCwIcon, { className: `size-4 ${rollKeyMutation.isPending ? "animate-spin" : ""}` }), rollKeyMutation.isPending ? "Rolling..." : "Roll API Key"]
|
|
734
|
+
})]
|
|
735
|
+
}),
|
|
736
|
+
deleteKeyMutation.error && /* @__PURE__ */ jsxs(Alert, {
|
|
737
|
+
variant: "destructive",
|
|
738
|
+
children: [/* @__PURE__ */ jsx(AlertTitle, { children: "Could not delete API key" }), /* @__PURE__ */ jsx(AlertDescription, { children: deleteKeyMutation.error.message })]
|
|
739
|
+
}),
|
|
740
|
+
rollKeyMutation.error && /* @__PURE__ */ jsxs(Alert, {
|
|
741
|
+
variant: "destructive",
|
|
742
|
+
children: [/* @__PURE__ */ jsx(AlertTitle, { children: "Could not roll API key" }), /* @__PURE__ */ jsx(AlertDescription, { children: rollKeyMutation.error.message })]
|
|
743
|
+
}),
|
|
744
|
+
/* @__PURE__ */ jsxs("div", {
|
|
745
|
+
className: "space-y-4",
|
|
746
|
+
children: [activeKey && /* @__PURE__ */ jsx(ApiKey, {
|
|
747
|
+
deploymentName,
|
|
748
|
+
consumerId,
|
|
749
|
+
apiKeyId: activeKey.id,
|
|
750
|
+
apiKey: activeKey.key,
|
|
751
|
+
createdAt: activeKey.createdOn,
|
|
752
|
+
lastUsed: activeKey.updatedOn,
|
|
753
|
+
expiresOn: activeKey.expiresOn,
|
|
754
|
+
isActive: true,
|
|
755
|
+
label: "Current Key",
|
|
756
|
+
onDelete: () => deleteKeyMutation.mutateAsync({ keyId: activeKey.id })
|
|
757
|
+
}, activeKey.id), expiringKeys.map((apiKey) => /* @__PURE__ */ jsx(ApiKey, {
|
|
758
|
+
deploymentName,
|
|
759
|
+
consumerId,
|
|
760
|
+
apiKeyId: apiKey.id,
|
|
761
|
+
apiKey: apiKey.key,
|
|
762
|
+
createdAt: apiKey.createdOn,
|
|
763
|
+
lastUsed: apiKey.updatedOn,
|
|
764
|
+
expiresOn: apiKey.expiresOn,
|
|
765
|
+
isActive: false,
|
|
766
|
+
label: "Previous Key",
|
|
767
|
+
onDelete: () => deleteKeyMutation.mutateAsync({ keyId: apiKey.id })
|
|
768
|
+
}, apiKey.id))]
|
|
769
|
+
})
|
|
770
|
+
]
|
|
736
771
|
});
|
|
737
772
|
};
|
|
738
773
|
|
|
@@ -873,7 +908,7 @@ const enableMonetization = (config, options) => {
|
|
|
873
908
|
const zuploMonetizationPlugin = (options) => {
|
|
874
909
|
return {
|
|
875
910
|
getIdentities: async (context) => {
|
|
876
|
-
return (await
|
|
911
|
+
return (await queryClient.fetchQuery({
|
|
877
912
|
queryKey: [`/v3/zudoku-metering/${options.environmentName}/subscriptions`],
|
|
878
913
|
meta: { context }
|
|
879
914
|
})).items.flatMap((item) => item.consumer.apiKeys.map((apiKey) => ({
|