@onesub/server 0.6.2 → 0.6.3
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 +63 -0
- package/dist/__tests__/apple-root-ca.test.d.ts +2 -0
- package/dist/__tests__/apple-root-ca.test.d.ts.map +1 -0
- package/dist/__tests__/apple-root-ca.test.js +41 -0
- package/dist/__tests__/apple-root-ca.test.js.map +1 -0
- package/dist/__tests__/schema.test.d.ts +2 -0
- package/dist/__tests__/schema.test.d.ts.map +1 -0
- package/dist/__tests__/schema.test.js +42 -0
- package/dist/__tests__/schema.test.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +4 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +20 -0
- package/dist/logger.js.map +1 -0
- package/dist/providers/apple.d.ts.map +1 -1
- package/dist/providers/apple.js +14 -13
- package/dist/providers/apple.js.map +1 -1
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +12 -11
- package/dist/providers/google.js.map +1 -1
- package/dist/routes/purchase.d.ts.map +1 -1
- package/dist/routes/purchase.js +4 -3
- package/dist/routes/purchase.js.map +1 -1
- package/dist/routes/status.d.ts.map +1 -1
- package/dist/routes/status.js +2 -1
- package/dist/routes/status.js.map +1 -1
- package/dist/routes/validate.d.ts.map +1 -1
- package/dist/routes/validate.js +2 -1
- package/dist/routes/validate.js.map +1 -1
- package/dist/routes/webhook.d.ts +21 -0
- package/dist/routes/webhook.d.ts.map +1 -1
- package/dist/routes/webhook.js +28 -6
- package/dist/routes/webhook.js.map +1 -1
- package/dist/stores/postgres.d.ts.map +1 -1
- package/dist/stores/postgres.js +7 -38
- package/dist/stores/postgres.js.map +1 -1
- package/dist/stores/schema.d.ts +14 -0
- package/dist/stores/schema.d.ts.map +1 -0
- package/dist/stores/schema.js +50 -0
- package/dist/stores/schema.js.map +1 -0
- package/package.json +4 -3
- package/sql/schema.sql +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @onesub/server
|
|
2
|
+
|
|
3
|
+
Express middleware for Apple StoreKit 2 + Google Play Billing receipt validation, webhooks, and subscription/purchase storage. One line to mount.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @onesub/server
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import express from 'express';
|
|
13
|
+
import { createOneSubMiddleware, PostgresSubscriptionStore, PostgresPurchaseStore } from '@onesub/server';
|
|
14
|
+
|
|
15
|
+
const app = express();
|
|
16
|
+
|
|
17
|
+
app.use(createOneSubMiddleware({
|
|
18
|
+
apple: { bundleId: 'com.yourapp.id', sharedSecret: process.env.APPLE_SHARED_SECRET },
|
|
19
|
+
google: { packageName: 'com.yourapp.id', serviceAccountKey: process.env.GOOGLE_SERVICE_ACCOUNT_KEY },
|
|
20
|
+
database: { url: process.env.DATABASE_URL },
|
|
21
|
+
store: new PostgresSubscriptionStore(process.env.DATABASE_URL),
|
|
22
|
+
purchaseStore: new PostgresPurchaseStore(process.env.DATABASE_URL),
|
|
23
|
+
// Optional:
|
|
24
|
+
adminSecret: process.env.ADMIN_SECRET, // enables /onesub/purchase/admin/*
|
|
25
|
+
logger: require('pino')(), // any { info, warn, error } logger
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
app.listen(4100);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Endpoints
|
|
32
|
+
|
|
33
|
+
| Route | Purpose |
|
|
34
|
+
|------|---------|
|
|
35
|
+
| `POST /onesub/validate` | Verify Apple/Google subscription receipt |
|
|
36
|
+
| `GET /onesub/status?userId=` | Check subscription state |
|
|
37
|
+
| `POST /onesub/webhook/apple` | App Store Server Notifications V2 |
|
|
38
|
+
| `POST /onesub/webhook/google` | Google Play RTDN (Pub/Sub push) |
|
|
39
|
+
| `POST /onesub/purchase/validate` | Verify one-time purchase (consumable / non-consumable) |
|
|
40
|
+
| `GET /onesub/purchase/status?userId=` | List user's one-time purchases |
|
|
41
|
+
| `DELETE /onesub/purchase/admin/:userId/:productId` | Wipe a non-consumable (requires `adminSecret`) |
|
|
42
|
+
| `POST /onesub/purchase/admin/grant` | Manually grant a purchase (requires `adminSecret`) |
|
|
43
|
+
| `POST /onesub/purchase/admin/transfer` | Reassign a `transactionId` to a new `userId` (requires `adminSecret`) |
|
|
44
|
+
|
|
45
|
+
## Schema
|
|
46
|
+
|
|
47
|
+
Canonical Postgres DDL shipped at [`sql/schema.sql`](./sql/schema.sql). Apply with `psql -f` or let `store.initSchema()` run it for you on startup.
|
|
48
|
+
|
|
49
|
+
## Security
|
|
50
|
+
|
|
51
|
+
- Apple JWS signature verified end-to-end against **Apple Root CA G3** (as of `0.6.0`)
|
|
52
|
+
- Google RTDN: `Authorization: Bearer` JWT verified against Google JWKS when `pushAudience` is configured
|
|
53
|
+
- `transactionId` ownership enforced — same receipt can't be reused across users (`0.5.0+`)
|
|
54
|
+
- zod input validation + 50 KB body cap
|
|
55
|
+
- Full write-up: [`docs/SECURITY.md`](../../docs/SECURITY.md)
|
|
56
|
+
|
|
57
|
+
## Links
|
|
58
|
+
|
|
59
|
+
- Repo: <https://github.com/jeonghwanko/onesub>
|
|
60
|
+
- Migration guide: [`docs/MIGRATION.md`](../../docs/MIGRATION.md)
|
|
61
|
+
- Changelog: [`CHANGELOG.md`](../../CHANGELOG.md)
|
|
62
|
+
|
|
63
|
+
MIT © onesub contributors.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apple-root-ca.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/apple-root-ca.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { X509Certificate } from 'node:crypto';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import { APPLE_ROOT_CA_G3_PEM, APPLE_ROOT_CA_PEMS, } from '../providers/apple-root-ca.js';
|
|
4
|
+
/**
|
|
5
|
+
* Protects against accidental deletion when Apple publishes Root CA G4 and
|
|
6
|
+
* someone "replaces" G3 instead of appending. StoreKit 2 receipts signed
|
|
7
|
+
* under the older root must keep validating after G4 ships.
|
|
8
|
+
*/
|
|
9
|
+
describe('Apple Root CA bundle', () => {
|
|
10
|
+
it('includes at least one root', () => {
|
|
11
|
+
expect(APPLE_ROOT_CA_PEMS.length).toBeGreaterThan(0);
|
|
12
|
+
});
|
|
13
|
+
it('includes G3 verbatim (retained even after G4 is added)', () => {
|
|
14
|
+
expect(APPLE_ROOT_CA_PEMS).toContain(APPLE_ROOT_CA_G3_PEM);
|
|
15
|
+
});
|
|
16
|
+
it('every bundled root is a parseable X.509 certificate', () => {
|
|
17
|
+
for (const pem of APPLE_ROOT_CA_PEMS) {
|
|
18
|
+
expect(() => new X509Certificate(pem)).not.toThrow();
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
it('every bundled root is currently within its validity window', () => {
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
for (const pem of APPLE_ROOT_CA_PEMS) {
|
|
24
|
+
const cert = new X509Certificate(pem);
|
|
25
|
+
const notBefore = Date.parse(cert.validFrom);
|
|
26
|
+
const notAfter = Date.parse(cert.validTo);
|
|
27
|
+
expect(notBefore).toBeLessThanOrEqual(now);
|
|
28
|
+
expect(notAfter).toBeGreaterThan(now);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
it('G3 is self-signed by Apple (issuer matches subject)', () => {
|
|
32
|
+
const cert = new X509Certificate(APPLE_ROOT_CA_G3_PEM);
|
|
33
|
+
expect(cert.issuer).toBe(cert.subject);
|
|
34
|
+
expect(cert.subject).toContain('Apple Root CA - G3');
|
|
35
|
+
});
|
|
36
|
+
it('no duplicate PEMs in the bundle', () => {
|
|
37
|
+
const set = new Set(APPLE_ROOT_CA_PEMS);
|
|
38
|
+
expect(set.size).toBe(APPLE_ROOT_CA_PEMS.length);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=apple-root-ca.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apple-root-ca.test.js","sourceRoot":"","sources":["../../src/__tests__/apple-root-ca.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AAEvC;;;;GAIG;AACH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,kBAAkB,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;YACrC,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;YACtC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1C,MAAM,CAAC,SAAS,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;YAC3C,MAAM,CAAC,QAAQ,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,oBAAoB,CAAC,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/schema.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { describe, it, expect } from 'vitest';
|
|
5
|
+
import { SUBSCRIPTIONS_SCHEMA_SQL, PURCHASES_SCHEMA_SQL } from '../stores/schema.js';
|
|
6
|
+
/**
|
|
7
|
+
* Parity check between the canonical SQL file (sql/schema.sql) and the
|
|
8
|
+
* embedded string constants used by initSchema() at runtime. If this fails,
|
|
9
|
+
* one of the two was edited without the other.
|
|
10
|
+
*/
|
|
11
|
+
describe('schema SQL parity', () => {
|
|
12
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
// __tests__ lives under src/, so sql/schema.sql is three levels up.
|
|
14
|
+
const schemaPath = join(here, '..', '..', 'sql', 'schema.sql');
|
|
15
|
+
const sqlFile = readFileSync(schemaPath, 'utf8');
|
|
16
|
+
// Normalize both sides to compare by semantics rather than whitespace:
|
|
17
|
+
// strip SQL line comments, collapse whitespace, lowercase.
|
|
18
|
+
const normalize = (sql) => sql
|
|
19
|
+
.split('\n')
|
|
20
|
+
.map((l) => l.replace(/--.*$/, ''))
|
|
21
|
+
.join('\n')
|
|
22
|
+
.replace(/\s+/g, ' ')
|
|
23
|
+
.trim()
|
|
24
|
+
.toLowerCase();
|
|
25
|
+
it('contains both table DDLs in the canonical .sql file', () => {
|
|
26
|
+
const n = normalize(sqlFile);
|
|
27
|
+
expect(n).toContain('create table if not exists onesub_subscriptions');
|
|
28
|
+
expect(n).toContain('create table if not exists onesub_purchases');
|
|
29
|
+
});
|
|
30
|
+
it('subscriptions DDL constant appears verbatim in schema.sql', () => {
|
|
31
|
+
expect(normalize(sqlFile)).toContain(normalize(SUBSCRIPTIONS_SCHEMA_SQL));
|
|
32
|
+
});
|
|
33
|
+
it('purchases DDL constant appears verbatim in schema.sql', () => {
|
|
34
|
+
expect(normalize(sqlFile)).toContain(normalize(PURCHASES_SCHEMA_SQL));
|
|
35
|
+
});
|
|
36
|
+
it('non-consumable partial unique index is present (0.2.0 semantics)', () => {
|
|
37
|
+
const n = normalize(sqlFile);
|
|
38
|
+
expect(n).toContain('create unique index if not exists idx_onesub_purchases_non_consumable');
|
|
39
|
+
expect(n).toContain("where type = 'non_consumable'");
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=schema.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.test.js","sourceRoot":"","sources":["../../src/__tests__/schema.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAErF;;;;GAIG;AACH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,oEAAoE;IACpE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAEjD,uEAAuE;IACvE,2DAA2D;IAC3D,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,EAAE,CAChC,GAAG;SACA,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;SAClC,IAAI,CAAC,IAAI,CAAC;SACV,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;IAEnB,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,iDAAiD,CAAC,CAAC;QACvE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,6CAA6C,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,uEAAuE,CAAC,CAAC;QAC7F,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,+BAA+B,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -49,5 +49,6 @@ export type { SubscriptionStore, PurchaseStore } from './store.js';
|
|
|
49
49
|
export { PostgresSubscriptionStore, PostgresPurchaseStore } from './stores/postgres.js';
|
|
50
50
|
export { validateAppleReceipt } from './providers/apple.js';
|
|
51
51
|
export { validateGoogleReceipt } from './providers/google.js';
|
|
52
|
+
export { setLogger, log } from './logger.js';
|
|
52
53
|
export default createOneSubMiddleware;
|
|
53
54
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAQnE;;GAEG;AACH,MAAM,WAAW,sBAAuB,SAAQ,kBAAkB;IAChE;;;OAGG;IACH,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAqB7E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,sBAAsB,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAW7F;AAGD,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAC9E,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAGxF,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAI9D,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAG7C,eAAe,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { createStatusRouter } from './routes/status.js';
|
|
|
6
6
|
import { createWebhookRouter } from './routes/webhook.js';
|
|
7
7
|
import { createPurchaseRouter } from './routes/purchase.js';
|
|
8
8
|
import { createAdminRouter } from './routes/admin.js';
|
|
9
|
+
import { setLogger } from './logger.js';
|
|
9
10
|
/**
|
|
10
11
|
* Create an Express Router with all OneSub routes mounted.
|
|
11
12
|
*
|
|
@@ -24,6 +25,7 @@ import { createAdminRouter } from './routes/admin.js';
|
|
|
24
25
|
* POST /onesub/webhook/google
|
|
25
26
|
*/
|
|
26
27
|
export function createOneSubMiddleware(config) {
|
|
28
|
+
setLogger(config.logger);
|
|
27
29
|
const store = config.store ?? new InMemorySubscriptionStore();
|
|
28
30
|
const purchaseStore = config.purchaseStore ?? new InMemoryPurchaseStore();
|
|
29
31
|
const router = Router();
|
|
@@ -62,6 +64,9 @@ export { PostgresSubscriptionStore, PostgresPurchaseStore } from './stores/postg
|
|
|
62
64
|
// Provider functions for direct (non-HTTP) usage
|
|
63
65
|
export { validateAppleReceipt } from './providers/apple.js';
|
|
64
66
|
export { validateGoogleReceipt } from './providers/google.js';
|
|
67
|
+
// Logger plumbing — expose so non-middleware callers (direct provider use)
|
|
68
|
+
// can still redirect logs.
|
|
69
|
+
export { setLogger, log } from './logger.js';
|
|
65
70
|
// Default export: the middleware factory
|
|
66
71
|
export default createOneSubMiddleware;
|
|
67
72
|
// Allow running directly: node dist/index.js
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAcnD,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,CAEhE;AAED,eAAO,MAAM,GAAG,EAAE,YAIjB,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-wide logger used by @onesub/server's providers and routes.
|
|
3
|
+
*
|
|
4
|
+
* Defaults to `console`. `createOneSubMiddleware()` calls `setLogger()` once
|
|
5
|
+
* during setup if `config.logger` is provided. All internal call sites should
|
|
6
|
+
* import `log` from this module instead of calling `console.*` directly so
|
|
7
|
+
* operators can redirect logs (pino / winston / bunyan) with a single config
|
|
8
|
+
* setting.
|
|
9
|
+
*/
|
|
10
|
+
let current = console;
|
|
11
|
+
export function setLogger(logger) {
|
|
12
|
+
if (logger)
|
|
13
|
+
current = logger;
|
|
14
|
+
}
|
|
15
|
+
export const log = {
|
|
16
|
+
info: (...args) => current.info(...args),
|
|
17
|
+
warn: (...args) => current.warn(...args),
|
|
18
|
+
error: (...args) => current.error(...args),
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,IAAI,OAAO,GAAiB,OAAO,CAAC;AAEpC,MAAM,UAAU,SAAS,CAAC,MAAgC;IACxD,IAAI,MAAM;QAAE,OAAO,GAAG,MAAM,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAiB;IAC/B,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;CAC3C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple.d.ts","sourceRoot":"","sources":["../../src/providers/apple.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"apple.d.ts","sourceRoot":"","sources":["../../src/providers/apple.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAKrG,KAAK,WAAW,GAAG,WAAW,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;AA2F5D;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,gBAAgB,UAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAuBpF;AAsBD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAmDlC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAsB,8BAA8B,CAClD,iBAAiB,EAAE,MAAM,EACzB,MAAM,EAAE,WAAW,EACnB,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA+EpC;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,wBAAwB,EACjC,mBAAmB,UAAQ,GAC1B,OAAO,CAAC;IAAE,qBAAqB,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA6B9H"}
|
package/dist/providers/apple.js
CHANGED
|
@@ -2,6 +2,7 @@ import { decodeJwt, decodeProtectedHeader, importX509, jwtVerify } from 'jose';
|
|
|
2
2
|
import { X509Certificate } from 'node:crypto';
|
|
3
3
|
import { SUBSCRIPTION_STATUS } from '@onesub/shared';
|
|
4
4
|
import { APPLE_ROOT_CA_PEMS } from './apple-root-ca.js';
|
|
5
|
+
import { log } from '../logger.js';
|
|
5
6
|
/** Maximum age for consumable receipts (72 hours). Older receipts may indicate replay attacks. */
|
|
6
7
|
const MAX_CONSUMABLE_RECEIPT_AGE_MS = 72 * 60 * 60 * 1000;
|
|
7
8
|
function derBase64ToPem(der) {
|
|
@@ -71,7 +72,7 @@ function verifyAppleCertChain(x5c) {
|
|
|
71
72
|
export async function decodeJws(jws, skipVerification = false) {
|
|
72
73
|
if (skipVerification) {
|
|
73
74
|
if (process.env['NODE_ENV'] === 'production') {
|
|
74
|
-
|
|
75
|
+
log.warn('[onesub/apple] WARNING: skipJwsVerification is enabled in production. ' +
|
|
75
76
|
'JWS signatures are NOT being verified. This is a security risk.');
|
|
76
77
|
}
|
|
77
78
|
return decodeJwt(jws);
|
|
@@ -118,7 +119,7 @@ export async function validateAppleReceipt(receipt, config) {
|
|
|
118
119
|
catch (err) {
|
|
119
120
|
const preview = receipt.slice(0, 60);
|
|
120
121
|
const parts = receipt.split('.').length;
|
|
121
|
-
|
|
122
|
+
log.warn('[onesub/apple] Failed to decode receipt as JWS:', err?.message ?? err, `| preview: "${preview}..." (len=${receipt.length}, parts=${parts})`);
|
|
122
123
|
return null;
|
|
123
124
|
}
|
|
124
125
|
if (!tx.originalTransactionId || !tx.productId || !tx.expiresDate) {
|
|
@@ -126,7 +127,7 @@ export async function validateAppleReceipt(receipt, config) {
|
|
|
126
127
|
}
|
|
127
128
|
// Validate bundle ID — missing or mismatched both rejected
|
|
128
129
|
if (!tx.bundleId || tx.bundleId !== config.bundleId) {
|
|
129
|
-
|
|
130
|
+
log.warn('[onesub/apple] Bundle ID mismatch:', tx.bundleId, '!==', config.bundleId);
|
|
130
131
|
return null;
|
|
131
132
|
}
|
|
132
133
|
// Reject Sandbox receipts in production unless explicitly allowed.
|
|
@@ -135,7 +136,7 @@ export async function validateAppleReceipt(receipt, config) {
|
|
|
135
136
|
if (process.env['NODE_ENV'] === 'production' &&
|
|
136
137
|
tx.environment !== 'Production' &&
|
|
137
138
|
process.env['ONESUB_ALLOW_SANDBOX'] !== 'true') {
|
|
138
|
-
|
|
139
|
+
log.warn('[onesub/apple] Sandbox receipt rejected in production:', tx.environment);
|
|
139
140
|
return null;
|
|
140
141
|
}
|
|
141
142
|
const status = deriveStatus(tx, null);
|
|
@@ -170,17 +171,17 @@ export async function validateAppleConsumableReceipt(signedTransaction, config,
|
|
|
170
171
|
const preview = signedTransaction.slice(0, 60);
|
|
171
172
|
const parts = signedTransaction.split('.').length;
|
|
172
173
|
const looksLikeJws = parts === 3;
|
|
173
|
-
|
|
174
|
+
log.warn('[onesub/apple] Failed to decode consumable JWS:', err?.message ?? err, `| receipt preview: "${preview}..." (len=${signedTransaction.length}, parts=${parts}, looksLikeJws=${looksLikeJws})`);
|
|
174
175
|
return null;
|
|
175
176
|
}
|
|
176
177
|
// bundleId must be present and match
|
|
177
178
|
if (!tx.bundleId || tx.bundleId !== config.bundleId) {
|
|
178
|
-
|
|
179
|
+
log.warn('[onesub/apple] Bundle ID mismatch:', tx.bundleId, '!==', config.bundleId);
|
|
179
180
|
return null;
|
|
180
181
|
}
|
|
181
182
|
// Must be a one-time purchase type (not a subscription)
|
|
182
183
|
if (tx.type !== 'Consumable' && tx.type !== 'Non-Consumable') {
|
|
183
|
-
|
|
184
|
+
log.warn('[onesub/apple] Invalid purchase type for product validation:', tx.type);
|
|
184
185
|
return null;
|
|
185
186
|
}
|
|
186
187
|
// Reject Sandbox receipts in production unless explicitly allowed.
|
|
@@ -189,25 +190,25 @@ export async function validateAppleConsumableReceipt(signedTransaction, config,
|
|
|
189
190
|
if (process.env['NODE_ENV'] === 'production' &&
|
|
190
191
|
tx.environment !== 'Production' &&
|
|
191
192
|
process.env['ONESUB_ALLOW_SANDBOX'] !== 'true') {
|
|
192
|
-
|
|
193
|
+
log.warn('[onesub/apple] Sandbox receipt rejected in production:', tx.environment);
|
|
193
194
|
return null;
|
|
194
195
|
}
|
|
195
196
|
if (!tx.productId) {
|
|
196
|
-
|
|
197
|
+
log.warn('[onesub/apple] No productId in transaction');
|
|
197
198
|
return null;
|
|
198
199
|
}
|
|
199
200
|
if (expectedProductId && tx.productId !== expectedProductId) {
|
|
200
|
-
|
|
201
|
+
log.warn('[onesub/apple] Product ID mismatch:', tx.productId, '!==', expectedProductId);
|
|
201
202
|
return null;
|
|
202
203
|
}
|
|
203
204
|
// Reject refunded purchases
|
|
204
205
|
if (tx.revocationDate) {
|
|
205
|
-
|
|
206
|
+
log.warn('[onesub/apple] Purchase was revoked/refunded');
|
|
206
207
|
return null;
|
|
207
208
|
}
|
|
208
209
|
// Reject receipts older than 72 hours (replay attack prevention)
|
|
209
210
|
if (tx.purchaseDate && Date.now() - tx.purchaseDate > MAX_CONSUMABLE_RECEIPT_AGE_MS) {
|
|
210
|
-
|
|
211
|
+
log.warn('[onesub/apple] Consumable receipt too old (>72h)');
|
|
211
212
|
return null;
|
|
212
213
|
}
|
|
213
214
|
// For consumables, transactionId is per-purchase unique.
|
|
@@ -215,7 +216,7 @@ export async function validateAppleConsumableReceipt(signedTransaction, config,
|
|
|
215
216
|
// as the deduplication key for consumables.
|
|
216
217
|
const transactionId = tx.transactionId ?? tx.originalTransactionId;
|
|
217
218
|
if (!transactionId) {
|
|
218
|
-
|
|
219
|
+
log.warn('[onesub/apple] No transactionId in consumable transaction');
|
|
219
220
|
return null;
|
|
220
221
|
}
|
|
221
222
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple.js","sourceRoot":"","sources":["../../src/providers/apple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"apple.js","sourceRoot":"","sources":["../../src/providers/apple.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAItG,KAAK,YAAY,GAAG,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAuB9D;;;GAGG;AACH,QAAA,MAAM,wBAAwB;;;;;;;;;;;;;;CAcpB,CAAC;AAEX,KAAK,sBAAsB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,OAAO,wBAAwB,CAAC,CAAC;AAkLvG;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAmBD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA6BlC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAsB,4BAA4B,CAChD,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,IAAI,GAAE,YAAY,GAAG,gBAAmC,GACvD,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAgDrC;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG;IAC5E,gBAAgB,EAAE,sBAAsB,CAAC;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,IAAI,CAuBP;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,gBAAgB,EAAE,sBAAsB,GAAG,OAAO,CAQ5F;AAED,wBAAgB,4BAA4B,CAAC,gBAAgB,EAAE,sBAAsB,GAAG,OAAO,CAK9F;AAED,wBAAgB,2BAA2B,CAAC,gBAAgB,EAAE,sBAAsB,GAAG,OAAO,CAE7F"}
|
package/dist/providers/google.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SUBSCRIPTION_STATUS } from '@onesub/shared';
|
|
2
|
+
import { log } from '../logger.js';
|
|
2
3
|
/**
|
|
3
4
|
* Google RTDN notification types.
|
|
4
5
|
* https://developer.android.com/google/play/billing/rtdn-reference
|
|
@@ -144,7 +145,7 @@ export async function consumeGoogleProductReceipt(purchaseToken, productId, conf
|
|
|
144
145
|
accessToken = await getCachedAccessToken(config.serviceAccountKey);
|
|
145
146
|
}
|
|
146
147
|
catch (err) {
|
|
147
|
-
|
|
148
|
+
log.warn('[onesub/google] Could not get access token for consume:', err);
|
|
148
149
|
return;
|
|
149
150
|
}
|
|
150
151
|
const url = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/` +
|
|
@@ -157,11 +158,11 @@ export async function consumeGoogleProductReceipt(purchaseToken, productId, conf
|
|
|
157
158
|
});
|
|
158
159
|
if (!resp.ok) {
|
|
159
160
|
const body = await resp.text();
|
|
160
|
-
|
|
161
|
+
log.warn(`[onesub/google] Consume API error ${resp.status}: ${body} — auto-refund risk`);
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
164
|
catch (err) {
|
|
164
|
-
|
|
165
|
+
log.warn('[onesub/google] Consume network error — auto-refund risk:', err);
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
168
|
/**
|
|
@@ -187,7 +188,7 @@ function deriveStatus(purchase) {
|
|
|
187
188
|
*/
|
|
188
189
|
export async function validateGoogleReceipt(receipt, productId, config) {
|
|
189
190
|
if (!config.serviceAccountKey) {
|
|
190
|
-
|
|
191
|
+
log.warn('[onesub/google] No serviceAccountKey provided — cannot call Play API');
|
|
191
192
|
return null;
|
|
192
193
|
}
|
|
193
194
|
let purchase;
|
|
@@ -196,7 +197,7 @@ export async function validateGoogleReceipt(receipt, productId, config) {
|
|
|
196
197
|
purchase = await fetchSubscriptionPurchase(config.packageName, productId, receipt, token);
|
|
197
198
|
}
|
|
198
199
|
catch (err) {
|
|
199
|
-
|
|
200
|
+
log.error('[onesub/google] Receipt validation failed:', err);
|
|
200
201
|
return null;
|
|
201
202
|
}
|
|
202
203
|
const status = deriveStatus(purchase);
|
|
@@ -225,7 +226,7 @@ export async function validateGoogleReceipt(receipt, productId, config) {
|
|
|
225
226
|
*/
|
|
226
227
|
export async function validateGoogleProductReceipt(purchaseToken, productId, config, type = 'non_consumable') {
|
|
227
228
|
if (!config.serviceAccountKey) {
|
|
228
|
-
|
|
229
|
+
log.warn('[onesub/google] No serviceAccountKey — cannot validate product receipt');
|
|
229
230
|
return null;
|
|
230
231
|
}
|
|
231
232
|
let purchase;
|
|
@@ -234,30 +235,30 @@ export async function validateGoogleProductReceipt(purchaseToken, productId, con
|
|
|
234
235
|
purchase = await fetchProductPurchase(config.packageName, productId, purchaseToken, token);
|
|
235
236
|
}
|
|
236
237
|
catch (err) {
|
|
237
|
-
|
|
238
|
+
log.error('[onesub/google] Product receipt validation failed:', err);
|
|
238
239
|
return null;
|
|
239
240
|
}
|
|
240
241
|
// purchaseState 0 = completed (1 = canceled, 2 = pending)
|
|
241
242
|
if (purchase.purchaseState !== 0) {
|
|
242
|
-
|
|
243
|
+
log.warn('[onesub/google] Purchase not completed, state:', purchase.purchaseState);
|
|
243
244
|
return null;
|
|
244
245
|
}
|
|
245
246
|
// For consumables: consumptionState 1 means already consumed by a previous request.
|
|
246
247
|
// This is the primary replay-attack signal for consumables on Android.
|
|
247
248
|
if (type === 'consumable' && purchase.consumptionState === 1) {
|
|
248
|
-
|
|
249
|
+
log.warn('[onesub/google] Consumable already consumed — possible replay attack');
|
|
249
250
|
return null;
|
|
250
251
|
}
|
|
251
252
|
// Reject receipts older than 72 hours
|
|
252
253
|
if (purchase.purchaseTimeMillis) {
|
|
253
254
|
const purchaseTime = parseInt(purchase.purchaseTimeMillis, 10);
|
|
254
255
|
if (Date.now() - purchaseTime > MAX_PRODUCT_RECEIPT_AGE_MS) {
|
|
255
|
-
|
|
256
|
+
log.warn('[onesub/google] Product receipt too old (>72h)');
|
|
256
257
|
return null;
|
|
257
258
|
}
|
|
258
259
|
}
|
|
259
260
|
if (!purchase.orderId) {
|
|
260
|
-
|
|
261
|
+
log.warn('[onesub/google] No orderId in product purchase');
|
|
261
262
|
return null;
|
|
262
263
|
}
|
|
263
264
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"purchase.d.ts","sourceRoot":"","sources":["../../src/routes/purchase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,KAAK,EAIV,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"purchase.d.ts","sourceRoot":"","sources":["../../src/routes/purchase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,KAAK,EAIV,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAkBjD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,kBAAkB,EAC1B,aAAa,EAAE,aAAa,GAC3B,MAAM,CAwNR"}
|
package/dist/routes/purchase.js
CHANGED
|
@@ -3,6 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
import { ROUTES, PURCHASE_TYPE } from '@onesub/shared';
|
|
4
4
|
import { validateAppleConsumableReceipt } from '../providers/apple.js';
|
|
5
5
|
import { validateGoogleProductReceipt, consumeGoogleProductReceipt } from '../providers/google.js';
|
|
6
|
+
import { log } from '../logger.js';
|
|
6
7
|
const validatePurchaseSchema = z.object({
|
|
7
8
|
platform: z.enum(['apple', 'google']),
|
|
8
9
|
receipt: z.string().min(1).max(10000),
|
|
@@ -121,7 +122,7 @@ export function createPurchaseRouter(config, purchaseStore) {
|
|
|
121
122
|
if (existing.userId !== userId) {
|
|
122
123
|
if (type === PURCHASE_TYPE.NON_CONSUMABLE) {
|
|
123
124
|
await purchaseStore.reassignPurchase(transactionId, userId);
|
|
124
|
-
|
|
125
|
+
log.info(`[onesub/purchase] reassigned transaction ${transactionId} from ${existing.userId} to ${userId}`);
|
|
125
126
|
}
|
|
126
127
|
else {
|
|
127
128
|
const response = {
|
|
@@ -165,7 +166,7 @@ export function createPurchaseRouter(config, purchaseStore) {
|
|
|
165
166
|
res.status(200).json(response);
|
|
166
167
|
}
|
|
167
168
|
catch (err) {
|
|
168
|
-
|
|
169
|
+
log.error('[onesub/purchase/validate] Unexpected error:', err);
|
|
169
170
|
const response = {
|
|
170
171
|
valid: false,
|
|
171
172
|
purchase: null,
|
|
@@ -204,7 +205,7 @@ export function createPurchaseRouter(config, purchaseStore) {
|
|
|
204
205
|
res.status(200).json(response);
|
|
205
206
|
}
|
|
206
207
|
catch (err) {
|
|
207
|
-
|
|
208
|
+
log.error('[onesub/purchase/status] Store error:', err);
|
|
208
209
|
res.status(500).json({ purchases: [], error: 'Internal server error' });
|
|
209
210
|
}
|
|
210
211
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"purchase.js","sourceRoot":"","sources":["../../src/routes/purchase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"purchase.js","sourceRoot":"","sources":["../../src/routes/purchase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AACnG,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACrC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;IACrC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAClC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACrC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,UAAU,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;CACvE,CAAC,CAAC;AAEH,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAClC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;CACjD,CAAC,CAAC;AAEH,MAAM,UAAU,oBAAoB,CAClC,MAA0B,EAC1B,aAA4B;IAE5B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QAC1E,IAAI,IAA4C,CAAC;QAEjD,IAAI,CAAC;YACH,IAAI,GAAG,sBAAsB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC9B,MAAM,QAAQ,GAA6B;oBACzC,KAAK,EAAE,KAAK;oBACZ,QAAQ,EAAE,IAAI;oBACd,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAsB,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;iBACxE,CAAC;gBACF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC/B,OAAO;YACT,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;QAE5D,IAAI,CAAC;YACH,0EAA0E;YAC1E,IAAI,IAAI,KAAK,aAAa,CAAC,cAAc,EAAE,CAAC;gBAC1C,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;gBACzE,IAAI,YAAY,EAAE,CAAC;oBACjB,MAAM,QAAQ,GAA6B;wBACzC,KAAK,EAAE,KAAK;wBACZ,QAAQ,EAAE,IAAI;wBACd,KAAK,EAAE,8BAA8B;qBACtC,CAAC;oBACF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC/B,OAAO;gBACT,CAAC;YACH,CAAC;YAED,4EAA4E;YAC5E,wEAAwE;YACxE,8EAA8E;YAC9E,oEAAoE;YACpE,IAAI,aAAa,GAAkB,IAAI,CAAC;YACxC,IAAI,WAAW,GAAW,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAEnD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;gBACzB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;oBAClB,MAAM,QAAQ,GAA6B;wBACzC,KAAK,EAAE,KAAK;wBACZ,QAAQ,EAAE,IAAI;wBACd,KAAK,EAAE,kCAAkC;qBAC1C,CAAC;oBACF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC/B,OAAO;gBACT,CAAC;gBACD,MAAM,MAAM,GAAG,MAAM,8BAA8B,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;gBACtF,IAAI,MAAM,EAAE,CAAC;oBACX,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;oBACrC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;gBACnC,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;oBACnB,MAAM,QAAQ,GAA6B;wBACzC,KAAK,EAAE,KAAK;wBACZ,QAAQ,EAAE,IAAI;wBACd,KAAK,EAAE,mCAAmC;qBAC3C,CAAC;oBACF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC/B,OAAO;gBACT,CAAC;gBACD,MAAM,MAAM,GAAG,MAAM,4BAA4B,CAC/C,OAAO,EACP,SAAS,EACT,MAAM,CAAC,MAAM,EACb,IAAI,KAAK,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,gBAAgB,CACpE,CAAC;gBACF,IAAI,MAAM,EAAE,CAAC;oBACX,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;oBACrC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;gBACnC,CAAC;YACH,CAAC;YAED,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,MAAM,QAAQ,GAA6B;oBACzC,KAAK,EAAE,KAAK;oBACZ,QAAQ,EAAE,IAAI;oBACd,KAAK,EAAE,2BAA2B;iBACnC,CAAC;gBACF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC/B,OAAO;YACT,CAAC;YAED,oDAAoD;YACpD,0DAA0D;YAC1D,oEAAoE;YACpE,sEAAsE;YACtE,mDAAmD;YACnD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,0BAA0B,CAAC,aAAa,CAAC,CAAC;YAC/E,IAAI,MAAM,GAAuB,KAAK,CAAC;YAEvC,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,GAAG,UAAU,CAAC;gBACpB,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;oBAC/B,IAAI,IAAI,KAAK,aAAa,CAAC,cAAc,EAAE,CAAC;wBAC1C,MAAM,aAAa,CAAC,gBAAgB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;wBAC5D,GAAG,CAAC,IAAI,CACN,4CAA4C,aAAa,SAAS,QAAQ,CAAC,MAAM,OAAO,MAAM,EAAE,CACjG,CAAC;oBACJ,CAAC;yBAAM,CAAC;wBACN,MAAM,QAAQ,GAA6B;4BACzC,KAAK,EAAE,KAAK;4BACZ,QAAQ,EAAE,IAAI;4BACd,KAAK,EAAE,mCAAmC;yBAC3C,CAAC;wBACF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;wBAC/B,OAAO;oBACT,CAAC;gBACH,CAAC;gBACD,MAAM,QAAQ,GAA6B;oBACzC,KAAK,EAAE,IAAI;oBACX,QAAQ,EAAE,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE;oBACjC,MAAM;iBACP,CAAC;gBACF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC/B,OAAO;YACT,CAAC;YAED,MAAM,QAAQ,GAAiB;gBAC7B,MAAM;gBACN,SAAS;gBACT,QAAQ;gBACR,IAAI;gBACJ,aAAa;gBACb,WAAW;gBACX,QAAQ,EAAE,CAAC;aACZ,CAAC;YAEF,MAAM,aAAa,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAE3C,mFAAmF;YACnF,kFAAkF;YAClF,qEAAqE;YACrE,IAAI,QAAQ,KAAK,QAAQ,IAAI,IAAI,KAAK,aAAa,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAChF,KAAK,2BAA2B,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YACtE,CAAC;YAED,MAAM,QAAQ,GAA6B;gBACzC,KAAK,EAAE,IAAI;gBACX,QAAQ;gBACR,MAAM;aACP,CAAC;YACF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,8CAA8C,EAAE,GAAG,CAAC,CAAC;YAC/D,MAAM,QAAQ,GAA6B;gBACzC,KAAK,EAAE,KAAK;gBACZ,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,kDAAkD;aAC1D,CAAC;YACF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QACvE,IAAI,KAAgD,CAAC;QAErD,IAAI,CAAC;YACH,KAAK,GAAG,yBAAyB,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC9B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACnB,SAAS,EAAE,EAAE;oBACb,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAsB,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;iBACxE,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;QAEpC,IAAI,CAAC;YACH,IAAI,SAAS,GAAG,MAAM,aAAa,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;YAEjE,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;YACjE,CAAC;YAED,MAAM,QAAQ,GAA2B,EAAE,SAAS,EAAE,CAAC;YACvD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;YACxD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/routes/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/routes/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGrD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CA2CnE"}
|
package/dist/routes/status.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
2
|
import { ROUTES, SUBSCRIPTION_STATUS } from '@onesub/shared';
|
|
3
|
+
import { log } from '../logger.js';
|
|
3
4
|
export function createStatusRouter(store) {
|
|
4
5
|
const router = Router();
|
|
5
6
|
/**
|
|
@@ -32,7 +33,7 @@ export function createStatusRouter(store) {
|
|
|
32
33
|
res.status(200).json(response);
|
|
33
34
|
}
|
|
34
35
|
catch (err) {
|
|
35
|
-
|
|
36
|
+
log.error('[onesub/status] Store error:', err);
|
|
36
37
|
res.status(500).json({ active: false, subscription: null, error: 'Internal server error' });
|
|
37
38
|
}
|
|
38
39
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/routes/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/routes/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,MAAM,UAAU,kBAAkB,CAAC,KAAwB;IACzD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB;;;;;OAKG;IACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QAC9D,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAEnC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC1C,MAAM,QAAQ,GAAmB,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;YACvE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,sCAAsC,EAAE,CAAC,CAAC;YACrF,OAAO;QACT,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAmB,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;YACvE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,uCAAuC,EAAE,CAAC,CAAC;YACtF,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAE5C,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,QAAQ,GAAmB,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;gBACvE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC/B,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,KAAK,mBAAmB,CAAC,MAAM,CAAC;YACzD,MAAM,QAAQ,GAAmB,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;YAC/D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;YAC/C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/routes/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,KAAK,EAA2B,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAElF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/routes/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,KAAK,EAA2B,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAElF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAYrD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,iBAAiB,GACvB,MAAM,CAoFR"}
|
package/dist/routes/validate.js
CHANGED
|
@@ -3,6 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
import { ROUTES } from '@onesub/shared';
|
|
4
4
|
import { validateAppleReceipt } from '../providers/apple.js';
|
|
5
5
|
import { validateGoogleReceipt } from '../providers/google.js';
|
|
6
|
+
import { log } from '../logger.js';
|
|
6
7
|
const validateSchema = z.object({
|
|
7
8
|
platform: z.enum(['apple', 'google']),
|
|
8
9
|
receipt: z.string().min(1).max(10000),
|
|
@@ -77,7 +78,7 @@ export function createValidateRouter(config, store) {
|
|
|
77
78
|
res.status(200).json(response);
|
|
78
79
|
}
|
|
79
80
|
catch (err) {
|
|
80
|
-
|
|
81
|
+
log.error('[onesub/validate] Unexpected error:', err);
|
|
81
82
|
const response = {
|
|
82
83
|
valid: false,
|
|
83
84
|
subscription: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/routes/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/routes/validate.ts"],"names":[],"mappings":"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"}
|
package/dist/routes/webhook.d.ts
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
2
|
import type { OneSubServerConfig } from '@onesub/shared';
|
|
3
3
|
import type { SubscriptionStore } from '../store.js';
|
|
4
|
+
/**
|
|
5
|
+
* Retry / durability semantics.
|
|
6
|
+
*
|
|
7
|
+
* Both Apple (App Store Server Notifications V2) and Google (Pub/Sub RTDN)
|
|
8
|
+
* retry on any non-2xx response:
|
|
9
|
+
* - Apple: up to 5 retries over ~3 days, exponential backoff.
|
|
10
|
+
* - Google: per-Pub/Sub-subscription retry policy (default: retries until
|
|
11
|
+
* the message is ack'd or the retention window expires, up to 7 days).
|
|
12
|
+
*
|
|
13
|
+
* This router uses that built-in retry instead of a local dead-letter queue:
|
|
14
|
+
*
|
|
15
|
+
* 4xx — the payload is unusable (missing signedPayload, bad signature,
|
|
16
|
+
* package mismatch). Return 4xx so the sender does NOT retry, since
|
|
17
|
+
* the same request would fail again.
|
|
18
|
+
* 5xx — a transient failure on our side (DB down, network to Play API).
|
|
19
|
+
* Return 5xx so Apple / Google retry the notification for us.
|
|
20
|
+
* 2xx — processed, or intentionally ignored (e.g. test notification).
|
|
21
|
+
*
|
|
22
|
+
* If you need an explicit DLQ, wrap `store.save()` with your own error
|
|
23
|
+
* handler before passing the store to `createOneSubMiddleware()`.
|
|
24
|
+
*/
|
|
4
25
|
export declare function createWebhookRouter(config: OneSubServerConfig, store: SubscriptionStore): Router;
|
|
5
26
|
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/routes/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,KAAK,EAGV,kBAAkB,EAEnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/routes/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,KAAK,EAGV,kBAAkB,EAEnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA2ErD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,iBAAiB,GACvB,MAAM,CAoLR"}
|
package/dist/routes/webhook.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createRemoteJWKSet, jwtVerify } from 'jose';
|
|
|
3
3
|
import { ROUTES, SUBSCRIPTION_STATUS } from '@onesub/shared';
|
|
4
4
|
import { decodeAppleNotification, decodeJws } from '../providers/apple.js';
|
|
5
5
|
import { decodeGoogleNotification, validateGoogleReceipt, isGoogleActiveNotification, isGoogleCanceledNotification, isGoogleExpiredNotification, } from '../providers/google.js';
|
|
6
|
+
import { log } from '../logger.js';
|
|
6
7
|
/**
|
|
7
8
|
* Google's public JWKS endpoint used to verify Pub/Sub push JWT tokens.
|
|
8
9
|
*/
|
|
@@ -60,6 +61,27 @@ const APPLE_EXPIRED_TYPES = new Set([
|
|
|
60
61
|
'EXPIRED',
|
|
61
62
|
'GRACE_PERIOD_EXPIRED',
|
|
62
63
|
]);
|
|
64
|
+
/**
|
|
65
|
+
* Retry / durability semantics.
|
|
66
|
+
*
|
|
67
|
+
* Both Apple (App Store Server Notifications V2) and Google (Pub/Sub RTDN)
|
|
68
|
+
* retry on any non-2xx response:
|
|
69
|
+
* - Apple: up to 5 retries over ~3 days, exponential backoff.
|
|
70
|
+
* - Google: per-Pub/Sub-subscription retry policy (default: retries until
|
|
71
|
+
* the message is ack'd or the retention window expires, up to 7 days).
|
|
72
|
+
*
|
|
73
|
+
* This router uses that built-in retry instead of a local dead-letter queue:
|
|
74
|
+
*
|
|
75
|
+
* 4xx — the payload is unusable (missing signedPayload, bad signature,
|
|
76
|
+
* package mismatch). Return 4xx so the sender does NOT retry, since
|
|
77
|
+
* the same request would fail again.
|
|
78
|
+
* 5xx — a transient failure on our side (DB down, network to Play API).
|
|
79
|
+
* Return 5xx so Apple / Google retry the notification for us.
|
|
80
|
+
* 2xx — processed, or intentionally ignored (e.g. test notification).
|
|
81
|
+
*
|
|
82
|
+
* If you need an explicit DLQ, wrap `store.save()` with your own error
|
|
83
|
+
* handler before passing the store to `createOneSubMiddleware()`.
|
|
84
|
+
*/
|
|
63
85
|
export function createWebhookRouter(config, store) {
|
|
64
86
|
const router = Router();
|
|
65
87
|
/**
|
|
@@ -82,7 +104,7 @@ export function createWebhookRouter(config, store) {
|
|
|
82
104
|
payload = await decodeJws(body.signedPayload, config.apple?.skipJwsVerification);
|
|
83
105
|
}
|
|
84
106
|
catch (err) {
|
|
85
|
-
|
|
107
|
+
log.error('[onesub/webhook/apple] Failed to decode signedPayload:', err);
|
|
86
108
|
res.status(400).json({ error: 'Invalid signedPayload' });
|
|
87
109
|
return;
|
|
88
110
|
}
|
|
@@ -117,12 +139,12 @@ export function createWebhookRouter(config, store) {
|
|
|
117
139
|
else {
|
|
118
140
|
// We have no record of this transaction — log and acknowledge.
|
|
119
141
|
// This can happen for purchases made before the server started.
|
|
120
|
-
|
|
142
|
+
log.warn('[onesub/webhook/apple] Received notification for unknown transaction:', originalTransactionId);
|
|
121
143
|
}
|
|
122
144
|
res.status(200).json({ received: true });
|
|
123
145
|
}
|
|
124
146
|
catch (err) {
|
|
125
|
-
|
|
147
|
+
log.error('[onesub/webhook/apple] Store update error:', err);
|
|
126
148
|
res.status(500).json({ error: 'Failed to update subscription' });
|
|
127
149
|
}
|
|
128
150
|
});
|
|
@@ -156,7 +178,7 @@ export function createWebhookRouter(config, store) {
|
|
|
156
178
|
const { notificationType, purchaseToken, subscriptionId, packageName } = notification;
|
|
157
179
|
// Validate the package name matches our config
|
|
158
180
|
if (config.google?.packageName && packageName !== config.google.packageName) {
|
|
159
|
-
|
|
181
|
+
log.warn('[onesub/webhook/google] Package name mismatch:', packageName, '!==', config.google.packageName);
|
|
160
182
|
res.status(400).json({ error: 'Package name mismatch' });
|
|
161
183
|
return;
|
|
162
184
|
}
|
|
@@ -204,13 +226,13 @@ export function createWebhookRouter(config, store) {
|
|
|
204
226
|
}
|
|
205
227
|
}
|
|
206
228
|
else {
|
|
207
|
-
|
|
229
|
+
log.warn('[onesub/webhook/google] Unknown purchase token and no serviceAccountKey to re-fetch:', purchaseToken);
|
|
208
230
|
}
|
|
209
231
|
}
|
|
210
232
|
res.status(200).json({ received: true });
|
|
211
233
|
}
|
|
212
234
|
catch (err) {
|
|
213
|
-
|
|
235
|
+
log.error('[onesub/webhook/google] Error handling notification:', err);
|
|
214
236
|
res.status(500).json({ error: 'Failed to process notification' });
|
|
215
237
|
}
|
|
216
238
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/routes/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAOrD,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,4BAA4B,EAC5B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/routes/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAOrD,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,4BAA4B,EAC5B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC;;GAEG;AACH,MAAM,eAAe,GAAG,4CAA4C,CAAC;AAErE,iFAAiF;AACjF,kCAAkC;AAClC,IAAI,UAAU,GAAiD,IAAI,CAAC;AAEpE,SAAS,aAAa;IACpB,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,UAAU,GAAG,kBAAkB,CAAC,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,qBAAqB,CAAC,GAAY,EAAE,gBAAwB;IACzE,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAChD,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACxE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACxD,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACjC,YAAY;IACZ,WAAW;IACX,aAAa;IACb,gBAAgB;CACjB,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,QAAQ;IACR,QAAQ;IACR,qBAAqB;CACtB,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,SAAS;IACT,sBAAsB;CACvB,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAA0B,EAC1B,KAAwB;IAExB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB;;;;;OAKG;IACH,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QACtE,8DAA8D;QAC9D,0EAA0E;QAC1E,gFAAgF;QAChF,MAAM,IAAI,GAAG,GAAG,CAAC,IAAkC,CAAC;QAEpD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;YACzD,OAAO;QACT,CAAC;QAED,IAAI,OAAiC,CAAC;QAEtC,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,SAAS,CACvB,IAAI,CAAC,aAAa,EAClB,MAAM,CAAC,KAAK,EAAE,mBAAmB,CAClC,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,wDAAwD,EAAE,GAAG,CAAC,CAAC;YACzE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;YACzD,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;QAC1F,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,oEAAoE;YACpE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,OAAO;QACT,CAAC;QAED,MAAM,EAAE,qBAAqB,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;QACxE,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;QAElD,mFAAmF;QACnF,4DAA4D;QAC5D,IAAI,WAAW,GAA+B,MAAM,CAAC;QACrD,IAAI,oBAAoB,CAAC,GAAG,CAAC,gBAAgB,CAAC;YAAE,WAAW,GAAG,mBAAmB,CAAC,QAAQ,CAAC;aACtF,IAAI,mBAAmB,CAAC,GAAG,CAAC,gBAAgB,CAAC;YAAE,WAAW,GAAG,mBAAmB,CAAC,OAAO,CAAC;aACzF,IAAI,kBAAkB,CAAC,GAAG,CAAC,gBAAgB,CAAC;YAAE,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC;QAE5F,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC,qBAAqB,CAAC,CAAC;YACvE,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,OAAO,GAAqB;oBAChC,GAAG,QAAQ;oBACX,MAAM,EAAE,WAAW;oBACnB,SAAS;oBACT,SAAS;iBACV,CAAC;gBACF,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,+DAA+D;gBAC/D,gEAAgE;gBAChE,GAAG,CAAC,IAAI,CACN,uEAAuE,EACvE,qBAAqB,CACtB,CAAC;YACJ,CAAC;YAED,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,4CAA4C,EAAE,GAAG,CAAC,CAAC;YAC7D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH;;;;;OAKG;IACH,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QACvE,4DAA4D;QAC5D,oFAAoF;QACpF,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC;YAChC,MAAM,aAAa,GAAG,MAAM,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YACnF,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;gBAChD,OAAO;YACT,CAAC;QACH,CAAC;QAED,MAAM,IAAI,GAAG,GAAG,CAAC,IAA0C,CAAC;QAE5D,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;YACxB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC;YACxD,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,wBAAwB,CAAC,IAAiC,CAAC,CAAC;QAEjF,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,kDAAkD;YAClD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,OAAO;QACT,CAAC;QAED,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,YAAY,CAAC;QAEtF,+CAA+C;QAC/C,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,IAAI,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YAC5E,GAAG,CAAC,IAAI,CACN,gDAAgD,EAChD,WAAW,EACX,KAAK,EACL,MAAM,CAAC,MAAM,CAAC,WAAW,CAC1B,CAAC;YACF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;YACzD,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,oFAAoF;YACpF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;YAE/D,IAAI,WAAuC,CAAC;YAC5C,IAAI,0BAA0B,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACjD,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC;YAC3C,CAAC;iBAAM,IAAI,4BAA4B,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAC1D,WAAW,GAAG,mBAAmB,CAAC,QAAQ,CAAC;YAC7C,CAAC;iBAAM,IAAI,2BAA2B,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACzD,WAAW,GAAG,mBAAmB,CAAC,OAAO,CAAC;YAC5C,CAAC;iBAAM,CAAC;gBACN,gFAAgF;gBAChF,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC,6CAA6C;YACzF,CAAC;YAED,IAAI,QAAQ,EAAE,CAAC;gBACb,6DAA6D;gBAC7D,IAAI,OAAO,GAAqB,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;gBAErE,IAAI,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC;oBACrC,MAAM,KAAK,GAAG,MAAM,qBAAqB,CAAC,aAAa,EAAE,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;oBACxF,IAAI,KAAK,EAAE,CAAC;wBACV,OAAO,GAAG;4BACR,GAAG,QAAQ;4BACX,MAAM,EAAE,KAAK,CAAC,MAAM;4BACpB,SAAS,EAAE,KAAK,CAAC,SAAS;4BAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;yBAC3B,CAAC;oBACJ,CAAC;gBACH,CAAC;gBAED,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,mEAAmE;gBACnE,IAAI,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC;oBACrC,MAAM,KAAK,GAAG,MAAM,qBAAqB,CAAC,aAAa,EAAE,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;oBACxF,IAAI,KAAK,EAAE,CAAC;wBACV,uEAAuE;wBACvE,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC;wBAC7B,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAC1B,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,IAAI,CACN,sFAAsF,EACtF,aAAa,CACd,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,sDAAsD,EAAE,GAAG,CAAC,CAAC;YACvE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/stores/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/stores/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGpE;;;;;;;;;;;;;GAaG;AACH,qBAAa,yBAA0B,YAAW,iBAAiB;IAIrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAF7C,OAAO,CAAC,WAAW,CAA2C;gBAEjC,gBAAgB,EAAE,MAAM;IAErD,OAAO,CAAC,OAAO;IAkBf;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAOjC;;;;OAIG;IACG,IAAI,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BhD;;;;;;OAMG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAanE;;;OAGG;IACG,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAWxE,uDAAuD;IACjD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAsB,YAAW,aAAa;IAG7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAF7C,OAAO,CAAC,WAAW,CAA2C;gBAEjC,gBAAgB,EAAE,MAAM;IAErD,OAAO,CAAC,OAAO;IAgBf;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,YAAY,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCnD,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAY7D,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAWtE,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYjE,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS5E,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IASzE,uDAAuD;IACjD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B"}
|
package/dist/stores/postgres.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SUBSCRIPTIONS_SCHEMA_SQL, PURCHASES_SCHEMA_SQL } from './schema.js';
|
|
1
2
|
/**
|
|
2
3
|
* PostgreSQL-backed subscription store.
|
|
3
4
|
*
|
|
@@ -40,22 +41,9 @@ export class PostgresSubscriptionStore {
|
|
|
40
41
|
*/
|
|
41
42
|
async initSchema() {
|
|
42
43
|
const pool = await this.getPool();
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
user_id TEXT NOT NULL,
|
|
47
|
-
product_id TEXT NOT NULL,
|
|
48
|
-
platform TEXT NOT NULL,
|
|
49
|
-
status TEXT NOT NULL,
|
|
50
|
-
expires_at TIMESTAMPTZ NOT NULL,
|
|
51
|
-
purchased_at TIMESTAMPTZ NOT NULL,
|
|
52
|
-
will_renew BOOLEAN NOT NULL,
|
|
53
|
-
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
CREATE INDEX IF NOT EXISTS idx_onesub_subscriptions_user_id
|
|
57
|
-
ON onesub_subscriptions (user_id, updated_at DESC);
|
|
58
|
-
`);
|
|
44
|
+
// DDL mirrored in packages/server/sql/schema.sql — kept in sync by
|
|
45
|
+
// schema parity test. Edit both (or only the .sql file and regenerate).
|
|
46
|
+
await pool.query(SUBSCRIPTIONS_SCHEMA_SQL);
|
|
59
47
|
}
|
|
60
48
|
/**
|
|
61
49
|
* Upserts the given subscription.
|
|
@@ -161,28 +149,9 @@ export class PostgresPurchaseStore {
|
|
|
161
149
|
*/
|
|
162
150
|
async initSchema() {
|
|
163
151
|
const pool = await this.getPool();
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
user_id TEXT NOT NULL,
|
|
168
|
-
product_id TEXT NOT NULL,
|
|
169
|
-
platform TEXT NOT NULL,
|
|
170
|
-
type TEXT NOT NULL,
|
|
171
|
-
quantity INTEGER NOT NULL DEFAULT 1,
|
|
172
|
-
purchased_at TIMESTAMPTZ NOT NULL,
|
|
173
|
-
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
CREATE INDEX IF NOT EXISTS idx_onesub_purchases_user_id
|
|
177
|
-
ON onesub_purchases (user_id, purchased_at DESC);
|
|
178
|
-
|
|
179
|
-
CREATE INDEX IF NOT EXISTS idx_onesub_purchases_user_product
|
|
180
|
-
ON onesub_purchases (user_id, product_id);
|
|
181
|
-
|
|
182
|
-
CREATE UNIQUE INDEX IF NOT EXISTS idx_onesub_purchases_non_consumable
|
|
183
|
-
ON onesub_purchases (user_id, product_id)
|
|
184
|
-
WHERE type = 'non_consumable';
|
|
185
|
-
`);
|
|
152
|
+
// DDL mirrored in packages/server/sql/schema.sql — kept in sync by
|
|
153
|
+
// schema parity test.
|
|
154
|
+
await pool.query(PURCHASES_SCHEMA_SQL);
|
|
186
155
|
}
|
|
187
156
|
async savePurchase(purchase) {
|
|
188
157
|
const pool = await this.getPool();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/stores/postgres.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/stores/postgres.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded Postgres DDL mirrored from `packages/server/sql/schema.sql`.
|
|
3
|
+
*
|
|
4
|
+
* The `.sql` file is the single human-facing source of truth (mounted into
|
|
5
|
+
* docker-entrypoint-initdb.d, runnable via `psql -f`, readable by DBAs).
|
|
6
|
+
* These constants exist so that `initSchema()` can run without a filesystem
|
|
7
|
+
* lookup after the package is bundled/installed.
|
|
8
|
+
*
|
|
9
|
+
* A test in `__tests__/schema.test.ts` asserts that the two stay in sync —
|
|
10
|
+
* if you edit one, update the other (or the test will fail).
|
|
11
|
+
*/
|
|
12
|
+
export declare const SUBSCRIPTIONS_SCHEMA_SQL: string;
|
|
13
|
+
export declare const PURCHASES_SCHEMA_SQL: string;
|
|
14
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/stores/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,wBAAwB,QAe7B,CAAC;AAET,eAAO,MAAM,oBAAoB,QAqBzB,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded Postgres DDL mirrored from `packages/server/sql/schema.sql`.
|
|
3
|
+
*
|
|
4
|
+
* The `.sql` file is the single human-facing source of truth (mounted into
|
|
5
|
+
* docker-entrypoint-initdb.d, runnable via `psql -f`, readable by DBAs).
|
|
6
|
+
* These constants exist so that `initSchema()` can run without a filesystem
|
|
7
|
+
* lookup after the package is bundled/installed.
|
|
8
|
+
*
|
|
9
|
+
* A test in `__tests__/schema.test.ts` asserts that the two stay in sync —
|
|
10
|
+
* if you edit one, update the other (or the test will fail).
|
|
11
|
+
*/
|
|
12
|
+
export const SUBSCRIPTIONS_SCHEMA_SQL = `
|
|
13
|
+
CREATE TABLE IF NOT EXISTS onesub_subscriptions (
|
|
14
|
+
original_transaction_id TEXT PRIMARY KEY,
|
|
15
|
+
user_id TEXT NOT NULL,
|
|
16
|
+
product_id TEXT NOT NULL,
|
|
17
|
+
platform TEXT NOT NULL,
|
|
18
|
+
status TEXT NOT NULL,
|
|
19
|
+
expires_at TIMESTAMPTZ NOT NULL,
|
|
20
|
+
purchased_at TIMESTAMPTZ NOT NULL,
|
|
21
|
+
will_renew BOOLEAN NOT NULL,
|
|
22
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
CREATE INDEX IF NOT EXISTS idx_onesub_subscriptions_user_id
|
|
26
|
+
ON onesub_subscriptions (user_id, updated_at DESC);
|
|
27
|
+
`.trim();
|
|
28
|
+
export const PURCHASES_SCHEMA_SQL = `
|
|
29
|
+
CREATE TABLE IF NOT EXISTS onesub_purchases (
|
|
30
|
+
transaction_id TEXT PRIMARY KEY,
|
|
31
|
+
user_id TEXT NOT NULL,
|
|
32
|
+
product_id TEXT NOT NULL,
|
|
33
|
+
platform TEXT NOT NULL,
|
|
34
|
+
type TEXT NOT NULL,
|
|
35
|
+
quantity INTEGER NOT NULL DEFAULT 1,
|
|
36
|
+
purchased_at TIMESTAMPTZ NOT NULL,
|
|
37
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
CREATE INDEX IF NOT EXISTS idx_onesub_purchases_user_id
|
|
41
|
+
ON onesub_purchases (user_id, purchased_at DESC);
|
|
42
|
+
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_onesub_purchases_user_product
|
|
44
|
+
ON onesub_purchases (user_id, product_id);
|
|
45
|
+
|
|
46
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_onesub_purchases_non_consumable
|
|
47
|
+
ON onesub_purchases (user_id, product_id)
|
|
48
|
+
WHERE type = 'non_consumable';
|
|
49
|
+
`.trim();
|
|
50
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/stores/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;CAevC,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBnC,CAAC,IAAI,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onesub/server",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "Server-side receipt validation middleware for react-native-iap. Apple StoreKit 2 + Google Play Billing. One line.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"files": [
|
|
9
|
-
"dist"
|
|
9
|
+
"dist",
|
|
10
|
+
"sql"
|
|
10
11
|
],
|
|
11
12
|
"scripts": {
|
|
12
13
|
"build": "tsc",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
},
|
|
41
42
|
"license": "MIT",
|
|
42
43
|
"dependencies": {
|
|
43
|
-
"@onesub/shared": "0.3.
|
|
44
|
+
"@onesub/shared": "0.3.2",
|
|
44
45
|
"express": "^4.19.2",
|
|
45
46
|
"jose": "^5.9.6",
|
|
46
47
|
"zod": "^3.23.0"
|
package/sql/schema.sql
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
-- @onesub/server — canonical Postgres schema
|
|
2
|
+
--
|
|
3
|
+
-- This file is the single source of truth for the database schema used by
|
|
4
|
+
-- `PostgresSubscriptionStore` and `PostgresPurchaseStore`.
|
|
5
|
+
--
|
|
6
|
+
-- How it's applied:
|
|
7
|
+
-- 1. Automatically: `store.initSchema()` executes the same DDL at runtime
|
|
8
|
+
-- (embedded in packages/server/src/stores/postgres.ts). A parity test
|
|
9
|
+
-- asserts the two stay in sync.
|
|
10
|
+
-- 2. Manually: `psql $DATABASE_URL -f packages/server/sql/schema.sql`
|
|
11
|
+
-- 3. Via docker-compose: mounted into
|
|
12
|
+
-- `/docker-entrypoint-initdb.d/` so a fresh Postgres container
|
|
13
|
+
-- bootstraps automatically on first boot.
|
|
14
|
+
--
|
|
15
|
+
-- All statements are idempotent (`IF NOT EXISTS`) and safe to re-run.
|
|
16
|
+
|
|
17
|
+
-- ─── Subscriptions (auto-renewable) ──────────────────────────────────────────
|
|
18
|
+
CREATE TABLE IF NOT EXISTS onesub_subscriptions (
|
|
19
|
+
original_transaction_id TEXT PRIMARY KEY,
|
|
20
|
+
user_id TEXT NOT NULL,
|
|
21
|
+
product_id TEXT NOT NULL,
|
|
22
|
+
platform TEXT NOT NULL,
|
|
23
|
+
status TEXT NOT NULL,
|
|
24
|
+
expires_at TIMESTAMPTZ NOT NULL,
|
|
25
|
+
purchased_at TIMESTAMPTZ NOT NULL,
|
|
26
|
+
will_renew BOOLEAN NOT NULL,
|
|
27
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
CREATE INDEX IF NOT EXISTS idx_onesub_subscriptions_user_id
|
|
31
|
+
ON onesub_subscriptions (user_id, updated_at DESC);
|
|
32
|
+
|
|
33
|
+
-- ─── One-time purchases (consumable + non-consumable) ────────────────────────
|
|
34
|
+
-- `transaction_id` is the primary key: enforces one row per Apple/Google
|
|
35
|
+
-- transaction, which is what makes receipt-reuse across users detectable
|
|
36
|
+
-- (see @onesub/server@0.5.0 — TRANSACTION_BELONGS_TO_OTHER_USER).
|
|
37
|
+
--
|
|
38
|
+
-- The partial unique index on (user_id, product_id) WHERE type = 'non_consumable'
|
|
39
|
+
-- enforces "purchased once" semantics for non-consumables while still
|
|
40
|
+
-- allowing consumables (coins, credits) to accumulate rows per user.
|
|
41
|
+
CREATE TABLE IF NOT EXISTS onesub_purchases (
|
|
42
|
+
transaction_id TEXT PRIMARY KEY,
|
|
43
|
+
user_id TEXT NOT NULL,
|
|
44
|
+
product_id TEXT NOT NULL,
|
|
45
|
+
platform TEXT NOT NULL,
|
|
46
|
+
type TEXT NOT NULL,
|
|
47
|
+
quantity INTEGER NOT NULL DEFAULT 1,
|
|
48
|
+
purchased_at TIMESTAMPTZ NOT NULL,
|
|
49
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
CREATE INDEX IF NOT EXISTS idx_onesub_purchases_user_id
|
|
53
|
+
ON onesub_purchases (user_id, purchased_at DESC);
|
|
54
|
+
|
|
55
|
+
CREATE INDEX IF NOT EXISTS idx_onesub_purchases_user_product
|
|
56
|
+
ON onesub_purchases (user_id, product_id);
|
|
57
|
+
|
|
58
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_onesub_purchases_non_consumable
|
|
59
|
+
ON onesub_purchases (user_id, product_id)
|
|
60
|
+
WHERE type = 'non_consumable';
|