reveclicat 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/LICENSE +21 -0
- package/README.md +186 -0
- package/dist/cli.js +1905 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +2255 -0
- package/dist/index.js +1940 -0
- package/dist/index.js.map +1 -0
- package/examples/express-handler.ts +90 -0
- package/examples/github-action.yml +57 -0
- package/examples/inbox/Caddyfile +5 -0
- package/examples/inbox/Dockerfile +24 -0
- package/package.json +74 -0
- package/scenarios/billing-issue-churns.yaml +18 -0
- package/scenarios/billing-issue-recovers.yaml +20 -0
- package/scenarios/cancel-then-uncancel.yaml +16 -0
- package/scenarios/happy-year.yaml +35 -0
- package/scenarios/trial-churns.yaml +15 -0
- package/scenarios/trial-converts.yaml +15 -0
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "reveclicat",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Unofficial CLI to simulate RevenueCat subscription lifecycles and test webhooks locally and in CI. Not affiliated with RevenueCat, Inc.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"rcc": "dist/cli.js",
|
|
12
|
+
"purr": "dist/cli.js"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"types": "dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"scenarios",
|
|
25
|
+
"examples",
|
|
26
|
+
"README.md",
|
|
27
|
+
"CHANGELOG.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsup",
|
|
32
|
+
"dev": "tsx src/cli.ts",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"test:watch": "vitest",
|
|
35
|
+
"lint": "eslint .",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"check": "npm run typecheck && npm run lint && npm test",
|
|
38
|
+
"prepublishOnly": "npm run check && npm run build"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"revenuecat",
|
|
42
|
+
"webhooks",
|
|
43
|
+
"cli",
|
|
44
|
+
"subscriptions",
|
|
45
|
+
"testing",
|
|
46
|
+
"ci"
|
|
47
|
+
],
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/RadW2020/ReveCliCat.git"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"commander": "15.0.0",
|
|
54
|
+
"yaml": "2.9.0",
|
|
55
|
+
"zod": "4.5.1"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@eslint/js": "10.0.1",
|
|
59
|
+
"@types/express": "5.0.6",
|
|
60
|
+
"@types/node": "26.4.0",
|
|
61
|
+
"eslint": "10.9.1",
|
|
62
|
+
"express": "5.2.1",
|
|
63
|
+
"tsup": "8.5.1",
|
|
64
|
+
"tsx": "4.23.12",
|
|
65
|
+
"typescript": "6.0.3",
|
|
66
|
+
"typescript-eslint": "8.68.0",
|
|
67
|
+
"vitest": "4.1.11"
|
|
68
|
+
},
|
|
69
|
+
"homepage": "https://github.com/RadW2020/ReveCliCat#readme",
|
|
70
|
+
"bugs": {
|
|
71
|
+
"url": "https://github.com/RadW2020/ReveCliCat/issues"
|
|
72
|
+
},
|
|
73
|
+
"author": "RadW2020"
|
|
74
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: billing-issue-churns
|
|
2
|
+
description: Trial converts, the first renewal charge fails, and the grace period ends without recovery
|
|
3
|
+
subscriber:
|
|
4
|
+
app_user_id: auto
|
|
5
|
+
product_id: com.example.premium.monthly
|
|
6
|
+
period: P1M
|
|
7
|
+
trial: P1W
|
|
8
|
+
grace_period: P16D
|
|
9
|
+
steps:
|
|
10
|
+
- event: INITIAL_PURCHASE # trial starts
|
|
11
|
+
- advance: P1W
|
|
12
|
+
- event: RENEWAL # trial → paid
|
|
13
|
+
- advance: P1M
|
|
14
|
+
- event: BILLING_ISSUE # charge failed; grace period opens
|
|
15
|
+
- advance: P16D
|
|
16
|
+
- event: EXPIRATION # expiration_reason: BILLING_ERROR — revoke access
|
|
17
|
+
expect:
|
|
18
|
+
all_responses_status: 200
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: billing-issue-recovers
|
|
2
|
+
description: Trial converts, the first renewal charge fails, and payment recovers within the grace period
|
|
3
|
+
subscriber:
|
|
4
|
+
app_user_id: auto
|
|
5
|
+
product_id: com.example.premium.monthly
|
|
6
|
+
period: P1M
|
|
7
|
+
trial: P1W
|
|
8
|
+
grace_period: P16D
|
|
9
|
+
steps:
|
|
10
|
+
- event: INITIAL_PURCHASE # trial starts
|
|
11
|
+
- advance: P1W
|
|
12
|
+
- event: RENEWAL # trial → paid
|
|
13
|
+
- advance: P1M
|
|
14
|
+
- event: BILLING_ISSUE # charge failed; grace period opens (grace_period_expiration_at_ms)
|
|
15
|
+
- advance: P3D
|
|
16
|
+
- event: RENEWAL # payment recovered; access never lapsed
|
|
17
|
+
expect:
|
|
18
|
+
response_status: 200
|
|
19
|
+
expect:
|
|
20
|
+
all_responses_status: 200
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: cancel-then-uncancel
|
|
2
|
+
description: A paying subscriber cancels, changes their mind before expiry, and the subscription renews normally
|
|
3
|
+
subscriber:
|
|
4
|
+
app_user_id: auto
|
|
5
|
+
product_id: com.example.premium.monthly
|
|
6
|
+
period: P1M
|
|
7
|
+
steps:
|
|
8
|
+
- event: INITIAL_PURCHASE # no trial: goes straight to active
|
|
9
|
+
- advance: P10D
|
|
10
|
+
- event: CANCELLATION # auto-renew off
|
|
11
|
+
- advance: P5D
|
|
12
|
+
- event: UNCANCELLATION # auto-renew back on; entitlements never lost
|
|
13
|
+
- advance: P15D
|
|
14
|
+
- event: RENEWAL # renews at the end of the period as if nothing happened
|
|
15
|
+
expect:
|
|
16
|
+
all_responses_status: 200
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: happy-year
|
|
2
|
+
description: A loyal monthly subscriber with no trial renews every month for a full year (13 events, one virtual year)
|
|
3
|
+
subscriber:
|
|
4
|
+
app_user_id: auto
|
|
5
|
+
product_id: com.example.premium.monthly
|
|
6
|
+
period: P1M
|
|
7
|
+
steps:
|
|
8
|
+
- event: INITIAL_PURCHASE
|
|
9
|
+
- advance: P1M
|
|
10
|
+
- event: RENEWAL # renewal 1
|
|
11
|
+
- advance: P1M
|
|
12
|
+
- event: RENEWAL # renewal 2
|
|
13
|
+
- advance: P1M
|
|
14
|
+
- event: RENEWAL # renewal 3
|
|
15
|
+
- advance: P1M
|
|
16
|
+
- event: RENEWAL # renewal 4
|
|
17
|
+
- advance: P1M
|
|
18
|
+
- event: RENEWAL # renewal 5
|
|
19
|
+
- advance: P1M
|
|
20
|
+
- event: RENEWAL # renewal 6
|
|
21
|
+
- advance: P1M
|
|
22
|
+
- event: RENEWAL # renewal 7
|
|
23
|
+
- advance: P1M
|
|
24
|
+
- event: RENEWAL # renewal 8
|
|
25
|
+
- advance: P1M
|
|
26
|
+
- event: RENEWAL # renewal 9
|
|
27
|
+
- advance: P1M
|
|
28
|
+
- event: RENEWAL # renewal 10
|
|
29
|
+
- advance: P1M
|
|
30
|
+
- event: RENEWAL # renewal 11
|
|
31
|
+
- advance: P1M
|
|
32
|
+
- event: RENEWAL # renewal 12
|
|
33
|
+
expect:
|
|
34
|
+
all_responses_status: 200
|
|
35
|
+
max_response_ms: 2000
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: trial-churns
|
|
2
|
+
description: A one-week free trial is cancelled on day 2; access ends when the trial expires
|
|
3
|
+
subscriber:
|
|
4
|
+
app_user_id: auto
|
|
5
|
+
product_id: com.example.premium.monthly
|
|
6
|
+
period: P1M
|
|
7
|
+
trial: P1W
|
|
8
|
+
steps:
|
|
9
|
+
- event: INITIAL_PURCHASE # trial starts
|
|
10
|
+
- advance: P2D
|
|
11
|
+
- event: CANCELLATION # auto-renew off; access continues until expiry
|
|
12
|
+
- advance: P5D
|
|
13
|
+
- event: EXPIRATION # expiration_reason: UNSUBSCRIBE
|
|
14
|
+
expect:
|
|
15
|
+
all_responses_status: 200
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: trial-converts
|
|
2
|
+
description: A one-week free trial converts to a paid monthly subscription and renews once more
|
|
3
|
+
subscriber:
|
|
4
|
+
app_user_id: auto
|
|
5
|
+
product_id: com.example.premium.monthly
|
|
6
|
+
period: P1M
|
|
7
|
+
trial: P1W
|
|
8
|
+
steps:
|
|
9
|
+
- event: INITIAL_PURCHASE # trial starts (period_type: TRIAL, price 0)
|
|
10
|
+
- advance: P1W
|
|
11
|
+
- event: RENEWAL # trial → paid (is_trial_conversion: true)
|
|
12
|
+
- advance: P1M
|
|
13
|
+
- event: RENEWAL # first regular renewal
|
|
14
|
+
expect:
|
|
15
|
+
all_responses_status: 200
|