🔖
【NextJs + BetterAuth + Polar】Subcription サブスクサービスの実装【#14 Polar Route】
【#14 Polar tRPC Route】
YouTube: https://youtu.be/Nk07mpgtV8E
今回は、サーバーサイドでサブスクリプションの状態を管理する部分を実装します。
trpc/init.ts
import { cache } from "react";
import { headers } from "next/headers";
import { initTRPC, TRPCError } from "@trpc/server";
import { auth } from "@/lib/auth";
import { polarClient } from "@/lib/polar-client";
import superjson from "superjson";
export const createTRPCContext = cache(async () => {
/**
* @see: https://trpc.io/docs/server/context
*/
return { userId: "user_123" };
});
// Avoid exporting the entire t-object
// since it's not very descriptive.
// For instance, the use of a t variable
// is common in i18n libraries.
const t = initTRPC.create({
/**
* @see https://trpc.io/docs/server/data-transformers
*/
transformer: superjson,
});
// Base router and procedure helpers
export const createTRPCRouter = t.router;
export const createCallerFactory = t.createCallerFactory;
export const baseProcedure = t.procedure;
export const protectedProcedure = baseProcedure.use(async ({ ctx, next }) => {
const session = await auth.api.getSession({
headers: await headers(),
});
if (!session) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Unauthorized" });
}
return next({
ctx: { ...ctx, auth: session },
});
});
export const subscribedProcedure = protectedProcedure.use(
async ({ ctx, next }) => {
const customer = await polarClient.customers.getStateExternal({
externalId: ctx.auth.user.id,
});
if (
!customer.activeSubscriptions ||
customer.activeSubscriptions.length === 0
) {
throw new TRPCError({ code: "FORBIDDEN", message: "Not subscribed" });
}
return next({ ctx: { ...ctx, customer } });
}
);
Discussion