paykitjs 0.0.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.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/dist/_virtual/_rolldown/runtime.js +13 -0
  3. package/dist/api/define-route.d.ts +94 -0
  4. package/dist/api/define-route.js +153 -0
  5. package/dist/api/methods.d.ts +422 -0
  6. package/dist/api/methods.js +67 -0
  7. package/dist/cli/commands/check.js +92 -0
  8. package/dist/cli/commands/init.js +264 -0
  9. package/dist/cli/commands/push.js +73 -0
  10. package/dist/cli/commands/telemetry.js +16 -0
  11. package/dist/cli/index.d.ts +1 -0
  12. package/dist/cli/index.js +21 -0
  13. package/dist/cli/templates/index.js +64 -0
  14. package/dist/cli/utils/detect.js +67 -0
  15. package/dist/cli/utils/format.js +58 -0
  16. package/dist/cli/utils/get-config.js +117 -0
  17. package/dist/cli/utils/telemetry.js +103 -0
  18. package/dist/client/index.d.ts +25 -0
  19. package/dist/client/index.js +27 -0
  20. package/dist/core/context.d.ts +17 -0
  21. package/dist/core/context.js +23 -0
  22. package/dist/core/create-paykit.d.ts +7 -0
  23. package/dist/core/create-paykit.js +52 -0
  24. package/dist/core/error-codes.d.ts +12 -0
  25. package/dist/core/error-codes.js +10 -0
  26. package/dist/core/errors.d.ts +41 -0
  27. package/dist/core/errors.js +47 -0
  28. package/dist/core/logger.d.ts +11 -0
  29. package/dist/core/logger.js +51 -0
  30. package/dist/core/utils.js +21 -0
  31. package/dist/customer/customer.api.js +47 -0
  32. package/dist/customer/customer.service.js +342 -0
  33. package/dist/customer/customer.types.d.ts +31 -0
  34. package/dist/database/index.d.ts +8 -0
  35. package/dist/database/index.js +32 -0
  36. package/dist/database/migrations/0000_init.sql +157 -0
  37. package/dist/database/migrations/meta/0000_snapshot.json +1222 -0
  38. package/dist/database/migrations/meta/_journal.json +13 -0
  39. package/dist/database/schema.d.ts +1767 -0
  40. package/dist/database/schema.js +150 -0
  41. package/dist/entitlement/entitlement.api.js +33 -0
  42. package/dist/entitlement/entitlement.service.d.ts +17 -0
  43. package/dist/entitlement/entitlement.service.js +123 -0
  44. package/dist/handlers/next.d.ts +9 -0
  45. package/dist/handlers/next.js +9 -0
  46. package/dist/index.d.ts +14 -0
  47. package/dist/index.js +6 -0
  48. package/dist/invoice/invoice.service.js +54 -0
  49. package/dist/payment/payment.service.js +49 -0
  50. package/dist/payment-method/payment-method.service.js +78 -0
  51. package/dist/product/product-sync.service.js +111 -0
  52. package/dist/product/product.service.js +127 -0
  53. package/dist/providers/provider.d.ts +159 -0
  54. package/dist/providers/stripe.js +547 -0
  55. package/dist/subscription/subscription.api.js +24 -0
  56. package/dist/subscription/subscription.service.js +896 -0
  57. package/dist/subscription/subscription.types.d.ts +18 -0
  58. package/dist/subscription/subscription.types.js +11 -0
  59. package/dist/testing/testing.api.js +29 -0
  60. package/dist/testing/testing.service.js +49 -0
  61. package/dist/types/events.d.ts +181 -0
  62. package/dist/types/instance.d.ts +88 -0
  63. package/dist/types/models.d.ts +11 -0
  64. package/dist/types/options.d.ts +32 -0
  65. package/dist/types/plugin.d.ts +11 -0
  66. package/dist/types/schema.d.ts +99 -0
  67. package/dist/types/schema.js +192 -0
  68. package/dist/webhook/webhook.api.js +29 -0
  69. package/dist/webhook/webhook.service.js +143 -0
  70. package/package.json +72 -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 };