@tellescope/sdk 1.256.15 → 2.0.0-beta.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/CLAUDE.md +5 -0
- package/env.example +39 -0
- package/lib/cjs/enduser.d.ts +1 -0
- package/lib/cjs/enduser.d.ts.map +1 -1
- package/lib/cjs/sdk.d.ts +5 -3
- package/lib/cjs/sdk.d.ts.map +1 -1
- package/lib/cjs/sdk.js +1 -0
- package/lib/cjs/sdk.js.map +1 -1
- package/lib/cjs/session.d.ts +1 -0
- package/lib/cjs/session.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/active_patient_count.test.js +1 -1
- package/lib/cjs/tests/api_tests/active_patient_count.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/appointment_rescheduled_trigger.test.js +1 -1
- package/lib/cjs/tests/api_tests/appointment_rescheduled_trigger.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/calendar_event_limits.test.js +5 -5
- package/lib/cjs/tests/api_tests/calendar_event_limits.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/calendar_event_references_update.test.js +1 -1
- package/lib/cjs/tests/api_tests/calendar_event_references_update.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/enduser_cross_access_isolation.test.js +1 -1
- package/lib/cjs/tests/api_tests/enduser_cross_access_isolation.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/enduser_fields_sync.test.d.ts +21 -0
- package/lib/cjs/tests/api_tests/enduser_fields_sync.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/enduser_fields_sync.test.js +215 -0
- package/lib/cjs/tests/api_tests/enduser_fields_sync.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/enduser_login_rate_limits.test.js +6 -6
- package/lib/cjs/tests/api_tests/enduser_login_rate_limits.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/enduser_session_invalidation.test.js +3 -3
- package/lib/cjs/tests/api_tests/enduser_session_invalidation.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/load_threads_care_team.test.d.ts +32 -0
- package/lib/cjs/tests/api_tests/load_threads_care_team.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/load_threads_care_team.test.js +257 -0
- package/lib/cjs/tests/api_tests/load_threads_care_team.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/managed_content_enduser_access.test.js +1 -1
- package/lib/cjs/tests/api_tests/managed_content_enduser_access.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/managed_content_file_access.test.js +1 -1
- package/lib/cjs/tests/api_tests/managed_content_file_access.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/mdi_webhooks.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/mdi_webhooks.test.js +21 -8
- package/lib/cjs/tests/api_tests/mdi_webhooks.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/nutrition_tracking.test.js +1 -1
- package/lib/cjs/tests/api_tests/nutrition_tracking.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/openloop_webhooks.test.js +1 -1
- package/lib/cjs/tests/api_tests/openloop_webhooks.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/programs.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/programs.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/programs.test.js +370 -0
- package/lib/cjs/tests/api_tests/programs.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/programs_trigger_filters.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/programs_trigger_filters.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/programs_trigger_filters.test.js +295 -0
- package/lib/cjs/tests/api_tests/programs_trigger_filters.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.js +1 -1
- package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/security/appointment-reschedule-ownership.test.d.ts +42 -0
- package/lib/cjs/tests/api_tests/security/appointment-reschedule-ownership.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/appointment-reschedule-ownership.test.js +484 -0
- package/lib/cjs/tests/api_tests/security/appointment-reschedule-ownership.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.js +1 -1
- package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/security/enduser-ai-summary-trust-gate.test.js +1 -1
- package/lib/cjs/tests/api_tests/security/enduser-ai-summary-trust-gate.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.js +1 -1
- package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.js +1 -1
- package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/security/file-link-session-confinement.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/security/file-link-session-confinement.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/file-link-session-confinement.test.js +357 -0
- package/lib/cjs/tests/api_tests/security/file-link-session-confinement.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.js +2 -2
- package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/security/rich-text-answer-sanitized-on-write.test.d.ts +32 -0
- package/lib/cjs/tests/api_tests/security/rich-text-answer-sanitized-on-write.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/rich-text-answer-sanitized-on-write.test.js +297 -0
- package/lib/cjs/tests/api_tests/security/rich-text-answer-sanitized-on-write.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.js +4 -1
- package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/templated_message_date_fields.test.d.ts +3 -0
- package/lib/cjs/tests/api_tests/templated_message_date_fields.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/templated_message_date_fields.test.js +202 -0
- package/lib/cjs/tests/api_tests/templated_message_date_fields.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/templated_message_link_in_href.test.d.ts +3 -0
- package/lib/cjs/tests/api_tests/templated_message_link_in_href.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/templated_message_link_in_href.test.js +233 -0
- package/lib/cjs/tests/api_tests/templated_message_link_in_href.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/templated_message_links.test.d.ts +3 -0
- package/lib/cjs/tests/api_tests/templated_message_links.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/templated_message_links.test.js +235 -0
- package/lib/cjs/tests/api_tests/templated_message_links.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/time_tracks.test.js +1 -1
- package/lib/cjs/tests/api_tests/time_tracks.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/trigger_contains_matching.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/trigger_contains_matching.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/trigger_contains_matching.test.js +395 -0
- package/lib/cjs/tests/api_tests/trigger_contains_matching.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/user_logs_restore_deleted.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/user_logs_restore_deleted.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/user_logs_restore_deleted.test.js +471 -0
- package/lib/cjs/tests/api_tests/user_logs_restore_deleted.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/user_portal_settings.test.js +1 -1
- package/lib/cjs/tests/api_tests/user_portal_settings.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/validation_behavior_locks.test.d.ts +2 -0
- package/lib/cjs/tests/api_tests/validation_behavior_locks.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/validation_behavior_locks.test.js +233 -0
- package/lib/cjs/tests/api_tests/validation_behavior_locks.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/vital_review_trigger_action.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/vital_review_trigger_action.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/vital_review_trigger_action.test.js +569 -0
- package/lib/cjs/tests/api_tests/vital_review_trigger_action.test.js.map +1 -0
- package/lib/cjs/tests/public_endpoint_tests.js +3 -2
- package/lib/cjs/tests/public_endpoint_tests.js.map +1 -1
- package/lib/cjs/tests/setup.d.ts +16 -0
- package/lib/cjs/tests/setup.d.ts.map +1 -1
- package/lib/cjs/tests/setup.js +55 -8
- package/lib/cjs/tests/setup.js.map +1 -1
- package/lib/cjs/tests/setup_isolated.d.ts +9 -0
- package/lib/cjs/tests/setup_isolated.d.ts.map +1 -1
- package/lib/cjs/tests/setup_isolated.js +23 -2
- package/lib/cjs/tests/setup_isolated.js.map +1 -1
- package/lib/cjs/tests/socket_tests.d.ts.map +1 -1
- package/lib/cjs/tests/socket_tests.js +3 -2
- package/lib/cjs/tests/socket_tests.js.map +1 -1
- package/lib/cjs/tests/tests.d.ts.map +1 -1
- package/lib/cjs/tests/tests.js +182 -166
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/cjs/tests/unit_tests/trigger_title_partials.test.d.ts +3 -0
- package/lib/cjs/tests/unit_tests/trigger_title_partials.test.d.ts.map +1 -0
- package/lib/cjs/tests/unit_tests/trigger_title_partials.test.js +118 -0
- package/lib/cjs/tests/unit_tests/trigger_title_partials.test.js.map +1 -0
- package/lib/cjs/tests/webhooks_tests.js +3 -2
- package/lib/cjs/tests/webhooks_tests.js.map +1 -1
- package/lib/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/esm/enduser.d.ts +2 -0
- package/lib/esm/enduser.d.ts.map +1 -1
- package/lib/esm/sdk.d.ts +8 -5
- package/lib/esm/sdk.d.ts.map +1 -1
- package/lib/esm/sdk.js +1 -0
- package/lib/esm/sdk.js.map +1 -1
- package/lib/esm/session.d.ts +2 -0
- package/lib/esm/session.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/active_patient_count.test.js +1 -1
- package/lib/esm/tests/api_tests/active_patient_count.test.js.map +1 -1
- package/lib/esm/tests/api_tests/appointment_rescheduled_trigger.test.js +1 -1
- package/lib/esm/tests/api_tests/appointment_rescheduled_trigger.test.js.map +1 -1
- package/lib/esm/tests/api_tests/calendar_event_limits.test.js +5 -5
- package/lib/esm/tests/api_tests/calendar_event_limits.test.js.map +1 -1
- package/lib/esm/tests/api_tests/calendar_event_references_update.test.js +1 -1
- package/lib/esm/tests/api_tests/calendar_event_references_update.test.js.map +1 -1
- package/lib/esm/tests/api_tests/enduser_cross_access_isolation.test.js +1 -1
- package/lib/esm/tests/api_tests/enduser_cross_access_isolation.test.js.map +1 -1
- package/lib/esm/tests/api_tests/enduser_fields_sync.test.d.ts +21 -0
- package/lib/esm/tests/api_tests/enduser_fields_sync.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/enduser_fields_sync.test.js +210 -0
- package/lib/esm/tests/api_tests/enduser_fields_sync.test.js.map +1 -0
- package/lib/esm/tests/api_tests/enduser_login_rate_limits.test.js +7 -7
- package/lib/esm/tests/api_tests/enduser_login_rate_limits.test.js.map +1 -1
- package/lib/esm/tests/api_tests/enduser_session_invalidation.test.js +4 -4
- package/lib/esm/tests/api_tests/enduser_session_invalidation.test.js.map +1 -1
- package/lib/esm/tests/api_tests/load_threads_care_team.test.d.ts +32 -0
- package/lib/esm/tests/api_tests/load_threads_care_team.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/load_threads_care_team.test.js +252 -0
- package/lib/esm/tests/api_tests/load_threads_care_team.test.js.map +1 -0
- package/lib/esm/tests/api_tests/managed_content_enduser_access.test.js +1 -1
- package/lib/esm/tests/api_tests/managed_content_enduser_access.test.js.map +1 -1
- package/lib/esm/tests/api_tests/managed_content_file_access.test.js +1 -1
- package/lib/esm/tests/api_tests/managed_content_file_access.test.js.map +1 -1
- package/lib/esm/tests/api_tests/mdi_webhooks.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/mdi_webhooks.test.js +21 -8
- package/lib/esm/tests/api_tests/mdi_webhooks.test.js.map +1 -1
- package/lib/esm/tests/api_tests/nutrition_tracking.test.js +1 -1
- package/lib/esm/tests/api_tests/nutrition_tracking.test.js.map +1 -1
- package/lib/esm/tests/api_tests/openloop_webhooks.test.js +1 -1
- package/lib/esm/tests/api_tests/openloop_webhooks.test.js.map +1 -1
- package/lib/esm/tests/api_tests/programs.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/programs.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/programs.test.js +365 -0
- package/lib/esm/tests/api_tests/programs.test.js.map +1 -0
- package/lib/esm/tests/api_tests/programs_trigger_filters.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/programs_trigger_filters.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/programs_trigger_filters.test.js +290 -0
- package/lib/esm/tests/api_tests/programs_trigger_filters.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.js +1 -1
- package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.js.map +1 -1
- package/lib/esm/tests/api_tests/security/appointment-reschedule-ownership.test.d.ts +42 -0
- package/lib/esm/tests/api_tests/security/appointment-reschedule-ownership.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/appointment-reschedule-ownership.test.js +479 -0
- package/lib/esm/tests/api_tests/security/appointment-reschedule-ownership.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.js +1 -1
- package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.js.map +1 -1
- package/lib/esm/tests/api_tests/security/enduser-ai-summary-trust-gate.test.js +1 -1
- package/lib/esm/tests/api_tests/security/enduser-ai-summary-trust-gate.test.js.map +1 -1
- package/lib/esm/tests/api_tests/security/enduser-cross-create.test.js +1 -1
- package/lib/esm/tests/api_tests/security/enduser-cross-create.test.js.map +1 -1
- package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.js +1 -1
- package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.js.map +1 -1
- package/lib/esm/tests/api_tests/security/file-link-session-confinement.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/security/file-link-session-confinement.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/file-link-session-confinement.test.js +349 -0
- package/lib/esm/tests/api_tests/security/file-link-session-confinement.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.js +3 -3
- package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.js.map +1 -1
- package/lib/esm/tests/api_tests/security/rich-text-answer-sanitized-on-write.test.d.ts +32 -0
- package/lib/esm/tests/api_tests/security/rich-text-answer-sanitized-on-write.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/rich-text-answer-sanitized-on-write.test.js +292 -0
- package/lib/esm/tests/api_tests/security/rich-text-answer-sanitized-on-write.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.js +4 -1
- package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.js.map +1 -1
- package/lib/esm/tests/api_tests/templated_message_date_fields.test.d.ts +3 -0
- package/lib/esm/tests/api_tests/templated_message_date_fields.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/templated_message_date_fields.test.js +198 -0
- package/lib/esm/tests/api_tests/templated_message_date_fields.test.js.map +1 -0
- package/lib/esm/tests/api_tests/templated_message_link_in_href.test.d.ts +3 -0
- package/lib/esm/tests/api_tests/templated_message_link_in_href.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/templated_message_link_in_href.test.js +229 -0
- package/lib/esm/tests/api_tests/templated_message_link_in_href.test.js.map +1 -0
- package/lib/esm/tests/api_tests/templated_message_links.test.d.ts +3 -0
- package/lib/esm/tests/api_tests/templated_message_links.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/templated_message_links.test.js +231 -0
- package/lib/esm/tests/api_tests/templated_message_links.test.js.map +1 -0
- package/lib/esm/tests/api_tests/time_tracks.test.js +1 -1
- package/lib/esm/tests/api_tests/time_tracks.test.js.map +1 -1
- package/lib/esm/tests/api_tests/trigger_contains_matching.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/trigger_contains_matching.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/trigger_contains_matching.test.js +390 -0
- package/lib/esm/tests/api_tests/trigger_contains_matching.test.js.map +1 -0
- package/lib/esm/tests/api_tests/user_logs_restore_deleted.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/user_logs_restore_deleted.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/user_logs_restore_deleted.test.js +466 -0
- package/lib/esm/tests/api_tests/user_logs_restore_deleted.test.js.map +1 -0
- package/lib/esm/tests/api_tests/user_portal_settings.test.js +1 -1
- package/lib/esm/tests/api_tests/user_portal_settings.test.js.map +1 -1
- package/lib/esm/tests/api_tests/validation_behavior_locks.test.d.ts +2 -0
- package/lib/esm/tests/api_tests/validation_behavior_locks.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/validation_behavior_locks.test.js +229 -0
- package/lib/esm/tests/api_tests/validation_behavior_locks.test.js.map +1 -0
- package/lib/esm/tests/api_tests/vital_review_trigger_action.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/vital_review_trigger_action.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/vital_review_trigger_action.test.js +564 -0
- package/lib/esm/tests/api_tests/vital_review_trigger_action.test.js.map +1 -0
- package/lib/esm/tests/public_endpoint_tests.js +3 -2
- package/lib/esm/tests/public_endpoint_tests.js.map +1 -1
- package/lib/esm/tests/setup.d.ts +16 -0
- package/lib/esm/tests/setup.d.ts.map +1 -1
- package/lib/esm/tests/setup.js +53 -7
- package/lib/esm/tests/setup.js.map +1 -1
- package/lib/esm/tests/setup_isolated.d.ts +9 -0
- package/lib/esm/tests/setup_isolated.d.ts.map +1 -1
- package/lib/esm/tests/setup_isolated.js +21 -1
- package/lib/esm/tests/setup_isolated.js.map +1 -1
- package/lib/esm/tests/socket_tests.d.ts.map +1 -1
- package/lib/esm/tests/socket_tests.js +3 -2
- package/lib/esm/tests/socket_tests.js.map +1 -1
- package/lib/esm/tests/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +182 -166
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/esm/tests/unit_tests/trigger_title_partials.test.d.ts +3 -0
- package/lib/esm/tests/unit_tests/trigger_title_partials.test.d.ts.map +1 -0
- package/lib/esm/tests/unit_tests/trigger_title_partials.test.js +115 -0
- package/lib/esm/tests/unit_tests/trigger_title_partials.test.js.map +1 -0
- package/lib/esm/tests/webhooks_tests.js +3 -2
- package/lib/esm/tests/webhooks_tests.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +22 -19
- package/src/sdk.ts +5 -1
- package/src/tests/api_tests/active_patient_count.test.ts +1 -1
- package/src/tests/api_tests/appointment_rescheduled_trigger.test.ts +1 -1
- package/src/tests/api_tests/calendar_event_references_update.test.ts +1 -1
- package/src/tests/api_tests/enduser_cross_access_isolation.test.ts +1 -1
- package/src/tests/api_tests/enduser_login_rate_limits.test.ts +7 -7
- package/src/tests/api_tests/enduser_session_invalidation.test.ts +4 -4
- package/src/tests/api_tests/managed_content_enduser_access.test.ts +1 -1
- package/src/tests/api_tests/managed_content_file_access.test.ts +1 -1
- package/src/tests/api_tests/mdi_webhooks.test.ts +9 -0
- package/src/tests/api_tests/nutrition_tracking.test.ts +1 -1
- package/src/tests/api_tests/openloop_webhooks.test.ts +1 -1
- package/src/tests/api_tests/security/allowed-paths-confinement.test.ts +1 -1
- package/src/tests/api_tests/security/booking-info-idor-token-mint.test.ts +1 -1
- package/src/tests/api_tests/security/enduser-ai-summary-trust-gate.test.ts +1 -1
- package/src/tests/api_tests/security/enduser-cross-create.test.ts +1 -1
- package/src/tests/api_tests/security/enduser-write-restrictions.test.ts +1 -1
- package/src/tests/api_tests/security/file-link-session-confinement.test.ts +291 -0
- package/src/tests/api_tests/security/invite-user-enumeration.test.ts +3 -3
- package/src/tests/api_tests/security/rich-text-answer-sanitized-on-write.test.ts +197 -0
- package/src/tests/api_tests/security/sanitize-user-html-with-iframes.test.ts +4 -1
- package/src/tests/api_tests/templated_message_date_fields.test.ts +146 -0
- package/src/tests/api_tests/templated_message_links.test.ts +192 -0
- package/src/tests/api_tests/time_tracks.test.ts +1 -1
- package/src/tests/api_tests/user_portal_settings.test.ts +1 -1
- package/src/tests/api_tests/validation_behavior_locks.test.ts +204 -0
- package/src/tests/public_endpoint_tests.ts +3 -2
- package/src/tests/setup.ts +43 -7
- package/src/tests/setup_isolated.ts +10 -0
- package/src/tests/socket_tests.ts +3 -2
- package/src/tests/tests.ts +12 -2
- package/src/tests/webhooks_tests.ts +4 -2
- package/test_generated.pdf +0 -0
- package/tsconfig.cjs.json +17 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { dateValidator, dateOptionalOrEmptyStringValidator, dateValidatorOptional, slugValidator, urlValidator } from "@tellescope/validation"
|
|
2
|
+
|
|
3
|
+
// Pins the accept-sets of the validators whose behavior is delegated to the `validator` package, so
|
|
4
|
+
// a dependency upgrade cannot move what the API accepts without a test failing.
|
|
5
|
+
//
|
|
6
|
+
// These assertions describe PRODUCTION — deliberately, including the parts that are wrong. Two of
|
|
7
|
+
// them are: a bare `YYYY-MM-DD` is rejected while an ISO datetime is accepted, and an unparseable
|
|
8
|
+
// string is accepted and persisted as an `Invalid Date`. Both predate this work and both are
|
|
9
|
+
// API-visible across ~135 schema fields, so changing them belongs in its own PR. Pinning them is
|
|
10
|
+
// what makes this file useful: it is proof of how the deployed API behaves, not an aspiration.
|
|
11
|
+
//
|
|
12
|
+
// Why it was needed. Validator 13.11.0's `isDate` was timezone-dependent — its last step compared a
|
|
13
|
+
// UTC-parsed date against a local-time `.getDate()` — so it answered false west of Greenwich and
|
|
14
|
+
// true in UTC. The servers run UTC, so the behavior pinned below is what production has been doing,
|
|
15
|
+
// while the same code on a US developer's machine did the opposite. 13.12.0 fixed that (#2257), and
|
|
16
|
+
// 13.15.35 was verified to return exactly what 13.11.0 returned under UTC, across 26 inputs and four
|
|
17
|
+
// timezones. So every assertion here holds in EVERY timezone — that is the point of the file, and
|
|
18
|
+
// the reason it can be trusted as a statement about production while running on a laptop.
|
|
19
|
+
//
|
|
20
|
+
// The `isSlug` half is different: 13.15.35 genuinely narrowed it (lowercase-only, alphanumeric ends,
|
|
21
|
+
// 1-character minimum), which would have moved the subdomain accept-set. `validation.ts` pins
|
|
22
|
+
// 13.11.0's pattern inline instead, and the checks below are that pattern.
|
|
23
|
+
//
|
|
24
|
+
// The `isURL` half (section 5) is neither: 13.11.0 and 13.15.35 were compared across 37 URL inputs
|
|
25
|
+
// and agreed on every one, so nothing was at risk in that upgrade and nothing needed pinning inline.
|
|
26
|
+
// It is here as a forward guard — webhook destinations are customer-configured and an accept-set that
|
|
27
|
+
// narrows silently breaks live integrations — and because the staging QA asserted this behavior with
|
|
28
|
+
// no test behind it. `isURL` reads no clock, so that section has no timezone caveat.
|
|
29
|
+
//
|
|
30
|
+
// Pure-function test — no Session needed. Runs as part of the main suite and standalone:
|
|
31
|
+
// npm run test:modular -- api_tests/validation_behavior_locks
|
|
32
|
+
// TZ=UTC npm run test:modular -- api_tests/validation_behavior_locks (must give the same result)
|
|
33
|
+
|
|
34
|
+
// Every assertion runs before anything throws, so one run reports the complete diff rather than the
|
|
35
|
+
// first case that happened to trip.
|
|
36
|
+
const failures: string[] = []
|
|
37
|
+
|
|
38
|
+
const accepts = (label: string, validate: (v: any) => any, value: any) => {
|
|
39
|
+
try { validate(value) }
|
|
40
|
+
catch (err: any) { failures.push(`${label}: expected to ACCEPT ${JSON.stringify(value)}, but it was rejected (${err?.message || err})`) }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const rejects = (label: string, validate: (v: any) => any, value: any) => {
|
|
44
|
+
let accepted = false
|
|
45
|
+
try { validate(value); accepted = true }
|
|
46
|
+
catch { /* expected */ }
|
|
47
|
+
if (accepted) failures.push(`${label}: expected to REJECT ${JSON.stringify(value)}, but it was accepted`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const validation_behavior_lock_tests = async () => {
|
|
51
|
+
console.log(`Running validation behavior lock tests (TZ=${process.env.TZ || Intl.DateTimeFormat().resolvedOptions().timeZone})`)
|
|
52
|
+
|
|
53
|
+
const date = dateValidator.validate()
|
|
54
|
+
const dateOptional = dateValidatorOptional.validate()
|
|
55
|
+
const dateOrEmpty = dateOptionalOrEmptyStringValidator.validate()
|
|
56
|
+
|
|
57
|
+
// -----------------------------------------------------------------------------------------------
|
|
58
|
+
// 1. Date fields: ISO datetimes are accepted
|
|
59
|
+
// -----------------------------------------------------------------------------------------------
|
|
60
|
+
// What the SDK sends, since JSON.stringify turns a Date into one of these.
|
|
61
|
+
for (const value of [
|
|
62
|
+
'2024-06-15T14:30:00Z',
|
|
63
|
+
'2024-06-15T00:00:00.000Z',
|
|
64
|
+
'2024-06-15T14:30:00+05:00',
|
|
65
|
+
]) {
|
|
66
|
+
accepts('dateValidator', date, value)
|
|
67
|
+
accepts('dateValidatorOptional', dateOptional, value)
|
|
68
|
+
accepts('dateOptionalOrEmptyStringValidator', dateOrEmpty, value)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Epoch milliseconds round-trip through `new Date()`.
|
|
72
|
+
accepts('dateValidator', date, 1718400000000)
|
|
73
|
+
|
|
74
|
+
// The empty string is the "cleared" value for the two lenient variants only.
|
|
75
|
+
accepts('dateOptionalOrEmptyStringValidator', dateOrEmpty, '')
|
|
76
|
+
rejects('dateValidator', date, '')
|
|
77
|
+
|
|
78
|
+
// -----------------------------------------------------------------------------------------------
|
|
79
|
+
// 2. Date fields: a bare calendar date is REJECTED
|
|
80
|
+
// -----------------------------------------------------------------------------------------------
|
|
81
|
+
// Surprising, and not a typo. `isDate` returns true for these and the check is inverted, so they
|
|
82
|
+
// 400. This is long-standing production behavior; it is pinned, not endorsed. A client sending
|
|
83
|
+
// `"1985-03-12"` to a date field gets an error and must send an ISO datetime instead.
|
|
84
|
+
for (const value of ['1985-03-12', '2024-01-01', '2026-10-01', '2000-02-29', '1999/12/31']) {
|
|
85
|
+
rejects('dateValidator', date, value)
|
|
86
|
+
rejects('dateValidatorOptional', dateOptional, value)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// A real Date object is rejected by the same mechanism (isDate is true for one). Nothing sends a
|
|
90
|
+
// Date over HTTP, so this only reaches internal callers — but the three validators disagree here:
|
|
91
|
+
// the `dateOrEmpty` variant coerces with `.toString()` first, producing "Sat Jun 15 2024 ...",
|
|
92
|
+
// which isDate calls false, so it accepts. Pinned because it is a real inconsistency.
|
|
93
|
+
rejects('dateValidator', date, new Date('2024-06-15T14:30:00Z'))
|
|
94
|
+
rejects('dateValidatorOptional', dateOptional, new Date('2024-06-15T14:30:00Z'))
|
|
95
|
+
accepts('dateOptionalOrEmptyStringValidator', dateOrEmpty, new Date('2024-06-15T14:30:00Z'))
|
|
96
|
+
|
|
97
|
+
// -----------------------------------------------------------------------------------------------
|
|
98
|
+
// 3. Date fields: an unparseable string is ACCEPTED and stored as an Invalid Date
|
|
99
|
+
// -----------------------------------------------------------------------------------------------
|
|
100
|
+
// A data-corruption path, pinned so it is documented and so a future fix is a deliberate, visible
|
|
101
|
+
// change rather than a silent one. `new Date('not a date')` is an Invalid Date, and it is what
|
|
102
|
+
// gets written.
|
|
103
|
+
for (const value of ['not a date', 'hello world', 'tomorrow', '??']) {
|
|
104
|
+
accepts('dateValidator', date, value)
|
|
105
|
+
accepts('dateValidatorOptional', dateOptional, value)
|
|
106
|
+
accepts('dateOptionalOrEmptyStringValidator', dateOrEmpty, value)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// -----------------------------------------------------------------------------------------------
|
|
110
|
+
// 4. Organization subdomain
|
|
111
|
+
// -----------------------------------------------------------------------------------------------
|
|
112
|
+
const slug = slugValidator.validate()
|
|
113
|
+
|
|
114
|
+
// Valid, and must stay valid — 13.15.35's isSlug would reject the mixed-case ones.
|
|
115
|
+
for (const value of ['acme', 'acme-health', 'tellescope-demo', 'demo_org_1', 'Acme', 'My-Org', 'TellescopeDemo', 'abc']) {
|
|
116
|
+
accepts('slugValidator', slug, value)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Also accepted today, though none of these are valid DNS labels. Pinned so the upgrade does not
|
|
120
|
+
// quietly change them; tightening is a separate decision.
|
|
121
|
+
for (const value of ['acme.health', 'org/sub', 'my@org', 'org?x=1']) {
|
|
122
|
+
accepts('slugValidator', slug, value)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Rejected today — note 13.15.35's isSlug would ACCEPT the 1- and 2-character cases.
|
|
126
|
+
for (const value of ['a', 'ab', 'my--org', 'my__org', '-acme', 'acme-', 'org name']) {
|
|
127
|
+
rejects('slugValidator', slug, value)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// -----------------------------------------------------------------------------------------------
|
|
131
|
+
// 5. Webhook and other URL fields
|
|
132
|
+
// -----------------------------------------------------------------------------------------------
|
|
133
|
+
// `urlValidator` is a thin `isURL` passthrough behind `build_validator`, used for webhook
|
|
134
|
+
// subscriptions (schema `webhooks.url`) among others. It is a SYNTAX check only — refusing internal
|
|
135
|
+
// destinations is a separate layer (`api/modules/outbound_url.ts`), which is why several things
|
|
136
|
+
// accepted here are refused at delivery time.
|
|
137
|
+
const url = urlValidator.validate()
|
|
138
|
+
|
|
139
|
+
// Ports and query strings, the cases the staging QA calls out.
|
|
140
|
+
for (const value of [
|
|
141
|
+
'https://example.com:8443/hook',
|
|
142
|
+
'https://example.com/hook?a=1&b=two',
|
|
143
|
+
'https://example.com:8443/hook?a=1',
|
|
144
|
+
'https://example.com/a?b=c&d=%7B%22x%22%3A1%7D', // percent-encoded JSON in the query
|
|
145
|
+
'https://example.com:443/hook',
|
|
146
|
+
'https://example.com:8443', // port, no path
|
|
147
|
+
'https://example.com/hook#frag',
|
|
148
|
+
'HTTPS://EXAMPLE.COM/Hook',
|
|
149
|
+
'https://[::1]:8443/hook',
|
|
150
|
+
]) {
|
|
151
|
+
accepts('urlValidator', url, value)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Accepted, but quirks rather than intent — pinned like the date quirks above so that tightening any
|
|
155
|
+
// of them is a deliberate, visible change.
|
|
156
|
+
// - schemeless: values of this shape exist in the webhooks collection today (outbound_url.ts:213)
|
|
157
|
+
// - ftp: isURL's default protocol list is http/https/ftp
|
|
158
|
+
// - the last two are refused by assertPublicHttpUrl at delivery, not here
|
|
159
|
+
for (const value of [
|
|
160
|
+
'api.customer.com/hook',
|
|
161
|
+
'ftp://example.com/x',
|
|
162
|
+
'http://10.0.0.1/hook',
|
|
163
|
+
'https://user:pass@example.com/hook',
|
|
164
|
+
]) {
|
|
165
|
+
accepts('urlValidator', url, value)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Rejected. `localhost` fails isURL's require_tld, which defaults on — a local webhook receiver has
|
|
169
|
+
// to be configured as 127.0.0.1, and that is why the SSRF suite binds loopback by address.
|
|
170
|
+
for (const value of [
|
|
171
|
+
'http://localhost:8080/hook',
|
|
172
|
+
'localhost:8080/hook',
|
|
173
|
+
'https://example.com:65536/hook',
|
|
174
|
+
'https://example.com:0/hook',
|
|
175
|
+
'https://example.com:abc/x',
|
|
176
|
+
'javascript:alert(1)',
|
|
177
|
+
'file:///etc/passwd',
|
|
178
|
+
'mailto:a@b.com',
|
|
179
|
+
'//example.com/hook',
|
|
180
|
+
'not a url',
|
|
181
|
+
'https://example.com/hook with space',
|
|
182
|
+
'https://example.com./hook', // trailing dot
|
|
183
|
+
]) {
|
|
184
|
+
rejects('urlValidator', url, value)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Non-string and absent values. The empty string is rejected by build_validator's non-empty rule
|
|
188
|
+
// rather than by isURL, so it is pinned separately from the malformed strings above.
|
|
189
|
+
rejects('urlValidator', url, '')
|
|
190
|
+
rejects('urlValidator', url, 123)
|
|
191
|
+
rejects('urlValidator', url, null)
|
|
192
|
+
rejects('urlValidator', url, undefined)
|
|
193
|
+
|
|
194
|
+
if (failures.length) {
|
|
195
|
+
throw new Error(`${failures.length} validation behavior lock(s) broken:\n - ` + failures.join('\n - '))
|
|
196
|
+
}
|
|
197
|
+
console.log("✅ validation behavior lock tests passed")
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (require.main === module) {
|
|
201
|
+
validation_behavior_lock_tests()
|
|
202
|
+
.then(() => { console.log("✅ suite completed"); process.exit(0) })
|
|
203
|
+
.catch((err) => { console.error("❌ suite failed:", err); process.exit(1) })
|
|
204
|
+
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "@tellescope/utilities"
|
|
10
10
|
import { Session, /* APIQuery */ } from "../sdk"
|
|
11
11
|
import { PublicEndpoints } from "../public"
|
|
12
|
+
import { reset_test_tenant } from "./setup"
|
|
12
13
|
|
|
13
14
|
const host = process.env.API_URL || 'http://localhost:8080'
|
|
14
15
|
const [email, password] = [process.env.TEST_EMAIL, process.env.TEST_PASSWORD]
|
|
@@ -18,7 +19,7 @@ const sdkPub = PublicEndpoints({ host })
|
|
|
18
19
|
|
|
19
20
|
if (!(email && password)) {
|
|
20
21
|
console.error("Set TEST_EMAIL and TEST_PASSWORD")
|
|
21
|
-
process.exit()
|
|
22
|
+
process.exit(1) // 1, not 0: an unconfigured run must not report success
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
const enduser_login_tests = async () => {
|
|
@@ -59,7 +60,7 @@ const enduser_login_tests = async () => {
|
|
|
59
60
|
|
|
60
61
|
try {
|
|
61
62
|
await sdk.authenticate(email, password)
|
|
62
|
-
await sdk
|
|
63
|
+
await reset_test_tenant(sdk)
|
|
63
64
|
|
|
64
65
|
await enduser_login_tests()
|
|
65
66
|
} catch(err) {
|
package/src/tests/setup.ts
CHANGED
|
@@ -9,19 +9,55 @@ import {
|
|
|
9
9
|
assert,
|
|
10
10
|
} from "@tellescope/testing"
|
|
11
11
|
|
|
12
|
+
import { test_support_request } from "./setup_isolated"
|
|
13
|
+
|
|
12
14
|
const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
13
15
|
const [email, password] = [process.env.TEST_EMAIL, process.env.TEST_PASSWORD]
|
|
14
16
|
const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.env.NON_ADMIN_PASSWORD]
|
|
15
|
-
const businessId = '60398b1131a295e64f084ff6'
|
|
16
17
|
|
|
18
|
+
/** The hand-seeded shared fixture this suite was written against; still the default. */
|
|
19
|
+
export const LEGACY_TEST_BUSINESS_ID = '60398b1131a295e64f084ff6'
|
|
20
|
+
const businessId = process.env.TEST_BUSINESS_ID || LEGACY_TEST_BUSINESS_ID
|
|
21
|
+
// The legacy fixture's local API key. `npm run bootstrap` writes a provisioned tenant's key to
|
|
22
|
+
// TEST_API_KEY, so a fresh checkout does not need a copy of anyone's database.
|
|
23
|
+
const apiKey = process.env.TEST_API_KEY || '3n5q0SCBT_iUvZz-b9BJtX7o7HQUVJ9v132PgHJNJsg.'
|
|
24
|
+
|
|
25
|
+
// exit 1, not 0: a bare process.exit() reports success, which turns "nobody configured the
|
|
26
|
+
// credentials" into a silently passing test run
|
|
17
27
|
if (!(email && password)) {
|
|
18
28
|
console.error("Set TEST_EMAIL and TEST_PASSWORD")
|
|
19
|
-
process.exit()
|
|
29
|
+
process.exit(1)
|
|
20
30
|
}
|
|
21
31
|
|
|
22
32
|
if (!(nonAdminEmail && nonAdminPassword)) {
|
|
23
33
|
console.error("Set NON_ADMIN_EMAIL and NON_ADMIN_PASSWORD")
|
|
24
|
-
process.exit()
|
|
34
|
+
process.exit(1)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Per-run database reset for whichever tenant the fixture is pointed at.
|
|
39
|
+
*
|
|
40
|
+
* The legacy path is `sdk.reset_db()` (POST /reset-demo): it deletes a HARDCODED businessId's records
|
|
41
|
+
* plus six global throttle namespaces, and requires a session whose email is in the API's
|
|
42
|
+
* ADMIN_EMAILS allowlist — so it does nothing useful for, and is not even authorized for, a tenant
|
|
43
|
+
* provisioned by /test-support. That tenant resets through /test-support/reset-tenant instead, which
|
|
44
|
+
* is scoped to its own businessId and keeps the org, users, API keys and roles the caller is holding.
|
|
45
|
+
*
|
|
46
|
+
* `clearGlobalThrottles` is requested here (and honored only under LOCAL) because this is the shared
|
|
47
|
+
* fixture: setup_tests deliberately exhausts login throttles and must clear them, exactly as
|
|
48
|
+
* reset_db did. Isolated tests use `reset_isolated_tenant`, which never touches global state.
|
|
49
|
+
*/
|
|
50
|
+
export const reset_test_tenant = async (sdk: Session) => {
|
|
51
|
+
const id = sdk.userInfo?.businessId || businessId
|
|
52
|
+
const provisioned = process.env.TEST_TENANT_PROVISIONED === 'true' || id !== LEGACY_TEST_BUSINESS_ID
|
|
53
|
+
if (!provisioned) { await sdk.reset_db(); return }
|
|
54
|
+
|
|
55
|
+
const { status, body } = await test_support_request('/reset-tenant', {
|
|
56
|
+
businessId: id, clearGlobalThrottles: true,
|
|
57
|
+
})
|
|
58
|
+
if (status !== 200) {
|
|
59
|
+
throw new Error(`test-support /reset-tenant failed (${status}): ${JSON.stringify(body)}`)
|
|
60
|
+
}
|
|
25
61
|
}
|
|
26
62
|
|
|
27
63
|
const passOnAnyResult = { shouldError: false, onResult: () => true }
|
|
@@ -49,7 +85,7 @@ export const setup_tests = async (sdk: Session, sdkNonAdmin: Session) => {
|
|
|
49
85
|
|
|
50
86
|
await async_test(
|
|
51
87
|
'test_authenticated (with API Key)',
|
|
52
|
-
(new Session({ host, apiKey
|
|
88
|
+
(new Session({ host, apiKey })).test_authenticated,
|
|
53
89
|
{ expectedResult: 'Authenticated!' }
|
|
54
90
|
)
|
|
55
91
|
|
|
@@ -71,7 +107,7 @@ export const setup_tests = async (sdk: Session, sdkNonAdmin: Session) => {
|
|
|
71
107
|
passOnAnyResult
|
|
72
108
|
)
|
|
73
109
|
|
|
74
|
-
const badEnduserSDK = new EnduserSession({ host, businessId });
|
|
110
|
+
const badEnduserSDK = new EnduserSession({ host, businessId: sdk.userInfo.businessId });
|
|
75
111
|
await badEnduserSDK.authenticate('bademail@tellescope.com', 'badpassword').catch(console.error)
|
|
76
112
|
await badEnduserSDK.authenticate('bademail@tellescope.com', 'badpassword').catch(console.error)
|
|
77
113
|
await badEnduserSDK.authenticate('bademail@tellescope.com', 'badpassword').catch(console.error)
|
|
@@ -89,7 +125,7 @@ export const setup_tests = async (sdk: Session, sdkNonAdmin: Session) => {
|
|
|
89
125
|
)
|
|
90
126
|
|
|
91
127
|
// prevent additional login throttling
|
|
92
|
-
await async_test('
|
|
128
|
+
await async_test('reset_test_tenant', () => reset_test_tenant(sdk), passOnVoid)
|
|
93
129
|
|
|
94
130
|
await sdk.logout()
|
|
95
131
|
await async_test<string, string>('test_authenticated - (logout invalidates jwt)', sdk.test_authenticated, { shouldError: true, onError: e => e === 'Unauthenticated' })
|
|
@@ -148,7 +184,7 @@ export const setup_tests = async (sdk: Session, sdkNonAdmin: Session) => {
|
|
|
148
184
|
await sdkNonAdmin.authenticate(nonAdminEmail, nonAdminPassword)
|
|
149
185
|
|
|
150
186
|
// may do some stuff in background after returning
|
|
151
|
-
await async_test('
|
|
187
|
+
await async_test('reset_test_tenant', () => reset_test_tenant(sdk), passOnVoid)
|
|
152
188
|
await wait(undefined, 250)
|
|
153
189
|
|
|
154
190
|
// Prevent test-triggered notifications (e.g. timeTrackRejected, inbound-message
|
|
@@ -103,6 +103,16 @@ export const set_email_verification_code = async (email: string, code: string) =
|
|
|
103
103
|
post('/set-email-verification-code', { email, code })
|
|
104
104
|
)
|
|
105
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Empties a provisioned tenant's records while keeping the tenant, its users, API keys and roles —
|
|
108
|
+
* for a test that wants a clean slate between phases without re-provisioning.
|
|
109
|
+
*
|
|
110
|
+
* Records only: the shared login/IP throttle namespaces are NOT cleared, so this stays safe to call
|
|
111
|
+
* while another suite is running. (setup.ts's `reset_test_tenant` does ask for those, because the
|
|
112
|
+
* shared fixture deliberately exhausts login throttles.)
|
|
113
|
+
*/
|
|
114
|
+
export const reset_isolated_tenant = async (businessId: string) => post('/reset-tenant', { businessId })
|
|
115
|
+
|
|
106
116
|
/** Raw access, for tests that need to assert on the response of a rejected call. */
|
|
107
117
|
export const test_support_request = async (path: string, body: object) => {
|
|
108
118
|
const r = await axios.request({
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "@tellescope/types-utilities"
|
|
17
17
|
import { EnduserSession } from "../enduser"
|
|
18
18
|
import { Session, /* APIQuery */ } from "../sdk"
|
|
19
|
+
import { reset_test_tenant } from "./setup"
|
|
19
20
|
import { PLACEHOLDER_ID } from "@tellescope/constants"
|
|
20
21
|
import { UserSession } from "@tellescope/types-models"
|
|
21
22
|
|
|
@@ -29,7 +30,7 @@ const host = process.env.API_URL || 'http://localhost:8080'
|
|
|
29
30
|
const [email, password] = [process.env.TEST_EMAIL, process.env.TEST_PASSWORD]
|
|
30
31
|
const [email2, password2] = [process.env.TEST_EMAIL_2, process.env.TEST_PASSWORD_2]
|
|
31
32
|
const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.env.NON_ADMIN_PASSWORD]
|
|
32
|
-
const businessId = '60398b1131a295e64f084ff6'
|
|
33
|
+
const businessId = process.env.TEST_BUSINESS_ID || '60398b1131a295e64f084ff6'
|
|
33
34
|
|
|
34
35
|
const subUserEmail = process.env.SUB_EMAIL
|
|
35
36
|
const otherSubUserEmail = process.env.OTHER_SUB_EMAIL
|
|
@@ -487,7 +488,7 @@ const cleanup_cache = () => {
|
|
|
487
488
|
|
|
488
489
|
try {
|
|
489
490
|
await user1.authenticate(email, password)
|
|
490
|
-
await user1
|
|
491
|
+
await reset_test_tenant(user1)
|
|
491
492
|
|
|
492
493
|
await Promise.all([
|
|
493
494
|
user2.authenticate(email2, password2), // generate authToken + socket connection for API keyj
|
package/src/tests/tests.ts
CHANGED
|
@@ -123,6 +123,9 @@ import { register_business_id_injection_tests } from "./api_tests/security/regis
|
|
|
123
123
|
import { handle_incoming_communication_cross_tenant_tests } from "./api_tests/security/handle-incoming-communication-cross-tenant.test";
|
|
124
124
|
import { sanitize_user_html_xss_tests } from "./api_tests/security/sanitize-user-html.test";
|
|
125
125
|
import { sanitize_user_html_with_iframes_tests } from "./api_tests/security/sanitize-user-html-with-iframes.test";
|
|
126
|
+
import { validation_behavior_lock_tests } from "./api_tests/validation_behavior_locks.test";
|
|
127
|
+
import { templated_message_date_field_tests } from "./api_tests/templated_message_date_fields.test";
|
|
128
|
+
import { templated_message_link_tests } from "./api_tests/templated_message_links.test";
|
|
126
129
|
import { prototype_pollution_tests } from "./api_tests/security/prototype-pollution.test";
|
|
127
130
|
import { enduser_cross_create_tests } from "./api_tests/security/enduser-cross-create.test";
|
|
128
131
|
import { globalunique_leak_tests } from "./api_tests/security/globalunique-conflict-redaction.test";
|
|
@@ -140,6 +143,7 @@ import { automated_actions_process_gate_tests } from "./api_tests/security/autom
|
|
|
140
143
|
import { schema_adminonly_enforcement_tests } from "./api_tests/security/schema-adminonly-enforcement.test";
|
|
141
144
|
import { startlinktoken_escalation_tests } from "./api_tests/security/startlinktoken-enduser-staff-escalation.test";
|
|
142
145
|
import { form_logic_js_execution_checks } from "./api_tests/security/form-logic-js-execution.test";
|
|
146
|
+
import { rich_text_answer_sanitized_on_write_checks } from "./api_tests/security/rich-text-answer-sanitized-on-write.test";
|
|
143
147
|
import { bulk_assignment_tests } from "./api_tests/bulk_assignment.test";
|
|
144
148
|
import { tickets_bulk_assign_care_team_tests } from "./api_tests/tickets_bulk_assign_care_team.test";
|
|
145
149
|
import { managed_content_enduser_access_tests } from "./api_tests/managed_content_enduser_access.test";
|
|
@@ -163,6 +167,7 @@ import { organization_signup_checks } from "./api_tests/organization_signup.test
|
|
|
163
167
|
import { add_to_journey_foreign_enduserid_checks } from "./api_tests/security/add-to-journey-foreign-enduserid.test";
|
|
164
168
|
import { tickets_bulk_assign_from_queue_checks } from "./api_tests/tickets_bulk_assign_from_queue.test";
|
|
165
169
|
import { enduser_observations_auto_review_checks } from "./api_tests/enduser_observations_auto_review.test";
|
|
170
|
+
import { file_link_session_confinement_checks } from "./api_tests/security/file-link-session-confinement.test";
|
|
166
171
|
import { run_isolated_in_parallel } from "./setup_isolated";
|
|
167
172
|
import { elation_user_id_tests } from "./api_tests/elation_user_id.test";
|
|
168
173
|
import { organization_settings_duplicates_tests } from "./api_tests/organization_settings_duplicates.test";
|
|
@@ -204,7 +209,7 @@ const otherSubUserEmail = process.env.OTHER_SUB_EMAIL
|
|
|
204
209
|
const subSubUserEmail = process.env.SUB_SUB_EMAIL
|
|
205
210
|
|
|
206
211
|
const userId = '60398b0231a295e64f084fd9'
|
|
207
|
-
const businessId = '60398b1131a295e64f084ff6'
|
|
212
|
+
const businessId = process.env.TEST_BUSINESS_ID || '60398b1131a295e64f084ff6'
|
|
208
213
|
|
|
209
214
|
// const example_SDK_usage = async () => {
|
|
210
215
|
// // initialize SDK and authenticate a user
|
|
@@ -255,7 +260,7 @@ const enduserSDKDifferentBusinessId = new EnduserSession({ host, businessId: '80
|
|
|
255
260
|
|
|
256
261
|
if (!(email && mfaEmail && mfaPassword && subUserEmail && otherSubUserEmail && subSubUserEmail && password && email2 && password2 && nonAdminEmail && nonAdminPassword)) {
|
|
257
262
|
console.error("Set TEST_EMAIL and TEST_PASSWORD")
|
|
258
|
-
process.exit()
|
|
263
|
+
process.exit(1) // 1, not 0: an unconfigured run must not report success
|
|
259
264
|
}
|
|
260
265
|
|
|
261
266
|
const recordNotFound = { shouldError: true, onError: (e: { message: string }) => e.message === 'Could not find a record for the given id' }
|
|
@@ -15405,6 +15410,8 @@ const ip_address_form_tests = async () => {
|
|
|
15405
15410
|
{ name: 'Tickets bulk assign from queue', run: tickets_bulk_assign_from_queue_checks },
|
|
15406
15411
|
{ name: 'Vital auto-review on create', run: enduser_observations_auto_review_checks },
|
|
15407
15412
|
{ name: '$JS in stored conditional logic', run: form_logic_js_execution_checks },
|
|
15413
|
+
{ name: 'Rich Text answers sanitized on write', run: rich_text_answer_sanitized_on_write_checks },
|
|
15414
|
+
{ name: 'Shared file link session confinement', run: file_link_session_confinement_checks },
|
|
15408
15415
|
])
|
|
15409
15416
|
await embeddables_auth_token_tests({ sdk, sdkNonAdmin })
|
|
15410
15417
|
await proxy_image_ssrf_tests({ sdk, sdkNonAdmin })
|
|
@@ -15450,6 +15457,9 @@ const ip_address_form_tests = async () => {
|
|
|
15450
15457
|
await self_admin_role_assignment_tests({ sdk, sdkNonAdmin })
|
|
15451
15458
|
await sanitize_user_html_xss_tests()
|
|
15452
15459
|
await sanitize_user_html_with_iframes_tests()
|
|
15460
|
+
await validation_behavior_lock_tests()
|
|
15461
|
+
await templated_message_date_field_tests()
|
|
15462
|
+
await templated_message_link_tests()
|
|
15453
15463
|
await prototype_pollution_tests()
|
|
15454
15464
|
await account_switcher_tests({ sdk, sdkNonAdmin })
|
|
15455
15465
|
await totp_mfa_tests({ sdk, sdkNonAdmin })
|
|
@@ -31,7 +31,9 @@ const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.
|
|
|
31
31
|
const subUserEmail = process.env.SUB_EMAIL
|
|
32
32
|
|
|
33
33
|
const host = process.env.API_URL || 'http://localhost:8080'
|
|
34
|
-
|
|
34
|
+
import { reset_test_tenant } from "./setup"
|
|
35
|
+
|
|
36
|
+
const businessId = process.env.TEST_BUSINESS_ID || '60398b1131a295e64f084ff6'
|
|
35
37
|
const enduserSDK = new EnduserSession({ host, businessId })
|
|
36
38
|
|
|
37
39
|
if (!(email && subUserEmail && password && email2 && password2 && nonAdminEmail && nonAdminPassword)) {
|
|
@@ -754,7 +756,7 @@ const run_tests = async () => {
|
|
|
754
756
|
log_header("Webhooks Tests")
|
|
755
757
|
await sdk.authenticate(email, password)
|
|
756
758
|
await sdkSub.authenticate(subUserEmail, password)
|
|
757
|
-
await sdk
|
|
759
|
+
await reset_test_tenant(sdk)
|
|
758
760
|
await nonAdminSdk.authenticate(nonAdminEmail, nonAdminPassword)
|
|
759
761
|
|
|
760
762
|
await async_test(
|
package/test_generated.pdf
CHANGED
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
// CommonJS build (lib/cjs, also where the runnable tests land); see constants/tsconfig.cjs.json.
|
|
3
|
+
"extends": "./tsconfig.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"outDir": "lib/cjs",
|
|
7
|
+
"tsBuildInfoFile": "lib/cjs/tsconfig.cjs.tsbuildinfo"
|
|
8
|
+
},
|
|
9
|
+
"references": [
|
|
10
|
+
{ "path": "../constants/tsconfig.cjs.json" },
|
|
11
|
+
{ "path": "../schema/tsconfig.cjs.json" },
|
|
12
|
+
{ "path": "../testing/tsconfig.cjs.json" },
|
|
13
|
+
{ "path": "../types-client/tsconfig.cjs.json" },
|
|
14
|
+
{ "path": "../utilities/tsconfig.cjs.json" },
|
|
15
|
+
{ "path": "../validation/tsconfig.cjs.json" }
|
|
16
|
+
]
|
|
17
|
+
}
|