@magnet-cms/plugin-polar 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/index.cjs +2494 -0
- package/dist/backend/index.d.cts +435 -0
- package/dist/backend/index.d.ts +435 -0
- package/dist/backend/index.js +22 -0
- package/dist/chunk-7KT7JQIH.js +2474 -0
- package/dist/frontend/bundle.iife.js +23323 -0
- package/dist/frontend/bundle.iife.js.map +1 -0
- package/dist/index.cjs +2474 -0
- package/dist/index.d.cts +140 -0
- package/dist/index.d.ts +140 -0
- package/dist/index.js +1 -0
- package/package.json +83 -0
- package/src/admin/components/recent-orders.tsx +80 -0
- package/src/admin/components/revenue-chart.tsx +56 -0
- package/src/admin/components/subscription-metrics.tsx +65 -0
- package/src/admin/index.ts +128 -0
- package/src/admin/pages/benefits.tsx +175 -0
- package/src/admin/pages/customers.tsx +187 -0
- package/src/admin/pages/orders.tsx +188 -0
- package/src/admin/pages/polar-dashboard.tsx +90 -0
- package/src/admin/pages/products.tsx +203 -0
- package/src/admin/pages/subscriptions.tsx +245 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2474 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@magnet-cms/core');
|
|
4
|
+
var common = require('@nestjs/common');
|
|
5
|
+
var sdk = require('@polar-sh/sdk');
|
|
6
|
+
var common$1 = require('@magnet-cms/common');
|
|
7
|
+
var rfcdate = require('@polar-sh/sdk/types/rfcdate');
|
|
8
|
+
var webhooks = require('@polar-sh/sdk/webhooks');
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
15
|
+
var __esm = (fn, res) => function __init() {
|
|
16
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
17
|
+
};
|
|
18
|
+
var __export = (target, all) => {
|
|
19
|
+
for (var name in all)
|
|
20
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
21
|
+
};
|
|
22
|
+
var __copyProps = (to, from, except, desc) => {
|
|
23
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
24
|
+
for (let key of __getOwnPropNames(from))
|
|
25
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
26
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
27
|
+
}
|
|
28
|
+
return to;
|
|
29
|
+
};
|
|
30
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
31
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
32
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
33
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
34
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
35
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
36
|
+
}
|
|
37
|
+
function _ts_metadata(k, v) {
|
|
38
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
39
|
+
}
|
|
40
|
+
function _ts_param(paramIndex, decorator) {
|
|
41
|
+
return function(target, key) {
|
|
42
|
+
decorator(target, key, paramIndex);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
var PolarService;
|
|
46
|
+
var init_polar_service = __esm({
|
|
47
|
+
"src/polar.service.ts"() {
|
|
48
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
49
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
50
|
+
__name(_ts_param, "_ts_param");
|
|
51
|
+
PolarService = class _PolarService {
|
|
52
|
+
static {
|
|
53
|
+
__name(this, "PolarService");
|
|
54
|
+
}
|
|
55
|
+
config;
|
|
56
|
+
logger;
|
|
57
|
+
polar;
|
|
58
|
+
constructor(config) {
|
|
59
|
+
this.config = config;
|
|
60
|
+
this.logger = new common.Logger(_PolarService.name);
|
|
61
|
+
this.polar = null;
|
|
62
|
+
}
|
|
63
|
+
onModuleInit() {
|
|
64
|
+
if (!this.config.accessToken) {
|
|
65
|
+
throw new Error("[PolarPlugin] Missing accessToken in plugin options. Configure it via: { plugin: PolarPlugin, options: { accessToken: process.env.POLAR_ACCESS_TOKEN } }");
|
|
66
|
+
}
|
|
67
|
+
this.polar = new sdk.Polar({
|
|
68
|
+
accessToken: this.config.accessToken
|
|
69
|
+
});
|
|
70
|
+
if (this.config.webhookSecret) {
|
|
71
|
+
this.logger.debug("Webhook secret configured. Ensure rawBody is enabled in NestFactory.create() for signature verification.");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Get the initialized Polar client */
|
|
75
|
+
get client() {
|
|
76
|
+
if (!this.polar) {
|
|
77
|
+
throw new Error("[PolarPlugin] Polar client not initialized. Ensure the module has been initialized.");
|
|
78
|
+
}
|
|
79
|
+
return this.polar;
|
|
80
|
+
}
|
|
81
|
+
/** Get the plugin configuration */
|
|
82
|
+
get pluginConfig() {
|
|
83
|
+
return this.config;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Verify that raw body is available on the request.
|
|
87
|
+
* Must be called before webhook signature verification.
|
|
88
|
+
* Consumers must enable `rawBody: true` in NestFactory.create().
|
|
89
|
+
*/
|
|
90
|
+
verifyRawBodyAvailable(req) {
|
|
91
|
+
if (!req.rawBody) {
|
|
92
|
+
throw new common.HttpException("[PolarPlugin] Raw request body not available. Enable rawBody in your NestJS bootstrap: NestFactory.create(AppModule, { rawBody: true }). This is required for Polar webhook signature verification.", common.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
PolarService = _ts_decorate([
|
|
97
|
+
common.Injectable(),
|
|
98
|
+
_ts_param(0, core.InjectPluginOptions("polar")),
|
|
99
|
+
_ts_metadata("design:type", Function),
|
|
100
|
+
_ts_metadata("design:paramtypes", [
|
|
101
|
+
typeof PolarPluginConfig === "undefined" ? Object : PolarPluginConfig
|
|
102
|
+
])
|
|
103
|
+
], PolarService);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
107
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
108
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
109
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
110
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
111
|
+
}
|
|
112
|
+
function _ts_metadata2(k, v) {
|
|
113
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
114
|
+
}
|
|
115
|
+
var PolarOrder;
|
|
116
|
+
var init_order_schema = __esm({
|
|
117
|
+
"src/schemas/order.schema.ts"() {
|
|
118
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
119
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
120
|
+
PolarOrder = class {
|
|
121
|
+
static {
|
|
122
|
+
__name(this, "PolarOrder");
|
|
123
|
+
}
|
|
124
|
+
/** Polar Order ID */
|
|
125
|
+
polarOrderId;
|
|
126
|
+
/** Reference to PolarCustomer.polarCustomerId */
|
|
127
|
+
customerId;
|
|
128
|
+
/** Reference to PolarProduct.polarProductId */
|
|
129
|
+
productId;
|
|
130
|
+
/** Reference to PolarSubscription.polarSubscriptionId (nullable for one-time purchases) */
|
|
131
|
+
subscriptionId;
|
|
132
|
+
/** Order status */
|
|
133
|
+
status;
|
|
134
|
+
/** Total order amount in smallest currency unit (cents) */
|
|
135
|
+
totalAmount;
|
|
136
|
+
/** Three-letter ISO currency code */
|
|
137
|
+
currency;
|
|
138
|
+
/** Reason for billing (purchase, subscription_create, subscription_cycle, etc.) */
|
|
139
|
+
billingReason;
|
|
140
|
+
/** When the order was created */
|
|
141
|
+
createdAt;
|
|
142
|
+
};
|
|
143
|
+
_ts_decorate2([
|
|
144
|
+
common$1.Field.Text({
|
|
145
|
+
required: true,
|
|
146
|
+
unique: true
|
|
147
|
+
}),
|
|
148
|
+
_ts_metadata2("design:type", String)
|
|
149
|
+
], PolarOrder.prototype, "polarOrderId", void 0);
|
|
150
|
+
_ts_decorate2([
|
|
151
|
+
common$1.Field.Text({
|
|
152
|
+
required: true
|
|
153
|
+
}),
|
|
154
|
+
_ts_metadata2("design:type", String)
|
|
155
|
+
], PolarOrder.prototype, "customerId", void 0);
|
|
156
|
+
_ts_decorate2([
|
|
157
|
+
common$1.Field.Text({
|
|
158
|
+
required: true
|
|
159
|
+
}),
|
|
160
|
+
_ts_metadata2("design:type", String)
|
|
161
|
+
], PolarOrder.prototype, "productId", void 0);
|
|
162
|
+
_ts_decorate2([
|
|
163
|
+
common$1.Field.Text(),
|
|
164
|
+
_ts_metadata2("design:type", String)
|
|
165
|
+
], PolarOrder.prototype, "subscriptionId", void 0);
|
|
166
|
+
_ts_decorate2([
|
|
167
|
+
common$1.Field.Select({
|
|
168
|
+
required: true,
|
|
169
|
+
options: [
|
|
170
|
+
{
|
|
171
|
+
label: "Paid",
|
|
172
|
+
value: "paid"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
label: "Refunded",
|
|
176
|
+
value: "refunded"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
label: "Pending",
|
|
180
|
+
value: "pending"
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
}),
|
|
184
|
+
_ts_metadata2("design:type", String)
|
|
185
|
+
], PolarOrder.prototype, "status", void 0);
|
|
186
|
+
_ts_decorate2([
|
|
187
|
+
common$1.Field.Number({
|
|
188
|
+
required: true
|
|
189
|
+
}),
|
|
190
|
+
_ts_metadata2("design:type", Number)
|
|
191
|
+
], PolarOrder.prototype, "totalAmount", void 0);
|
|
192
|
+
_ts_decorate2([
|
|
193
|
+
common$1.Field.Text({
|
|
194
|
+
required: true
|
|
195
|
+
}),
|
|
196
|
+
_ts_metadata2("design:type", String)
|
|
197
|
+
], PolarOrder.prototype, "currency", void 0);
|
|
198
|
+
_ts_decorate2([
|
|
199
|
+
common$1.Field.Text(),
|
|
200
|
+
_ts_metadata2("design:type", String)
|
|
201
|
+
], PolarOrder.prototype, "billingReason", void 0);
|
|
202
|
+
_ts_decorate2([
|
|
203
|
+
common$1.Field.Date({
|
|
204
|
+
required: true,
|
|
205
|
+
default: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "default")
|
|
206
|
+
}),
|
|
207
|
+
_ts_metadata2("design:type", typeof Date === "undefined" ? Object : Date)
|
|
208
|
+
], PolarOrder.prototype, "createdAt", void 0);
|
|
209
|
+
PolarOrder = _ts_decorate2([
|
|
210
|
+
common$1.Schema({
|
|
211
|
+
versioning: false,
|
|
212
|
+
i18n: false,
|
|
213
|
+
visible: false
|
|
214
|
+
})
|
|
215
|
+
], PolarOrder);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
219
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
220
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
221
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
222
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
223
|
+
}
|
|
224
|
+
function _ts_metadata3(k, v) {
|
|
225
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
226
|
+
}
|
|
227
|
+
var PolarProduct;
|
|
228
|
+
var init_product_schema = __esm({
|
|
229
|
+
"src/schemas/product.schema.ts"() {
|
|
230
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
231
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
232
|
+
PolarProduct = class {
|
|
233
|
+
static {
|
|
234
|
+
__name(this, "PolarProduct");
|
|
235
|
+
}
|
|
236
|
+
/** Polar Product ID */
|
|
237
|
+
polarProductId;
|
|
238
|
+
/** Product name */
|
|
239
|
+
name;
|
|
240
|
+
/** Product description */
|
|
241
|
+
description;
|
|
242
|
+
/** Whether the product is a recurring subscription */
|
|
243
|
+
isRecurring = false;
|
|
244
|
+
/** Whether the product is archived in Polar */
|
|
245
|
+
isArchived = false;
|
|
246
|
+
/** Polar Organization ID */
|
|
247
|
+
organizationId;
|
|
248
|
+
/** Arbitrary metadata from Polar */
|
|
249
|
+
metadata;
|
|
250
|
+
/** When the product was last synced */
|
|
251
|
+
updatedAt;
|
|
252
|
+
};
|
|
253
|
+
_ts_decorate3([
|
|
254
|
+
common$1.Field.Text({
|
|
255
|
+
required: true,
|
|
256
|
+
unique: true
|
|
257
|
+
}),
|
|
258
|
+
_ts_metadata3("design:type", String)
|
|
259
|
+
], PolarProduct.prototype, "polarProductId", void 0);
|
|
260
|
+
_ts_decorate3([
|
|
261
|
+
common$1.Field.Text({
|
|
262
|
+
required: true
|
|
263
|
+
}),
|
|
264
|
+
_ts_metadata3("design:type", String)
|
|
265
|
+
], PolarProduct.prototype, "name", void 0);
|
|
266
|
+
_ts_decorate3([
|
|
267
|
+
common$1.Field.Text(),
|
|
268
|
+
_ts_metadata3("design:type", String)
|
|
269
|
+
], PolarProduct.prototype, "description", void 0);
|
|
270
|
+
_ts_decorate3([
|
|
271
|
+
common$1.Field.Boolean({
|
|
272
|
+
default: false
|
|
273
|
+
})
|
|
274
|
+
], PolarProduct.prototype, "isRecurring", void 0);
|
|
275
|
+
_ts_decorate3([
|
|
276
|
+
common$1.Field.Boolean({
|
|
277
|
+
default: false
|
|
278
|
+
})
|
|
279
|
+
], PolarProduct.prototype, "isArchived", void 0);
|
|
280
|
+
_ts_decorate3([
|
|
281
|
+
common$1.Field.Text(),
|
|
282
|
+
_ts_metadata3("design:type", String)
|
|
283
|
+
], PolarProduct.prototype, "organizationId", void 0);
|
|
284
|
+
_ts_decorate3([
|
|
285
|
+
common$1.Prop({
|
|
286
|
+
type: Object
|
|
287
|
+
}),
|
|
288
|
+
_ts_metadata3("design:type", typeof Record === "undefined" ? Object : Record)
|
|
289
|
+
], PolarProduct.prototype, "metadata", void 0);
|
|
290
|
+
_ts_decorate3([
|
|
291
|
+
common$1.Field.Date({
|
|
292
|
+
required: true,
|
|
293
|
+
default: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "default")
|
|
294
|
+
}),
|
|
295
|
+
_ts_metadata3("design:type", typeof Date === "undefined" ? Object : Date)
|
|
296
|
+
], PolarProduct.prototype, "updatedAt", void 0);
|
|
297
|
+
PolarProduct = _ts_decorate3([
|
|
298
|
+
common$1.Schema({
|
|
299
|
+
versioning: false,
|
|
300
|
+
i18n: false,
|
|
301
|
+
visible: false
|
|
302
|
+
})
|
|
303
|
+
], PolarProduct);
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
307
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
308
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
309
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
310
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
311
|
+
}
|
|
312
|
+
function _ts_metadata4(k, v) {
|
|
313
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
314
|
+
}
|
|
315
|
+
var PolarCustomer;
|
|
316
|
+
var init_customer_schema = __esm({
|
|
317
|
+
"src/schemas/customer.schema.ts"() {
|
|
318
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
319
|
+
__name(_ts_metadata4, "_ts_metadata");
|
|
320
|
+
PolarCustomer = class {
|
|
321
|
+
static {
|
|
322
|
+
__name(this, "PolarCustomer");
|
|
323
|
+
}
|
|
324
|
+
/** Polar Customer ID */
|
|
325
|
+
polarCustomerId;
|
|
326
|
+
/** Customer email address */
|
|
327
|
+
email;
|
|
328
|
+
/** Customer display name */
|
|
329
|
+
name;
|
|
330
|
+
/** Reference to the Magnet user ID (via Polar externalId) */
|
|
331
|
+
userId;
|
|
332
|
+
/** Arbitrary metadata from Polar */
|
|
333
|
+
metadata;
|
|
334
|
+
/** When the customer was created in Polar */
|
|
335
|
+
createdAt;
|
|
336
|
+
};
|
|
337
|
+
_ts_decorate4([
|
|
338
|
+
common$1.Field.Text({
|
|
339
|
+
required: true,
|
|
340
|
+
unique: true
|
|
341
|
+
}),
|
|
342
|
+
_ts_metadata4("design:type", String)
|
|
343
|
+
], PolarCustomer.prototype, "polarCustomerId", void 0);
|
|
344
|
+
_ts_decorate4([
|
|
345
|
+
common$1.Field.Email({
|
|
346
|
+
required: true
|
|
347
|
+
}),
|
|
348
|
+
_ts_metadata4("design:type", String)
|
|
349
|
+
], PolarCustomer.prototype, "email", void 0);
|
|
350
|
+
_ts_decorate4([
|
|
351
|
+
common$1.Field.Text(),
|
|
352
|
+
_ts_metadata4("design:type", String)
|
|
353
|
+
], PolarCustomer.prototype, "name", void 0);
|
|
354
|
+
_ts_decorate4([
|
|
355
|
+
common$1.Field.Text(),
|
|
356
|
+
_ts_metadata4("design:type", String)
|
|
357
|
+
], PolarCustomer.prototype, "userId", void 0);
|
|
358
|
+
_ts_decorate4([
|
|
359
|
+
common$1.Prop({
|
|
360
|
+
type: Object
|
|
361
|
+
}),
|
|
362
|
+
_ts_metadata4("design:type", typeof Record === "undefined" ? Object : Record)
|
|
363
|
+
], PolarCustomer.prototype, "metadata", void 0);
|
|
364
|
+
_ts_decorate4([
|
|
365
|
+
common$1.Field.Date({
|
|
366
|
+
required: true,
|
|
367
|
+
default: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "default")
|
|
368
|
+
}),
|
|
369
|
+
_ts_metadata4("design:type", typeof Date === "undefined" ? Object : Date)
|
|
370
|
+
], PolarCustomer.prototype, "createdAt", void 0);
|
|
371
|
+
PolarCustomer = _ts_decorate4([
|
|
372
|
+
common$1.Schema({
|
|
373
|
+
versioning: false,
|
|
374
|
+
i18n: false,
|
|
375
|
+
visible: false
|
|
376
|
+
})
|
|
377
|
+
], PolarCustomer);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
381
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
382
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
383
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
384
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
385
|
+
}
|
|
386
|
+
function _ts_metadata5(k, v) {
|
|
387
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
388
|
+
}
|
|
389
|
+
function _ts_param2(paramIndex, decorator) {
|
|
390
|
+
return function(target, key) {
|
|
391
|
+
decorator(target, key, paramIndex);
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
var PolarCustomerService;
|
|
395
|
+
var init_customer_service = __esm({
|
|
396
|
+
"src/services/customer.service.ts"() {
|
|
397
|
+
init_customer_schema();
|
|
398
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
399
|
+
__name(_ts_metadata5, "_ts_metadata");
|
|
400
|
+
__name(_ts_param2, "_ts_param");
|
|
401
|
+
PolarCustomerService = class {
|
|
402
|
+
static {
|
|
403
|
+
__name(this, "PolarCustomerService");
|
|
404
|
+
}
|
|
405
|
+
customerModel;
|
|
406
|
+
constructor(customerModel) {
|
|
407
|
+
this.customerModel = customerModel;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Upsert a Polar customer record from a webhook customer payload.
|
|
411
|
+
*/
|
|
412
|
+
async upsertFromWebhook(data) {
|
|
413
|
+
const customerData = {
|
|
414
|
+
polarCustomerId: data.id,
|
|
415
|
+
email: data.email,
|
|
416
|
+
name: data.name ?? void 0,
|
|
417
|
+
userId: data.externalId ?? void 0,
|
|
418
|
+
metadata: data.metadata
|
|
419
|
+
};
|
|
420
|
+
const existing = await this.customerModel.findOne({
|
|
421
|
+
polarCustomerId: data.id
|
|
422
|
+
});
|
|
423
|
+
if (existing) {
|
|
424
|
+
return this.customerModel.update({
|
|
425
|
+
polarCustomerId: data.id
|
|
426
|
+
}, customerData);
|
|
427
|
+
}
|
|
428
|
+
return this.customerModel.create(customerData);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Delete a customer record by Polar Customer ID.
|
|
432
|
+
*/
|
|
433
|
+
async deleteByPolarId(polarCustomerId) {
|
|
434
|
+
await this.customerModel.delete({
|
|
435
|
+
polarCustomerId
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Find a customer by Magnet user ID.
|
|
440
|
+
*/
|
|
441
|
+
async findByUserId(userId) {
|
|
442
|
+
return this.customerModel.findOne({
|
|
443
|
+
userId
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Find a customer by Polar Customer ID.
|
|
448
|
+
*/
|
|
449
|
+
async findByPolarId(polarCustomerId) {
|
|
450
|
+
return this.customerModel.findOne({
|
|
451
|
+
polarCustomerId
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* List all customers.
|
|
456
|
+
*/
|
|
457
|
+
async findAll() {
|
|
458
|
+
return this.customerModel.find();
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Link a Polar customer to a Magnet user.
|
|
462
|
+
*/
|
|
463
|
+
async linkToUser(polarCustomerId, userId) {
|
|
464
|
+
return this.customerModel.update({
|
|
465
|
+
polarCustomerId
|
|
466
|
+
}, {
|
|
467
|
+
userId
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
PolarCustomerService = _ts_decorate5([
|
|
472
|
+
common.Injectable(),
|
|
473
|
+
_ts_param2(0, common$1.InjectModel(PolarCustomer)),
|
|
474
|
+
_ts_metadata5("design:type", Function),
|
|
475
|
+
_ts_metadata5("design:paramtypes", [
|
|
476
|
+
typeof Model === "undefined" ? Object : Model
|
|
477
|
+
])
|
|
478
|
+
], PolarCustomerService);
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
482
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
483
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
484
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
485
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
486
|
+
}
|
|
487
|
+
function _ts_metadata6(k, v) {
|
|
488
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
489
|
+
}
|
|
490
|
+
var PolarSubscription;
|
|
491
|
+
var init_subscription_schema = __esm({
|
|
492
|
+
"src/schemas/subscription.schema.ts"() {
|
|
493
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
494
|
+
__name(_ts_metadata6, "_ts_metadata");
|
|
495
|
+
PolarSubscription = class {
|
|
496
|
+
static {
|
|
497
|
+
__name(this, "PolarSubscription");
|
|
498
|
+
}
|
|
499
|
+
/** Polar Subscription ID */
|
|
500
|
+
polarSubscriptionId;
|
|
501
|
+
/** Reference to PolarCustomer.polarCustomerId */
|
|
502
|
+
customerId;
|
|
503
|
+
/** Reference to PolarProduct.polarProductId */
|
|
504
|
+
productId;
|
|
505
|
+
/** Subscription status from Polar */
|
|
506
|
+
status;
|
|
507
|
+
/** Subscription amount in smallest currency unit (cents) */
|
|
508
|
+
amount;
|
|
509
|
+
/** Three-letter ISO currency code */
|
|
510
|
+
currency;
|
|
511
|
+
/** Recurring interval (month, year, week, day) */
|
|
512
|
+
recurringInterval;
|
|
513
|
+
/** Start of the current billing period */
|
|
514
|
+
currentPeriodStart;
|
|
515
|
+
/** End of the current billing period */
|
|
516
|
+
currentPeriodEnd;
|
|
517
|
+
/** Whether the subscription will be canceled at the end of the period */
|
|
518
|
+
cancelAtPeriodEnd = false;
|
|
519
|
+
/** When the subscription started */
|
|
520
|
+
startedAt;
|
|
521
|
+
/** When the subscription ended (null if still active) */
|
|
522
|
+
endedAt;
|
|
523
|
+
/** When the subscription was last synced */
|
|
524
|
+
updatedAt;
|
|
525
|
+
};
|
|
526
|
+
_ts_decorate6([
|
|
527
|
+
common$1.Field.Text({
|
|
528
|
+
required: true,
|
|
529
|
+
unique: true
|
|
530
|
+
}),
|
|
531
|
+
_ts_metadata6("design:type", String)
|
|
532
|
+
], PolarSubscription.prototype, "polarSubscriptionId", void 0);
|
|
533
|
+
_ts_decorate6([
|
|
534
|
+
common$1.Field.Text({
|
|
535
|
+
required: true
|
|
536
|
+
}),
|
|
537
|
+
_ts_metadata6("design:type", String)
|
|
538
|
+
], PolarSubscription.prototype, "customerId", void 0);
|
|
539
|
+
_ts_decorate6([
|
|
540
|
+
common$1.Field.Text({
|
|
541
|
+
required: true
|
|
542
|
+
}),
|
|
543
|
+
_ts_metadata6("design:type", String)
|
|
544
|
+
], PolarSubscription.prototype, "productId", void 0);
|
|
545
|
+
_ts_decorate6([
|
|
546
|
+
common$1.Field.Select({
|
|
547
|
+
required: true,
|
|
548
|
+
options: [
|
|
549
|
+
{
|
|
550
|
+
label: "Active",
|
|
551
|
+
value: "active"
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
label: "Canceled",
|
|
555
|
+
value: "canceled"
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
label: "Past Due",
|
|
559
|
+
value: "past_due"
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
label: "Trialing",
|
|
563
|
+
value: "trialing"
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
label: "Incomplete",
|
|
567
|
+
value: "incomplete"
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
label: "Unpaid",
|
|
571
|
+
value: "unpaid"
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
label: "Revoked",
|
|
575
|
+
value: "revoked"
|
|
576
|
+
}
|
|
577
|
+
]
|
|
578
|
+
}),
|
|
579
|
+
_ts_metadata6("design:type", String)
|
|
580
|
+
], PolarSubscription.prototype, "status", void 0);
|
|
581
|
+
_ts_decorate6([
|
|
582
|
+
common$1.Field.Number(),
|
|
583
|
+
_ts_metadata6("design:type", Number)
|
|
584
|
+
], PolarSubscription.prototype, "amount", void 0);
|
|
585
|
+
_ts_decorate6([
|
|
586
|
+
common$1.Field.Text(),
|
|
587
|
+
_ts_metadata6("design:type", String)
|
|
588
|
+
], PolarSubscription.prototype, "currency", void 0);
|
|
589
|
+
_ts_decorate6([
|
|
590
|
+
common$1.Field.Text(),
|
|
591
|
+
_ts_metadata6("design:type", String)
|
|
592
|
+
], PolarSubscription.prototype, "recurringInterval", void 0);
|
|
593
|
+
_ts_decorate6([
|
|
594
|
+
common$1.Field.Date({
|
|
595
|
+
required: true
|
|
596
|
+
}),
|
|
597
|
+
_ts_metadata6("design:type", typeof Date === "undefined" ? Object : Date)
|
|
598
|
+
], PolarSubscription.prototype, "currentPeriodStart", void 0);
|
|
599
|
+
_ts_decorate6([
|
|
600
|
+
common$1.Field.Date({
|
|
601
|
+
required: true
|
|
602
|
+
}),
|
|
603
|
+
_ts_metadata6("design:type", typeof Date === "undefined" ? Object : Date)
|
|
604
|
+
], PolarSubscription.prototype, "currentPeriodEnd", void 0);
|
|
605
|
+
_ts_decorate6([
|
|
606
|
+
common$1.Field.Boolean({
|
|
607
|
+
default: false
|
|
608
|
+
})
|
|
609
|
+
], PolarSubscription.prototype, "cancelAtPeriodEnd", void 0);
|
|
610
|
+
_ts_decorate6([
|
|
611
|
+
common$1.Field.Date(),
|
|
612
|
+
_ts_metadata6("design:type", typeof Date === "undefined" ? Object : Date)
|
|
613
|
+
], PolarSubscription.prototype, "startedAt", void 0);
|
|
614
|
+
_ts_decorate6([
|
|
615
|
+
common$1.Field.Date(),
|
|
616
|
+
_ts_metadata6("design:type", typeof Date === "undefined" ? Object : Date)
|
|
617
|
+
], PolarSubscription.prototype, "endedAt", void 0);
|
|
618
|
+
_ts_decorate6([
|
|
619
|
+
common$1.Field.Date({
|
|
620
|
+
required: true,
|
|
621
|
+
default: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "default")
|
|
622
|
+
}),
|
|
623
|
+
_ts_metadata6("design:type", typeof Date === "undefined" ? Object : Date)
|
|
624
|
+
], PolarSubscription.prototype, "updatedAt", void 0);
|
|
625
|
+
PolarSubscription = _ts_decorate6([
|
|
626
|
+
common$1.Schema({
|
|
627
|
+
versioning: false,
|
|
628
|
+
i18n: false,
|
|
629
|
+
visible: false
|
|
630
|
+
})
|
|
631
|
+
], PolarSubscription);
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
function _ts_decorate7(decorators, target, key, desc) {
|
|
635
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
636
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
637
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
638
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
639
|
+
}
|
|
640
|
+
function _ts_metadata7(k, v) {
|
|
641
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
642
|
+
}
|
|
643
|
+
function _ts_param3(paramIndex, decorator) {
|
|
644
|
+
return function(target, key) {
|
|
645
|
+
decorator(target, key, paramIndex);
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
var PolarSubscriptionService;
|
|
649
|
+
var init_subscription_service = __esm({
|
|
650
|
+
"src/services/subscription.service.ts"() {
|
|
651
|
+
init_polar_service();
|
|
652
|
+
init_subscription_schema();
|
|
653
|
+
__name(_ts_decorate7, "_ts_decorate");
|
|
654
|
+
__name(_ts_metadata7, "_ts_metadata");
|
|
655
|
+
__name(_ts_param3, "_ts_param");
|
|
656
|
+
PolarSubscriptionService = class {
|
|
657
|
+
static {
|
|
658
|
+
__name(this, "PolarSubscriptionService");
|
|
659
|
+
}
|
|
660
|
+
subscriptionModel;
|
|
661
|
+
polarService;
|
|
662
|
+
constructor(subscriptionModel, polarService) {
|
|
663
|
+
this.subscriptionModel = subscriptionModel;
|
|
664
|
+
this.polarService = polarService;
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Upsert a subscription from a webhook subscription payload.
|
|
668
|
+
*/
|
|
669
|
+
async syncSubscription(data) {
|
|
670
|
+
const subData = {
|
|
671
|
+
polarSubscriptionId: data.id,
|
|
672
|
+
customerId: data.customerId,
|
|
673
|
+
productId: data.productId,
|
|
674
|
+
status: data.status,
|
|
675
|
+
amount: data.amount,
|
|
676
|
+
currency: data.currency,
|
|
677
|
+
recurringInterval: data.recurringInterval,
|
|
678
|
+
currentPeriodStart: data.currentPeriodStart,
|
|
679
|
+
currentPeriodEnd: data.currentPeriodEnd,
|
|
680
|
+
cancelAtPeriodEnd: data.cancelAtPeriodEnd,
|
|
681
|
+
startedAt: data.startedAt ?? void 0,
|
|
682
|
+
endedAt: data.endedAt ?? void 0,
|
|
683
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
684
|
+
};
|
|
685
|
+
const existing = await this.subscriptionModel.findOne({
|
|
686
|
+
polarSubscriptionId: data.id
|
|
687
|
+
});
|
|
688
|
+
if (existing) {
|
|
689
|
+
return this.subscriptionModel.update({
|
|
690
|
+
polarSubscriptionId: data.id
|
|
691
|
+
}, subData);
|
|
692
|
+
}
|
|
693
|
+
return this.subscriptionModel.create(subData);
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Delete a subscription record by Polar Subscription ID.
|
|
697
|
+
*/
|
|
698
|
+
async deleteByPolarId(polarSubscriptionId) {
|
|
699
|
+
await this.subscriptionModel.delete({
|
|
700
|
+
polarSubscriptionId
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Find active subscription for a customer.
|
|
705
|
+
*/
|
|
706
|
+
async findActiveByCustomerId(customerId) {
|
|
707
|
+
return this.subscriptionModel.findOne({
|
|
708
|
+
customerId,
|
|
709
|
+
status: "active"
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* List all subscriptions.
|
|
714
|
+
*/
|
|
715
|
+
async findAll() {
|
|
716
|
+
return this.subscriptionModel.find();
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Revoke (cancel immediately) a subscription via Polar SDK.
|
|
720
|
+
*/
|
|
721
|
+
async revoke(polarSubscriptionId) {
|
|
722
|
+
await this.polarService.client.subscriptions.revoke({
|
|
723
|
+
id: polarSubscriptionId
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
PolarSubscriptionService = _ts_decorate7([
|
|
728
|
+
common.Injectable(),
|
|
729
|
+
_ts_param3(0, common$1.InjectModel(PolarSubscription)),
|
|
730
|
+
_ts_metadata7("design:type", Function),
|
|
731
|
+
_ts_metadata7("design:paramtypes", [
|
|
732
|
+
typeof Model === "undefined" ? Object : Model,
|
|
733
|
+
typeof PolarService === "undefined" ? Object : PolarService
|
|
734
|
+
])
|
|
735
|
+
], PolarSubscriptionService);
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
739
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
740
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
741
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
742
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
743
|
+
}
|
|
744
|
+
function _ts_metadata8(k, v) {
|
|
745
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
746
|
+
}
|
|
747
|
+
function _ts_param4(paramIndex, decorator) {
|
|
748
|
+
return function(target, key) {
|
|
749
|
+
decorator(target, key, paramIndex);
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
var PolarAccessService;
|
|
753
|
+
var init_access_service = __esm({
|
|
754
|
+
"src/services/access.service.ts"() {
|
|
755
|
+
init_polar_service();
|
|
756
|
+
init_product_schema();
|
|
757
|
+
init_customer_service();
|
|
758
|
+
init_subscription_service();
|
|
759
|
+
__name(_ts_decorate8, "_ts_decorate");
|
|
760
|
+
__name(_ts_metadata8, "_ts_metadata");
|
|
761
|
+
__name(_ts_param4, "_ts_param");
|
|
762
|
+
PolarAccessService = class {
|
|
763
|
+
static {
|
|
764
|
+
__name(this, "PolarAccessService");
|
|
765
|
+
}
|
|
766
|
+
polarService;
|
|
767
|
+
customerService;
|
|
768
|
+
subscriptionService;
|
|
769
|
+
productModel;
|
|
770
|
+
constructor(polarService, customerService, subscriptionService, productModel) {
|
|
771
|
+
this.polarService = polarService;
|
|
772
|
+
this.customerService = customerService;
|
|
773
|
+
this.subscriptionService = subscriptionService;
|
|
774
|
+
this.productModel = productModel;
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Get subscription access info for a user.
|
|
778
|
+
* Returns subscription status, plan name, and feature flags.
|
|
779
|
+
*/
|
|
780
|
+
async getAccess(userId) {
|
|
781
|
+
const noAccess = {
|
|
782
|
+
hasActiveSubscription: false,
|
|
783
|
+
plan: null,
|
|
784
|
+
expiresAt: null,
|
|
785
|
+
features: []
|
|
786
|
+
};
|
|
787
|
+
const customer = await this.customerService.findByUserId(userId);
|
|
788
|
+
if (!customer) {
|
|
789
|
+
return noAccess;
|
|
790
|
+
}
|
|
791
|
+
const subscription = await this.subscriptionService.findActiveByCustomerId(customer.polarCustomerId);
|
|
792
|
+
if (!subscription) {
|
|
793
|
+
return noAccess;
|
|
794
|
+
}
|
|
795
|
+
let planName = null;
|
|
796
|
+
const product = await this.productModel.findOne({
|
|
797
|
+
polarProductId: subscription.productId
|
|
798
|
+
});
|
|
799
|
+
planName = product?.name ?? null;
|
|
800
|
+
const features = this.resolveFeaturesForPlan(planName);
|
|
801
|
+
return {
|
|
802
|
+
hasActiveSubscription: true,
|
|
803
|
+
plan: planName,
|
|
804
|
+
expiresAt: subscription.currentPeriodEnd,
|
|
805
|
+
features
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Resolve feature flags for a plan name from plugin config.
|
|
810
|
+
*/
|
|
811
|
+
resolveFeaturesForPlan(planName) {
|
|
812
|
+
if (!planName) return [];
|
|
813
|
+
const featuresConfig = this.polarService.pluginConfig.features;
|
|
814
|
+
if (!featuresConfig) return [];
|
|
815
|
+
const normalizedPlan = planName.toLowerCase();
|
|
816
|
+
for (const [key, features] of Object.entries(featuresConfig)) {
|
|
817
|
+
if (key.toLowerCase() === normalizedPlan) {
|
|
818
|
+
return features;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
return [];
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
PolarAccessService = _ts_decorate8([
|
|
825
|
+
common.Injectable(),
|
|
826
|
+
_ts_param4(3, common$1.InjectModel(PolarProduct)),
|
|
827
|
+
_ts_metadata8("design:type", Function),
|
|
828
|
+
_ts_metadata8("design:paramtypes", [
|
|
829
|
+
typeof PolarService === "undefined" ? Object : PolarService,
|
|
830
|
+
typeof PolarCustomerService === "undefined" ? Object : PolarCustomerService,
|
|
831
|
+
typeof PolarSubscriptionService === "undefined" ? Object : PolarSubscriptionService,
|
|
832
|
+
typeof Model === "undefined" ? Object : Model
|
|
833
|
+
])
|
|
834
|
+
], PolarAccessService);
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
function _ts_decorate9(decorators, target, key, desc) {
|
|
838
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
839
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
840
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
841
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
842
|
+
}
|
|
843
|
+
function _ts_metadata9(k, v) {
|
|
844
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
845
|
+
}
|
|
846
|
+
var PolarBenefitGrant;
|
|
847
|
+
var init_benefit_grant_schema = __esm({
|
|
848
|
+
"src/schemas/benefit-grant.schema.ts"() {
|
|
849
|
+
__name(_ts_decorate9, "_ts_decorate");
|
|
850
|
+
__name(_ts_metadata9, "_ts_metadata");
|
|
851
|
+
PolarBenefitGrant = class {
|
|
852
|
+
static {
|
|
853
|
+
__name(this, "PolarBenefitGrant");
|
|
854
|
+
}
|
|
855
|
+
/** Polar Benefit Grant ID */
|
|
856
|
+
polarBenefitGrantId;
|
|
857
|
+
/** Reference to PolarBenefit.polarBenefitId */
|
|
858
|
+
benefitId;
|
|
859
|
+
/** Reference to PolarCustomer.polarCustomerId */
|
|
860
|
+
customerId;
|
|
861
|
+
/** Reference to PolarSubscription.polarSubscriptionId (optional) */
|
|
862
|
+
subscriptionId;
|
|
863
|
+
/** Whether the benefit is currently granted */
|
|
864
|
+
isGranted = true;
|
|
865
|
+
/** Whether the benefit has been revoked */
|
|
866
|
+
isRevoked = false;
|
|
867
|
+
/** When the benefit was granted */
|
|
868
|
+
grantedAt;
|
|
869
|
+
/** When the benefit was revoked (null if still active) */
|
|
870
|
+
revokedAt;
|
|
871
|
+
};
|
|
872
|
+
_ts_decorate9([
|
|
873
|
+
common$1.Field.Text({
|
|
874
|
+
required: true,
|
|
875
|
+
unique: true
|
|
876
|
+
}),
|
|
877
|
+
_ts_metadata9("design:type", String)
|
|
878
|
+
], PolarBenefitGrant.prototype, "polarBenefitGrantId", void 0);
|
|
879
|
+
_ts_decorate9([
|
|
880
|
+
common$1.Field.Text({
|
|
881
|
+
required: true
|
|
882
|
+
}),
|
|
883
|
+
_ts_metadata9("design:type", String)
|
|
884
|
+
], PolarBenefitGrant.prototype, "benefitId", void 0);
|
|
885
|
+
_ts_decorate9([
|
|
886
|
+
common$1.Field.Text({
|
|
887
|
+
required: true
|
|
888
|
+
}),
|
|
889
|
+
_ts_metadata9("design:type", String)
|
|
890
|
+
], PolarBenefitGrant.prototype, "customerId", void 0);
|
|
891
|
+
_ts_decorate9([
|
|
892
|
+
common$1.Field.Text(),
|
|
893
|
+
_ts_metadata9("design:type", String)
|
|
894
|
+
], PolarBenefitGrant.prototype, "subscriptionId", void 0);
|
|
895
|
+
_ts_decorate9([
|
|
896
|
+
common$1.Field.Boolean({
|
|
897
|
+
default: true
|
|
898
|
+
})
|
|
899
|
+
], PolarBenefitGrant.prototype, "isGranted", void 0);
|
|
900
|
+
_ts_decorate9([
|
|
901
|
+
common$1.Field.Boolean({
|
|
902
|
+
default: false
|
|
903
|
+
})
|
|
904
|
+
], PolarBenefitGrant.prototype, "isRevoked", void 0);
|
|
905
|
+
_ts_decorate9([
|
|
906
|
+
common$1.Field.Date(),
|
|
907
|
+
_ts_metadata9("design:type", typeof Date === "undefined" ? Object : Date)
|
|
908
|
+
], PolarBenefitGrant.prototype, "grantedAt", void 0);
|
|
909
|
+
_ts_decorate9([
|
|
910
|
+
common$1.Field.Date(),
|
|
911
|
+
_ts_metadata9("design:type", typeof Date === "undefined" ? Object : Date)
|
|
912
|
+
], PolarBenefitGrant.prototype, "revokedAt", void 0);
|
|
913
|
+
PolarBenefitGrant = _ts_decorate9([
|
|
914
|
+
common$1.Schema({
|
|
915
|
+
versioning: false,
|
|
916
|
+
i18n: false,
|
|
917
|
+
visible: false
|
|
918
|
+
})
|
|
919
|
+
], PolarBenefitGrant);
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
function _ts_decorate10(decorators, target, key, desc) {
|
|
923
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
924
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
925
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
926
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
927
|
+
}
|
|
928
|
+
function _ts_metadata10(k, v) {
|
|
929
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
930
|
+
}
|
|
931
|
+
var PolarBenefit;
|
|
932
|
+
var init_benefit_schema = __esm({
|
|
933
|
+
"src/schemas/benefit.schema.ts"() {
|
|
934
|
+
__name(_ts_decorate10, "_ts_decorate");
|
|
935
|
+
__name(_ts_metadata10, "_ts_metadata");
|
|
936
|
+
PolarBenefit = class {
|
|
937
|
+
static {
|
|
938
|
+
__name(this, "PolarBenefit");
|
|
939
|
+
}
|
|
940
|
+
/** Polar Benefit ID */
|
|
941
|
+
polarBenefitId;
|
|
942
|
+
/** Benefit type (license_keys, downloadables, discord, custom, github_repository, meter_credit, etc.) */
|
|
943
|
+
type;
|
|
944
|
+
/** Benefit description */
|
|
945
|
+
description;
|
|
946
|
+
/** Polar Organization ID */
|
|
947
|
+
organizationId;
|
|
948
|
+
/** Whether the benefit is selectable by the customer */
|
|
949
|
+
selectable = false;
|
|
950
|
+
/** Whether the benefit can be deleted */
|
|
951
|
+
deletable = true;
|
|
952
|
+
/** When the benefit was created */
|
|
953
|
+
createdAt;
|
|
954
|
+
};
|
|
955
|
+
_ts_decorate10([
|
|
956
|
+
common$1.Field.Text({
|
|
957
|
+
required: true,
|
|
958
|
+
unique: true
|
|
959
|
+
}),
|
|
960
|
+
_ts_metadata10("design:type", String)
|
|
961
|
+
], PolarBenefit.prototype, "polarBenefitId", void 0);
|
|
962
|
+
_ts_decorate10([
|
|
963
|
+
common$1.Field.Text({
|
|
964
|
+
required: true
|
|
965
|
+
}),
|
|
966
|
+
_ts_metadata10("design:type", String)
|
|
967
|
+
], PolarBenefit.prototype, "type", void 0);
|
|
968
|
+
_ts_decorate10([
|
|
969
|
+
common$1.Field.Text(),
|
|
970
|
+
_ts_metadata10("design:type", String)
|
|
971
|
+
], PolarBenefit.prototype, "description", void 0);
|
|
972
|
+
_ts_decorate10([
|
|
973
|
+
common$1.Field.Text(),
|
|
974
|
+
_ts_metadata10("design:type", String)
|
|
975
|
+
], PolarBenefit.prototype, "organizationId", void 0);
|
|
976
|
+
_ts_decorate10([
|
|
977
|
+
common$1.Field.Boolean({
|
|
978
|
+
default: false
|
|
979
|
+
})
|
|
980
|
+
], PolarBenefit.prototype, "selectable", void 0);
|
|
981
|
+
_ts_decorate10([
|
|
982
|
+
common$1.Field.Boolean({
|
|
983
|
+
default: true
|
|
984
|
+
})
|
|
985
|
+
], PolarBenefit.prototype, "deletable", void 0);
|
|
986
|
+
_ts_decorate10([
|
|
987
|
+
common$1.Field.Date({
|
|
988
|
+
required: true,
|
|
989
|
+
default: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "default")
|
|
990
|
+
}),
|
|
991
|
+
_ts_metadata10("design:type", typeof Date === "undefined" ? Object : Date)
|
|
992
|
+
], PolarBenefit.prototype, "createdAt", void 0);
|
|
993
|
+
PolarBenefit = _ts_decorate10([
|
|
994
|
+
common$1.Schema({
|
|
995
|
+
versioning: false,
|
|
996
|
+
i18n: false,
|
|
997
|
+
visible: false
|
|
998
|
+
})
|
|
999
|
+
], PolarBenefit);
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
function _ts_decorate11(decorators, target, key, desc) {
|
|
1003
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1004
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1005
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1006
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1007
|
+
}
|
|
1008
|
+
function _ts_metadata11(k, v) {
|
|
1009
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1010
|
+
}
|
|
1011
|
+
function _ts_param5(paramIndex, decorator) {
|
|
1012
|
+
return function(target, key) {
|
|
1013
|
+
decorator(target, key, paramIndex);
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
var PolarBenefitService;
|
|
1017
|
+
var init_benefit_service = __esm({
|
|
1018
|
+
"src/services/benefit.service.ts"() {
|
|
1019
|
+
init_benefit_grant_schema();
|
|
1020
|
+
init_benefit_schema();
|
|
1021
|
+
__name(_ts_decorate11, "_ts_decorate");
|
|
1022
|
+
__name(_ts_metadata11, "_ts_metadata");
|
|
1023
|
+
__name(_ts_param5, "_ts_param");
|
|
1024
|
+
PolarBenefitService = class {
|
|
1025
|
+
static {
|
|
1026
|
+
__name(this, "PolarBenefitService");
|
|
1027
|
+
}
|
|
1028
|
+
benefitModel;
|
|
1029
|
+
benefitGrantModel;
|
|
1030
|
+
constructor(benefitModel, benefitGrantModel) {
|
|
1031
|
+
this.benefitModel = benefitModel;
|
|
1032
|
+
this.benefitGrantModel = benefitGrantModel;
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Upsert a benefit from a webhook benefit payload.
|
|
1036
|
+
*/
|
|
1037
|
+
async syncBenefit(data) {
|
|
1038
|
+
const benefitData = {
|
|
1039
|
+
polarBenefitId: data.id,
|
|
1040
|
+
type: data.type,
|
|
1041
|
+
description: data.description,
|
|
1042
|
+
organizationId: data.organizationId,
|
|
1043
|
+
selectable: data.selectable,
|
|
1044
|
+
deletable: data.deletable
|
|
1045
|
+
};
|
|
1046
|
+
const existing = await this.benefitModel.findOne({
|
|
1047
|
+
polarBenefitId: data.id
|
|
1048
|
+
});
|
|
1049
|
+
if (existing) {
|
|
1050
|
+
return this.benefitModel.update({
|
|
1051
|
+
polarBenefitId: data.id
|
|
1052
|
+
}, benefitData);
|
|
1053
|
+
}
|
|
1054
|
+
return this.benefitModel.create(benefitData);
|
|
1055
|
+
}
|
|
1056
|
+
/**
|
|
1057
|
+
* Upsert a benefit grant from a webhook payload.
|
|
1058
|
+
* Handles created, updated, and revoked states.
|
|
1059
|
+
*/
|
|
1060
|
+
async syncBenefitGrant(data) {
|
|
1061
|
+
const grantData = {
|
|
1062
|
+
polarBenefitGrantId: data.id,
|
|
1063
|
+
benefitId: data.benefitId,
|
|
1064
|
+
customerId: data.customerId,
|
|
1065
|
+
subscriptionId: data.subscriptionId,
|
|
1066
|
+
isGranted: data.isGranted,
|
|
1067
|
+
isRevoked: data.isRevoked,
|
|
1068
|
+
grantedAt: data.grantedAt,
|
|
1069
|
+
revokedAt: data.revokedAt
|
|
1070
|
+
};
|
|
1071
|
+
const existing = await this.benefitGrantModel.findOne({
|
|
1072
|
+
polarBenefitGrantId: data.id
|
|
1073
|
+
});
|
|
1074
|
+
if (existing) {
|
|
1075
|
+
return this.benefitGrantModel.update({
|
|
1076
|
+
polarBenefitGrantId: data.id
|
|
1077
|
+
}, grantData);
|
|
1078
|
+
}
|
|
1079
|
+
return this.benefitGrantModel.create(grantData);
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* Find active benefit grants for a customer.
|
|
1083
|
+
*/
|
|
1084
|
+
async findGrantsByCustomerId(customerId) {
|
|
1085
|
+
return this.benefitGrantModel.findMany({
|
|
1086
|
+
customerId,
|
|
1087
|
+
isGranted: true,
|
|
1088
|
+
isRevoked: false
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* List all benefits.
|
|
1093
|
+
*/
|
|
1094
|
+
async findAll() {
|
|
1095
|
+
return this.benefitModel.find();
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* List all benefit grants.
|
|
1099
|
+
*/
|
|
1100
|
+
async findGrantsAll() {
|
|
1101
|
+
return this.benefitGrantModel.find();
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
PolarBenefitService = _ts_decorate11([
|
|
1105
|
+
common.Injectable(),
|
|
1106
|
+
_ts_param5(0, common$1.InjectModel(PolarBenefit)),
|
|
1107
|
+
_ts_param5(1, common$1.InjectModel(PolarBenefitGrant)),
|
|
1108
|
+
_ts_metadata11("design:type", Function),
|
|
1109
|
+
_ts_metadata11("design:paramtypes", [
|
|
1110
|
+
typeof Model === "undefined" ? Object : Model,
|
|
1111
|
+
typeof Model === "undefined" ? Object : Model
|
|
1112
|
+
])
|
|
1113
|
+
], PolarBenefitService);
|
|
1114
|
+
}
|
|
1115
|
+
});
|
|
1116
|
+
function _ts_decorate12(decorators, target, key, desc) {
|
|
1117
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1118
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1119
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1120
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1121
|
+
}
|
|
1122
|
+
function _ts_metadata12(k, v) {
|
|
1123
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1124
|
+
}
|
|
1125
|
+
var PolarCheckoutService;
|
|
1126
|
+
var init_checkout_service = __esm({
|
|
1127
|
+
"src/services/checkout.service.ts"() {
|
|
1128
|
+
init_polar_service();
|
|
1129
|
+
__name(_ts_decorate12, "_ts_decorate");
|
|
1130
|
+
__name(_ts_metadata12, "_ts_metadata");
|
|
1131
|
+
PolarCheckoutService = class {
|
|
1132
|
+
static {
|
|
1133
|
+
__name(this, "PolarCheckoutService");
|
|
1134
|
+
}
|
|
1135
|
+
polarService;
|
|
1136
|
+
constructor(polarService) {
|
|
1137
|
+
this.polarService = polarService;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Create a Polar Checkout session.
|
|
1141
|
+
*/
|
|
1142
|
+
async createCheckoutSession(dto) {
|
|
1143
|
+
const checkout = await this.polarService.client.checkouts.create({
|
|
1144
|
+
products: dto.products,
|
|
1145
|
+
successUrl: dto.successUrl,
|
|
1146
|
+
returnUrl: dto.returnUrl,
|
|
1147
|
+
customerEmail: dto.customerEmail,
|
|
1148
|
+
externalCustomerId: dto.userId,
|
|
1149
|
+
metadata: dto.metadata
|
|
1150
|
+
});
|
|
1151
|
+
return {
|
|
1152
|
+
sessionId: checkout.id,
|
|
1153
|
+
url: checkout.url
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1157
|
+
PolarCheckoutService = _ts_decorate12([
|
|
1158
|
+
common.Injectable(),
|
|
1159
|
+
_ts_metadata12("design:type", Function),
|
|
1160
|
+
_ts_metadata12("design:paramtypes", [
|
|
1161
|
+
typeof PolarService === "undefined" ? Object : PolarService
|
|
1162
|
+
])
|
|
1163
|
+
], PolarCheckoutService);
|
|
1164
|
+
}
|
|
1165
|
+
});
|
|
1166
|
+
function _ts_decorate13(decorators, target, key, desc) {
|
|
1167
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1168
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1169
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1170
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1171
|
+
}
|
|
1172
|
+
function _ts_metadata13(k, v) {
|
|
1173
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1174
|
+
}
|
|
1175
|
+
function _ts_param6(paramIndex, decorator) {
|
|
1176
|
+
return function(target, key) {
|
|
1177
|
+
decorator(target, key, paramIndex);
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
var PolarMetricsService;
|
|
1181
|
+
var init_metrics_service = __esm({
|
|
1182
|
+
"src/services/metrics.service.ts"() {
|
|
1183
|
+
init_polar_service();
|
|
1184
|
+
init_order_schema();
|
|
1185
|
+
init_subscription_schema();
|
|
1186
|
+
__name(_ts_decorate13, "_ts_decorate");
|
|
1187
|
+
__name(_ts_metadata13, "_ts_metadata");
|
|
1188
|
+
__name(_ts_param6, "_ts_param");
|
|
1189
|
+
PolarMetricsService = class _PolarMetricsService {
|
|
1190
|
+
static {
|
|
1191
|
+
__name(this, "PolarMetricsService");
|
|
1192
|
+
}
|
|
1193
|
+
orderModel;
|
|
1194
|
+
subscriptionModel;
|
|
1195
|
+
polarService;
|
|
1196
|
+
logger;
|
|
1197
|
+
constructor(orderModel, subscriptionModel, polarService) {
|
|
1198
|
+
this.orderModel = orderModel;
|
|
1199
|
+
this.subscriptionModel = subscriptionModel;
|
|
1200
|
+
this.polarService = polarService;
|
|
1201
|
+
this.logger = new common.Logger(_PolarMetricsService.name);
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Get dashboard metrics — hybrid of live Polar API and local DB data.
|
|
1205
|
+
*/
|
|
1206
|
+
async getMetrics() {
|
|
1207
|
+
try {
|
|
1208
|
+
return await this.getMetricsFromApi();
|
|
1209
|
+
} catch (error) {
|
|
1210
|
+
this.logger.warn(`Failed to fetch metrics from Polar API, falling back to local DB: ${error instanceof Error ? error.message : String(error)}`);
|
|
1211
|
+
return this.getMetricsFromDb();
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Fetch metrics from Polar's analytics API.
|
|
1216
|
+
*/
|
|
1217
|
+
async getMetricsFromApi() {
|
|
1218
|
+
const now = /* @__PURE__ */ new Date();
|
|
1219
|
+
const startDate = new Date(now.getFullYear(), now.getMonth() - 11, 1);
|
|
1220
|
+
const response = await this.polarService.client.metrics.get({
|
|
1221
|
+
startDate: new rfcdate.RFCDate(startDate),
|
|
1222
|
+
endDate: new rfcdate.RFCDate(now),
|
|
1223
|
+
interval: "month"
|
|
1224
|
+
});
|
|
1225
|
+
const periods = response.periods;
|
|
1226
|
+
const latestPeriod = periods[periods.length - 1];
|
|
1227
|
+
const mrr = Number(latestPeriod?.monthlyRecurringRevenue ?? 0);
|
|
1228
|
+
const revenueThisMonth = Number(latestPeriod?.revenue ?? 0);
|
|
1229
|
+
const activeSubscriptions = Number(latestPeriod?.activeSubscriptions ?? 0);
|
|
1230
|
+
const churned = Number(latestPeriod?.churnedSubscriptions ?? 0);
|
|
1231
|
+
const churnRate = activeSubscriptions + churned > 0 ? Math.round(churned / (activeSubscriptions + churned) * 100) : 0;
|
|
1232
|
+
const revenueByMonth = periods.map((period) => {
|
|
1233
|
+
const d = period.timestamp;
|
|
1234
|
+
const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
|
|
1235
|
+
return {
|
|
1236
|
+
month: key,
|
|
1237
|
+
revenue: Number(period.revenue ?? 0)
|
|
1238
|
+
};
|
|
1239
|
+
});
|
|
1240
|
+
const recentOrders = await this.getRecentOrders();
|
|
1241
|
+
return {
|
|
1242
|
+
mrr,
|
|
1243
|
+
revenueThisMonth,
|
|
1244
|
+
activeSubscriptions,
|
|
1245
|
+
churnRate,
|
|
1246
|
+
revenueByMonth,
|
|
1247
|
+
recentOrders
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Fall back to local DB computation if API call fails.
|
|
1252
|
+
*/
|
|
1253
|
+
async getMetricsFromDb() {
|
|
1254
|
+
const [activeSubscriptions, revenueThisMonth, recentOrders] = await Promise.all([
|
|
1255
|
+
this.countActiveSubscriptions(),
|
|
1256
|
+
this.calculateRevenueThisMonth(),
|
|
1257
|
+
this.getRecentOrders()
|
|
1258
|
+
]);
|
|
1259
|
+
const churnRate = await this.calculateChurnRate();
|
|
1260
|
+
const revenueByMonth = await this.getRevenueByMonth();
|
|
1261
|
+
return {
|
|
1262
|
+
mrr: 0,
|
|
1263
|
+
revenueThisMonth,
|
|
1264
|
+
activeSubscriptions,
|
|
1265
|
+
churnRate,
|
|
1266
|
+
revenueByMonth,
|
|
1267
|
+
recentOrders
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
async countActiveSubscriptions() {
|
|
1271
|
+
const subs = await this.subscriptionModel.findMany({
|
|
1272
|
+
status: "active"
|
|
1273
|
+
});
|
|
1274
|
+
return subs.length;
|
|
1275
|
+
}
|
|
1276
|
+
async calculateRevenueThisMonth() {
|
|
1277
|
+
const orders = await this.orderModel.findMany({
|
|
1278
|
+
status: "paid"
|
|
1279
|
+
});
|
|
1280
|
+
const now = /* @__PURE__ */ new Date();
|
|
1281
|
+
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
1282
|
+
return orders.filter((o) => new Date(o.createdAt) >= startOfMonth).reduce((sum, o) => sum + o.totalAmount, 0);
|
|
1283
|
+
}
|
|
1284
|
+
async calculateChurnRate() {
|
|
1285
|
+
const allSubs = await this.subscriptionModel.find();
|
|
1286
|
+
if (allSubs.length === 0) return 0;
|
|
1287
|
+
const canceled = allSubs.filter((s) => s.status === "canceled");
|
|
1288
|
+
return Math.round(canceled.length / allSubs.length * 100);
|
|
1289
|
+
}
|
|
1290
|
+
async getRevenueByMonth() {
|
|
1291
|
+
const orders = await this.orderModel.findMany({
|
|
1292
|
+
status: "paid"
|
|
1293
|
+
});
|
|
1294
|
+
const monthMap = /* @__PURE__ */ new Map();
|
|
1295
|
+
const now = /* @__PURE__ */ new Date();
|
|
1296
|
+
for (let i = 11; i >= 0; i--) {
|
|
1297
|
+
const d = new Date(now.getFullYear(), now.getMonth() - i, 1);
|
|
1298
|
+
const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
|
|
1299
|
+
monthMap.set(key, 0);
|
|
1300
|
+
}
|
|
1301
|
+
for (const order of orders) {
|
|
1302
|
+
const d = new Date(order.createdAt);
|
|
1303
|
+
const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
|
|
1304
|
+
if (monthMap.has(key)) {
|
|
1305
|
+
monthMap.set(key, (monthMap.get(key) ?? 0) + order.totalAmount);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
return Array.from(monthMap.entries()).map(([month, revenue]) => ({
|
|
1309
|
+
month,
|
|
1310
|
+
revenue
|
|
1311
|
+
}));
|
|
1312
|
+
}
|
|
1313
|
+
async getRecentOrders() {
|
|
1314
|
+
const orders = await this.orderModel.find();
|
|
1315
|
+
return orders.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()).slice(0, 10).map((o) => ({
|
|
1316
|
+
id: o.id,
|
|
1317
|
+
totalAmount: o.totalAmount,
|
|
1318
|
+
currency: o.currency,
|
|
1319
|
+
status: o.status,
|
|
1320
|
+
customerEmail: o.customerId,
|
|
1321
|
+
createdAt: o.createdAt.toISOString()
|
|
1322
|
+
}));
|
|
1323
|
+
}
|
|
1324
|
+
};
|
|
1325
|
+
PolarMetricsService = _ts_decorate13([
|
|
1326
|
+
common.Injectable(),
|
|
1327
|
+
_ts_param6(0, common$1.InjectModel(PolarOrder)),
|
|
1328
|
+
_ts_param6(1, common$1.InjectModel(PolarSubscription)),
|
|
1329
|
+
_ts_metadata13("design:type", Function),
|
|
1330
|
+
_ts_metadata13("design:paramtypes", [
|
|
1331
|
+
typeof Model === "undefined" ? Object : Model,
|
|
1332
|
+
typeof Model === "undefined" ? Object : Model,
|
|
1333
|
+
typeof PolarService === "undefined" ? Object : PolarService
|
|
1334
|
+
])
|
|
1335
|
+
], PolarMetricsService);
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
function _ts_decorate14(decorators, target, key, desc) {
|
|
1339
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1340
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1341
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1342
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1343
|
+
}
|
|
1344
|
+
function _ts_metadata14(k, v) {
|
|
1345
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1346
|
+
}
|
|
1347
|
+
var PolarPortalService;
|
|
1348
|
+
var init_portal_service = __esm({
|
|
1349
|
+
"src/services/portal.service.ts"() {
|
|
1350
|
+
init_polar_service();
|
|
1351
|
+
init_customer_service();
|
|
1352
|
+
__name(_ts_decorate14, "_ts_decorate");
|
|
1353
|
+
__name(_ts_metadata14, "_ts_metadata");
|
|
1354
|
+
PolarPortalService = class {
|
|
1355
|
+
static {
|
|
1356
|
+
__name(this, "PolarPortalService");
|
|
1357
|
+
}
|
|
1358
|
+
polarService;
|
|
1359
|
+
customerService;
|
|
1360
|
+
constructor(polarService, customerService) {
|
|
1361
|
+
this.polarService = polarService;
|
|
1362
|
+
this.customerService = customerService;
|
|
1363
|
+
}
|
|
1364
|
+
/**
|
|
1365
|
+
* Create a Polar Customer Portal session.
|
|
1366
|
+
*/
|
|
1367
|
+
async createPortalSession(dto) {
|
|
1368
|
+
let customerId = dto.customerId;
|
|
1369
|
+
if (!customerId && dto.userId) {
|
|
1370
|
+
const customer = await this.customerService.findByUserId(dto.userId);
|
|
1371
|
+
if (!customer) {
|
|
1372
|
+
throw new common.HttpException("No Polar customer found for this user", common.HttpStatus.NOT_FOUND);
|
|
1373
|
+
}
|
|
1374
|
+
customerId = customer.polarCustomerId;
|
|
1375
|
+
}
|
|
1376
|
+
if (!customerId) {
|
|
1377
|
+
throw new common.HttpException("Either customerId or userId must be provided", common.HttpStatus.BAD_REQUEST);
|
|
1378
|
+
}
|
|
1379
|
+
const session = await this.polarService.client.customerSessions.create({
|
|
1380
|
+
customerId,
|
|
1381
|
+
returnUrl: dto.returnUrl
|
|
1382
|
+
});
|
|
1383
|
+
return {
|
|
1384
|
+
sessionId: session.id,
|
|
1385
|
+
url: session.customerPortalUrl
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
};
|
|
1389
|
+
PolarPortalService = _ts_decorate14([
|
|
1390
|
+
common.Injectable(),
|
|
1391
|
+
_ts_metadata14("design:type", Function),
|
|
1392
|
+
_ts_metadata14("design:paramtypes", [
|
|
1393
|
+
typeof PolarService === "undefined" ? Object : PolarService,
|
|
1394
|
+
typeof PolarCustomerService === "undefined" ? Object : PolarCustomerService
|
|
1395
|
+
])
|
|
1396
|
+
], PolarPortalService);
|
|
1397
|
+
}
|
|
1398
|
+
});
|
|
1399
|
+
function _ts_decorate15(decorators, target, key, desc) {
|
|
1400
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1401
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1402
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1403
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1404
|
+
}
|
|
1405
|
+
function _ts_metadata15(k, v) {
|
|
1406
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1407
|
+
}
|
|
1408
|
+
function _ts_param7(paramIndex, decorator) {
|
|
1409
|
+
return function(target, key) {
|
|
1410
|
+
decorator(target, key, paramIndex);
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
var PolarProductService;
|
|
1414
|
+
var init_product_service = __esm({
|
|
1415
|
+
"src/services/product.service.ts"() {
|
|
1416
|
+
init_product_schema();
|
|
1417
|
+
__name(_ts_decorate15, "_ts_decorate");
|
|
1418
|
+
__name(_ts_metadata15, "_ts_metadata");
|
|
1419
|
+
__name(_ts_param7, "_ts_param");
|
|
1420
|
+
PolarProductService = class {
|
|
1421
|
+
static {
|
|
1422
|
+
__name(this, "PolarProductService");
|
|
1423
|
+
}
|
|
1424
|
+
productModel;
|
|
1425
|
+
constructor(productModel) {
|
|
1426
|
+
this.productModel = productModel;
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* Upsert a product from a webhook product payload.
|
|
1430
|
+
*/
|
|
1431
|
+
async syncProduct(data) {
|
|
1432
|
+
const productData = {
|
|
1433
|
+
polarProductId: data.id,
|
|
1434
|
+
name: data.name,
|
|
1435
|
+
description: data.description ?? void 0,
|
|
1436
|
+
isRecurring: data.isRecurring,
|
|
1437
|
+
isArchived: data.isArchived,
|
|
1438
|
+
organizationId: data.organizationId,
|
|
1439
|
+
metadata: data.metadata,
|
|
1440
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1441
|
+
};
|
|
1442
|
+
const existing = await this.productModel.findOne({
|
|
1443
|
+
polarProductId: data.id
|
|
1444
|
+
});
|
|
1445
|
+
if (existing) {
|
|
1446
|
+
return this.productModel.update({
|
|
1447
|
+
polarProductId: data.id
|
|
1448
|
+
}, productData);
|
|
1449
|
+
}
|
|
1450
|
+
return this.productModel.create(productData);
|
|
1451
|
+
}
|
|
1452
|
+
/**
|
|
1453
|
+
* Delete a product by Polar Product ID.
|
|
1454
|
+
*/
|
|
1455
|
+
async deleteProduct(polarProductId) {
|
|
1456
|
+
await this.productModel.delete({
|
|
1457
|
+
polarProductId
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* List all non-archived products.
|
|
1462
|
+
*/
|
|
1463
|
+
async findActiveProducts() {
|
|
1464
|
+
return this.productModel.findMany({
|
|
1465
|
+
isArchived: false
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* List all products.
|
|
1470
|
+
*/
|
|
1471
|
+
async findAllProducts() {
|
|
1472
|
+
return this.productModel.find();
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
PolarProductService = _ts_decorate15([
|
|
1476
|
+
common.Injectable(),
|
|
1477
|
+
_ts_param7(0, common$1.InjectModel(PolarProduct)),
|
|
1478
|
+
_ts_metadata15("design:type", Function),
|
|
1479
|
+
_ts_metadata15("design:paramtypes", [
|
|
1480
|
+
typeof Model === "undefined" ? Object : Model
|
|
1481
|
+
])
|
|
1482
|
+
], PolarProductService);
|
|
1483
|
+
}
|
|
1484
|
+
});
|
|
1485
|
+
function _ts_decorate16(decorators, target, key, desc) {
|
|
1486
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1487
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1488
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1489
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1490
|
+
}
|
|
1491
|
+
function _ts_metadata16(k, v) {
|
|
1492
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1493
|
+
}
|
|
1494
|
+
function _ts_param8(paramIndex, decorator) {
|
|
1495
|
+
return function(target, key) {
|
|
1496
|
+
decorator(target, key, paramIndex);
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
var PolarApiController;
|
|
1500
|
+
var init_polar_api_controller = __esm({
|
|
1501
|
+
"src/polar-api.controller.ts"() {
|
|
1502
|
+
init_polar_service();
|
|
1503
|
+
init_order_schema();
|
|
1504
|
+
init_access_service();
|
|
1505
|
+
init_benefit_service();
|
|
1506
|
+
init_checkout_service();
|
|
1507
|
+
init_customer_service();
|
|
1508
|
+
init_metrics_service();
|
|
1509
|
+
init_portal_service();
|
|
1510
|
+
init_product_service();
|
|
1511
|
+
init_subscription_service();
|
|
1512
|
+
__name(_ts_decorate16, "_ts_decorate");
|
|
1513
|
+
__name(_ts_metadata16, "_ts_metadata");
|
|
1514
|
+
__name(_ts_param8, "_ts_param");
|
|
1515
|
+
PolarApiController = class {
|
|
1516
|
+
static {
|
|
1517
|
+
__name(this, "PolarApiController");
|
|
1518
|
+
}
|
|
1519
|
+
accessService;
|
|
1520
|
+
benefitService;
|
|
1521
|
+
checkoutService;
|
|
1522
|
+
customerService;
|
|
1523
|
+
metricsService;
|
|
1524
|
+
orderModel;
|
|
1525
|
+
portalService;
|
|
1526
|
+
productService;
|
|
1527
|
+
polarService;
|
|
1528
|
+
subscriptionService;
|
|
1529
|
+
constructor(accessService, benefitService, checkoutService, customerService, metricsService, orderModel, portalService, productService, polarService, subscriptionService) {
|
|
1530
|
+
this.accessService = accessService;
|
|
1531
|
+
this.benefitService = benefitService;
|
|
1532
|
+
this.checkoutService = checkoutService;
|
|
1533
|
+
this.customerService = customerService;
|
|
1534
|
+
this.metricsService = metricsService;
|
|
1535
|
+
this.orderModel = orderModel;
|
|
1536
|
+
this.portalService = portalService;
|
|
1537
|
+
this.productService = productService;
|
|
1538
|
+
this.polarService = polarService;
|
|
1539
|
+
this.subscriptionService = subscriptionService;
|
|
1540
|
+
}
|
|
1541
|
+
// =========================================================================
|
|
1542
|
+
// Public Endpoints
|
|
1543
|
+
// =========================================================================
|
|
1544
|
+
/**
|
|
1545
|
+
* Create a Polar Checkout session.
|
|
1546
|
+
* POST /polar/checkout
|
|
1547
|
+
*/
|
|
1548
|
+
async createCheckout(dto) {
|
|
1549
|
+
try {
|
|
1550
|
+
return await this.checkoutService.createCheckoutSession(dto);
|
|
1551
|
+
} catch (error) {
|
|
1552
|
+
if (error instanceof common.HttpException) throw error;
|
|
1553
|
+
throw new common.HttpException(error instanceof Error ? error.message : "Failed to create checkout session", common.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* Create a Polar Customer Portal session.
|
|
1558
|
+
* POST /polar/portal
|
|
1559
|
+
*/
|
|
1560
|
+
async createPortal(dto) {
|
|
1561
|
+
try {
|
|
1562
|
+
return await this.portalService.createPortalSession(dto);
|
|
1563
|
+
} catch (error) {
|
|
1564
|
+
if (error instanceof common.HttpException) throw error;
|
|
1565
|
+
throw new common.HttpException(error instanceof Error ? error.message : "Failed to create portal session", common.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
/**
|
|
1569
|
+
* List active products.
|
|
1570
|
+
* GET /polar/products
|
|
1571
|
+
*/
|
|
1572
|
+
async listProducts() {
|
|
1573
|
+
return this.productService.findActiveProducts();
|
|
1574
|
+
}
|
|
1575
|
+
/**
|
|
1576
|
+
* Get a user's active subscription.
|
|
1577
|
+
* GET /polar/subscription/:userId
|
|
1578
|
+
*/
|
|
1579
|
+
async getUserSubscription(userId) {
|
|
1580
|
+
const customer = await this.customerService.findByUserId(userId);
|
|
1581
|
+
if (!customer) {
|
|
1582
|
+
return {
|
|
1583
|
+
subscription: null
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
const subscription = await this.subscriptionService.findActiveByCustomerId(customer.polarCustomerId);
|
|
1587
|
+
return {
|
|
1588
|
+
subscription
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* Get subscription access info and feature flags for a user.
|
|
1593
|
+
* GET /polar/access/:userId
|
|
1594
|
+
*/
|
|
1595
|
+
async getAccess(userId) {
|
|
1596
|
+
return this.accessService.getAccess(userId);
|
|
1597
|
+
}
|
|
1598
|
+
// =========================================================================
|
|
1599
|
+
// Admin Endpoints
|
|
1600
|
+
// =========================================================================
|
|
1601
|
+
/**
|
|
1602
|
+
* Get dashboard metrics.
|
|
1603
|
+
* GET /polar/admin/metrics
|
|
1604
|
+
*/
|
|
1605
|
+
async getMetrics() {
|
|
1606
|
+
return this.metricsService.getMetrics();
|
|
1607
|
+
}
|
|
1608
|
+
/**
|
|
1609
|
+
* List all customers (admin).
|
|
1610
|
+
* GET /polar/admin/customers
|
|
1611
|
+
*/
|
|
1612
|
+
async listCustomers() {
|
|
1613
|
+
return this.customerService.findAll();
|
|
1614
|
+
}
|
|
1615
|
+
/**
|
|
1616
|
+
* List all subscriptions (admin).
|
|
1617
|
+
* GET /polar/admin/subscriptions
|
|
1618
|
+
*/
|
|
1619
|
+
async listSubscriptions() {
|
|
1620
|
+
return this.subscriptionService.findAll();
|
|
1621
|
+
}
|
|
1622
|
+
/**
|
|
1623
|
+
* Cancel (revoke) a subscription (admin).
|
|
1624
|
+
* POST /polar/admin/subscriptions/:id/cancel
|
|
1625
|
+
*/
|
|
1626
|
+
async cancelSubscription(polarSubscriptionId) {
|
|
1627
|
+
await this.subscriptionService.revoke(polarSubscriptionId);
|
|
1628
|
+
return {
|
|
1629
|
+
canceled: true
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* List all products (admin).
|
|
1634
|
+
* GET /polar/admin/products
|
|
1635
|
+
*/
|
|
1636
|
+
async listAllProducts() {
|
|
1637
|
+
return this.productService.findAllProducts();
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* Sync products from Polar API (admin).
|
|
1641
|
+
* POST /polar/admin/sync-products
|
|
1642
|
+
*/
|
|
1643
|
+
async syncProducts() {
|
|
1644
|
+
let productCount = 0;
|
|
1645
|
+
for await (const page of await this.polarService.client.products.list({})) {
|
|
1646
|
+
for (const product of page.result.items) {
|
|
1647
|
+
await this.productService.syncProduct({
|
|
1648
|
+
id: product.id,
|
|
1649
|
+
name: product.name,
|
|
1650
|
+
description: product.description ?? void 0,
|
|
1651
|
+
isRecurring: product.isRecurring,
|
|
1652
|
+
isArchived: product.isArchived,
|
|
1653
|
+
organizationId: product.organizationId,
|
|
1654
|
+
metadata: product.metadata
|
|
1655
|
+
});
|
|
1656
|
+
productCount++;
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
return {
|
|
1660
|
+
synced: true,
|
|
1661
|
+
products: productCount
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* List all orders (admin).
|
|
1666
|
+
* GET /polar/admin/orders
|
|
1667
|
+
*/
|
|
1668
|
+
async listOrders() {
|
|
1669
|
+
return this.orderModel.find();
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* List all benefits (admin).
|
|
1673
|
+
* GET /polar/admin/benefits
|
|
1674
|
+
*/
|
|
1675
|
+
async listBenefits() {
|
|
1676
|
+
return this.benefitService.findAll();
|
|
1677
|
+
}
|
|
1678
|
+
/**
|
|
1679
|
+
* List all benefit grants (admin).
|
|
1680
|
+
* GET /polar/admin/benefit-grants
|
|
1681
|
+
*/
|
|
1682
|
+
async listBenefitGrants() {
|
|
1683
|
+
return this.benefitService.findGrantsAll();
|
|
1684
|
+
}
|
|
1685
|
+
};
|
|
1686
|
+
_ts_decorate16([
|
|
1687
|
+
common.Post("checkout"),
|
|
1688
|
+
_ts_param8(0, common.Body()),
|
|
1689
|
+
_ts_metadata16("design:type", Function),
|
|
1690
|
+
_ts_metadata16("design:paramtypes", [
|
|
1691
|
+
typeof CreateCheckoutDto === "undefined" ? Object : CreateCheckoutDto
|
|
1692
|
+
]),
|
|
1693
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1694
|
+
], PolarApiController.prototype, "createCheckout", null);
|
|
1695
|
+
_ts_decorate16([
|
|
1696
|
+
common.Post("portal"),
|
|
1697
|
+
_ts_param8(0, common.Body()),
|
|
1698
|
+
_ts_metadata16("design:type", Function),
|
|
1699
|
+
_ts_metadata16("design:paramtypes", [
|
|
1700
|
+
typeof CreatePortalDto === "undefined" ? Object : CreatePortalDto
|
|
1701
|
+
]),
|
|
1702
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1703
|
+
], PolarApiController.prototype, "createPortal", null);
|
|
1704
|
+
_ts_decorate16([
|
|
1705
|
+
common.Get("products"),
|
|
1706
|
+
_ts_metadata16("design:type", Function),
|
|
1707
|
+
_ts_metadata16("design:paramtypes", []),
|
|
1708
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1709
|
+
], PolarApiController.prototype, "listProducts", null);
|
|
1710
|
+
_ts_decorate16([
|
|
1711
|
+
common.Get("subscription/:userId"),
|
|
1712
|
+
_ts_param8(0, common.Param("userId")),
|
|
1713
|
+
_ts_metadata16("design:type", Function),
|
|
1714
|
+
_ts_metadata16("design:paramtypes", [
|
|
1715
|
+
String
|
|
1716
|
+
]),
|
|
1717
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1718
|
+
], PolarApiController.prototype, "getUserSubscription", null);
|
|
1719
|
+
_ts_decorate16([
|
|
1720
|
+
common.Get("access/:userId"),
|
|
1721
|
+
core.RestrictedRoute(),
|
|
1722
|
+
_ts_param8(0, common.Param("userId")),
|
|
1723
|
+
_ts_metadata16("design:type", Function),
|
|
1724
|
+
_ts_metadata16("design:paramtypes", [
|
|
1725
|
+
String
|
|
1726
|
+
]),
|
|
1727
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1728
|
+
], PolarApiController.prototype, "getAccess", null);
|
|
1729
|
+
_ts_decorate16([
|
|
1730
|
+
common.Get("admin/metrics"),
|
|
1731
|
+
core.RestrictedRoute(),
|
|
1732
|
+
_ts_metadata16("design:type", Function),
|
|
1733
|
+
_ts_metadata16("design:paramtypes", []),
|
|
1734
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1735
|
+
], PolarApiController.prototype, "getMetrics", null);
|
|
1736
|
+
_ts_decorate16([
|
|
1737
|
+
common.Get("admin/customers"),
|
|
1738
|
+
core.RestrictedRoute(),
|
|
1739
|
+
_ts_metadata16("design:type", Function),
|
|
1740
|
+
_ts_metadata16("design:paramtypes", []),
|
|
1741
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1742
|
+
], PolarApiController.prototype, "listCustomers", null);
|
|
1743
|
+
_ts_decorate16([
|
|
1744
|
+
common.Get("admin/subscriptions"),
|
|
1745
|
+
core.RestrictedRoute(),
|
|
1746
|
+
_ts_metadata16("design:type", Function),
|
|
1747
|
+
_ts_metadata16("design:paramtypes", []),
|
|
1748
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1749
|
+
], PolarApiController.prototype, "listSubscriptions", null);
|
|
1750
|
+
_ts_decorate16([
|
|
1751
|
+
common.Post("admin/subscriptions/:id/cancel"),
|
|
1752
|
+
core.RestrictedRoute(),
|
|
1753
|
+
_ts_param8(0, common.Param("id")),
|
|
1754
|
+
_ts_metadata16("design:type", Function),
|
|
1755
|
+
_ts_metadata16("design:paramtypes", [
|
|
1756
|
+
String
|
|
1757
|
+
]),
|
|
1758
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1759
|
+
], PolarApiController.prototype, "cancelSubscription", null);
|
|
1760
|
+
_ts_decorate16([
|
|
1761
|
+
common.Get("admin/products"),
|
|
1762
|
+
core.RestrictedRoute(),
|
|
1763
|
+
_ts_metadata16("design:type", Function),
|
|
1764
|
+
_ts_metadata16("design:paramtypes", []),
|
|
1765
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1766
|
+
], PolarApiController.prototype, "listAllProducts", null);
|
|
1767
|
+
_ts_decorate16([
|
|
1768
|
+
common.Post("admin/sync-products"),
|
|
1769
|
+
core.RestrictedRoute(),
|
|
1770
|
+
_ts_metadata16("design:type", Function),
|
|
1771
|
+
_ts_metadata16("design:paramtypes", []),
|
|
1772
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1773
|
+
], PolarApiController.prototype, "syncProducts", null);
|
|
1774
|
+
_ts_decorate16([
|
|
1775
|
+
common.Get("admin/orders"),
|
|
1776
|
+
core.RestrictedRoute(),
|
|
1777
|
+
_ts_metadata16("design:type", Function),
|
|
1778
|
+
_ts_metadata16("design:paramtypes", []),
|
|
1779
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1780
|
+
], PolarApiController.prototype, "listOrders", null);
|
|
1781
|
+
_ts_decorate16([
|
|
1782
|
+
common.Get("admin/benefits"),
|
|
1783
|
+
core.RestrictedRoute(),
|
|
1784
|
+
_ts_metadata16("design:type", Function),
|
|
1785
|
+
_ts_metadata16("design:paramtypes", []),
|
|
1786
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1787
|
+
], PolarApiController.prototype, "listBenefits", null);
|
|
1788
|
+
_ts_decorate16([
|
|
1789
|
+
common.Get("admin/benefit-grants"),
|
|
1790
|
+
core.RestrictedRoute(),
|
|
1791
|
+
_ts_metadata16("design:type", Function),
|
|
1792
|
+
_ts_metadata16("design:paramtypes", []),
|
|
1793
|
+
_ts_metadata16("design:returntype", Promise)
|
|
1794
|
+
], PolarApiController.prototype, "listBenefitGrants", null);
|
|
1795
|
+
PolarApiController = _ts_decorate16([
|
|
1796
|
+
common.Controller("polar"),
|
|
1797
|
+
_ts_param8(5, common$1.InjectModel(PolarOrder)),
|
|
1798
|
+
_ts_metadata16("design:type", Function),
|
|
1799
|
+
_ts_metadata16("design:paramtypes", [
|
|
1800
|
+
typeof PolarAccessService === "undefined" ? Object : PolarAccessService,
|
|
1801
|
+
typeof PolarBenefitService === "undefined" ? Object : PolarBenefitService,
|
|
1802
|
+
typeof PolarCheckoutService === "undefined" ? Object : PolarCheckoutService,
|
|
1803
|
+
typeof PolarCustomerService === "undefined" ? Object : PolarCustomerService,
|
|
1804
|
+
typeof PolarMetricsService === "undefined" ? Object : PolarMetricsService,
|
|
1805
|
+
typeof Model === "undefined" ? Object : Model,
|
|
1806
|
+
typeof PolarPortalService === "undefined" ? Object : PolarPortalService,
|
|
1807
|
+
typeof PolarProductService === "undefined" ? Object : PolarProductService,
|
|
1808
|
+
typeof PolarService === "undefined" ? Object : PolarService,
|
|
1809
|
+
typeof PolarSubscriptionService === "undefined" ? Object : PolarSubscriptionService
|
|
1810
|
+
])
|
|
1811
|
+
], PolarApiController);
|
|
1812
|
+
}
|
|
1813
|
+
});
|
|
1814
|
+
function _ts_decorate17(decorators, target, key, desc) {
|
|
1815
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1816
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1817
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1818
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1819
|
+
}
|
|
1820
|
+
function _ts_metadata17(k, v) {
|
|
1821
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1822
|
+
}
|
|
1823
|
+
var PolarProcessedEvent;
|
|
1824
|
+
var init_processed_event_schema = __esm({
|
|
1825
|
+
"src/schemas/processed-event.schema.ts"() {
|
|
1826
|
+
__name(_ts_decorate17, "_ts_decorate");
|
|
1827
|
+
__name(_ts_metadata17, "_ts_metadata");
|
|
1828
|
+
PolarProcessedEvent = class {
|
|
1829
|
+
static {
|
|
1830
|
+
__name(this, "PolarProcessedEvent");
|
|
1831
|
+
}
|
|
1832
|
+
/** Polar Event ID — unique to prevent reprocessing */
|
|
1833
|
+
polarEventId;
|
|
1834
|
+
/** Event type (e.g., 'order.paid', 'subscription.updated') */
|
|
1835
|
+
eventType;
|
|
1836
|
+
/** When this event was processed */
|
|
1837
|
+
processedAt;
|
|
1838
|
+
};
|
|
1839
|
+
_ts_decorate17([
|
|
1840
|
+
common$1.Field.Text({
|
|
1841
|
+
required: true,
|
|
1842
|
+
unique: true
|
|
1843
|
+
}),
|
|
1844
|
+
_ts_metadata17("design:type", String)
|
|
1845
|
+
], PolarProcessedEvent.prototype, "polarEventId", void 0);
|
|
1846
|
+
_ts_decorate17([
|
|
1847
|
+
common$1.Field.Text({
|
|
1848
|
+
required: true
|
|
1849
|
+
}),
|
|
1850
|
+
_ts_metadata17("design:type", String)
|
|
1851
|
+
], PolarProcessedEvent.prototype, "eventType", void 0);
|
|
1852
|
+
_ts_decorate17([
|
|
1853
|
+
common$1.Field.Date({
|
|
1854
|
+
required: true,
|
|
1855
|
+
default: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "default")
|
|
1856
|
+
}),
|
|
1857
|
+
_ts_metadata17("design:type", typeof Date === "undefined" ? Object : Date)
|
|
1858
|
+
], PolarProcessedEvent.prototype, "processedAt", void 0);
|
|
1859
|
+
PolarProcessedEvent = _ts_decorate17([
|
|
1860
|
+
common$1.Schema({
|
|
1861
|
+
versioning: false,
|
|
1862
|
+
i18n: false,
|
|
1863
|
+
visible: false
|
|
1864
|
+
})
|
|
1865
|
+
], PolarProcessedEvent);
|
|
1866
|
+
}
|
|
1867
|
+
});
|
|
1868
|
+
function _ts_decorate18(decorators, target, key, desc) {
|
|
1869
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1870
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1871
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1872
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1873
|
+
}
|
|
1874
|
+
function _ts_metadata18(k, v) {
|
|
1875
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1876
|
+
}
|
|
1877
|
+
function _ts_param9(paramIndex, decorator) {
|
|
1878
|
+
return function(target, key) {
|
|
1879
|
+
decorator(target, key, paramIndex);
|
|
1880
|
+
};
|
|
1881
|
+
}
|
|
1882
|
+
var PolarOrderService;
|
|
1883
|
+
var init_order_service = __esm({
|
|
1884
|
+
"src/services/order.service.ts"() {
|
|
1885
|
+
init_order_schema();
|
|
1886
|
+
__name(_ts_decorate18, "_ts_decorate");
|
|
1887
|
+
__name(_ts_metadata18, "_ts_metadata");
|
|
1888
|
+
__name(_ts_param9, "_ts_param");
|
|
1889
|
+
PolarOrderService = class {
|
|
1890
|
+
static {
|
|
1891
|
+
__name(this, "PolarOrderService");
|
|
1892
|
+
}
|
|
1893
|
+
orderModel;
|
|
1894
|
+
constructor(orderModel) {
|
|
1895
|
+
this.orderModel = orderModel;
|
|
1896
|
+
}
|
|
1897
|
+
/**
|
|
1898
|
+
* Upsert an order from a webhook order payload.
|
|
1899
|
+
*/
|
|
1900
|
+
async syncOrder(data) {
|
|
1901
|
+
const orderData = {
|
|
1902
|
+
polarOrderId: data.id,
|
|
1903
|
+
customerId: data.customerId,
|
|
1904
|
+
productId: data.productId,
|
|
1905
|
+
subscriptionId: data.subscriptionId ?? void 0,
|
|
1906
|
+
status: data.status === "paid" ? "paid" : data.status === "refunded" ? "refunded" : "pending",
|
|
1907
|
+
totalAmount: data.totalAmount,
|
|
1908
|
+
currency: data.currency,
|
|
1909
|
+
billingReason: data.billingReason,
|
|
1910
|
+
createdAt: data.createdAt ?? /* @__PURE__ */ new Date()
|
|
1911
|
+
};
|
|
1912
|
+
const existing = await this.orderModel.findOne({
|
|
1913
|
+
polarOrderId: data.id
|
|
1914
|
+
});
|
|
1915
|
+
if (existing) {
|
|
1916
|
+
return this.orderModel.update({
|
|
1917
|
+
polarOrderId: data.id
|
|
1918
|
+
}, orderData);
|
|
1919
|
+
}
|
|
1920
|
+
return this.orderModel.create(orderData);
|
|
1921
|
+
}
|
|
1922
|
+
/**
|
|
1923
|
+
* List all orders.
|
|
1924
|
+
*/
|
|
1925
|
+
async findAll() {
|
|
1926
|
+
return this.orderModel.find();
|
|
1927
|
+
}
|
|
1928
|
+
/**
|
|
1929
|
+
* Find orders for a customer.
|
|
1930
|
+
*/
|
|
1931
|
+
async findByCustomerId(customerId) {
|
|
1932
|
+
return this.orderModel.findMany({
|
|
1933
|
+
customerId
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
};
|
|
1937
|
+
PolarOrderService = _ts_decorate18([
|
|
1938
|
+
common.Injectable(),
|
|
1939
|
+
_ts_param9(0, common$1.InjectModel(PolarOrder)),
|
|
1940
|
+
_ts_metadata18("design:type", Function),
|
|
1941
|
+
_ts_metadata18("design:paramtypes", [
|
|
1942
|
+
typeof Model === "undefined" ? Object : Model
|
|
1943
|
+
])
|
|
1944
|
+
], PolarOrderService);
|
|
1945
|
+
}
|
|
1946
|
+
});
|
|
1947
|
+
function _ts_decorate19(decorators, target, key, desc) {
|
|
1948
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1949
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1950
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1951
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1952
|
+
}
|
|
1953
|
+
function _ts_metadata19(k, v) {
|
|
1954
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1955
|
+
}
|
|
1956
|
+
function _ts_param10(paramIndex, decorator) {
|
|
1957
|
+
return function(target, key) {
|
|
1958
|
+
decorator(target, key, paramIndex);
|
|
1959
|
+
};
|
|
1960
|
+
}
|
|
1961
|
+
var PolarWebhookService;
|
|
1962
|
+
var init_polar_webhook_service = __esm({
|
|
1963
|
+
"src/polar-webhook.service.ts"() {
|
|
1964
|
+
init_processed_event_schema();
|
|
1965
|
+
init_benefit_service();
|
|
1966
|
+
init_customer_service();
|
|
1967
|
+
init_order_service();
|
|
1968
|
+
init_product_service();
|
|
1969
|
+
init_subscription_service();
|
|
1970
|
+
__name(_ts_decorate19, "_ts_decorate");
|
|
1971
|
+
__name(_ts_metadata19, "_ts_metadata");
|
|
1972
|
+
__name(_ts_param10, "_ts_param");
|
|
1973
|
+
PolarWebhookService = class _PolarWebhookService {
|
|
1974
|
+
static {
|
|
1975
|
+
__name(this, "PolarWebhookService");
|
|
1976
|
+
}
|
|
1977
|
+
processedEventModel;
|
|
1978
|
+
customerService;
|
|
1979
|
+
productService;
|
|
1980
|
+
subscriptionService;
|
|
1981
|
+
orderService;
|
|
1982
|
+
benefitService;
|
|
1983
|
+
emailService;
|
|
1984
|
+
logger;
|
|
1985
|
+
constructor(processedEventModel, customerService, productService, subscriptionService, orderService, benefitService, emailService) {
|
|
1986
|
+
this.processedEventModel = processedEventModel;
|
|
1987
|
+
this.customerService = customerService;
|
|
1988
|
+
this.productService = productService;
|
|
1989
|
+
this.subscriptionService = subscriptionService;
|
|
1990
|
+
this.orderService = orderService;
|
|
1991
|
+
this.benefitService = benefitService;
|
|
1992
|
+
this.emailService = emailService;
|
|
1993
|
+
this.logger = new common.Logger(_PolarWebhookService.name);
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Process a verified Polar event with idempotency.
|
|
1997
|
+
* Returns silently if the event was already processed.
|
|
1998
|
+
*/
|
|
1999
|
+
async processEvent(event) {
|
|
2000
|
+
const eventId = "data" in event && event.data && "id" in event.data ? event.data.id : `${event.type}-${Date.now()}`;
|
|
2001
|
+
const existing = await this.findProcessedEvent(eventId);
|
|
2002
|
+
if (existing) {
|
|
2003
|
+
this.logger.log(`Event ${eventId} already processed, skipping`);
|
|
2004
|
+
return;
|
|
2005
|
+
}
|
|
2006
|
+
try {
|
|
2007
|
+
await this.dispatchEvent(event);
|
|
2008
|
+
await this.recordProcessedEvent(eventId, event.type);
|
|
2009
|
+
} catch (error) {
|
|
2010
|
+
this.logger.error(`Failed to process event ${eventId} (${event.type}): ${error instanceof Error ? error.message : String(error)}`);
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
/**
|
|
2014
|
+
* Dispatch event to the appropriate handler.
|
|
2015
|
+
*/
|
|
2016
|
+
async dispatchEvent(event) {
|
|
2017
|
+
switch (event.type) {
|
|
2018
|
+
case "customer.created":
|
|
2019
|
+
case "customer.updated":
|
|
2020
|
+
await this.customerService.upsertFromWebhook({
|
|
2021
|
+
id: event.data.id,
|
|
2022
|
+
email: event.data.email,
|
|
2023
|
+
name: event.data.name ?? void 0,
|
|
2024
|
+
externalId: event.data.externalId ?? void 0,
|
|
2025
|
+
metadata: event.data.metadata
|
|
2026
|
+
});
|
|
2027
|
+
break;
|
|
2028
|
+
case "customer.deleted":
|
|
2029
|
+
await this.customerService.deleteByPolarId(event.data.id);
|
|
2030
|
+
break;
|
|
2031
|
+
case "product.created":
|
|
2032
|
+
case "product.updated":
|
|
2033
|
+
await this.productService.syncProduct({
|
|
2034
|
+
id: event.data.id,
|
|
2035
|
+
name: event.data.name,
|
|
2036
|
+
description: event.data.description ?? void 0,
|
|
2037
|
+
isRecurring: event.data.isRecurring,
|
|
2038
|
+
isArchived: event.data.isArchived,
|
|
2039
|
+
organizationId: event.data.organizationId,
|
|
2040
|
+
metadata: event.data.metadata
|
|
2041
|
+
});
|
|
2042
|
+
break;
|
|
2043
|
+
case "subscription.created":
|
|
2044
|
+
case "subscription.updated":
|
|
2045
|
+
case "subscription.active":
|
|
2046
|
+
case "subscription.canceled":
|
|
2047
|
+
case "subscription.uncanceled":
|
|
2048
|
+
case "subscription.revoked":
|
|
2049
|
+
case "subscription.past_due":
|
|
2050
|
+
await this.subscriptionService.syncSubscription({
|
|
2051
|
+
id: event.data.id,
|
|
2052
|
+
customerId: event.data.customerId,
|
|
2053
|
+
productId: event.data.productId,
|
|
2054
|
+
status: event.data.status,
|
|
2055
|
+
amount: event.data.amount,
|
|
2056
|
+
currency: event.data.currency,
|
|
2057
|
+
recurringInterval: event.data.recurringInterval,
|
|
2058
|
+
currentPeriodStart: event.data.currentPeriodStart,
|
|
2059
|
+
currentPeriodEnd: event.data.currentPeriodEnd,
|
|
2060
|
+
cancelAtPeriodEnd: event.data.cancelAtPeriodEnd,
|
|
2061
|
+
startedAt: event.data.startedAt ?? void 0,
|
|
2062
|
+
endedAt: event.data.endedAt ?? void 0
|
|
2063
|
+
});
|
|
2064
|
+
break;
|
|
2065
|
+
case "order.created":
|
|
2066
|
+
case "order.paid":
|
|
2067
|
+
case "order.updated":
|
|
2068
|
+
await this.orderService.syncOrder({
|
|
2069
|
+
id: event.data.id,
|
|
2070
|
+
customerId: event.data.customerId,
|
|
2071
|
+
productId: event.data.productId ?? "",
|
|
2072
|
+
subscriptionId: event.data.subscriptionId ?? void 0,
|
|
2073
|
+
status: event.data.paid ? "paid" : "pending",
|
|
2074
|
+
totalAmount: event.data.totalAmount,
|
|
2075
|
+
currency: event.data.currency,
|
|
2076
|
+
billingReason: event.data.billingReason,
|
|
2077
|
+
createdAt: event.data.createdAt
|
|
2078
|
+
});
|
|
2079
|
+
break;
|
|
2080
|
+
case "order.refunded":
|
|
2081
|
+
await this.orderService.syncOrder({
|
|
2082
|
+
id: event.data.id,
|
|
2083
|
+
customerId: event.data.customerId,
|
|
2084
|
+
productId: event.data.productId ?? "",
|
|
2085
|
+
subscriptionId: event.data.subscriptionId ?? void 0,
|
|
2086
|
+
status: "refunded",
|
|
2087
|
+
totalAmount: event.data.totalAmount,
|
|
2088
|
+
currency: event.data.currency,
|
|
2089
|
+
billingReason: event.data.billingReason,
|
|
2090
|
+
createdAt: event.data.createdAt
|
|
2091
|
+
});
|
|
2092
|
+
break;
|
|
2093
|
+
case "benefit.created":
|
|
2094
|
+
case "benefit.updated":
|
|
2095
|
+
await this.benefitService.syncBenefit({
|
|
2096
|
+
id: event.data.id,
|
|
2097
|
+
type: event.data.type,
|
|
2098
|
+
description: event.data.description,
|
|
2099
|
+
organizationId: event.data.organizationId,
|
|
2100
|
+
selectable: event.data.selectable,
|
|
2101
|
+
deletable: event.data.deletable
|
|
2102
|
+
});
|
|
2103
|
+
break;
|
|
2104
|
+
case "benefit_grant.created":
|
|
2105
|
+
case "benefit_grant.updated":
|
|
2106
|
+
await this.benefitService.syncBenefitGrant({
|
|
2107
|
+
id: event.data.id,
|
|
2108
|
+
benefitId: event.data.benefitId,
|
|
2109
|
+
customerId: event.data.customerId,
|
|
2110
|
+
subscriptionId: event.data.subscriptionId ?? void 0,
|
|
2111
|
+
isGranted: event.data.isGranted,
|
|
2112
|
+
isRevoked: event.data.isRevoked,
|
|
2113
|
+
grantedAt: event.data.isGranted ? event.data.modifiedAt ?? /* @__PURE__ */ new Date() : void 0
|
|
2114
|
+
});
|
|
2115
|
+
break;
|
|
2116
|
+
case "benefit_grant.revoked":
|
|
2117
|
+
await this.benefitService.syncBenefitGrant({
|
|
2118
|
+
id: event.data.id,
|
|
2119
|
+
benefitId: event.data.benefitId,
|
|
2120
|
+
customerId: event.data.customerId,
|
|
2121
|
+
subscriptionId: event.data.subscriptionId ?? void 0,
|
|
2122
|
+
isGranted: false,
|
|
2123
|
+
isRevoked: true,
|
|
2124
|
+
revokedAt: event.data.modifiedAt ?? /* @__PURE__ */ new Date()
|
|
2125
|
+
});
|
|
2126
|
+
break;
|
|
2127
|
+
default:
|
|
2128
|
+
this.logger.log(`Unhandled event type: ${event.type}`);
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
// =========================================================================
|
|
2132
|
+
// Idempotency Helpers
|
|
2133
|
+
// =========================================================================
|
|
2134
|
+
async findProcessedEvent(eventId) {
|
|
2135
|
+
const result = await this.processedEventModel.findOne({
|
|
2136
|
+
polarEventId: eventId
|
|
2137
|
+
});
|
|
2138
|
+
return result !== null;
|
|
2139
|
+
}
|
|
2140
|
+
async recordProcessedEvent(eventId, eventType) {
|
|
2141
|
+
try {
|
|
2142
|
+
await this.processedEventModel.create({
|
|
2143
|
+
polarEventId: eventId,
|
|
2144
|
+
eventType,
|
|
2145
|
+
processedAt: /* @__PURE__ */ new Date()
|
|
2146
|
+
});
|
|
2147
|
+
} catch (error) {
|
|
2148
|
+
this.logger.warn(`Failed to record processed event ${eventId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
};
|
|
2152
|
+
PolarWebhookService = _ts_decorate19([
|
|
2153
|
+
common.Injectable(),
|
|
2154
|
+
_ts_param10(0, common$1.InjectModel(PolarProcessedEvent)),
|
|
2155
|
+
_ts_param10(6, common.Optional()),
|
|
2156
|
+
_ts_metadata19("design:type", Function),
|
|
2157
|
+
_ts_metadata19("design:paramtypes", [
|
|
2158
|
+
typeof Model === "undefined" ? Object : Model,
|
|
2159
|
+
typeof PolarCustomerService === "undefined" ? Object : PolarCustomerService,
|
|
2160
|
+
typeof PolarProductService === "undefined" ? Object : PolarProductService,
|
|
2161
|
+
typeof PolarSubscriptionService === "undefined" ? Object : PolarSubscriptionService,
|
|
2162
|
+
typeof PolarOrderService === "undefined" ? Object : PolarOrderService,
|
|
2163
|
+
typeof PolarBenefitService === "undefined" ? Object : PolarBenefitService,
|
|
2164
|
+
typeof core.EmailService === "undefined" ? Object : core.EmailService
|
|
2165
|
+
])
|
|
2166
|
+
], PolarWebhookService);
|
|
2167
|
+
}
|
|
2168
|
+
});
|
|
2169
|
+
function _ts_decorate20(decorators, target, key, desc) {
|
|
2170
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2171
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2172
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2173
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2174
|
+
}
|
|
2175
|
+
function _ts_metadata20(k, v) {
|
|
2176
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2177
|
+
}
|
|
2178
|
+
function _ts_param11(paramIndex, decorator) {
|
|
2179
|
+
return function(target, key) {
|
|
2180
|
+
decorator(target, key, paramIndex);
|
|
2181
|
+
};
|
|
2182
|
+
}
|
|
2183
|
+
var PolarWebhookController;
|
|
2184
|
+
var init_polar_webhook_controller = __esm({
|
|
2185
|
+
"src/polar-webhook.controller.ts"() {
|
|
2186
|
+
init_polar_webhook_service();
|
|
2187
|
+
init_polar_service();
|
|
2188
|
+
__name(_ts_decorate20, "_ts_decorate");
|
|
2189
|
+
__name(_ts_metadata20, "_ts_metadata");
|
|
2190
|
+
__name(_ts_param11, "_ts_param");
|
|
2191
|
+
PolarWebhookController = class {
|
|
2192
|
+
static {
|
|
2193
|
+
__name(this, "PolarWebhookController");
|
|
2194
|
+
}
|
|
2195
|
+
polarService;
|
|
2196
|
+
webhookService;
|
|
2197
|
+
constructor(polarService, webhookService) {
|
|
2198
|
+
this.polarService = polarService;
|
|
2199
|
+
this.webhookService = webhookService;
|
|
2200
|
+
}
|
|
2201
|
+
async handleWebhook(req, headers) {
|
|
2202
|
+
this.polarService.verifyRawBodyAvailable(req);
|
|
2203
|
+
const { webhookSecret } = this.polarService.pluginConfig;
|
|
2204
|
+
if (!webhookSecret) {
|
|
2205
|
+
throw new Error("[PolarPlugin] webhookSecret is required for webhook verification");
|
|
2206
|
+
}
|
|
2207
|
+
let event;
|
|
2208
|
+
try {
|
|
2209
|
+
event = webhooks.validateEvent(req.rawBody.toString(), headers, webhookSecret);
|
|
2210
|
+
} catch (error) {
|
|
2211
|
+
if (error instanceof webhooks.WebhookVerificationError) {
|
|
2212
|
+
throw error;
|
|
2213
|
+
}
|
|
2214
|
+
throw error;
|
|
2215
|
+
}
|
|
2216
|
+
await this.webhookService.processEvent(event);
|
|
2217
|
+
return {
|
|
2218
|
+
received: true
|
|
2219
|
+
};
|
|
2220
|
+
}
|
|
2221
|
+
};
|
|
2222
|
+
_ts_decorate20([
|
|
2223
|
+
common.Post(),
|
|
2224
|
+
common.HttpCode(200),
|
|
2225
|
+
_ts_param11(0, common.Req()),
|
|
2226
|
+
_ts_param11(1, common.Headers()),
|
|
2227
|
+
_ts_metadata20("design:type", Function),
|
|
2228
|
+
_ts_metadata20("design:paramtypes", [
|
|
2229
|
+
Object,
|
|
2230
|
+
typeof Record === "undefined" ? Object : Record
|
|
2231
|
+
]),
|
|
2232
|
+
_ts_metadata20("design:returntype", Promise)
|
|
2233
|
+
], PolarWebhookController.prototype, "handleWebhook", null);
|
|
2234
|
+
PolarWebhookController = _ts_decorate20([
|
|
2235
|
+
common.Controller("polar/webhooks"),
|
|
2236
|
+
_ts_metadata20("design:type", Function),
|
|
2237
|
+
_ts_metadata20("design:paramtypes", [
|
|
2238
|
+
typeof PolarService === "undefined" ? Object : PolarService,
|
|
2239
|
+
typeof PolarWebhookService === "undefined" ? Object : PolarWebhookService
|
|
2240
|
+
])
|
|
2241
|
+
], PolarWebhookController);
|
|
2242
|
+
}
|
|
2243
|
+
});
|
|
2244
|
+
|
|
2245
|
+
// src/polar.module.ts
|
|
2246
|
+
var polar_module_exports = {};
|
|
2247
|
+
__export(polar_module_exports, {
|
|
2248
|
+
PolarModule: () => PolarModule
|
|
2249
|
+
});
|
|
2250
|
+
function _ts_decorate21(decorators, target, key, desc) {
|
|
2251
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2252
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2253
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2254
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2255
|
+
}
|
|
2256
|
+
var PolarModule;
|
|
2257
|
+
var init_polar_module = __esm({
|
|
2258
|
+
"src/polar.module.ts"() {
|
|
2259
|
+
init_polar_api_controller();
|
|
2260
|
+
init_polar_webhook_controller();
|
|
2261
|
+
init_polar_webhook_service();
|
|
2262
|
+
init_polar_service();
|
|
2263
|
+
init_benefit_grant_schema();
|
|
2264
|
+
init_benefit_schema();
|
|
2265
|
+
init_customer_schema();
|
|
2266
|
+
init_order_schema();
|
|
2267
|
+
init_processed_event_schema();
|
|
2268
|
+
init_product_schema();
|
|
2269
|
+
init_subscription_schema();
|
|
2270
|
+
init_access_service();
|
|
2271
|
+
init_benefit_service();
|
|
2272
|
+
init_checkout_service();
|
|
2273
|
+
init_customer_service();
|
|
2274
|
+
init_metrics_service();
|
|
2275
|
+
init_order_service();
|
|
2276
|
+
init_portal_service();
|
|
2277
|
+
init_product_service();
|
|
2278
|
+
init_subscription_service();
|
|
2279
|
+
__name(_ts_decorate21, "_ts_decorate");
|
|
2280
|
+
PolarModule = class {
|
|
2281
|
+
static {
|
|
2282
|
+
__name(this, "PolarModule");
|
|
2283
|
+
}
|
|
2284
|
+
};
|
|
2285
|
+
PolarModule = _ts_decorate21([
|
|
2286
|
+
common.Module({
|
|
2287
|
+
imports: [
|
|
2288
|
+
core.DatabaseModule.forFeature(PolarCustomer),
|
|
2289
|
+
core.DatabaseModule.forFeature(PolarProduct),
|
|
2290
|
+
core.DatabaseModule.forFeature(PolarSubscription),
|
|
2291
|
+
core.DatabaseModule.forFeature(PolarOrder),
|
|
2292
|
+
core.DatabaseModule.forFeature(PolarBenefit),
|
|
2293
|
+
core.DatabaseModule.forFeature(PolarBenefitGrant),
|
|
2294
|
+
core.DatabaseModule.forFeature(PolarProcessedEvent)
|
|
2295
|
+
],
|
|
2296
|
+
controllers: [
|
|
2297
|
+
PolarApiController,
|
|
2298
|
+
PolarWebhookController
|
|
2299
|
+
],
|
|
2300
|
+
providers: [
|
|
2301
|
+
PolarService,
|
|
2302
|
+
PolarWebhookService,
|
|
2303
|
+
PolarCustomerService,
|
|
2304
|
+
PolarProductService,
|
|
2305
|
+
PolarSubscriptionService,
|
|
2306
|
+
PolarOrderService,
|
|
2307
|
+
PolarBenefitService,
|
|
2308
|
+
PolarCheckoutService,
|
|
2309
|
+
PolarPortalService,
|
|
2310
|
+
PolarAccessService,
|
|
2311
|
+
PolarMetricsService
|
|
2312
|
+
],
|
|
2313
|
+
exports: [
|
|
2314
|
+
PolarService,
|
|
2315
|
+
PolarCustomerService,
|
|
2316
|
+
PolarProductService,
|
|
2317
|
+
PolarSubscriptionService,
|
|
2318
|
+
PolarOrderService,
|
|
2319
|
+
PolarBenefitService,
|
|
2320
|
+
PolarCheckoutService,
|
|
2321
|
+
PolarPortalService,
|
|
2322
|
+
PolarAccessService
|
|
2323
|
+
]
|
|
2324
|
+
})
|
|
2325
|
+
], PolarModule);
|
|
2326
|
+
}
|
|
2327
|
+
});
|
|
2328
|
+
function _ts_decorate22(decorators, target, key, desc) {
|
|
2329
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2330
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2331
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2332
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2333
|
+
}
|
|
2334
|
+
__name(_ts_decorate22, "_ts_decorate");
|
|
2335
|
+
exports.PolarPlugin = class _PolarPlugin {
|
|
2336
|
+
static {
|
|
2337
|
+
__name(this, "PolarPlugin");
|
|
2338
|
+
}
|
|
2339
|
+
/** Environment variables used by this plugin */
|
|
2340
|
+
static envVars = [
|
|
2341
|
+
{
|
|
2342
|
+
name: "POLAR_ACCESS_TOKEN",
|
|
2343
|
+
required: true,
|
|
2344
|
+
description: "Polar API access token"
|
|
2345
|
+
},
|
|
2346
|
+
{
|
|
2347
|
+
name: "POLAR_WEBHOOK_SECRET",
|
|
2348
|
+
required: true,
|
|
2349
|
+
description: "Polar webhook signing secret"
|
|
2350
|
+
},
|
|
2351
|
+
{
|
|
2352
|
+
name: "POLAR_ORGANIZATION_ID",
|
|
2353
|
+
required: false,
|
|
2354
|
+
description: "Polar organization ID"
|
|
2355
|
+
}
|
|
2356
|
+
];
|
|
2357
|
+
/**
|
|
2358
|
+
* Create a configured plugin provider for MagnetModule.forRoot().
|
|
2359
|
+
* Auto-resolves secret values from environment variables if not provided.
|
|
2360
|
+
*
|
|
2361
|
+
* @example
|
|
2362
|
+
* ```typescript
|
|
2363
|
+
* MagnetModule.forRoot([
|
|
2364
|
+
* PolarPlugin.forRoot({ currency: 'usd' }),
|
|
2365
|
+
* ])
|
|
2366
|
+
* ```
|
|
2367
|
+
*/
|
|
2368
|
+
static forRoot(config) {
|
|
2369
|
+
const resolvedConfig = {
|
|
2370
|
+
accessToken: config?.accessToken ?? process.env.POLAR_ACCESS_TOKEN,
|
|
2371
|
+
webhookSecret: config?.webhookSecret ?? process.env.POLAR_WEBHOOK_SECRET,
|
|
2372
|
+
organizationId: config?.organizationId ?? process.env.POLAR_ORGANIZATION_ID,
|
|
2373
|
+
syncProducts: config?.syncProducts,
|
|
2374
|
+
currency: config?.currency,
|
|
2375
|
+
features: config?.features
|
|
2376
|
+
};
|
|
2377
|
+
return {
|
|
2378
|
+
type: "plugin",
|
|
2379
|
+
plugin: _PolarPlugin,
|
|
2380
|
+
options: resolvedConfig,
|
|
2381
|
+
envVars: _PolarPlugin.envVars
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
};
|
|
2385
|
+
exports.PolarPlugin = _ts_decorate22([
|
|
2386
|
+
core.Plugin({
|
|
2387
|
+
name: "polar",
|
|
2388
|
+
description: "Polar.sh payments plugin for Magnet CMS",
|
|
2389
|
+
version: "0.1.0",
|
|
2390
|
+
module: /* @__PURE__ */ __name(() => (init_polar_module(), __toCommonJS(polar_module_exports)).PolarModule, "module"),
|
|
2391
|
+
frontend: {
|
|
2392
|
+
routes: [
|
|
2393
|
+
{
|
|
2394
|
+
path: "polar",
|
|
2395
|
+
componentId: "PolarDashboard",
|
|
2396
|
+
requiresAuth: true,
|
|
2397
|
+
children: [
|
|
2398
|
+
{
|
|
2399
|
+
path: "",
|
|
2400
|
+
componentId: "PolarDashboard"
|
|
2401
|
+
},
|
|
2402
|
+
{
|
|
2403
|
+
path: "customers",
|
|
2404
|
+
componentId: "PolarCustomers"
|
|
2405
|
+
},
|
|
2406
|
+
{
|
|
2407
|
+
path: "products",
|
|
2408
|
+
componentId: "PolarProducts"
|
|
2409
|
+
},
|
|
2410
|
+
{
|
|
2411
|
+
path: "subscriptions",
|
|
2412
|
+
componentId: "PolarSubscriptions"
|
|
2413
|
+
},
|
|
2414
|
+
{
|
|
2415
|
+
path: "orders",
|
|
2416
|
+
componentId: "PolarOrders"
|
|
2417
|
+
},
|
|
2418
|
+
{
|
|
2419
|
+
path: "benefits",
|
|
2420
|
+
componentId: "PolarBenefits"
|
|
2421
|
+
}
|
|
2422
|
+
]
|
|
2423
|
+
}
|
|
2424
|
+
],
|
|
2425
|
+
sidebar: [
|
|
2426
|
+
{
|
|
2427
|
+
id: "polar",
|
|
2428
|
+
title: "Polar Payments",
|
|
2429
|
+
url: "/polar",
|
|
2430
|
+
icon: "Zap",
|
|
2431
|
+
order: 31,
|
|
2432
|
+
items: [
|
|
2433
|
+
{
|
|
2434
|
+
id: "polar-dashboard",
|
|
2435
|
+
title: "Dashboard",
|
|
2436
|
+
url: "/polar",
|
|
2437
|
+
icon: "BarChart3"
|
|
2438
|
+
},
|
|
2439
|
+
{
|
|
2440
|
+
id: "polar-customers",
|
|
2441
|
+
title: "Customers",
|
|
2442
|
+
url: "/polar/customers",
|
|
2443
|
+
icon: "Users"
|
|
2444
|
+
},
|
|
2445
|
+
{
|
|
2446
|
+
id: "polar-products",
|
|
2447
|
+
title: "Products",
|
|
2448
|
+
url: "/polar/products",
|
|
2449
|
+
icon: "Package"
|
|
2450
|
+
},
|
|
2451
|
+
{
|
|
2452
|
+
id: "polar-subscriptions",
|
|
2453
|
+
title: "Subscriptions",
|
|
2454
|
+
url: "/polar/subscriptions",
|
|
2455
|
+
icon: "RefreshCw"
|
|
2456
|
+
},
|
|
2457
|
+
{
|
|
2458
|
+
id: "polar-orders",
|
|
2459
|
+
title: "Orders",
|
|
2460
|
+
url: "/polar/orders",
|
|
2461
|
+
icon: "Receipt"
|
|
2462
|
+
},
|
|
2463
|
+
{
|
|
2464
|
+
id: "polar-benefits",
|
|
2465
|
+
title: "Benefits",
|
|
2466
|
+
url: "/polar/benefits",
|
|
2467
|
+
icon: "Gift"
|
|
2468
|
+
}
|
|
2469
|
+
]
|
|
2470
|
+
}
|
|
2471
|
+
]
|
|
2472
|
+
}
|
|
2473
|
+
})
|
|
2474
|
+
], exports.PolarPlugin);
|