Skip to content

Commit 44e2082

Browse files
committed
feat: add customer schemas and contracts
Add customer endpoint support for subscription management: - CustomerSchema with subscriptions and hasActiveSubscription - CustomerSubscriptionSchema for subscription summaries - GetCustomerInputSchema with externalId/email/customerId lookup - customer.get ORPC contract
1 parent 4770609 commit 44e2082

3 files changed

Lines changed: 90 additions & 1 deletion

File tree

src/contracts/customer.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { oc } from "@orpc/contract";
2+
import { CustomerSchema, GetCustomerInputSchema } from "../schemas/customer";
3+
4+
export const getCustomerContract = oc
5+
.input(GetCustomerInputSchema)
6+
.output(CustomerSchema);
7+
8+
export const customer = {
9+
get: getCustomerContract,
10+
};

src/index.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { checkout } from "./contracts/checkout";
2+
import { customer } from "./contracts/customer";
23
import { onboarding } from "./contracts/onboarding";
34
import { products } from "./contracts/products";
45
import { subscription } from "./contracts/subscription";
@@ -23,6 +24,7 @@ export type {
2324
CreateRenewalCheckout,
2425
GetSubscriptionInput,
2526
} from "./contracts/subscription";
27+
export type { GetCustomerInput } from "./schemas/customer";
2628
export type { Checkout } from "./schemas/checkout";
2729
export { CheckoutSchema } from "./schemas/checkout";
2830
export type { Currency } from "./schemas/currency";
@@ -47,8 +49,23 @@ export {
4749
SubscriptionWebhookEventSchema,
4850
SubscriptionWebhookPayloadSchema,
4951
} from "./schemas/subscription";
52+
export type {
53+
Customer,
54+
CustomerSubscription,
55+
} from "./schemas/customer";
56+
export {
57+
CustomerSchema,
58+
CustomerSubscriptionSchema,
59+
GetCustomerInputSchema,
60+
} from "./schemas/customer";
5061

51-
export const contract = { checkout, onboarding, products, subscription };
62+
export const contract = {
63+
checkout,
64+
customer,
65+
onboarding,
66+
products,
67+
subscription,
68+
};
5269

5370
export type { MetadataValidationError } from "./validation/metadata-validation";
5471
export {

src/schemas/customer.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { z } from "zod";
2+
import { CurrencySchema } from "./currency";
3+
import {
4+
RecurringIntervalSchema,
5+
SubscriptionStatusSchema,
6+
} from "./subscription";
7+
8+
/**
9+
* Summary of a subscription for the customer response.
10+
* Contains the essential fields needed for displaying subscription status.
11+
*/
12+
export const CustomerSubscriptionSchema = z.object({
13+
id: z.string(),
14+
productId: z.string(),
15+
status: SubscriptionStatusSchema,
16+
currentPeriodStart: z.string(), // ISO date
17+
currentPeriodEnd: z.string(), // ISO date
18+
cancelAtPeriodEnd: z.boolean().optional(),
19+
amount: z.number(),
20+
currency: CurrencySchema,
21+
recurringInterval: RecurringIntervalSchema,
22+
});
23+
24+
/**
25+
* Customer data with their subscriptions.
26+
* Returned by the customer.get endpoint.
27+
*/
28+
export const CustomerSchema = z.object({
29+
id: z.string(),
30+
email: z.string().nullable().optional(),
31+
name: z.string().nullable().optional(),
32+
externalId: z.string().nullable().optional(),
33+
subscriptions: z.array(CustomerSubscriptionSchema),
34+
hasActiveSubscription: z.boolean(),
35+
});
36+
37+
/**
38+
* Input for getting a customer.
39+
* Requires exactly one of: externalId, email, or customerId.
40+
*/
41+
export const GetCustomerInputSchema = z
42+
.object({
43+
externalId: z.string().optional(),
44+
email: z.string().optional(),
45+
customerId: z.string().optional(),
46+
})
47+
.refine(
48+
(data) => {
49+
const fields = [data.externalId, data.email, data.customerId].filter(
50+
Boolean,
51+
);
52+
return fields.length === 1;
53+
},
54+
{
55+
message:
56+
"Exactly one of externalId, email, or customerId must be provided",
57+
},
58+
);
59+
60+
export type CustomerSubscription = z.infer<typeof CustomerSubscriptionSchema>;
61+
export type Customer = z.infer<typeof CustomerSchema>;
62+
export type GetCustomerInput = z.infer<typeof GetCustomerInputSchema>;

0 commit comments

Comments
 (0)