@kamod-ch/otok-stripe 2.0.0
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/README.md +93 -0
- package/dist/actions.d.ts +8 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +19 -0
- package/dist/actions.js.map +1 -0
- package/dist/adapter/index.d.ts +2 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +2 -0
- package/dist/adapter/index.js.map +1 -0
- package/dist/adapter/types.d.ts +11 -0
- package/dist/adapter/types.d.ts.map +1 -0
- package/dist/adapter/types.js +2 -0
- package/dist/adapter/types.js.map +1 -0
- package/dist/checkout.d.ts +4 -0
- package/dist/checkout.d.ts.map +1 -0
- package/dist/checkout.js +45 -0
- package/dist/checkout.js.map +1 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +10 -0
- package/dist/client.js.map +1 -0
- package/dist/dto.d.ts +25 -0
- package/dist/dto.d.ts.map +1 -0
- package/dist/dto.js +21 -0
- package/dist/dto.js.map +1 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +21 -0
- package/dist/errors.js.map +1 -0
- package/dist/factory.d.ts +3 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +16 -0
- package/dist/factory.js.map +1 -0
- package/dist/idempotency.d.ts +17 -0
- package/dist/idempotency.d.ts.map +1 -0
- package/dist/idempotency.js +41 -0
- package/dist/idempotency.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +14 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +90 -0
- package/dist/plugin.js.map +1 -0
- package/dist/portal.d.ts +10 -0
- package/dist/portal.d.ts.map +1 -0
- package/dist/portal.js +15 -0
- package/dist/portal.js.map +1 -0
- package/dist/provider/types.d.ts +38 -0
- package/dist/provider/types.d.ts.map +1 -0
- package/dist/provider/types.js +2 -0
- package/dist/provider/types.js.map +1 -0
- package/dist/providers/live.d.ts +4 -0
- package/dist/providers/live.d.ts.map +1 -0
- package/dist/providers/live.js +29 -0
- package/dist/providers/live.js.map +1 -0
- package/dist/providers/test.d.ts +13 -0
- package/dist/providers/test.d.ts.map +1 -0
- package/dist/providers/test.js +70 -0
- package/dist/providers/test.js.map +1 -0
- package/dist/registry.d.ts +7 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +18 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/webhook/events.d.ts +8 -0
- package/dist/webhook/events.d.ts.map +1 -0
- package/dist/webhook/events.js +82 -0
- package/dist/webhook/events.js.map +1 -0
- package/dist/webhook/index.d.ts +3 -0
- package/dist/webhook/index.d.ts.map +1 -0
- package/dist/webhook/index.js +3 -0
- package/dist/webhook/index.js.map +1 -0
- package/dist/webhook/middleware.d.ts +26 -0
- package/dist/webhook/middleware.d.ts.map +1 -0
- package/dist/webhook/middleware.js +31 -0
- package/dist/webhook/middleware.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAE,iCAAiC,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AACrG,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,IAAI,gBAAgB,GAAG,iCAAiC,EAAE,CAAC;AAE3D,4BAA4B;AAC5B,MAAM,UAAU,8BAA8B;IAC5C,gBAAgB,GAAG,iCAAiC,EAAE,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,yBAAyB;IACvC,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,SAAS,oBAAoB,CAAC,OAA4B;IACxD,OAAO,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,IAAI,uBAAuB,CAAC,EAAE,IAAI,EAAE,CAAC;AAC3G,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,GAAS,EACT,OAAmC,EACnC,OAA+B;IAE/B,MAAM,QAAQ,GAAG,oBAAoB,CAAQ,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/D,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,sBAAsB,CAAC;IAClE,MAAM,aAAa,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAEpD,MAAM,OAAO,GAAyB;QACpC,QAAQ;QACR,WAAW;QACX,aAAa;KACd,CAAC;IAEF,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAE/B,IAAI,OAAO,IAAI,aAAa,EAAE,CAAC;QAC7B,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YAChC,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;YACnD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,iCAAiC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;YAC3G,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,KAAK,CAAC;YACV,IAAI,CAAC;gBACH,KAAK,GAAG,QAAQ,CAAC,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;YAC5E,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;gBAC7E,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;YACxE,CAAC;YAED,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,8BAA8B,CAAC,gBAAgB,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE,CACxG,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CACpC,CAAC;YAEF,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,mBAAmB,GAAG,YAAY,CAAsB;IAC5D,IAAI,EAAE,uBAAuB;IAC7B,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE;QACN,KAAK,CAAC,KAAK;YACT,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACxC,MAAM,IAAI,qBAAqB,CAAC,oCAAoC,CAAC,CAAC;YACxE,CAAC;YACD,MAAM,MAAM,GAAG,KAAgC,CAAC;YAChD,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC5D,MAAM,IAAI,qBAAqB,CAAC,0CAA0C,CAAC,CAAC;YAC9E,CAAC;YACD,OAAO,KAA4B,CAAC;QACtC,CAAC;KACF;IACD,SAAS,EAAE;QACT,KAAK,CAAC,KAAK;YACT,MAAM,SAAS,GAAG,KAAK,CAAC,iBAAiB,CAAC;YAC1C,MAAM,aAAa,GAAG,KAAK,CAAC,qBAAqB,CAAC;YAClD,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC1C,MAAM,IAAI,qBAAqB,CAAC,8CAA8C,CAAC,CAAC;YAClF,CAAC;YACD,IAAI,aAAa,KAAK,SAAS,IAAI,CAAC,aAAa,EAAE,CAAC;gBAClD,MAAM,IAAI,qBAAqB,CAAC,kDAAkD,CAAC,CAAC;YACtF,CAAC;YACD,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,mBAAmB,EAAE,aAAa,EAAE,CAAC;QAC5E,CAAC;KACF;CACF,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,CAAgC,OAAmC;IAC/F,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAA8B,CAAC,CAAC;IAEnE,MAAM,CAAC,YAAY,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;QACtC,MAAM,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/portal.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type Stripe from "stripe";
|
|
2
|
+
export interface BillingPortalSessionInput {
|
|
3
|
+
customerId: string;
|
|
4
|
+
returnUrl: string;
|
|
5
|
+
}
|
|
6
|
+
export interface BillingPortalSessionResult {
|
|
7
|
+
url: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function createBillingPortalSession(stripe: Stripe, input: BillingPortalSessionInput): Promise<BillingPortalSessionResult>;
|
|
10
|
+
//# sourceMappingURL=portal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../src/portal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,0BAA0B,CAAC,CAcrC"}
|
package/dist/portal.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export async function createBillingPortalSession(stripe, input) {
|
|
2
|
+
if (!input.customerId)
|
|
3
|
+
throw new Error("createBillingPortalSession requires customerId");
|
|
4
|
+
if (!input.returnUrl)
|
|
5
|
+
throw new Error("createBillingPortalSession requires returnUrl");
|
|
6
|
+
const session = await stripe.billingPortal.sessions.create({
|
|
7
|
+
customer: input.customerId,
|
|
8
|
+
return_url: input.returnUrl,
|
|
9
|
+
});
|
|
10
|
+
if (!session.url) {
|
|
11
|
+
throw new Error("Stripe Billing Portal Session was created without a URL");
|
|
12
|
+
}
|
|
13
|
+
return { url: session.url };
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=portal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal.js","sourceRoot":"","sources":["../src/portal.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,MAAc,EACd,KAAgC;IAEhC,IAAI,CAAC,KAAK,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACzF,IAAI,CAAC,KAAK,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAEvF,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC;QACzD,QAAQ,EAAE,KAAK,CAAC,UAAU;QAC1B,UAAU,EAAE,KAAK,CAAC,SAAS;KAC5B,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type Stripe from "stripe";
|
|
2
|
+
import type { BillingPortalSessionInput, BillingPortalSessionResult } from "../portal.js";
|
|
3
|
+
import type { CheckoutSessionInput, CheckoutSessionResult } from "../types.js";
|
|
4
|
+
export interface StripeProviderCapabilities {
|
|
5
|
+
checkout: boolean;
|
|
6
|
+
portal: boolean;
|
|
7
|
+
webhooks: boolean;
|
|
8
|
+
liveMode: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface StripeProvider<TPlan extends string = string> {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly capabilities: StripeProviderCapabilities;
|
|
13
|
+
readonly client: Stripe;
|
|
14
|
+
createCheckoutSession(input: CheckoutSessionInput<TPlan>): Promise<CheckoutSessionResult>;
|
|
15
|
+
createBillingPortalSession(input: BillingPortalSessionInput): Promise<BillingPortalSessionResult>;
|
|
16
|
+
constructWebhookEvent(rawBody: string, signature: string, secret: string): Stripe.Event;
|
|
17
|
+
}
|
|
18
|
+
export type LiveStripeProviderConfig = {
|
|
19
|
+
type: "live";
|
|
20
|
+
secretKey?: string;
|
|
21
|
+
secretKeyEnv?: string;
|
|
22
|
+
};
|
|
23
|
+
export type TestStripeProviderConfig = {
|
|
24
|
+
type: "test";
|
|
25
|
+
};
|
|
26
|
+
export type StripeProviderConfig = LiveStripeProviderConfig | TestStripeProviderConfig;
|
|
27
|
+
export interface StripePluginOptions<TPlan extends string = string> {
|
|
28
|
+
provider: StripeProviderConfig;
|
|
29
|
+
webhookPath?: string;
|
|
30
|
+
webhookSecret?: string;
|
|
31
|
+
webhookSecretEnv?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface StripeRuntime<TPlan extends string = string> {
|
|
34
|
+
provider: StripeProvider<TPlan>;
|
|
35
|
+
webhookPath: string;
|
|
36
|
+
webhookSecret?: string;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/provider/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAE/E,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAc,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,0BAA0B,CAAC;IAClD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qBAAqB,CAAC,KAAK,EAAE,oBAAoB,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC1F,0BAA0B,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAClG,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;CACzF;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,wBAAwB,GAAG,wBAAwB,CAAC;AAEvF,MAAM,WAAW,mBAAmB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IAChE,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IAC1D,QAAQ,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/provider/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { LiveStripeProviderConfig, StripeProvider } from "../provider/types.js";
|
|
2
|
+
export declare function createLiveStripeProvider<TPlan extends string = string>(config: LiveStripeProviderConfig): StripeProvider<TPlan>;
|
|
3
|
+
export type { StripeProvider };
|
|
4
|
+
//# sourceMappingURL=live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../src/providers/live.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,wBAAwB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAYrF,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACpE,MAAM,EAAE,wBAAwB,GAC/B,cAAc,CAAC,KAAK,CAAC,CAkBvB;AAED,YAAY,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createBillingPortalSession } from "../portal.js";
|
|
2
|
+
import { createCheckoutSession } from "../checkout.js";
|
|
3
|
+
import { createStripeClient } from "../client.js";
|
|
4
|
+
import { OtokStripeConfigError } from "../errors.js";
|
|
5
|
+
function resolveSecretKey(config) {
|
|
6
|
+
const key = config.secretKey ?? process.env[config.secretKeyEnv ?? "STRIPE_SECRET_KEY"];
|
|
7
|
+
if (!key?.trim()) {
|
|
8
|
+
throw new OtokStripeConfigError("live stripe provider requires secretKey or STRIPE_SECRET_KEY environment variable");
|
|
9
|
+
}
|
|
10
|
+
return key.trim();
|
|
11
|
+
}
|
|
12
|
+
export function createLiveStripeProvider(config) {
|
|
13
|
+
const secretKey = resolveSecretKey(config);
|
|
14
|
+
const client = createStripeClient({ secretKey });
|
|
15
|
+
return {
|
|
16
|
+
name: "live",
|
|
17
|
+
capabilities: {
|
|
18
|
+
checkout: true,
|
|
19
|
+
portal: true,
|
|
20
|
+
webhooks: true,
|
|
21
|
+
liveMode: !secretKey.startsWith("sk_test"),
|
|
22
|
+
},
|
|
23
|
+
client,
|
|
24
|
+
createCheckoutSession: (input) => createCheckoutSession(client, input),
|
|
25
|
+
createBillingPortalSession: (input) => createBillingPortalSession(client, input),
|
|
26
|
+
constructWebhookEvent: (rawBody, signature, secret) => client.webhooks.constructEvent(rawBody, signature, secret),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.js","sourceRoot":"","sources":["../../src/providers/live.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGrD,SAAS,gBAAgB,CAAC,MAAgC;IACxD,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,mBAAmB,CAAC,CAAC;IACxF,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,qBAAqB,CAC7B,mFAAmF,CACpF,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,MAAgC;IAEhC,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;IAEjD,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,YAAY,EAAE;YACZ,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC;SAC3C;QACD,MAAM;QACN,qBAAqB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,qBAAqB,CAAC,MAAM,EAAE,KAAK,CAAC;QACtE,0BAA0B,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,0BAA0B,CAAC,MAAM,EAAE,KAAK,CAAC;QAChF,qBAAqB,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CACpD,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC;KAC7D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CheckoutSessionResult } from "../types.js";
|
|
2
|
+
import type { StripeProvider } from "../provider/types.js";
|
|
3
|
+
interface TestCheckoutSession extends CheckoutSessionResult {
|
|
4
|
+
metadata: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
/** @internal Test helper */
|
|
7
|
+
export declare function resetTestStripeProvider(): void;
|
|
8
|
+
export declare function getTestCheckoutSessions(): readonly TestCheckoutSession[];
|
|
9
|
+
export declare function createTestStripeProvider<TPlan extends string = string>(): StripeProvider<TPlan>;
|
|
10
|
+
export declare function markTestStripeEventProcessed(eventId: string): boolean;
|
|
11
|
+
export declare function isTestStripeEventProcessed(eventId: string): boolean;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/providers/test.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAwB,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,UAAU,mBAAoB,SAAQ,qBAAqB;IACzD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAKD,4BAA4B;AAC5B,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C;AAED,wBAAgB,uBAAuB,IAAI,SAAS,mBAAmB,EAAE,CAExE;AAED,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,KAAK,cAAc,CAAC,KAAK,CAAC,CAgD/F;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIrE;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEnE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const checkoutSessions = new Map();
|
|
2
|
+
const processedEvents = new Set();
|
|
3
|
+
/** @internal Test helper */
|
|
4
|
+
export function resetTestStripeProvider() {
|
|
5
|
+
checkoutSessions.clear();
|
|
6
|
+
processedEvents.clear();
|
|
7
|
+
}
|
|
8
|
+
export function getTestCheckoutSessions() {
|
|
9
|
+
return [...checkoutSessions.values()];
|
|
10
|
+
}
|
|
11
|
+
export function createTestStripeProvider() {
|
|
12
|
+
const client = {
|
|
13
|
+
apiKey: "sk_test_otok",
|
|
14
|
+
webhooks: {
|
|
15
|
+
constructEvent(rawBody, signature, _secret) {
|
|
16
|
+
if (!signature.startsWith("t=")) {
|
|
17
|
+
throw new Error("invalid signature");
|
|
18
|
+
}
|
|
19
|
+
return JSON.parse(rawBody);
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
name: "test",
|
|
25
|
+
capabilities: {
|
|
26
|
+
checkout: true,
|
|
27
|
+
portal: true,
|
|
28
|
+
webhooks: true,
|
|
29
|
+
liveMode: false,
|
|
30
|
+
},
|
|
31
|
+
client,
|
|
32
|
+
async createCheckoutSession(input) {
|
|
33
|
+
if (!input.priceId)
|
|
34
|
+
throw new Error("createCheckoutSession requires priceId");
|
|
35
|
+
const sessionId = `cs_test_${checkoutSessions.size + 1}`;
|
|
36
|
+
const result = {
|
|
37
|
+
sessionId,
|
|
38
|
+
url: `https://checkout.test/${sessionId}`,
|
|
39
|
+
metadata: {
|
|
40
|
+
workspaceId: input.workspaceId,
|
|
41
|
+
userId: input.userId,
|
|
42
|
+
plan: input.plan,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
checkoutSessions.set(sessionId, result);
|
|
46
|
+
return { sessionId: result.sessionId, url: result.url };
|
|
47
|
+
},
|
|
48
|
+
async createBillingPortalSession(input) {
|
|
49
|
+
if (!input.customerId)
|
|
50
|
+
throw new Error("createBillingPortalSession requires customerId");
|
|
51
|
+
return { url: `https://portal.test/${input.customerId}` };
|
|
52
|
+
},
|
|
53
|
+
constructWebhookEvent(rawBody, signature, _secret) {
|
|
54
|
+
if (!signature.startsWith("t=")) {
|
|
55
|
+
throw new Error("invalid signature");
|
|
56
|
+
}
|
|
57
|
+
return JSON.parse(rawBody);
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export function markTestStripeEventProcessed(eventId) {
|
|
62
|
+
if (processedEvents.has(eventId))
|
|
63
|
+
return false;
|
|
64
|
+
processedEvents.add(eventId);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
export function isTestStripeEventProcessed(eventId) {
|
|
68
|
+
return processedEvents.has(eventId);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/providers/test.ts"],"names":[],"mappings":"AASA,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAA+B,CAAC;AAChE,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;AAE1C,4BAA4B;AAC5B,MAAM,UAAU,uBAAuB;IACrC,gBAAgB,CAAC,KAAK,EAAE,CAAC;IACzB,eAAe,CAAC,KAAK,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,OAAO,CAAC,GAAG,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,MAAM,MAAM,GAAG;QACb,MAAM,EAAE,cAAc;QACtB,QAAQ,EAAE;YACR,cAAc,CAAC,OAAe,EAAE,SAAiB,EAAE,OAAe;gBAChE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;oBAChC,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBACvC,CAAC;gBACD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;YAC7C,CAAC;SACF;KACmB,CAAC;IAEvB,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,YAAY,EAAE;YACZ,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,KAAK;SAChB;QACD,MAAM;QACN,KAAK,CAAC,qBAAqB,CAAC,KAAkC;YAC5D,IAAI,CAAC,KAAK,CAAC,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC9E,MAAM,SAAS,GAAG,WAAW,gBAAgB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YACzD,MAAM,MAAM,GAAwB;gBAClC,SAAS;gBACT,GAAG,EAAE,yBAAyB,SAAS,EAAE;gBACzC,QAAQ,EAAE;oBACR,WAAW,EAAE,KAAK,CAAC,WAAW;oBAC9B,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;iBACjB;aACF,CAAC;YACF,gBAAgB,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YACxC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;QAC1D,CAAC;QACD,KAAK,CAAC,0BAA0B,CAAC,KAAgC;YAC/D,IAAI,CAAC,KAAK,CAAC,UAAU;gBAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;YACzF,OAAO,EAAE,GAAG,EAAE,uBAAuB,KAAK,CAAC,UAAU,EAAE,EAAE,CAAC;QAC5D,CAAC;QACD,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO;YAC/C,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACvC,CAAC;YACD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;QAC7C,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,OAAe;IAC1D,IAAI,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/C,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,OAAe;IACxD,OAAO,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { StripeRuntime } from "./provider/types.js";
|
|
2
|
+
/** @internal Test helper */
|
|
3
|
+
export declare function resetStripeRuntimeForTests(): void;
|
|
4
|
+
export declare function registerStripeRuntime<TPlan extends string = string>(value: StripeRuntime<TPlan>): void;
|
|
5
|
+
export declare function getStripeRuntime<TPlan extends string = string>(): StripeRuntime<TPlan>;
|
|
6
|
+
export declare function getStripeProvider<TPlan extends string = string>(): import("./index.js").StripeProvider<TPlan>;
|
|
7
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD,4BAA4B;AAC5B,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED,wBAAgB,qBAAqB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,CAEtG;AAED,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,KAAK,aAAa,CAAC,KAAK,CAAC,CAOtF;AAED,wBAAgB,iBAAiB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,gDAE9D"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
let runtime = null;
|
|
2
|
+
/** @internal Test helper */
|
|
3
|
+
export function resetStripeRuntimeForTests() {
|
|
4
|
+
runtime = null;
|
|
5
|
+
}
|
|
6
|
+
export function registerStripeRuntime(value) {
|
|
7
|
+
runtime = value;
|
|
8
|
+
}
|
|
9
|
+
export function getStripeRuntime() {
|
|
10
|
+
if (!runtime) {
|
|
11
|
+
throw new Error("otok-stripe: no stripe runtime registered. Add stripe() to otok.config.ts plugins.");
|
|
12
|
+
}
|
|
13
|
+
return runtime;
|
|
14
|
+
}
|
|
15
|
+
export function getStripeProvider() {
|
|
16
|
+
return getStripeRuntime().provider;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAEA,IAAI,OAAO,GAAyB,IAAI,CAAC;AAEzC,4BAA4B;AAC5B,MAAM,UAAU,0BAA0B;IACxC,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAgC,KAA2B;IAC9F,OAAO,GAAG,KAAsB,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,oFAAoF,CACrF,CAAC;IACJ,CAAC;IACD,OAAO,OAA+B,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,gBAAgB,EAAS,CAAC,QAAQ,CAAC;AAC5C,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type Stripe from "stripe";
|
|
2
|
+
export type CheckoutMode = "subscription" | "payment";
|
|
3
|
+
export interface StripeClientConfig {
|
|
4
|
+
secretKey: string;
|
|
5
|
+
/** Stripe API version override. Defaults to the SDK default. */
|
|
6
|
+
apiVersion?: Stripe.LatestApiVersion;
|
|
7
|
+
}
|
|
8
|
+
export interface CheckoutSessionInput<TPlan extends string = string> {
|
|
9
|
+
/** App plan key (e.g. "launch" | "pro"). Stored in session metadata. */
|
|
10
|
+
plan: TPlan;
|
|
11
|
+
/** Stripe Price ID for this plan. */
|
|
12
|
+
priceId: string;
|
|
13
|
+
workspaceId: string;
|
|
14
|
+
userId: string;
|
|
15
|
+
customerEmail?: string;
|
|
16
|
+
successUrl: string;
|
|
17
|
+
cancelUrl: string;
|
|
18
|
+
mode?: CheckoutMode;
|
|
19
|
+
/** Extra metadata merged into the Checkout Session. */
|
|
20
|
+
metadata?: Record<string, string>;
|
|
21
|
+
quantity?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface CheckoutSessionResult {
|
|
24
|
+
sessionId: string;
|
|
25
|
+
url: string;
|
|
26
|
+
}
|
|
27
|
+
export interface BillingRecord<TPlan extends string = string> {
|
|
28
|
+
workspaceId: string;
|
|
29
|
+
plan: TPlan;
|
|
30
|
+
stripeCustomerId?: string | null;
|
|
31
|
+
stripeSubscriptionId?: string | null;
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,SAAS,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC,gBAAgB,CAAC;CACtC;AAED,MAAM,WAAW,oBAAoB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IACjE,wEAAwE;IACxE,IAAI,EAAE,KAAK,CAAC;IACZ,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,KAAK,CAAC;IACZ,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type Stripe from "stripe";
|
|
2
|
+
import type { BillingAdapter } from "../adapter/types.js";
|
|
3
|
+
import type { BillingRecord } from "../types.js";
|
|
4
|
+
export declare function handleCheckoutCompleted<TPlan extends string>(adapter: BillingAdapter<TPlan>, session: Stripe.Checkout.Session): Promise<BillingRecord<TPlan> | null>;
|
|
5
|
+
export declare function handleSubscriptionUpdated<TPlan extends string>(adapter: BillingAdapter<TPlan>, subscription: Stripe.Subscription): Promise<BillingRecord<TPlan> | null>;
|
|
6
|
+
export declare function handleSubscriptionDeleted<TPlan extends string>(adapter: BillingAdapter<TPlan>, subscription: Stripe.Subscription): Promise<BillingRecord<TPlan> | null>;
|
|
7
|
+
export declare function dispatchStripeEvent<TPlan extends string>(adapter: BillingAdapter<TPlan>, event: Stripe.Event): Promise<BillingRecord<TPlan> | null>;
|
|
8
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/webhook/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAYjD,wBAAsB,uBAAuB,CAAC,KAAK,SAAS,MAAM,EAChE,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,EAC9B,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,GAC/B,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CActC;AAED,wBAAsB,yBAAyB,CAAC,KAAK,SAAS,MAAM,EAClE,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,EAC9B,YAAY,EAAE,MAAM,CAAC,YAAY,GAChC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CA8BtC;AAED,wBAAsB,yBAAyB,CAAC,KAAK,SAAS,MAAM,EAClE,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,EAC9B,YAAY,EAAE,MAAM,CAAC,YAAY,GAChC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CActC;AAED,wBAAsB,mBAAmB,CAAC,KAAK,SAAS,MAAM,EAC5D,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,EAC9B,KAAK,EAAE,MAAM,CAAC,KAAK,GAClB,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAWtC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
function customerId(value) {
|
|
2
|
+
if (!value)
|
|
3
|
+
return null;
|
|
4
|
+
return typeof value === "string" ? value : value.id;
|
|
5
|
+
}
|
|
6
|
+
function subscriptionId(value) {
|
|
7
|
+
if (!value)
|
|
8
|
+
return null;
|
|
9
|
+
return typeof value === "string" ? value : value.id;
|
|
10
|
+
}
|
|
11
|
+
export async function handleCheckoutCompleted(adapter, session) {
|
|
12
|
+
const workspaceId = session.metadata?.workspaceId ?? session.client_reference_id ?? null;
|
|
13
|
+
const plan = session.metadata?.plan;
|
|
14
|
+
if (!workspaceId || !plan)
|
|
15
|
+
return null;
|
|
16
|
+
const record = {
|
|
17
|
+
workspaceId,
|
|
18
|
+
plan,
|
|
19
|
+
stripeCustomerId: customerId(session.customer),
|
|
20
|
+
stripeSubscriptionId: subscriptionId(session.subscription),
|
|
21
|
+
updatedAt: new Date().toISOString(),
|
|
22
|
+
};
|
|
23
|
+
await adapter.upsertRecord(record);
|
|
24
|
+
return record;
|
|
25
|
+
}
|
|
26
|
+
export async function handleSubscriptionUpdated(adapter, subscription) {
|
|
27
|
+
const workspaceId = subscription.metadata?.workspaceId;
|
|
28
|
+
if (!workspaceId)
|
|
29
|
+
return null;
|
|
30
|
+
const priceId = subscription.items.data[0]?.price?.id;
|
|
31
|
+
let plan = subscription.metadata?.plan ?? undefined;
|
|
32
|
+
if (!plan && priceId && adapter.resolvePlanFromPriceId) {
|
|
33
|
+
plan = adapter.resolvePlanFromPriceId(priceId) ?? undefined;
|
|
34
|
+
}
|
|
35
|
+
if (!plan) {
|
|
36
|
+
const existing = await adapter.getRecord(workspaceId);
|
|
37
|
+
plan = existing?.plan;
|
|
38
|
+
}
|
|
39
|
+
if (!plan)
|
|
40
|
+
return null;
|
|
41
|
+
const active = subscription.status === "active" ||
|
|
42
|
+
subscription.status === "trialing" ||
|
|
43
|
+
subscription.status === "past_due";
|
|
44
|
+
const freePlan = (adapter.freePlan ?? "free");
|
|
45
|
+
const record = {
|
|
46
|
+
workspaceId,
|
|
47
|
+
plan: active ? plan : freePlan,
|
|
48
|
+
stripeCustomerId: customerId(subscription.customer),
|
|
49
|
+
stripeSubscriptionId: subscription.id,
|
|
50
|
+
updatedAt: new Date().toISOString(),
|
|
51
|
+
};
|
|
52
|
+
await adapter.upsertRecord(record);
|
|
53
|
+
return record;
|
|
54
|
+
}
|
|
55
|
+
export async function handleSubscriptionDeleted(adapter, subscription) {
|
|
56
|
+
const workspaceId = subscription.metadata?.workspaceId;
|
|
57
|
+
if (!workspaceId)
|
|
58
|
+
return null;
|
|
59
|
+
const freePlan = (adapter.freePlan ?? "free");
|
|
60
|
+
const record = {
|
|
61
|
+
workspaceId,
|
|
62
|
+
plan: freePlan,
|
|
63
|
+
stripeCustomerId: customerId(subscription.customer),
|
|
64
|
+
stripeSubscriptionId: null,
|
|
65
|
+
updatedAt: new Date().toISOString(),
|
|
66
|
+
};
|
|
67
|
+
await adapter.upsertRecord(record);
|
|
68
|
+
return record;
|
|
69
|
+
}
|
|
70
|
+
export async function dispatchStripeEvent(adapter, event) {
|
|
71
|
+
switch (event.type) {
|
|
72
|
+
case "checkout.session.completed":
|
|
73
|
+
return handleCheckoutCompleted(adapter, event.data.object);
|
|
74
|
+
case "customer.subscription.updated":
|
|
75
|
+
return handleSubscriptionUpdated(adapter, event.data.object);
|
|
76
|
+
case "customer.subscription.deleted":
|
|
77
|
+
return handleSubscriptionDeleted(adapter, event.data.object);
|
|
78
|
+
default:
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/webhook/events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webhook/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,0BAA0B,EAC1B,KAAK,2BAA2B,GACjC,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/webhook/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,0BAA0B,GAE3B,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import type Stripe from "stripe";
|
|
3
|
+
import type { BillingAdapter } from "../adapter/types.js";
|
|
4
|
+
import type { BillingRecord } from "../types.js";
|
|
5
|
+
export interface StripeWebhookHandlerOptions<TPlan extends string = string> {
|
|
6
|
+
stripe: Stripe;
|
|
7
|
+
webhookSecret: string;
|
|
8
|
+
adapter: BillingAdapter<TPlan>;
|
|
9
|
+
/** Called after a handled event updates billing state. */
|
|
10
|
+
onRecord?: (record: BillingRecord<TPlan>, event: Stripe.Event) => void | Promise<void>;
|
|
11
|
+
/** Called for events that produce no billing update (ignored types). */
|
|
12
|
+
onIgnored?: (event: Stripe.Event) => void | Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Returns a Hono route handler for Stripe webhooks.
|
|
16
|
+
* Uses the raw request body for signature verification — do not parse JSON first.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createStripeWebhookHandler<TPlan extends string = string>(options: StripeWebhookHandlerOptions<TPlan>): (c: Context) => Promise<(Response & import("hono").TypedResponse<{
|
|
19
|
+
error: {
|
|
20
|
+
code: string;
|
|
21
|
+
message: string;
|
|
22
|
+
};
|
|
23
|
+
}, 400, "json">) | (Response & import("hono").TypedResponse<{
|
|
24
|
+
received: true;
|
|
25
|
+
}, import("hono/utils/http-status").ContentfulStatusCode, "json">)>;
|
|
26
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/webhook/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,MAAM,WAAW,2BAA2B,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAC/B,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvF,wEAAwE;IACxE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACtE,OAAO,EAAE,2BAA2B,CAAC,KAAK,CAAC,IAE7B,GAAG,OAAO;;;;;;;oEAwBzB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { dispatchStripeEvent } from "./events.js";
|
|
2
|
+
/**
|
|
3
|
+
* Returns a Hono route handler for Stripe webhooks.
|
|
4
|
+
* Uses the raw request body for signature verification — do not parse JSON first.
|
|
5
|
+
*/
|
|
6
|
+
export function createStripeWebhookHandler(options) {
|
|
7
|
+
return async (c) => {
|
|
8
|
+
const signature = c.req.header("stripe-signature");
|
|
9
|
+
if (!signature) {
|
|
10
|
+
return c.json({ error: { code: "missing_signature", message: "Missing stripe-signature header" } }, 400);
|
|
11
|
+
}
|
|
12
|
+
const rawBody = await c.req.text();
|
|
13
|
+
let event;
|
|
14
|
+
try {
|
|
15
|
+
event = options.stripe.webhooks.constructEvent(rawBody, signature, options.webhookSecret);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
const message = error instanceof Error ? error.message : "Invalid signature";
|
|
19
|
+
return c.json({ error: { code: "invalid_signature", message } }, 400);
|
|
20
|
+
}
|
|
21
|
+
const record = await dispatchStripeEvent(options.adapter, event);
|
|
22
|
+
if (record) {
|
|
23
|
+
await options.onRecord?.(record, event);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
await options.onIgnored?.(event);
|
|
27
|
+
}
|
|
28
|
+
return c.json({ received: true });
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/webhook/middleware.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAYlD;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAA2C;IAE3C,OAAO,KAAK,EAAE,CAAU,EAAE,EAAE;QAC1B,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACnD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,iCAAiC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QAC3G,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,KAAmB,CAAC;QACxB,IAAI,CAAC;YACH,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;QAC5F,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;YAC7E,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACjE,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;QAED,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kamod-ch/otok-stripe",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Stripe Checkout and webhook helpers for Otok apps.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/kamod-ch/otok/tree/main/packages/otok-stripe#readme",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://github.com/kamod-ch/otok/issues"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/kamod-ch/otok.git",
|
|
13
|
+
"directory": "packages/otok-stripe"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./adapter": {
|
|
26
|
+
"types": "./dist/adapter/index.d.ts",
|
|
27
|
+
"default": "./dist/adapter/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./webhook": {
|
|
30
|
+
"types": "./dist/webhook/index.d.ts",
|
|
31
|
+
"default": "./dist/webhook/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./providers/test": {
|
|
34
|
+
"types": "./dist/providers/test.d.ts",
|
|
35
|
+
"default": "./dist/providers/test.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@kamod-ch/otok": ">=0.6.1",
|
|
40
|
+
"hono": ">=4",
|
|
41
|
+
"stripe": ">=17"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^24.12.2",
|
|
45
|
+
"hono": "^4.12.25",
|
|
46
|
+
"stripe": "^18.5.0",
|
|
47
|
+
"typescript": "~6.0.2",
|
|
48
|
+
"vitest": "^4.1.2",
|
|
49
|
+
"@kamod-ch/otok": "0.6.1",
|
|
50
|
+
"@kamod-ch/otok-test": "0.5.1"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=20"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
60
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
61
|
+
"test": "vitest run"
|
|
62
|
+
}
|
|
63
|
+
}
|