@onesub/server 0.11.4 → 0.12.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.
Files changed (127) hide show
  1. package/README.md +119 -2
  2. package/dist/__tests__/cache.test.d.ts +2 -0
  3. package/dist/__tests__/cache.test.d.ts.map +1 -0
  4. package/dist/__tests__/openapi.test.d.ts +2 -0
  5. package/dist/__tests__/openapi.test.d.ts.map +1 -0
  6. package/dist/__tests__/redis-store.test.d.ts +2 -0
  7. package/dist/__tests__/redis-store.test.d.ts.map +1 -0
  8. package/dist/__tests__/webhook-apple.test.d.ts +12 -0
  9. package/dist/__tests__/webhook-apple.test.d.ts.map +1 -0
  10. package/dist/__tests__/webhook-events.test.d.ts +2 -0
  11. package/dist/__tests__/webhook-events.test.d.ts.map +1 -0
  12. package/dist/__tests__/webhook-google.test.d.ts +13 -0
  13. package/dist/__tests__/webhook-google.test.d.ts.map +1 -0
  14. package/dist/__tests__/webhook-queue.test.d.ts +2 -0
  15. package/dist/__tests__/webhook-queue.test.d.ts.map +1 -0
  16. package/dist/cache.d.ts +32 -0
  17. package/dist/cache.d.ts.map +1 -0
  18. package/dist/index.cjs +3084 -0
  19. package/dist/index.cjs.map +1 -0
  20. package/dist/index.d.ts +34 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +3045 -118
  23. package/dist/index.js.map +1 -1
  24. package/dist/openapi.d.ts +41 -0
  25. package/dist/openapi.d.ts.map +1 -0
  26. package/dist/providers/apple.d.ts +1 -1
  27. package/dist/providers/apple.d.ts.map +1 -1
  28. package/dist/providers/google.d.ts.map +1 -1
  29. package/dist/routes/admin.d.ts +2 -1
  30. package/dist/routes/admin.d.ts.map +1 -1
  31. package/dist/routes/webhook-apple.d.ts +6 -0
  32. package/dist/routes/webhook-apple.d.ts.map +1 -0
  33. package/dist/routes/webhook-google.d.ts +7 -0
  34. package/dist/routes/webhook-google.d.ts.map +1 -0
  35. package/dist/routes/webhook.d.ts +6 -18
  36. package/dist/routes/webhook.d.ts.map +1 -1
  37. package/dist/stores/redis.d.ts +60 -0
  38. package/dist/stores/redis.d.ts.map +1 -0
  39. package/dist/stores/schema.d.ts.map +1 -1
  40. package/dist/tracing.d.ts +32 -0
  41. package/dist/tracing.d.ts.map +1 -0
  42. package/dist/webhook-events.d.ts +58 -0
  43. package/dist/webhook-events.d.ts.map +1 -0
  44. package/dist/webhook-queue.d.ts +92 -0
  45. package/dist/webhook-queue.d.ts.map +1 -0
  46. package/package.json +33 -4
  47. package/sql/schema.sql +10 -0
  48. package/dist/__tests__/admin-customer-detail.test.js +0 -146
  49. package/dist/__tests__/admin-customer-detail.test.js.map +0 -1
  50. package/dist/__tests__/admin-list-subscriptions.test.js +0 -192
  51. package/dist/__tests__/admin-list-subscriptions.test.js.map +0 -1
  52. package/dist/__tests__/admin-subscription-detail.test.js +0 -112
  53. package/dist/__tests__/admin-subscription-detail.test.js.map +0 -1
  54. package/dist/__tests__/apple-root-ca.test.js +0 -41
  55. package/dist/__tests__/apple-root-ca.test.js.map +0 -1
  56. package/dist/__tests__/apple-status-api.test.js +0 -345
  57. package/dist/__tests__/apple-status-api.test.js.map +0 -1
  58. package/dist/__tests__/entitlements.test.js +0 -268
  59. package/dist/__tests__/entitlements.test.js.map +0 -1
  60. package/dist/__tests__/error-codes.test.js +0 -168
  61. package/dist/__tests__/error-codes.test.js.map +0 -1
  62. package/dist/__tests__/fetch-hardening.test.js +0 -192
  63. package/dist/__tests__/fetch-hardening.test.js.map +0 -1
  64. package/dist/__tests__/google-paused.test.js +0 -126
  65. package/dist/__tests__/google-paused.test.js.map +0 -1
  66. package/dist/__tests__/google-price-change.test.js +0 -186
  67. package/dist/__tests__/google-price-change.test.js.map +0 -1
  68. package/dist/__tests__/google-subscriptions-v2.test.js +0 -206
  69. package/dist/__tests__/google-subscriptions-v2.test.js.map +0 -1
  70. package/dist/__tests__/lifecycle-scenarios.test.js +0 -579
  71. package/dist/__tests__/lifecycle-scenarios.test.js.map +0 -1
  72. package/dist/__tests__/lifecycle-states.test.js +0 -423
  73. package/dist/__tests__/lifecycle-states.test.js.map +0 -1
  74. package/dist/__tests__/linked-purchase-token.test.js +0 -227
  75. package/dist/__tests__/linked-purchase-token.test.js.map +0 -1
  76. package/dist/__tests__/metrics.test.js +0 -340
  77. package/dist/__tests__/metrics.test.js.map +0 -1
  78. package/dist/__tests__/mock-provider.test.js +0 -188
  79. package/dist/__tests__/mock-provider.test.js.map +0 -1
  80. package/dist/__tests__/paused-auto-resume.test.js +0 -162
  81. package/dist/__tests__/paused-auto-resume.test.js.map +0 -1
  82. package/dist/__tests__/providers.test.js +0 -321
  83. package/dist/__tests__/providers.test.js.map +0 -1
  84. package/dist/__tests__/refund-policy.test.js +0 -317
  85. package/dist/__tests__/refund-policy.test.js.map +0 -1
  86. package/dist/__tests__/schema.test.js +0 -46
  87. package/dist/__tests__/schema.test.js.map +0 -1
  88. package/dist/__tests__/store.test.js +0 -172
  89. package/dist/__tests__/store.test.js.map +0 -1
  90. package/dist/__tests__/test-utils.js +0 -30
  91. package/dist/__tests__/test-utils.js.map +0 -1
  92. package/dist/__tests__/webhook-refund.test.js +0 -313
  93. package/dist/__tests__/webhook-refund.test.js.map +0 -1
  94. package/dist/errors.js +0 -19
  95. package/dist/errors.js.map +0 -1
  96. package/dist/http.js +0 -36
  97. package/dist/http.js.map +0 -1
  98. package/dist/logger.js +0 -20
  99. package/dist/logger.js.map +0 -1
  100. package/dist/providers/apple-root-ca.js +0 -38
  101. package/dist/providers/apple-root-ca.js.map +0 -1
  102. package/dist/providers/apple.js +0 -499
  103. package/dist/providers/apple.js.map +0 -1
  104. package/dist/providers/google.js +0 -493
  105. package/dist/providers/google.js.map +0 -1
  106. package/dist/providers/mock.js +0 -93
  107. package/dist/providers/mock.js.map +0 -1
  108. package/dist/routes/admin.js +0 -251
  109. package/dist/routes/admin.js.map +0 -1
  110. package/dist/routes/entitlements.js +0 -130
  111. package/dist/routes/entitlements.js.map +0 -1
  112. package/dist/routes/metrics.js +0 -281
  113. package/dist/routes/metrics.js.map +0 -1
  114. package/dist/routes/purchase.js +0 -187
  115. package/dist/routes/purchase.js.map +0 -1
  116. package/dist/routes/status.js +0 -55
  117. package/dist/routes/status.js.map +0 -1
  118. package/dist/routes/validate.js +0 -70
  119. package/dist/routes/validate.js.map +0 -1
  120. package/dist/routes/webhook.js +0 -441
  121. package/dist/routes/webhook.js.map +0 -1
  122. package/dist/store.js +0 -145
  123. package/dist/store.js.map +0 -1
  124. package/dist/stores/postgres.js +0 -329
  125. package/dist/stores/postgres.js.map +0 -1
  126. package/dist/stores/schema.js +0 -57
  127. package/dist/stores/schema.js.map +0 -1
@@ -1,329 +0,0 @@
1
- import { SUBSCRIPTIONS_SCHEMA_SQL, PURCHASES_SCHEMA_SQL } from './schema.js';
2
- /**
3
- * PostgreSQL-backed subscription store.
4
- *
5
- * Uses raw `pg` (node-postgres) to avoid Prisma / ORM dependencies.
6
- * The `pg` package must be installed separately:
7
- *
8
- * npm install pg
9
- * npm install -D @types/pg
10
- *
11
- * Usage:
12
- * const store = new PostgresSubscriptionStore(process.env.DATABASE_URL!);
13
- * await store.initSchema();
14
- * app.use(createOneSubMiddleware({ ...config, store }));
15
- */
16
- export class PostgresSubscriptionStore {
17
- connectionString;
18
- // Lazy-loaded to avoid requiring `pg` unless this class is actually instantiated.
19
- poolPromise = null;
20
- constructor(connectionString) {
21
- this.connectionString = connectionString;
22
- }
23
- getPool() {
24
- if (!this.poolPromise) {
25
- this.poolPromise = (async () => {
26
- // Dynamic import so that `pg` is an optional peer dependency —
27
- // consumers who only use InMemorySubscriptionStore pay no cost.
28
- const pg = await import('pg').catch(() => {
29
- throw new Error('[onesub] PostgresSubscriptionStore requires the `pg` package. ' +
30
- 'Run: npm install pg');
31
- });
32
- const Pool = pg.default?.Pool ?? pg.Pool;
33
- return new Pool({ connectionString: this.connectionString, max: 10 });
34
- })();
35
- }
36
- return this.poolPromise;
37
- }
38
- /**
39
- * Creates the `onesub_subscriptions` table and indexes if they do not
40
- * already exist. Call this once during application startup.
41
- */
42
- async initSchema() {
43
- const pool = await this.getPool();
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);
47
- }
48
- /**
49
- * Upserts the given subscription.
50
- * If a row with the same `original_transaction_id` already exists it is
51
- * updated in place; otherwise a new row is inserted.
52
- */
53
- async save(sub) {
54
- const pool = await this.getPool();
55
- await pool.query(`INSERT INTO onesub_subscriptions
56
- (original_transaction_id, user_id, product_id, platform, status,
57
- expires_at, purchased_at, will_renew, linked_purchase_token,
58
- auto_resume_time, updated_at)
59
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NOW())
60
- ON CONFLICT (original_transaction_id) DO UPDATE SET
61
- user_id = EXCLUDED.user_id,
62
- product_id = EXCLUDED.product_id,
63
- platform = EXCLUDED.platform,
64
- status = EXCLUDED.status,
65
- expires_at = EXCLUDED.expires_at,
66
- purchased_at = EXCLUDED.purchased_at,
67
- will_renew = EXCLUDED.will_renew,
68
- linked_purchase_token = EXCLUDED.linked_purchase_token,
69
- auto_resume_time = EXCLUDED.auto_resume_time,
70
- updated_at = NOW()`, [
71
- sub.originalTransactionId,
72
- sub.userId,
73
- sub.productId,
74
- sub.platform,
75
- sub.status,
76
- sub.expiresAt,
77
- sub.purchasedAt,
78
- sub.willRenew,
79
- sub.linkedPurchaseToken ?? null,
80
- sub.autoResumeTime ?? null,
81
- ]);
82
- }
83
- /**
84
- * Returns the most recently updated subscription for the given user, or
85
- * `null` if no record exists.
86
- *
87
- * "Most recent" is determined by `updated_at DESC` so that the latest
88
- * status change is always returned when a user has multiple subscriptions.
89
- */
90
- async getByUserId(userId) {
91
- const pool = await this.getPool();
92
- const result = await pool.query(`SELECT *
93
- FROM onesub_subscriptions
94
- WHERE user_id = $1
95
- ORDER BY updated_at DESC
96
- LIMIT 1`, [userId]);
97
- return result.rows.length > 0 ? rowToSubscriptionInfo(result.rows[0]) : null;
98
- }
99
- /**
100
- * Returns every subscription record for the user (across all productIds),
101
- * ordered most-recent-first. Used by entitlement evaluation, which needs to
102
- * see all of a user's active subscriptions to decide whether any of them
103
- * grants the requested entitlement.
104
- */
105
- async getAllByUserId(userId) {
106
- const pool = await this.getPool();
107
- const result = await pool.query(`SELECT *
108
- FROM onesub_subscriptions
109
- WHERE user_id = $1
110
- ORDER BY updated_at DESC`, [userId]);
111
- return result.rows.map(rowToSubscriptionInfo);
112
- }
113
- /**
114
- * Returns the subscription identified by `originalTransactionId` (the
115
- * table primary key), or `null` if it does not exist.
116
- */
117
- async getByTransactionId(txId) {
118
- const pool = await this.getPool();
119
- const result = await pool.query(`SELECT *
120
- FROM onesub_subscriptions
121
- WHERE original_transaction_id = $1`, [txId]);
122
- return result.rows.length > 0 ? rowToSubscriptionInfo(result.rows[0]) : null;
123
- }
124
- async listAll() {
125
- const pool = await this.getPool();
126
- const result = await pool.query(`SELECT * FROM onesub_subscriptions`);
127
- return result.rows.map(rowToSubscriptionInfo);
128
- }
129
- async listFiltered(opts) {
130
- const pool = await this.getPool();
131
- const limit = opts.limit ?? 50;
132
- const offset = opts.offset ?? 0;
133
- // Build the WHERE clause incrementally. Each non-undefined filter adds an
134
- // AND condition with a parameterised value (no SQL injection surface).
135
- const conditions = [];
136
- const params = [];
137
- if (opts.userId) {
138
- params.push(opts.userId);
139
- conditions.push(`user_id = $${params.length}`);
140
- }
141
- if (opts.status) {
142
- params.push(opts.status);
143
- conditions.push(`status = $${params.length}`);
144
- }
145
- if (opts.productId) {
146
- params.push(opts.productId);
147
- conditions.push(`product_id = $${params.length}`);
148
- }
149
- if (opts.platform) {
150
- params.push(opts.platform);
151
- conditions.push(`platform = $${params.length}`);
152
- }
153
- const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';
154
- // Run the count + page in parallel — both queries hit the same WHERE clause
155
- // so they share the index plan, and we save a round-trip.
156
- const [countResult, pageResult] = await Promise.all([
157
- pool.query(`SELECT COUNT(*)::text AS total FROM onesub_subscriptions ${where}`, params),
158
- pool.query(`SELECT * FROM onesub_subscriptions ${where}
159
- ORDER BY updated_at DESC
160
- LIMIT $${params.length + 1} OFFSET $${params.length + 2}`, [...params, limit, offset]),
161
- ]);
162
- return {
163
- items: pageResult.rows.map(rowToSubscriptionInfo),
164
- total: parseInt(countResult.rows[0]?.total ?? '0', 10),
165
- limit,
166
- offset,
167
- };
168
- }
169
- /** Gracefully close the underlying connection pool. */
170
- async close() {
171
- if (this.poolPromise) {
172
- const pool = await this.poolPromise;
173
- await pool.end();
174
- this.poolPromise = null;
175
- }
176
- }
177
- }
178
- /**
179
- * PostgreSQL-backed purchase store for consumables and non-consumables.
180
- *
181
- * Uses raw `pg` (node-postgres). The `pg` package must be installed separately:
182
- *
183
- * npm install pg
184
- * npm install -D @types/pg
185
- *
186
- * Usage:
187
- * const store = new PostgresPurchaseStore(process.env.DATABASE_URL!);
188
- * await store.initSchema();
189
- * app.use(createOneSubMiddleware({ ...config, purchaseStore: store }));
190
- */
191
- export class PostgresPurchaseStore {
192
- connectionString;
193
- poolPromise = null;
194
- constructor(connectionString) {
195
- this.connectionString = connectionString;
196
- }
197
- getPool() {
198
- if (!this.poolPromise) {
199
- this.poolPromise = (async () => {
200
- const pg = await import('pg').catch(() => {
201
- throw new Error('[onesub] PostgresPurchaseStore requires the `pg` package. ' +
202
- 'Run: npm install pg');
203
- });
204
- const Pool = pg.default?.Pool ?? pg.Pool;
205
- return new Pool({ connectionString: this.connectionString, max: 10 });
206
- })();
207
- }
208
- return this.poolPromise;
209
- }
210
- /**
211
- * Creates the `onesub_purchases` table and indexes if they do not already exist.
212
- * Call this once during application startup.
213
- */
214
- async initSchema() {
215
- const pool = await this.getPool();
216
- // DDL mirrored in packages/server/sql/schema.sql — kept in sync by
217
- // schema parity test.
218
- await pool.query(PURCHASES_SCHEMA_SQL);
219
- }
220
- async savePurchase(purchase) {
221
- const pool = await this.getPool();
222
- // transactionId is PRIMARY KEY. If the same transactionId already belongs
223
- // to a different userId we refuse the save — the second call is either a
224
- // fraudulent receipt-reuse attempt or a legitimate device migration that
225
- // should go through an explicit admin transfer instead. Returning silently
226
- // (the old ON CONFLICT DO NOTHING behavior) leaves the server reporting
227
- // valid:true while the DB has no row for the current user, which lets the
228
- // caller keep re-"buying" forever.
229
- const existing = await pool.query(`SELECT user_id FROM onesub_purchases WHERE transaction_id = $1`, [purchase.transactionId]);
230
- if (existing.rows.length > 0) {
231
- const owner = existing.rows[0].user_id;
232
- if (owner !== purchase.userId) {
233
- const err = new Error('TRANSACTION_BELONGS_TO_OTHER_USER');
234
- err.code = 'TRANSACTION_BELONGS_TO_OTHER_USER';
235
- throw err;
236
- }
237
- // same user — idempotent no-op
238
- return;
239
- }
240
- await pool.query(`INSERT INTO onesub_purchases
241
- (transaction_id, user_id, product_id, platform, type, quantity, purchased_at)
242
- VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
243
- purchase.transactionId,
244
- purchase.userId,
245
- purchase.productId,
246
- purchase.platform,
247
- purchase.type,
248
- purchase.quantity,
249
- purchase.purchasedAt,
250
- ]);
251
- }
252
- async getPurchasesByUserId(userId) {
253
- const pool = await this.getPool();
254
- const result = await pool.query(`SELECT *
255
- FROM onesub_purchases
256
- WHERE user_id = $1
257
- ORDER BY purchased_at DESC`, [userId]);
258
- return result.rows.map(rowToPurchaseInfo);
259
- }
260
- async getPurchaseByTransactionId(txId) {
261
- const pool = await this.getPool();
262
- const result = await pool.query(`SELECT *
263
- FROM onesub_purchases
264
- WHERE transaction_id = $1`, [txId]);
265
- return result.rows.length > 0 ? rowToPurchaseInfo(result.rows[0]) : null;
266
- }
267
- async hasPurchased(userId, productId) {
268
- const pool = await this.getPool();
269
- const result = await pool.query(`SELECT EXISTS(
270
- SELECT 1 FROM onesub_purchases
271
- WHERE user_id = $1 AND product_id = $2
272
- ) AS exists`, [userId, productId]);
273
- return result.rows[0]?.exists === true;
274
- }
275
- async reassignPurchase(transactionId, newUserId) {
276
- const pool = await this.getPool();
277
- const result = await pool.query(`UPDATE onesub_purchases SET user_id = $2 WHERE transaction_id = $1`, [transactionId, newUserId]);
278
- return (result.rowCount ?? 0) > 0;
279
- }
280
- async deletePurchases(userId, productId) {
281
- const pool = await this.getPool();
282
- const result = await pool.query(`DELETE FROM onesub_purchases WHERE user_id = $1 AND product_id = $2`, [userId, productId]);
283
- return result.rowCount ?? 0;
284
- }
285
- async deletePurchaseByTransactionId(transactionId) {
286
- const pool = await this.getPool();
287
- const result = await pool.query(`DELETE FROM onesub_purchases WHERE transaction_id = $1`, [transactionId]);
288
- return (result.rowCount ?? 0) > 0;
289
- }
290
- async listAll() {
291
- const pool = await this.getPool();
292
- const result = await pool.query(`SELECT * FROM onesub_purchases`);
293
- return result.rows.map(rowToPurchaseInfo);
294
- }
295
- /** Gracefully close the underlying connection pool. */
296
- async close() {
297
- if (this.poolPromise) {
298
- const pool = await this.poolPromise;
299
- await pool.end();
300
- this.poolPromise = null;
301
- }
302
- }
303
- }
304
- function rowToSubscriptionInfo(row) {
305
- return {
306
- originalTransactionId: row.original_transaction_id,
307
- userId: row.user_id,
308
- productId: row.product_id,
309
- platform: row.platform,
310
- status: row.status,
311
- expiresAt: row.expires_at.toISOString(),
312
- purchasedAt: row.purchased_at.toISOString(),
313
- willRenew: row.will_renew,
314
- linkedPurchaseToken: row.linked_purchase_token ?? undefined,
315
- autoResumeTime: row.auto_resume_time?.toISOString(),
316
- };
317
- }
318
- function rowToPurchaseInfo(row) {
319
- return {
320
- transactionId: row.transaction_id,
321
- userId: row.user_id,
322
- productId: row.product_id,
323
- platform: row.platform,
324
- type: row.type,
325
- quantity: row.quantity,
326
- purchasedAt: row.purchased_at.toISOString(),
327
- };
328
- }
329
- //# sourceMappingURL=postgres.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/stores/postgres.ts"],"names":[],"mappings":"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"}
@@ -1,57 +0,0 @@
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
- linked_purchase_token TEXT,
23
- auto_resume_time TIMESTAMPTZ,
24
- updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
25
- );
26
-
27
- CREATE INDEX IF NOT EXISTS idx_onesub_subscriptions_user_id
28
- ON onesub_subscriptions (user_id, updated_at DESC);
29
-
30
- -- Backfill columns for installs that already created the table from an older
31
- -- schema. Safe to re-run.
32
- ALTER TABLE onesub_subscriptions ADD COLUMN IF NOT EXISTS linked_purchase_token TEXT;
33
- ALTER TABLE onesub_subscriptions ADD COLUMN IF NOT EXISTS auto_resume_time TIMESTAMPTZ;
34
- `.trim();
35
- export const PURCHASES_SCHEMA_SQL = `
36
- CREATE TABLE IF NOT EXISTS onesub_purchases (
37
- transaction_id TEXT PRIMARY KEY,
38
- user_id TEXT NOT NULL,
39
- product_id TEXT NOT NULL,
40
- platform TEXT NOT NULL,
41
- type TEXT NOT NULL,
42
- quantity INTEGER NOT NULL DEFAULT 1,
43
- purchased_at TIMESTAMPTZ NOT NULL,
44
- created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
45
- );
46
-
47
- CREATE INDEX IF NOT EXISTS idx_onesub_purchases_user_id
48
- ON onesub_purchases (user_id, purchased_at DESC);
49
-
50
- CREATE INDEX IF NOT EXISTS idx_onesub_purchases_user_product
51
- ON onesub_purchases (user_id, product_id);
52
-
53
- CREATE UNIQUE INDEX IF NOT EXISTS idx_onesub_purchases_non_consumable
54
- ON onesub_purchases (user_id, product_id)
55
- WHERE type = 'non_consumable';
56
- `.trim();
57
- //# sourceMappingURL=schema.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/stores/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsBvC,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBnC,CAAC,IAAI,EAAE,CAAC"}