@tellescope/sdk 1.256.2 → 1.256.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/lib/cjs/tests/api_tests/metriport_push_form_response.test.d.ts +6 -0
  2. package/lib/cjs/tests/api_tests/metriport_push_form_response.test.d.ts.map +1 -0
  3. package/lib/cjs/tests/api_tests/metriport_push_form_response.test.js +298 -0
  4. package/lib/cjs/tests/api_tests/metriport_push_form_response.test.js.map +1 -0
  5. package/lib/cjs/tests/api_tests/phone_calls_move_enduser.test.d.ts +6 -0
  6. package/lib/cjs/tests/api_tests/phone_calls_move_enduser.test.d.ts.map +1 -0
  7. package/lib/cjs/tests/api_tests/phone_calls_move_enduser.test.js +274 -0
  8. package/lib/cjs/tests/api_tests/phone_calls_move_enduser.test.js.map +1 -0
  9. package/lib/cjs/tests/api_tests/stripe_webhook_triggers.test.d.ts +18 -0
  10. package/lib/cjs/tests/api_tests/stripe_webhook_triggers.test.d.ts.map +1 -0
  11. package/lib/cjs/tests/api_tests/stripe_webhook_triggers.test.js +964 -0
  12. package/lib/cjs/tests/api_tests/stripe_webhook_triggers.test.js.map +1 -0
  13. package/lib/cjs/tests/api_tests/welle_partner_token.test.d.ts +6 -0
  14. package/lib/cjs/tests/api_tests/welle_partner_token.test.d.ts.map +1 -0
  15. package/lib/cjs/tests/api_tests/welle_partner_token.test.js +313 -0
  16. package/lib/cjs/tests/api_tests/welle_partner_token.test.js.map +1 -0
  17. package/lib/cjs/tests/stripe_webhook_helpers.d.ts +204 -0
  18. package/lib/cjs/tests/stripe_webhook_helpers.d.ts.map +1 -0
  19. package/lib/cjs/tests/stripe_webhook_helpers.js +286 -0
  20. package/lib/cjs/tests/stripe_webhook_helpers.js.map +1 -0
  21. package/lib/cjs/tests/tests.d.ts.map +1 -1
  22. package/lib/cjs/tests/tests.js +192 -180
  23. package/lib/cjs/tests/tests.js.map +1 -1
  24. package/lib/cjs/tests/unit_tests/translation.test.d.ts +3 -0
  25. package/lib/cjs/tests/unit_tests/translation.test.d.ts.map +1 -0
  26. package/lib/cjs/tests/unit_tests/translation.test.js.map +1 -0
  27. package/lib/esm/tests/api_tests/metriport_push_form_response.test.d.ts +6 -0
  28. package/lib/esm/tests/api_tests/metriport_push_form_response.test.d.ts.map +1 -0
  29. package/lib/esm/tests/api_tests/metriport_push_form_response.test.js +294 -0
  30. package/lib/esm/tests/api_tests/metriport_push_form_response.test.js.map +1 -0
  31. package/lib/esm/tests/api_tests/phone_calls_move_enduser.test.d.ts +6 -0
  32. package/lib/esm/tests/api_tests/phone_calls_move_enduser.test.d.ts.map +1 -0
  33. package/lib/esm/tests/api_tests/phone_calls_move_enduser.test.js +270 -0
  34. package/lib/esm/tests/api_tests/phone_calls_move_enduser.test.js.map +1 -0
  35. package/lib/esm/tests/api_tests/stripe_webhook_triggers.test.d.ts +18 -0
  36. package/lib/esm/tests/api_tests/stripe_webhook_triggers.test.d.ts.map +1 -0
  37. package/lib/esm/tests/api_tests/stripe_webhook_triggers.test.js +960 -0
  38. package/lib/esm/tests/api_tests/stripe_webhook_triggers.test.js.map +1 -0
  39. package/lib/esm/tests/api_tests/welle_partner_token.test.d.ts +6 -0
  40. package/lib/esm/tests/api_tests/welle_partner_token.test.d.ts.map +1 -0
  41. package/lib/esm/tests/api_tests/welle_partner_token.test.js +309 -0
  42. package/lib/esm/tests/api_tests/welle_partner_token.test.js.map +1 -0
  43. package/lib/esm/tests/stripe_webhook_helpers.d.ts +204 -0
  44. package/lib/esm/tests/stripe_webhook_helpers.d.ts.map +1 -0
  45. package/lib/esm/tests/stripe_webhook_helpers.js +267 -0
  46. package/lib/esm/tests/stripe_webhook_helpers.js.map +1 -0
  47. package/lib/esm/tests/tests.d.ts.map +1 -1
  48. package/lib/esm/tests/tests.js +192 -180
  49. package/lib/esm/tests/tests.js.map +1 -1
  50. package/lib/esm/tests/unit_tests/translation.test.d.ts +3 -0
  51. package/lib/esm/tests/unit_tests/translation.test.d.ts.map +1 -0
  52. package/lib/esm/tests/unit_tests/translation.test.js +52 -0
  53. package/lib/esm/tests/unit_tests/translation.test.js.map +1 -0
  54. package/lib/tsconfig.tsbuildinfo +1 -1
  55. package/package.json +10 -10
  56. package/src/tests/api_tests/metriport_push_form_response.test.ts +226 -0
  57. package/src/tests/api_tests/stripe_webhook_triggers.test.ts +676 -0
  58. package/src/tests/api_tests/welle_partner_token.test.ts +249 -0
  59. package/src/tests/stripe_webhook_helpers.ts +240 -0
  60. package/src/tests/tests.ts +6 -0
  61. package/test_generated.pdf +0 -0
@@ -0,0 +1,964 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
50
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
51
+ if (ar || !(i in from)) {
52
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
53
+ ar[i] = from[i];
54
+ }
55
+ }
56
+ return to.concat(ar || Array.prototype.slice.call(from));
57
+ };
58
+ Object.defineProperty(exports, "__esModule", { value: true });
59
+ exports.stripe_webhook_triggers_tests = void 0;
60
+ require('source-map-support').install();
61
+ var sdk_1 = require("../../sdk");
62
+ var testing_1 = require("@tellescope/testing");
63
+ var setup_1 = require("../setup");
64
+ var stripe_webhook_helpers_1 = require("../stripe_webhook_helpers");
65
+ var host = process.env.API_URL || "http://localhost:8080";
66
+ /**
67
+ * End-to-end coverage of the custom Stripe webhook -> automation trigger path, driven by synthetic
68
+ * but genuinely-signed payloads (see ../stripe_webhook_helpers).
69
+ *
70
+ * Fixture rules, all forced by handle_actions_for_triggers:
71
+ * - 'Add Tags' is the action because it applies inline via $addToSet, with no worker involved.
72
+ * - Every webhook POST gets its own enduser: triggers throttle per (trigger, enduser) for 60s, and
73
+ * neither handle_payment_failed nor handle_subscription_ended opts out.
74
+ * - No journeyId (the handler skips the action entirely for journey-scoped triggers), no
75
+ * oncePerEnduser, no enduserCondition, no weeklyAvailabilities.
76
+ * - Tags are run-unique, so a stale tag can't satisfy an assertion and 'Add Tags' can't no-op.
77
+ */
78
+ var stripe_webhook_triggers_tests = function (_a) {
79
+ var sdk = _a.sdk, sdkNonAdmin = _a.sdkNonAdmin;
80
+ return __awaiter(void 0, void 0, void 0, function () {
81
+ var RUN, tag, createdEnduserIds, createdTriggerIds, createdProductIds, _b, stripePublicKey, webhooksSecret, cleanup, new_enduser, new_trigger, new_product, poll_for_tag, expect_fired, expect_not_fired, B1_TAG, b1Enduser, b1Event, b1Res, b2Res, B3_TAG, b3Enduser, b3Res, B4_TAG, b4Enduser, b4Res, stripeProductA_1, stripeProductB, productA, productB, B5_TAG, b5Enduser, b5Res, B6_TAG, b6Enduser, B7_TAG, b7Enduser, B8_TAG, b8Enduser, run_scoped_payment_failed_case, f7Scoped, f7Fetched, rejectedInvalidProductId, e_1, run_pause_case, p14Scoped, p14Fetched, rejectedInvalidPausedProductId, e_2;
82
+ var _c, _d;
83
+ return __generator(this, function (_e) {
84
+ switch (_e.label) {
85
+ case 0:
86
+ (0, testing_1.log_header)("Stripe Webhook Triggers");
87
+ RUN = "".concat(Date.now());
88
+ tag = function (name) { return "stripe-wh-".concat(name, "-").concat(RUN); };
89
+ createdEnduserIds = [];
90
+ createdTriggerIds = [];
91
+ createdProductIds = [];
92
+ return [4 /*yield*/, (0, stripe_webhook_helpers_1.setup_stripe_test_integration)(sdk)
93
+ // Each enduser is matched by the handler on stripeCustomerId, so it must be unique per case.
94
+ ];
95
+ case 1:
96
+ _b = _e.sent(), stripePublicKey = _b.stripePublicKey, webhooksSecret = _b.webhooksSecret, cleanup = _b.cleanup;
97
+ new_enduser = function (label) { return __awaiter(void 0, void 0, void 0, function () {
98
+ var stripeCustomerId, enduser;
99
+ return __generator(this, function (_a) {
100
+ switch (_a.label) {
101
+ case 0:
102
+ stripeCustomerId = "cus_test_".concat(label, "_").concat(RUN);
103
+ return [4 /*yield*/, sdk.api.endusers.createOne({
104
+ fname: 'Stripe',
105
+ lname: "Webhook ".concat(label),
106
+ email: "stripe-webhook-".concat(label, "-").concat(RUN, "@tellescope.com"),
107
+ // settable by a staff session, but declared readonly in the client types
108
+ stripeCustomerId: stripeCustomerId,
109
+ })];
110
+ case 1:
111
+ enduser = _a.sent();
112
+ createdEnduserIds.push(enduser.id);
113
+ return [2 /*return*/, { id: enduser.id, stripeCustomerId: stripeCustomerId }];
114
+ }
115
+ });
116
+ }); };
117
+ new_trigger = function (_a) {
118
+ var title = _a.title, event = _a.event, tags = _a.tags;
119
+ return __awaiter(void 0, void 0, void 0, function () {
120
+ var trigger;
121
+ return __generator(this, function (_b) {
122
+ switch (_b.label) {
123
+ case 0: return [4 /*yield*/, sdk.api.automation_triggers.createOne({
124
+ title: title,
125
+ status: 'Active',
126
+ event: event,
127
+ action: { type: 'Add Tags', info: { tags: tags } },
128
+ })];
129
+ case 1:
130
+ trigger = _b.sent();
131
+ createdTriggerIds.push(trigger.id);
132
+ return [2 /*return*/, trigger];
133
+ }
134
+ });
135
+ });
136
+ };
137
+ new_product = function (label, stripeProductId) { return __awaiter(void 0, void 0, void 0, function () {
138
+ var product;
139
+ return __generator(this, function (_a) {
140
+ switch (_a.label) {
141
+ case 0: return [4 /*yield*/, sdk.api.products.createOne({
142
+ title: "Stripe Webhook Test ".concat(label, " ").concat(RUN),
143
+ cost: { amount: 1999, currency: 'USD' },
144
+ processor: 'Stripe',
145
+ stripeSubscriptionId: stripeProductId,
146
+ })];
147
+ case 1:
148
+ product = _a.sent();
149
+ createdProductIds.push(product.id);
150
+ return [2 /*return*/, product];
151
+ }
152
+ });
153
+ }); };
154
+ poll_for_tag = function (enduserId, expected, iterations) {
155
+ if (iterations === void 0) { iterations = 20; }
156
+ return __awaiter(void 0, void 0, void 0, function () {
157
+ var i, enduser;
158
+ var _a;
159
+ return __generator(this, function (_b) {
160
+ switch (_b.label) {
161
+ case 0:
162
+ i = 0;
163
+ _b.label = 1;
164
+ case 1:
165
+ if (!(i < iterations)) return [3 /*break*/, 5];
166
+ return [4 /*yield*/, (0, testing_1.wait)(undefined, 500)];
167
+ case 2:
168
+ _b.sent();
169
+ return [4 /*yield*/, sdk.api.endusers.getOne(enduserId)];
170
+ case 3:
171
+ enduser = _b.sent();
172
+ if ((_a = enduser.tags) === null || _a === void 0 ? void 0 : _a.includes(expected))
173
+ return [2 /*return*/, true];
174
+ _b.label = 4;
175
+ case 4:
176
+ i++;
177
+ return [3 /*break*/, 1];
178
+ case 5: return [2 /*return*/, false];
179
+ }
180
+ });
181
+ });
182
+ };
183
+ expect_fired = function (enduserId, expected, title) { return __awaiter(void 0, void 0, void 0, function () {
184
+ var _a;
185
+ return __generator(this, function (_b) {
186
+ switch (_b.label) {
187
+ case 0:
188
+ _a = testing_1.assert;
189
+ return [4 /*yield*/, poll_for_tag(enduserId, expected)];
190
+ case 1:
191
+ _a.apply(void 0, [_b.sent(), "expected tag ".concat(expected, " to be added by the trigger"), title]);
192
+ return [2 /*return*/];
193
+ }
194
+ });
195
+ }); };
196
+ expect_not_fired = function (enduserId, expected, title) { return __awaiter(void 0, void 0, void 0, function () {
197
+ var enduser;
198
+ var _a;
199
+ return __generator(this, function (_b) {
200
+ switch (_b.label) {
201
+ case 0: return [4 /*yield*/, (0, testing_1.wait)(undefined, 2500)];
202
+ case 1:
203
+ _b.sent();
204
+ return [4 /*yield*/, sdk.api.endusers.getOne(enduserId)];
205
+ case 2:
206
+ enduser = _b.sent();
207
+ (0, testing_1.assert)(!((_a = enduser.tags) === null || _a === void 0 ? void 0 : _a.includes(expected)), "expected the trigger NOT to fire, but tag ".concat(expected, " was added"), title);
208
+ return [2 /*return*/];
209
+ }
210
+ });
211
+ }); };
212
+ _e.label = 2;
213
+ case 2:
214
+ _e.trys.push([2, , 69, 72]);
215
+ B1_TAG = tag('b1-bad-signature');
216
+ return [4 /*yield*/, new_enduser('b1')];
217
+ case 3:
218
+ b1Enduser = _e.sent();
219
+ return [4 /*yield*/, new_trigger({
220
+ title: "Stripe payment failed (bad signature) ".concat(RUN),
221
+ event: { type: 'Subscription Payment Failed', info: {} },
222
+ tags: [B1_TAG],
223
+ })];
224
+ case 4:
225
+ _e.sent();
226
+ b1Event = (0, stripe_webhook_helpers_1.invoice_payment_failed_event)({ stripeCustomerId: b1Enduser.stripeCustomerId });
227
+ return [4 /*yield*/, (0, stripe_webhook_helpers_1.post_stripe_webhook)({
228
+ stripePublicKey: stripePublicKey,
229
+ secret: webhooksSecret,
230
+ event: b1Event,
231
+ signature: (0, stripe_webhook_helpers_1.sign_stripe_payload)('{"tampered":true}', webhooksSecret),
232
+ })];
233
+ case 5:
234
+ b1Res = _e.sent();
235
+ (0, testing_1.assert)(b1Res.status === 400, "expected 400 for a mismatched signature, got ".concat(b1Res.status), 'invalid signature rejected');
236
+ return [4 /*yield*/, expect_not_fired(b1Enduser.id, B1_TAG, 'invalid signature does not fire triggers')
237
+ // B2: unknown public key in the URL -> no integration -> 404
238
+ ];
239
+ case 6:
240
+ _e.sent();
241
+ return [4 /*yield*/, (0, stripe_webhook_helpers_1.post_stripe_webhook)({
242
+ stripePublicKey: "pk_test_missing_".concat(RUN),
243
+ secret: webhooksSecret,
244
+ event: (0, stripe_webhook_helpers_1.invoice_payment_failed_event)({ stripeCustomerId: "cus_test_missing_".concat(RUN) }),
245
+ })];
246
+ case 7:
247
+ b2Res = _e.sent();
248
+ (0, testing_1.assert)(b2Res.status === 404, "expected 404 for an unknown public key, got ".concat(b2Res.status), 'unknown integration rejected');
249
+ B3_TAG = tag('b3-unknown-customer');
250
+ return [4 /*yield*/, new_enduser('b3')];
251
+ case 8:
252
+ b3Enduser = _e.sent();
253
+ return [4 /*yield*/, new_trigger({
254
+ title: "Stripe payment failed (unknown customer) ".concat(RUN),
255
+ event: { type: 'Subscription Payment Failed', info: {} },
256
+ tags: [B3_TAG],
257
+ })];
258
+ case 9:
259
+ _e.sent();
260
+ return [4 /*yield*/, (0, stripe_webhook_helpers_1.post_stripe_webhook)({
261
+ stripePublicKey: stripePublicKey,
262
+ secret: webhooksSecret,
263
+ event: (0, stripe_webhook_helpers_1.invoice_payment_failed_event)({ stripeCustomerId: "cus_test_nobody_".concat(RUN) }),
264
+ })];
265
+ case 10:
266
+ b3Res = _e.sent();
267
+ (0, testing_1.assert)(b3Res.status === 200, "expected 200 for an unmatched customer, got ".concat(b3Res.status), 'unmatched customer accepted');
268
+ return [4 /*yield*/, expect_not_fired(b3Enduser.id, B3_TAG, 'unmatched customer does not fire triggers')
269
+ // B4: the baseline behavior the productIds feature must preserve — a Subscription Payment Failed
270
+ // trigger with no product scoping fires for any failed invoice.
271
+ ];
272
+ case 11:
273
+ _e.sent();
274
+ B4_TAG = tag('b4-unscoped');
275
+ return [4 /*yield*/, new_enduser('b4')];
276
+ case 12:
277
+ b4Enduser = _e.sent();
278
+ return [4 /*yield*/, new_trigger({
279
+ title: "Stripe payment failed (unscoped) ".concat(RUN),
280
+ event: { type: 'Subscription Payment Failed', info: {} },
281
+ tags: [B4_TAG],
282
+ })];
283
+ case 13:
284
+ _e.sent();
285
+ return [4 /*yield*/, (0, stripe_webhook_helpers_1.post_stripe_webhook)({
286
+ stripePublicKey: stripePublicKey,
287
+ secret: webhooksSecret,
288
+ event: (0, stripe_webhook_helpers_1.invoice_payment_failed_event)({
289
+ stripeCustomerId: b4Enduser.stripeCustomerId,
290
+ lines: [(0, stripe_webhook_helpers_1.line_with_price_product)("prod_test_b4_".concat(RUN))],
291
+ }),
292
+ })];
293
+ case 14:
294
+ b4Res = _e.sent();
295
+ (0, testing_1.assert)(b4Res.status === 200, "expected 200, got ".concat(b4Res.status, " (").concat(b4Res.data, ")"), 'payment failed webhook accepted');
296
+ return [4 /*yield*/, expect_fired(b4Enduser.id, B4_TAG, 'unscoped Subscription Payment Failed trigger fires')
297
+ /* ===================== customer.subscription.deleted ===================== */
298
+ // Products A and B exist to distinguish "the subscription's product" from "some other product".
299
+ ];
300
+ case 15:
301
+ _e.sent();
302
+ stripeProductA_1 = "prod_test_a_".concat(RUN);
303
+ stripeProductB = "prod_test_b_".concat(RUN);
304
+ return [4 /*yield*/, new_product('A', stripeProductA_1)];
305
+ case 16:
306
+ productA = _e.sent();
307
+ return [4 /*yield*/, new_product('B', stripeProductB)
308
+ // B5: unscoped Subscription Ended fires
309
+ ];
310
+ case 17:
311
+ productB = _e.sent();
312
+ B5_TAG = tag('b5-ended-unscoped');
313
+ return [4 /*yield*/, new_enduser('b5')];
314
+ case 18:
315
+ b5Enduser = _e.sent();
316
+ return [4 /*yield*/, new_trigger({
317
+ title: "Stripe subscription ended (unscoped) ".concat(RUN),
318
+ event: { type: 'Subscription Ended', info: {} },
319
+ tags: [B5_TAG],
320
+ })];
321
+ case 19:
322
+ _e.sent();
323
+ return [4 /*yield*/, (0, stripe_webhook_helpers_1.post_stripe_webhook)({
324
+ stripePublicKey: stripePublicKey,
325
+ secret: webhooksSecret,
326
+ event: (0, stripe_webhook_helpers_1.subscription_deleted_event)({
327
+ stripeCustomerId: b5Enduser.stripeCustomerId,
328
+ stripeProductIds: [stripeProductA_1],
329
+ }),
330
+ })];
331
+ case 20:
332
+ b5Res = _e.sent();
333
+ (0, testing_1.assert)(b5Res.status === 200, "expected 200, got ".concat(b5Res.status, " (").concat(b5Res.data, ")"), 'subscription deleted webhook accepted');
334
+ return [4 /*yield*/, expect_fired(b5Enduser.id, B5_TAG, 'unscoped Subscription Ended trigger fires')
335
+ // B6: an explicitly empty productIds list means "all products"
336
+ ];
337
+ case 21:
338
+ _e.sent();
339
+ B6_TAG = tag('b6-ended-empty-list');
340
+ return [4 /*yield*/, new_enduser('b6')];
341
+ case 22:
342
+ b6Enduser = _e.sent();
343
+ return [4 /*yield*/, new_trigger({
344
+ title: "Stripe subscription ended (empty productIds) ".concat(RUN),
345
+ event: { type: 'Subscription Ended', info: { productIds: [] } },
346
+ tags: [B6_TAG],
347
+ })];
348
+ case 23:
349
+ _e.sent();
350
+ return [4 /*yield*/, (0, stripe_webhook_helpers_1.post_stripe_webhook)({
351
+ stripePublicKey: stripePublicKey,
352
+ secret: webhooksSecret,
353
+ event: (0, stripe_webhook_helpers_1.subscription_deleted_event)({
354
+ stripeCustomerId: b6Enduser.stripeCustomerId,
355
+ stripeProductIds: [stripeProductA_1],
356
+ }),
357
+ })];
358
+ case 24:
359
+ _e.sent();
360
+ return [4 /*yield*/, expect_fired(b6Enduser.id, B6_TAG, 'Subscription Ended trigger with empty productIds fires')
361
+ // B7/B8 pin the existing product-matching semantics end-to-end, so any refactor of the
362
+ // productIds query clause is provably behavior-preserving.
363
+ // B7: productIds matching the subscription's product fires
364
+ ];
365
+ case 25:
366
+ _e.sent();
367
+ B7_TAG = tag('b7-ended-matching');
368
+ return [4 /*yield*/, new_enduser('b7')];
369
+ case 26:
370
+ b7Enduser = _e.sent();
371
+ return [4 /*yield*/, new_trigger({
372
+ title: "Stripe subscription ended (matching product) ".concat(RUN),
373
+ event: { type: 'Subscription Ended', info: { productIds: [productA.id] } },
374
+ tags: [B7_TAG],
375
+ })];
376
+ case 27:
377
+ _e.sent();
378
+ return [4 /*yield*/, (0, stripe_webhook_helpers_1.post_stripe_webhook)({
379
+ stripePublicKey: stripePublicKey,
380
+ secret: webhooksSecret,
381
+ event: (0, stripe_webhook_helpers_1.subscription_deleted_event)({
382
+ stripeCustomerId: b7Enduser.stripeCustomerId,
383
+ stripeProductIds: [stripeProductA_1],
384
+ }),
385
+ })];
386
+ case 28:
387
+ _e.sent();
388
+ return [4 /*yield*/, expect_fired(b7Enduser.id, B7_TAG, 'Subscription Ended trigger scoped to the matching product fires')
389
+ // B8: productIds naming a different product does not fire
390
+ ];
391
+ case 29:
392
+ _e.sent();
393
+ B8_TAG = tag('b8-ended-nonmatching');
394
+ return [4 /*yield*/, new_enduser('b8')];
395
+ case 30:
396
+ b8Enduser = _e.sent();
397
+ return [4 /*yield*/, new_trigger({
398
+ title: "Stripe subscription ended (other product) ".concat(RUN),
399
+ event: { type: 'Subscription Ended', info: { productIds: [productB.id] } },
400
+ tags: [B8_TAG],
401
+ })];
402
+ case 31:
403
+ _e.sent();
404
+ return [4 /*yield*/, (0, stripe_webhook_helpers_1.post_stripe_webhook)({
405
+ stripePublicKey: stripePublicKey,
406
+ secret: webhooksSecret,
407
+ event: (0, stripe_webhook_helpers_1.subscription_deleted_event)({
408
+ stripeCustomerId: b8Enduser.stripeCustomerId,
409
+ stripeProductIds: [stripeProductA_1],
410
+ }),
411
+ })];
412
+ case 32:
413
+ _e.sent();
414
+ return [4 /*yield*/, expect_not_fired(b8Enduser.id, B8_TAG, 'Subscription Ended trigger scoped to another product does not fire')
415
+ /* ============ invoice.payment_failed, scoped to products ============ */
416
+ // Shared shape for the cases below: a trigger scoped to productA, and an invoice whose line
417
+ // items are varied per case to cover how Stripe can reference a product.
418
+ ];
419
+ case 33:
420
+ _e.sent();
421
+ run_scoped_payment_failed_case = function (_a) {
422
+ var label = _a.label, productIds = _a.productIds, lines = _a.lines, shouldFire = _a.shouldFire, title = _a.title;
423
+ return __awaiter(void 0, void 0, void 0, function () {
424
+ var caseTag, enduser, res;
425
+ return __generator(this, function (_b) {
426
+ switch (_b.label) {
427
+ case 0:
428
+ caseTag = tag(label);
429
+ return [4 /*yield*/, new_enduser(label)];
430
+ case 1:
431
+ enduser = _b.sent();
432
+ return [4 /*yield*/, new_trigger({
433
+ title: "Stripe payment failed (".concat(label, ") ").concat(RUN),
434
+ event: { type: 'Subscription Payment Failed', info: { productIds: productIds } },
435
+ tags: [caseTag],
436
+ })];
437
+ case 2:
438
+ _b.sent();
439
+ return [4 /*yield*/, (0, stripe_webhook_helpers_1.post_stripe_webhook)({
440
+ stripePublicKey: stripePublicKey,
441
+ secret: webhooksSecret,
442
+ event: (0, stripe_webhook_helpers_1.invoice_payment_failed_event)({ stripeCustomerId: enduser.stripeCustomerId, lines: lines }),
443
+ })];
444
+ case 3:
445
+ res = _b.sent();
446
+ (0, testing_1.assert)(res.status === 200, "expected 200, got ".concat(res.status, " (").concat(res.data, ")"), "".concat(label, " webhook accepted"));
447
+ if (!shouldFire) return [3 /*break*/, 5];
448
+ return [4 /*yield*/, expect_fired(enduser.id, caseTag, title)];
449
+ case 4:
450
+ _b.sent();
451
+ return [3 /*break*/, 7];
452
+ case 5: return [4 /*yield*/, expect_not_fired(enduser.id, caseTag, title)];
453
+ case 6:
454
+ _b.sent();
455
+ _b.label = 7;
456
+ case 7: return [2 /*return*/];
457
+ }
458
+ });
459
+ });
460
+ };
461
+ // F1: the feature — a trigger scoped to the product that actually failed fires
462
+ return [4 /*yield*/, run_scoped_payment_failed_case({
463
+ label: 'f1-matching',
464
+ productIds: [productA.id],
465
+ lines: [(0, stripe_webhook_helpers_1.line_with_price_product)(stripeProductA_1)],
466
+ shouldFire: true,
467
+ title: 'Subscription Payment Failed scoped to the failed product fires',
468
+ })
469
+ // F2: the point of the feature — a trigger scoped to a different product stays quiet
470
+ ];
471
+ case 34:
472
+ // F1: the feature — a trigger scoped to the product that actually failed fires
473
+ _e.sent();
474
+ // F2: the point of the feature — a trigger scoped to a different product stays quiet
475
+ return [4 /*yield*/, run_scoped_payment_failed_case({
476
+ label: 'f2-nonmatching',
477
+ productIds: [productB.id],
478
+ lines: [(0, stripe_webhook_helpers_1.line_with_price_product)(stripeProductA_1)],
479
+ shouldFire: false,
480
+ title: 'Subscription Payment Failed scoped to another product does not fire',
481
+ })
482
+ // F3: "leave blank for all" — an empty list is not a filter
483
+ ];
484
+ case 35:
485
+ // F2: the point of the feature — a trigger scoped to a different product stays quiet
486
+ _e.sent();
487
+ // F3: "leave blank for all" — an empty list is not a filter
488
+ return [4 /*yield*/, run_scoped_payment_failed_case({
489
+ label: 'f3-empty-list',
490
+ productIds: [],
491
+ lines: [(0, stripe_webhook_helpers_1.line_with_price_product)(stripeProductA_1)],
492
+ shouldFire: true,
493
+ title: 'Subscription Payment Failed with empty productIds fires',
494
+ })
495
+ // F4: price.product may arrive expanded as an object rather than a bare id
496
+ ];
497
+ case 36:
498
+ // F3: "leave blank for all" — an empty list is not a filter
499
+ _e.sent();
500
+ // F4: price.product may arrive expanded as an object rather than a bare id
501
+ return [4 /*yield*/, run_scoped_payment_failed_case({
502
+ label: 'f4-expanded-product',
503
+ productIds: [productA.id],
504
+ lines: [(0, stripe_webhook_helpers_1.line_with_expanded_price_product)(stripeProductA_1)],
505
+ shouldFire: true,
506
+ title: 'expanded price.product object resolves to the product',
507
+ })
508
+ // F5: subscription/proration lines can carry plan.product with no price
509
+ ];
510
+ case 37:
511
+ // F4: price.product may arrive expanded as an object rather than a bare id
512
+ _e.sent();
513
+ // F5: subscription/proration lines can carry plan.product with no price
514
+ return [4 /*yield*/, run_scoped_payment_failed_case({
515
+ label: 'f5-plan-product',
516
+ productIds: [productA.id],
517
+ lines: [(0, stripe_webhook_helpers_1.line_with_plan_product)(stripeProductA_1)],
518
+ shouldFire: true,
519
+ title: 'plan.product fallback resolves to the product',
520
+ })
521
+ // F6: one matching line among several is enough
522
+ ];
523
+ case 38:
524
+ // F5: subscription/proration lines can carry plan.product with no price
525
+ _e.sent();
526
+ // F6: one matching line among several is enough
527
+ return [4 /*yield*/, run_scoped_payment_failed_case({
528
+ label: 'f6-multi-line',
529
+ productIds: [productA.id],
530
+ lines: [(0, stripe_webhook_helpers_1.line_with_price_product)(stripeProductB), (0, stripe_webhook_helpers_1.line_with_price_product)(stripeProductA_1)],
531
+ shouldFire: true,
532
+ title: 'a matching line among several fires the scoped trigger',
533
+ })
534
+ /* ===================== validator ===================== */
535
+ // F7: productIds must round-trip, and an omitted info must stay valid — it was accepted before
536
+ // productIds existed, so requiring it would break existing API clients.
537
+ ];
538
+ case 39:
539
+ // F6: one matching line among several is enough
540
+ _e.sent();
541
+ return [4 /*yield*/, new_trigger({
542
+ title: "Stripe payment failed (validator round-trip) ".concat(RUN),
543
+ event: { type: 'Subscription Payment Failed', info: { productIds: [productA.id] } },
544
+ tags: [tag('f7')],
545
+ })];
546
+ case 40:
547
+ f7Scoped = _e.sent();
548
+ return [4 /*yield*/, sdk.api.automation_triggers.getOne(f7Scoped.id)];
549
+ case 41:
550
+ f7Fetched = _e.sent();
551
+ (0, testing_1.assert)(JSON.stringify((_c = f7Fetched.event.info) === null || _c === void 0 ? void 0 : _c.productIds) === JSON.stringify([productA.id]), "expected productIds to round-trip, got ".concat(JSON.stringify(f7Fetched.event)), 'productIds round-trips through the validator');
552
+ return [4 /*yield*/, new_trigger({
553
+ title: "Stripe payment failed (empty info) ".concat(RUN),
554
+ event: { type: 'Subscription Payment Failed', info: {} },
555
+ tags: [tag('f7-empty-info')],
556
+ })];
557
+ case 42:
558
+ _e.sent();
559
+ (0, testing_1.assert)(true, '', 'empty info accepted');
560
+ return [4 /*yield*/, new_trigger({
561
+ title: "Stripe payment failed (no info) ".concat(RUN),
562
+ event: { type: 'Subscription Payment Failed' },
563
+ tags: [tag('f7-no-info')],
564
+ })];
565
+ case 43:
566
+ _e.sent();
567
+ (0, testing_1.assert)(true, '', 'omitted info still accepted');
568
+ rejectedInvalidProductId = false;
569
+ _e.label = 44;
570
+ case 44:
571
+ _e.trys.push([44, 46, , 47]);
572
+ return [4 /*yield*/, new_trigger({
573
+ title: "Stripe payment failed (invalid productId) ".concat(RUN),
574
+ event: { type: 'Subscription Payment Failed', info: { productIds: ['not-a-mongo-id'] } },
575
+ tags: [tag('f7-invalid')],
576
+ })];
577
+ case 45:
578
+ _e.sent();
579
+ return [3 /*break*/, 47];
580
+ case 46:
581
+ e_1 = _e.sent();
582
+ rejectedInvalidProductId = true;
583
+ return [3 /*break*/, 47];
584
+ case 47:
585
+ (0, testing_1.assert)(rejectedInvalidProductId, 'expected a non-ObjectId productId to be rejected', 'invalid productId rejected');
586
+ run_pause_case = function (_a) {
587
+ var label = _a.label, type = _a.type, productIds = _a.productIds, buildEvent = _a.event, shouldFire = _a.shouldFire, title = _a.title;
588
+ return __awaiter(void 0, void 0, void 0, function () {
589
+ var caseTag, enduser, res;
590
+ return __generator(this, function (_b) {
591
+ switch (_b.label) {
592
+ case 0:
593
+ caseTag = tag(label);
594
+ return [4 /*yield*/, new_enduser(label)];
595
+ case 1:
596
+ enduser = _b.sent();
597
+ return [4 /*yield*/, new_trigger({
598
+ title: "Stripe ".concat(type, " (").concat(label, ") ").concat(RUN),
599
+ event: __assign({ type: type }, productIds !== undefined ? { info: { productIds: productIds } } : {}),
600
+ tags: [caseTag],
601
+ })];
602
+ case 2:
603
+ _b.sent();
604
+ return [4 /*yield*/, (0, stripe_webhook_helpers_1.post_stripe_webhook)({
605
+ stripePublicKey: stripePublicKey,
606
+ secret: webhooksSecret,
607
+ event: buildEvent(enduser.stripeCustomerId),
608
+ })];
609
+ case 3:
610
+ res = _b.sent();
611
+ (0, testing_1.assert)(res.status === 200, "expected 200, got ".concat(res.status, " (").concat(res.data, ")"), "".concat(label, " webhook accepted"));
612
+ if (!shouldFire) return [3 /*break*/, 5];
613
+ return [4 /*yield*/, expect_fired(enduser.id, caseTag, title)];
614
+ case 4:
615
+ _b.sent();
616
+ return [3 /*break*/, 7];
617
+ case 5: return [4 /*yield*/, expect_not_fired(enduser.id, caseTag, title)];
618
+ case 6:
619
+ _b.sent();
620
+ _b.label = 7;
621
+ case 7: return [2 /*return*/];
622
+ }
623
+ });
624
+ });
625
+ };
626
+ // P1: the core pause path — pause_collection goes null -> set on customer.subscription.updated.
627
+ // This is how a pause from the billing portal or dashboard actually arrives; there is no
628
+ // dedicated event for it.
629
+ return [4 /*yield*/, run_pause_case({
630
+ label: 'p1-pause-collection-set',
631
+ type: 'Subscription Paused',
632
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_updated_event)({
633
+ stripeCustomerId: stripeCustomerId,
634
+ previousAttributes: { pause_collection: null },
635
+ pauseCollection: stripe_webhook_helpers_1.PAUSE_COLLECTION,
636
+ }); },
637
+ shouldFire: true,
638
+ title: 'pause_collection null -> set fires Subscription Paused',
639
+ })
640
+ // P2: the mirror — pause_collection cleared is a resume
641
+ ];
642
+ case 48:
643
+ // P1: the core pause path — pause_collection goes null -> set on customer.subscription.updated.
644
+ // This is how a pause from the billing portal or dashboard actually arrives; there is no
645
+ // dedicated event for it.
646
+ _e.sent();
647
+ // P2: the mirror — pause_collection cleared is a resume
648
+ return [4 /*yield*/, run_pause_case({
649
+ label: 'p2-pause-collection-cleared',
650
+ type: 'Subscription Resumed',
651
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_updated_event)({
652
+ stripeCustomerId: stripeCustomerId,
653
+ previousAttributes: { pause_collection: stripe_webhook_helpers_1.PAUSE_COLLECTION },
654
+ pauseCollection: null,
655
+ }); },
656
+ shouldFire: true,
657
+ title: 'pause_collection set -> null fires Subscription Resumed',
658
+ })
659
+ // P3: a pause that is only *modified* (behavior or resumes_at changed) is neither a pause nor a
660
+ // resume — firing here would re-trigger every time a customer adjusts an existing pause
661
+ ];
662
+ case 49:
663
+ // P2: the mirror — pause_collection cleared is a resume
664
+ _e.sent();
665
+ // P3: a pause that is only *modified* (behavior or resumes_at changed) is neither a pause nor a
666
+ // resume — firing here would re-trigger every time a customer adjusts an existing pause
667
+ return [4 /*yield*/, run_pause_case({
668
+ label: 'p3-pause-modified',
669
+ type: 'Subscription Paused',
670
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_updated_event)({
671
+ stripeCustomerId: stripeCustomerId,
672
+ previousAttributes: { pause_collection: { behavior: 'void', resumes_at: null } },
673
+ pauseCollection: { behavior: 'keep_as_draft', resumes_at: null },
674
+ }); },
675
+ shouldFire: false,
676
+ title: 'a modified pause_collection fires neither trigger',
677
+ })
678
+ // P4: the volume guard. customer.subscription.updated fires on every renewal, price change and
679
+ // cancel_at_period_end toggle; with no pause_collection key in previous_attributes the handler
680
+ // must do nothing (and, in the API, must not even reach the enduser lookup).
681
+ ];
682
+ case 50:
683
+ // P3: a pause that is only *modified* (behavior or resumes_at changed) is neither a pause nor a
684
+ // resume — firing here would re-trigger every time a customer adjusts an existing pause
685
+ _e.sent();
686
+ // P4: the volume guard. customer.subscription.updated fires on every renewal, price change and
687
+ // cancel_at_period_end toggle; with no pause_collection key in previous_attributes the handler
688
+ // must do nothing (and, in the API, must not even reach the enduser lookup).
689
+ return [4 /*yield*/, run_pause_case({
690
+ label: 'p4-unrelated-update',
691
+ type: 'Subscription Paused',
692
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_updated_event)({
693
+ stripeCustomerId: stripeCustomerId,
694
+ previousAttributes: { items: { object: 'list', data: [] } },
695
+ }); },
696
+ shouldFire: false,
697
+ title: 'an unrelated subscription update fires neither trigger',
698
+ })
699
+ // P4b: the idempotency case. previous_attributes carries only what changed, so an unrelated
700
+ // update to an already-paused subscription has no pause_collection key even though
701
+ // pause_collection is currently set. Firing here would re-trigger on every renewal, quantity
702
+ // change and coupon edit for the whole duration of a pause — which is what would happen if the
703
+ // gate were ever "simplified" to read current state instead of the transition.
704
+ ];
705
+ case 51:
706
+ // P4: the volume guard. customer.subscription.updated fires on every renewal, price change and
707
+ // cancel_at_period_end toggle; with no pause_collection key in previous_attributes the handler
708
+ // must do nothing (and, in the API, must not even reach the enduser lookup).
709
+ _e.sent();
710
+ // P4b: the idempotency case. previous_attributes carries only what changed, so an unrelated
711
+ // update to an already-paused subscription has no pause_collection key even though
712
+ // pause_collection is currently set. Firing here would re-trigger on every renewal, quantity
713
+ // change and coupon edit for the whole duration of a pause — which is what would happen if the
714
+ // gate were ever "simplified" to read current state instead of the transition.
715
+ return [4 /*yield*/, run_pause_case({
716
+ label: 'p4b-update-while-paused',
717
+ type: 'Subscription Paused',
718
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_updated_event)({
719
+ stripeCustomerId: stripeCustomerId,
720
+ previousAttributes: { quantity: 1 },
721
+ pauseCollection: stripe_webhook_helpers_1.PAUSE_COLLECTION,
722
+ }); },
723
+ shouldFire: false,
724
+ title: 'an unrelated update while already paused does not re-fire Subscription Paused',
725
+ })
726
+ // P5/P6: the dedicated events, which Stripe emits for status='paused' transitions only
727
+ ];
728
+ case 52:
729
+ // P4b: the idempotency case. previous_attributes carries only what changed, so an unrelated
730
+ // update to an already-paused subscription has no pause_collection key even though
731
+ // pause_collection is currently set. Firing here would re-trigger on every renewal, quantity
732
+ // change and coupon edit for the whole duration of a pause — which is what would happen if the
733
+ // gate were ever "simplified" to read current state instead of the transition.
734
+ _e.sent();
735
+ // P5/P6: the dedicated events, which Stripe emits for status='paused' transitions only
736
+ return [4 /*yield*/, run_pause_case({
737
+ label: 'p5-dedicated-paused',
738
+ type: 'Subscription Paused',
739
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_paused_event)({ stripeCustomerId: stripeCustomerId }); },
740
+ shouldFire: true,
741
+ title: 'customer.subscription.paused fires Subscription Paused',
742
+ })];
743
+ case 53:
744
+ // P5/P6: the dedicated events, which Stripe emits for status='paused' transitions only
745
+ _e.sent();
746
+ return [4 /*yield*/, run_pause_case({
747
+ label: 'p6-dedicated-resumed',
748
+ type: 'Subscription Resumed',
749
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_resumed_event)({ stripeCustomerId: stripeCustomerId }); },
750
+ shouldFire: true,
751
+ title: 'customer.subscription.resumed fires Subscription Resumed',
752
+ })
753
+ // P7: a Paused trigger must not fire on a resume, and vice versa — the two are separate types
754
+ ];
755
+ case 54:
756
+ _e.sent();
757
+ // P7: a Paused trigger must not fire on a resume, and vice versa — the two are separate types
758
+ return [4 /*yield*/, run_pause_case({
759
+ label: 'p7-wrong-direction',
760
+ type: 'Subscription Paused',
761
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_resumed_event)({ stripeCustomerId: stripeCustomerId }); },
762
+ shouldFire: false,
763
+ title: 'a resume does not fire a Subscription Paused trigger',
764
+ })
765
+ // P8: the dedupe guard — the .updated that accompanies a status='paused' transition must not
766
+ // fire on top of the dedicated event. Stripe isn't expected to send this combination at all;
767
+ // the case pins the guard so a future refactor can't quietly drop it.
768
+ ];
769
+ case 55:
770
+ // P7: a Paused trigger must not fire on a resume, and vice versa — the two are separate types
771
+ _e.sent();
772
+ // P8: the dedupe guard — the .updated that accompanies a status='paused' transition must not
773
+ // fire on top of the dedicated event. Stripe isn't expected to send this combination at all;
774
+ // the case pins the guard so a future refactor can't quietly drop it.
775
+ return [4 /*yield*/, run_pause_case({
776
+ label: 'p8-paused-status-suppressed',
777
+ type: 'Subscription Paused',
778
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_updated_event)({
779
+ stripeCustomerId: stripeCustomerId,
780
+ previousAttributes: { pause_collection: null, status: 'trialing' },
781
+ pauseCollection: stripe_webhook_helpers_1.PAUSE_COLLECTION,
782
+ status: 'paused',
783
+ }); },
784
+ shouldFire: false,
785
+ title: 'a pause_collection change coinciding with status=paused is suppressed',
786
+ })
787
+ /* ---- product scoping, over the pause_collection path ---- */
788
+ // P9-P12: the same matrix the payment-failed cases cover, applied to the new triggers
789
+ ];
790
+ case 56:
791
+ // P8: the dedupe guard — the .updated that accompanies a status='paused' transition must not
792
+ // fire on top of the dedicated event. Stripe isn't expected to send this combination at all;
793
+ // the case pins the guard so a future refactor can't quietly drop it.
794
+ _e.sent();
795
+ /* ---- product scoping, over the pause_collection path ---- */
796
+ // P9-P12: the same matrix the payment-failed cases cover, applied to the new triggers
797
+ return [4 /*yield*/, run_pause_case({
798
+ label: 'p9-scoped-matching',
799
+ type: 'Subscription Paused',
800
+ productIds: [productA.id],
801
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_updated_event)({
802
+ stripeCustomerId: stripeCustomerId,
803
+ items: [(0, stripe_webhook_helpers_1.item_with_price_product)(stripeProductA_1)],
804
+ previousAttributes: { pause_collection: null },
805
+ pauseCollection: stripe_webhook_helpers_1.PAUSE_COLLECTION,
806
+ }); },
807
+ shouldFire: true,
808
+ title: 'Subscription Paused scoped to the paused product fires',
809
+ })];
810
+ case 57:
811
+ /* ---- product scoping, over the pause_collection path ---- */
812
+ // P9-P12: the same matrix the payment-failed cases cover, applied to the new triggers
813
+ _e.sent();
814
+ return [4 /*yield*/, run_pause_case({
815
+ label: 'p10-scoped-nonmatching',
816
+ type: 'Subscription Paused',
817
+ productIds: [productB.id],
818
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_updated_event)({
819
+ stripeCustomerId: stripeCustomerId,
820
+ items: [(0, stripe_webhook_helpers_1.item_with_price_product)(stripeProductA_1)],
821
+ previousAttributes: { pause_collection: null },
822
+ pauseCollection: stripe_webhook_helpers_1.PAUSE_COLLECTION,
823
+ }); },
824
+ shouldFire: false,
825
+ title: 'Subscription Paused scoped to another product does not fire',
826
+ })];
827
+ case 58:
828
+ _e.sent();
829
+ return [4 /*yield*/, run_pause_case({
830
+ label: 'p11-empty-list',
831
+ type: 'Subscription Paused',
832
+ productIds: [],
833
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_updated_event)({
834
+ stripeCustomerId: stripeCustomerId,
835
+ items: [(0, stripe_webhook_helpers_1.item_with_price_product)(stripeProductA_1)],
836
+ previousAttributes: { pause_collection: null },
837
+ pauseCollection: stripe_webhook_helpers_1.PAUSE_COLLECTION,
838
+ }); },
839
+ shouldFire: true,
840
+ title: 'Subscription Paused with empty productIds fires',
841
+ })
842
+ // plan.product and expanded price.product objects both have to resolve, same as the invoice path
843
+ ];
844
+ case 59:
845
+ _e.sent();
846
+ // plan.product and expanded price.product objects both have to resolve, same as the invoice path
847
+ return [4 /*yield*/, run_pause_case({
848
+ label: 'p12-plan-product',
849
+ type: 'Subscription Resumed',
850
+ productIds: [productA.id],
851
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_updated_event)({
852
+ stripeCustomerId: stripeCustomerId,
853
+ items: [(0, stripe_webhook_helpers_1.item_with_plan_product)(stripeProductA_1)],
854
+ previousAttributes: { pause_collection: stripe_webhook_helpers_1.PAUSE_COLLECTION },
855
+ pauseCollection: null,
856
+ }); },
857
+ shouldFire: true,
858
+ title: 'plan.product resolves for a scoped Subscription Resumed trigger',
859
+ })];
860
+ case 60:
861
+ // plan.product and expanded price.product objects both have to resolve, same as the invoice path
862
+ _e.sent();
863
+ return [4 /*yield*/, run_pause_case({
864
+ label: 'p13-expanded-product',
865
+ type: 'Subscription Resumed',
866
+ productIds: [productA.id],
867
+ event: function (stripeCustomerId) { return (0, stripe_webhook_helpers_1.subscription_resumed_event)({
868
+ stripeCustomerId: stripeCustomerId,
869
+ items: [(0, stripe_webhook_helpers_1.item_with_expanded_price_product)(stripeProductA_1)],
870
+ }); },
871
+ shouldFire: true,
872
+ title: 'expanded price.product resolves on the dedicated resumed event',
873
+ })
874
+ /* ---- validator ---- */
875
+ // P14: same round-trip guarantees as F7, for both new types
876
+ ];
877
+ case 61:
878
+ _e.sent();
879
+ return [4 /*yield*/, new_trigger({
880
+ title: "Stripe subscription paused (validator round-trip) ".concat(RUN),
881
+ event: { type: 'Subscription Paused', info: { productIds: [productA.id] } },
882
+ tags: [tag('p14')],
883
+ })];
884
+ case 62:
885
+ p14Scoped = _e.sent();
886
+ return [4 /*yield*/, sdk.api.automation_triggers.getOne(p14Scoped.id)];
887
+ case 63:
888
+ p14Fetched = _e.sent();
889
+ (0, testing_1.assert)(JSON.stringify((_d = p14Fetched.event.info) === null || _d === void 0 ? void 0 : _d.productIds) === JSON.stringify([productA.id]), "expected productIds to round-trip, got ".concat(JSON.stringify(p14Fetched.event)), 'Subscription Paused productIds round-trips through the validator');
890
+ return [4 /*yield*/, new_trigger({
891
+ title: "Stripe subscription resumed (no info) ".concat(RUN),
892
+ event: { type: 'Subscription Resumed' },
893
+ tags: [tag('p14-no-info')],
894
+ })];
895
+ case 64:
896
+ _e.sent();
897
+ (0, testing_1.assert)(true, '', 'Subscription Resumed with omitted info accepted');
898
+ rejectedInvalidPausedProductId = false;
899
+ _e.label = 65;
900
+ case 65:
901
+ _e.trys.push([65, 67, , 68]);
902
+ return [4 /*yield*/, new_trigger({
903
+ title: "Stripe subscription paused (invalid productId) ".concat(RUN),
904
+ event: { type: 'Subscription Paused', info: { productIds: ['not-a-mongo-id'] } },
905
+ tags: [tag('p14-invalid')],
906
+ })];
907
+ case 66:
908
+ _e.sent();
909
+ return [3 /*break*/, 68];
910
+ case 67:
911
+ e_2 = _e.sent();
912
+ rejectedInvalidPausedProductId = true;
913
+ return [3 /*break*/, 68];
914
+ case 68:
915
+ (0, testing_1.assert)(rejectedInvalidPausedProductId, 'expected a non-ObjectId productId to be rejected', 'invalid Subscription Paused productId rejected');
916
+ console.log("All Stripe webhook trigger tests passed!");
917
+ return [3 /*break*/, 72];
918
+ case 69:
919
+ // Best-effort only: the harness exits the process on the first failed assertion, which skips
920
+ // this block. setup_stripe_test_integration clears integration residue on the next run.
921
+ return [4 /*yield*/, cleanup().catch(console.error)];
922
+ case 70:
923
+ // Best-effort only: the harness exits the process on the first failed assertion, which skips
924
+ // this block. setup_stripe_test_integration clears integration residue on the next run.
925
+ _e.sent();
926
+ return [4 /*yield*/, Promise.all(__spreadArray(__spreadArray(__spreadArray([], createdTriggerIds.map(function (id) { return sdk.api.automation_triggers.deleteOne(id).catch(console.error); }), true), createdProductIds.map(function (id) { return sdk.api.products.deleteOne(id).catch(console.error); }), true), createdEnduserIds.map(function (id) { return sdk.api.endusers.deleteOne(id).catch(console.error); }), true))];
927
+ case 71:
928
+ _e.sent();
929
+ return [7 /*endfinally*/];
930
+ case 72: return [2 /*return*/];
931
+ }
932
+ });
933
+ });
934
+ };
935
+ exports.stripe_webhook_triggers_tests = stripe_webhook_triggers_tests;
936
+ // Allow running this test file independently
937
+ if (require.main === module) {
938
+ console.log("Using API URL: ".concat(host));
939
+ var sdk_2 = new sdk_1.Session({ host: host });
940
+ var sdkNonAdmin_1 = new sdk_1.Session({ host: host });
941
+ var runTests = function () { return __awaiter(void 0, void 0, void 0, function () {
942
+ return __generator(this, function (_a) {
943
+ switch (_a.label) {
944
+ case 0: return [4 /*yield*/, (0, setup_1.setup_tests)(sdk_2, sdkNonAdmin_1)];
945
+ case 1:
946
+ _a.sent();
947
+ return [4 /*yield*/, (0, exports.stripe_webhook_triggers_tests)({ sdk: sdk_2, sdkNonAdmin: sdkNonAdmin_1 })];
948
+ case 2:
949
+ _a.sent();
950
+ return [2 /*return*/];
951
+ }
952
+ });
953
+ }); };
954
+ runTests()
955
+ .then(function () {
956
+ console.log("Stripe webhook triggers test suite completed successfully");
957
+ process.exit(0);
958
+ })
959
+ .catch(function (error) {
960
+ console.error("Stripe webhook triggers test suite failed:", error);
961
+ process.exit(1);
962
+ });
963
+ }
964
+ //# sourceMappingURL=stripe_webhook_triggers.test.js.map