@onesub/cli 0.1.4 → 0.1.6
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/dist/index.js +95 -17
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -14,34 +14,50 @@ import { fileURLToPath } from 'node:url';
|
|
|
14
14
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
15
15
|
// dist/index.js → packages/cli/templates
|
|
16
16
|
const TEMPLATES_DIR = resolve(here, '..', 'templates');
|
|
17
|
-
const HELP = `onesub — scaffold a receipt-validation server
|
|
17
|
+
const HELP = `onesub — scaffold and run a receipt-validation server locally
|
|
18
18
|
|
|
19
19
|
Usage:
|
|
20
20
|
onesub init [directory] Create a new onesub project in <directory> (default: .)
|
|
21
|
+
onesub dev [--port N] Start a fully-mocked onesub server for local testing
|
|
21
22
|
onesub --help Show this help
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
docker-compose.yml Postgres + server, schema auto-initialized
|
|
28
|
-
README.md Next-steps guide
|
|
24
|
+
── init ─────────────────────────────────────────────────────────────────
|
|
25
|
+
Creates server.ts, .env.example, package.json, docker-compose.yml, README.md,
|
|
26
|
+
tsconfig.json, .gitignore. After:
|
|
27
|
+
cd <directory> && cp .env.example .env && npm install && npm start
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
── dev ──────────────────────────────────────────────────────────────────
|
|
30
|
+
Zero-config server with mock Apple / Google providers + in-memory stores.
|
|
31
|
+
No credentials needed. Use for local testing, CI, or AI-driven flows:
|
|
32
|
+
POST /onesub/validate { platform, receipt, userId, productId }
|
|
33
|
+
POST /onesub/purchase/validate { ...same + type }
|
|
34
|
+
GET /onesub/status?userId=
|
|
35
|
+
GET /onesub/purchase/status?userId=
|
|
36
|
+
|
|
37
|
+
Receipt patterns (prefix match):
|
|
38
|
+
MOCK_VALID_* / any other string → valid
|
|
39
|
+
MOCK_REVOKED_* → revoked/refunded (422)
|
|
40
|
+
MOCK_EXPIRED_* → 72h expired (422)
|
|
41
|
+
MOCK_INVALID_* / MOCK_BAD_SIG_* → bad signature (422)
|
|
42
|
+
MOCK_NETWORK_ERROR_* → simulated upstream failure (500)
|
|
43
|
+
MOCK_SANDBOX_* → valid but short expiry
|
|
44
|
+
|
|
45
|
+
No persistence — restarting clears all purchases.
|
|
35
46
|
`;
|
|
36
47
|
function parseArgs(argv) {
|
|
37
48
|
const args = argv.slice(2);
|
|
49
|
+
const portFlag = args.findIndex((a) => a === '--port' || a === '-p');
|
|
50
|
+
const port = portFlag >= 0 && args[portFlag + 1] ? parseInt(args[portFlag + 1], 10) : 4100;
|
|
38
51
|
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
39
|
-
return { cmd: 'help', target: '.' };
|
|
52
|
+
return { cmd: 'help', target: '.', port };
|
|
53
|
+
}
|
|
54
|
+
if (args[0] === 'init') {
|
|
55
|
+
return { cmd: 'init', target: args[1] ?? '.', port };
|
|
40
56
|
}
|
|
41
|
-
if (args[0]
|
|
42
|
-
return { cmd: '
|
|
57
|
+
if (args[0] === 'dev') {
|
|
58
|
+
return { cmd: 'dev', target: '.', port };
|
|
43
59
|
}
|
|
44
|
-
return { cmd: '
|
|
60
|
+
return { cmd: 'unknown', target: args[0] ?? '', port };
|
|
45
61
|
}
|
|
46
62
|
async function isEmpty(dir) {
|
|
47
63
|
if (!existsSync(dir))
|
|
@@ -96,12 +112,74 @@ Or with Docker (Postgres + server):
|
|
|
96
112
|
Docs: https://github.com/jeonghwanko/onesub
|
|
97
113
|
`);
|
|
98
114
|
}
|
|
115
|
+
async function dev(port) {
|
|
116
|
+
// Lazy imports — only loaded when the dev command runs, so `onesub init`
|
|
117
|
+
// doesn't pay express + @onesub/server startup cost.
|
|
118
|
+
const express = (await import('express')).default;
|
|
119
|
+
const { createOneSubMiddleware, InMemorySubscriptionStore, InMemoryPurchaseStore } = await import('@onesub/server');
|
|
120
|
+
const app = express();
|
|
121
|
+
app.use(createOneSubMiddleware({
|
|
122
|
+
apple: { bundleId: 'mock.onesub.dev', mockMode: true },
|
|
123
|
+
google: { packageName: 'mock.onesub.dev', mockMode: true },
|
|
124
|
+
database: { url: '' },
|
|
125
|
+
store: new InMemorySubscriptionStore(),
|
|
126
|
+
purchaseStore: new InMemoryPurchaseStore(),
|
|
127
|
+
adminSecret: 'dev-admin-secret',
|
|
128
|
+
logger: console,
|
|
129
|
+
}));
|
|
130
|
+
app.get('/health', (_req, res) => {
|
|
131
|
+
res.json({ ok: true, mode: 'mock', uptime: process.uptime() });
|
|
132
|
+
});
|
|
133
|
+
// Bind to loopback so port-forwarding or stray ngrok exposure doesn't
|
|
134
|
+
// let anyone on the internet hit the mock admin routes with the well-known
|
|
135
|
+
// dev secret.
|
|
136
|
+
const server = app.listen(port, '127.0.0.1', () => {
|
|
137
|
+
console.log(`
|
|
138
|
+
onesub dev server — mocked Apple / Google providers
|
|
139
|
+
───────────────────────────────────────────────────
|
|
140
|
+
http://localhost:${port}/health
|
|
141
|
+
http://localhost:${port}/onesub/*
|
|
142
|
+
|
|
143
|
+
Try it:
|
|
144
|
+
|
|
145
|
+
# validate a mock subscription
|
|
146
|
+
curl -X POST http://localhost:${port}/onesub/validate \\
|
|
147
|
+
-H "Content-Type: application/json" \\
|
|
148
|
+
-d '{"platform":"apple","receipt":"MOCK_VALID_sub","userId":"u1","productId":"pro"}'
|
|
149
|
+
|
|
150
|
+
# validate a mock one-time purchase
|
|
151
|
+
curl -X POST http://localhost:${port}/onesub/purchase/validate \\
|
|
152
|
+
-H "Content-Type: application/json" \\
|
|
153
|
+
-d '{"platform":"google","receipt":"MOCK_VALID_prod","userId":"u1","productId":"premium","type":"non_consumable"}'
|
|
154
|
+
|
|
155
|
+
# check status
|
|
156
|
+
curl 'http://localhost:${port}/onesub/status?userId=u1'
|
|
157
|
+
|
|
158
|
+
# simulate a rejected receipt
|
|
159
|
+
curl -X POST http://localhost:${port}/onesub/purchase/validate \\
|
|
160
|
+
-H "Content-Type: application/json" \\
|
|
161
|
+
-d '{"platform":"apple","receipt":"MOCK_REVOKED","userId":"u1","productId":"premium","type":"non_consumable"}'
|
|
162
|
+
|
|
163
|
+
Admin secret: "dev-admin-secret"
|
|
164
|
+
Ctrl+C to stop. State is in-memory — restarts clear everything.
|
|
165
|
+
`);
|
|
166
|
+
});
|
|
167
|
+
const shutdown = () => {
|
|
168
|
+
console.log('\n[onesub] shutting down...');
|
|
169
|
+
server.close(() => process.exit(0));
|
|
170
|
+
};
|
|
171
|
+
process.on('SIGINT', shutdown);
|
|
172
|
+
process.on('SIGTERM', shutdown);
|
|
173
|
+
}
|
|
99
174
|
async function main() {
|
|
100
|
-
const { cmd, target } = parseArgs(process.argv);
|
|
175
|
+
const { cmd, target, port } = parseArgs(process.argv);
|
|
101
176
|
switch (cmd) {
|
|
102
177
|
case 'help':
|
|
103
178
|
console.log(HELP);
|
|
104
179
|
return;
|
|
180
|
+
case 'dev':
|
|
181
|
+
await dev(port);
|
|
182
|
+
return;
|
|
105
183
|
case 'init':
|
|
106
184
|
await init(target);
|
|
107
185
|
return;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,yCAAyC;AACzC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;AAEvD,MAAM,IAAI,GAAG
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onesub/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "CLI scaffolding for onesub — `npx onesub init` bootstraps a server + Expo app.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,9 @@
|
|
|
35
35
|
},
|
|
36
36
|
"license": "MIT",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@onesub/
|
|
38
|
+
"@onesub/server": "0.7.3",
|
|
39
|
+
"@onesub/shared": "0.3.5",
|
|
40
|
+
"express": "^5.2.1"
|
|
39
41
|
},
|
|
40
42
|
"devDependencies": {
|
|
41
43
|
"@types/node": "^20.17.0",
|