@sudobility/subscription_service 1.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/CLAUDE.md ADDED
@@ -0,0 +1,108 @@
1
+ # Subscription Service
2
+
3
+ Shared backend library for subscription management using RevenueCat.
4
+
5
+ **npm**: `@sudobility/subscription_service` (public)
6
+
7
+ ## Tech Stack
8
+
9
+ - **Language**: TypeScript (strict mode)
10
+ - **Runtime**: Bun
11
+ - **Build**: TypeScript compiler (ESM)
12
+ - **Test**: vitest
13
+
14
+ ## Project Structure
15
+
16
+ ```
17
+ src/
18
+ ├── index.ts # Main exports
19
+ ├── types/
20
+ │ ├── index.ts # Type re-exports
21
+ │ ├── entitlements.ts # RevenueCat API types
22
+ │ └── subscription.ts # SubscriptionInfo type
23
+ └── helpers/
24
+ ├── index.ts # Helper re-exports
25
+ └── SubscriptionHelper.ts # RevenueCat API client
26
+ tests/
27
+ └── *.test.ts
28
+ ```
29
+
30
+ ## Commands
31
+
32
+ ```bash
33
+ bun run build # Build ESM
34
+ bun run clean # Remove dist/
35
+ bun run dev # Watch mode
36
+ bun test # Run tests
37
+ bun run lint # Run ESLint
38
+ bun run typecheck # TypeScript check
39
+ bun run verify # All checks + build (use before commit)
40
+ ```
41
+
42
+ ## Key Concepts
43
+
44
+ ### SubscriptionHelper
45
+
46
+ Fetches user entitlements from RevenueCat API v1.
47
+
48
+ - Uses RevenueCat secret API key (server-side only)
49
+ - Supports testMode to include/exclude sandbox purchases
50
+ - Returns `["none"]` if user has no active entitlements
51
+
52
+ ### testMode Parameter
53
+
54
+ - `testMode=true`: Accept sandbox purchases (for testing)
55
+ - `testMode=false` (default): Reject sandbox purchases (production)
56
+
57
+ The helper checks each subscription's `sandbox` flag and filters accordingly.
58
+
59
+ ## Usage
60
+
61
+ ```typescript
62
+ import { SubscriptionHelper, NONE_ENTITLEMENT } from "@sudobility/subscription_service";
63
+
64
+ const helper = new SubscriptionHelper({
65
+ revenueCatApiKey: process.env.REVENUECAT_API_KEY!,
66
+ });
67
+
68
+ // Get entitlements (production mode - no sandbox)
69
+ const entitlements = await helper.getEntitlements(userId);
70
+ // Returns: ["pro"] or ["none"]
71
+
72
+ // Get entitlements (test mode - includes sandbox)
73
+ const entitlements = await helper.getEntitlements(userId, true);
74
+
75
+ // Get full subscription info
76
+ const info = await helper.getSubscriptionInfo(userId, testMode);
77
+ // Returns: { entitlements: ["pro"], subscriptionStartedAt: Date | null }
78
+
79
+ // Check if user has a subscription
80
+ if (!info.entitlements.includes(NONE_ENTITLEMENT)) {
81
+ // User has active subscription
82
+ }
83
+ ```
84
+
85
+ ## Architecture
86
+
87
+ ```
88
+ subscription_service (this package)
89
+
90
+ ratelimit_service (depends on this)
91
+
92
+ shapeshyft_api, sudojo_api, etc.
93
+ ```
94
+
95
+ ## Consuming APIs
96
+
97
+ APIs using this library:
98
+ - shapeshyft_api
99
+ - sudojo_api
100
+ - whisperly_api
101
+ - ratelimit_service
102
+
103
+ ## Publishing
104
+
105
+ ```bash
106
+ bun run verify # All checks
107
+ npm publish # Publish to npm
108
+ ```
@@ -0,0 +1,28 @@
1
+ import type { SubscriptionInfo } from "../types/subscription";
2
+ /**
3
+ * Configuration for SubscriptionHelper.
4
+ */
5
+ export interface SubscriptionHelperConfig {
6
+ /** RevenueCat secret API key (for server-side use) */
7
+ revenueCatApiKey: string;
8
+ /** Base URL for RevenueCat API. Defaults to https://api.revenuecat.com/v1 */
9
+ baseUrl?: string;
10
+ }
11
+ /**
12
+ * Helper class for interacting with RevenueCat API to get user entitlements
13
+ * and subscription information.
14
+ */
15
+ export declare class SubscriptionHelper {
16
+ private readonly apiKey;
17
+ private readonly baseUrl;
18
+ constructor(config: SubscriptionHelperConfig);
19
+ /**
20
+ * Get active entitlement names for a user.
21
+ */
22
+ getEntitlements(userId: string, testMode?: boolean): Promise<string[]>;
23
+ /**
24
+ * Get full subscription info including entitlements and subscription start date.
25
+ */
26
+ getSubscriptionInfo(userId: string, testMode?: boolean): Promise<SubscriptionInfo>;
27
+ }
28
+ //# sourceMappingURL=SubscriptionHelper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubscriptionHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/SubscriptionHelper.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,sDAAsD;IACtD,gBAAgB,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,wBAAwB;IAK5C;;OAEG;IACG,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,MAAM,EAAE,CAAC;IAKpB;;OAEG;IACG,mBAAmB,CACvB,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,gBAAgB,CAAC;CAgE7B"}
@@ -0,0 +1,72 @@
1
+ import { NONE_ENTITLEMENT, } from "../types/entitlements";
2
+ /**
3
+ * Helper class for interacting with RevenueCat API to get user entitlements
4
+ * and subscription information.
5
+ */
6
+ export class SubscriptionHelper {
7
+ constructor(config) {
8
+ this.apiKey = config.revenueCatApiKey;
9
+ this.baseUrl = config.baseUrl ?? "https://api.revenuecat.com/v1";
10
+ }
11
+ /**
12
+ * Get active entitlement names for a user.
13
+ */
14
+ async getEntitlements(userId, testMode = false) {
15
+ const info = await this.getSubscriptionInfo(userId, testMode);
16
+ return info.entitlements;
17
+ }
18
+ /**
19
+ * Get full subscription info including entitlements and subscription start date.
20
+ */
21
+ async getSubscriptionInfo(userId, testMode = false) {
22
+ const url = `${this.baseUrl}/subscribers/${encodeURIComponent(userId)}`;
23
+ const response = await fetch(url, {
24
+ method: "GET",
25
+ headers: {
26
+ Authorization: `Bearer ${this.apiKey}`,
27
+ "Content-Type": "application/json",
28
+ },
29
+ });
30
+ if (response.status === 404) {
31
+ return {
32
+ entitlements: [NONE_ENTITLEMENT],
33
+ subscriptionStartedAt: null,
34
+ };
35
+ }
36
+ if (!response.ok) {
37
+ throw new Error(`RevenueCat API error: ${response.status} ${response.statusText}`);
38
+ }
39
+ const data = (await response.json());
40
+ const entitlements = data.subscriber?.entitlements ?? {};
41
+ const subscriptions = data.subscriber?.subscriptions ?? {};
42
+ const now = new Date();
43
+ const activeEntitlements = [];
44
+ let earliestPurchaseDate = null;
45
+ for (const [name, entitlement] of Object.entries(entitlements)) {
46
+ const isActive = !entitlement.expires_date || new Date(entitlement.expires_date) > now;
47
+ if (!isActive) {
48
+ continue;
49
+ }
50
+ const subscription = subscriptions[entitlement.product_identifier];
51
+ if (!testMode && subscription?.sandbox === true) {
52
+ continue;
53
+ }
54
+ activeEntitlements.push(name);
55
+ const purchaseDate = new Date(entitlement.purchase_date);
56
+ if (!earliestPurchaseDate || purchaseDate < earliestPurchaseDate) {
57
+ earliestPurchaseDate = purchaseDate;
58
+ }
59
+ }
60
+ if (activeEntitlements.length === 0) {
61
+ return {
62
+ entitlements: [NONE_ENTITLEMENT],
63
+ subscriptionStartedAt: null,
64
+ };
65
+ }
66
+ return {
67
+ entitlements: activeEntitlements,
68
+ subscriptionStartedAt: earliestPurchaseDate,
69
+ };
70
+ }
71
+ }
72
+ //# sourceMappingURL=SubscriptionHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubscriptionHelper.js","sourceRoot":"","sources":["../../src/helpers/SubscriptionHelper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { SubscriptionHelper, type SubscriptionHelperConfig, } from "./SubscriptionHelper";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,wBAAwB,GAC9B,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { SubscriptionHelper, } from "./SubscriptionHelper";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAEnB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { NONE_ENTITLEMENT, type RevenueCatEntitlement, type RevenueCatSubscription, type RevenueCatSubscriberResponse, type SubscriptionInfo, } from "./types";
2
+ export { SubscriptionHelper, type SubscriptionHelperConfig, } from "./helpers";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,EACjC,KAAK,gBAAgB,GACtB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,kBAAkB,EAClB,KAAK,wBAAwB,GAC9B,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // Types
2
+ export { NONE_ENTITLEMENT, } from "./types";
3
+ // Helpers
4
+ export { SubscriptionHelper, } from "./helpers";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,OAAO,EACL,gBAAgB,GAKjB,MAAM,SAAS,CAAC;AAEjB,UAAU;AACV,OAAO,EACL,kBAAkB,GAEnB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The special entitlement name for users without any subscription.
3
+ * This is returned when a user has no active entitlements in RevenueCat.
4
+ */
5
+ export declare const NONE_ENTITLEMENT: "none";
6
+ /**
7
+ * RevenueCat entitlement information from the subscriber API.
8
+ */
9
+ export interface RevenueCatEntitlement {
10
+ /** Expiration date in ISO format, or null if lifetime */
11
+ expires_date: string | null;
12
+ /** Grace period expiration date */
13
+ grace_period_expires_date: string | null;
14
+ /** Product identifier in the app store */
15
+ product_identifier: string;
16
+ /** Purchase date in ISO format */
17
+ purchase_date: string;
18
+ }
19
+ /**
20
+ * RevenueCat subscription information from the subscriber API.
21
+ */
22
+ export interface RevenueCatSubscription {
23
+ /** Expiration date in ISO format, or null if lifetime */
24
+ expires_date: string | null;
25
+ /** Purchase date in ISO format */
26
+ purchase_date: string;
27
+ /** Whether this is a sandbox purchase */
28
+ sandbox: boolean;
29
+ /** Store where the purchase was made */
30
+ store: string;
31
+ }
32
+ /**
33
+ * Response shape from RevenueCat's GET /subscribers/{user_id} endpoint.
34
+ */
35
+ export interface RevenueCatSubscriberResponse {
36
+ subscriber: {
37
+ entitlements: {
38
+ [key: string]: RevenueCatEntitlement;
39
+ };
40
+ subscriptions: {
41
+ [key: string]: RevenueCatSubscription;
42
+ };
43
+ };
44
+ }
45
+ //# sourceMappingURL=entitlements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitlements.d.ts","sourceRoot":"","sources":["../../src/types/entitlements.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAG,MAAe,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,yDAAyD;IACzD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mCAAmC;IACnC,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,0CAA0C;IAC1C,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kCAAkC;IAClC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,yDAAyD;IACzD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,kCAAkC;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,UAAU,EAAE;QACV,YAAY,EAAE;YACZ,CAAC,GAAG,EAAE,MAAM,GAAG,qBAAqB,CAAC;SACtC,CAAC;QACF,aAAa,EAAE;YACb,CAAC,GAAG,EAAE,MAAM,GAAG,sBAAsB,CAAC;SACvC,CAAC;KACH,CAAC;CACH"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The special entitlement name for users without any subscription.
3
+ * This is returned when a user has no active entitlements in RevenueCat.
4
+ */
5
+ export const NONE_ENTITLEMENT = "none";
6
+ //# sourceMappingURL=entitlements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitlements.js","sourceRoot":"","sources":["../../src/types/entitlements.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAe,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { NONE_ENTITLEMENT, type RevenueCatEntitlement, type RevenueCatSubscription, type RevenueCatSubscriberResponse, } from "./entitlements";
2
+ export { type SubscriptionInfo } from "./subscription";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,GAClC,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { NONE_ENTITLEMENT, } from "./entitlements";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,GAIjB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Subscription information returned by SubscriptionHelper.
3
+ */
4
+ export interface SubscriptionInfo {
5
+ /** Array of active entitlement names */
6
+ entitlements: string[];
7
+ /** When the subscription started (earliest purchase date), or null if no subscription */
8
+ subscriptionStartedAt: Date | null;
9
+ }
10
+ //# sourceMappingURL=subscription.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../src/types/subscription.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,yFAAyF;IACzF,qBAAqB,EAAE,IAAI,GAAG,IAAI,CAAC;CACpC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=subscription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../src/types/subscription.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@sudobility/subscription_service",
3
+ "version": "1.0.1",
4
+ "description": "Shared subscription management library using RevenueCat for entitlements",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.esm.json",
16
+ "clean": "rm -rf dist",
17
+ "dev": "tsc --watch",
18
+ "test": "vitest run",
19
+ "test:watch": "vitest",
20
+ "lint": "eslint src/",
21
+ "lint:fix": "eslint src/ --fix",
22
+ "typecheck": "tsc --noEmit",
23
+ "format": "prettier --write \"src/**/*.ts\"",
24
+ "format:check": "prettier --check \"src/**/*.ts\"",
25
+ "verify": "bun run typecheck && bun run lint && bun run test && bun run build",
26
+ "prepublishOnly": "bun run clean && bun run verify"
27
+ },
28
+ "files": [
29
+ "dist/**/*",
30
+ "CLAUDE.md"
31
+ ],
32
+ "keywords": [
33
+ "subscription",
34
+ "revenuecat",
35
+ "entitlements",
36
+ "in-app-purchase"
37
+ ],
38
+ "author": "Sudobility",
39
+ "license": "MIT",
40
+ "peerDependencies": {},
41
+ "devDependencies": {
42
+ "vitest": "^4.0.4",
43
+ "@types/bun": "latest",
44
+ "@types/node": "^24.0.0",
45
+ "@typescript-eslint/eslint-plugin": "^8.50.0",
46
+ "@typescript-eslint/parser": "^8.50.0",
47
+ "eslint": "^9.39.0",
48
+ "eslint-plugin-import": "^2.32.0",
49
+ "prettier": "^3.7.0",
50
+ "typescript": "^5.9.0"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ }
55
+ }