@tellescope/sdk 1.253.0 → 1.253.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.d.ts +6 -0
  2. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.d.ts.map +1 -0
  3. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.js +256 -0
  4. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.js.map +1 -0
  5. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.d.ts +43 -0
  6. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.d.ts.map +1 -0
  7. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.js +168 -0
  8. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.js.map +1 -0
  9. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts +23 -0
  10. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts.map +1 -0
  11. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js +325 -0
  12. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js.map +1 -0
  13. package/lib/cjs/tests/api_tests/user_portal_settings.test.d.ts.map +1 -1
  14. package/lib/cjs/tests/api_tests/user_portal_settings.test.js +104 -28
  15. package/lib/cjs/tests/api_tests/user_portal_settings.test.js.map +1 -1
  16. package/lib/cjs/tests/tests.d.ts.map +1 -1
  17. package/lib/cjs/tests/tests.js +444 -174
  18. package/lib/cjs/tests/tests.js.map +1 -1
  19. package/lib/esm/tests/api_tests/beluga_manual_sync.test.d.ts +6 -0
  20. package/lib/esm/tests/api_tests/beluga_manual_sync.test.d.ts.map +1 -0
  21. package/lib/esm/tests/api_tests/beluga_manual_sync.test.js +252 -0
  22. package/lib/esm/tests/api_tests/beluga_manual_sync.test.js.map +1 -0
  23. package/lib/esm/tests/api_tests/gcal_sync_retry.test.d.ts +43 -0
  24. package/lib/esm/tests/api_tests/gcal_sync_retry.test.d.ts.map +1 -0
  25. package/lib/esm/tests/api_tests/gcal_sync_retry.test.js +164 -0
  26. package/lib/esm/tests/api_tests/gcal_sync_retry.test.js.map +1 -0
  27. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts +23 -0
  28. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts.map +1 -0
  29. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js +321 -0
  30. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js.map +1 -0
  31. package/lib/esm/tests/api_tests/user_portal_settings.test.d.ts.map +1 -1
  32. package/lib/esm/tests/api_tests/user_portal_settings.test.js +104 -28
  33. package/lib/esm/tests/api_tests/user_portal_settings.test.js.map +1 -1
  34. package/lib/esm/tests/tests.d.ts.map +1 -1
  35. package/lib/esm/tests/tests.js +444 -174
  36. package/lib/esm/tests/tests.js.map +1 -1
  37. package/lib/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +10 -10
  39. package/src/tests/api_tests/beluga_manual_sync.test.ts +159 -0
  40. package/src/tests/api_tests/gcal_sync_retry.test.ts +104 -0
  41. package/src/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.ts +214 -0
  42. package/src/tests/api_tests/user_portal_settings.test.ts +71 -1
  43. package/src/tests/tests.ts +222 -6
  44. package/test_generated.pdf +0 -0
@@ -0,0 +1,6 @@
1
+ import { Session } from "../../sdk";
2
+ export declare const beluga_manual_sync_tests: ({ sdk, sdkNonAdmin }: {
3
+ sdk: Session;
4
+ sdkNonAdmin: Session;
5
+ }) => Promise<void>;
6
+ //# sourceMappingURL=beluga_manual_sync.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"beluga_manual_sync.test.d.ts","sourceRoot":"","sources":["../../../../src/tests/api_tests/beluga_manual_sync.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAkBnC,eAAO,MAAM,wBAAwB;SAAuC,OAAO;iBAAe,OAAO;mBAqHxG,CAAA"}
@@ -0,0 +1,256 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ 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;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.beluga_manual_sync_tests = void 0;
40
+ require('source-map-support').install();
41
+ var sdk_1 = require("../../sdk");
42
+ var testing_1 = require("@tellescope/testing");
43
+ var setup_1 = require("../setup");
44
+ var constants_1 = require("@tellescope/constants");
45
+ var host = process.env.API_URL || 'http://localhost:8080';
46
+ // Manual Beluga re-sync guard tests (CU-86e1uxz1n).
47
+ // - form_responses.push_to_EHR with target === BELUGA_TITLE
48
+ // - files.push with destination === BELUGA_TITLE
49
+ //
50
+ // Fast / no-upload: this only verifies the bad-input / guard branches that reject before any
51
+ // Beluga call. It performs NO S3 file uploads and triggers NO actual sync (both slow and require
52
+ // live Beluga sandbox credentials). File records are created via prepare_file_upload alone — that
53
+ // inserts the DB record, which is all the guards need.
54
+ var beluga_manual_sync_tests = function (_a) {
55
+ var sdk = _a.sdk, sdkNonAdmin = _a.sdkNonAdmin;
56
+ return __awaiter(void 0, void 0, void 0, function () {
57
+ var errorMessage, enduserId, belugaFormId, plainFormId, fileIds, createdBelugaIntegrationId, enduser_1, belugaForm, plainForm, plainField_1, submitForm, createFileRecord, draft_1, plainResponseId_1, belugaIntegrationAvailable, existing, _b, created, e_1, unlinkedFile_1, _i, fileIds_1, id;
58
+ return __generator(this, function (_c) {
59
+ switch (_c.label) {
60
+ case 0:
61
+ (0, testing_1.log_header)("Beluga Manual Sync Guard Tests (FormResponses & Files)");
62
+ errorMessage = function (e) { var _a; return ((e === null || e === void 0 ? void 0 : e.message) || ((_a = e === null || e === void 0 ? void 0 : e.toString) === null || _a === void 0 ? void 0 : _a.call(e)) || JSON.stringify(e)); };
63
+ fileIds = [];
64
+ _c.label = 1;
65
+ case 1:
66
+ _c.trys.push([1, , 22, 35]);
67
+ return [4 /*yield*/, sdk.api.endusers.createOne({
68
+ fname: 'beluga-sync',
69
+ email: "beluga_manual_sync_".concat(Date.now(), "@test.tellescope.com"),
70
+ })];
71
+ case 2:
72
+ enduser_1 = _c.sent();
73
+ enduserId = enduser_1.id;
74
+ return [4 /*yield*/, sdk.api.forms.createOne({ title: 'Beluga Manual Sync Form', belugaVisitType: 'sync' })];
75
+ case 3:
76
+ belugaForm = _c.sent();
77
+ belugaFormId = belugaForm.id;
78
+ return [4 /*yield*/, sdk.api.forms.createOne({ title: 'Non-Beluga Manual Sync Form' })];
79
+ case 4:
80
+ plainForm = _c.sent();
81
+ plainFormId = plainForm.id;
82
+ return [4 /*yield*/, sdk.api.form_fields.createOne({
83
+ formId: plainForm.id, type: 'string', title: 'Field', previousFields: [{ type: 'root', info: {} }],
84
+ })];
85
+ case 5:
86
+ plainField_1 = _c.sent();
87
+ submitForm = function (formId) { return __awaiter(void 0, void 0, void 0, function () {
88
+ var _a, accessCode, response;
89
+ return __generator(this, function (_b) {
90
+ switch (_b.label) {
91
+ case 0: return [4 /*yield*/, sdk.api.form_responses.prepare_form_response({ enduserId: enduser_1.id, formId: formId })];
92
+ case 1:
93
+ _a = _b.sent(), accessCode = _a.accessCode, response = _a.response;
94
+ return [4 /*yield*/, sdk.api.form_responses.submit_form_response({
95
+ accessCode: accessCode,
96
+ responses: [{ fieldId: plainField_1.id, fieldTitle: 'Field', answer: { type: 'string', value: 'x' } }],
97
+ })];
98
+ case 2:
99
+ _b.sent();
100
+ return [2 /*return*/, response.id];
101
+ }
102
+ });
103
+ }); };
104
+ createFileRecord = function (name) { return __awaiter(void 0, void 0, void 0, function () {
105
+ var file;
106
+ return __generator(this, function (_a) {
107
+ switch (_a.label) {
108
+ case 0: return [4 /*yield*/, sdk.api.files.prepare_file_upload({
109
+ name: name,
110
+ type: 'text/plain', size: 1, enduserId: enduser_1.id,
111
+ })];
112
+ case 1:
113
+ file = (_a.sent()).file;
114
+ fileIds.push(file.id);
115
+ return [2 /*return*/, file];
116
+ }
117
+ });
118
+ }); };
119
+ return [4 /*yield*/, sdk.api.form_responses.prepare_form_response({ enduserId: enduser_1.id, formId: belugaForm.id })];
120
+ case 6:
121
+ draft_1 = (_c.sent()).response;
122
+ return [4 /*yield*/, (0, testing_1.async_test)("push_to_EHR(target=BELUGA) rejects an unsubmitted form response", function () { return sdk.api.form_responses.push_to_EHR({ id: draft_1.id, target: constants_1.BELUGA_TITLE }); }, { shouldError: true, onError: function (e) { return /has not been submitted/i.test(errorMessage(e)); } })
123
+ // Submitted, but the form has no belugaVisitType → rejected as not configured
124
+ ];
125
+ case 7:
126
+ _c.sent();
127
+ return [4 /*yield*/, submitForm(plainForm.id)];
128
+ case 8:
129
+ plainResponseId_1 = _c.sent();
130
+ return [4 /*yield*/, (0, testing_1.async_test)("push_to_EHR(target=BELUGA) rejects a form not configured for Beluga", function () { return sdk.api.form_responses.push_to_EHR({ id: plainResponseId_1, target: constants_1.BELUGA_TITLE }); }, { shouldError: true, onError: function (e) { return /not configured for Beluga/i.test(errorMessage(e)); } })
131
+ // ──────────────────────────────────────────────────────────────────────────
132
+ // 2. files.push(destination=BELUGA) guard — the endpoint resolves the destination
133
+ // integration first, so a Beluga integration must exist for the branch to be reached.
134
+ // Create a placeholder if the org has none; skip gracefully if that's not permitted.
135
+ // ──────────────────────────────────────────────────────────────────────────
136
+ ];
137
+ case 9:
138
+ _c.sent();
139
+ belugaIntegrationAvailable = false;
140
+ _c.label = 10;
141
+ case 10:
142
+ _c.trys.push([10, 12, , 13]);
143
+ return [4 /*yield*/, sdk.api.integrations.load_redacted({})];
144
+ case 11:
145
+ existing = _c.sent();
146
+ belugaIntegrationAvailable = !!existing.integrations.find(function (i) { return i.title === constants_1.BELUGA_TITLE; });
147
+ return [3 /*break*/, 13];
148
+ case 12:
149
+ _b = _c.sent();
150
+ return [3 /*break*/, 13];
151
+ case 13:
152
+ if (!!belugaIntegrationAvailable) return [3 /*break*/, 17];
153
+ _c.label = 14;
154
+ case 14:
155
+ _c.trys.push([14, 16, , 17]);
156
+ return [4 /*yield*/, sdk.api.integrations.createOne({
157
+ title: constants_1.BELUGA_TITLE,
158
+ authentication: {
159
+ type: 'oauth2',
160
+ info: { access_token: 'test-access-token', refresh_token: 'test-refresh-token', scope: '', token_type: 'Bearer', expiry_date: new Date().getTime() },
161
+ },
162
+ })];
163
+ case 15:
164
+ created = _c.sent();
165
+ createdBelugaIntegrationId = created.id;
166
+ belugaIntegrationAvailable = true;
167
+ return [3 /*break*/, 17];
168
+ case 16:
169
+ e_1 = _c.sent();
170
+ console.log("Could not create a Beluga integration for testing; skipping files.push guard:", errorMessage(e_1));
171
+ return [3 /*break*/, 17];
172
+ case 17:
173
+ if (!belugaIntegrationAvailable) return [3 /*break*/, 20];
174
+ return [4 /*yield*/, createFileRecord('beluga-unlinked.txt')];
175
+ case 18:
176
+ unlinkedFile_1 = _c.sent();
177
+ return [4 /*yield*/, (0, testing_1.async_test)("files.push(destination=BELUGA) rejects a file with no associated form response", function () { return sdk.api.files.push({ id: unlinkedFile_1.id, destination: constants_1.BELUGA_TITLE }); }, { shouldError: true, onError: function (e) { return /not associated with a form response/i.test(errorMessage(e)); } })];
178
+ case 19:
179
+ _c.sent();
180
+ return [3 /*break*/, 21];
181
+ case 20:
182
+ console.log("⏭️ Skipping files.push(destination=BELUGA) guard (no Beluga integration available)");
183
+ _c.label = 21;
184
+ case 21: return [3 /*break*/, 35];
185
+ case 22:
186
+ _i = 0, fileIds_1 = fileIds;
187
+ _c.label = 23;
188
+ case 23:
189
+ if (!(_i < fileIds_1.length)) return [3 /*break*/, 26];
190
+ id = fileIds_1[_i];
191
+ return [4 /*yield*/, sdk.api.files.deleteOne(id).catch(console.error)];
192
+ case 24:
193
+ _c.sent();
194
+ _c.label = 25;
195
+ case 25:
196
+ _i++;
197
+ return [3 /*break*/, 23];
198
+ case 26:
199
+ if (!belugaFormId) return [3 /*break*/, 28];
200
+ return [4 /*yield*/, sdk.api.forms.deleteOne(belugaFormId).catch(console.error)];
201
+ case 27:
202
+ _c.sent();
203
+ _c.label = 28;
204
+ case 28:
205
+ if (!plainFormId) return [3 /*break*/, 30];
206
+ return [4 /*yield*/, sdk.api.forms.deleteOne(plainFormId).catch(console.error)];
207
+ case 29:
208
+ _c.sent();
209
+ _c.label = 30;
210
+ case 30:
211
+ if (!enduserId) return [3 /*break*/, 32];
212
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(enduserId).catch(console.error)];
213
+ case 31:
214
+ _c.sent();
215
+ _c.label = 32;
216
+ case 32:
217
+ if (!createdBelugaIntegrationId) return [3 /*break*/, 34];
218
+ return [4 /*yield*/, sdk.api.integrations.deleteOne(createdBelugaIntegrationId).catch(console.error)];
219
+ case 33:
220
+ _c.sent();
221
+ _c.label = 34;
222
+ case 34: return [7 /*endfinally*/];
223
+ case 35: return [2 /*return*/];
224
+ }
225
+ });
226
+ });
227
+ };
228
+ exports.beluga_manual_sync_tests = beluga_manual_sync_tests;
229
+ if (require.main === module) {
230
+ console.log("Using API URL: ".concat(host));
231
+ var sdk_2 = new sdk_1.Session({ host: host });
232
+ var sdkNonAdmin_1 = new sdk_1.Session({ host: host });
233
+ var runTests = function () { return __awaiter(void 0, void 0, void 0, function () {
234
+ return __generator(this, function (_a) {
235
+ switch (_a.label) {
236
+ case 0: return [4 /*yield*/, (0, setup_1.setup_tests)(sdk_2, sdkNonAdmin_1)];
237
+ case 1:
238
+ _a.sent();
239
+ return [4 /*yield*/, (0, exports.beluga_manual_sync_tests)({ sdk: sdk_2, sdkNonAdmin: sdkNonAdmin_1 })];
240
+ case 2:
241
+ _a.sent();
242
+ return [2 /*return*/];
243
+ }
244
+ });
245
+ }); };
246
+ runTests()
247
+ .then(function () {
248
+ console.log("✅ Beluga manual sync test suite completed successfully");
249
+ process.exit(0);
250
+ })
251
+ .catch(function (error) {
252
+ console.error("❌ Beluga manual sync test suite failed:", error);
253
+ process.exit(1);
254
+ });
255
+ }
256
+ //# sourceMappingURL=beluga_manual_sync.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"beluga_manual_sync.test.js","sourceRoot":"","sources":["../../../../src/tests/api_tests/beluga_manual_sync.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { Session } from "../../sdk";
2
+ /**
3
+ * Google Calendar sync retry — integration coverage.
4
+ *
5
+ * ┌─ ARCHITECTURE NOTE (why the full mock-Google scenarios are gated) ──────────┐
6
+ * │ SDK api_tests run in a SEPARATE process from the API server (they talk to │
7
+ * │ host = API_URL / http://localhost:8080). The retry scheduler, the Google │
8
+ * │ retryable-error predicates, and the google.calendar() client all live in the │
9
+ * │ API SERVER process. A stub installed here (in the SDK test process) cannot │
10
+ * │ replace the server's in-process google client, so we cannot deterministically│
11
+ * │ inject 429 / 500 / ECONNRESET responses from this test alone. │
12
+ * │ │
13
+ * │ Two ways to run the full fail-429-then-succeed / exhaustion / cap scenarios: │
14
+ * │ 1. Run the API server with NODE_ENV=test and RETRY_SCHEDULER_DELAYS_MS=10,20 │
15
+ * │ (already honored by the singleton constructor) plus a server-side │
16
+ * │ fault-injection hook on sdk.events.* that reads e.g. │
17
+ * │ process.env.GCAL_TEST_FORCE_ERROR — that hook does not exist yet. │
18
+ * │ 2. Drive the scheduler directly with the in-process unit tests, which DO │
19
+ * │ cover all retry mechanics deterministically: │
20
+ * │ packages/private/api/api/modules/retry_scheduler.test.ts │
21
+ * │ packages/private/api/api/integrations/google.test.ts │
22
+ * │ │
23
+ * │ The scenario matrix below is recorded for when a server-side hook is added. │
24
+ * └──────────────────────────────────────────────────────────────────────────────┘
25
+ *
26
+ * Scenario matrix (requires server-side Google fault injection — see note):
27
+ * 1. create retry: fail 429 once then succeed -> gcal reference written, NO background_errors
28
+ * 2. exhaustion: fail 429 on every call -> exactly one "Google Calendar Push Error" background_errors row
29
+ * 3. non-retryable: fail 403 -> background_errors written immediately, no retries
30
+ * 4. create idempotency: fail ECONNRESET (network) -> NON-retryable for create (duplicate risk),
31
+ * background_errors written, no retry, no duplicate insert
32
+ * 5. update + delete: same as (1) for events.patch and events.delete
33
+ * 6. cap exceeded: maxOpenRetries=2, 3 events all fail retryably -> 3rd -> background_errors immediately
34
+ *
35
+ * The runnable assertions below cover what IS observable end-to-end without a
36
+ * connected Google account: the refactored call sites must not regress the common
37
+ * "user has no Google integration" path (no sync attempt, no background_errors, no retry).
38
+ */
39
+ export declare const gcal_sync_retry_tests: ({ sdk }: {
40
+ sdk: Session;
41
+ sdkNonAdmin: Session;
42
+ }) => Promise<void>;
43
+ //# sourceMappingURL=gcal_sync_retry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gcal_sync_retry.test.d.ts","sourceRoot":"","sources":["../../../../src/tests/api_tests/gcal_sync_retry.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAUnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,qBAAqB;SAA2B,OAAO;iBAAe,OAAO;mBAwCzF,CAAA"}
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ 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;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.gcal_sync_retry_tests = void 0;
40
+ require('source-map-support').install();
41
+ var sdk_1 = require("../../sdk");
42
+ var testing_1 = require("@tellescope/testing");
43
+ var setup_1 = require("../setup");
44
+ var host = process.env.API_URL || 'http://localhost:8080';
45
+ /**
46
+ * Google Calendar sync retry — integration coverage.
47
+ *
48
+ * ┌─ ARCHITECTURE NOTE (why the full mock-Google scenarios are gated) ──────────┐
49
+ * │ SDK api_tests run in a SEPARATE process from the API server (they talk to │
50
+ * │ host = API_URL / http://localhost:8080). The retry scheduler, the Google │
51
+ * │ retryable-error predicates, and the google.calendar() client all live in the │
52
+ * │ API SERVER process. A stub installed here (in the SDK test process) cannot │
53
+ * │ replace the server's in-process google client, so we cannot deterministically│
54
+ * │ inject 429 / 500 / ECONNRESET responses from this test alone. │
55
+ * │ │
56
+ * │ Two ways to run the full fail-429-then-succeed / exhaustion / cap scenarios: │
57
+ * │ 1. Run the API server with NODE_ENV=test and RETRY_SCHEDULER_DELAYS_MS=10,20 │
58
+ * │ (already honored by the singleton constructor) plus a server-side │
59
+ * │ fault-injection hook on sdk.events.* that reads e.g. │
60
+ * │ process.env.GCAL_TEST_FORCE_ERROR — that hook does not exist yet. │
61
+ * │ 2. Drive the scheduler directly with the in-process unit tests, which DO │
62
+ * │ cover all retry mechanics deterministically: │
63
+ * │ packages/private/api/api/modules/retry_scheduler.test.ts │
64
+ * │ packages/private/api/api/integrations/google.test.ts │
65
+ * │ │
66
+ * │ The scenario matrix below is recorded for when a server-side hook is added. │
67
+ * └──────────────────────────────────────────────────────────────────────────────┘
68
+ *
69
+ * Scenario matrix (requires server-side Google fault injection — see note):
70
+ * 1. create retry: fail 429 once then succeed -> gcal reference written, NO background_errors
71
+ * 2. exhaustion: fail 429 on every call -> exactly one "Google Calendar Push Error" background_errors row
72
+ * 3. non-retryable: fail 403 -> background_errors written immediately, no retries
73
+ * 4. create idempotency: fail ECONNRESET (network) -> NON-retryable for create (duplicate risk),
74
+ * background_errors written, no retry, no duplicate insert
75
+ * 5. update + delete: same as (1) for events.patch and events.delete
76
+ * 6. cap exceeded: maxOpenRetries=2, 3 events all fail retryably -> 3rd -> background_errors immediately
77
+ *
78
+ * The runnable assertions below cover what IS observable end-to-end without a
79
+ * connected Google account: the refactored call sites must not regress the common
80
+ * "user has no Google integration" path (no sync attempt, no background_errors, no retry).
81
+ */
82
+ var gcal_sync_retry_tests = function (_a) {
83
+ var sdk = _a.sdk;
84
+ return __awaiter(void 0, void 0, void 0, function () {
85
+ var enduser;
86
+ return __generator(this, function (_b) {
87
+ switch (_b.label) {
88
+ case 0:
89
+ (0, testing_1.log_header)("Google Calendar Sync Retry");
90
+ if (process.env.GCAL_RETRY_INTEGRATION !== '1') {
91
+ console.log("ℹ️ Skipping mock-Google scenarios (set GCAL_RETRY_INTEGRATION=1 with a server-side "
92
+ + "fault-injection hook to run scenarios 1-6). Running no-integration regression checks only.");
93
+ }
94
+ return [4 /*yield*/, sdk.api.endusers.createOne({ fname: 'GcalRetry', lname: 'Test' })];
95
+ case 1:
96
+ enduser = _b.sent();
97
+ return [4 /*yield*/, (0, testing_1.async_test)('create event for user without Google integration does not produce a background error', function () { return __awaiter(void 0, void 0, void 0, function () {
98
+ var event, errors;
99
+ return __generator(this, function (_a) {
100
+ switch (_a.label) {
101
+ case 0: return [4 /*yield*/, sdk.api.calendar_events.createOne({
102
+ title: 'Gcal Retry Regression',
103
+ startTimeInMS: Date.now() + 1000 * 60 * 60,
104
+ durationInMinutes: 30,
105
+ attendees: [{ type: 'user', id: sdk.userInfo.id }, { type: 'enduser', id: enduser.id }],
106
+ })
107
+ // give side-effect handlers a moment to run
108
+ ];
109
+ case 1:
110
+ event = _a.sent();
111
+ // give side-effect handlers a moment to run
112
+ return [4 /*yield*/, (0, testing_1.wait)(undefined, 750)];
113
+ case 2:
114
+ // give side-effect handlers a moment to run
115
+ _a.sent();
116
+ return [4 /*yield*/, sdk.api.background_errors.getSome({}).catch(function () { return []; })
117
+ // clean up
118
+ ];
119
+ case 3:
120
+ errors = _a.sent();
121
+ // clean up
122
+ return [4 /*yield*/, sdk.api.calendar_events.deleteOne(event.id).catch(function () { })
123
+ // No Google integration on the test user => no push attempt => no error row.
124
+ ];
125
+ case 4:
126
+ // clean up
127
+ _a.sent();
128
+ // No Google integration on the test user => no push attempt => no error row.
129
+ return [2 /*return*/, errors.filter(function (e) { return (e.userId === sdk.userInfo.id && e.title === "Google Calendar Push Error"); }).length];
130
+ }
131
+ });
132
+ }); }, { onResult: function (count) { return count === 0; } })
133
+ // cleanup
134
+ ];
135
+ case 2:
136
+ _b.sent();
137
+ // cleanup
138
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(enduser.id).catch(function () { })];
139
+ case 3:
140
+ // cleanup
141
+ _b.sent();
142
+ return [2 /*return*/];
143
+ }
144
+ });
145
+ });
146
+ };
147
+ exports.gcal_sync_retry_tests = gcal_sync_retry_tests;
148
+ if (require.main === module) {
149
+ var sdk_2 = new sdk_1.Session({ host: host });
150
+ var sdkNonAdmin_1 = new sdk_1.Session({ host: host });
151
+ var runTests = function () { return __awaiter(void 0, void 0, void 0, function () {
152
+ return __generator(this, function (_a) {
153
+ switch (_a.label) {
154
+ case 0: return [4 /*yield*/, (0, setup_1.setup_tests)(sdk_2, sdkNonAdmin_1)];
155
+ case 1:
156
+ _a.sent();
157
+ return [4 /*yield*/, (0, exports.gcal_sync_retry_tests)({ sdk: sdk_2, sdkNonAdmin: sdkNonAdmin_1 })];
158
+ case 2:
159
+ _a.sent();
160
+ return [2 /*return*/];
161
+ }
162
+ });
163
+ }); };
164
+ runTests()
165
+ .then(function () { console.log("✅ gcal sync retry test suite completed successfully"); process.exit(0); })
166
+ .catch(function (error) { console.error("❌ gcal sync retry test suite failed:", error); process.exit(1); });
167
+ }
168
+ //# sourceMappingURL=gcal_sync_retry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gcal_sync_retry.test.js","sourceRoot":"","sources":["../../../../src/tests/api_tests/gcal_sync_retry.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,CAAC,oBAAoB,CAAC,CAAC,OAAO,EAAE,CAAC;AAExC,iCAAmC;AACnC,+CAI4B;AAC5B,kCAAsC;AAEtC,IAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,uBAAgC,CAAA;AAEpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACI,IAAM,qBAAqB,GAAG,UAAO,EAAgD;QAA9C,GAAG,SAAA;;;;;;oBAC/C,IAAA,oBAAU,EAAC,4BAA4B,CAAC,CAAA;oBAExC,IAAI,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,GAAG,EAAE;wBAC9C,OAAO,CAAC,GAAG,CAAC,sFAAsF;8BAC9F,4FAA4F,CAAC,CAAA;qBAClG;oBAIe,qBAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAA;;oBAAjF,OAAO,GAAG,SAAuE;oBAEvF,qBAAM,IAAA,oBAAU,EACd,sFAAsF,EACtF;;;;4CACgB,qBAAM,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,SAAS,CAAC;4CACpD,KAAK,EAAE,uBAAuB;4CAC9B,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE;4CAC1C,iBAAiB,EAAE,EAAE;4CACrB,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC;yCACxF,CAAC;wCAEF,4CAA4C;sCAF1C;;wCALI,KAAK,GAAG,SAKZ;wCAEF,4CAA4C;wCAC5C,qBAAM,IAAA,cAAI,EAAC,SAAS,EAAE,GAAG,CAAC,EAAA;;wCAD1B,4CAA4C;wCAC5C,SAA0B,CAAA;wCAEX,qBAAM,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,cAAM,OAAA,EAAE,EAAF,CAAE,CAAC;4CAE1E,WAAW;0CAF+D;;wCAApE,MAAM,GAAG,SAA2D;wCAE1E,WAAW;wCACX,qBAAM,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,cAAO,CAAC,CAAC;4CAEjE,6EAA6E;0CAFZ;;wCADjE,WAAW;wCACX,SAAiE,CAAA;wCAEjE,6EAA6E;wCAC7E,sBAAO,MAAM,CAAC,MAAM,CAAC,UAAC,CAAM,IAAK,OAAA,CAC/B,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,4BAA4B,CACzE,EAFgC,CAEhC,CAAC,CAAC,MAAM,EAAA;;;6BACV,EACD,EAAE,QAAQ,EAAE,UAAC,KAAK,IAAK,OAAA,KAAK,KAAK,CAAC,EAAX,CAAW,EAAE,CACrC;wBAED,UAAU;sBAFT;;oBAxBD,SAwBC,CAAA;oBAED,UAAU;oBACV,qBAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,cAAO,CAAC,CAAC,EAAA;;oBAD5D,UAAU;oBACV,SAA4D,CAAA;;;;;CAC7D,CAAA;AAxCY,QAAA,qBAAqB,yBAwCjC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE;IAC3B,IAAM,KAAG,GAAG,IAAI,aAAO,CAAC,EAAE,IAAI,MAAA,EAAE,CAAC,CAAA;IACjC,IAAM,aAAW,GAAG,IAAI,aAAO,CAAC,EAAE,IAAI,MAAA,EAAE,CAAC,CAAA;IAEzC,IAAM,QAAQ,GAAG;;;wBACf,qBAAM,IAAA,mBAAW,EAAC,KAAG,EAAE,aAAW,CAAC,EAAA;;oBAAnC,SAAmC,CAAA;oBACnC,qBAAM,IAAA,6BAAqB,EAAC,EAAE,GAAG,OAAA,EAAE,WAAW,eAAA,EAAE,CAAC,EAAA;;oBAAjD,SAAiD,CAAA;;;;SAClD,CAAA;IAED,QAAQ,EAAE;SACP,IAAI,CAAC,cAAQ,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA,CAAC,CAAC,CAAC;SACnG,KAAK,CAAC,UAAC,KAAK,IAAO,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;CACvG"}
@@ -0,0 +1,23 @@
1
+ import { Session } from "../../../sdk";
2
+ /**
3
+ * Regression test for F-0106 and F-0110
4
+ * (security-audit/findings/F-0106-enduser-self-update-admin-only-fields.md,
5
+ * security-audit/findings/F-0110-form-responses-enduser-update-admin-only-fields.md).
6
+ *
7
+ * Endusers could PATCH admin-only / access-bearing / attribution-bearing fields on
8
+ * their own endusers record (assignedTo, tags, references, ...) and their own
9
+ * form_responses (procedureCodes, submittedBy, markedAsSubmitted, ...). The fix adds
10
+ * the `enduserUpdatesDisabled` field option (schema.ts ModelFieldInfo), enforced for
11
+ * enduser sessions in the generic update handler (routing.ts createDefaultEndpoints).
12
+ *
13
+ * This test asserts, for every flagged field on both models:
14
+ * - an enduser session updating its OWN record gets a 400 "<field> cannot be updated by endusers"
15
+ * - nothing persists (spot-checked on assignedTo, the highest-impact field)
16
+ * - enduser self-updates of allowed fields still work (fname, hideFromEnduserPortal)
17
+ * - staff sessions can still update the restricted fields
18
+ */
19
+ export declare const enduser_write_restrictions_tests: ({ sdk }: {
20
+ sdk: Session;
21
+ sdkNonAdmin: Session;
22
+ }) => Promise<void>;
23
+ //# sourceMappingURL=F-0106-F-0110-enduser-write-restrictions.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"F-0106-F-0110-enduser-write-restrictions.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAkB,MAAM,cAAc,CAAA;AA+DtD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gCAAgC;SAA2B,OAAO;iBAAe,OAAO;mBA6GpG,CAAA"}