@shware/purchase 7.6.0 → 8.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.
- package/README.md +25 -14
- package/dist/app-store/config.cjs +24 -3
- package/dist/app-store/config.cjs.map +1 -1
- package/dist/app-store/config.d.cts +14 -2
- package/dist/app-store/config.d.cts.map +1 -1
- package/dist/app-store/config.d.mts +14 -2
- package/dist/app-store/config.d.mts.map +1 -1
- package/dist/app-store/config.mjs +24 -4
- package/dist/app-store/config.mjs.map +1 -1
- package/dist/app-store/index.cjs +1 -0
- package/dist/app-store/index.d.cts +2 -2
- package/dist/app-store/index.d.mts +2 -2
- package/dist/app-store/index.mjs +2 -2
- package/dist/catalog.cjs +22 -0
- package/dist/catalog.cjs.map +1 -0
- package/dist/catalog.d.cts +21 -0
- package/dist/catalog.d.cts.map +1 -0
- package/dist/catalog.d.mts +21 -0
- package/dist/catalog.d.mts.map +1 -0
- package/dist/catalog.mjs +19 -0
- package/dist/catalog.mjs.map +1 -0
- package/dist/google-play/config.cjs +23 -3
- package/dist/google-play/config.cjs.map +1 -1
- package/dist/google-play/config.d.cts +14 -2
- package/dist/google-play/config.d.cts.map +1 -1
- package/dist/google-play/config.d.mts +14 -2
- package/dist/google-play/config.d.mts.map +1 -1
- package/dist/google-play/config.mjs +23 -4
- package/dist/google-play/config.mjs.map +1 -1
- package/dist/google-play/index.cjs +1 -0
- package/dist/google-play/index.d.cts +2 -2
- package/dist/google-play/index.d.mts +2 -2
- package/dist/google-play/index.mjs +2 -2
- package/dist/index.cjs +3 -0
- package/dist/index.d.cts +4 -4
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +4 -4
- package/dist/stripe/config.cjs +41 -4
- package/dist/stripe/config.cjs.map +1 -1
- package/dist/stripe/config.d.cts +30 -2
- package/dist/stripe/config.d.cts.map +1 -1
- package/dist/stripe/config.d.mts +30 -2
- package/dist/stripe/config.d.mts.map +1 -1
- package/dist/stripe/config.mjs +41 -5
- package/dist/stripe/config.mjs.map +1 -1
- package/dist/stripe/index.cjs +5 -0
- package/dist/stripe/index.d.cts +3 -2
- package/dist/stripe/index.d.mts +3 -2
- package/dist/stripe/index.mjs +3 -2
- package/dist/stripe/plan-change.cjs +400 -0
- package/dist/stripe/plan-change.cjs.map +1 -0
- package/dist/stripe/plan-change.d.cts +142 -0
- package/dist/stripe/plan-change.d.cts.map +1 -0
- package/dist/stripe/plan-change.d.mts +142 -0
- package/dist/stripe/plan-change.d.mts.map +1 -0
- package/dist/stripe/plan-change.mjs +397 -0
- package/dist/stripe/plan-change.mjs.map +1 -0
- package/package.json +2 -2
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
3
|
+
const require_catalog = require("../catalog.cjs");
|
|
3
4
|
let _shware_utils = require("@shware/utils");
|
|
4
5
|
let ms = require("ms");
|
|
5
6
|
ms = require_runtime.__toESM(ms, 1);
|
|
6
7
|
//#region src/google-play/config.ts
|
|
7
8
|
const addMethod = Symbol("addMethod");
|
|
9
|
+
/** The private constructor's one door, for this module's `define` function only. */
|
|
10
|
+
const construct = Symbol("construct");
|
|
8
11
|
var Subscription = class {
|
|
9
12
|
productId;
|
|
10
13
|
config;
|
|
@@ -25,6 +28,7 @@ var Subscription = class {
|
|
|
25
28
|
credits: 0,
|
|
26
29
|
expiresIn: "0"
|
|
27
30
|
}) => {
|
|
31
|
+
require_catalog.assertDeclared(this.config, plan, billingPeriod);
|
|
28
32
|
(0, _shware_utils.invariant)(!this.plans.has(planId), `Duplicate base plan ${planId}`);
|
|
29
33
|
this.plans.set(planId, {
|
|
30
34
|
...metadata,
|
|
@@ -45,6 +49,9 @@ var Subscription = class {
|
|
|
45
49
|
var GooglePlayConfig = class GooglePlayConfig {
|
|
46
50
|
package;
|
|
47
51
|
audience;
|
|
52
|
+
namespace;
|
|
53
|
+
plans;
|
|
54
|
+
billingPeriods;
|
|
48
55
|
onetimes;
|
|
49
56
|
subscriptions;
|
|
50
57
|
products;
|
|
@@ -62,22 +69,26 @@ var GooglePlayConfig = class GooglePlayConfig {
|
|
|
62
69
|
return planId ? `${productId}:${planId}` : productId;
|
|
63
70
|
};
|
|
64
71
|
constructor(options) {
|
|
72
|
+
require_catalog.assertCatalog(options);
|
|
73
|
+
this.namespace = options.namespace;
|
|
74
|
+
this.plans = options.plans;
|
|
75
|
+
this.billingPeriods = options.billingPeriods;
|
|
65
76
|
this.package = options.package;
|
|
66
77
|
this.audience = options.audience;
|
|
67
78
|
this.products = /* @__PURE__ */ new Map();
|
|
68
79
|
this.onetimes = /* @__PURE__ */ new Set();
|
|
69
80
|
this.subscriptions = /* @__PURE__ */ new Map();
|
|
70
81
|
}
|
|
71
|
-
static
|
|
72
|
-
return new GooglePlayConfig(options);
|
|
73
|
-
};
|
|
82
|
+
static [construct] = (options) => new GooglePlayConfig(options);
|
|
74
83
|
subscription = (productId) => {
|
|
84
|
+
require_catalog.assertInNamespace(this.namespace, productId);
|
|
75
85
|
return new Subscription(this, productId);
|
|
76
86
|
};
|
|
77
87
|
onetime = (productId, metadata = {
|
|
78
88
|
credits: 0,
|
|
79
89
|
expiresIn: "0"
|
|
80
90
|
}) => {
|
|
91
|
+
require_catalog.assertInNamespace(this.namespace, productId);
|
|
81
92
|
(0, _shware_utils.invariant)(!this.products.has(productId), `Duplicate product ${productId}`);
|
|
82
93
|
this.onetimes.add(productId);
|
|
83
94
|
this.products.set(productId, metadata);
|
|
@@ -125,7 +136,16 @@ var GooglePlayConfig = class GooglePlayConfig {
|
|
|
125
136
|
return new Date(Date.now() + expiresIn).toISOString();
|
|
126
137
|
};
|
|
127
138
|
};
|
|
139
|
+
/**
|
|
140
|
+
* Declare the GooglePlay product catalog. Every type parameter is inferred from the options:
|
|
141
|
+
* the namespace from `namespace`, the plans and billing periods from `plans` and `billingPeriods`
|
|
142
|
+
* (`const`, so a literal array needs no `as const`). Products are then added with the fluent chain.
|
|
143
|
+
*/
|
|
144
|
+
function defineGooglePlayConfig(options) {
|
|
145
|
+
return GooglePlayConfig[construct](options);
|
|
146
|
+
}
|
|
128
147
|
//#endregion
|
|
129
148
|
exports.GooglePlayConfig = GooglePlayConfig;
|
|
149
|
+
exports.defineGooglePlayConfig = defineGooglePlayConfig;
|
|
130
150
|
|
|
131
151
|
//# sourceMappingURL=config.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.cjs","names":[],"sources":["../../src/google-play/config.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport ms from 'ms';\nimport type { IsUnique, Metadata } from '../types';\n\nconst addMethod = Symbol('addMethod');\n\nclass Subscription<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PI extends string = never,\n I extends Lowercase<string> = never,\n> {\n readonly productId: string;\n readonly config: GooglePlayConfig<NS, PE, BP, PI>;\n readonly plans: Map<string, Metadata & { plan?: PE; billingPeriod?: BP }>;\n readonly defaultPlans: Set<string>;\n\n constructor(config: GooglePlayConfig<NS, PE, BP, PI>, productId: string) {\n this.config = config;\n this.productId = productId;\n this.plans = new Map();\n this.defaultPlans = new Set();\n }\n\n /**\n * Non-default base plans stay declared on purpose: they keep resolving for\n * grandfathered subscribers and serve as price-experiment arms. Never sell\n * a legacy base plan to new users unless that is intentional.\n */\n basePlan = <K extends Lowercase<string>>(\n planId: K extends I ? never : K,\n plan: PE,\n billingPeriod: BP,\n metadata: Metadata = { credits: 0, expiresIn: '0' }\n ): Subscription<NS, PE, BP, PI, I | K> => {\n invariant(!this.plans.has(planId), `Duplicate base plan ${planId}`);\n this.plans.set(planId, { ...metadata, plan, billingPeriod });\n return this;\n };\n\n default = <const T extends readonly [I, ...I[]]>(\n planIds: T & (IsUnique<T> extends true ? unknown : never)\n ) => {\n planIds.forEach((planId) => {\n invariant(this.plans.has(planId), `Default base plan ${planId} is not declared`);\n this.defaultPlans.add(planId);\n });\n this.config[addMethod](this);\n return this.config;\n };\n}\n\ntype Options = { package: string; audience: string };\n\nexport class GooglePlayConfig<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PI extends string = never,\n> {\n readonly package: string;\n readonly audience: string;\n private readonly onetimes: Set<string>;\n private readonly subscriptions: Map<string, Subscription<NS, PE, BP, PI>>;\n private readonly products: Map<string, (Metadata & { plan?: PE; billingPeriod?: BP }) | null>;\n\n // runtime mirror of the type-level guards: generic accumulation only\n // protects a single fluent chain, not statement-style re-entry or casts\n [addMethod] = (subscription: Subscription<NS, PE, BP, PI>) => {\n invariant(\n !this.subscriptions.has(subscription.productId),\n `Duplicate subscription ${subscription.productId}`\n );\n subscription.plans.forEach((metadata, planId) => {\n const id = this.getId(subscription.productId, planId);\n invariant(!this.products.has(id), `Duplicate product ${id}`);\n this.products.set(id, metadata);\n });\n this.subscriptions.set(subscription.productId, subscription);\n return this;\n };\n\n private readonly getId = (productId: string, planId?: string) => {\n return planId ? `${productId}:${planId}` : productId;\n };\n\n private constructor(options: Options) {\n this.package = options.package;\n this.audience = options.audience;\n this.products = new Map();\n this.onetimes = new Set();\n this.subscriptions = new Map();\n }\n\n static create = <\n NS extends Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n >(\n options: Options\n ) => {\n return new GooglePlayConfig<NS, PE, BP>(options);\n };\n\n subscription = <K extends `${NS}.${Lowercase<string>}`>(productId: K extends PI ? never : K) => {\n return new Subscription<NS, PE, BP, PI | K>(this, productId);\n };\n\n onetime = <K extends `${NS}.${Lowercase<string>}`>(\n productId: K extends PI ? never : K,\n metadata: Metadata = { credits: 0, expiresIn: '0' }\n ) => {\n invariant(!this.products.has(productId), `Duplicate product ${productId}`);\n this.onetimes.add(productId);\n this.products.set(productId, metadata);\n return this as GooglePlayConfig<NS, PE, BP, PI | K>;\n };\n\n /** Base plan ids that new subscribers should purchase for the product. */\n getDefaultPlanIds = (productId: string): string[] => {\n const subscription = this.subscriptions.get(productId);\n invariant(subscription, `Subscription not found for ${productId}`);\n return Array.from(subscription.defaultPlans);\n };\n\n getPlan = (productId: string, planId: string): PE => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n invariant(metadata.plan, `Plan not found for ${id}`);\n return metadata.plan;\n };\n\n getBillingPeriod = (productId: string, planId: string): BP => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n invariant(metadata.billingPeriod, `Billing period not found for ${id}`);\n return metadata.billingPeriod;\n };\n\n getMode = (productId: string): 'payment' | 'subscription' => {\n if (this.onetimes.has(productId)) return 'payment';\n if (this.subscriptions.has(productId)) return 'subscription';\n throw new Error(`Mode not found for product ${productId}`);\n };\n\n getCreditAmount = (productId: string, planId?: string): number => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n return metadata.credits;\n };\n\n private readonly getCreditExpiresIn = (productId: string, planId?: string): number => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n return ms(metadata.expiresIn);\n };\n\n getCreditExpiresAt = (productId: string, planId?: string): string => {\n const expiresIn = this.getCreditExpiresIn(productId, planId);\n return new Date(Date.now() + expiresIn).toISOString();\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.cjs","names":[],"sources":["../../src/google-play/config.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport ms from 'ms';\nimport { type Catalog, assertCatalog, assertDeclared, assertInNamespace } from '../catalog';\nimport type { IsUnique, Metadata } from '../types';\n\nconst addMethod = Symbol('addMethod');\n/** The private constructor's one door, for this module's `define` function only. */\nconst construct = Symbol('construct');\n\nclass Subscription<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PI extends string = never,\n I extends Lowercase<string> = never,\n> {\n readonly productId: string;\n readonly config: GooglePlayConfig<NS, PE, BP, PI>;\n readonly plans: Map<string, Metadata & { plan?: PE; billingPeriod?: BP }>;\n readonly defaultPlans: Set<string>;\n\n constructor(config: GooglePlayConfig<NS, PE, BP, PI>, productId: string) {\n this.config = config;\n this.productId = productId;\n this.plans = new Map();\n this.defaultPlans = new Set();\n }\n\n /**\n * Non-default base plans stay declared on purpose: they keep resolving for\n * grandfathered subscribers and serve as price-experiment arms. Never sell\n * a legacy base plan to new users unless that is intentional.\n */\n basePlan = <K extends Lowercase<string>>(\n planId: K extends I ? never : K,\n plan: PE,\n billingPeriod: BP,\n metadata: Metadata = { credits: 0, expiresIn: '0' }\n ): Subscription<NS, PE, BP, PI, I | K> => {\n assertDeclared(this.config, plan, billingPeriod);\n invariant(!this.plans.has(planId), `Duplicate base plan ${planId}`);\n this.plans.set(planId, { ...metadata, plan, billingPeriod });\n return this;\n };\n\n default = <const T extends readonly [I, ...I[]]>(\n planIds: T & (IsUnique<T> extends true ? unknown : never)\n ) => {\n planIds.forEach((planId) => {\n invariant(this.plans.has(planId), `Default base plan ${planId} is not declared`);\n this.defaultPlans.add(planId);\n });\n this.config[addMethod](this);\n return this.config;\n };\n}\n\ntype Options<NS extends Lowercase<string>, PE extends string, BP extends string> = Catalog<\n NS,\n PE,\n BP\n> & { package: string; audience: string };\n\nexport class GooglePlayConfig<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PI extends string = never,\n> {\n readonly package: string;\n readonly audience: string;\n readonly namespace: NS;\n readonly plans: readonly PE[];\n readonly billingPeriods: readonly BP[];\n private readonly onetimes: Set<string>;\n private readonly subscriptions: Map<string, Subscription<NS, PE, BP, PI>>;\n private readonly products: Map<string, (Metadata & { plan?: PE; billingPeriod?: BP }) | null>;\n\n // runtime mirror of the type-level guards: generic accumulation only\n // protects a single fluent chain, not statement-style re-entry or casts\n [addMethod] = (subscription: Subscription<NS, PE, BP, PI>) => {\n invariant(\n !this.subscriptions.has(subscription.productId),\n `Duplicate subscription ${subscription.productId}`\n );\n subscription.plans.forEach((metadata, planId) => {\n const id = this.getId(subscription.productId, planId);\n invariant(!this.products.has(id), `Duplicate product ${id}`);\n this.products.set(id, metadata);\n });\n this.subscriptions.set(subscription.productId, subscription);\n return this;\n };\n\n private readonly getId = (productId: string, planId?: string) => {\n return planId ? `${productId}:${planId}` : productId;\n };\n\n private constructor(options: Options<NS, PE, BP>) {\n assertCatalog(options);\n this.namespace = options.namespace;\n this.plans = options.plans;\n this.billingPeriods = options.billingPeriods;\n this.package = options.package;\n this.audience = options.audience;\n this.products = new Map();\n this.onetimes = new Set();\n this.subscriptions = new Map();\n }\n\n static [construct] = <NS extends Lowercase<string>, PE extends string, BP extends string>(\n options: Options<NS, PE, BP>\n ) => new GooglePlayConfig<NS, PE, BP>(options);\n\n subscription = <K extends `${NS}.${Lowercase<string>}`>(productId: K extends PI ? never : K) => {\n assertInNamespace(this.namespace, productId);\n return new Subscription<NS, PE, BP, PI | K>(this, productId);\n };\n\n onetime = <K extends `${NS}.${Lowercase<string>}`>(\n productId: K extends PI ? never : K,\n metadata: Metadata = { credits: 0, expiresIn: '0' }\n ) => {\n assertInNamespace(this.namespace, productId);\n invariant(!this.products.has(productId), `Duplicate product ${productId}`);\n this.onetimes.add(productId);\n this.products.set(productId, metadata);\n return this as GooglePlayConfig<NS, PE, BP, PI | K>;\n };\n\n /** Base plan ids that new subscribers should purchase for the product. */\n getDefaultPlanIds = (productId: string): string[] => {\n const subscription = this.subscriptions.get(productId);\n invariant(subscription, `Subscription not found for ${productId}`);\n return Array.from(subscription.defaultPlans);\n };\n\n getPlan = (productId: string, planId: string): PE => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n invariant(metadata.plan, `Plan not found for ${id}`);\n return metadata.plan;\n };\n\n getBillingPeriod = (productId: string, planId: string): BP => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n invariant(metadata.billingPeriod, `Billing period not found for ${id}`);\n return metadata.billingPeriod;\n };\n\n getMode = (productId: string): 'payment' | 'subscription' => {\n if (this.onetimes.has(productId)) return 'payment';\n if (this.subscriptions.has(productId)) return 'subscription';\n throw new Error(`Mode not found for product ${productId}`);\n };\n\n getCreditAmount = (productId: string, planId?: string): number => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n return metadata.credits;\n };\n\n private readonly getCreditExpiresIn = (productId: string, planId?: string): number => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n return ms(metadata.expiresIn);\n };\n\n getCreditExpiresAt = (productId: string, planId?: string): string => {\n const expiresIn = this.getCreditExpiresIn(productId, planId);\n return new Date(Date.now() + expiresIn).toISOString();\n };\n}\n\n/**\n * Declare the GooglePlay product catalog. Every type parameter is inferred from the options:\n * the namespace from `namespace`, the plans and billing periods from `plans` and `billingPeriods`\n * (`const`, so a literal array needs no `as const`). Products are then added with the fluent chain.\n */\nexport function defineGooglePlayConfig<\n const NS extends Lowercase<string>,\n const PE extends string,\n const BP extends string,\n>(options: Options<NS, PE, BP>): GooglePlayConfig<NS, PE, BP> {\n return GooglePlayConfig[construct](options);\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { Catalog } from "../catalog.cjs";
|
|
1
2
|
import { IsUnique, Metadata } from "../types.cjs";
|
|
2
3
|
//#region src/google-play/config.d.ts
|
|
3
4
|
declare const addMethod: unique symbol;
|
|
5
|
+
/** The private constructor's one door, for this module's `define` function only. */
|
|
6
|
+
declare const construct: unique symbol;
|
|
4
7
|
declare class Subscription<NS extends Lowercase<string> = Lowercase<string>, PE extends string = string, BP extends string = string, PI extends string = never, I extends Lowercase<string> = never> {
|
|
5
8
|
readonly productId: string;
|
|
6
9
|
readonly config: GooglePlayConfig<NS, PE, BP, PI>;
|
|
@@ -18,20 +21,23 @@ declare class Subscription<NS extends Lowercase<string> = Lowercase<string>, PE
|
|
|
18
21
|
basePlan: <K extends Lowercase<string>>(planId: K extends I ? never : K, plan: PE, billingPeriod: BP, metadata?: Metadata) => Subscription<NS, PE, BP, PI, I | K>;
|
|
19
22
|
default: <const T extends readonly [I, ...I[]]>(planIds: T & (IsUnique<T> extends true ? unknown : never)) => GooglePlayConfig<NS, PE, BP, PI>;
|
|
20
23
|
}
|
|
21
|
-
type Options = {
|
|
24
|
+
type Options<NS extends Lowercase<string>, PE extends string, BP extends string> = Catalog<NS, PE, BP> & {
|
|
22
25
|
package: string;
|
|
23
26
|
audience: string;
|
|
24
27
|
};
|
|
25
28
|
export declare class GooglePlayConfig<NS extends Lowercase<string> = Lowercase<string>, PE extends string = string, BP extends string = string, PI extends string = never> {
|
|
26
29
|
readonly package: string;
|
|
27
30
|
readonly audience: string;
|
|
31
|
+
readonly namespace: NS;
|
|
32
|
+
readonly plans: readonly PE[];
|
|
33
|
+
readonly billingPeriods: readonly BP[];
|
|
28
34
|
private readonly onetimes;
|
|
29
35
|
private readonly subscriptions;
|
|
30
36
|
private readonly products;
|
|
31
37
|
[addMethod]: (subscription: Subscription<NS, PE, BP, PI>) => this;
|
|
32
38
|
private readonly getId;
|
|
33
39
|
private constructor();
|
|
34
|
-
static
|
|
40
|
+
static [construct]: <NS_1 extends Lowercase<string>, PE_1 extends string, BP_1 extends string>(options: Options<NS_1, PE_1, BP_1>) => GooglePlayConfig<NS_1, PE_1, BP_1, never>;
|
|
35
41
|
subscription: <K extends `${NS}.${Lowercase<string>}`>(productId: K extends PI ? never : K) => Subscription<NS, PE, BP, K | PI, never>;
|
|
36
42
|
onetime: <K extends `${NS}.${Lowercase<string>}`>(productId: K extends PI ? never : K, metadata?: Metadata) => GooglePlayConfig<NS, PE, BP, PI | K>;
|
|
37
43
|
/** Base plan ids that new subscribers should purchase for the product. */
|
|
@@ -43,6 +49,12 @@ export declare class GooglePlayConfig<NS extends Lowercase<string> = Lowercase<s
|
|
|
43
49
|
private readonly getCreditExpiresIn;
|
|
44
50
|
getCreditExpiresAt: (productId: string, planId?: string) => string;
|
|
45
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Declare the GooglePlay product catalog. Every type parameter is inferred from the options:
|
|
54
|
+
* the namespace from `namespace`, the plans and billing periods from `plans` and `billingPeriods`
|
|
55
|
+
* (`const`, so a literal array needs no `as const`). Products are then added with the fluent chain.
|
|
56
|
+
*/
|
|
57
|
+
export declare function defineGooglePlayConfig<const NS extends Lowercase<string>, const PE extends string, const BP extends string>(options: Options<NS, PE, BP>): GooglePlayConfig<NS, PE, BP>;
|
|
46
58
|
//#endregion
|
|
47
59
|
export {};
|
|
48
60
|
//# sourceMappingURL=config.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.cts","names":[],"sources":["../../src/google-play/config.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"config.d.cts","names":[],"sources":["../../src/google-play/config.ts"],"mappings":";;;cAKM;;cAEA;cAEA,aACJ,WAAW,oBAAoB,mBAC/B,4BACA,4BACA,2BACA,UAAU;WAED;WACA,QAAQ,iBAAiB,IAAI,IAAI,IAAI;WACrC,OAAO,YAAY;IAAa,OAAO;IAAI,gBAAgB;;WAC3D,cAAc;EAEvB,YAAY,QAAQ,iBAAiB,IAAI,IAAI,IAAI,KAAK;;;;;;EAYtD,WAAY,UAAU,mBAAiB,QAC7B,UAAU,YAAY,GAAC,MACzB,IAAE,eACO,IAAE,WACP,aACT,aAAa,IAAI,IAAI,IAAI,IAAI,IAAI;EAOpC,gBAAiB,oBAAoB,MAAM,MAAI,SACpC,KAAK,SAAS,uCAAkC,iBAAA,IAAA,IAAA,IAAA;;KAWxD,QAAQ,WAAW,mBAAmB,mBAAmB,qBAAqB,QACjF,IACA,IACA;EACI;EAAiB;;qBAEV,iBACX,WAAW,oBAAoB,mBAC/B,4BACA,4BACA;WAES;WACA;WACA,WAAW;WACX,gBAAgB;WAChB,yBAAyB;mBACjB;mBACA;mBACA;GAIhB,aAAU,cAAkB,aAAa,IAAI,IAAI,IAAI;mBAcrC;UAIV;UAYC,aAAc,aAAW,mBAAmB,qBAAmB,qBAAiB,SAC7E,QAAQ,MAAI,MAAI,UAAG,iBAAA,MAAA,MAAA;EAG9B,eAAgB,aAAa,MAAM,qBAAmB,WAAa,UAAU,aAAa,MAAC,aAAA,IAAA,IAAA,IAAA,IAAA;EAK3F,UAAW,aAAa,MAAM,qBAAmB,WACpC,UAAU,aAAa,GAAC,WACzB,aAMK,iBAAiB,IAAI,IAAI,IAAI,KAAK;;EAInD,oBAAiB;EAMjB,UAAO,mBAAqB,mBAAmB;EAQ/C,mBAAgB,mBAAqB,mBAAmB;EAQxD,UAAO;EAMP,kBAAe,mBAAqB;mBAOnB;EAOjB,qBAAkB,mBAAqB;;;;;;;wBAWzB,6BACR,WAAW,yBACX,yBACA,mBACN,SAAS,QAAQ,IAAI,IAAI,MAAM,iBAAiB,IAAI,IAAI"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { Catalog } from "../catalog.mjs";
|
|
1
2
|
import { IsUnique, Metadata } from "../types.mjs";
|
|
2
3
|
//#region src/google-play/config.d.ts
|
|
3
4
|
declare const addMethod: unique symbol;
|
|
5
|
+
/** The private constructor's one door, for this module's `define` function only. */
|
|
6
|
+
declare const construct: unique symbol;
|
|
4
7
|
declare class Subscription<NS extends Lowercase<string> = Lowercase<string>, PE extends string = string, BP extends string = string, PI extends string = never, I extends Lowercase<string> = never> {
|
|
5
8
|
readonly productId: string;
|
|
6
9
|
readonly config: GooglePlayConfig<NS, PE, BP, PI>;
|
|
@@ -18,20 +21,23 @@ declare class Subscription<NS extends Lowercase<string> = Lowercase<string>, PE
|
|
|
18
21
|
basePlan: <K extends Lowercase<string>>(planId: K extends I ? never : K, plan: PE, billingPeriod: BP, metadata?: Metadata) => Subscription<NS, PE, BP, PI, I | K>;
|
|
19
22
|
default: <const T extends readonly [I, ...I[]]>(planIds: T & (IsUnique<T> extends true ? unknown : never)) => GooglePlayConfig<NS, PE, BP, PI>;
|
|
20
23
|
}
|
|
21
|
-
type Options = {
|
|
24
|
+
type Options<NS extends Lowercase<string>, PE extends string, BP extends string> = Catalog<NS, PE, BP> & {
|
|
22
25
|
package: string;
|
|
23
26
|
audience: string;
|
|
24
27
|
};
|
|
25
28
|
export declare class GooglePlayConfig<NS extends Lowercase<string> = Lowercase<string>, PE extends string = string, BP extends string = string, PI extends string = never> {
|
|
26
29
|
readonly package: string;
|
|
27
30
|
readonly audience: string;
|
|
31
|
+
readonly namespace: NS;
|
|
32
|
+
readonly plans: readonly PE[];
|
|
33
|
+
readonly billingPeriods: readonly BP[];
|
|
28
34
|
private readonly onetimes;
|
|
29
35
|
private readonly subscriptions;
|
|
30
36
|
private readonly products;
|
|
31
37
|
[addMethod]: (subscription: Subscription<NS, PE, BP, PI>) => this;
|
|
32
38
|
private readonly getId;
|
|
33
39
|
private constructor();
|
|
34
|
-
static
|
|
40
|
+
static [construct]: <NS_1 extends Lowercase<string>, PE_1 extends string, BP_1 extends string>(options: Options<NS_1, PE_1, BP_1>) => GooglePlayConfig<NS_1, PE_1, BP_1, never>;
|
|
35
41
|
subscription: <K extends `${NS}.${Lowercase<string>}`>(productId: K extends PI ? never : K) => Subscription<NS, PE, BP, K | PI, never>;
|
|
36
42
|
onetime: <K extends `${NS}.${Lowercase<string>}`>(productId: K extends PI ? never : K, metadata?: Metadata) => GooglePlayConfig<NS, PE, BP, PI | K>;
|
|
37
43
|
/** Base plan ids that new subscribers should purchase for the product. */
|
|
@@ -43,6 +49,12 @@ export declare class GooglePlayConfig<NS extends Lowercase<string> = Lowercase<s
|
|
|
43
49
|
private readonly getCreditExpiresIn;
|
|
44
50
|
getCreditExpiresAt: (productId: string, planId?: string) => string;
|
|
45
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Declare the GooglePlay product catalog. Every type parameter is inferred from the options:
|
|
54
|
+
* the namespace from `namespace`, the plans and billing periods from `plans` and `billingPeriods`
|
|
55
|
+
* (`const`, so a literal array needs no `as const`). Products are then added with the fluent chain.
|
|
56
|
+
*/
|
|
57
|
+
export declare function defineGooglePlayConfig<const NS extends Lowercase<string>, const PE extends string, const BP extends string>(options: Options<NS, PE, BP>): GooglePlayConfig<NS, PE, BP>;
|
|
46
58
|
//#endregion
|
|
47
59
|
export {};
|
|
48
60
|
//# sourceMappingURL=config.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.mts","names":[],"sources":["../../src/google-play/config.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"config.d.mts","names":[],"sources":["../../src/google-play/config.ts"],"mappings":";;;cAKM;;cAEA;cAEA,aACJ,WAAW,oBAAoB,mBAC/B,4BACA,4BACA,2BACA,UAAU;WAED;WACA,QAAQ,iBAAiB,IAAI,IAAI,IAAI;WACrC,OAAO,YAAY;IAAa,OAAO;IAAI,gBAAgB;;WAC3D,cAAc;EAEvB,YAAY,QAAQ,iBAAiB,IAAI,IAAI,IAAI,KAAK;;;;;;EAYtD,WAAY,UAAU,mBAAiB,QAC7B,UAAU,YAAY,GAAC,MACzB,IAAE,eACO,IAAE,WACP,aACT,aAAa,IAAI,IAAI,IAAI,IAAI,IAAI;EAOpC,gBAAiB,oBAAoB,MAAM,MAAI,SACpC,KAAK,SAAS,uCAAkC,iBAAA,IAAA,IAAA,IAAA;;KAWxD,QAAQ,WAAW,mBAAmB,mBAAmB,qBAAqB,QACjF,IACA,IACA;EACI;EAAiB;;qBAEV,iBACX,WAAW,oBAAoB,mBAC/B,4BACA,4BACA;WAES;WACA;WACA,WAAW;WACX,gBAAgB;WAChB,yBAAyB;mBACjB;mBACA;mBACA;GAIhB,aAAU,cAAkB,aAAa,IAAI,IAAI,IAAI;mBAcrC;UAIV;UAYC,aAAc,aAAW,mBAAmB,qBAAmB,qBAAiB,SAC7E,QAAQ,MAAI,MAAI,UAAG,iBAAA,MAAA,MAAA;EAG9B,eAAgB,aAAa,MAAM,qBAAmB,WAAa,UAAU,aAAa,MAAC,aAAA,IAAA,IAAA,IAAA,IAAA;EAK3F,UAAW,aAAa,MAAM,qBAAmB,WACpC,UAAU,aAAa,GAAC,WACzB,aAMK,iBAAiB,IAAI,IAAI,IAAI,KAAK;;EAInD,oBAAiB;EAMjB,UAAO,mBAAqB,mBAAmB;EAQ/C,mBAAgB,mBAAqB,mBAAmB;EAQxD,UAAO;EAMP,kBAAe,mBAAqB;mBAOnB;EAOjB,qBAAkB,mBAAqB;;;;;;;wBAWzB,6BACR,WAAW,yBACX,yBACA,mBACN,SAAS,QAAQ,IAAI,IAAI,MAAM,iBAAiB,IAAI,IAAI"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { assertCatalog, assertDeclared, assertInNamespace } from "../catalog.mjs";
|
|
1
2
|
import { invariant } from "@shware/utils";
|
|
2
3
|
import ms from "ms";
|
|
3
4
|
//#region src/google-play/config.ts
|
|
4
5
|
const addMethod = Symbol("addMethod");
|
|
6
|
+
/** The private constructor's one door, for this module's `define` function only. */
|
|
7
|
+
const construct = Symbol("construct");
|
|
5
8
|
var Subscription = class {
|
|
6
9
|
productId;
|
|
7
10
|
config;
|
|
@@ -22,6 +25,7 @@ var Subscription = class {
|
|
|
22
25
|
credits: 0,
|
|
23
26
|
expiresIn: "0"
|
|
24
27
|
}) => {
|
|
28
|
+
assertDeclared(this.config, plan, billingPeriod);
|
|
25
29
|
invariant(!this.plans.has(planId), `Duplicate base plan ${planId}`);
|
|
26
30
|
this.plans.set(planId, {
|
|
27
31
|
...metadata,
|
|
@@ -42,6 +46,9 @@ var Subscription = class {
|
|
|
42
46
|
var GooglePlayConfig = class GooglePlayConfig {
|
|
43
47
|
package;
|
|
44
48
|
audience;
|
|
49
|
+
namespace;
|
|
50
|
+
plans;
|
|
51
|
+
billingPeriods;
|
|
45
52
|
onetimes;
|
|
46
53
|
subscriptions;
|
|
47
54
|
products;
|
|
@@ -59,22 +66,26 @@ var GooglePlayConfig = class GooglePlayConfig {
|
|
|
59
66
|
return planId ? `${productId}:${planId}` : productId;
|
|
60
67
|
};
|
|
61
68
|
constructor(options) {
|
|
69
|
+
assertCatalog(options);
|
|
70
|
+
this.namespace = options.namespace;
|
|
71
|
+
this.plans = options.plans;
|
|
72
|
+
this.billingPeriods = options.billingPeriods;
|
|
62
73
|
this.package = options.package;
|
|
63
74
|
this.audience = options.audience;
|
|
64
75
|
this.products = /* @__PURE__ */ new Map();
|
|
65
76
|
this.onetimes = /* @__PURE__ */ new Set();
|
|
66
77
|
this.subscriptions = /* @__PURE__ */ new Map();
|
|
67
78
|
}
|
|
68
|
-
static
|
|
69
|
-
return new GooglePlayConfig(options);
|
|
70
|
-
};
|
|
79
|
+
static [construct] = (options) => new GooglePlayConfig(options);
|
|
71
80
|
subscription = (productId) => {
|
|
81
|
+
assertInNamespace(this.namespace, productId);
|
|
72
82
|
return new Subscription(this, productId);
|
|
73
83
|
};
|
|
74
84
|
onetime = (productId, metadata = {
|
|
75
85
|
credits: 0,
|
|
76
86
|
expiresIn: "0"
|
|
77
87
|
}) => {
|
|
88
|
+
assertInNamespace(this.namespace, productId);
|
|
78
89
|
invariant(!this.products.has(productId), `Duplicate product ${productId}`);
|
|
79
90
|
this.onetimes.add(productId);
|
|
80
91
|
this.products.set(productId, metadata);
|
|
@@ -122,7 +133,15 @@ var GooglePlayConfig = class GooglePlayConfig {
|
|
|
122
133
|
return new Date(Date.now() + expiresIn).toISOString();
|
|
123
134
|
};
|
|
124
135
|
};
|
|
136
|
+
/**
|
|
137
|
+
* Declare the GooglePlay product catalog. Every type parameter is inferred from the options:
|
|
138
|
+
* the namespace from `namespace`, the plans and billing periods from `plans` and `billingPeriods`
|
|
139
|
+
* (`const`, so a literal array needs no `as const`). Products are then added with the fluent chain.
|
|
140
|
+
*/
|
|
141
|
+
function defineGooglePlayConfig(options) {
|
|
142
|
+
return GooglePlayConfig[construct](options);
|
|
143
|
+
}
|
|
125
144
|
//#endregion
|
|
126
|
-
export { GooglePlayConfig };
|
|
145
|
+
export { GooglePlayConfig, defineGooglePlayConfig };
|
|
127
146
|
|
|
128
147
|
//# sourceMappingURL=config.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.mjs","names":[],"sources":["../../src/google-play/config.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport ms from 'ms';\nimport type { IsUnique, Metadata } from '../types';\n\nconst addMethod = Symbol('addMethod');\n\nclass Subscription<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PI extends string = never,\n I extends Lowercase<string> = never,\n> {\n readonly productId: string;\n readonly config: GooglePlayConfig<NS, PE, BP, PI>;\n readonly plans: Map<string, Metadata & { plan?: PE; billingPeriod?: BP }>;\n readonly defaultPlans: Set<string>;\n\n constructor(config: GooglePlayConfig<NS, PE, BP, PI>, productId: string) {\n this.config = config;\n this.productId = productId;\n this.plans = new Map();\n this.defaultPlans = new Set();\n }\n\n /**\n * Non-default base plans stay declared on purpose: they keep resolving for\n * grandfathered subscribers and serve as price-experiment arms. Never sell\n * a legacy base plan to new users unless that is intentional.\n */\n basePlan = <K extends Lowercase<string>>(\n planId: K extends I ? never : K,\n plan: PE,\n billingPeriod: BP,\n metadata: Metadata = { credits: 0, expiresIn: '0' }\n ): Subscription<NS, PE, BP, PI, I | K> => {\n invariant(!this.plans.has(planId), `Duplicate base plan ${planId}`);\n this.plans.set(planId, { ...metadata, plan, billingPeriod });\n return this;\n };\n\n default = <const T extends readonly [I, ...I[]]>(\n planIds: T & (IsUnique<T> extends true ? unknown : never)\n ) => {\n planIds.forEach((planId) => {\n invariant(this.plans.has(planId), `Default base plan ${planId} is not declared`);\n this.defaultPlans.add(planId);\n });\n this.config[addMethod](this);\n return this.config;\n };\n}\n\ntype Options = { package: string; audience: string };\n\nexport class GooglePlayConfig<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PI extends string = never,\n> {\n readonly package: string;\n readonly audience: string;\n private readonly onetimes: Set<string>;\n private readonly subscriptions: Map<string, Subscription<NS, PE, BP, PI>>;\n private readonly products: Map<string, (Metadata & { plan?: PE; billingPeriod?: BP }) | null>;\n\n // runtime mirror of the type-level guards: generic accumulation only\n // protects a single fluent chain, not statement-style re-entry or casts\n [addMethod] = (subscription: Subscription<NS, PE, BP, PI>) => {\n invariant(\n !this.subscriptions.has(subscription.productId),\n `Duplicate subscription ${subscription.productId}`\n );\n subscription.plans.forEach((metadata, planId) => {\n const id = this.getId(subscription.productId, planId);\n invariant(!this.products.has(id), `Duplicate product ${id}`);\n this.products.set(id, metadata);\n });\n this.subscriptions.set(subscription.productId, subscription);\n return this;\n };\n\n private readonly getId = (productId: string, planId?: string) => {\n return planId ? `${productId}:${planId}` : productId;\n };\n\n private constructor(options: Options) {\n this.package = options.package;\n this.audience = options.audience;\n this.products = new Map();\n this.onetimes = new Set();\n this.subscriptions = new Map();\n }\n\n static create = <\n NS extends Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n >(\n options: Options\n ) => {\n return new GooglePlayConfig<NS, PE, BP>(options);\n };\n\n subscription = <K extends `${NS}.${Lowercase<string>}`>(productId: K extends PI ? never : K) => {\n return new Subscription<NS, PE, BP, PI | K>(this, productId);\n };\n\n onetime = <K extends `${NS}.${Lowercase<string>}`>(\n productId: K extends PI ? never : K,\n metadata: Metadata = { credits: 0, expiresIn: '0' }\n ) => {\n invariant(!this.products.has(productId), `Duplicate product ${productId}`);\n this.onetimes.add(productId);\n this.products.set(productId, metadata);\n return this as GooglePlayConfig<NS, PE, BP, PI | K>;\n };\n\n /** Base plan ids that new subscribers should purchase for the product. */\n getDefaultPlanIds = (productId: string): string[] => {\n const subscription = this.subscriptions.get(productId);\n invariant(subscription, `Subscription not found for ${productId}`);\n return Array.from(subscription.defaultPlans);\n };\n\n getPlan = (productId: string, planId: string): PE => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n invariant(metadata.plan, `Plan not found for ${id}`);\n return metadata.plan;\n };\n\n getBillingPeriod = (productId: string, planId: string): BP => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n invariant(metadata.billingPeriod, `Billing period not found for ${id}`);\n return metadata.billingPeriod;\n };\n\n getMode = (productId: string): 'payment' | 'subscription' => {\n if (this.onetimes.has(productId)) return 'payment';\n if (this.subscriptions.has(productId)) return 'subscription';\n throw new Error(`Mode not found for product ${productId}`);\n };\n\n getCreditAmount = (productId: string, planId?: string): number => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n return metadata.credits;\n };\n\n private readonly getCreditExpiresIn = (productId: string, planId?: string): number => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n return ms(metadata.expiresIn);\n };\n\n getCreditExpiresAt = (productId: string, planId?: string): string => {\n const expiresIn = this.getCreditExpiresIn(productId, planId);\n return new Date(Date.now() + expiresIn).toISOString();\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.mjs","names":[],"sources":["../../src/google-play/config.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport ms from 'ms';\nimport { type Catalog, assertCatalog, assertDeclared, assertInNamespace } from '../catalog';\nimport type { IsUnique, Metadata } from '../types';\n\nconst addMethod = Symbol('addMethod');\n/** The private constructor's one door, for this module's `define` function only. */\nconst construct = Symbol('construct');\n\nclass Subscription<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PI extends string = never,\n I extends Lowercase<string> = never,\n> {\n readonly productId: string;\n readonly config: GooglePlayConfig<NS, PE, BP, PI>;\n readonly plans: Map<string, Metadata & { plan?: PE; billingPeriod?: BP }>;\n readonly defaultPlans: Set<string>;\n\n constructor(config: GooglePlayConfig<NS, PE, BP, PI>, productId: string) {\n this.config = config;\n this.productId = productId;\n this.plans = new Map();\n this.defaultPlans = new Set();\n }\n\n /**\n * Non-default base plans stay declared on purpose: they keep resolving for\n * grandfathered subscribers and serve as price-experiment arms. Never sell\n * a legacy base plan to new users unless that is intentional.\n */\n basePlan = <K extends Lowercase<string>>(\n planId: K extends I ? never : K,\n plan: PE,\n billingPeriod: BP,\n metadata: Metadata = { credits: 0, expiresIn: '0' }\n ): Subscription<NS, PE, BP, PI, I | K> => {\n assertDeclared(this.config, plan, billingPeriod);\n invariant(!this.plans.has(planId), `Duplicate base plan ${planId}`);\n this.plans.set(planId, { ...metadata, plan, billingPeriod });\n return this;\n };\n\n default = <const T extends readonly [I, ...I[]]>(\n planIds: T & (IsUnique<T> extends true ? unknown : never)\n ) => {\n planIds.forEach((planId) => {\n invariant(this.plans.has(planId), `Default base plan ${planId} is not declared`);\n this.defaultPlans.add(planId);\n });\n this.config[addMethod](this);\n return this.config;\n };\n}\n\ntype Options<NS extends Lowercase<string>, PE extends string, BP extends string> = Catalog<\n NS,\n PE,\n BP\n> & { package: string; audience: string };\n\nexport class GooglePlayConfig<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PI extends string = never,\n> {\n readonly package: string;\n readonly audience: string;\n readonly namespace: NS;\n readonly plans: readonly PE[];\n readonly billingPeriods: readonly BP[];\n private readonly onetimes: Set<string>;\n private readonly subscriptions: Map<string, Subscription<NS, PE, BP, PI>>;\n private readonly products: Map<string, (Metadata & { plan?: PE; billingPeriod?: BP }) | null>;\n\n // runtime mirror of the type-level guards: generic accumulation only\n // protects a single fluent chain, not statement-style re-entry or casts\n [addMethod] = (subscription: Subscription<NS, PE, BP, PI>) => {\n invariant(\n !this.subscriptions.has(subscription.productId),\n `Duplicate subscription ${subscription.productId}`\n );\n subscription.plans.forEach((metadata, planId) => {\n const id = this.getId(subscription.productId, planId);\n invariant(!this.products.has(id), `Duplicate product ${id}`);\n this.products.set(id, metadata);\n });\n this.subscriptions.set(subscription.productId, subscription);\n return this;\n };\n\n private readonly getId = (productId: string, planId?: string) => {\n return planId ? `${productId}:${planId}` : productId;\n };\n\n private constructor(options: Options<NS, PE, BP>) {\n assertCatalog(options);\n this.namespace = options.namespace;\n this.plans = options.plans;\n this.billingPeriods = options.billingPeriods;\n this.package = options.package;\n this.audience = options.audience;\n this.products = new Map();\n this.onetimes = new Set();\n this.subscriptions = new Map();\n }\n\n static [construct] = <NS extends Lowercase<string>, PE extends string, BP extends string>(\n options: Options<NS, PE, BP>\n ) => new GooglePlayConfig<NS, PE, BP>(options);\n\n subscription = <K extends `${NS}.${Lowercase<string>}`>(productId: K extends PI ? never : K) => {\n assertInNamespace(this.namespace, productId);\n return new Subscription<NS, PE, BP, PI | K>(this, productId);\n };\n\n onetime = <K extends `${NS}.${Lowercase<string>}`>(\n productId: K extends PI ? never : K,\n metadata: Metadata = { credits: 0, expiresIn: '0' }\n ) => {\n assertInNamespace(this.namespace, productId);\n invariant(!this.products.has(productId), `Duplicate product ${productId}`);\n this.onetimes.add(productId);\n this.products.set(productId, metadata);\n return this as GooglePlayConfig<NS, PE, BP, PI | K>;\n };\n\n /** Base plan ids that new subscribers should purchase for the product. */\n getDefaultPlanIds = (productId: string): string[] => {\n const subscription = this.subscriptions.get(productId);\n invariant(subscription, `Subscription not found for ${productId}`);\n return Array.from(subscription.defaultPlans);\n };\n\n getPlan = (productId: string, planId: string): PE => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n invariant(metadata.plan, `Plan not found for ${id}`);\n return metadata.plan;\n };\n\n getBillingPeriod = (productId: string, planId: string): BP => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n invariant(metadata.billingPeriod, `Billing period not found for ${id}`);\n return metadata.billingPeriod;\n };\n\n getMode = (productId: string): 'payment' | 'subscription' => {\n if (this.onetimes.has(productId)) return 'payment';\n if (this.subscriptions.has(productId)) return 'subscription';\n throw new Error(`Mode not found for product ${productId}`);\n };\n\n getCreditAmount = (productId: string, planId?: string): number => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n return metadata.credits;\n };\n\n private readonly getCreditExpiresIn = (productId: string, planId?: string): number => {\n const id = this.getId(productId, planId);\n const metadata = this.products.get(id);\n invariant(metadata, `Product not found for ${id}`);\n return ms(metadata.expiresIn);\n };\n\n getCreditExpiresAt = (productId: string, planId?: string): string => {\n const expiresIn = this.getCreditExpiresIn(productId, planId);\n return new Date(Date.now() + expiresIn).toISOString();\n };\n}\n\n/**\n * Declare the GooglePlay product catalog. Every type parameter is inferred from the options:\n * the namespace from `namespace`, the plans and billing periods from `plans` and `billingPeriods`\n * (`const`, so a literal array needs no `as const`). Products are then added with the fluent chain.\n */\nexport function defineGooglePlayConfig<\n const NS extends Lowercase<string>,\n const PE extends string,\n const BP extends string,\n>(options: Options<NS, PE, BP>): GooglePlayConfig<NS, PE, BP> {\n return GooglePlayConfig[construct](options);\n}\n"],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@ exports.OneTimeProductNotificationType = require_google_play_real_time_developer
|
|
|
8
8
|
exports.SubscriptionNotificationType = require_google_play_real_time_developer_notification.SubscriptionNotificationType;
|
|
9
9
|
exports.VoidedPurchaseProductType = require_google_play_real_time_developer_notification.VoidedPurchaseProductType;
|
|
10
10
|
exports.VoidedPurchaseRefundType = require_google_play_real_time_developer_notification.VoidedPurchaseRefundType;
|
|
11
|
+
exports.defineGooglePlayConfig = require_google_play_config.defineGooglePlayConfig;
|
|
11
12
|
exports.mapCanceledAt = require_google_play_mapper.mapCanceledAt;
|
|
12
13
|
exports.mapCancellationDetails = require_google_play_mapper.mapCancellationDetails;
|
|
13
14
|
exports.mapPaymentType = require_google_play_mapper.mapPaymentType;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GooglePlayConfig } from "./config.cjs";
|
|
1
|
+
import { GooglePlayConfig, defineGooglePlayConfig } from "./config.cjs";
|
|
2
2
|
import { DeveloperNotification, GOOGLE_PLAY_SUBSCRIPTION_STATES, GooglePlaySubscriptionState, OneTimeProductNotification, OneTimeProductNotificationType, PubsubMessage, SubscriptionNotification, SubscriptionNotificationType, TestNotification, VoidedPurchaseNotification, VoidedPurchaseProductType, VoidedPurchaseRefundType } from "./real-time-developer-notification.cjs";
|
|
3
3
|
import { CanceledStateContext, mapCanceledAt, mapCancellationDetails, mapPaymentType, mapSubscriptionStatus } from "./mapper.cjs";
|
|
4
|
-
export { type CanceledStateContext, type DeveloperNotification, GOOGLE_PLAY_SUBSCRIPTION_STATES, GooglePlayConfig, type GooglePlaySubscriptionState, type OneTimeProductNotification, OneTimeProductNotificationType, type PubsubMessage, type SubscriptionNotification, SubscriptionNotificationType, type TestNotification, type VoidedPurchaseNotification, VoidedPurchaseProductType, VoidedPurchaseRefundType, mapCanceledAt, mapCancellationDetails, mapPaymentType, mapSubscriptionStatus };
|
|
4
|
+
export { type CanceledStateContext, type DeveloperNotification, GOOGLE_PLAY_SUBSCRIPTION_STATES, GooglePlayConfig, type GooglePlaySubscriptionState, type OneTimeProductNotification, OneTimeProductNotificationType, type PubsubMessage, type SubscriptionNotification, SubscriptionNotificationType, type TestNotification, type VoidedPurchaseNotification, VoidedPurchaseProductType, VoidedPurchaseRefundType, defineGooglePlayConfig, mapCanceledAt, mapCancellationDetails, mapPaymentType, mapSubscriptionStatus };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GooglePlayConfig } from "./config.mjs";
|
|
1
|
+
import { GooglePlayConfig, defineGooglePlayConfig } from "./config.mjs";
|
|
2
2
|
import { DeveloperNotification, GOOGLE_PLAY_SUBSCRIPTION_STATES, GooglePlaySubscriptionState, OneTimeProductNotification, OneTimeProductNotificationType, PubsubMessage, SubscriptionNotification, SubscriptionNotificationType, TestNotification, VoidedPurchaseNotification, VoidedPurchaseProductType, VoidedPurchaseRefundType } from "./real-time-developer-notification.mjs";
|
|
3
3
|
import { CanceledStateContext, mapCanceledAt, mapCancellationDetails, mapPaymentType, mapSubscriptionStatus } from "./mapper.mjs";
|
|
4
|
-
export { type CanceledStateContext, type DeveloperNotification, GOOGLE_PLAY_SUBSCRIPTION_STATES, GooglePlayConfig, type GooglePlaySubscriptionState, type OneTimeProductNotification, OneTimeProductNotificationType, type PubsubMessage, type SubscriptionNotification, SubscriptionNotificationType, type TestNotification, type VoidedPurchaseNotification, VoidedPurchaseProductType, VoidedPurchaseRefundType, mapCanceledAt, mapCancellationDetails, mapPaymentType, mapSubscriptionStatus };
|
|
4
|
+
export { type CanceledStateContext, type DeveloperNotification, GOOGLE_PLAY_SUBSCRIPTION_STATES, GooglePlayConfig, type GooglePlaySubscriptionState, type OneTimeProductNotification, OneTimeProductNotificationType, type PubsubMessage, type SubscriptionNotification, SubscriptionNotificationType, type TestNotification, type VoidedPurchaseNotification, VoidedPurchaseProductType, VoidedPurchaseRefundType, defineGooglePlayConfig, mapCanceledAt, mapCancellationDetails, mapPaymentType, mapSubscriptionStatus };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GooglePlayConfig } from "./config.mjs";
|
|
1
|
+
import { GooglePlayConfig, defineGooglePlayConfig } from "./config.mjs";
|
|
2
2
|
import { GOOGLE_PLAY_SUBSCRIPTION_STATES, OneTimeProductNotificationType, SubscriptionNotificationType, VoidedPurchaseProductType, VoidedPurchaseRefundType } from "./real-time-developer-notification.mjs";
|
|
3
3
|
import { mapCanceledAt, mapCancellationDetails, mapPaymentType, mapSubscriptionStatus } from "./mapper.mjs";
|
|
4
|
-
export { GOOGLE_PLAY_SUBSCRIPTION_STATES, GooglePlayConfig, OneTimeProductNotificationType, SubscriptionNotificationType, VoidedPurchaseProductType, VoidedPurchaseRefundType, mapCanceledAt, mapCancellationDetails, mapPaymentType, mapSubscriptionStatus };
|
|
4
|
+
export { GOOGLE_PLAY_SUBSCRIPTION_STATES, GooglePlayConfig, OneTimeProductNotificationType, SubscriptionNotificationType, VoidedPurchaseProductType, VoidedPurchaseRefundType, defineGooglePlayConfig, mapCanceledAt, mapCancellationDetails, mapPaymentType, mapSubscriptionStatus };
|
package/dist/index.cjs
CHANGED
|
@@ -17,3 +17,6 @@ exports.REFUND_STATUS_TRANSITIONS = require_subscription_index.REFUND_STATUS_TRA
|
|
|
17
17
|
exports.RESUBSCRIBE_INTENTS = require_subscription_index.RESUBSCRIBE_INTENTS;
|
|
18
18
|
exports.SUBSCRIPTION_STATUSES = require_subscription_index.SUBSCRIPTION_STATUSES;
|
|
19
19
|
exports.StripeConfig = require_stripe_config.StripeConfig;
|
|
20
|
+
exports.defineAppStoreConfig = require_app_store_config.defineAppStoreConfig;
|
|
21
|
+
exports.defineGooglePlayConfig = require_google_play_config.defineGooglePlayConfig;
|
|
22
|
+
exports.defineStripeConfig = require_stripe_config.defineStripeConfig;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AppStoreConfig } from "./app-store/config.cjs";
|
|
1
|
+
import { AppStoreConfig, defineAppStoreConfig } from "./app-store/config.cjs";
|
|
2
2
|
import { AVAILABLE_STATUSES, CANCELLATION_FEEDBACKS, CANCELLATION_INITIATORS, CLOSED_DISPUTE_STATUSES, CancellationDetails, CancellationFeedback, CancellationInitiator, DISPUTE_STATUSES, DisputeStatus, PAYMENT_TYPES, PLATFORMS, PaymentType, Platform, REFUND_STATUSES, REFUND_STATUS_TRANSITIONS, RESUBSCRIBE_INTENTS, RefundStatus, ResubscribeIntent, SUBSCRIPTION_STATUSES, SubscriptionStatus } from "./subscription/index.cjs";
|
|
3
|
-
import { GooglePlayConfig } from "./google-play/config.cjs";
|
|
4
|
-
import { StripeConfig } from "./stripe/config.cjs";
|
|
5
|
-
export { AVAILABLE_STATUSES, AppStoreConfig, CANCELLATION_FEEDBACKS, CANCELLATION_INITIATORS, CLOSED_DISPUTE_STATUSES, type CancellationDetails, type CancellationFeedback, type CancellationInitiator, DISPUTE_STATUSES, type DisputeStatus, GooglePlayConfig, PAYMENT_TYPES, PLATFORMS, type PaymentType, type Platform, REFUND_STATUSES, REFUND_STATUS_TRANSITIONS, RESUBSCRIBE_INTENTS, type RefundStatus, type ResubscribeIntent, SUBSCRIPTION_STATUSES, StripeConfig, type SubscriptionStatus };
|
|
3
|
+
import { GooglePlayConfig, defineGooglePlayConfig } from "./google-play/config.cjs";
|
|
4
|
+
import { StripeConfig, defineStripeConfig } from "./stripe/config.cjs";
|
|
5
|
+
export { AVAILABLE_STATUSES, AppStoreConfig, CANCELLATION_FEEDBACKS, CANCELLATION_INITIATORS, CLOSED_DISPUTE_STATUSES, type CancellationDetails, type CancellationFeedback, type CancellationInitiator, DISPUTE_STATUSES, type DisputeStatus, GooglePlayConfig, PAYMENT_TYPES, PLATFORMS, type PaymentType, type Platform, REFUND_STATUSES, REFUND_STATUS_TRANSITIONS, RESUBSCRIBE_INTENTS, type RefundStatus, type ResubscribeIntent, SUBSCRIPTION_STATUSES, StripeConfig, type SubscriptionStatus, defineAppStoreConfig, defineGooglePlayConfig, defineStripeConfig };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AppStoreConfig } from "./app-store/config.mjs";
|
|
1
|
+
import { AppStoreConfig, defineAppStoreConfig } from "./app-store/config.mjs";
|
|
2
2
|
import { AVAILABLE_STATUSES, CANCELLATION_FEEDBACKS, CANCELLATION_INITIATORS, CLOSED_DISPUTE_STATUSES, CancellationDetails, CancellationFeedback, CancellationInitiator, DISPUTE_STATUSES, DisputeStatus, PAYMENT_TYPES, PLATFORMS, PaymentType, Platform, REFUND_STATUSES, REFUND_STATUS_TRANSITIONS, RESUBSCRIBE_INTENTS, RefundStatus, ResubscribeIntent, SUBSCRIPTION_STATUSES, SubscriptionStatus } from "./subscription/index.mjs";
|
|
3
|
-
import { GooglePlayConfig } from "./google-play/config.mjs";
|
|
4
|
-
import { StripeConfig } from "./stripe/config.mjs";
|
|
5
|
-
export { AVAILABLE_STATUSES, AppStoreConfig, CANCELLATION_FEEDBACKS, CANCELLATION_INITIATORS, CLOSED_DISPUTE_STATUSES, type CancellationDetails, type CancellationFeedback, type CancellationInitiator, DISPUTE_STATUSES, type DisputeStatus, GooglePlayConfig, PAYMENT_TYPES, PLATFORMS, type PaymentType, type Platform, REFUND_STATUSES, REFUND_STATUS_TRANSITIONS, RESUBSCRIBE_INTENTS, type RefundStatus, type ResubscribeIntent, SUBSCRIPTION_STATUSES, StripeConfig, type SubscriptionStatus };
|
|
3
|
+
import { GooglePlayConfig, defineGooglePlayConfig } from "./google-play/config.mjs";
|
|
4
|
+
import { StripeConfig, defineStripeConfig } from "./stripe/config.mjs";
|
|
5
|
+
export { AVAILABLE_STATUSES, AppStoreConfig, CANCELLATION_FEEDBACKS, CANCELLATION_INITIATORS, CLOSED_DISPUTE_STATUSES, type CancellationDetails, type CancellationFeedback, type CancellationInitiator, DISPUTE_STATUSES, type DisputeStatus, GooglePlayConfig, PAYMENT_TYPES, PLATFORMS, type PaymentType, type Platform, REFUND_STATUSES, REFUND_STATUS_TRANSITIONS, RESUBSCRIBE_INTENTS, type RefundStatus, type ResubscribeIntent, SUBSCRIPTION_STATUSES, StripeConfig, type SubscriptionStatus, defineAppStoreConfig, defineGooglePlayConfig, defineStripeConfig };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AVAILABLE_STATUSES, CANCELLATION_FEEDBACKS, CANCELLATION_INITIATORS, CLOSED_DISPUTE_STATUSES, DISPUTE_STATUSES, PAYMENT_TYPES, PLATFORMS, REFUND_STATUSES, REFUND_STATUS_TRANSITIONS, RESUBSCRIBE_INTENTS, SUBSCRIPTION_STATUSES } from "./subscription/index.mjs";
|
|
2
|
-
import { AppStoreConfig } from "./app-store/config.mjs";
|
|
3
|
-
import { GooglePlayConfig } from "./google-play/config.mjs";
|
|
4
|
-
import { StripeConfig } from "./stripe/config.mjs";
|
|
5
|
-
export { AVAILABLE_STATUSES, AppStoreConfig, CANCELLATION_FEEDBACKS, CANCELLATION_INITIATORS, CLOSED_DISPUTE_STATUSES, DISPUTE_STATUSES, GooglePlayConfig, PAYMENT_TYPES, PLATFORMS, REFUND_STATUSES, REFUND_STATUS_TRANSITIONS, RESUBSCRIBE_INTENTS, SUBSCRIPTION_STATUSES, StripeConfig };
|
|
2
|
+
import { AppStoreConfig, defineAppStoreConfig } from "./app-store/config.mjs";
|
|
3
|
+
import { GooglePlayConfig, defineGooglePlayConfig } from "./google-play/config.mjs";
|
|
4
|
+
import { StripeConfig, defineStripeConfig } from "./stripe/config.mjs";
|
|
5
|
+
export { AVAILABLE_STATUSES, AppStoreConfig, CANCELLATION_FEEDBACKS, CANCELLATION_INITIATORS, CLOSED_DISPUTE_STATUSES, DISPUTE_STATUSES, GooglePlayConfig, PAYMENT_TYPES, PLATFORMS, REFUND_STATUSES, REFUND_STATUS_TRANSITIONS, RESUBSCRIBE_INTENTS, SUBSCRIPTION_STATUSES, StripeConfig, defineAppStoreConfig, defineGooglePlayConfig, defineStripeConfig };
|
package/dist/stripe/config.cjs
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
3
|
+
const require_catalog = require("../catalog.cjs");
|
|
3
4
|
let _shware_utils = require("@shware/utils");
|
|
4
5
|
let ms = require("ms");
|
|
5
6
|
ms = require_runtime.__toESM(ms, 1);
|
|
6
7
|
//#region src/stripe/config.ts
|
|
7
8
|
const addMethod = Symbol("addMethod");
|
|
9
|
+
/** The private constructor's one door, for this module's `define` function only. */
|
|
10
|
+
const construct = Symbol("construct");
|
|
8
11
|
var Product = class {
|
|
9
12
|
id;
|
|
10
13
|
config;
|
|
@@ -62,6 +65,9 @@ var StripeConfig = class StripeConfig {
|
|
|
62
65
|
successUrl;
|
|
63
66
|
cancellationCouponId;
|
|
64
67
|
allowPromotionCodes;
|
|
68
|
+
namespace;
|
|
69
|
+
plans;
|
|
70
|
+
billingPeriods;
|
|
65
71
|
get productIds() {
|
|
66
72
|
return Array.from(this.products.keys());
|
|
67
73
|
}
|
|
@@ -73,6 +79,10 @@ var StripeConfig = class StripeConfig {
|
|
|
73
79
|
return this;
|
|
74
80
|
};
|
|
75
81
|
constructor(options) {
|
|
82
|
+
require_catalog.assertCatalog(options);
|
|
83
|
+
this.namespace = options.namespace;
|
|
84
|
+
this.plans = options.plans;
|
|
85
|
+
this.billingPeriods = options.billingPeriods;
|
|
76
86
|
this.mode = options.mode;
|
|
77
87
|
this.returnUrl = options.returnUrl;
|
|
78
88
|
this.cancelUrl = options.cancelUrl;
|
|
@@ -80,14 +90,16 @@ var StripeConfig = class StripeConfig {
|
|
|
80
90
|
this.cancellationCouponId = options.cancellationCouponId;
|
|
81
91
|
this.allowPromotionCodes = options.allowPromotionCodes;
|
|
82
92
|
}
|
|
83
|
-
static
|
|
84
|
-
return new StripeConfig(options);
|
|
85
|
-
};
|
|
93
|
+
static [construct] = (options) => new StripeConfig(options);
|
|
86
94
|
/**
|
|
87
95
|
* One-time products take no extra args; subscriptions require both plan and billingPeriod.
|
|
88
96
|
* A plan+period pair may be declared on only one product — version its prices in that chain.
|
|
89
97
|
*/
|
|
90
|
-
product = (productId, plan = null, billingPeriod = null) =>
|
|
98
|
+
product = (productId, plan = null, billingPeriod = null) => {
|
|
99
|
+
require_catalog.assertInNamespace(this.namespace, productId);
|
|
100
|
+
require_catalog.assertDeclared(this, plan, billingPeriod);
|
|
101
|
+
return new Product(this, productId, plan, billingPeriod);
|
|
102
|
+
};
|
|
91
103
|
getPlan = (productId) => {
|
|
92
104
|
const product = this.products.get(productId);
|
|
93
105
|
(0, _shware_utils.invariant)(product, `Product not found for ${productId}`);
|
|
@@ -131,6 +143,22 @@ var StripeConfig = class StripeConfig {
|
|
|
131
143
|
for (const product of this.products.values()) if (product.prices.has(priceId)) return product.id;
|
|
132
144
|
return null;
|
|
133
145
|
};
|
|
146
|
+
/**
|
|
147
|
+
* How switching from one subscription product to another relates them (see
|
|
148
|
+
* {@link PlanComparison}), by the order `plans` and `billingPeriods` were declared in. Throws for
|
|
149
|
+
* a product that is not a subscription.
|
|
150
|
+
*/
|
|
151
|
+
comparePlans = (fromProductId, toProductId) => {
|
|
152
|
+
const level = (productId) => ({
|
|
153
|
+
plan: this.plans.indexOf(this.getPlan(productId)),
|
|
154
|
+
period: this.billingPeriods.indexOf(this.getBillingPeriod(productId))
|
|
155
|
+
});
|
|
156
|
+
const from = level(fromProductId);
|
|
157
|
+
const to = level(toProductId);
|
|
158
|
+
if (to.plan !== from.plan) return to.plan > from.plan ? "upgrade" : "downgrade";
|
|
159
|
+
if (to.period !== from.period) return to.period > from.period ? "longer" : "shorter";
|
|
160
|
+
return "same";
|
|
161
|
+
};
|
|
134
162
|
getCreditAmount = (productId, priceId) => {
|
|
135
163
|
const product = this.products.get(productId);
|
|
136
164
|
(0, _shware_utils.invariant)(product, `Product not found for ${productId}`);
|
|
@@ -158,7 +186,16 @@ var StripeConfig = class StripeConfig {
|
|
|
158
186
|
return new Date(Date.now() + expiresIn).toISOString();
|
|
159
187
|
};
|
|
160
188
|
};
|
|
189
|
+
/**
|
|
190
|
+
* Declare the Stripe product catalog. Every type parameter is inferred from the options:
|
|
191
|
+
* the namespace from `namespace`, the plans and billing periods from `plans` and `billingPeriods`
|
|
192
|
+
* (`const`, so a literal array needs no `as const`). Products are then added with the fluent chain.
|
|
193
|
+
*/
|
|
194
|
+
function defineStripeConfig(options) {
|
|
195
|
+
return StripeConfig[construct](options);
|
|
196
|
+
}
|
|
161
197
|
//#endregion
|
|
162
198
|
exports.StripeConfig = StripeConfig;
|
|
199
|
+
exports.defineStripeConfig = defineStripeConfig;
|
|
163
200
|
|
|
164
201
|
//# sourceMappingURL=config.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.cjs","names":[],"sources":["../../src/stripe/config.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport ms from 'ms';\nimport type { Metadata } from '../types';\n\nexport type PriceId = `price_${string}`;\n\n/**\n * Which Stripe object space the config addresses. Test and live prices are\n * disjoint, so a config is built for exactly one of them. Derive it from the\n * secret key (`sk_test_` vs `sk_live_`) rather than from the deployment\n * environment: the key is what actually decides which space API calls hit.\n */\nexport type StripeMode = 'live' | 'test';\n\nconst addMethod = Symbol('addMethod');\n\nclass Product<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PL extends string = never,\n PI extends string = never,\n I extends PriceId = never,\n> {\n readonly id: string;\n readonly config: StripeConfig<NS, PE, BP, PL, PI>;\n readonly plan: PE | null;\n readonly billingPeriod: BP | null;\n readonly prices: Map<PriceId, Metadata>;\n\n defaultPriceId: PriceId | null;\n\n constructor(\n config: StripeConfig<NS, PE, BP, PL, PI>,\n id: string,\n plan: PE | null = null,\n billingPeriod: BP | null = null\n ) {\n this.id = id;\n this.config = config;\n this.plan = plan;\n this.billingPeriod = billingPeriod;\n this.prices = new Map();\n this.defaultPriceId = null;\n }\n\n /**\n * Non-default prices stay declared on purpose: they keep resolving for\n * grandfathered subscribers and serve as price-experiment arms. Never\n * create new checkouts with a legacy price unless that is intentional.\n */\n price = <K extends PriceId>(\n priceId: K extends I ? never : K,\n metadata: Metadata = { credits: 0, expiresIn: '0' }\n ): Product<NS, PE, BP, PL, PI, I | K> => {\n invariant(!this.prices.has(priceId), `Duplicate price ${priceId}`);\n this.prices.set(priceId, metadata);\n return this as Product<NS, PE, BP, PL, PI, I | K>;\n };\n\n /**\n * `test` is the sandbox twin of the default price. In test mode it is what\n * checkouts are created with, and it resolves to the default price's\n * entitlement, so credits are declared once and cannot drift between the\n * two modes. Legacy prices need no twin: a sandbox holds no grandfathered\n * subscribers. Live mode ignores it, so a test price reaching a live config\n * still fails as an unknown price instead of being granted an entitlement.\n */\n default = (defaultPriceId: I, twin?: { test: PriceId }) => {\n const metadata = this.prices.get(defaultPriceId);\n invariant(metadata, `Default price ${defaultPriceId} is not declared`);\n if (this.config.mode === 'test') {\n invariant(twin, `Test price not declared for default ${defaultPriceId} of ${this.id}`);\n invariant(!this.prices.has(twin.test), `Duplicate price ${twin.test}`);\n this.prices.set(twin.test, metadata);\n this.defaultPriceId = twin.test;\n } else {\n this.defaultPriceId = defaultPriceId;\n }\n this.config[addMethod](this);\n return this.config;\n };\n}\n\ntype Options = {\n mode: StripeMode;\n returnUrl: string;\n cancelUrl: string;\n successUrl: `${string}session_id={CHECKOUT_SESSION_ID}${string}`;\n cancellationCouponId: string;\n allowPromotionCodes: boolean;\n};\n\nexport class StripeConfig<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PL extends string = never,\n PI extends string = never,\n> {\n private readonly products: Map<string, Product<NS, PE, BP, PL, PI>> = new Map();\n\n public readonly mode: StripeMode;\n public returnUrl: string;\n public cancelUrl: string;\n public successUrl: `${string}session_id={CHECKOUT_SESSION_ID}${string}`;\n public cancellationCouponId: string;\n public allowPromotionCodes: boolean;\n\n get productIds(): string[] {\n return Array.from(this.products.keys());\n }\n\n // runtime mirror of the type-level guards: generic accumulation only\n // protects a single fluent chain, not statement-style re-entry or casts\n [addMethod] = (product: Product<NS, PE, BP, PL, PI>) => {\n invariant(!this.products.has(product.id), `Duplicate product ${product.id}`);\n // A Stripe price belongs to one Stripe product, and getProductId must have one answer.\n for (const existing of this.products.values()) {\n for (const priceId of product.prices.keys()) {\n invariant(!existing.prices.has(priceId), `Duplicate price ${priceId} on ${existing.id}`);\n }\n }\n if (product.plan !== null) {\n for (const existing of this.products.values()) {\n invariant(\n existing.plan !== product.plan || existing.billingPeriod !== product.billingPeriod,\n `Duplicate plan ${product.plan}:${product.billingPeriod}`\n );\n }\n }\n this.products.set(product.id, product);\n return this;\n };\n\n private constructor(options: Options) {\n this.mode = options.mode;\n this.returnUrl = options.returnUrl;\n this.cancelUrl = options.cancelUrl;\n this.successUrl = options.successUrl;\n this.cancellationCouponId = options.cancellationCouponId;\n this.allowPromotionCodes = options.allowPromotionCodes;\n }\n\n static create = <NS extends Lowercase<string>, PE extends string, BP extends string = string>(\n options: Options\n ) => {\n return new StripeConfig<NS, PE, BP>(options);\n };\n\n /**\n * One-time products take no extra args; subscriptions require both plan and billingPeriod.\n * A plan+period pair may be declared on only one product — version its prices in that chain.\n */\n product: {\n <K extends `${NS}.${Lowercase<string>}`>(\n productId: K extends PI ? never : K\n ): Product<NS, PE, BP, PL, K | PI>;\n <K extends `${NS}.${Lowercase<string>}`, L extends PE, P extends BP>(\n productId: K extends PI ? never : K,\n plan: L,\n billingPeriod: `${L}:${P}` extends PL ? never : P\n ): Product<NS, PE, BP, `${L}:${P}` | PL, K | PI>;\n } = (productId: string, plan: PE | null = null, billingPeriod: BP | null = null) =>\n // oxlint-disable-next-line typescript/no-unnecessary-type-assertion -- widens to the overloads' accumulated generics\n new Product(this, productId, plan, billingPeriod) as never;\n\n getPlan = (productId: string): PE => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n invariant(product.plan, `Product ${productId} is not a subscription`);\n return product.plan;\n };\n\n getBillingPeriod = (productId: string): BP => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n invariant(product.billingPeriod, `Product ${productId} is not a subscription`);\n return product.billingPeriod;\n };\n\n getMode = (productId: string): 'payment' | 'subscription' => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n return product.plan === null ? 'payment' : 'subscription';\n };\n\n /**\n * Whether the config declares `productId` and sells it as a subscription, so `getPlan` and\n * `getBillingPeriod` hold for it. False, not a throw, for an id it does not know: a product that\n * left the config (renamed, retired) or one named by metadata set outside the app.\n */\n isSubscription = (productId: string): boolean => {\n const product = this.products.get(productId);\n return product !== undefined && product.plan !== null;\n };\n\n /** The price new checkouts are created with: the default, or its test twin in test mode. */\n getPriceId = (productId: string): PriceId => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n invariant(product.defaultPriceId, `Default price not found for product ${productId}`);\n return product.defaultPriceId;\n };\n\n /**\n * The product that declares `priceId` (a legacy price or the test twin included), or null for a\n * price this config does not know: one set up by hand in the dashboard, or a test price reaching\n * a live config. Reading the product from the price a Stripe object charged, rather than from\n * metadata that may already name the next plan, is what an invoice should be credited by.\n */\n getProductId = (priceId: string): string | null => {\n for (const product of this.products.values()) {\n if (product.prices.has(priceId as PriceId)) return product.id;\n }\n return null;\n };\n\n getCreditAmount = (productId: string, priceId?: string): number => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n if (priceId) {\n const price = product.prices.get(priceId as PriceId);\n invariant(price, `Price not found for ${priceId}`);\n return price.credits;\n }\n\n invariant(product.defaultPriceId, `Default price not found for product ${productId}`);\n return product.prices.get(product.defaultPriceId)?.credits ?? 0;\n };\n\n private readonly getCreditExpiresIn = (productId: string, priceId?: string): number => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n if (priceId) {\n const price = product.prices.get(priceId as PriceId);\n invariant(price, `Price not found for ${priceId}`);\n return ms(price.expiresIn);\n }\n\n invariant(product.defaultPriceId, `Default price not found for product ${productId}`);\n return ms(product.prices.get(product.defaultPriceId)?.expiresIn ?? '0');\n };\n\n getCreditExpiresAt = (productId: string, priceId?: string): string => {\n const expiresIn = this.getCreditExpiresIn(productId, priceId);\n return new Date(Date.now() + expiresIn).toISOString();\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.cjs","names":[],"sources":["../../src/stripe/config.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport ms from 'ms';\nimport { type Catalog, assertCatalog, assertDeclared, assertInNamespace } from '../catalog';\nimport type { Metadata } from '../types';\n\nexport type PriceId = `price_${string}`;\n\n/**\n * Which Stripe object space the config addresses. Test and live prices are\n * disjoint, so a config is built for exactly one of them. Derive it from the\n * secret key (`sk_test_` vs `sk_live_`) rather than from the deployment\n * environment: the key is what actually decides which space API calls hit.\n */\nexport type StripeMode = 'live' | 'test';\n\nconst addMethod = Symbol('addMethod');\n/** The private constructor's one door, for this module's `define` function only. */\nconst construct = Symbol('construct');\n\nclass Product<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PL extends string = never,\n PI extends string = never,\n I extends PriceId = never,\n> {\n readonly id: string;\n readonly config: StripeConfig<NS, PE, BP, PL, PI>;\n readonly plan: PE | null;\n readonly billingPeriod: BP | null;\n readonly prices: Map<PriceId, Metadata>;\n\n defaultPriceId: PriceId | null;\n\n constructor(\n config: StripeConfig<NS, PE, BP, PL, PI>,\n id: string,\n plan: PE | null = null,\n billingPeriod: BP | null = null\n ) {\n this.id = id;\n this.config = config;\n this.plan = plan;\n this.billingPeriod = billingPeriod;\n this.prices = new Map();\n this.defaultPriceId = null;\n }\n\n /**\n * Non-default prices stay declared on purpose: they keep resolving for\n * grandfathered subscribers and serve as price-experiment arms. Never\n * create new checkouts with a legacy price unless that is intentional.\n */\n price = <K extends PriceId>(\n priceId: K extends I ? never : K,\n metadata: Metadata = { credits: 0, expiresIn: '0' }\n ): Product<NS, PE, BP, PL, PI, I | K> => {\n invariant(!this.prices.has(priceId), `Duplicate price ${priceId}`);\n this.prices.set(priceId, metadata);\n return this as Product<NS, PE, BP, PL, PI, I | K>;\n };\n\n /**\n * `test` is the sandbox twin of the default price. In test mode it is what\n * checkouts are created with, and it resolves to the default price's\n * entitlement, so credits are declared once and cannot drift between the\n * two modes. Legacy prices need no twin: a sandbox holds no grandfathered\n * subscribers. Live mode ignores it, so a test price reaching a live config\n * still fails as an unknown price instead of being granted an entitlement.\n */\n default = (defaultPriceId: I, twin?: { test: PriceId }) => {\n const metadata = this.prices.get(defaultPriceId);\n invariant(metadata, `Default price ${defaultPriceId} is not declared`);\n if (this.config.mode === 'test') {\n invariant(twin, `Test price not declared for default ${defaultPriceId} of ${this.id}`);\n invariant(!this.prices.has(twin.test), `Duplicate price ${twin.test}`);\n this.prices.set(twin.test, metadata);\n this.defaultPriceId = twin.test;\n } else {\n this.defaultPriceId = defaultPriceId;\n }\n this.config[addMethod](this);\n return this.config;\n };\n}\n\n/** `plans` and `billingPeriods` are the order {@link StripeConfig.comparePlans} reads. */\ntype Options<NS extends Lowercase<string>, PE extends string, BP extends string> = Catalog<\n NS,\n PE,\n BP\n> & {\n mode: StripeMode;\n returnUrl: string;\n cancelUrl: string;\n successUrl: `${string}session_id={CHECKOUT_SESSION_ID}${string}`;\n cancellationCouponId: string;\n allowPromotionCodes: boolean;\n};\n\n/**\n * How a switch between two subscription products relates them, by plan level first and billing\n * period second:\n * - `upgrade` / `downgrade`: a higher or lower plan, whatever the periods.\n * - `longer` / `shorter`: the same plan billed over a longer or shorter period (monthly → yearly\n * is `longer`). Apple calls these crossgrades.\n * - `same`: the same plan and period.\n */\nexport type PlanComparison = 'upgrade' | 'downgrade' | 'longer' | 'shorter' | 'same';\n\nexport class StripeConfig<\n NS extends Lowercase<string> = Lowercase<string>,\n PE extends string = string,\n BP extends string = string,\n PL extends string = never,\n PI extends string = never,\n> {\n private readonly products: Map<string, Product<NS, PE, BP, PL, PI>> = new Map();\n\n public readonly mode: StripeMode;\n public returnUrl: string;\n public cancelUrl: string;\n public successUrl: `${string}session_id={CHECKOUT_SESSION_ID}${string}`;\n public cancellationCouponId: string;\n public allowPromotionCodes: boolean;\n public readonly namespace: NS;\n public readonly plans: readonly PE[];\n public readonly billingPeriods: readonly BP[];\n\n get productIds(): string[] {\n return Array.from(this.products.keys());\n }\n\n // runtime mirror of the type-level guards: generic accumulation only\n // protects a single fluent chain, not statement-style re-entry or casts\n [addMethod] = (product: Product<NS, PE, BP, PL, PI>) => {\n invariant(!this.products.has(product.id), `Duplicate product ${product.id}`);\n // A Stripe price belongs to one Stripe product, and getProductId must have one answer.\n for (const existing of this.products.values()) {\n for (const priceId of product.prices.keys()) {\n invariant(!existing.prices.has(priceId), `Duplicate price ${priceId} on ${existing.id}`);\n }\n }\n if (product.plan !== null) {\n for (const existing of this.products.values()) {\n invariant(\n existing.plan !== product.plan || existing.billingPeriod !== product.billingPeriod,\n `Duplicate plan ${product.plan}:${product.billingPeriod}`\n );\n }\n }\n this.products.set(product.id, product);\n return this;\n };\n\n private constructor(options: Options<NS, PE, BP>) {\n assertCatalog(options);\n this.namespace = options.namespace;\n this.plans = options.plans;\n this.billingPeriods = options.billingPeriods;\n this.mode = options.mode;\n this.returnUrl = options.returnUrl;\n this.cancelUrl = options.cancelUrl;\n this.successUrl = options.successUrl;\n this.cancellationCouponId = options.cancellationCouponId;\n this.allowPromotionCodes = options.allowPromotionCodes;\n }\n\n static [construct] = <NS extends Lowercase<string>, PE extends string, BP extends string>(\n options: Options<NS, PE, BP>\n ) => new StripeConfig<NS, PE, BP>(options);\n\n /**\n * One-time products take no extra args; subscriptions require both plan and billingPeriod.\n * A plan+period pair may be declared on only one product — version its prices in that chain.\n */\n product: {\n <K extends `${NS}.${Lowercase<string>}`>(\n productId: K extends PI ? never : K\n ): Product<NS, PE, BP, PL, K | PI>;\n <K extends `${NS}.${Lowercase<string>}`, L extends PE, P extends BP>(\n productId: K extends PI ? never : K,\n plan: L,\n billingPeriod: `${L}:${P}` extends PL ? never : P\n ): Product<NS, PE, BP, `${L}:${P}` | PL, K | PI>;\n } = (productId: string, plan: PE | null = null, billingPeriod: BP | null = null) => {\n assertInNamespace(this.namespace, productId);\n assertDeclared(this, plan, billingPeriod);\n // oxlint-disable-next-line typescript/no-unnecessary-type-assertion -- widens to the overloads' accumulated generics\n return new Product(this, productId, plan, billingPeriod) as never;\n };\n\n getPlan = (productId: string): PE => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n invariant(product.plan, `Product ${productId} is not a subscription`);\n return product.plan;\n };\n\n getBillingPeriod = (productId: string): BP => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n invariant(product.billingPeriod, `Product ${productId} is not a subscription`);\n return product.billingPeriod;\n };\n\n getMode = (productId: string): 'payment' | 'subscription' => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n return product.plan === null ? 'payment' : 'subscription';\n };\n\n /**\n * Whether the config declares `productId` and sells it as a subscription, so `getPlan` and\n * `getBillingPeriod` hold for it. False, not a throw, for an id it does not know: a product that\n * left the config (renamed, retired) or one named by metadata set outside the app.\n */\n isSubscription = (productId: string): boolean => {\n const product = this.products.get(productId);\n return product !== undefined && product.plan !== null;\n };\n\n /** The price new checkouts are created with: the default, or its test twin in test mode. */\n getPriceId = (productId: string): PriceId => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n invariant(product.defaultPriceId, `Default price not found for product ${productId}`);\n return product.defaultPriceId;\n };\n\n /**\n * The product that declares `priceId` (a legacy price or the test twin included), or null for a\n * price this config does not know: one set up by hand in the dashboard, or a test price reaching\n * a live config. Reading the product from the price a Stripe object charged, rather than from\n * metadata that may already name the next plan, is what an invoice should be credited by.\n */\n getProductId = (priceId: string): string | null => {\n for (const product of this.products.values()) {\n if (product.prices.has(priceId as PriceId)) return product.id;\n }\n return null;\n };\n\n /**\n * How switching from one subscription product to another relates them (see\n * {@link PlanComparison}), by the order `plans` and `billingPeriods` were declared in. Throws for\n * a product that is not a subscription.\n */\n comparePlans = (fromProductId: string, toProductId: string): PlanComparison => {\n const level = (productId: string) => ({\n plan: this.plans.indexOf(this.getPlan(productId)),\n period: this.billingPeriods.indexOf(this.getBillingPeriod(productId)),\n });\n const from = level(fromProductId);\n const to = level(toProductId);\n if (to.plan !== from.plan) return to.plan > from.plan ? 'upgrade' : 'downgrade';\n if (to.period !== from.period) return to.period > from.period ? 'longer' : 'shorter';\n return 'same';\n };\n\n getCreditAmount = (productId: string, priceId?: string): number => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n if (priceId) {\n const price = product.prices.get(priceId as PriceId);\n invariant(price, `Price not found for ${priceId}`);\n return price.credits;\n }\n\n invariant(product.defaultPriceId, `Default price not found for product ${productId}`);\n return product.prices.get(product.defaultPriceId)?.credits ?? 0;\n };\n\n private readonly getCreditExpiresIn = (productId: string, priceId?: string): number => {\n const product = this.products.get(productId);\n invariant(product, `Product not found for ${productId}`);\n if (priceId) {\n const price = product.prices.get(priceId as PriceId);\n invariant(price, `Price not found for ${priceId}`);\n return ms(price.expiresIn);\n }\n\n invariant(product.defaultPriceId, `Default price not found for product ${productId}`);\n return ms(product.prices.get(product.defaultPriceId)?.expiresIn ?? '0');\n };\n\n getCreditExpiresAt = (productId: string, priceId?: string): string => {\n const expiresIn = this.getCreditExpiresIn(productId, priceId);\n return new Date(Date.now() + expiresIn).toISOString();\n };\n}\n\n/**\n * Declare the Stripe product catalog. Every type parameter is inferred from the options:\n * the namespace from `namespace`, the plans and billing periods from `plans` and `billingPeriods`\n * (`const`, so a literal array needs no `as const`). Products are then added with the fluent chain.\n */\nexport function defineStripeConfig<\n const NS extends Lowercase<string>,\n const PE extends string,\n const BP extends string,\n>(options: Options<NS, PE, BP>): StripeConfig<NS, PE, BP> {\n return StripeConfig[construct](options);\n}\n"],"mappings":"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"}
|