@cosmicdrift/kumiko-server-runtime 0.393.0 → 0.395.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.
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import { type TierSyncResult } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
|
|
2
|
-
import { type
|
|
2
|
+
import { type SubscriptionPaddleOptions } from "@cosmicdrift/kumiko-bundled-features/subscription-paddle";
|
|
3
3
|
import { type SubscriptionStripeOptions } from "@cosmicdrift/kumiko-bundled-features/subscription-stripe";
|
|
4
4
|
import type { ExtraRouteDefinition } from "@cosmicdrift/kumiko-framework/api";
|
|
5
5
|
import type { FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
6
|
-
/** Mounts `subscription-stripe` and/or `subscription-
|
|
6
|
+
/** Mounts `subscription-stripe` and/or `subscription-paddle` plus one webhook
|
|
7
7
|
* route that writes the subscription and syncs the tenant's tier
|
|
8
8
|
* (`tier-engine`). Needs `billing-foundation`, `tier-engine`, `config` and
|
|
9
9
|
* `secrets` in `features`. The env keys (`STRIPE_API_KEY` /
|
|
10
|
-
* `STRIPE_WEBHOOK_SECRET`, `
|
|
11
|
-
* `
|
|
10
|
+
* `STRIPE_WEBHOOK_SECRET`, `PADDLE_API_KEY` / `PADDLE_WEBHOOK_SECRET` /
|
|
11
|
+
* `PADDLE_TENANT_BINDING_KEY` / `PADDLE_CLIENT_TOKEN`) are only the bridge fallback; the keys
|
|
12
12
|
* normally live in the secrets store.
|
|
13
13
|
*
|
|
14
14
|
* @example
|
|
15
15
|
* runProdApp({ ..., billing: {
|
|
16
16
|
* stripe: { priceToTier: { [env.STRIPE_PRICE_PRO]: "pro" } },
|
|
17
|
-
*
|
|
17
|
+
* paddle: { priceToTier: { [env.PADDLE_PRICE_PRO]: "pro" } },
|
|
18
18
|
* defaultTier: "free",
|
|
19
19
|
* } })
|
|
20
20
|
*/
|
|
21
21
|
export type BillingBootOption = {
|
|
22
|
-
/** At least one of `stripe` and `
|
|
22
|
+
/** At least one of `stripe` and `paddle` is required. */
|
|
23
23
|
readonly stripe?: {
|
|
24
24
|
readonly priceToTier: Readonly<Record<string, string>>;
|
|
25
25
|
/** Default `SUBSCRIPTION_WEBHOOK_PATH`; must contain `:providerName`. Applies to every provider. */
|
|
@@ -27,9 +27,9 @@ export type BillingBootOption = {
|
|
|
27
27
|
readonly oneOffPriceIds?: SubscriptionStripeOptions["oneOffPriceIds"];
|
|
28
28
|
readonly paymentInvoiceCreation?: boolean;
|
|
29
29
|
};
|
|
30
|
-
readonly
|
|
30
|
+
readonly paddle?: {
|
|
31
31
|
readonly priceToTier: Readonly<Record<string, string>>;
|
|
32
|
-
readonly oneOffPriceIds?:
|
|
32
|
+
readonly oneOffPriceIds?: SubscriptionPaddleOptions["oneOffPriceIds"];
|
|
33
33
|
};
|
|
34
34
|
/** Tier a tenant falls back to without an active subscription. */
|
|
35
35
|
readonly defaultTier: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSubscriptionTierSync, SUBSCRIPTION_WEBHOOK_PATH, } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
|
|
2
|
-
import {
|
|
2
|
+
import { createSubscriptionPaddleFeature, } from "@cosmicdrift/kumiko-bundled-features/subscription-paddle";
|
|
3
3
|
import { createSubscriptionStripeFeature, } from "@cosmicdrift/kumiko-bundled-features/subscription-stripe";
|
|
4
4
|
const PROVIDER_NAME_PARAM = ":providerName";
|
|
5
5
|
function warnOnEmptyPriceMap(provider, priceToTier) {
|
|
@@ -13,7 +13,7 @@ function bridgeCredentials(envSource, apiKeyName, webhookSecretName) {
|
|
|
13
13
|
const webhookSecret = envSource[webhookSecretName];
|
|
14
14
|
return { ...(apiKey && { apiKey }), ...(webhookSecret && { webhookSecret }) };
|
|
15
15
|
}
|
|
16
|
-
function providerFeatures({ stripe,
|
|
16
|
+
function providerFeatures({ stripe, paddle }, envSource) {
|
|
17
17
|
const features = [];
|
|
18
18
|
if (stripe) {
|
|
19
19
|
warnOnEmptyPriceMap("stripe", stripe.priceToTier);
|
|
@@ -26,20 +26,24 @@ function providerFeatures({ stripe, dodo }, envSource) {
|
|
|
26
26
|
...bridgeCredentials(envSource, "STRIPE_API_KEY", "STRIPE_WEBHOOK_SECRET"),
|
|
27
27
|
}));
|
|
28
28
|
}
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
if (paddle) {
|
|
30
|
+
const tenantBindingKey = envSource["PADDLE_TENANT_BINDING_KEY"];
|
|
31
|
+
const clientToken = envSource["PADDLE_CLIENT_TOKEN"];
|
|
32
|
+
warnOnEmptyPriceMap("paddle", paddle.priceToTier);
|
|
33
|
+
features.push(createSubscriptionPaddleFeature({
|
|
34
|
+
priceToTier: paddle.priceToTier,
|
|
35
|
+
...(paddle.oneOffPriceIds && { oneOffPriceIds: paddle.oneOffPriceIds }),
|
|
36
|
+
...bridgeCredentials(envSource, "PADDLE_API_KEY", "PADDLE_WEBHOOK_SECRET"),
|
|
37
|
+
...(tenantBindingKey && { tenantBindingKey }),
|
|
38
|
+
...(clientToken && { clientToken }),
|
|
35
39
|
}));
|
|
36
40
|
}
|
|
37
41
|
return features;
|
|
38
42
|
}
|
|
39
43
|
export function resolveBillingOption(billing, envSource) {
|
|
40
|
-
const { stripe,
|
|
41
|
-
if (!stripe && !
|
|
42
|
-
throw new Error("[runProdApp] billing needs at least one provider: set billing.stripe or billing.
|
|
44
|
+
const { stripe, paddle } = billing;
|
|
45
|
+
if (!stripe && !paddle) {
|
|
46
|
+
throw new Error("[runProdApp] billing needs at least one provider: set billing.stripe or billing.paddle.");
|
|
43
47
|
}
|
|
44
48
|
const webhookPath = stripe?.webhookPath ?? SUBSCRIPTION_WEBHOOK_PATH;
|
|
45
49
|
if (!webhookPath.includes(PROVIDER_NAME_PARAM)) {
|
|
@@ -49,7 +53,7 @@ export function resolveBillingOption(billing, envSource) {
|
|
|
49
53
|
const tierNames = new Set([
|
|
50
54
|
billing.defaultTier,
|
|
51
55
|
...Object.values(stripe?.priceToTier ?? {}),
|
|
52
|
-
...Object.values(
|
|
56
|
+
...Object.values(paddle?.priceToTier ?? {}),
|
|
53
57
|
...(billing.tierNames ?? []),
|
|
54
58
|
]);
|
|
55
59
|
const tierSync = createSubscriptionTierSync({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BILLING_FOUNDATION_FEATURE } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
|
|
2
2
|
import { DELIVERY_FEATURE } from "@cosmicdrift/kumiko-bundled-features/delivery";
|
|
3
3
|
import { FEATURE_TOGGLES_FEATURE } from "@cosmicdrift/kumiko-bundled-features/feature-toggles";
|
|
4
|
-
import {
|
|
4
|
+
import { SUBSCRIPTION_PADDLE_FEATURE } from "@cosmicdrift/kumiko-bundled-features/subscription-paddle";
|
|
5
5
|
import { SUBSCRIPTION_STRIPE_FEATURE } from "@cosmicdrift/kumiko-bundled-features/subscription-stripe";
|
|
6
6
|
import { TIER_ENGINE_FEATURE } from "@cosmicdrift/kumiko-bundled-features/tier-engine";
|
|
7
7
|
import { resolveBillingOption } from "./billing-option.js";
|
|
@@ -87,8 +87,8 @@ export async function resolveBootOptionWiring(options, envSource) {
|
|
|
87
87
|
if (options.billing.stripe) {
|
|
88
88
|
rejectDoubleMount(mounted, "billing.stripe", SUBSCRIPTION_STRIPE_FEATURE);
|
|
89
89
|
}
|
|
90
|
-
if (options.billing.
|
|
91
|
-
rejectDoubleMount(mounted, "billing.
|
|
90
|
+
if (options.billing.paddle) {
|
|
91
|
+
rejectDoubleMount(mounted, "billing.paddle", SUBSCRIPTION_PADDLE_FEATURE);
|
|
92
92
|
}
|
|
93
93
|
const billing = resolveBillingOption(options.billing, envSource);
|
|
94
94
|
features.push(...billing.features);
|
|
@@ -23,7 +23,7 @@ const OPTION_CHECKS = {
|
|
|
23
23
|
},
|
|
24
24
|
billing: {
|
|
25
25
|
isSatisfied: (options, mounted) => options.billing !== undefined || mountsExtension(mounted, SUBSCRIPTION_PROVIDER_EXTENSION),
|
|
26
|
-
hint: "set billing: { stripe: { priceToTier }, defaultTier } (or
|
|
26
|
+
hint: "set billing: { stripe: { priceToTier }, defaultTier } (or paddle)",
|
|
27
27
|
},
|
|
28
28
|
featureToggles: {
|
|
29
29
|
isSatisfied: (options) => options.featureToggles === true,
|
package/dist/run-prod-app.d.ts
CHANGED
|
@@ -395,7 +395,7 @@ export type RunProdAppOptions = {
|
|
|
395
395
|
* @example
|
|
396
396
|
* fileStorage: { provider: "auto" } */
|
|
397
397
|
readonly fileStorage?: FileStorageBootOption;
|
|
398
|
-
/** Billing: `subscription-stripe` and/or `subscription-
|
|
398
|
+
/** Billing: `subscription-stripe` and/or `subscription-paddle` plus one tier-syncing webhook
|
|
399
399
|
* route. Needs `billing-foundation` and `tier-engine`. See `BillingBootOption`.
|
|
400
400
|
* @example
|
|
401
401
|
* billing: { stripe: { priceToTier: { [env.STRIPE_PRICE_PRO]: "pro" } }, defaultTier: "free" } */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-server-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.395.0",
|
|
4
4
|
"description": "Production server-boot runtime for Kumiko apps: connections, schema-drift-gate, seeds, lifecycle, graceful shutdown. Symmetric to kumiko-dev-server's runDevApp, without dev/scaffold tooling.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -96,11 +96,11 @@
|
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"dependencies": {
|
|
99
|
-
"@cosmicdrift/kumiko-bundled-features": "0.
|
|
100
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
101
|
-
"@cosmicdrift/kumiko-renderer": "0.
|
|
102
|
-
"@cosmicdrift/kumiko-renderer-mail-html": "0.
|
|
103
|
-
"@cosmicdrift/kumiko-types": "0.
|
|
99
|
+
"@cosmicdrift/kumiko-bundled-features": "0.395.0",
|
|
100
|
+
"@cosmicdrift/kumiko-framework": "0.395.0",
|
|
101
|
+
"@cosmicdrift/kumiko-renderer": "0.395.0",
|
|
102
|
+
"@cosmicdrift/kumiko-renderer-mail-html": "0.395.0",
|
|
103
|
+
"@cosmicdrift/kumiko-types": "0.395.0",
|
|
104
104
|
"ioredis": "^5.10.1",
|
|
105
105
|
"temporal-polyfill": "^0.3.2",
|
|
106
106
|
"zod": "^4.6.7"
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
"bun-types": "^1.4.4"
|
|
110
110
|
},
|
|
111
111
|
"devDependencies": {
|
|
112
|
-
"@cosmicdrift/kumiko-testing": "0.
|
|
112
|
+
"@cosmicdrift/kumiko-testing": "0.395.0",
|
|
113
113
|
"bun-types": "^1.4.4"
|
|
114
114
|
},
|
|
115
115
|
"publishConfig": {
|