paykitjs 0.0.1-alpha.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.
- package/LICENSE +21 -0
- package/dist/_virtual/_rolldown/runtime.js +14 -0
- package/dist/api/define-route.d.ts +94 -0
- package/dist/api/define-route.js +153 -0
- package/dist/api/methods.d.ts +422 -0
- package/dist/api/methods.js +67 -0
- package/dist/cli/commands/init.js +264 -0
- package/dist/cli/commands/push.js +71 -0
- package/dist/cli/commands/status.js +84 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +45 -0
- package/dist/cli/templates/index.js +64 -0
- package/dist/cli/utils/detect.js +73 -0
- package/dist/cli/utils/format.js +58 -0
- package/dist/cli/utils/get-config.js +117 -0
- package/dist/cli/utils/shared.js +81 -0
- package/dist/cli/utils/telemetry.js +63 -0
- package/dist/client/index.d.ts +25 -0
- package/dist/client/index.js +27 -0
- package/dist/core/context.d.ts +17 -0
- package/dist/core/context.js +23 -0
- package/dist/core/create-paykit.d.ts +7 -0
- package/dist/core/create-paykit.js +67 -0
- package/dist/core/error-codes.d.ts +12 -0
- package/dist/core/error-codes.js +10 -0
- package/dist/core/errors.d.ts +41 -0
- package/dist/core/errors.js +47 -0
- package/dist/core/logger.d.ts +11 -0
- package/dist/core/logger.js +51 -0
- package/dist/core/utils.js +21 -0
- package/dist/customer/customer.api.js +47 -0
- package/dist/customer/customer.service.js +342 -0
- package/dist/customer/customer.types.d.ts +31 -0
- package/dist/database/index.d.ts +8 -0
- package/dist/database/index.js +32 -0
- package/dist/database/migrations/0000_init.sql +157 -0
- package/dist/database/migrations/meta/0000_snapshot.json +1222 -0
- package/dist/database/migrations/meta/_journal.json +13 -0
- package/dist/database/schema.d.ts +1767 -0
- package/dist/database/schema.js +150 -0
- package/dist/entitlement/entitlement.api.js +33 -0
- package/dist/entitlement/entitlement.service.d.ts +17 -0
- package/dist/entitlement/entitlement.service.js +123 -0
- package/dist/handlers/next.d.ts +9 -0
- package/dist/handlers/next.js +9 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +6 -0
- package/dist/invoice/invoice.service.js +54 -0
- package/dist/payment/payment.service.js +49 -0
- package/dist/payment-method/payment-method.service.js +78 -0
- package/dist/product/product-sync.service.js +111 -0
- package/dist/product/product.service.js +127 -0
- package/dist/providers/provider.d.ts +159 -0
- package/dist/providers/stripe.js +547 -0
- package/dist/subscription/subscription.api.js +24 -0
- package/dist/subscription/subscription.service.js +896 -0
- package/dist/subscription/subscription.types.d.ts +18 -0
- package/dist/subscription/subscription.types.js +11 -0
- package/dist/testing/testing.api.js +29 -0
- package/dist/testing/testing.service.js +49 -0
- package/dist/types/events.d.ts +181 -0
- package/dist/types/instance.d.ts +88 -0
- package/dist/types/models.d.ts +11 -0
- package/dist/types/options.d.ts +32 -0
- package/dist/types/plugin.d.ts +11 -0
- package/dist/types/schema.d.ts +99 -0
- package/dist/types/schema.js +192 -0
- package/dist/utilities/dependencies/check-dependencies.js +16 -0
- package/dist/utilities/dependencies/get-dependencies.js +68 -0
- package/dist/utilities/dependencies/index.js +8 -0
- package/dist/utilities/dependencies/paykit-package-list.js +8 -0
- package/dist/webhook/webhook.api.js +29 -0
- package/dist/webhook/webhook.service.js +143 -0
- package/package.json +76 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { PAYKIT_ERROR_CODES, PayKitError } from "../core/errors.js";
|
|
2
|
+
import { feature, product, productFeature } from "../database/schema.js";
|
|
3
|
+
import { generateId } from "../core/utils.js";
|
|
4
|
+
import { and, desc, eq, sql } from "drizzle-orm";
|
|
5
|
+
//#region src/product/product.service.ts
|
|
6
|
+
function withProviderInfo(storedProduct, providerId) {
|
|
7
|
+
const providerInfo = (storedProduct.provider ?? {})[providerId];
|
|
8
|
+
return {
|
|
9
|
+
...storedProduct,
|
|
10
|
+
providerProductId: providerInfo?.productId ?? null,
|
|
11
|
+
providerPriceId: providerInfo?.priceId ?? null
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
async function upsertFeature(database, input) {
|
|
15
|
+
const now = /* @__PURE__ */ new Date();
|
|
16
|
+
const row = (await database.insert(feature).values({
|
|
17
|
+
createdAt: now,
|
|
18
|
+
id: input.id,
|
|
19
|
+
type: input.type,
|
|
20
|
+
updatedAt: now
|
|
21
|
+
}).onConflictDoUpdate({
|
|
22
|
+
target: feature.id,
|
|
23
|
+
set: {
|
|
24
|
+
type: input.type,
|
|
25
|
+
updatedAt: now
|
|
26
|
+
}
|
|
27
|
+
}).returning())[0];
|
|
28
|
+
if (!row) throw PayKitError.from("INTERNAL_SERVER_ERROR", PAYKIT_ERROR_CODES.FEATURE_UPSERT_FAILED, `Failed to upsert feature "${input.id}"`);
|
|
29
|
+
return row;
|
|
30
|
+
}
|
|
31
|
+
async function getLatestProduct(database, id) {
|
|
32
|
+
return await database.query.product.findFirst({
|
|
33
|
+
where: eq(product.id, id),
|
|
34
|
+
orderBy: (p, { desc }) => [desc(p.version)]
|
|
35
|
+
}) ?? null;
|
|
36
|
+
}
|
|
37
|
+
async function getLatestProductSnapshot(database, id) {
|
|
38
|
+
const storedProduct = await getLatestProduct(database, id);
|
|
39
|
+
if (!storedProduct) return null;
|
|
40
|
+
return {
|
|
41
|
+
features: await getProductFeatures(database, storedProduct.internalId),
|
|
42
|
+
product: storedProduct
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async function insertProductVersion(database, input) {
|
|
46
|
+
const now = /* @__PURE__ */ new Date();
|
|
47
|
+
const internalId = generateId("prod");
|
|
48
|
+
await database.insert(product).values({
|
|
49
|
+
createdAt: now,
|
|
50
|
+
group: input.group,
|
|
51
|
+
hash: input.hash,
|
|
52
|
+
id: input.id,
|
|
53
|
+
internalId,
|
|
54
|
+
isDefault: input.isDefault,
|
|
55
|
+
name: input.name,
|
|
56
|
+
priceAmount: input.priceAmount,
|
|
57
|
+
priceInterval: input.priceInterval,
|
|
58
|
+
updatedAt: now,
|
|
59
|
+
version: input.version
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
createdAt: now,
|
|
63
|
+
group: input.group,
|
|
64
|
+
hash: input.hash,
|
|
65
|
+
id: input.id,
|
|
66
|
+
internalId,
|
|
67
|
+
isDefault: input.isDefault,
|
|
68
|
+
name: input.name,
|
|
69
|
+
priceAmount: input.priceAmount,
|
|
70
|
+
priceInterval: input.priceInterval,
|
|
71
|
+
provider: {},
|
|
72
|
+
updatedAt: now,
|
|
73
|
+
version: input.version
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function updateProductName(database, internalId, name) {
|
|
77
|
+
await database.update(product).set({
|
|
78
|
+
name,
|
|
79
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
80
|
+
}).where(eq(product.internalId, internalId));
|
|
81
|
+
}
|
|
82
|
+
async function getProductFeatures(database, productInternalId) {
|
|
83
|
+
return await database.query.productFeature.findMany({
|
|
84
|
+
where: eq(productFeature.productInternalId, productInternalId),
|
|
85
|
+
orderBy: (pf) => [pf.featureId]
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async function replaceProductFeatures(database, input) {
|
|
89
|
+
await database.delete(productFeature).where(eq(productFeature.productInternalId, input.productInternalId));
|
|
90
|
+
if (input.features.length === 0) return;
|
|
91
|
+
const now = /* @__PURE__ */ new Date();
|
|
92
|
+
for (const planFeature of input.features) await database.insert(productFeature).values({
|
|
93
|
+
config: planFeature.config,
|
|
94
|
+
createdAt: now,
|
|
95
|
+
featureId: planFeature.id,
|
|
96
|
+
limit: planFeature.limit,
|
|
97
|
+
productInternalId: input.productInternalId,
|
|
98
|
+
resetInterval: planFeature.resetInterval,
|
|
99
|
+
updatedAt: now
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
async function getProviderProduct(database, productInternalId, providerId) {
|
|
103
|
+
const row = await database.query.product.findFirst({ where: eq(product.internalId, productInternalId) });
|
|
104
|
+
if (!row) return null;
|
|
105
|
+
return row.provider[providerId] ?? null;
|
|
106
|
+
}
|
|
107
|
+
async function upsertProviderProduct(database, input) {
|
|
108
|
+
const existing = await database.query.product.findFirst({ where: eq(product.internalId, input.productInternalId) });
|
|
109
|
+
if (!existing) return;
|
|
110
|
+
const providerMap = existing.provider ?? {};
|
|
111
|
+
providerMap[input.providerId] = {
|
|
112
|
+
productId: input.providerProductId,
|
|
113
|
+
priceId: input.providerPriceId ?? null
|
|
114
|
+
};
|
|
115
|
+
await database.update(product).set({ provider: providerMap }).where(eq(product.internalId, input.productInternalId));
|
|
116
|
+
}
|
|
117
|
+
async function getDefaultProductInGroup(database, group) {
|
|
118
|
+
return await database.query.product.findFirst({
|
|
119
|
+
where: and(eq(product.group, group), eq(product.isDefault, true)),
|
|
120
|
+
orderBy: [desc(product.version)]
|
|
121
|
+
}) ?? null;
|
|
122
|
+
}
|
|
123
|
+
async function getProductByProviderPriceId(database, input) {
|
|
124
|
+
return await database.query.product.findFirst({ where: sql`${product.provider}->${input.providerId}->>'priceId' = ${input.providerPriceId}` }) ?? null;
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
export { getDefaultProductInGroup, getLatestProduct, getLatestProductSnapshot, getProductByProviderPriceId, getProviderProduct, insertProductVersion, replaceProductFeatures, updateProductName, upsertFeature, upsertProviderProduct, withProviderInfo };
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { NormalizedWebhookEvent } from "../types/events.js";
|
|
2
|
+
|
|
3
|
+
//#region src/providers/provider.d.ts
|
|
4
|
+
interface ProviderCustomer {
|
|
5
|
+
frozenTime?: string;
|
|
6
|
+
id: string;
|
|
7
|
+
testClockId?: string;
|
|
8
|
+
}
|
|
9
|
+
type ProviderCustomerMap = Record<string, ProviderCustomer>;
|
|
10
|
+
interface ProviderTestClock {
|
|
11
|
+
frozenTime: Date;
|
|
12
|
+
id: string;
|
|
13
|
+
name?: string | null;
|
|
14
|
+
status: string;
|
|
15
|
+
}
|
|
16
|
+
interface ProviderInvoice {
|
|
17
|
+
currency: string;
|
|
18
|
+
hostedUrl?: string | null;
|
|
19
|
+
periodEndAt?: Date | null;
|
|
20
|
+
periodStartAt?: Date | null;
|
|
21
|
+
providerInvoiceId: string;
|
|
22
|
+
status: string | null;
|
|
23
|
+
totalAmount: number;
|
|
24
|
+
}
|
|
25
|
+
interface ProviderRequiredAction {
|
|
26
|
+
clientSecret?: string;
|
|
27
|
+
paymentIntentId?: string;
|
|
28
|
+
type: string;
|
|
29
|
+
}
|
|
30
|
+
interface ProviderSubscription {
|
|
31
|
+
cancelAtPeriodEnd: boolean;
|
|
32
|
+
canceledAt?: Date | null;
|
|
33
|
+
currentPeriodEndAt?: Date | null;
|
|
34
|
+
currentPeriodStartAt?: Date | null;
|
|
35
|
+
endedAt?: Date | null;
|
|
36
|
+
providerPriceId?: string | null;
|
|
37
|
+
providerSubscriptionId: string;
|
|
38
|
+
providerSubscriptionScheduleId?: string | null;
|
|
39
|
+
status: string;
|
|
40
|
+
}
|
|
41
|
+
interface ProviderSubscriptionResult {
|
|
42
|
+
invoice?: ProviderInvoice | null;
|
|
43
|
+
paymentUrl: string | null;
|
|
44
|
+
providerCheckoutSessionId?: string;
|
|
45
|
+
requiredAction?: ProviderRequiredAction | null;
|
|
46
|
+
subscription?: ProviderSubscription | null;
|
|
47
|
+
}
|
|
48
|
+
interface StripeRuntime {
|
|
49
|
+
upsertCustomer(data: {
|
|
50
|
+
createTestClock?: boolean;
|
|
51
|
+
id: string;
|
|
52
|
+
email?: string;
|
|
53
|
+
name?: string;
|
|
54
|
+
metadata?: Record<string, string>;
|
|
55
|
+
}): Promise<{
|
|
56
|
+
providerCustomer: ProviderCustomer;
|
|
57
|
+
}>;
|
|
58
|
+
deleteCustomer(data: {
|
|
59
|
+
providerCustomerId: string;
|
|
60
|
+
}): Promise<void>;
|
|
61
|
+
getTestClock(data: {
|
|
62
|
+
testClockId: string;
|
|
63
|
+
}): Promise<ProviderTestClock>;
|
|
64
|
+
advanceTestClock(data: {
|
|
65
|
+
testClockId: string;
|
|
66
|
+
frozenTime: Date;
|
|
67
|
+
}): Promise<ProviderTestClock>;
|
|
68
|
+
attachPaymentMethod(data: {
|
|
69
|
+
providerCustomerId: string;
|
|
70
|
+
returnURL: string;
|
|
71
|
+
}): Promise<{
|
|
72
|
+
url: string;
|
|
73
|
+
}>;
|
|
74
|
+
createSubscriptionCheckout(data: {
|
|
75
|
+
providerCustomerId: string;
|
|
76
|
+
providerPriceId: string;
|
|
77
|
+
successUrl: string;
|
|
78
|
+
cancelUrl?: string;
|
|
79
|
+
metadata?: Record<string, string>;
|
|
80
|
+
}): Promise<{
|
|
81
|
+
paymentUrl: string;
|
|
82
|
+
providerCheckoutSessionId: string;
|
|
83
|
+
}>;
|
|
84
|
+
createSubscription(data: {
|
|
85
|
+
providerCustomerId: string;
|
|
86
|
+
providerPriceId: string;
|
|
87
|
+
}): Promise<ProviderSubscriptionResult>;
|
|
88
|
+
updateSubscription(data: {
|
|
89
|
+
providerPriceId: string;
|
|
90
|
+
providerSubscriptionId: string;
|
|
91
|
+
}): Promise<ProviderSubscriptionResult>;
|
|
92
|
+
createInvoice(data: {
|
|
93
|
+
providerCustomerId: string;
|
|
94
|
+
lines: Array<{
|
|
95
|
+
amount: number;
|
|
96
|
+
description: string;
|
|
97
|
+
}>;
|
|
98
|
+
autoAdvance?: boolean;
|
|
99
|
+
}): Promise<ProviderInvoice>;
|
|
100
|
+
scheduleSubscriptionChange(data: {
|
|
101
|
+
providerPriceId?: string | null;
|
|
102
|
+
providerSubscriptionScheduleId?: string | null;
|
|
103
|
+
providerSubscriptionId: string;
|
|
104
|
+
}): Promise<ProviderSubscriptionResult>;
|
|
105
|
+
cancelSubscription(data: {
|
|
106
|
+
currentPeriodEndAt?: Date | null;
|
|
107
|
+
providerSubscriptionId: string;
|
|
108
|
+
providerSubscriptionScheduleId?: string | null;
|
|
109
|
+
}): Promise<ProviderSubscriptionResult>;
|
|
110
|
+
listActiveSubscriptions(data: {
|
|
111
|
+
providerCustomerId: string;
|
|
112
|
+
}): Promise<Array<{
|
|
113
|
+
providerSubscriptionId: string;
|
|
114
|
+
}>>;
|
|
115
|
+
resumeSubscription(data: {
|
|
116
|
+
providerSubscriptionId: string;
|
|
117
|
+
providerSubscriptionScheduleId?: string | null;
|
|
118
|
+
}): Promise<ProviderSubscriptionResult>;
|
|
119
|
+
detachPaymentMethod(data: {
|
|
120
|
+
providerMethodId: string;
|
|
121
|
+
}): Promise<void>;
|
|
122
|
+
syncProduct(data: {
|
|
123
|
+
id: string;
|
|
124
|
+
name: string;
|
|
125
|
+
priceAmount: number;
|
|
126
|
+
priceInterval?: string | null;
|
|
127
|
+
existingProviderProductId?: string | null;
|
|
128
|
+
existingProviderPriceId?: string | null;
|
|
129
|
+
}): Promise<{
|
|
130
|
+
providerProductId: string;
|
|
131
|
+
providerPriceId: string;
|
|
132
|
+
}>;
|
|
133
|
+
handleWebhook(data: {
|
|
134
|
+
body: string;
|
|
135
|
+
headers: Record<string, string>;
|
|
136
|
+
}): Promise<NormalizedWebhookEvent[]>;
|
|
137
|
+
createPortalSession(data: {
|
|
138
|
+
providerCustomerId: string;
|
|
139
|
+
returnUrl: string;
|
|
140
|
+
}): Promise<{
|
|
141
|
+
url: string;
|
|
142
|
+
}>;
|
|
143
|
+
}
|
|
144
|
+
interface StripeProviderOptions {
|
|
145
|
+
currency?: string;
|
|
146
|
+
secretKey: string;
|
|
147
|
+
webhookSecret: string;
|
|
148
|
+
}
|
|
149
|
+
interface StripeProviderConfig extends StripeProviderOptions {
|
|
150
|
+
id: string;
|
|
151
|
+
kind: "stripe";
|
|
152
|
+
/**
|
|
153
|
+
* Internal test hook so repo tests can stub the Stripe runtime without a network client.
|
|
154
|
+
*/
|
|
155
|
+
runtime?: StripeRuntime;
|
|
156
|
+
}
|
|
157
|
+
type PayKitProvider = StripeProviderConfig;
|
|
158
|
+
//#endregion
|
|
159
|
+
export { PayKitProvider, ProviderCustomer, ProviderCustomerMap, ProviderTestClock, StripeProviderConfig, StripeProviderOptions, StripeRuntime };
|