@torrow/sdk-client 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -10269,7 +10269,16 @@ function projectItemPrice(item) {
10269
10269
 
10270
10270
  // ../../src/resources/cases/read-projection.ts
10271
10271
  function projectCaseItem(item) {
10272
- return projectReadChild(projectItemPrice(projectItemSocial(item)), "personalInfo", projectCasePersonalInfo);
10272
+ const projected = projectReadChild(
10273
+ projectItemPrice(projectItemSocial(item)),
10274
+ "personalInfo",
10275
+ projectCasePersonalInfo
10276
+ );
10277
+ if (projected !== null && typeof projected === "object" && !Array.isArray(projected)) {
10278
+ const { visitCard: _visitCard, ...subject } = projected;
10279
+ return subject;
10280
+ }
10281
+ return projected;
10273
10282
  }
10274
10283
 
10275
10284
  // ../../src/resources/loyalty-cards/read-projection.ts
@@ -11957,6 +11966,12 @@ function patchPublicMessage(category, failureAt) {
11957
11966
  }
11958
11967
  }
11959
11968
  async function patchItem(http, itemId, fields, options, adapter) {
11969
+ return patchItemCore(http, itemId, fields, options, adapter);
11970
+ }
11971
+ async function patchDerivedItem(http, itemId, selector, options, adapter) {
11972
+ return patchItemCore(http, itemId, selector, options, adapter, adapter);
11973
+ }
11974
+ async function patchItemCore(http, itemId, input, options, adapter, derived) {
11960
11975
  let failureAt = "ValidateInput" /* ValidateInput */;
11961
11976
  let effect = "NotApplied" /* NotApplied */;
11962
11977
  const trustedErrors = /* @__PURE__ */ new Set();
@@ -11989,16 +12004,20 @@ async function patchItem(http, itemId, fields, options, adapter) {
11989
12004
  if (expectedVersion !== void 0 && !isVersion(expectedVersion) || Object.hasOwn(opts, "versionToCheck") && expectedVersion === void 0 || signal !== void 0 && !isAbortSignal(signal)) {
11990
12005
  throw localError("InvalidInput" /* InvalidInput */);
11991
12006
  }
11992
- const selected = copyValue(fields, /* @__PURE__ */ new Set(), [], adapter.ridPaths);
11993
- if (!isRecord(selected) || Object.keys(selected).length === 0) {
12007
+ const copied = copyValue(input, /* @__PURE__ */ new Set(), [], adapter.ridPaths);
12008
+ if (!isRecord(copied) || !derived && Object.keys(copied).length === 0) {
11994
12009
  throw localError("InvalidInput" /* InvalidInput */);
11995
12010
  }
11996
- for (const [key, value] of Object.entries(selected)) {
11997
- if (!Object.hasOwn(adapter.fields, key) || !validField(value, adapter.fields[key])) {
11998
- throw localError("InvalidInput" /* InvalidInput */);
12011
+ if (derived) {
12012
+ derived.validateSelector(copied);
12013
+ } else {
12014
+ for (const [key, value] of Object.entries(copied)) {
12015
+ if (!Object.hasOwn(adapter.fields, key) || !validField(value, adapter.fields[key])) {
12016
+ throw localError("InvalidInput" /* InvalidInput */);
12017
+ }
11999
12018
  }
12019
+ adapter.validateFields?.(copied);
12000
12020
  }
12001
- adapter.validateFields?.(selected);
12002
12021
  const readQuery = adapter.readQuery ? { ...adapter.readQuery } : void 0;
12003
12022
  const writeQuery = adapter.writeQuery ? { ...adapter.writeQuery } : void 0;
12004
12023
  if (signal?.aborted) {
@@ -12058,12 +12077,28 @@ async function patchItem(http, itemId, fields, options, adapter) {
12058
12077
  if (signal?.aborted) {
12059
12078
  throw localError("Cancelled" /* Cancelled */);
12060
12079
  }
12080
+ const selected = derived ? await derived.deriveSelectedFields(dto, copied, signal) : copied;
12081
+ if (!isRecord(selected) || Object.keys(selected).length === 0) {
12082
+ throw localError("InvalidInput" /* InvalidInput */);
12083
+ }
12084
+ for (const [key, value] of Object.entries(selected)) {
12085
+ if (!Object.hasOwn(adapter.fields, key) || !validField(value, adapter.fields[key])) {
12086
+ throw localError("InvalidInput" /* InvalidInput */);
12087
+ }
12088
+ }
12089
+ if (derived) {
12090
+ adapter.validateFields?.(selected);
12091
+ }
12092
+ if (signal?.aborted) {
12093
+ throw localError("Cancelled" /* Cancelled */);
12094
+ }
12095
+ Object.assign(selected, adapter.deriveFields?.(dto, selected));
12061
12096
  const unchanged = Object.entries(selected).every(([key, value]) => {
12062
12097
  const equal = adapter.equalField?.(key, dto[key], value, dto);
12063
12098
  if (equal !== void 0) {
12064
12099
  return equal;
12065
12100
  }
12066
- if (adapter.fields[key].kind === "Image" /* Image */ && isRecord(dto[key]) && isRecord(value)) {
12101
+ if (adapter.fields[key]?.kind === "Image" /* Image */ && isRecord(dto[key]) && isRecord(value)) {
12067
12102
  return dto[key].id === value.id;
12068
12103
  }
12069
12104
  return equalItemPatchValue(dto[key], value);
@@ -12112,6 +12147,7 @@ async function patchItem(http, itemId, fields, options, adapter) {
12112
12147
  if (!isRecord(ack) || ack.id !== itemId) {
12113
12148
  throw localError("InvalidResponse" /* InvalidResponse */);
12114
12149
  }
12150
+ adapter.assertAck?.(ack, prepared);
12115
12151
  effect = "Applied" /* Applied */;
12116
12152
  failureAt = "ProjectResult" /* ProjectResult */;
12117
12153
  return { itemId, item: projectItem(ack, adapter.project), changed: true };
@@ -12414,32 +12450,6 @@ function validateItemPricePatch(fields) {
12414
12450
  }
12415
12451
  }
12416
12452
 
12417
- // ../../src/resources/cases/types.ts
12418
- var CaseStateValues = {
12419
- Unknown: "UnknownCaseState",
12420
- Verifying: "Verifying",
12421
- Waiting: "Waiting",
12422
- Processing: "Processing",
12423
- Preparing: "Preparing",
12424
- Completed: "Completed",
12425
- Closed: "Closed",
12426
- Rejected: "Rejected",
12427
- Canceled: "Canceled",
12428
- TimeControlled: "TimeControlled",
12429
- TaskNotCompleted: "TaskNotCompleted",
12430
- TaskCompleted: "TaskCompleted"
12431
- };
12432
- var CaseTypeValues = {
12433
- Unknown: "UnknownTimeType",
12434
- Time: "Time",
12435
- RepeatedTime: "RepeatedTime",
12436
- Today: "Today",
12437
- Week: "Week",
12438
- Later: "Later",
12439
- Date: "Date",
12440
- State: "State"
12441
- };
12442
-
12443
12453
  // ../../src/resources/common/item-patch-predicates.ts
12444
12454
  function isItemPatchDtoObject(value) {
12445
12455
  return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
@@ -12504,6 +12514,57 @@ function normalizeCaseActionRidsForWrite(body, path) {
12504
12514
  });
12505
12515
  }
12506
12516
 
12517
+ // ../../src/resources/cases/types.ts
12518
+ var CaseStateValues = {
12519
+ Unknown: "UnknownCaseState",
12520
+ Verifying: "Verifying",
12521
+ Waiting: "Waiting",
12522
+ Processing: "Processing",
12523
+ Preparing: "Preparing",
12524
+ Completed: "Completed",
12525
+ Closed: "Closed",
12526
+ Rejected: "Rejected",
12527
+ Canceled: "Canceled",
12528
+ TimeControlled: "TimeControlled",
12529
+ TaskNotCompleted: "TaskNotCompleted",
12530
+ TaskCompleted: "TaskCompleted"
12531
+ };
12532
+ var CaseTypeValues = {
12533
+ Unknown: "UnknownTimeType",
12534
+ Time: "Time",
12535
+ RepeatedTime: "RepeatedTime",
12536
+ Today: "Today",
12537
+ Week: "Week",
12538
+ Later: "Later",
12539
+ Date: "Date",
12540
+ State: "State"
12541
+ };
12542
+
12543
+ // ../../src/resources/cases/case-create-visit-card.ts
12544
+ function isValidCaseCardType(value) {
12545
+ return value !== CaseTypeValues.Unknown && Object.values(CaseTypeValues).some((type) => type === value);
12546
+ }
12547
+ function createCaseVisitCard(source) {
12548
+ const { name, caseType, beginDate, endDate, place, description } = source;
12549
+ return {
12550
+ fields: [
12551
+ { number: 0, value: name ?? "", expression: JSON.stringify({ type: "Name" /* Name */ }) },
12552
+ {
12553
+ number: 1,
12554
+ value: caseType,
12555
+ expression: JSON.stringify({ type: "CaseType" /* CaseType */, caseType, beginDate, endDate })
12556
+ },
12557
+ {
12558
+ number: 2,
12559
+ value: (place ? place : description) ?? "",
12560
+ expression: JSON.stringify({
12561
+ type: place ? "PlaceAddress" /* PlaceAddress */ : "Description" /* Description */
12562
+ })
12563
+ }
12564
+ ]
12565
+ };
12566
+ }
12567
+
12507
12568
  // ../../src/resources/cases/case-patch.ts
12508
12569
  function optionalDate2(value) {
12509
12570
  return value == null || value instanceof Date && Number.isFinite(value.getTime());
@@ -12511,19 +12572,6 @@ function optionalDate2(value) {
12511
12572
  function appendices(value) {
12512
12573
  return isItemPatchObjectArray(value) && value.every((item) => optionalDate2(item.openDate) && optionalDate2(item.closeDate));
12513
12574
  }
12514
- function visitCard(value) {
12515
- if (!isItemPatchDtoObject(value) || Object.keys(value).some((key) => key !== "fields")) {
12516
- return false;
12517
- }
12518
- if (value.fields == null) {
12519
- return true;
12520
- }
12521
- return Array.isArray(value.fields) && value.fields.every(
12522
- (field) => isItemPatchDtoObject(field) && Object.entries(field).every(
12523
- ([key, member]) => key === "number" ? isItemPatchInt32(member) : (key === "value" || key === "expression") && (member === null || typeof member === "string")
12524
- )
12525
- );
12526
- }
12527
12575
  function checkinPermission(value) {
12528
12576
  return isItemPatchDtoObject(value) && Object.entries(value).every(
12529
12577
  ([key, member]) => key === "userAccessLevel" ? Object.values(UserAccessLevelValues).some((level) => level === member) : key === "consumerMinTimeSecBetweenCasesInService" && (member === null || isItemPatchInt32(member))
@@ -12546,7 +12594,7 @@ function createCasePatchAdapter() {
12546
12594
  clientGroupId: { kind: "String" /* String */, nullable: true, validate: isItemPatchReferenceId },
12547
12595
  caseType: {
12548
12596
  kind: "String" /* String */,
12549
- validate: (value) => value !== CaseTypeValues.Unknown && Object.values(CaseTypeValues).some((type) => type === value)
12597
+ validate: isValidCaseCardType
12550
12598
  },
12551
12599
  schedule: { kind: "Object" /* Object */, nullable: true, validate: isItemPatchSchedule },
12552
12600
  registrationOpen: { kind: "Integer" /* Integer */, nullable: true, validate: isItemPatchInt32 },
@@ -12565,7 +12613,6 @@ function createCasePatchAdapter() {
12565
12613
  createSingleCases: { kind: "Boolean" /* Boolean */, nullable: true },
12566
12614
  checkinPermission: { kind: "Object" /* Object */, nullable: true, validate: checkinPermission },
12567
12615
  participateFieldRequirements: { kind: "Object" /* Object */, nullable: true },
12568
- visitCard: { kind: "Object" /* Object */, validate: visitCard },
12569
12616
  appendixList: { kind: "Array" /* Array */, nullable: true, validate: appendices },
12570
12617
  resourceGroupList: { kind: "Array" /* Array */, nullable: true, validate: isItemPatchObjectArray },
12571
12618
  caseActionList: { kind: "Array" /* Array */, nullable: true, validate: isItemPatchObjectArray },
@@ -12581,6 +12628,18 @@ function createCasePatchAdapter() {
12581
12628
  throw itemPatchError("InvalidInput" /* InvalidInput */);
12582
12629
  }
12583
12630
  },
12631
+ deriveFields: (dto, selected) => {
12632
+ const final = { ...dto, ...selected };
12633
+ if (!isValidCaseCardType(final.caseType)) {
12634
+ throw itemPatchError("InsufficientData" /* InsufficientData */);
12635
+ }
12636
+ return { visitCard: createCaseVisitCard(final) };
12637
+ },
12638
+ assertAck: (ack, written) => {
12639
+ if (!equalItemPatchValue(ack.visitCard, written.visitCard)) {
12640
+ throw itemPatchError("InvalidResponse" /* InvalidResponse */);
12641
+ }
12642
+ },
12584
12643
  project: (item) => projectCaseItem(item),
12585
12644
  casRefusal: isItemPatchCasRefusal
12586
12645
  };
@@ -12615,6 +12674,20 @@ function cancelCaseParticipation(http, torrowId, body, options) {
12615
12674
 
12616
12675
  // ../../src/resources/cases/CasesFacade.ts
12617
12676
  var BASE3 = "/api/v1/cases";
12677
+ var CARD_SOURCE_FIELDS = /* @__PURE__ */ new Set(["visitCard", "name", "caseType", "beginDate", "endDate", "place", "description"]);
12678
+ function affectsCaseCard(pointer) {
12679
+ if (typeof pointer !== "string" || pointer === "") {
12680
+ return true;
12681
+ }
12682
+ if (!pointer.startsWith("/")) {
12683
+ return true;
12684
+ }
12685
+ const first = pointer.slice(1).split("/")[0];
12686
+ if (/~(?![01])/.test(first)) {
12687
+ return true;
12688
+ }
12689
+ return CARD_SOURCE_FIELDS.has(first.replace(/~1/g, "/").replace(/~0/g, "~"));
12690
+ }
12618
12691
  var CasesFacade = class extends TorrowItemFacade {
12619
12692
  itemObjectTypeCode = TorrowObjectTypeCode.Case;
12620
12693
  /** Чтение полной карточки для метаданных без дочерних данных. */
@@ -12678,7 +12751,11 @@ var CasesFacade = class extends TorrowItemFacade {
12678
12751
  /** `PUT /api/v1/cases/{body.id}` */
12679
12752
  update(body, options) {
12680
12753
  const itemId = requireItemUpdateId(body, "Case");
12754
+ if (!isValidCaseCardType(body.caseType)) {
12755
+ throw new TorrowSdkError({ category: "InvalidInput" /* InvalidInput */ });
12756
+ }
12681
12757
  const payload = structuredClone(body);
12758
+ payload.visitCard = createCaseVisitCard(payload);
12682
12759
  normalizeItemScheduleRidsForWrite(payload, "case");
12683
12760
  normalizeCaseActionRidsForWrite(payload, "case");
12684
12761
  return this.http.requestJson({
@@ -12692,26 +12769,24 @@ var CasesFacade = class extends TorrowItemFacade {
12692
12769
  },
12693
12770
  body: payload,
12694
12771
  signal: options?.signal
12695
- }).then((dto) => projectCaseItem(dto));
12772
+ }).then((dto) => {
12773
+ if (dto === null || typeof dto !== "object" || Array.isArray(dto) || dto.id !== itemId || !equalItemPatchValue(dto.visitCard, payload.visitCard)) {
12774
+ throw new TorrowSdkError({ category: "InvalidResponse" /* InvalidResponse */ });
12775
+ }
12776
+ return projectCaseItem(dto);
12777
+ });
12696
12778
  }
12697
12779
  withCreateDefaults(body, publicityType) {
12698
12780
  const payload = applyItemCreateDefaults(structuredClone(body), "CaseItem" /* CaseItem */, publicityType);
12699
12781
  const prepared = {
12700
12782
  ...payload,
12701
12783
  caseState: payload.caseState ?? CaseStateValues.Verifying,
12702
- caseType: payload.caseType ?? CaseTypeValues.Time,
12703
- // Сервер отклоняет create без VisitCard («Parameter VisitCard cannot have value null»).
12704
- visitCard: payload.visitCard ?? {
12705
- fields: [
12706
- { number: 0, value: payload.name ?? "", expression: '{"type":"Name"}' },
12707
- { number: 1, value: "", expression: null },
12708
- { number: 2, value: "", expression: null }
12709
- ]
12710
- }
12784
+ caseType: payload.caseType ?? CaseTypeValues.Time
12711
12785
  };
12712
- normalizeItemScheduleRidsForWrite(prepared, "case");
12713
- normalizeCaseActionRidsForWrite(prepared, "case");
12714
- return prepared;
12786
+ const withCard = { ...prepared, visitCard: createCaseVisitCard(prepared) };
12787
+ normalizeItemScheduleRidsForWrite(withCard, "case");
12788
+ normalizeCaseActionRidsForWrite(withCard, "case");
12789
+ return withCard;
12715
12790
  }
12716
12791
  /** `DELETE /api/v1/cases/{torrowId}` */
12717
12792
  async delete(torrowId, options) {
@@ -12980,6 +13055,11 @@ var CasesFacade = class extends TorrowItemFacade {
12980
13055
  }
12981
13056
  /** `POST /api/v1/cases/{torrowId}/patch` */
12982
13057
  patchCase(torrowId, body, options) {
13058
+ if (!Array.isArray(body?.patchDoc?.operations) || body.patchDoc.operations.some(
13059
+ (operation) => affectsCaseCard(operation.path) || operation.from != null && affectsCaseCard(operation.from)
13060
+ )) {
13061
+ throw new TorrowSdkError({ category: "InvalidInput" /* InvalidInput */ });
13062
+ }
12983
13063
  return this.http.requestJson({
12984
13064
  method: "POST",
12985
13065
  path: `${BASE3}/${encodePathSegment(torrowId)}/patch`,
@@ -13050,11 +13130,11 @@ function contactVisitCardDefaultSlot0Value(body) {
13050
13130
  return trimNonEmptyString(body.company) ?? "";
13051
13131
  }
13052
13132
  function normalizeContactVisitCardFieldsForWrite(body) {
13053
- let visitCard3 = body.visitCard;
13054
- if (visitCard3 === void 0 || visitCard3 === null || typeof visitCard3 !== "object" || Array.isArray(visitCard3)) {
13055
- visitCard3 = {};
13133
+ let visitCard2 = body.visitCard;
13134
+ if (visitCard2 === void 0 || visitCard2 === null || typeof visitCard2 !== "object" || Array.isArray(visitCard2)) {
13135
+ visitCard2 = {};
13056
13136
  }
13057
- let incoming = Array.isArray(visitCard3.fields) ? visitCard3.fields : [];
13137
+ let incoming = Array.isArray(visitCard2.fields) ? visitCard2.fields : [];
13058
13138
  if (incoming.length === 0) {
13059
13139
  incoming = [
13060
13140
  {
@@ -13082,7 +13162,7 @@ function normalizeContactVisitCardFieldsForWrite(body) {
13082
13162
  for (let i = 0; i < CONTACT_VISIT_CARD_SLOT_COUNT; i++) {
13083
13163
  fields.push(picked[i] ?? { number: i, value: "" });
13084
13164
  }
13085
- body.visitCard = { ...visitCard3, fields };
13165
+ body.visitCard = { ...visitCard2, fields };
13086
13166
  }
13087
13167
 
13088
13168
  // ../../src/resources/contacts/types.ts
@@ -13170,7 +13250,7 @@ var memorableDateShape = {
13170
13250
  order: integer
13171
13251
  };
13172
13252
  var file = (value) => shape(value, { id: (value2) => typeof value2 === "string" && value2.length > 0 }) && record4(value) && Object.hasOwn(value, "id");
13173
- var visitCard2 = (value) => shape(value, {
13253
+ var visitCard = (value) => shape(value, {
13174
13254
  fields: nullable(
13175
13255
  (value2) => Array.isArray(value2) && value2.every((child) => shape(child, { number: integer, value: nullable(text), expression: nullable(text) }))
13176
13256
  )
@@ -13247,7 +13327,7 @@ function createContactPatchAdapter() {
13247
13327
  validate: arrayOf((value) => shape(value, memorableDateShape))
13248
13328
  },
13249
13329
  photos: { kind: "Array" /* Array */, nullable: true, validate: arrayOf(file) },
13250
- visitCard: { kind: "Object" /* Object */, validate: visitCard2 }
13330
+ visitCard: { kind: "Object" /* Object */, validate: visitCard }
13251
13331
  },
13252
13332
  validateFields(fields) {
13253
13333
  selected = structuredClone(fields);
@@ -14487,6 +14567,9 @@ var resourceItemPatchFields = {
14487
14567
  kind: "String" /* String */,
14488
14568
  validate: (value) => Object.values(UsageTypeValues).some((type) => type === value)
14489
14569
  },
14570
+ // Это полная замена списка. Нельзя собирать одно изменение связи снаружи и передавать
14571
+ // сюда массив: внутренний GET/CAS не защитит изменения между внешним и внутренним чтением.
14572
+ // upsertServiceLink/removeServiceLink вычисляют список из собственного raw GET.
14490
14573
  serviceDescriptions: { kind: "Array" /* Array */, validate: isItemPatchObjectArray },
14491
14574
  code: { kind: "String" /* String */, nullable: true },
14492
14575
  duration: { kind: "Integer" /* Integer */, nullable: true, validate: isItemPatchInt32 },
@@ -14525,6 +14608,225 @@ function createResourcePatchAdapter(project) {
14525
14608
  };
14526
14609
  }
14527
14610
 
14611
+ // ../../src/resources/resources/resource-service-link.ts
14612
+ var preservedRootFields = [
14613
+ "name",
14614
+ "description",
14615
+ "contactId",
14616
+ "parentResourceId",
14617
+ "calendarId",
14618
+ "itemId",
14619
+ "timetableId",
14620
+ "schedule",
14621
+ "priceInfo",
14622
+ "usageType",
14623
+ "code",
14624
+ "duration",
14625
+ "amountProperties",
14626
+ "usageCondition",
14627
+ "appendixList",
14628
+ "paymentProperties",
14629
+ "ticketProperties",
14630
+ "loyaltyTransactionPropertiesList",
14631
+ "tags",
14632
+ "uniqueName",
14633
+ "image",
14634
+ "publicityType",
14635
+ "searchMode",
14636
+ "anyoneAccess",
14637
+ "feedbackOptions",
14638
+ "integrationIds"
14639
+ ];
14640
+ function invalidInput() {
14641
+ throw itemPatchError("InvalidInput" /* InvalidInput */);
14642
+ }
14643
+ function insufficientData() {
14644
+ throw itemPatchError("InsufficientData" /* InsufficientData */);
14645
+ }
14646
+ function invalidResponse() {
14647
+ throw itemPatchError("InvalidResponse" /* InvalidResponse */);
14648
+ }
14649
+ function validateSelector(selector) {
14650
+ if (Object.keys(selector).some((key) => !["action", "serviceId", "resourceGroupId", "fields"].includes(key))) {
14651
+ invalidInput();
14652
+ }
14653
+ if (selector.action !== "Upsert" /* Upsert */ && selector.action !== "Remove" /* Remove */) {
14654
+ invalidInput();
14655
+ }
14656
+ try {
14657
+ if (getTorrowObjectTypeFromTorrowId(selector.serviceId) !== "Service") {
14658
+ invalidInput();
14659
+ }
14660
+ } catch {
14661
+ invalidInput();
14662
+ }
14663
+ if (typeof selector.resourceGroupId !== "string" || selector.resourceGroupId.length === 0) {
14664
+ invalidInput();
14665
+ }
14666
+ if (selector.fields === null || typeof selector.fields !== "object" || Array.isArray(selector.fields)) {
14667
+ invalidInput();
14668
+ }
14669
+ if (selector.action === "Remove" /* Remove */ && Object.keys(selector.fields).length > 0) {
14670
+ invalidInput();
14671
+ }
14672
+ for (const [key, value] of Object.entries(selector.fields)) {
14673
+ if (key === "usageAmount") {
14674
+ if (value !== null && (typeof value !== "number" || !Number.isFinite(value))) {
14675
+ invalidInput();
14676
+ }
14677
+ } else if (key === "sortIndex") {
14678
+ if (value !== null && (typeof value !== "number" || !Number.isInteger(value) || value < -2147483648 || value > 2147483647)) {
14679
+ invalidInput();
14680
+ }
14681
+ } else {
14682
+ invalidInput();
14683
+ }
14684
+ }
14685
+ }
14686
+ function checkedDescriptions(dto) {
14687
+ const list = dto.serviceDescriptions;
14688
+ if (list == null || Array.isArray(list) && list.length === 0) {
14689
+ insufficientData();
14690
+ }
14691
+ if (!Array.isArray(list)) {
14692
+ invalidResponse();
14693
+ }
14694
+ const seen = /* @__PURE__ */ new Set();
14695
+ for (const binding of list) {
14696
+ if (binding === null || typeof binding !== "object" || Array.isArray(binding) || typeof binding.id !== "string" || typeof binding.resourceGroupId !== "string" || binding.resourceGroupId.length === 0) {
14697
+ invalidResponse();
14698
+ }
14699
+ try {
14700
+ if (getTorrowObjectTypeFromTorrowId(binding.id) !== "Service") {
14701
+ invalidResponse();
14702
+ }
14703
+ } catch {
14704
+ invalidResponse();
14705
+ }
14706
+ if (binding.serviceName != null && typeof binding.serviceName !== "string" || binding.resourceGroupName != null && typeof binding.resourceGroupName !== "string" || binding.laterBinding != null && typeof binding.laterBinding !== "boolean" || binding.usageAmount != null && (typeof binding.usageAmount !== "number" || !Number.isFinite(binding.usageAmount)) || binding.sortIndex != null && (typeof binding.sortIndex !== "number" || !Number.isInteger(binding.sortIndex) || binding.sortIndex < -2147483648 || binding.sortIndex > 2147483647)) {
14707
+ invalidResponse();
14708
+ }
14709
+ const pair = `${binding.id.length}:${binding.id}${binding.resourceGroupId}`;
14710
+ if (seen.has(pair)) {
14711
+ invalidResponse();
14712
+ }
14713
+ seen.add(pair);
14714
+ }
14715
+ return list;
14716
+ }
14717
+ function samePair(binding, selector) {
14718
+ return binding.id === selector.serviceId && binding.resourceGroupId === selector.resourceGroupId;
14719
+ }
14720
+ async function changeResourceServiceLink(http, project, resourceId, selector, options) {
14721
+ let before;
14722
+ let expected;
14723
+ let acknowledged;
14724
+ const adapter = createResourcePatchAdapter(project);
14725
+ const result = await patchDerivedItem(http, resourceId, selector, options, {
14726
+ ...adapter,
14727
+ operation: selector.action === "Upsert" /* Upsert */ ? "ResourcesFacade.upsertServiceLink" : "ResourcesFacade.removeServiceLink",
14728
+ validateSelector,
14729
+ async deriveSelectedFields(dto, selected, signal) {
14730
+ const list2 = checkedDescriptions(dto);
14731
+ before = dto;
14732
+ const at = list2.findIndex((binding) => samePair(binding, selected));
14733
+ if (selected.action === "Remove" /* Remove */) {
14734
+ if (at < 0) {
14735
+ expected = list2;
14736
+ return { serviceDescriptions: list2 };
14737
+ }
14738
+ if (list2.length === 1) {
14739
+ insufficientData();
14740
+ }
14741
+ expected = list2.filter((_, index) => index !== at);
14742
+ return { serviceDescriptions: expected };
14743
+ }
14744
+ if (signal?.aborted) {
14745
+ throw itemPatchError("Cancelled" /* Cancelled */);
14746
+ }
14747
+ const service = await http.requestJson({
14748
+ method: "GET",
14749
+ path: `/api/v1/services/${encodePathSegment(selected.serviceId)}`,
14750
+ signal
14751
+ });
14752
+ if (service === null || typeof service !== "object" || Array.isArray(service) || service.id !== selected.serviceId) {
14753
+ invalidResponse();
14754
+ }
14755
+ const groups = service.resourceGroupList;
14756
+ if (!Array.isArray(groups)) {
14757
+ insufficientData();
14758
+ }
14759
+ const matchingGroups = groups.filter((item) => item?.groupId === selected.resourceGroupId);
14760
+ if (matchingGroups.length > 1) {
14761
+ invalidResponse();
14762
+ }
14763
+ const group = matchingGroups[0];
14764
+ if (!group || typeof group.usageType !== "string" || group.usageType.length === 0 || typeof group.groupName !== "string" || typeof service.name !== "string") {
14765
+ insufficientData();
14766
+ }
14767
+ if (group.usageType === UsageTypeValues.Unknown || !Object.values(UsageTypeValues).some((value) => value === group.usageType)) {
14768
+ invalidResponse();
14769
+ }
14770
+ if (dto.usageType !== group.usageType) {
14771
+ invalidInput();
14772
+ }
14773
+ const next = [...list2];
14774
+ if (at < 0) {
14775
+ next.push({
14776
+ id: selected.serviceId,
14777
+ resourceGroupId: selected.resourceGroupId,
14778
+ serviceName: service.name,
14779
+ resourceGroupName: group.groupName,
14780
+ laterBinding: group.bookingProperties != null,
14781
+ ...selected.fields
14782
+ });
14783
+ } else {
14784
+ next[at] = { ...list2[at], ...selected.fields };
14785
+ }
14786
+ expected = next;
14787
+ return { serviceDescriptions: next };
14788
+ },
14789
+ assertAck(ack, written) {
14790
+ if (!before || !expected || !Array.isArray(ack.serviceDescriptions) || !equalItemPatchValue(ack.serviceDescriptions, expected) || !Number.isInteger(ack.meta?.version) || (ack.meta?.version ?? 0) <= 0) {
14791
+ invalidResponse();
14792
+ }
14793
+ const rawAck = ack;
14794
+ const rawWritten = written;
14795
+ for (const key of preservedRootFields) {
14796
+ if (Object.hasOwn(before, key) && !equalItemPatchValue(rawAck[key], rawWritten[key])) {
14797
+ invalidResponse();
14798
+ }
14799
+ }
14800
+ acknowledged = ack.serviceDescriptions;
14801
+ }
14802
+ });
14803
+ const list = result.changed ? acknowledged : before.serviceDescriptions;
14804
+ return {
14805
+ ...result,
14806
+ serviceId: selector.serviceId,
14807
+ resourceGroupId: selector.resourceGroupId,
14808
+ binding: list.find((binding) => samePair(binding, selector)) ?? null
14809
+ };
14810
+ }
14811
+ function upsertResourceServiceLink(http, project, resourceId, serviceId, resourceGroupId, fields, options) {
14812
+ return changeResourceServiceLink(
14813
+ http,
14814
+ project,
14815
+ resourceId,
14816
+ { action: "Upsert" /* Upsert */, serviceId, resourceGroupId, fields },
14817
+ options
14818
+ );
14819
+ }
14820
+ function removeResourceServiceLink(http, project, resourceId, serviceId, resourceGroupId, options) {
14821
+ return changeResourceServiceLink(
14822
+ http,
14823
+ project,
14824
+ resourceId,
14825
+ { action: "Remove" /* Remove */, serviceId, resourceGroupId, fields: {} },
14826
+ options
14827
+ );
14828
+ }
14829
+
14528
14830
  // ../../src/resources/resources/ResourcesFacade.ts
14529
14831
  var BASE7 = "/api/v1/resources";
14530
14832
  var ResourcesFacade = class extends TorrowItemFacade {
@@ -14555,6 +14857,35 @@ var ResourcesFacade = class extends TorrowItemFacade {
14555
14857
  createResourcePatchAdapter((item) => this.toSdkResourceItem(item))
14556
14858
  );
14557
14859
  }
14860
+ /**
14861
+ * Адресно добавляет или изменяет одну связь при полном непустом списке.
14862
+ * Предполагается, что Service не изменяется в течение вызова; CAS защищает Resource.
14863
+ * Серверный отказ проверки Service при PUT передаётся как TorrowSdkError с HTTP-данными.
14864
+ * Проверка Service не атомарна с записью Resource.
14865
+ * При неизвестном результате PUT требуется отдельная сверка, автоматического повтора нет.
14866
+ */
14867
+ upsertServiceLink(resourceId, serviceId, resourceGroupId, fields, options) {
14868
+ return upsertResourceServiceLink(
14869
+ this.http,
14870
+ (item) => this.toSdkResourceItem(item),
14871
+ resourceId,
14872
+ serviceId,
14873
+ resourceGroupId,
14874
+ fields,
14875
+ options
14876
+ );
14877
+ }
14878
+ /** Удаляет одну связь, если после неё остаётся непустой подтверждённый список. */
14879
+ removeServiceLink(resourceId, serviceId, resourceGroupId, options) {
14880
+ return removeResourceServiceLink(
14881
+ this.http,
14882
+ (item) => this.toSdkResourceItem(item),
14883
+ resourceId,
14884
+ serviceId,
14885
+ resourceGroupId,
14886
+ options
14887
+ );
14888
+ }
14558
14889
  /** Поиск по уникальному имени возвращает ту же модель ресурса, что и getById. */
14559
14890
  getByUniqueName(uniqueName, options) {
14560
14891
  return this.readByUniqueName(uniqueName, options).then((item) => this.toSdkResourceItem(item));
@@ -15529,11 +15860,13 @@ var ServicesFacade = class extends TorrowItemFacade {
15529
15860
  }
15530
15861
  /** `POST /api/v1/services/{serviceId}/session` — создать сессию записи (тело `CaseItem`). */
15531
15862
  createSession(serviceId, body, options) {
15863
+ const payload = { ...structuredClone(body), caseType: body.caseType ?? CaseTypeValues.Time };
15864
+ payload.visitCard = createCaseVisitCard(payload);
15532
15865
  return this.http.requestJson({
15533
15866
  method: "POST",
15534
15867
  path: `${BASE9}/${encodePathSegment(serviceId)}/session`,
15535
15868
  query: { profileId: options?.profileId },
15536
- body,
15869
+ body: payload,
15537
15870
  signal: options?.signal
15538
15871
  }).then((dto) => projectCaseItem(dto));
15539
15872
  }