@tellescope/schema 1.253.1 → 1.254.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/src/schema.ts CHANGED
@@ -90,6 +90,7 @@ import {
90
90
  AIDecisionAutomationAction,
91
91
  AutomationAction,
92
92
  TimeTrackTimestamp,
93
+ TimeTrackReviewHistoryItem,
93
94
  BelugaPharmacyMapping,
94
95
  BelugaAutomationMappingEntry,
95
96
  BelugaUpdateVisitPatientPreferenceItem,
@@ -172,6 +173,7 @@ import {
172
173
  fileSizeValidator,
173
174
  meetingStatusValidator,
174
175
  listOfAttendeesValidator,
176
+ listOfVideoCallParticipantEventsValidator,
175
177
  meetingInfoValidator,
176
178
  listOfUserIndentitiesValidator,
177
179
  meetingsListValidator,
@@ -287,6 +289,7 @@ import {
287
289
  userCallRoutingBehaviorValidator,
288
290
  userUIRestrictionsValidator,
289
291
  userFieldRedactionsValidator,
292
+ portalSchemaRestrictionsValidator,
290
293
  externalChatGPTMessagesValidator,
291
294
  enduserProfileViewBlocksValidator,
292
295
  customDashboardBlocksValidator,
@@ -2644,6 +2647,7 @@ export const schema: SchemaV1 = build_schema({
2644
2647
  info: {},
2645
2648
  fields: {
2646
2649
  ...BuiltInFields,
2650
+ accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
2647
2651
  archivedAt: { validator: dateOptionalOrEmptyStringValidator },
2648
2652
  title: {
2649
2653
  validator: stringValidator100,
@@ -3486,7 +3490,9 @@ export const schema: SchemaV1 = build_schema({
3486
3490
  {
3487
3491
  explanation: "Only admin users can update tags when accessTags is enabled",
3488
3492
  evaluate: ({ _id }, _, session, method, { updates } ) => {
3489
- if (session.type === 'user' && !session.eat) return // accessTags is not enabled
3493
+ // editing a user's tags is a privilege-escalation vector whenever tags gate visibility:
3494
+ // enduser access tags (eat) OR resource access tags (erat). Skip only when neither is enabled.
3495
+ if (session.type === 'user' && !session.eat && !(session as UserSession)?.erat) return // neither access-tags feature enabled
3490
3496
  if ((session as UserSession)?.roles?.includes('Admin')) return
3491
3497
  if (method === 'create') return
3492
3498
  if (!updates?.tags) return
@@ -4182,7 +4188,8 @@ export const schema: SchemaV1 = build_schema({
4182
4188
  },
4183
4189
  },
4184
4190
  fields: {
4185
- ...BuiltInFields,
4191
+ ...BuiltInFields,
4192
+ accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
4186
4193
  archivedAt: { validator: dateOptionalOrEmptyStringValidator },
4187
4194
  mmsAttachmentURLs: { validator: listOfUniqueStringsValidatorEmptyOk },
4188
4195
  title: {
@@ -4230,7 +4237,8 @@ export const schema: SchemaV1 = build_schema({
4230
4237
  defaultActions: { read: {}, readMany: {}, update: {}, delete: {} },
4231
4238
  enduserActions: { prepare_file_upload: {}, confirm_file_upload: {}, file_download_URL: {}, read: {}, readMany: {}, delete: {}, update: { } /* allow to hide from client side */ },
4232
4239
  fields: {
4233
- ...BuiltInFields,
4240
+ ...BuiltInFields,
4241
+ accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
4234
4242
  source: { validator: stringValidator100 },
4235
4243
  tags: { validator: listOfStringsValidatorUniqueOptionalOrEmptyOkay },
4236
4244
  name: {
@@ -4499,7 +4507,7 @@ export const schema: SchemaV1 = build_schema({
4499
4507
  },
4500
4508
  enduserActions: { create: {}, read: {}, readMany: {} },
4501
4509
  fields: {
4502
- ...BuiltInFields,
4510
+ ...BuiltInFields,
4503
4511
  title: {
4504
4512
  validator: stringValidator1000,
4505
4513
  required: true,
@@ -4824,6 +4832,7 @@ export const schema: SchemaV1 = build_schema({
4824
4832
  },
4825
4833
  fields: {
4826
4834
  ...BuiltInFields,
4835
+ accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
4827
4836
  showByUserTags: { validator: listOfStringsValidatorOptionalOrEmptyOk },
4828
4837
  belugaVisitType: { validator: stringValidator },
4829
4838
  belugaVerificationId: { validator: stringValidator },
@@ -5945,6 +5954,7 @@ export const schema: SchemaV1 = build_schema({
5945
5954
  meetingId: { validator: mongoIdStringValidator, readonly: true },
5946
5955
  bookingPageId: { validator: mongoIdStringValidator }, // allows rescheduling via booking page
5947
5956
  meetingStatus: { validator: meetingStatusValidator },
5957
+ videoCallAttendance: { validator: listOfVideoCallParticipantEventsValidator, readonly: true },
5948
5958
  attachments: { validator: listOfGenericAttachmentsValidator },
5949
5959
  cancelledAt: { validator: dateOptionalOrEmptyStringValidator },
5950
5960
  rescheduledAt: { validator: dateOptionalOrEmptyStringValidator },
@@ -6079,7 +6089,8 @@ export const schema: SchemaV1 = build_schema({
6079
6089
  customActions: {},
6080
6090
  enduserActions: { read: {}, readMany: {} },
6081
6091
  fields: {
6082
- ...BuiltInFields,
6092
+ ...BuiltInFields,
6093
+ accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
6083
6094
  dontSyncToElation: { validator: booleanValidator },
6084
6095
  sendIcsEmail: { validator: booleanValidator },
6085
6096
  createAndBookAthenaSlot: { validator: booleanValidator },
@@ -6607,7 +6618,8 @@ export const schema: SchemaV1 = build_schema({
6607
6618
  search: {},
6608
6619
  },
6609
6620
  fields: {
6610
- ...BuiltInFields,
6621
+ ...BuiltInFields,
6622
+ accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
6611
6623
  slug: { validator: stringValidator250 },
6612
6624
  title: {
6613
6625
  validator: stringValidator1000,
@@ -7623,6 +7635,12 @@ export const schema: SchemaV1 = build_schema({
7623
7635
  },
7624
7636
  uiRestrictions: { validator: userUIRestrictionsValidator },
7625
7637
  fieldRedactions: { validator: userFieldRedactionsValidator },
7638
+ portalSchemaRestrictions: {
7639
+ validator: portalSchemaRestrictionsValidator,
7640
+ initializer: () => ({ disableEditContent: true, disableEditTheming: true, disableEditSnippets: true }),
7641
+ },
7642
+ color: { validator: stringValidator1000 },
7643
+ description: { validator: stringValidator1000Optional },
7626
7644
  }
7627
7645
  },
7628
7646
  appointment_booking_pages: {
@@ -7666,7 +7684,8 @@ export const schema: SchemaV1 = build_schema({
7666
7684
  read: {}, readMany: {}, validate_access_token: {},
7667
7685
  },
7668
7686
  fields: {
7669
- ...BuiltInFields,
7687
+ ...BuiltInFields,
7688
+ accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
7670
7689
  dontRestrictRescheduleToOriginalHost: { validator: booleanValidator },
7671
7690
  gtmTag: { validator: stringValidator100EscapeHTML },
7672
7691
  archivedAt: { validator: dateOptionalOrEmptyStringValidator },
@@ -8503,7 +8522,8 @@ If a voicemail is left, it is indicated by recordingURI, transcription, or recor
8503
8522
  },
8504
8523
  enduserActions: {},
8505
8524
  fields: {
8506
- ...BuiltInFields,
8525
+ ...BuiltInFields,
8526
+ accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
8507
8527
  title: {
8508
8528
  validator: stringValidator100,
8509
8529
  required: true,
@@ -8858,7 +8878,8 @@ If a voicemail is left, it is indicated by recordingURI, transcription, or recor
8858
8878
  customActions: {},
8859
8879
  enduserActions: {},
8860
8880
  fields: {
8861
- ...BuiltInFields,
8881
+ ...BuiltInFields,
8882
+ accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
8862
8883
  title: {
8863
8884
  validator: stringValidator,
8864
8885
  required: true,
@@ -9040,14 +9061,33 @@ If a voicemail is left, it is indicated by recordingURI, transcription, or recor
9040
9061
  }
9041
9062
  },
9042
9063
  {
9043
- explanation: "Locked time tracks only allow review field updates",
9044
- evaluate: (_v, _deps, _session, method, { original, updates }) => {
9064
+ explanation: "Locked time tracks only allow review field updates, or owner resubmission of rejected entries",
9065
+ evaluate: (_v, _deps, session, method, { original, updates }) => {
9045
9066
  if (method !== 'update') return
9046
9067
  const orig = original as any as TimeTrack | undefined
9047
9068
  if (!orig?.lockedAt) return
9069
+
9070
+ const u = updates as any as Partial<TimeTrack> | undefined
9048
9071
  const reviewFields = ['reviewedAt', 'reviewedByUserId', 'reviewApproved', 'reviewNote']
9049
9072
  const nonReviewFields = Object.keys(updates || {}).filter(k => !reviewFields.includes(k))
9050
- if (nonReviewFields.length > 0) return `Time track is locked. Only review fields (${reviewFields.join(', ')}) can be updated.`
9073
+ if (nonReviewFields.length === 0) return // pure review update unchanged behavior
9074
+
9075
+ const isRejected = !!orig.reviewedAt && orig.reviewApproved === false
9076
+ const resubmitFields = [
9077
+ ...reviewFields,
9078
+ 'correctedAt', 'correctedByUserId', 'correctionNote',
9079
+ 'originalTotalDurationInMS', 'totalDurationInMS',
9080
+ 'lockedAt', 'lockedByUserId',
9081
+ ]
9082
+ const disallowed = Object.keys(updates || {}).filter(k => !resubmitFields.includes(k))
9083
+
9084
+ if (isRejected && session.id === orig.userId && disallowed.length === 0) {
9085
+ if (u?.reviewedAt !== '') return "Resubmitting a rejected time track requires clearing reviewedAt (set to '')"
9086
+ if (u?.reviewApproved === true) return "Cannot approve your own time track during resubmission"
9087
+ return // valid resubmit — entry returns to Pending
9088
+ }
9089
+
9090
+ return `Time track is locked. Only review fields (${reviewFields.join(', ')}) can be updated.`
9051
9091
  }
9052
9092
  },
9053
9093
  {
@@ -9132,6 +9172,19 @@ If a voicemail is left, it is indicated by recordingURI, transcription, or recor
9132
9172
  reviewNote: { validator: stringValidator1000Optional },
9133
9173
  lockedAt: { validator: dateValidatorOptional },
9134
9174
  lockedByUserId: { validator: mongoIdStringOptional },
9175
+ // server-appended on resubmission of a rejected entry (see routing.ts update handler)
9176
+ // note: reviewApproved remains false after resubmit (booleans can't be cleared to '') — status logic must key off reviewedAt
9177
+ reviewHistory: {
9178
+ validator: listValidatorOptionalOrEmptyOk(objectValidator<TimeTrackReviewHistoryItem>({
9179
+ reviewedAt: dateValidator,
9180
+ reviewedByUserId: mongoIdStringOptional,
9181
+ reviewApproved: booleanValidatorOptional,
9182
+ reviewNote: stringValidator1000Optional,
9183
+ resubmittedAt: dateValidatorOptional,
9184
+ resubmittedByUserId: mongoIdStringOptional,
9185
+ })),
9186
+ readonly: true, // server-appended only — clients can read, never write
9187
+ },
9135
9188
  },
9136
9189
  },
9137
9190
  ticket_queues: {
@@ -9744,7 +9797,7 @@ If a voicemail is left, it is indicated by recordingURI, transcription, or recor
9744
9797
  fields: {
9745
9798
  ...BuiltInFields,
9746
9799
  integration: { validator: stringValidator, readonly: true, examples: ['Canvas'] },
9747
- status: { validator: exactMatchValidator(['Success', 'Error']), readonly: true, examples: ['Error'] },
9800
+ status: { validator: exactMatchValidator(['Success', 'Error', 'Info']), readonly: true, examples: ['Error'] },
9748
9801
  type: { validator: stringValidator, readonly: true, examples: ['Patient Create'] },
9749
9802
  payload: { validator: stringValidator, readonly: true, examples: ['{}'] },
9750
9803
  response: { validator: stringValidator, readonly: true, examples: ['{}'] },