@solumflow-app/crm-mcp-server 0.12.0 → 0.13.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
@@ -6,16 +6,203 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
6
6
  import { createClient } from "@solumflow-app/crm-client";
7
7
 
8
8
  // package.json
9
- var version = "0.12.0";
9
+ var version = "0.13.0";
10
+
11
+ // src/calendar-setup-tools.ts
12
+ import { z as z2 } from "zod";
13
+
14
+ // src/tool-answers.ts
15
+ import { CrmApiError } from "@solumflow-app/crm-client";
16
+ import { z } from "zod";
17
+ function answer(text2, data) {
18
+ return {
19
+ content: [{ type: "text", text: text2 }],
20
+ structuredContent: { result: data }
21
+ };
22
+ }
23
+ function refusal(error, scope) {
24
+ if (!(error instanceof CrmApiError)) {
25
+ throw error;
26
+ }
27
+ const lines = [`${error.code}: ${error.message}`];
28
+ const next = error.code === "forbidden" ? `The key may not do this. It needs to be a secret key with the scope "${scope}".` : NEXT_STEP[error.code];
29
+ if (next) {
30
+ lines.push(next);
31
+ }
32
+ for (const field of error.fields) {
33
+ lines.push(`- ${field.path}: ${field.message}`);
34
+ }
35
+ return {
36
+ isError: true,
37
+ content: [{ type: "text", text: lines.join("\n") }]
38
+ };
39
+ }
40
+ var NEXT_STEP = {
41
+ unauthorized: "The key is not recognised or was revoked. Ask the account owner for a new secret key.",
42
+ feature_unavailable: "The module this needs is switched off for the account. Ask somebody to switch it on in the app.",
43
+ rate_limited: "Too many requests: 120 a minute per key, 600 per account, and 5 MB of bodies a day per key. Wait the seconds the answer names and try again.",
44
+ internal_error: "Something went wrong in the app. Trying again is safe.",
45
+ limit_reached: "The reseller has as many customer accounts as its plan allows. The platform owner raises that, not another try."
46
+ };
47
+ function codeBlock(snippet) {
48
+ return `\`\`\`html
49
+ ${snippet}
50
+ \`\`\``;
51
+ }
52
+ var page = {
53
+ cursor: z.string().optional().describe("The nextCursor of the previous page; leave out for the first."),
54
+ limit: z.number().int().min(1).max(100).optional()
55
+ };
56
+ function more(nextCursor) {
57
+ return nextCursor ? `More on the next page: cursor ${nextCursor}` : "";
58
+ }
59
+ function money(cents3, currency2) {
60
+ return `${(cents3 / 100).toFixed(2)} ${currency2.toUpperCase()}`;
61
+ }
62
+ function fieldsNotOnPageNote(slugs) {
63
+ if (!slugs?.length) {
64
+ return "";
65
+ }
66
+ const count = slugs.length === 1 ? "1 public field has" : `${slugs.length} public fields have`;
67
+ return ` ${count} a value but ${slugs.length === 1 ? "is" : "are"} not on this product's page: ${slugs.join(", ")}; send them in publicFields to show them.`;
68
+ }
69
+
70
+ // src/calendar-setup-tools.ts
71
+ var slug = z2.string().min(1).max(64).regex(/^[a-z0-9]+(-[a-z0-9]+)*$/).describe('Lowercase letters, digits and dashes, e.g. "kennismaking".');
72
+ var time = z2.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/).describe("HH:MM on the calendar\u2019s own clock.");
73
+ var NEVER_APPOINTMENTS = "It never makes or moves an appointment: that mails a customer, and stays in the app. list_booking_pages shows the result.";
74
+ function registerCalendarSetupTools(server, client) {
75
+ server.registerTool(
76
+ "upsert_calendar",
77
+ {
78
+ title: "Make or change a calendar",
79
+ description: `A calendar by its address (slug): "event" for meetings with one host, "round_robin" for whoever of the hosts is free, or "services" for the account\u2019s own services calendar, which is changed and never made. A new calendar takes the defaults for what is left out; one that exists keeps it. A new calendar naming no hosts is taken by the account\u2019s owner. ${NEVER_APPOINTMENTS}`,
80
+ inputSchema: {
81
+ slug,
82
+ name: z2.string().min(1).max(120),
83
+ type: z2.enum(["event", "round_robin", "services"]).optional(),
84
+ description: z2.string().max(5e3).nullable().optional(),
85
+ durationMinutes: z2.number().int().min(1).max(1440).optional(),
86
+ isActive: z2.boolean().optional(),
87
+ slotIntervalMinutes: z2.number().int().min(1).max(1440).optional(),
88
+ minNoticeMinutes: z2.number().int().min(0).optional(),
89
+ bookingHorizonDays: z2.number().int().min(1).max(730).optional(),
90
+ bufferBeforeMinutes: z2.number().int().min(0).max(1440).optional(),
91
+ bufferAfterMinutes: z2.number().int().min(0).max(1440).optional(),
92
+ maxPerDay: z2.number().int().min(1).nullable().optional(),
93
+ timezoneMode: z2.enum(["visitor", "fixed"]).optional(),
94
+ timezone: z2.string().optional().describe("An IANA zone, e.g. Europe/Amsterdam."),
95
+ hostUserIds: z2.array(z2.string().uuid()).min(1).max(50).optional()
96
+ },
97
+ annotations: { idempotentHint: true }
98
+ },
99
+ async (input) => {
100
+ try {
101
+ const result = await client.upsertCalendar(input);
102
+ return answer(
103
+ `${result.created ? "Made" : "Changed"}: ${describeCalendar(result.calendar)}`,
104
+ result
105
+ );
106
+ } catch (error) {
107
+ return refusal(error, "calendar:manage");
108
+ }
109
+ }
110
+ );
111
+ server.registerTool(
112
+ "set_calendar_availability",
113
+ {
114
+ title: "Set a calendar\u2019s opening hours",
115
+ description: "The hours a calendar can be booked: weekly rules (weekday 0 is Sunday) and exceptions per date (closed, or other hours). Each list sent replaces the one there; one left out is kept. For the services calendar these are the hours its services can be booked.",
116
+ inputSchema: {
117
+ slug,
118
+ rules: z2.array(
119
+ z2.object({
120
+ weekday: z2.number().int().min(0).max(6),
121
+ startsTime: time,
122
+ endsTime: time,
123
+ userId: z2.string().uuid().nullable().optional()
124
+ })
125
+ ).max(200).optional(),
126
+ overrides: z2.array(
127
+ z2.object({
128
+ date: z2.string().regex(/^\d{4}-\d{2}-\d{2}$/),
129
+ isUnavailable: z2.boolean().optional(),
130
+ startsTime: time.nullable().optional(),
131
+ endsTime: time.nullable().optional(),
132
+ userId: z2.string().uuid().nullable().optional()
133
+ })
134
+ ).max(365).optional()
135
+ },
136
+ annotations: { idempotentHint: true }
137
+ },
138
+ async ({ slug: calendarSlug, rules, overrides }) => {
139
+ try {
140
+ const result = await client.setCalendarAvailability(calendarSlug, {
141
+ rules,
142
+ overrides
143
+ });
144
+ const parts = [
145
+ rules ? `${rules.length} weekly rule(s)` : "",
146
+ overrides ? `${overrides.length} exception(s)` : ""
147
+ ].filter(Boolean);
148
+ return answer(
149
+ `Hours of "${result.slug}" saved: ${parts.join(" and ")}.`,
150
+ result
151
+ );
152
+ } catch (error) {
153
+ return refusal(error, "calendar:manage");
154
+ }
155
+ }
156
+ );
157
+ server.registerTool(
158
+ "upsert_services",
159
+ {
160
+ title: "Make or change bookable services",
161
+ description: `Up to fifty services the services calendar offers, each by its address (slug): name, length in minutes, price in cents, group (category) and whether the booking page lists it. A service nobody performs is given the account\u2019s owner, so it has free times at once. Paid on the spot: paying in advance needs the account\u2019s own Stripe connection, set in the app. ${NEVER_APPOINTMENTS}`,
162
+ inputSchema: {
163
+ services: z2.array(
164
+ z2.object({
165
+ slug: z2.string().min(1).max(120).regex(/^[a-z0-9]+(-[a-z0-9]+)*$/),
166
+ name: z2.string().min(1).max(200),
167
+ durationMinutes: z2.number().int().min(5).max(1440),
168
+ priceCents: z2.number().int().min(0).optional(),
169
+ description: z2.string().max(5e3).nullable().optional(),
170
+ active: z2.boolean().optional(),
171
+ visibility: z2.enum(["public", "private"]).optional(),
172
+ category: z2.string().min(1).max(120).nullable().optional()
173
+ })
174
+ ).min(1).max(50)
175
+ },
176
+ annotations: { idempotentHint: true }
177
+ },
178
+ async ({ services }) => {
179
+ try {
180
+ const result = await client.upsertServices(services);
181
+ return answer(result.map(describeService).join("\n"), result);
182
+ } catch (error) {
183
+ return refusal(error, "calendar:manage");
184
+ }
185
+ }
186
+ );
187
+ }
188
+ function describeCalendar(calendar) {
189
+ const state = calendar.isActive ? "" : ", switched off";
190
+ return `${calendar.name} (${calendar.slug}, ${calendar.type}), ${calendar.durationMinutes} min, ${calendar.timezone}${state}`;
191
+ }
192
+ function describeService(service) {
193
+ const verb = service.created ? "made" : "changed";
194
+ const price = service.priceCents ? `price ${(service.priceCents / 100).toFixed(2)}` : "free";
195
+ return `- ${service.name} (${service.slug}): ${service.durationMinutes} min, ${price}, ${service.visibility}${service.active ? "" : ", inactive"} -- ${verb}`;
196
+ }
10
197
 
11
198
  // src/catalog-migration-tools.ts
12
- import { z as z8 } from "zod";
199
+ import { z as z9 } from "zod";
13
200
 
14
201
  // ../features/crm-invoicing/src/schema/catalog-api.schema.ts
15
- import * as z5 from "zod";
202
+ import * as z7 from "zod";
16
203
 
17
204
  // ../features/crm-invoicing/src/shared/product-surcharge-options-schema.ts
18
- import { z as z4 } from "zod";
205
+ import { z as z6 } from "zod";
19
206
 
20
207
  // ../features/product-configurator/src/shared/configurator-limits.ts
21
208
  var CONFIGURATOR_LIMITS = {
@@ -385,16 +572,16 @@ function evaluateFormulaSource(source, scope) {
385
572
  }
386
573
 
387
574
  // ../features/product-configurator/src/shared/geometry-document.schema.ts
388
- import { z } from "zod";
575
+ import { z as z3 } from "zod";
389
576
  var CONFIGURATOR_NAME_PATTERN = /^[a-z][a-z0-9_]{0,39}$/;
390
577
  var CONFIGURATOR_CODE_PATTERN = /^[a-z0-9][a-z0-9_-]{0,39}$/;
391
- var ConfiguratorNameSchema = z.string().regex(CONFIGURATOR_NAME_PATTERN, "configurator.invalidName");
392
- var ConfiguratorCodeSchema = z.string().regex(CONFIGURATOR_CODE_PATTERN, "configurator.invalidCode");
393
- var FormulaSchema = z.union([
394
- z.number().finite(),
395
- z.string().trim().min(1).max(CONFIGURATOR_LIMITS.formulaChars, "configurator.formulaTooLong")
578
+ var ConfiguratorNameSchema = z3.string().regex(CONFIGURATOR_NAME_PATTERN, "configurator.invalidName");
579
+ var ConfiguratorCodeSchema = z3.string().regex(CONFIGURATOR_CODE_PATTERN, "configurator.invalidCode");
580
+ var FormulaSchema = z3.union([
581
+ z3.number().finite(),
582
+ z3.string().trim().min(1).max(CONFIGURATOR_LIMITS.formulaChars, "configurator.formulaTooLong")
396
583
  ]);
397
- var Vector3Schema = z.tuple([FormulaSchema, FormulaSchema, FormulaSchema]);
584
+ var Vector3Schema = z3.tuple([FormulaSchema, FormulaSchema, FormulaSchema]);
398
585
  var PRIMITIVE_TYPES = [
399
586
  "box",
400
587
  "rounded_top_box",
@@ -436,10 +623,10 @@ var CONFIGURATOR_FOLLOWS_PRESET = "preset";
436
623
  var MOTION_GROUP_PATTERN = /^[a-z](?:[a-z0-9_]|\{[ij]\}){0,39}$/;
437
624
  var MOTION_KINDS = ["hinge", "slide"];
438
625
  var MOTION_EDGES = ["bottom", "top", "left", "right"];
439
- var GeometryMotionSchema = z.strictObject({
440
- group: z.string().regex(MOTION_GROUP_PATTERN, "configurator.invalidName"),
441
- kind: z.enum(MOTION_KINDS),
442
- edge: z.enum(MOTION_EDGES).optional(),
626
+ var GeometryMotionSchema = z3.strictObject({
627
+ group: z3.string().regex(MOTION_GROUP_PATTERN, "configurator.invalidName"),
628
+ kind: z3.enum(MOTION_KINDS),
629
+ edge: z3.enum(MOTION_EDGES).optional(),
443
630
  angle: FormulaSchema.optional(),
444
631
  distance: FormulaSchema.optional()
445
632
  });
@@ -449,94 +636,94 @@ var PrimitiveNodeFields = {
449
636
  size: Vector3Schema,
450
637
  at: Vector3Schema,
451
638
  visible: FormulaSchema.optional(),
452
- params: z.record(ConfiguratorNameSchema, FormulaSchema).optional(),
639
+ params: z3.record(ConfiguratorNameSchema, FormulaSchema).optional(),
453
640
  motion: GeometryMotionSchema.optional()
454
641
  };
455
- var PrimitiveNodeSchema = z.strictObject({
642
+ var PrimitiveNodeSchema = z3.strictObject({
456
643
  ...PrimitiveNodeFields,
457
- type: z.enum(PRIMITIVE_TYPES).exclude(["model"])
644
+ type: z3.enum(PRIMITIVE_TYPES).exclude(["model"])
458
645
  });
459
- var ModelPathSchema = z.string().regex(CONFIGURATOR_MODEL_PATH_PATTERN, "configurator.invalidModelPath");
460
- var ServedFileUrlSchema = z.url({ protocol: /^https?$/ });
646
+ var ModelPathSchema = z3.string().regex(CONFIGURATOR_MODEL_PATH_PATTERN, "configurator.invalidModelPath");
647
+ var ServedFileUrlSchema = z3.url({ protocol: /^https?$/ });
461
648
  function geometryNodeSchema(modelFile) {
462
- const ModelNodeSchema = z.strictObject({
649
+ const ModelNodeSchema = z3.strictObject({
463
650
  ...PrimitiveNodeFields,
464
- type: z.literal("model"),
651
+ type: z3.literal("model"),
465
652
  model: modelFile
466
653
  });
467
- const ModelPerChoiceNodeSchema = z.strictObject({
654
+ const ModelPerChoiceNodeSchema = z3.strictObject({
468
655
  ...PrimitiveNodeFields,
469
- type: z.literal("model"),
656
+ type: z3.literal("model"),
470
657
  follows: ConfiguratorNameSchema,
471
- models: z.record(ConfiguratorCodeSchema, modelFile).refine(
658
+ models: z3.record(ConfiguratorCodeSchema, modelFile).refine(
472
659
  (models) => Object.keys(models).length <= CONFIGURATOR_LIMITS.presets,
473
660
  { message: "configurator.tooMany" }
474
661
  )
475
662
  });
476
- const node = z.lazy(
477
- () => z.union([
663
+ const node = z3.lazy(
664
+ () => z3.union([
478
665
  PrimitiveNodeSchema,
479
666
  ModelNodeSchema,
480
667
  ModelPerChoiceNodeSchema,
481
- z.strictObject({
668
+ z3.strictObject({
482
669
  id: ConfiguratorNameSchema,
483
- type: z.literal("repeat"),
670
+ type: z3.literal("repeat"),
484
671
  count: FormulaSchema,
485
- index: z.enum(["i", "j"]).optional(),
672
+ index: z3.enum(["i", "j"]).optional(),
486
673
  visible: FormulaSchema.optional(),
487
- children: z.array(node).min(1)
674
+ children: z3.array(node).min(1)
488
675
  })
489
676
  ])
490
677
  );
491
678
  return node;
492
679
  }
493
680
  var GeometryNodeSchema = geometryNodeSchema(ModelPathSchema);
494
- var GeometryBindingSchema = z.strictObject({
681
+ var GeometryBindingSchema = z3.strictObject({
495
682
  param: ConfiguratorNameSchema,
496
- map: z.record(ConfiguratorCodeSchema, z.number().finite()).optional()
683
+ map: z3.record(ConfiguratorCodeSchema, z3.number().finite()).optional()
497
684
  });
498
- var GeometryInputSchema = z.strictObject({
685
+ var GeometryInputSchema = z3.strictObject({
499
686
  name: ConfiguratorNameSchema,
500
687
  binding: GeometryBindingSchema
501
688
  });
502
- var GeometrySlotSchema = z.strictObject({
689
+ var GeometrySlotSchema = z3.strictObject({
503
690
  name: ConfiguratorNameSchema,
504
691
  param: ConfiguratorNameSchema.optional(),
505
692
  material: ConfiguratorCodeSchema.optional(),
506
- color: z.string().regex(/^#[0-9a-f]{6}$/i, "configurator.invalidColor").optional(),
693
+ color: z3.string().regex(/^#[0-9a-f]{6}$/i, "configurator.invalidColor").optional(),
507
694
  /**
508
695
  * Which way the grain of a picture runs on this part: `horizontal` (the
509
696
  * default) as the picture is drawn, `vertical` turned a quarter. It belongs
510
697
  * to the part, not the material: the same oak lies on a cabinet and stands
511
698
  * on a tall wall panel.
512
699
  */
513
- grain: z.enum(["horizontal", "vertical"]).optional()
700
+ grain: z3.enum(["horizontal", "vertical"]).optional()
514
701
  });
515
- var GeometryAnnotationSchema = z.strictObject({
702
+ var GeometryAnnotationSchema = z3.strictObject({
516
703
  id: ConfiguratorNameSchema,
517
- axis: z.enum(["x", "y"]),
704
+ axis: z3.enum(["x", "y"]),
518
705
  from: FormulaSchema,
519
706
  to: FormulaSchema,
520
707
  at: FormulaSchema,
521
- label: z.string().trim().min(1).max(80).optional()
708
+ label: z3.string().trim().min(1).max(80).optional()
522
709
  });
523
710
  function geometryDocumentSchema(modelFile) {
524
- return z.strictObject({
711
+ return z3.strictObject({
525
712
  /** Rises with every new upload, so a product page can say which one it shows. */
526
- version: z.number().int().min(1),
713
+ version: z3.number().int().min(1),
527
714
  /** The starter document this one was copied from, for information only. */
528
- startedFrom: z.string().trim().max(80).optional(),
529
- inputs: z.array(GeometryInputSchema).max(CONFIGURATOR_LIMITS.geometryInputs),
530
- constants: z.record(ConfiguratorNameSchema, z.number().finite()),
531
- slots: z.array(GeometrySlotSchema).min(1).max(CONFIGURATOR_LIMITS.geometrySlots),
532
- root: z.array(geometryNodeSchema(modelFile)).min(1),
533
- camera: z.strictObject({
715
+ startedFrom: z3.string().trim().max(80).optional(),
716
+ inputs: z3.array(GeometryInputSchema).max(CONFIGURATOR_LIMITS.geometryInputs),
717
+ constants: z3.record(ConfiguratorNameSchema, z3.number().finite()),
718
+ slots: z3.array(GeometrySlotSchema).min(1).max(CONFIGURATOR_LIMITS.geometrySlots),
719
+ root: z3.array(geometryNodeSchema(modelFile)).min(1),
720
+ camera: z3.strictObject({
534
721
  /** Degrees around the vertical axis, 0 is straight on. */
535
- azimuth: z.number().min(-90).max(90),
722
+ azimuth: z3.number().min(-90).max(90),
536
723
  /** Degrees above the horizon. */
537
- elevation: z.number().min(-10).max(80)
724
+ elevation: z3.number().min(-10).max(80)
538
725
  }).optional(),
539
- annotations: z.array(GeometryAnnotationSchema).max(CONFIGURATOR_LIMITS.annotations)
726
+ annotations: z3.array(GeometryAnnotationSchema).max(CONFIGURATOR_LIMITS.annotations)
540
727
  });
541
728
  }
542
729
  var GeometryDocumentSchema = geometryDocumentSchema(ModelPathSchema);
@@ -872,7 +1059,7 @@ function followProblems(follows, path, context) {
872
1059
  }
873
1060
 
874
1061
  // ../features/product-configurator/src/shared/configurator-structure.schema.ts
875
- import { z as z2 } from "zod";
1062
+ import { z as z4 } from "zod";
876
1063
 
877
1064
  // ../features/product-configurator/src/shared/room-palette.ts
878
1065
  var ROOM_WALL_PALETTE = [
@@ -901,104 +1088,104 @@ var ROOM_FLOOR_PALETTE = [
901
1088
  ];
902
1089
 
903
1090
  // ../features/product-configurator/src/shared/configurator-structure.schema.ts
904
- var LabelSchema = z2.string().trim().min(1).max(80);
1091
+ var LabelSchema = z4.string().trim().min(1).max(80);
905
1092
  var CONFIGURATOR_TEXTURE_PATH_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.(webp|jpg|jpeg)$/;
906
- var TexturePathSchema = z2.string().regex(CONFIGURATOR_TEXTURE_PATH_PATTERN, "configurator.invalidTexturePath");
1093
+ var TexturePathSchema = z4.string().regex(CONFIGURATOR_TEXTURE_PATH_PATTERN, "configurator.invalidTexturePath");
907
1094
  var ParameterBase = {
908
1095
  key: ConfiguratorNameSchema,
909
1096
  label: LabelSchema,
910
1097
  tab: ConfiguratorNameSchema
911
1098
  };
912
- var ConfiguratorParameterSchema = z2.discriminatedUnion("kind", [
913
- z2.strictObject({
1099
+ var ConfiguratorParameterSchema = z4.discriminatedUnion("kind", [
1100
+ z4.strictObject({
914
1101
  ...ParameterBase,
915
- kind: z2.literal("number"),
1102
+ kind: z4.literal("number"),
916
1103
  /** `mm` is a measure, `count` a number of things (compartments). */
917
- unit: z2.enum(["mm", "count"]),
918
- step: z2.number().positive().finite(),
1104
+ unit: z4.enum(["mm", "count"]),
1105
+ step: z4.number().positive().finite(),
919
1106
  /** The widest range any model may offer; a model narrows it in its value. */
920
- min: z2.number().finite(),
921
- max: z2.number().finite()
1107
+ min: z4.number().finite(),
1108
+ max: z4.number().finite()
922
1109
  }),
923
- z2.strictObject({
1110
+ z4.strictObject({
924
1111
  ...ParameterBase,
925
- kind: z2.literal("choice"),
1112
+ kind: z4.literal("choice"),
926
1113
  list: ConfiguratorNameSchema
927
1114
  }),
928
- z2.strictObject({ ...ParameterBase, kind: z2.literal("material") }),
929
- z2.strictObject({ ...ParameterBase, kind: z2.literal("toggle") })
1115
+ z4.strictObject({ ...ParameterBase, kind: z4.literal("material") }),
1116
+ z4.strictObject({ ...ParameterBase, kind: z4.literal("toggle") })
930
1117
  ]);
931
- var choiceListSchema = (picture) => z2.strictObject({
1118
+ var choiceListSchema = (picture) => z4.strictObject({
932
1119
  key: ConfiguratorNameSchema,
933
1120
  label: LabelSchema,
934
- options: z2.array(
935
- z2.strictObject({
1121
+ options: z4.array(
1122
+ z4.strictObject({
936
1123
  code: ConfiguratorCodeSchema,
937
1124
  label: LabelSchema,
938
1125
  image: picture.optional()
939
1126
  })
940
1127
  ).min(1).max(CONFIGURATOR_LIMITS.optionsPerList)
941
1128
  });
942
- var materialSchema = (picture) => z2.strictObject({
1129
+ var materialSchema = (picture) => z4.strictObject({
943
1130
  code: ConfiguratorCodeSchema,
944
1131
  label: LabelSchema,
945
- color: z2.string().regex(/^#[0-9a-f]{6}$/i, "configurator.invalidColor"),
1132
+ color: z4.string().regex(/^#[0-9a-f]{6}$/i, "configurator.invalidColor"),
946
1133
  texture: picture.optional(),
947
1134
  /** Millimetres one repeat of the texture covers; the two maps below share it. */
948
- textureSize: z2.number().positive().max(1e4).optional(),
1135
+ textureSize: z4.number().positive().max(1e4).optional(),
949
1136
  /** Relief that moves with the light: a tangent-space normal map. */
950
1137
  normalMap: picture.optional(),
951
1138
  /** How deep the relief reads; 1 is the map as drawn. */
952
- normalScale: z2.number().min(0).max(3).optional(),
1139
+ normalScale: z4.number().min(0).max(3).optional(),
953
1140
  /** Where the surface is matte and where it shines (the green channel), times `roughness`. */
954
1141
  roughnessMap: picture.optional(),
955
- roughness: z2.number().min(0).max(1).optional(),
956
- metalness: z2.number().min(0).max(1).optional(),
1142
+ roughness: z4.number().min(0).max(1).optional(),
1143
+ metalness: z4.number().min(0).max(1).optional(),
957
1144
  /** How much of what is behind it shows through: glass in front of a flame. Absent is solid. */
958
- opacity: z2.number().min(0.05).max(1).optional(),
1145
+ opacity: z4.number().min(0.05).max(1).optional(),
959
1146
  /** Gives light rather than reflecting it: a flame, a LED. */
960
- emissive: z2.boolean().optional(),
1147
+ emissive: z4.boolean().optional(),
961
1148
  /**
962
1149
  * The colour temperature of a light, in kelvin: a LED strip sold as
963
1150
  * 3000 K glows and lights in that colour rather than in `color`, which
964
1151
  * stays the swatch's fallback. A strip that can do several (2700-6500 K)
965
1152
  * names the one to show: 4000 K.
966
1153
  */
967
- kelvin: z2.number().int().min(1500).max(1e4).optional(),
1154
+ kelvin: z4.number().int().min(1500).max(1e4).optional(),
968
1155
  priceGroup: ConfiguratorCodeSchema.optional()
969
1156
  });
970
1157
  var ConfiguratorChoiceListSchema = choiceListSchema(TexturePathSchema);
971
1158
  var ConfiguratorMaterialSchema = materialSchema(TexturePathSchema);
972
- var ConditionValueSchema = z2.union([
973
- z2.number().finite(),
974
- z2.boolean(),
1159
+ var ConditionValueSchema = z4.union([
1160
+ z4.number().finite(),
1161
+ z4.boolean(),
975
1162
  ConfiguratorCodeSchema,
976
- z2.array(ConfiguratorCodeSchema).min(1).max(CONFIGURATOR_LIMITS.optionsPerList)
1163
+ z4.array(ConfiguratorCodeSchema).min(1).max(CONFIGURATOR_LIMITS.optionsPerList)
977
1164
  ]);
978
- var ConfiguratorConditionSchema = z2.strictObject({
1165
+ var ConfiguratorConditionSchema = z4.strictObject({
979
1166
  param: ConfiguratorNameSchema,
980
- op: z2.enum(["eq", "neq", "in", "gte", "lte"]),
1167
+ op: z4.enum(["eq", "neq", "in", "gte", "lte"]),
981
1168
  value: ConditionValueSchema
982
1169
  });
983
- var ConfiguratorRuleSchema = z2.discriminatedUnion("kind", [
1170
+ var ConfiguratorRuleSchema = z4.discriminatedUnion("kind", [
984
1171
  /** Show `param` only while `when` holds. */
985
- z2.strictObject({
986
- kind: z2.literal("visible"),
1172
+ z4.strictObject({
1173
+ kind: z4.literal("visible"),
987
1174
  param: ConfiguratorNameSchema,
988
1175
  when: ConfiguratorConditionSchema
989
1176
  }),
990
1177
  /** Narrow a number parameter: `max cabinet_height = total_height - 300`. */
991
- z2.strictObject({
992
- kind: z2.literal("limit"),
1178
+ z4.strictObject({
1179
+ kind: z4.literal("limit"),
993
1180
  param: ConfiguratorNameSchema,
994
- bound: z2.enum(["min", "max"]),
1181
+ bound: z4.enum(["min", "max"]),
995
1182
  formula: FormulaSchema
996
1183
  }),
997
1184
  /** While `when` holds, these codes of a choice or material are not offered. */
998
- z2.strictObject({
999
- kind: z2.literal("exclude"),
1185
+ z4.strictObject({
1186
+ kind: z4.literal("exclude"),
1000
1187
  param: ConfiguratorNameSchema,
1001
- codes: z2.array(ConfiguratorCodeSchema).min(1).max(CONFIGURATOR_LIMITS.optionsPerList),
1188
+ codes: z4.array(ConfiguratorCodeSchema).min(1).max(CONFIGURATOR_LIMITS.optionsPerList),
1002
1189
  when: ConfiguratorConditionSchema
1003
1190
  })
1004
1191
  ]);
@@ -1008,23 +1195,23 @@ var PriceRuleBase = {
1008
1195
  /** How many times the amount counts, e.g. `compartments`. Absent is once. */
1009
1196
  multiplier: FormulaSchema.optional()
1010
1197
  };
1011
- var ConfiguratorPriceRuleSchema = z2.discriminatedUnion("kind", [
1198
+ var ConfiguratorPriceRuleSchema = z4.discriminatedUnion("kind", [
1012
1199
  /** The surcharge the model gives the chosen option. */
1013
- z2.strictObject({
1200
+ z4.strictObject({
1014
1201
  ...PriceRuleBase,
1015
- kind: z2.literal("choice"),
1202
+ kind: z4.literal("choice"),
1016
1203
  param: ConfiguratorNameSchema
1017
1204
  }),
1018
1205
  /** The surcharge of the chosen material's price group. */
1019
- z2.strictObject({
1206
+ z4.strictObject({
1020
1207
  ...PriceRuleBase,
1021
- kind: z2.literal("material"),
1208
+ kind: z4.literal("material"),
1022
1209
  param: ConfiguratorNameSchema
1023
1210
  }),
1024
1211
  /** An amount, counted while a switch is on. */
1025
- z2.strictObject({
1212
+ z4.strictObject({
1026
1213
  ...PriceRuleBase,
1027
- kind: z2.literal("toggle"),
1214
+ kind: z4.literal("toggle"),
1028
1215
  param: ConfiguratorNameSchema,
1029
1216
  amount: ConfiguratorNameSchema
1030
1217
  }),
@@ -1032,10 +1219,10 @@ var ConfiguratorPriceRuleSchema = z2.discriminatedUnion("kind", [
1032
1219
  * A price on measure: `max(0, total_width - 1800) / 1000 * meter_price`.
1033
1220
  * Reads number parameters (in their unit) and amounts (in cents).
1034
1221
  */
1035
- z2.strictObject({
1222
+ z4.strictObject({
1036
1223
  key: ConfiguratorNameSchema,
1037
1224
  label: LabelSchema,
1038
- kind: z2.literal("formula"),
1225
+ kind: z4.literal("formula"),
1039
1226
  formula: FormulaSchema
1040
1227
  })
1041
1228
  ]);
@@ -1045,73 +1232,73 @@ var CONFIGURATOR_SCENE_LIGHTINGS = [
1045
1232
  "daylight"
1046
1233
  ];
1047
1234
  var CONFIGURATOR_SCENE_EDGES = ["soft", "sharp"];
1048
- var RoomColorSchema = z2.strictObject({
1235
+ var RoomColorSchema = z4.strictObject({
1049
1236
  code: ConfiguratorCodeSchema,
1050
1237
  label: LabelSchema,
1051
- color: z2.string().regex(/^#[0-9a-f]{6}$/i, "configurator.invalidColor")
1238
+ color: z4.string().regex(/^#[0-9a-f]{6}$/i, "configurator.invalidColor")
1052
1239
  });
1053
- var roomSurfaceSchema = (max) => z2.strictObject({
1240
+ var roomSurfaceSchema = (max) => z4.strictObject({
1054
1241
  /** The code shown first; absent is the first option. */
1055
1242
  default: ConfiguratorCodeSchema.optional(),
1056
1243
  /** Absent offers the package's own palette (`room-palette.ts`). */
1057
- options: z2.array(RoomColorSchema).min(1).max(max).optional()
1244
+ options: z4.array(RoomColorSchema).min(1).max(max).optional()
1058
1245
  });
1059
- var ConfiguratorRoomSchema = z2.strictObject({
1246
+ var ConfiguratorRoomSchema = z4.strictObject({
1060
1247
  wall: roomSurfaceSchema(CONFIGURATOR_LIMITS.roomWallOptions).optional(),
1061
1248
  floor: roomSurfaceSchema(CONFIGURATOR_LIMITS.roomFloorOptions).optional(),
1062
1249
  /** Millimetres of room beside the furniture on each side; 1500 by default. */
1063
- margin: z2.number().min(0).max(5e3).optional(),
1250
+ margin: z4.number().min(0).max(5e3).optional(),
1064
1251
  /** Millimetres of floor in front of the wall; 3500 by default. */
1065
- depth: z2.number().min(1e3).max(1e4).optional()
1252
+ depth: z4.number().min(1e3).max(1e4).optional()
1066
1253
  });
1067
- var ConfiguratorSceneSchema = z2.strictObject({
1068
- lighting: z2.enum(CONFIGURATOR_SCENE_LIGHTINGS).optional(),
1069
- edges: z2.enum(CONFIGURATOR_SCENE_EDGES).optional(),
1254
+ var ConfiguratorSceneSchema = z4.strictObject({
1255
+ lighting: z4.enum(CONFIGURATOR_SCENE_LIGHTINGS).optional(),
1256
+ edges: z4.enum(CONFIGURATOR_SCENE_EDGES).optional(),
1070
1257
  room: ConfiguratorRoomSchema.optional()
1071
1258
  });
1072
- var FocusNameSchema = z2.string().regex(/^[a-z][a-z0-9_]{0,39}$/, "configurator.invalidName");
1073
- var ConfiguratorFocusSchema = z2.strictObject({
1259
+ var FocusNameSchema = z4.string().regex(/^[a-z][a-z0-9_]{0,39}$/, "configurator.invalidName");
1260
+ var ConfiguratorFocusSchema = z4.strictObject({
1074
1261
  param: ConfiguratorNameSchema,
1075
1262
  when: ConfiguratorConditionSchema.optional(),
1076
- open: z2.array(FocusNameSchema).max(CONFIGURATOR_LIMITS.focusNames).optional(),
1077
- frame: z2.array(FocusNameSchema).min(1).max(CONFIGURATOR_LIMITS.focusNames).optional(),
1078
- night: z2.boolean().optional()
1263
+ open: z4.array(FocusNameSchema).max(CONFIGURATOR_LIMITS.focusNames).optional(),
1264
+ frame: z4.array(FocusNameSchema).min(1).max(CONFIGURATOR_LIMITS.focusNames).optional(),
1265
+ night: z4.boolean().optional()
1079
1266
  });
1080
- var structureObjectSchema = (files) => z2.strictObject({
1081
- schemaVersion: z2.literal(1),
1267
+ var structureObjectSchema = (files) => z4.strictObject({
1268
+ schemaVersion: z4.literal(1),
1082
1269
  geometry: geometryDocumentSchema(files.model),
1083
1270
  /**
1084
1271
  * How the scene is presented. Part of the structure and not of the shape
1085
1272
  * document, so the owner sets it under `crm.manage` like a material.
1086
1273
  */
1087
1274
  scene: ConfiguratorSceneSchema.optional(),
1088
- tabs: z2.array(
1089
- z2.strictObject({ key: ConfiguratorNameSchema, label: LabelSchema })
1275
+ tabs: z4.array(
1276
+ z4.strictObject({ key: ConfiguratorNameSchema, label: LabelSchema })
1090
1277
  ).min(1).max(CONFIGURATOR_LIMITS.tabs),
1091
- parameters: z2.array(ConfiguratorParameterSchema).max(CONFIGURATOR_LIMITS.parameters),
1092
- choiceLists: z2.array(choiceListSchema(files.picture)).max(CONFIGURATOR_LIMITS.choiceLists),
1093
- materials: z2.array(materialSchema(files.picture)).max(CONFIGURATOR_LIMITS.materials),
1094
- priceGroups: z2.array(
1095
- z2.strictObject({ code: ConfiguratorCodeSchema, label: LabelSchema })
1278
+ parameters: z4.array(ConfiguratorParameterSchema).max(CONFIGURATOR_LIMITS.parameters),
1279
+ choiceLists: z4.array(choiceListSchema(files.picture)).max(CONFIGURATOR_LIMITS.choiceLists),
1280
+ materials: z4.array(materialSchema(files.picture)).max(CONFIGURATOR_LIMITS.materials),
1281
+ priceGroups: z4.array(
1282
+ z4.strictObject({ code: ConfiguratorCodeSchema, label: LabelSchema })
1096
1283
  ).max(CONFIGURATOR_LIMITS.priceGroups),
1097
1284
  /** Named amounts a model fills in and price rules read (`meter_price`). */
1098
- amounts: z2.array(
1099
- z2.strictObject({ key: ConfiguratorNameSchema, label: LabelSchema })
1285
+ amounts: z4.array(
1286
+ z4.strictObject({ key: ConfiguratorNameSchema, label: LabelSchema })
1100
1287
  ).max(CONFIGURATOR_LIMITS.amounts),
1101
1288
  /**
1102
1289
  * A list of fixed combinations a model offers, each setting some number
1103
1290
  * parameters at once: a fireplace and the niche it needs.
1104
1291
  */
1105
- presets: z2.strictObject({
1292
+ presets: z4.strictObject({
1106
1293
  label: LabelSchema,
1107
1294
  tab: ConfiguratorNameSchema,
1108
- sets: z2.array(ConfiguratorNameSchema).min(1).max(CONFIGURATOR_LIMITS.parameters),
1109
- required: z2.boolean()
1295
+ sets: z4.array(ConfiguratorNameSchema).min(1).max(CONFIGURATOR_LIMITS.parameters),
1296
+ required: z4.boolean()
1110
1297
  }).optional(),
1111
- rules: z2.array(ConfiguratorRuleSchema).max(CONFIGURATOR_LIMITS.rules),
1298
+ rules: z4.array(ConfiguratorRuleSchema).max(CONFIGURATOR_LIMITS.rules),
1112
1299
  /** What the picture opens and looks at when a choice changes. */
1113
- focus: z2.array(ConfiguratorFocusSchema).max(CONFIGURATOR_LIMITS.focus).optional(),
1114
- priceRules: z2.array(ConfiguratorPriceRuleSchema).max(CONFIGURATOR_LIMITS.priceRules)
1300
+ focus: z4.array(ConfiguratorFocusSchema).max(CONFIGURATOR_LIMITS.focus).optional(),
1301
+ priceRules: z4.array(ConfiguratorPriceRuleSchema).max(CONFIGURATOR_LIMITS.priceRules)
1115
1302
  });
1116
1303
  var ConfiguratorStructureObjectSchema = structureObjectSchema({
1117
1304
  picture: TexturePathSchema,
@@ -1599,55 +1786,55 @@ function parameterResolutionOrder(structure) {
1599
1786
  }
1600
1787
 
1601
1788
  // ../features/product-configurator/src/shared/configurator-value.schema.ts
1602
- import { z as z3 } from "zod";
1603
- var CentsSchema = z3.number().int().min(0).max(1e8);
1789
+ import { z as z5 } from "zod";
1790
+ var CentsSchema = z5.number().int().min(0).max(1e8);
1604
1791
  var PriceSchema = CentsSchema.nullable();
1605
- var ConfiguratorValueObjectSchema = z3.strictObject({
1792
+ var ConfiguratorValueObjectSchema = z5.strictObject({
1606
1793
  /** Null: the model has no price of its own, every quote is "open". */
1607
1794
  basePriceCents: PriceSchema,
1608
- numbers: z3.record(
1795
+ numbers: z5.record(
1609
1796
  ConfiguratorNameSchema,
1610
- z3.strictObject({
1611
- min: z3.number().finite(),
1612
- max: z3.number().finite(),
1613
- default: z3.number().finite()
1797
+ z5.strictObject({
1798
+ min: z5.number().finite(),
1799
+ max: z5.number().finite(),
1800
+ default: z5.number().finite()
1614
1801
  })
1615
1802
  ).default({}),
1616
1803
  /** Per choice list: the options this model offers, with their surcharge. */
1617
- choices: z3.record(
1804
+ choices: z5.record(
1618
1805
  ConfiguratorNameSchema,
1619
- z3.strictObject({
1620
- options: z3.record(
1806
+ z5.strictObject({
1807
+ options: z5.record(
1621
1808
  ConfiguratorCodeSchema,
1622
- z3.strictObject({ priceCents: PriceSchema })
1809
+ z5.strictObject({ priceCents: PriceSchema })
1623
1810
  ),
1624
1811
  default: ConfiguratorCodeSchema.optional()
1625
1812
  })
1626
1813
  ).default({}),
1627
1814
  /** Per material parameter: the materials this model offers. */
1628
- materials: z3.record(
1815
+ materials: z5.record(
1629
1816
  ConfiguratorNameSchema,
1630
- z3.strictObject({
1631
- offered: z3.array(ConfiguratorCodeSchema).max(CONFIGURATOR_LIMITS.materials),
1817
+ z5.strictObject({
1818
+ offered: z5.array(ConfiguratorCodeSchema).max(CONFIGURATOR_LIMITS.materials),
1632
1819
  default: ConfiguratorCodeSchema.optional()
1633
1820
  })
1634
1821
  ).default({}),
1635
1822
  /** Per switch: whether this model offers it, and how it starts. Absent is offered, off. */
1636
- toggles: z3.record(
1823
+ toggles: z5.record(
1637
1824
  ConfiguratorNameSchema,
1638
- z3.strictObject({ offered: z3.boolean(), default: z3.boolean() })
1825
+ z5.strictObject({ offered: z5.boolean(), default: z5.boolean() })
1639
1826
  ).default({}),
1640
1827
  /** The surcharge of each material price group. */
1641
- priceGroups: z3.record(ConfiguratorCodeSchema, PriceSchema).default({}),
1828
+ priceGroups: z5.record(ConfiguratorCodeSchema, PriceSchema).default({}),
1642
1829
  /** The amounts the structure names, such as a price per metre. */
1643
- amounts: z3.record(ConfiguratorNameSchema, PriceSchema).default({}),
1644
- presets: z3.array(
1645
- z3.strictObject({
1830
+ amounts: z5.record(ConfiguratorNameSchema, PriceSchema).default({}),
1831
+ presets: z5.array(
1832
+ z5.strictObject({
1646
1833
  code: ConfiguratorCodeSchema,
1647
- label: z3.string().trim().min(1).max(80),
1834
+ label: z5.string().trim().min(1).max(80),
1648
1835
  /** A product of the same account this preset stands for, e.g. the fireplace. */
1649
- productId: z3.string().uuid().nullable(),
1650
- values: z3.record(ConfiguratorNameSchema, z3.number().finite())
1836
+ productId: z5.string().uuid().nullable(),
1837
+ values: z5.record(ConfiguratorNameSchema, z5.number().finite())
1651
1838
  })
1652
1839
  ).max(CONFIGURATOR_LIMITS.presets).default([])
1653
1840
  });
@@ -2148,13 +2335,13 @@ var PRODUCT_OPTION_LIMITS = {
2148
2335
  choicesBytes: 8 * 1024,
2149
2336
  maxSurchargeCents: 1e8
2150
2337
  };
2151
- var KeySchema = z4.string().regex(/^[a-z0-9_]{1,40}$/, {
2338
+ var KeySchema = z6.string().regex(/^[a-z0-9_]{1,40}$/, {
2152
2339
  // i18n-exempt: returned verbatim to an integration's own code, never rendered in this app's UI
2153
2340
  message: "A key is 1 to 40 lower-case letters, digits or underscores"
2154
2341
  });
2155
- var LabelSchema2 = z4.string().trim().min(1).max(PRODUCT_OPTION_LIMITS.labelLength);
2156
- var SurchargeSchema = z4.number().int().min(0).max(PRODUCT_OPTION_LIMITS.maxSurchargeCents);
2157
- var ProductOptionChoiceSchema = z4.object({
2342
+ var LabelSchema2 = z6.string().trim().min(1).max(PRODUCT_OPTION_LIMITS.labelLength);
2343
+ var SurchargeSchema = z6.number().int().min(0).max(PRODUCT_OPTION_LIMITS.maxSurchargeCents);
2344
+ var ProductOptionChoiceSchema = z6.object({
2158
2345
  key: KeySchema,
2159
2346
  label: LabelSchema2,
2160
2347
  surchargeCents: SurchargeSchema
@@ -2162,26 +2349,26 @@ var ProductOptionChoiceSchema = z4.object({
2162
2349
  var OptionFields = {
2163
2350
  key: KeySchema,
2164
2351
  label: LabelSchema2,
2165
- helpText: z4.string().trim().max(PRODUCT_OPTION_LIMITS.helpTextLength).nullable().default(null),
2166
- required: z4.boolean().default(false),
2167
- surchargePerUnit: z4.boolean().default(true)
2352
+ helpText: z6.string().trim().max(PRODUCT_OPTION_LIMITS.helpTextLength).nullable().default(null),
2353
+ required: z6.boolean().default(false),
2354
+ surchargePerUnit: z6.boolean().default(true)
2168
2355
  };
2169
- var ProductOptionSchema = z4.discriminatedUnion("kind", [
2170
- z4.object({
2356
+ var ProductOptionSchema = z6.discriminatedUnion("kind", [
2357
+ z6.object({
2171
2358
  ...OptionFields,
2172
- kind: z4.literal("text"),
2173
- maxLength: z4.number().int().min(1).max(PRODUCT_OPTION_LIMITS.textLength),
2359
+ kind: z6.literal("text"),
2360
+ maxLength: z6.number().int().min(1).max(PRODUCT_OPTION_LIMITS.textLength),
2174
2361
  surchargeCents: SurchargeSchema.default(0)
2175
2362
  }),
2176
- z4.object({
2363
+ z6.object({
2177
2364
  ...OptionFields,
2178
- kind: z4.literal("checkbox"),
2365
+ kind: z6.literal("checkbox"),
2179
2366
  surchargeCents: SurchargeSchema.default(0)
2180
2367
  }),
2181
- z4.object({
2368
+ z6.object({
2182
2369
  ...OptionFields,
2183
- kind: z4.literal("choice"),
2184
- choices: z4.array(ProductOptionChoiceSchema).min(PRODUCT_OPTION_LIMITS.minChoices).max(PRODUCT_OPTION_LIMITS.maxChoices)
2370
+ kind: z6.literal("choice"),
2371
+ choices: z6.array(ProductOptionChoiceSchema).min(PRODUCT_OPTION_LIMITS.minChoices).max(PRODUCT_OPTION_LIMITS.maxChoices)
2185
2372
  })
2186
2373
  ]).superRefine((option, context) => {
2187
2374
  if (option.kind !== "choice") {
@@ -2205,7 +2392,7 @@ var ProductOptionSchema = z4.discriminatedUnion("kind", [
2205
2392
  });
2206
2393
  }
2207
2394
  });
2208
- var ProductOptionsSchema = z4.array(ProductOptionSchema).max(PRODUCT_OPTION_LIMITS.options).superRefine((options, context) => {
2395
+ var ProductOptionsSchema = z6.array(ProductOptionSchema).max(PRODUCT_OPTION_LIMITS.options).superRefine((options, context) => {
2209
2396
  const keys = options.map((option) => option.key);
2210
2397
  if (new Set(keys).size !== keys.length) {
2211
2398
  context.addIssue({
@@ -2232,47 +2419,47 @@ var MAX_AMOUNT_CENTS = 99999999;
2232
2419
  // ../features/crm-invoicing/src/schema/catalog-api.schema.ts
2233
2420
  var WEB_SLUG = /^[a-z0-9]+(-[a-z0-9]+)*$/;
2234
2421
  var FIELD_SLUG = /^[a-z][a-z0-9_]*$/;
2235
- var CatalogSourceSchema = z5.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/, {
2422
+ var CatalogSourceSchema = z7.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/, {
2236
2423
  message: (
2237
2424
  // i18n-exempt: a public API's field error, returned verbatim to an integration's own code and never shown in this app
2238
2425
  'A source is lower-case letters, digits and hyphens, at most 64 characters (for example "coolflames-payload").'
2239
2426
  )
2240
2427
  });
2241
- var CatalogExternalRefSchema = z5.string().trim().min(1).max(255);
2242
- var CatalogWebSlugSchema = z5.string().min(2).max(64).regex(WEB_SLUG, {
2428
+ var CatalogExternalRefSchema = z7.string().trim().min(1).max(255);
2429
+ var CatalogWebSlugSchema = z7.string().min(2).max(64).regex(WEB_SLUG, {
2243
2430
  // i18n-exempt: a public API's field error, returned verbatim to an integration's own code and never shown in this app
2244
2431
  message: "An address is lower-case letters and digits joined by hyphens."
2245
2432
  });
2246
- var CatalogFieldSlugSchema = z5.string().max(63).regex(FIELD_SLUG, {
2433
+ var CatalogFieldSlugSchema = z7.string().max(63).regex(FIELD_SLUG, {
2247
2434
  message: (
2248
2435
  // i18n-exempt: a public API's field error, returned verbatim to an integration's own code and never shown in this app
2249
2436
  "A field slug starts with a letter and holds lower-case letters, digits and underscores."
2250
2437
  )
2251
2438
  });
2252
- var cents = z5.number().int().min(0).max(MAX_AMOUNT_CENTS);
2253
- var CatalogCategoryPlacementSchema = z5.object({
2439
+ var cents = z7.number().int().min(0).max(MAX_AMOUNT_CENTS);
2440
+ var CatalogCategoryPlacementSchema = z7.object({
2254
2441
  slug: CatalogWebSlugSchema,
2255
2442
  /** Lowest first; equal places stand in id order. */
2256
- position: z5.number().int().min(-1e6).max(1e6).optional()
2443
+ position: z7.number().int().min(-1e6).max(1e6).optional()
2257
2444
  }).strict();
2258
- var text = (max) => z5.string().trim().max(max).nullable().optional();
2259
- var CatalogPriceSchema = z5.object({
2445
+ var text = (max) => z7.string().trim().max(max).nullable().optional();
2446
+ var CatalogPriceSchema = z7.object({
2260
2447
  /** The price's own id at the source, so a renamed price stays itself. */
2261
2448
  externalRef: CatalogExternalRefSchema.optional(),
2262
- label: z5.string().trim().min(1).max(120),
2449
+ label: z7.string().trim().min(1).max(120),
2263
2450
  /**
2264
2451
  * ISO 4217. Left out, the price is in the product's own currency. A
2265
2452
  * price in another currency is the fixed price for that currency: it
2266
2453
  * wins over a converted one and is never the default.
2267
2454
  */
2268
- currency: z5.string().regex(/^[A-Z]{3}$/).optional(),
2455
+ currency: z7.string().regex(/^[A-Z]{3}$/).optional(),
2269
2456
  amountCents: cents,
2270
2457
  compareAtCents: cents.nullable().optional(),
2271
- kind: z5.enum(["one_off", "recurring"]).optional(),
2272
- recurringInterval: z5.enum(["day", "week", "month", "year"]).optional(),
2273
- recurringIntervalCount: z5.number().int().min(1).max(365).optional(),
2274
- isDefault: z5.boolean().optional(),
2275
- active: z5.boolean().optional()
2458
+ kind: z7.enum(["one_off", "recurring"]).optional(),
2459
+ recurringInterval: z7.enum(["day", "week", "month", "year"]).optional(),
2460
+ recurringIntervalCount: z7.number().int().min(1).max(365).optional(),
2461
+ isDefault: z7.boolean().optional(),
2462
+ active: z7.boolean().optional()
2276
2463
  }).strict().superRefine((price, ctx) => {
2277
2464
  if ((price.kind ?? "one_off") === "recurring" && !price.recurringInterval) {
2278
2465
  ctx.addIssue({
@@ -2283,7 +2470,7 @@ var CatalogPriceSchema = z5.object({
2283
2470
  });
2284
2471
  }
2285
2472
  });
2286
- var pricesSchema = z5.array(CatalogPriceSchema).min(1).max(50).superRefine((prices, ctx) => {
2473
+ var pricesSchema = z7.array(CatalogPriceSchema).min(1).max(50).superRefine((prices, ctx) => {
2287
2474
  if (prices.filter((price) => price.isDefault).length > 1) {
2288
2475
  ctx.addIssue({
2289
2476
  code: "custom",
@@ -2312,24 +2499,24 @@ var pricesSchema = z5.array(CatalogPriceSchema).min(1).max(50).superRefine((pric
2312
2499
  });
2313
2500
  }
2314
2501
  });
2315
- var HttpsUrlSchema = z5.string().max(2048).url().refine((url) => url.startsWith("https://"), {
2502
+ var HttpsUrlSchema = z7.string().max(2048).url().refine((url) => url.startsWith("https://"), {
2316
2503
  // i18n-exempt: a public API's field error, returned verbatim to an integration's own code and never shown in this app
2317
2504
  message: "A file is fetched over https only."
2318
2505
  });
2319
- var UploadPathSchema = z5.string().min(1).max(200);
2320
- var CatalogFileRefSchema = z5.union([
2321
- z5.object({ url: HttpsUrlSchema }).strict(),
2322
- z5.object({ upload: UploadPathSchema }).strict()
2506
+ var UploadPathSchema = z7.string().min(1).max(200);
2507
+ var CatalogFileRefSchema = z7.union([
2508
+ z7.object({ url: HttpsUrlSchema }).strict(),
2509
+ z7.object({ upload: UploadPathSchema }).strict()
2323
2510
  ]);
2324
2511
  var IMAGE_ROLE = /^[a-z][a-z0-9_-]{0,31}$/;
2325
- var CatalogImageDetailsSchema = z5.record(
2326
- z5.string().min(1).max(64),
2327
- z5.union([z5.string().max(500), z5.number().finite(), z5.boolean()])
2512
+ var CatalogImageDetailsSchema = z7.record(
2513
+ z7.string().min(1).max(64),
2514
+ z7.union([z7.string().max(500), z7.number().finite(), z7.boolean()])
2328
2515
  ).refine((details) => JSON.stringify(details).length <= 1800, {
2329
2516
  // i18n-exempt: a public API's field error, returned verbatim to an integration's own code and never shown in this app
2330
2517
  message: "Details are at most about 2 KB."
2331
2518
  });
2332
- var CatalogImageSchema = z5.object({
2519
+ var CatalogImageSchema = z7.object({
2333
2520
  url: HttpsUrlSchema.optional(),
2334
2521
  upload: UploadPathSchema.optional(),
2335
2522
  alt: text(300),
@@ -2337,7 +2524,7 @@ var CatalogImageSchema = z5.object({
2337
2524
  * What the picture is of, in the account's own words: `work`, `detail`,
2338
2525
  * `insitu`. Left out keeps the role a stored picture has; `null` clears it.
2339
2526
  */
2340
- role: z5.string().regex(IMAGE_ROLE, {
2527
+ role: z7.string().regex(IMAGE_ROLE, {
2341
2528
  message: (
2342
2529
  // i18n-exempt: a public API's field error, returned verbatim to an integration's own code and never shown in this app
2343
2530
  "A role starts with a letter and holds lower-case letters, digits, hyphens and underscores, at most 32."
@@ -2351,33 +2538,33 @@ var CatalogImageSchema = z5.object({
2351
2538
  message: "A picture names either a url or an upload, not both."
2352
2539
  }
2353
2540
  );
2354
- var CatalogStockSchema = z5.object({
2355
- managed: z5.boolean(),
2541
+ var CatalogStockSchema = z7.object({
2542
+ managed: z7.boolean(),
2356
2543
  /** Left out, the count stays as it is. */
2357
- quantity: z5.number().int().min(0).max(1e9).optional(),
2544
+ quantity: z7.number().int().min(0).max(1e9).optional(),
2358
2545
  /** Below this a product counts as running low; `null` warns never. */
2359
- lowThreshold: z5.number().int().min(0).max(1e9).nullable().optional(),
2546
+ lowThreshold: z7.number().int().min(0).max(1e9).nullable().optional(),
2360
2547
  /** Whether it can still be ordered at zero: `deny`, `allow`, or `allow_notify`. */
2361
- backorders: z5.enum(["deny", "allow", "allow_notify"]).optional()
2548
+ backorders: z7.enum(["deny", "allow", "allow_notify"]).optional()
2362
2549
  }).strict();
2363
- var CatalogVariantAxisSchema = z5.object({
2550
+ var CatalogVariantAxisSchema = z7.object({
2364
2551
  slug: CatalogFieldSlugSchema,
2365
- label: z5.string().trim().min(1).max(120).optional()
2552
+ label: z7.string().trim().min(1).max(120).optional()
2366
2553
  }).strict();
2367
- var CatalogVariantSchema = z5.object({
2554
+ var CatalogVariantSchema = z7.object({
2368
2555
  externalRef: CatalogExternalRefSchema,
2369
2556
  /** The value per axis, keyed by the axis slug. */
2370
- options: z5.record(
2557
+ options: z7.record(
2371
2558
  CatalogFieldSlugSchema,
2372
- z5.string().trim().min(1).max(120)
2559
+ z7.string().trim().min(1).max(120)
2373
2560
  ),
2374
2561
  sku: text(100),
2375
- gtin: z5.string().regex(/^[0-9]{8,14}$/).nullable().optional(),
2562
+ gtin: z7.string().regex(/^[0-9]{8,14}$/).nullable().optional(),
2376
2563
  prices: pricesSchema.optional(),
2377
2564
  /** The variant's own shelf; a physical product counts per variant. */
2378
2565
  stock: CatalogStockSchema.optional(),
2379
- position: z5.number().int().min(0).max(1e4).optional(),
2380
- active: z5.boolean().optional()
2566
+ position: z7.number().int().min(0).max(1e4).optional(),
2567
+ active: z7.boolean().optional()
2381
2568
  }).strict();
2382
2569
  var CATALOG_AVAILABILITIES = [
2383
2570
  "draft",
@@ -2385,26 +2572,26 @@ var CATALOG_AVAILABILITIES = [
2385
2572
  "scheduled",
2386
2573
  "public"
2387
2574
  ];
2388
- var CatalogProductUpsertSchema = z5.object({
2575
+ var CatalogProductUpsertSchema = z7.object({
2389
2576
  source: CatalogSourceSchema,
2390
2577
  /** Required to create a product; optional to update one. */
2391
- name: z5.string().trim().min(1).max(500).optional(),
2578
+ name: z7.string().trim().min(1).max(500).optional(),
2392
2579
  slug: CatalogWebSlugSchema.nullable().optional(),
2393
2580
  description: text(5e3),
2394
2581
  /** HTML; cleaned against the same allow-list the app uses. */
2395
2582
  longDescription: text(1e5),
2396
2583
  sku: text(100),
2397
- gtin: z5.string().regex(/^[0-9]{8,14}$/).nullable().optional(),
2398
- productType: z5.enum(["digital", "physical"]).optional(),
2584
+ gtin: z7.string().regex(/^[0-9]{8,14}$/).nullable().optional(),
2585
+ productType: z7.enum(["digital", "physical"]).optional(),
2399
2586
  /**
2400
2587
  * Where the product stands. A new product is a `draft` unless this says
2401
2588
  * otherwise -- an import should not put a hundred products on somebody's
2402
2589
  * website because a run finished.
2403
2590
  */
2404
- availability: z5.enum(CATALOG_AVAILABILITIES).optional(),
2591
+ availability: z7.enum(CATALOG_AVAILABILITIES).optional(),
2405
2592
  /** The moment for `scheduled`; ignored for the other three. */
2406
- publishedAt: z5.string().datetime({ offset: true }).nullable().optional(),
2407
- visibility: z5.enum(["public", "unlisted"]).optional(),
2593
+ publishedAt: z7.string().datetime({ offset: true }).nullable().optional(),
2594
+ visibility: z7.enum(["public", "unlisted"]).optional(),
2408
2595
  metaTitle: text(300),
2409
2596
  metaDescription: text(1e3),
2410
2597
  /**
@@ -2422,21 +2609,21 @@ var CatalogProductUpsertSchema = z5.object({
2422
2609
  * product stands on that category's page (`?sort=position`, lowest
2423
2610
  * first); a plain slug leaves a stored place as it is.
2424
2611
  */
2425
- categories: z5.array(z5.union([CatalogWebSlugSchema, CatalogCategoryPlacementSchema])).max(50).optional(),
2612
+ categories: z7.array(z7.union([CatalogWebSlugSchema, CatalogCategoryPlacementSchema])).max(50).optional(),
2426
2613
  /**
2427
2614
  * Make a category that does not exist yet instead of refusing. Off unless
2428
2615
  * asked for, so a typo cannot become a category on a customer's website.
2429
2616
  */
2430
- createMissingCategories: z5.boolean().optional(),
2617
+ createMissingCategories: z7.boolean().optional(),
2431
2618
  /** Field values by field slug; `null` empties one field. */
2432
- fields: z5.record(CatalogFieldSlugSchema, z5.unknown()).optional(),
2619
+ fields: z7.record(CatalogFieldSlugSchema, z7.unknown()).optional(),
2433
2620
  /** Which fields the product's own page shows, in that order. */
2434
- publicFields: z5.array(CatalogFieldSlugSchema).max(100).optional(),
2621
+ publicFields: z7.array(CatalogFieldSlugSchema).max(100).optional(),
2435
2622
  /**
2436
2623
  * Add a choice a select field does not offer yet instead of refusing.
2437
2624
  * Off unless asked for, for the same reason as categories.
2438
2625
  */
2439
- addMissingOptions: z5.boolean().optional(),
2626
+ addMissingOptions: z7.boolean().optional(),
2440
2627
  /** Replaces the product's prices as a whole. */
2441
2628
  prices: pricesSchema.optional(),
2442
2629
  /**
@@ -2445,29 +2632,29 @@ var CatalogProductUpsertSchema = z5.object({
2445
2632
  */
2446
2633
  stock: CatalogStockSchema.optional(),
2447
2634
  /** Replaces the product's pictures, in this order. */
2448
- images: z5.array(CatalogImageSchema).max(20).optional(),
2449
- variantAxes: z5.array(CatalogVariantAxisSchema).min(1).max(3).optional(),
2635
+ images: z7.array(CatalogImageSchema).max(20).optional(),
2636
+ variantAxes: z7.array(CatalogVariantAxisSchema).min(1).max(3).optional(),
2450
2637
  /** Replaces the product's variants; one missing here is archived. */
2451
- variants: z5.array(CatalogVariantSchema).max(100).optional(),
2638
+ variants: z7.array(CatalogVariantSchema).max(100).optional(),
2452
2639
  /** `false` brings back a product the API archived earlier. */
2453
- archived: z5.literal(false).optional(),
2640
+ archived: z7.literal(false).optional(),
2454
2641
  /**
2455
2642
  * Sold only as an extra with another product -- a warranty, assembly --
2456
2643
  * and how: at most `maxQuantity` per piece or per line, following the
2457
2644
  * quantity of its line (`perPiece`), and whether only the team adds it
2458
2645
  * (`teamOnly`). `null` makes it a product of its own again.
2459
2646
  */
2460
- soldAsExtra: z5.object({
2461
- maxQuantity: z5.number().int().min(1).max(99).default(1),
2462
- perPiece: z5.boolean().default(false),
2463
- teamOnly: z5.boolean().default(false)
2647
+ soldAsExtra: z7.object({
2648
+ maxQuantity: z7.number().int().min(1).max(99).default(1),
2649
+ perPiece: z7.boolean().default(false),
2650
+ teamOnly: z7.boolean().default(false)
2464
2651
  }).strict().nullable().optional(),
2465
2652
  /**
2466
2653
  * Replaces what may be taken with this product, in this order: each the
2467
2654
  * `externalRef` of another product of the same source and the same
2468
2655
  * catalogue. `[]` takes them all off.
2469
2656
  */
2470
- extras: z5.array(CatalogExternalRefSchema).max(50).optional(),
2657
+ extras: z7.array(CatalogExternalRefSchema).max(50).optional(),
2471
2658
  /**
2472
2659
  * Replaces what a buyer chooses or types on this product, with a
2473
2660
  * surcharge in the account's own currency (`ProductOptionsSchema`).
@@ -2546,8 +2733,8 @@ var CatalogProductUpsertSchema = z5.object({
2546
2733
  });
2547
2734
  }
2548
2735
  });
2549
- var CatalogProductArchiveSchema = z5.object({ source: CatalogSourceSchema }).strict();
2550
- var CatalogCategoryUpsertSchema = z5.object({
2736
+ var CatalogProductArchiveSchema = z7.object({ source: CatalogSourceSchema }).strict();
2737
+ var CatalogCategoryUpsertSchema = z7.object({
2551
2738
  /**
2552
2739
  * The category's id in the system it came from -- a series in a site's
2553
2740
  * own CMS -- with `source` naming whose id it is. With both, a category
@@ -2557,12 +2744,12 @@ var CatalogCategoryUpsertSchema = z5.object({
2557
2744
  */
2558
2745
  source: CatalogSourceSchema.optional(),
2559
2746
  externalRef: CatalogExternalRefSchema.optional(),
2560
- name: z5.string().trim().min(1).max(200).optional(),
2747
+ name: z7.string().trim().min(1).max(200).optional(),
2561
2748
  description: text(5e3),
2562
2749
  /** `null` puts the category at the top of the tree. */
2563
2750
  parentSlug: CatalogWebSlugSchema.nullable().optional(),
2564
- availability: z5.enum(CATALOG_AVAILABILITIES).optional(),
2565
- publishedAt: z5.string().datetime({ offset: true }).nullable().optional(),
2751
+ availability: z7.enum(CATALOG_AVAILABILITIES).optional(),
2752
+ publishedAt: z7.string().datetime({ offset: true }).nullable().optional(),
2566
2753
  metaTitle: text(300),
2567
2754
  metaDescription: text(1e3)
2568
2755
  }).strict().refine(
@@ -2573,19 +2760,19 @@ var CatalogCategoryUpsertSchema = z5.object({
2573
2760
  message: "A category reference names both source and externalRef."
2574
2761
  }
2575
2762
  );
2576
- var CatalogObjectSlugSchema = z5.string().max(64).regex(FIELD_SLUG, {
2763
+ var CatalogObjectSlugSchema = z7.string().max(64).regex(FIELD_SLUG, {
2577
2764
  message: (
2578
2765
  // i18n-exempt: a public API's field error, returned verbatim to an integration's own code and never shown in this app
2579
2766
  "A catalogue slug starts with a letter and holds lower-case letters, digits and underscores."
2580
2767
  )
2581
2768
  });
2582
- var CatalogCatalogueUpsertSchema = z5.object({
2583
- nameSingular: z5.string().trim().min(1).max(120).optional(),
2584
- namePlural: z5.string().trim().min(1).max(120).optional(),
2769
+ var CatalogCatalogueUpsertSchema = z7.object({
2770
+ nameSingular: z7.string().trim().min(1).max(120).optional(),
2771
+ namePlural: z7.string().trim().min(1).max(120).optional(),
2585
2772
  /** A lucide icon name, as the object settings offer them. */
2586
- icon: z5.string().trim().max(64).nullable().optional()
2773
+ icon: z7.string().trim().max(64).nullable().optional()
2587
2774
  }).strict();
2588
- var CatalogFieldTypeSchema = z5.enum([
2775
+ var CatalogFieldTypeSchema = z7.enum([
2589
2776
  "text",
2590
2777
  "number",
2591
2778
  "select",
@@ -2599,21 +2786,21 @@ var CatalogFieldTypeSchema = z5.enum([
2599
2786
  "configurator"
2600
2787
  ]);
2601
2788
  var CATALOG_FIELD_TYPES = CatalogFieldTypeSchema.options;
2602
- var CatalogFieldOptionSchema = z5.object({
2603
- value: z5.string().trim().min(1).max(120),
2604
- label: z5.string().trim().min(1).max(120).optional()
2789
+ var CatalogFieldOptionSchema = z7.object({
2790
+ value: z7.string().trim().min(1).max(120),
2791
+ label: z7.string().trim().min(1).max(120).optional()
2605
2792
  }).strict();
2606
- var CatalogAttributeUpsertSchema = z5.object({
2607
- label: z5.string().trim().min(1).max(120).optional(),
2793
+ var CatalogAttributeUpsertSchema = z7.object({
2794
+ label: z7.string().trim().min(1).max(120).optional(),
2608
2795
  type: CatalogFieldTypeSchema.optional(),
2609
2796
  /** For a select: whether a product may carry more than one choice. */
2610
- multiple: z5.boolean().optional(),
2797
+ multiple: z7.boolean().optional(),
2611
2798
  /** Choices to make sure exist; never removes one that is not listed. */
2612
- options: z5.array(CatalogFieldOptionSchema).max(500).optional(),
2799
+ options: z7.array(CatalogFieldOptionSchema).max(500).optional(),
2613
2800
  /** Choices to take off the list, by value. */
2614
- removeOptions: z5.array(z5.string().trim().min(1).max(120)).max(500).optional(),
2801
+ removeOptions: z7.array(z7.string().trim().min(1).max(120)).max(500).optional(),
2615
2802
  /** Whether the public API may show this field at all. */
2616
- public: z5.boolean().optional(),
2803
+ public: z7.boolean().optional(),
2617
2804
  /**
2618
2805
  * The field's settings, replaced as a whole. Checked against the same
2619
2806
  * schema the object builder saves with, per type: a repeater's `display`,
@@ -2621,47 +2808,47 @@ var CatalogAttributeUpsertSchema = z5.object({
2621
2808
  * a configurator's whole structure. An item field keeps its type once it
2622
2809
  * exists.
2623
2810
  */
2624
- config: z5.record(z5.string(), z5.unknown()).optional(),
2811
+ config: z7.record(z7.string(), z7.unknown()).optional(),
2625
2812
  /**
2626
2813
  * Say what this body would change -- a new field, a new label, choices
2627
2814
  * added, choices taken away and how many products hold each -- and
2628
2815
  * write nothing.
2629
2816
  */
2630
- dryRun: z5.boolean().optional(),
2817
+ dryRun: z7.boolean().optional(),
2631
2818
  /**
2632
2819
  * Bring the field back from the trash under its own id, with every value
2633
2820
  * the products kept. Nothing else may be sent with it.
2634
2821
  */
2635
- restore: z5.literal(true).optional(),
2822
+ restore: z7.literal(true).optional(),
2636
2823
  /**
2637
2824
  * For a new content field (`content_text`, `repeater`, `cta`): put its
2638
2825
  * block at the end of the product page. On by default; `false` makes the
2639
2826
  * field only. Never moves or restores a block of an existing field.
2640
2827
  */
2641
- placeOnPage: z5.boolean().optional()
2828
+ placeOnPage: z7.boolean().optional()
2642
2829
  }).strict();
2643
2830
  var CONFIGURATOR_FILE_KINDS = ["model", "texture"];
2644
2831
  var CONFIGURATOR_TEXTURE_CONTENT_TYPES = [
2645
2832
  "image/webp",
2646
2833
  "image/jpeg"
2647
2834
  ];
2648
- var ConfiguratorFileUploadSchema = z5.discriminatedUnion("step", [
2649
- z5.object({
2650
- step: z5.literal("start"),
2835
+ var ConfiguratorFileUploadSchema = z7.discriminatedUnion("step", [
2836
+ z7.object({
2837
+ step: z7.literal("start"),
2651
2838
  /** The slug of the configurator field the file is for. */
2652
2839
  field: CatalogFieldSlugSchema,
2653
- kind: z5.enum(CONFIGURATOR_FILE_KINDS),
2840
+ kind: z7.enum(CONFIGURATOR_FILE_KINDS),
2654
2841
  /** The bytes the caller is about to send, so a too-large file is refused before it travels. */
2655
- size: z5.number().int().min(1),
2842
+ size: z7.number().int().min(1),
2656
2843
  /** For a texture: what kind of picture it is. A model is always glTF binary. */
2657
- contentType: z5.enum(CONFIGURATOR_TEXTURE_CONTENT_TYPES).optional()
2844
+ contentType: z7.enum(CONFIGURATOR_TEXTURE_CONTENT_TYPES).optional()
2658
2845
  }).strict(),
2659
- z5.object({
2660
- step: z5.literal("finish"),
2846
+ z7.object({
2847
+ step: z7.literal("finish"),
2661
2848
  field: CatalogFieldSlugSchema,
2662
- kind: z5.enum(CONFIGURATOR_FILE_KINDS),
2849
+ kind: z7.enum(CONFIGURATOR_FILE_KINDS),
2663
2850
  /** The `uploadPath` `start` answered with. */
2664
- uploadPath: z5.string().max(200)
2851
+ uploadPath: z7.string().max(200)
2665
2852
  }).strict()
2666
2853
  ]);
2667
2854
  var CATALOG_FILE_KINDS = ["image", "file"];
@@ -2677,97 +2864,40 @@ var CATALOG_FILE_CONTENT_TYPES = [
2677
2864
  "text/csv",
2678
2865
  "application/zip"
2679
2866
  ];
2680
- var CatalogFileUploadSchema = z5.discriminatedUnion("step", [
2681
- z5.object({
2682
- step: z5.literal("start"),
2867
+ var CatalogFileUploadSchema = z7.discriminatedUnion("step", [
2868
+ z7.object({
2869
+ step: z7.literal("start"),
2683
2870
  /** A picture (2 MB, png/jpeg/webp) or a download for a list item (20 MB). */
2684
- kind: z5.enum(CATALOG_FILE_KINDS),
2871
+ kind: z7.enum(CATALOG_FILE_KINDS),
2685
2872
  /** The bytes about to be sent, so a too-large file is refused before it travels. */
2686
- size: z5.number().int().min(1),
2687
- contentType: z5.enum(CATALOG_FILE_CONTENT_TYPES)
2873
+ size: z7.number().int().min(1),
2874
+ contentType: z7.enum(CATALOG_FILE_CONTENT_TYPES)
2688
2875
  }).strict(),
2689
- z5.object({
2690
- step: z5.literal("finish"),
2691
- kind: z5.enum(CATALOG_FILE_KINDS),
2876
+ z7.object({
2877
+ step: z7.literal("finish"),
2878
+ kind: z7.enum(CATALOG_FILE_KINDS),
2692
2879
  /** The `uploadPath` `start` answered with. */
2693
- uploadPath: z5.string().max(200)
2880
+ uploadPath: z7.string().max(200)
2694
2881
  }).strict()
2695
2882
  ]);
2696
2883
 
2697
2884
  // src/catalog-tools.ts
2698
- import { z as z7 } from "zod";
2699
-
2700
- // src/tool-answers.ts
2701
- import { CrmApiError } from "@solumflow-app/crm-client";
2702
- import { z as z6 } from "zod";
2703
- function answer(text2, data) {
2704
- return {
2705
- content: [{ type: "text", text: text2 }],
2706
- structuredContent: { result: data }
2707
- };
2708
- }
2709
- function refusal(error, scope) {
2710
- if (!(error instanceof CrmApiError)) {
2711
- throw error;
2712
- }
2713
- const lines = [`${error.code}: ${error.message}`];
2714
- const next = error.code === "forbidden" ? `The key may not do this. It needs to be a secret key with the scope "${scope}".` : NEXT_STEP[error.code];
2715
- if (next) {
2716
- lines.push(next);
2717
- }
2718
- for (const field of error.fields) {
2719
- lines.push(`- ${field.path}: ${field.message}`);
2720
- }
2721
- return {
2722
- isError: true,
2723
- content: [{ type: "text", text: lines.join("\n") }]
2724
- };
2725
- }
2726
- var NEXT_STEP = {
2727
- unauthorized: "The key is not recognised or was revoked. Ask the account owner for a new secret key.",
2728
- feature_unavailable: "The module this needs is switched off for the account. Ask somebody to switch it on in the app.",
2729
- rate_limited: "Too many requests: 120 a minute per key, 600 per account, and 5 MB of bodies a day per key. Wait the seconds the answer names and try again.",
2730
- internal_error: "Something went wrong in the app. Trying again is safe."
2731
- };
2732
- function codeBlock(snippet) {
2733
- return `\`\`\`html
2734
- ${snippet}
2735
- \`\`\``;
2736
- }
2737
- var page = {
2738
- cursor: z6.string().optional().describe("The nextCursor of the previous page; leave out for the first."),
2739
- limit: z6.number().int().min(1).max(100).optional()
2740
- };
2741
- function more(nextCursor) {
2742
- return nextCursor ? `More on the next page: cursor ${nextCursor}` : "";
2743
- }
2744
- function money(cents3, currency2) {
2745
- return `${(cents3 / 100).toFixed(2)} ${currency2.toUpperCase()}`;
2746
- }
2747
- function fieldsNotOnPageNote(slugs) {
2748
- if (!slugs?.length) {
2749
- return "";
2750
- }
2751
- const count = slugs.length === 1 ? "1 public field has" : `${slugs.length} public fields have`;
2752
- return ` ${count} a value but ${slugs.length === 1 ? "is" : "are"} not on this product's page: ${slugs.join(", ")}; send them in publicFields to show them.`;
2753
- }
2754
-
2755
- // src/catalog-tools.ts
2885
+ import { z as z8 } from "zod";
2756
2886
  var objectInput = {
2757
2887
  object: CatalogObjectSlugSchema.optional().describe(
2758
2888
  "The slug of the catalogue (see list_catalogs). Leave out for the account\u2019s own catalogue."
2759
2889
  )
2760
2890
  };
2761
2891
  var CONTENT_BLOCKS = 'Besides plain values (text, number, choice), a product can carry content blocks, three field types: "content_text" is { html, links? } with already-sanitised html; "cta" is { heading, body, primary: {label,url}, secondary? }, a call to action; "repeater" is { items: [{ id, ...one value per item field }] } and covers lists, accordions (FAQ), downloads and testimonials. A repeater\u2019s field says how to draw it: "display" is "list" or "accordion", "preset" names where it started (list, faq, downloads, testimonials), "itemFields" is the structure of one item (key, label, type: text, richtext, url {label,url}, icon {set,name}, image or file {url,name,size,contentType}) and "titleKey" is the item field that names an item, such as the question of a FAQ. A "configurator" is a 3D product configurator: a listing carries only { configurator: true }, a product\u2019s own page the whole document (see read_configurator). A block that is public but empty is null; a block that is not public is not there at all. A new block field stands at the end of the product page from the moment upsert_field makes it (`placeOnPage: false` skips that).';
2762
- var currency = z7.string().regex(/^[A-Z]{3}$/).optional().describe(
2892
+ var currency = z8.string().regex(/^[A-Z]{3}$/).optional().describe(
2763
2893
  "Every price in this currency (see list_currencies), each with its origin: base, fixed or converted. Left out, every price in its own currency."
2764
2894
  );
2765
2895
  var READ_STATUS_HINT = 'Left out, only published ones. "draft" is what is not on the website yet (concept, internal or scheduled), "archived" what was taken out, "all" everything; each answers with a `status` and `publishedAt` per item. Anything but published needs a key with catalog:write.';
2766
- var productStatus = z7.enum(["published", "draft", "archived", "all"]).optional().describe(`Which products. ${READ_STATUS_HINT}`);
2767
- var categoryStatus = z7.enum(["published", "draft", "all"]).optional().describe(
2896
+ var productStatus = z8.enum(["published", "draft", "archived", "all"]).optional().describe(`Which products. ${READ_STATUS_HINT}`);
2897
+ var categoryStatus = z8.enum(["published", "draft", "all"]).optional().describe(
2768
2898
  `Which categories. ${READ_STATUS_HINT.replace('"archived" what was taken out, ', "")} A category cannot be archived.`
2769
2899
  );
2770
- var slugOrId = z7.string().min(1).max(200).describe("The address (slug) or the id of the product.");
2900
+ var slugOrId = z8.string().min(1).max(200).describe("The address (slug) or the id of the product.");
2771
2901
  function registerCatalogTools(server, client) {
2772
2902
  server.registerTool(
2773
2903
  "list_catalog_fields",
@@ -2817,7 +2947,7 @@ function registerCatalogTools(server, client) {
2817
2947
  title: "List the currencies the shop sells in",
2818
2948
  description: "The account\u2019s own currency first, then the ones it switched on, with a name and symbol: what a currency menu on a website is built from. Pass one as `currency` to get_product or list_products for prices in it. Which currencies are offered, and at what rate, is set in the app (Settings \u2192 Verkoop \u2192 Valuta), not through this tool.",
2819
2949
  inputSchema: {
2820
- locale: z7.string().min(2).max(35).optional().describe('The language names are written in, such as "nl".')
2950
+ locale: z8.string().min(2).max(35).optional().describe('The language names are written in, such as "nl".')
2821
2951
  },
2822
2952
  annotations: { readOnlyHint: true, idempotentHint: true }
2823
2953
  },
@@ -2874,22 +3004,22 @@ function registerCatalogTools(server, client) {
2874
3004
  description: "One page of the catalogue: name, address (slug), lowest price, whether it is in stock, its first picture and the public fields a listing shows. Narrow it to one category\u2019s whole branch by its id or address, or by the reference upsert_category recorded (`categorySource` + `categoryRef`), to one catalogue by the slug of its object, or to the product carrying an article number (`sku`). Read get_product for everything a product page needs. Published products only, and may be a minute old; `status` lists concepts, scheduled and archived ones too (needs a server key). `sort` orders the published ones: -publishedAt (newest first, the default), publishedAt, name, or position -- the seller\u2019s own order on the page of `category`, which it needs. Each item carries `sku`, `publishedAt` and `stockQuantity` (null when not counted).",
2875
3005
  inputSchema: {
2876
3006
  ...page,
2877
- category: z7.string().regex(
3007
+ category: z8.string().regex(
2878
3008
  /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|[a-z0-9]+(-[a-z0-9]+)*)$/i
2879
3009
  ).max(64).optional().describe(
2880
3010
  "A category id or address (slug); includes its subcategories."
2881
3011
  ),
2882
- categorySource: z7.string().max(64).optional().describe("With categoryRef: whose id the category reference is."),
2883
- categoryRef: z7.string().max(255).optional().describe("A category by the id it has in your own system."),
2884
- sku: z7.string().min(1).max(100).optional().describe(
3012
+ categorySource: z8.string().max(64).optional().describe("With categoryRef: whose id the category reference is."),
3013
+ categoryRef: z8.string().max(255).optional().describe("A category by the id it has in your own system."),
3014
+ sku: z8.string().min(1).max(100).optional().describe(
2885
3015
  "The product carrying this article number, or whose variant does."
2886
3016
  ),
2887
- object: z7.string().min(1).max(63).optional().describe(
3017
+ object: z8.string().min(1).max(63).optional().describe(
2888
3018
  'One catalogue, by the slug of its object, such as "product".'
2889
3019
  ),
2890
3020
  currency,
2891
3021
  status: productStatus,
2892
- sort: z7.enum(["-publishedAt", "publishedAt", "name", "position"]).optional().describe(
3022
+ sort: z8.enum(["-publishedAt", "publishedAt", "name", "position"]).optional().describe(
2893
3023
  "The order: newest first by default; position needs `category`."
2894
3024
  )
2895
3025
  },
@@ -2922,7 +3052,7 @@ function registerCatalogTools(server, client) {
2922
3052
  description: 'The categories of the catalogue, each with its path from the top and how many products are in it. Left without `parent`, every category comes back, which is what building a menu in one go needs; "root" asks for the top level, a category id for its children. Published categories only unless you pass `status` (draft or all, needs a server key).',
2923
3053
  inputSchema: {
2924
3054
  ...page,
2925
- parent: z7.union([z7.literal("root"), z7.string().uuid()]).optional().describe('"root" or the id of a category.'),
3055
+ parent: z8.union([z8.literal("root"), z8.string().uuid()]).optional().describe('"root" or the id of a category.'),
2926
3056
  status: categoryStatus
2927
3057
  },
2928
3058
  annotations: { readOnlyHint: true, idempotentHint: true }
@@ -2945,7 +3075,7 @@ function registerCatalogTools(server, client) {
2945
3075
  title: "Read one category page",
2946
3076
  description: "One category as its page needs it: name, description, the texts for search engines and social media, and the first page of its products. Pass the nextCursor back to page through the products. A category that is not on the website yet needs `status` (draft or all, a server key); its products are the published ones.",
2947
3077
  inputSchema: {
2948
- slugOrId: z7.string().min(1).max(200).describe("The address (slug) or the id of the category."),
3078
+ slugOrId: z8.string().min(1).max(200).describe("The address (slug) or the id of the category."),
2949
3079
  ...page,
2950
3080
  status: categoryStatus
2951
3081
  },
@@ -3121,8 +3251,8 @@ function registerCatalogMigrationTools(server, client) {
3121
3251
  title: "Make or change many products",
3122
3252
  description: `Up to ${BULK_LIMIT} products, one after another, each exactly as upsert_product takes it (\`externalRef\` beside its body). A refusal is that product\u2019s outcome and the others go on; a refusal for speed is waited out and the product sent again; a key that is refused stops the run and the rest is \`skipped\`. Answers per product \`created\`, \`changed\`, \`refused\` (with the fields) or \`skipped\`. ` + LIMITS,
3123
3253
  inputSchema: {
3124
- products: z8.array(
3125
- z8.object({
3254
+ products: z9.array(
3255
+ z9.object({
3126
3256
  externalRef: CatalogExternalRefSchema,
3127
3257
  product: CatalogProductUpsertSchema
3128
3258
  })
@@ -3166,20 +3296,20 @@ function registerCatalogMigrationTools(server, client) {
3166
3296
  description: "Moves a field to the trash, as the app does: for thirty days it can come back with restore_field, and every product keeps its value meanwhile. Use `permanent` only when the user explicitly asks to delete for good, and first without `confirm`: that only counts the products that would lose their value. Show the user that count; send `confirm` (the slug again) only after they agree. A field of the app\u2019s own, or one a product varies along, is refused.",
3167
3297
  inputSchema: {
3168
3298
  slug: CatalogFieldSlugSchema,
3169
- permanent: z8.boolean().optional(),
3170
- confirm: z8.string().max(63).optional(),
3299
+ permanent: z9.boolean().optional(),
3300
+ confirm: z9.string().max(63).optional(),
3171
3301
  ...objectInput
3172
3302
  },
3173
3303
  annotations: { destructiveHint: true, idempotentHint: true }
3174
3304
  },
3175
- async ({ slug: slug2, permanent, confirm, object: object2 }) => {
3305
+ async ({ slug: slug3, permanent, confirm, object: object2 }) => {
3176
3306
  try {
3177
- const result = await client.removeField(slug2, {
3307
+ const result = await client.removeField(slug3, {
3178
3308
  ...target(object2),
3179
3309
  ...permanent ? { permanent } : {},
3180
3310
  ...confirm ? { confirm } : {}
3181
3311
  });
3182
- const text2 = result.state === "trashed" ? `${slug2} is in the trash until ${result.restorableUntil ?? "thirty days from now"}; ${result.productsWithValue} products keep their value.` : result.state === "would_delete" ? `Nothing changed. Deleting ${slug2} for good would clear its value on ${result.productsWithValue} products. ${result.confirm}` : `${slug2} is deleted; its value on ${result.productsWithValue} products is being cleared.`;
3312
+ const text2 = result.state === "trashed" ? `${slug3} is in the trash until ${result.restorableUntil ?? "thirty days from now"}; ${result.productsWithValue} products keep their value.` : result.state === "would_delete" ? `Nothing changed. Deleting ${slug3} for good would clear its value on ${result.productsWithValue} products. ${result.confirm}` : `${slug3} is deleted; its value on ${result.productsWithValue} products is being cleared.`;
3183
3313
  return answer(text2, result);
3184
3314
  } catch (error) {
3185
3315
  return refusal(error, "catalog:write");
@@ -3194,9 +3324,9 @@ function registerCatalogMigrationTools(server, client) {
3194
3324
  inputSchema: { slug: CatalogFieldSlugSchema, ...objectInput },
3195
3325
  annotations: { destructiveHint: false, idempotentHint: true }
3196
3326
  },
3197
- async ({ slug: slug2, object: object2 }) => {
3327
+ async ({ slug: slug3, object: object2 }) => {
3198
3328
  try {
3199
- const field = await client.restoreField(slug2, target(object2));
3329
+ const field = await client.restoreField(slug3, target(object2));
3200
3330
  return answer(`${field.label} (${field.slug}) is back.`, field);
3201
3331
  } catch (error) {
3202
3332
  return refusal(error, "catalog:write");
@@ -3211,7 +3341,7 @@ function registerCatalogMigrationTools(server, client) {
3211
3341
  inputSchema: {
3212
3342
  source: CatalogSourceSchema,
3213
3343
  externalRef: CatalogExternalRefSchema,
3214
- status: z8.enum(["published", "draft", "all"]).optional().describe(
3344
+ status: z9.enum(["published", "draft", "all"]).optional().describe(
3215
3345
  "Which categories to look in; anything but published needs catalog:write."
3216
3346
  )
3217
3347
  },
@@ -3239,8 +3369,8 @@ function registerCatalogMigrationTools(server, client) {
3239
3369
  title: "Upload a picture or a file from disk",
3240
3370
  description: 'Reads one file from the user\u2019s disk and uploads it, for a product write to name as { "upload": "<uploadPath>" } instead of a url: a picture (png, jpeg, webp, at most 2 MB) for `images`, `socialImage` or a list item\u2019s image, or a "file" (pdf, Office, txt, csv, zip, at most 20 MB) for a list item\u2019s download. An upload is kept a day.',
3241
3371
  inputSchema: {
3242
- kind: z8.enum(["image", "file"]),
3243
- filePath: z8.string().min(1).max(1e3).describe("The absolute path of the file on this machine.")
3372
+ kind: z9.enum(["image", "file"]),
3373
+ filePath: z9.string().min(1).max(1e3).describe("The absolute path of the file on this machine.")
3244
3374
  },
3245
3375
  annotations: { destructiveHint: false, idempotentHint: false }
3246
3376
  },
@@ -3483,10 +3613,10 @@ Archive it with archive_product instead.`
3483
3613
  },
3484
3614
  annotations: { destructiveHint: false, idempotentHint: true }
3485
3615
  },
3486
- async ({ slug: slug2, object: object2, ...input }) => {
3616
+ async ({ slug: slug3, object: object2, ...input }) => {
3487
3617
  try {
3488
3618
  const category = await client.upsertCategory(
3489
- slug2,
3619
+ slug3,
3490
3620
  input,
3491
3621
  target2(object2)
3492
3622
  );
@@ -3513,14 +3643,14 @@ Archive it with archive_product instead.`
3513
3643
  },
3514
3644
  annotations: { destructiveHint: true, idempotentHint: true }
3515
3645
  },
3516
- async ({ slug: slug2, object: object2, ...input }) => {
3646
+ async ({ slug: slug3, object: object2, ...input }) => {
3517
3647
  try {
3518
3648
  if (input.dryRun) {
3519
3649
  const { dryRun: _dryRun, ...rest } = input;
3520
- const preview = await client.previewField(slug2, rest, target2(object2));
3650
+ const preview = await client.previewField(slug3, rest, target2(object2));
3521
3651
  return answer(`Nothing written. ${JSON.stringify(preview)}`, preview);
3522
3652
  }
3523
- const field = await client.upsertField(slug2, input, target2(object2));
3653
+ const field = await client.upsertField(slug3, input, target2(object2));
3524
3654
  return answer(
3525
3655
  `${field.created ? "Made" : "Changed"} ${field.label} (${field.slug}), ${field.type}, ${field.public ? "public" : "not public"}.` + (field.placedOnPage === void 0 ? "" : field.placedOnPage ? " Its block is at the end of the product page." : ` Its block is not on the product page (${field.notPlacedBecause ?? "not placed"}).`),
3526
3656
  field
@@ -3543,9 +3673,9 @@ Archive it with archive_product instead.`
3543
3673
  },
3544
3674
  annotations: { destructiveHint: false, idempotentHint: true }
3545
3675
  },
3546
- async ({ slug: slug2, ...input }) => {
3676
+ async ({ slug: slug3, ...input }) => {
3547
3677
  try {
3548
- const catalog = await client.upsertCatalog(slug2, input);
3678
+ const catalog = await client.upsertCatalog(slug3, input);
3549
3679
  return answer(
3550
3680
  `${catalog.created ? "Made" : "Changed"} ${catalog.namePlural} (${catalog.slug}).`,
3551
3681
  catalog
@@ -3557,8 +3687,106 @@ Archive it with archive_product instead.`
3557
3687
  );
3558
3688
  }
3559
3689
 
3690
+ // src/client-account-tools.ts
3691
+ import { z as z10 } from "zod";
3692
+ var RESELLER_ONLY = "Only on the key of a reseller, with clients:manage; only the customer accounts that reseller sold are reached.";
3693
+ function registerClientAccountTools(server, client) {
3694
+ server.registerTool(
3695
+ "list_client_accounts",
3696
+ {
3697
+ title: "List customer accounts",
3698
+ description: `The customer accounts this reseller sold, paged by id: name, address, owner, kind and the modules switched on. ${RESELLER_ONLY}`,
3699
+ inputSchema: { ...page },
3700
+ annotations: { readOnlyHint: true, idempotentHint: true }
3701
+ },
3702
+ async (input) => {
3703
+ try {
3704
+ const result = await client.getClientAccounts(input);
3705
+ return answer(
3706
+ result.data.length === 0 ? "No customer accounts." : [...result.data.map(describeAccount), more(result.nextCursor)].filter(Boolean).join("\n"),
3707
+ result
3708
+ );
3709
+ } catch (error) {
3710
+ return refusal(error, "clients:manage");
3711
+ }
3712
+ }
3713
+ );
3714
+ server.registerTool(
3715
+ "get_client_account",
3716
+ {
3717
+ title: "Read one customer account",
3718
+ description: `One customer account of this reseller by id. ${RESELLER_ONLY}`,
3719
+ inputSchema: { id: z10.string().uuid() },
3720
+ annotations: { readOnlyHint: true, idempotentHint: true }
3721
+ },
3722
+ async ({ id: id7 }) => {
3723
+ try {
3724
+ const account = await client.getClientAccount(id7);
3725
+ return account ? answer(describeAccount(account), account) : answer(`No customer account ${id7} under this reseller.`, null);
3726
+ } catch (error) {
3727
+ return refusal(error, "clients:manage");
3728
+ }
3729
+ }
3730
+ );
3731
+ server.registerTool(
3732
+ "create_client_account",
3733
+ {
3734
+ title: "Make a customer account",
3735
+ description: `A customer account with a SolumFlow workspace of its own: the owner gets a login and a mail with the way in. Asked again for the same owner it makes nothing and answers with the account that owner already has. It starts with the default modules; set_client_modules sets the ones it is sold with. ${RESELLER_ONLY}`,
3736
+ inputSchema: {
3737
+ name: z10.string().min(1).max(255).describe("What the account is called: the customer\u2019s business."),
3738
+ ownerEmail: z10.string().email().max(320).describe("Who owns it, and who gets the mail with the way in."),
3739
+ slug: z10.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(63).optional().describe(
3740
+ "The address in the app; derived from the name when left out."
3741
+ )
3742
+ },
3743
+ annotations: { idempotentHint: true }
3744
+ },
3745
+ async (input) => {
3746
+ try {
3747
+ const result = await client.createClientAccount(input);
3748
+ const said = result.created ? result.invited ? "Made, and its owner was mailed the way in." : "Made, but the mail to its owner did not go: give them access from the account\u2019s members in the app." : "That owner already had an account here; nothing was made.";
3749
+ return answer(`${said}
3750
+ ${describeAccount(result.account)}`, result);
3751
+ } catch (error) {
3752
+ return refusal(error, "clients:manage");
3753
+ }
3754
+ }
3755
+ );
3756
+ server.registerTool(
3757
+ "set_client_modules",
3758
+ {
3759
+ title: "Set a customer account\u2019s modules",
3760
+ description: `The modules a customer account is sold with: every key named is switched on, every other ordinary module off; never an empty list. A module a paid package switched on and this changes is the reseller\u2019s choice from then on. Only modules this reseller may hand out; hosting, domains, mail hosting and site monitoring stay the platform owner\u2019s. Typical: crm, calendar, forms, chat, consent, payments. ${RESELLER_ONLY}`,
3761
+ inputSchema: {
3762
+ clientAccountId: z10.string().uuid(),
3763
+ moduleKeys: z10.array(z10.string().regex(/^[a-z][a-z0-9_]{1,63}$/)).min(1).max(64)
3764
+ },
3765
+ annotations: { idempotentHint: true }
3766
+ },
3767
+ async ({ clientAccountId, moduleKeys }) => {
3768
+ try {
3769
+ const result = await client.setClientModules(
3770
+ clientAccountId,
3771
+ moduleKeys
3772
+ );
3773
+ const said = result.changed.length ? `Switched: ${result.changed.join(", ")}.` : "Nothing changed: the account already had exactly these.";
3774
+ return answer(`${said}
3775
+ ${describeAccount(result.account)}`, result);
3776
+ } catch (error) {
3777
+ return refusal(error, "clients:manage");
3778
+ }
3779
+ }
3780
+ );
3781
+ }
3782
+ function describeAccount(account) {
3783
+ const test = account.isTestAccount ? " (test)" : "";
3784
+ const modules = account.modules.length ? account.modules.join(", ") : "no modules";
3785
+ return `- ${account.name}${test} (id ${account.id}, ${account.slug}, ${account.kind}): owner ${account.ownerEmail ?? "unknown"}; ${modules}`;
3786
+ }
3787
+
3560
3788
  // src/configurator-tools.ts
3561
- import { z as z9 } from "zod";
3789
+ import { z as z11 } from "zod";
3562
3790
  import { readFile as readFile2, stat as stat2 } from "fs/promises";
3563
3791
  import { extname as extname2 } from "path";
3564
3792
  var FILE_RULES2 = {
@@ -3569,7 +3797,7 @@ var FILE_RULES2 = {
3569
3797
  }
3570
3798
  };
3571
3799
  var CONFIGURATOR = 'A "configurator" field holds a 3D product configurator. Its structure has "geometry" (the shape document: "inputs" bound to parameters, "constants", material "slots", a "root" tree of building blocks and "annotations" for dimension lines), "parameters", "choiceLists", "materials", "priceGroups", "amounts", optional "presets", optional "scene" ({ "lighting": "studio" | "warm" | "daylight" }), "rules" and "priceRules". Building blocks: box, rounded_top_box (params.radius), stadium_prism, arc_panel (params.thickness, params.mirror), led_strip, niche_panel (params.niche_x, niche_y, niche_width, niche_height), model (a "model" path to a .glb uploaded with upload_configurator_file, params.fit 0 contain or 1 stretch, params.paint 1 to use the slot material) and repeat (count, children, index i or j). Every measure is millimetres; "at" is the minimum corner, x left to right, y bottom to top, z from the wall into the room; "size" is width, height, depth. A measure is a number or a formula with + - * / ( ) and min, max, floor, ceil, round, abs over the shape\u2019s inputs, constants and the repeat index. Texture paths in materials come from upload_configurator_file too. Making a configurator, or changing its "geometry", needs a key with the configurator:shape scope; everything around the shape needs only catalog:write.';
3572
- var documentInput = z9.string().min(2).max(2e5).describe(
3800
+ var documentInput = z11.string().min(2).max(2e5).describe(
3573
3801
  'The JSON text of a whole configurator structure (it has "schemaVersion"), or of a shape document alone (it has "root").'
3574
3802
  );
3575
3803
  function registerConfiguratorTools(server, client) {
@@ -3601,16 +3829,16 @@ function registerConfiguratorTools(server, client) {
3601
3829
  slug: CatalogFieldSlugSchema.describe(
3602
3830
  "The slug of the configurator field."
3603
3831
  ),
3604
- label: z9.string().trim().min(1).max(120).optional(),
3605
- structure: z9.string().min(2).max(2e5).describe(
3832
+ label: z11.string().trim().min(1).max(120).optional(),
3833
+ structure: z11.string().min(2).max(2e5).describe(
3606
3834
  'The JSON text of the whole configurator structure (it has "schemaVersion").'
3607
3835
  ),
3608
- public: z9.boolean().optional().describe("Whether product pages may show the configurator."),
3836
+ public: z11.boolean().optional().describe("Whether product pages may show the configurator."),
3609
3837
  ...objectInput
3610
3838
  },
3611
3839
  annotations: { destructiveHint: true, idempotentHint: true }
3612
3840
  },
3613
- async ({ slug: slug2, label, structure, public: isPublic, object: object2 }) => {
3841
+ async ({ slug: slug3, label, structure, public: isPublic, object: object2 }) => {
3614
3842
  const problems = checkDocument(structure);
3615
3843
  if (problems.length > 0 || !structure.includes('"schemaVersion"')) {
3616
3844
  return {
@@ -3628,7 +3856,7 @@ function registerConfiguratorTools(server, client) {
3628
3856
  }
3629
3857
  try {
3630
3858
  const field = await client.upsertField(
3631
- slug2,
3859
+ slug3,
3632
3860
  {
3633
3861
  ...label ? { label } : {},
3634
3862
  type: "configurator",
@@ -3655,8 +3883,8 @@ function registerConfiguratorTools(server, client) {
3655
3883
  fieldSlug: CatalogFieldSlugSchema.describe(
3656
3884
  "The slug of the configurator field."
3657
3885
  ),
3658
- kind: z9.enum(CONFIGURATOR_FILE_KINDS),
3659
- filePath: z9.string().min(1).max(1e3).describe("The absolute path of the file on this machine."),
3886
+ kind: z11.enum(CONFIGURATOR_FILE_KINDS),
3887
+ filePath: z11.string().min(1).max(1e3).describe("The absolute path of the file on this machine."),
3660
3888
  ...objectInput
3661
3889
  },
3662
3890
  annotations: { destructiveHint: false, idempotentHint: false }
@@ -3709,8 +3937,8 @@ function registerConfiguratorTools(server, client) {
3709
3937
  title: "Read the configurator of a product",
3710
3938
  description: "The configurator field of one product as its page receives it: the structure (texture paths already URLs), the model\u2019s value (ranges, offered options, amounts, presets), the tax a quote uses and the two hashes a request must send back. Useful to draft a new shape from an existing one. " + CONFIGURATOR,
3711
3939
  inputSchema: {
3712
- slugOrId: z9.string().min(1).max(200).describe("The address (slug) or the id of the product."),
3713
- field: z9.string().min(1).max(64).describe("The slug of the configurator field.")
3940
+ slugOrId: z11.string().min(1).max(200).describe("The address (slug) or the id of the product."),
3941
+ field: z11.string().min(1).max(64).describe("The slug of the configurator field.")
3714
3942
  },
3715
3943
  annotations: { readOnlyHint: true, idempotentHint: true }
3716
3944
  },
@@ -3792,7 +4020,7 @@ function isRecord(value) {
3792
4020
  }
3793
4021
 
3794
4022
  // src/consent-banner-tools.ts
3795
- import { z as z10 } from "zod";
4023
+ import { z as z12 } from "zod";
3796
4024
  function registerConsentBannerTools(server, client) {
3797
4025
  server.registerTool(
3798
4026
  "get_consent_banner",
@@ -3819,16 +4047,16 @@ function registerConsentBannerTools(server, client) {
3819
4047
  title: "Set the cookie banner",
3820
4048
  description: "All of the banner\u2019s settings at once, as the screen in the app saves them. It changes the live site at once. `necessary` is always on and not sent.",
3821
4049
  inputSchema: {
3822
- enabled: z10.boolean(),
3823
- gtmContainerId: z10.string().max(20).describe("GTM-\u2026, or an empty string for none."),
3824
- privacyPolicyUrl: z10.string().max(2048).describe("https only, or an empty string for none."),
3825
- categories: z10.array(
3826
- z10.enum(["functionality", "measurement", "marketing", "experience"])
4050
+ enabled: z12.boolean(),
4051
+ gtmContainerId: z12.string().max(20).describe("GTM-\u2026, or an empty string for none."),
4052
+ privacyPolicyUrl: z12.string().max(2048).describe("https only, or an empty string for none."),
4053
+ categories: z12.array(
4054
+ z12.enum(["functionality", "measurement", "marketing", "experience"])
3827
4055
  ).max(4),
3828
- defaultLanguage: z10.enum(["nl", "en"]),
3829
- layout: z10.enum(["banner", "dialog"]),
3830
- showLogo: z10.boolean(),
3831
- sendHashedUserData: z10.boolean()
4056
+ defaultLanguage: z12.enum(["nl", "en"]),
4057
+ layout: z12.enum(["banner", "dialog"]),
4058
+ showLogo: z12.boolean(),
4059
+ sendHashedUserData: z12.boolean()
3832
4060
  },
3833
4061
  annotations: { idempotentHint: true }
3834
4062
  },
@@ -3844,17 +4072,17 @@ function registerConsentBannerTools(server, client) {
3844
4072
  }
3845
4073
 
3846
4074
  // src/deal-tools.ts
3847
- import { z as z11 } from "zod";
3848
- var dealId = z11.string().uuid().describe("The id of the deal.");
4075
+ import { z as z13 } from "zod";
4076
+ var dealId = z13.string().uuid().describe("The id of the deal.");
3849
4077
  var dealFields = {
3850
- name: z11.string().min(1).max(200),
3851
- value: z11.number().nonnegative().nullable().optional().describe("In whole units of the currency, such as 1500 for \u20AC1,500."),
3852
- currency: z11.string().length(3).optional().describe("Three letters; EUR when left out."),
3853
- contactRecordId: z11.string().uuid().nullable().optional(),
3854
- companyRecordId: z11.string().uuid().nullable().optional(),
3855
- ownerId: z11.string().uuid().nullable().optional().describe("A member of the account."),
3856
- expectedCloseDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional().describe("YYYY-MM-DD."),
3857
- values: z11.record(z11.string(), z11.unknown()).optional().describe("Field values by slug. A field marked sensitive is refused.")
4078
+ name: z13.string().min(1).max(200),
4079
+ value: z13.number().nonnegative().nullable().optional().describe("In whole units of the currency, such as 1500 for \u20AC1,500."),
4080
+ currency: z13.string().length(3).optional().describe("Three letters; EUR when left out."),
4081
+ contactRecordId: z13.string().uuid().nullable().optional(),
4082
+ companyRecordId: z13.string().uuid().nullable().optional(),
4083
+ ownerId: z13.string().uuid().nullable().optional().describe("A member of the account."),
4084
+ expectedCloseDate: z13.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional().describe("YYYY-MM-DD."),
4085
+ values: z13.record(z13.string(), z13.unknown()).optional().describe("Field values by slug. A field marked sensitive is refused.")
3858
4086
  };
3859
4087
  function registerDealTools(server, client) {
3860
4088
  server.registerTool(
@@ -3886,9 +4114,9 @@ function registerDealTools(server, client) {
3886
4114
  title: "List deals",
3887
4115
  description: "Deals paged by id, open ones unless status says otherwise; pipeline narrows to one pipeline, q searches the name.",
3888
4116
  inputSchema: {
3889
- pipeline: z11.string().uuid().optional(),
3890
- status: z11.enum(["open", "won", "lost", "all"]).optional(),
3891
- q: z11.string().max(200).optional(),
4117
+ pipeline: z13.string().uuid().optional(),
4118
+ status: z13.enum(["open", "won", "lost", "all"]).optional(),
4119
+ q: z13.string().max(200).optional(),
3892
4120
  ...page
3893
4121
  },
3894
4122
  annotations: { readOnlyHint: true, idempotentHint: true }
@@ -3928,7 +4156,7 @@ function registerDealTools(server, client) {
3928
4156
  title: "Make a deal",
3929
4157
  description: "A new deal in the stage named (list_pipelines gives the ids). A won or lost stage closes it at once; a lost one cannot be made directly. Automations that start on a new deal run as in the app.",
3930
4158
  inputSchema: {
3931
- stageId: z11.string().uuid(),
4159
+ stageId: z13.string().uuid(),
3932
4160
  ...dealFields
3933
4161
  }
3934
4162
  },
@@ -3948,10 +4176,10 @@ function registerDealTools(server, client) {
3948
4176
  description: "Changes only the fields sent. A new stageId moves the deal, also to another pipeline of the same deals list; moving into a lost stage needs lostReason. Deleting a deal is done in the app.",
3949
4177
  inputSchema: {
3950
4178
  id: dealId,
3951
- stageId: z11.string().uuid().optional(),
4179
+ stageId: z13.string().uuid().optional(),
3952
4180
  ...dealFields,
3953
4181
  name: dealFields.name.optional(),
3954
- lostReason: z11.string().min(1).max(500).nullable().optional()
4182
+ lostReason: z13.string().min(1).max(500).nullable().optional()
3955
4183
  },
3956
4184
  annotations: { idempotentHint: true }
3957
4185
  },
@@ -3989,7 +4217,7 @@ function registerDealTools(server, client) {
3989
4217
  {
3990
4218
  title: "Write a note on a deal",
3991
4219
  description: "A note on a deal, with no author: it was written through the API.",
3992
- inputSchema: { dealId, body: z11.string().min(1).max(2e4) }
4220
+ inputSchema: { dealId, body: z13.string().min(1).max(2e4) }
3993
4221
  },
3994
4222
  async ({ dealId: id7, body }) => {
3995
4223
  try {
@@ -4007,32 +4235,32 @@ function describeDeal(deal) {
4007
4235
  }
4008
4236
 
4009
4237
  // src/document-tools.ts
4010
- import { z as z12 } from "zod";
4011
- var id = z12.string().uuid();
4012
- var date = z12.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional().describe("YYYY-MM-DD.");
4013
- var line = z12.object({
4014
- name: z12.string().min(1).max(500),
4015
- description: z12.string().max(5e3).nullable().optional(),
4016
- quantity: z12.number().positive(),
4017
- unitPriceCents: z12.number().int().describe(
4238
+ import { z as z14 } from "zod";
4239
+ var id = z14.string().uuid();
4240
+ var date = z14.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional().describe("YYYY-MM-DD.");
4241
+ var line = z14.object({
4242
+ name: z14.string().min(1).max(500),
4243
+ description: z14.string().max(5e3).nullable().optional(),
4244
+ quantity: z14.number().positive(),
4245
+ unitPriceCents: z14.number().int().describe(
4018
4246
  "In cents: 12500 is 125.00. Negative for a line that takes something off."
4019
4247
  ),
4020
- taxRateId: z12.string().uuid().nullable().optional().describe("One of list_tax_rates; left out, the account\u2019s default rate."),
4021
- productId: z12.string().uuid().nullable().optional(),
4022
- lineGroup: z12.string().min(1).max(200).nullable().optional()
4248
+ taxRateId: z14.string().uuid().nullable().optional().describe("One of list_tax_rates; left out, the account\u2019s default rate."),
4249
+ productId: z14.string().uuid().nullable().optional(),
4250
+ lineGroup: z14.string().min(1).max(200).nullable().optional()
4023
4251
  });
4024
4252
  var header = {
4025
4253
  contactRecordId: id.nullable().optional(),
4026
4254
  companyRecordId: id.nullable().optional(),
4027
4255
  dealId: id.nullable().optional(),
4028
- notes: z12.string().max(2e4).nullable().optional(),
4029
- discountType: z12.enum(["flat", "percent"]).optional(),
4030
- discountValue: z12.number().nonnegative().optional().describe(
4256
+ notes: z14.string().max(2e4).nullable().optional(),
4257
+ discountType: z14.enum(["flat", "percent"]).optional(),
4258
+ discountValue: z14.number().nonnegative().optional().describe(
4031
4259
  "Cents for flat, a percentage (at most 100) for percent; sent together with discountType."
4032
4260
  )
4033
4261
  };
4034
4262
  var listInput = {
4035
- status: z12.string().max(40).optional(),
4263
+ status: z14.string().max(40).optional(),
4036
4264
  contactRecordId: id.optional(),
4037
4265
  ...page
4038
4266
  };
@@ -4115,9 +4343,9 @@ function registerDocumentTools(server, client) {
4115
4343
  description: `A draft estimate with its lines, in EUR unless currency says otherwise. Nobody receives it. ${NOT_HERE}`,
4116
4344
  inputSchema: {
4117
4345
  ...header,
4118
- currency: z12.string().regex(/^[A-Z]{3}$/).optional(),
4346
+ currency: z14.string().regex(/^[A-Z]{3}$/).optional(),
4119
4347
  expiryDate: date,
4120
- lines: z12.array(line).min(1).max(200)
4348
+ lines: z14.array(line).min(1).max(200)
4121
4349
  }
4122
4350
  },
4123
4351
  async (input) => {
@@ -4138,7 +4366,7 @@ function registerDocumentTools(server, client) {
4138
4366
  id,
4139
4367
  ...header,
4140
4368
  expiryDate: date,
4141
- lines: z12.array(line).min(1).max(200).optional()
4369
+ lines: z14.array(line).min(1).max(200).optional()
4142
4370
  },
4143
4371
  annotations: { idempotentHint: true }
4144
4372
  },
@@ -4158,10 +4386,10 @@ function registerDocumentTools(server, client) {
4158
4386
  description: `A draft invoice with its lines, in EUR unless currency says otherwise; the due date follows the account\u2019s payment terms when left out. Nobody receives it. ${NOT_HERE}`,
4159
4387
  inputSchema: {
4160
4388
  ...header,
4161
- currency: z12.string().regex(/^[A-Z]{3}$/).optional(),
4389
+ currency: z14.string().regex(/^[A-Z]{3}$/).optional(),
4162
4390
  dueDate: date,
4163
4391
  deliveryDate: date,
4164
- lines: z12.array(line).min(1).max(200)
4392
+ lines: z14.array(line).min(1).max(200)
4165
4393
  }
4166
4394
  },
4167
4395
  async (input) => {
@@ -4183,7 +4411,7 @@ function registerDocumentTools(server, client) {
4183
4411
  ...header,
4184
4412
  dueDate: date,
4185
4413
  deliveryDate: date,
4186
- lines: z12.array(line).min(1).max(200).optional()
4414
+ lines: z14.array(line).min(1).max(200).optional()
4187
4415
  },
4188
4416
  annotations: { idempotentHint: true }
4189
4417
  },
@@ -4203,8 +4431,8 @@ function describeDocument(document) {
4203
4431
  }
4204
4432
 
4205
4433
  // src/email-template-tools.ts
4206
- import { z as z13 } from "zod";
4207
- var id2 = z13.string().uuid();
4434
+ import { z as z15 } from "zod";
4435
+ var id2 = z15.string().uuid();
4208
4436
  function registerEmailTemplateTools(server, client) {
4209
4437
  server.registerTool(
4210
4438
  "list_email_templates",
@@ -4212,7 +4440,7 @@ function registerEmailTemplateTools(server, client) {
4212
4440
  title: "List e-mail templates",
4213
4441
  description: "The account\u2019s own e-mail templates, paged by id; kind narrows to transactional (one-to-one) or marketing. The built-in system mails (sign-in, password, receipts) are not among them.",
4214
4442
  inputSchema: {
4215
- kind: z13.enum(["transactional", "marketing"]).optional(),
4443
+ kind: z15.enum(["transactional", "marketing"]).optional(),
4216
4444
  ...page
4217
4445
  },
4218
4446
  annotations: { readOnlyHint: true, idempotentHint: true }
@@ -4246,7 +4474,7 @@ function registerEmailTemplateTools(server, client) {
4246
4474
  }
4247
4475
  }
4248
4476
  );
4249
- const design = z13.record(z13.string(), z13.unknown()).describe(
4477
+ const design = z15.record(z15.string(), z15.unknown()).describe(
4250
4478
  "The e-mail designer\u2019s document, in the shape get_email_template shows."
4251
4479
  );
4252
4480
  server.registerTool(
@@ -4255,14 +4483,14 @@ function registerEmailTemplateTools(server, client) {
4255
4483
  title: "Save a new e-mail template",
4256
4484
  description: "Saves a template; nobody receives anything. The app turns the design into the mail and cleans it.",
4257
4485
  inputSchema: {
4258
- name: z13.string().min(1).max(120),
4259
- subject: z13.string().min(1).max(300),
4486
+ name: z15.string().min(1).max(120),
4487
+ subject: z15.string().min(1).max(300),
4260
4488
  design,
4261
- kind: z13.enum(["transactional", "marketing"]).optional(),
4262
- language: z13.string().min(2).max(10).describe("nl or en."),
4263
- category: z13.string().min(1).max(80).nullable().optional(),
4489
+ kind: z15.enum(["transactional", "marketing"]).optional(),
4490
+ language: z15.string().min(2).max(10).describe("nl or en."),
4491
+ category: z15.string().min(1).max(80).nullable().optional(),
4264
4492
  layoutId: id2.nullable().optional(),
4265
- compositionMode: z13.enum(["layout", "standalone"]).optional()
4493
+ compositionMode: z15.enum(["layout", "standalone"]).optional()
4266
4494
  }
4267
4495
  },
4268
4496
  async (input) => {
@@ -4281,12 +4509,12 @@ function registerEmailTemplateTools(server, client) {
4281
4509
  description: "Only what is sent changes; a design sent replaces the design. Nobody receives anything.",
4282
4510
  inputSchema: {
4283
4511
  id: id2,
4284
- name: z13.string().min(1).max(120).optional(),
4285
- subject: z13.string().min(1).max(300).optional(),
4512
+ name: z15.string().min(1).max(120).optional(),
4513
+ subject: z15.string().min(1).max(300).optional(),
4286
4514
  design: design.optional(),
4287
- category: z13.string().min(1).max(80).nullable().optional(),
4515
+ category: z15.string().min(1).max(80).nullable().optional(),
4288
4516
  layoutId: id2.nullable().optional(),
4289
- compositionMode: z13.enum(["layout", "standalone"]).optional()
4517
+ compositionMode: z15.enum(["layout", "standalone"]).optional()
4290
4518
  },
4291
4519
  annotations: { idempotentHint: true }
4292
4520
  },
@@ -4305,8 +4533,8 @@ function describeTemplate(template) {
4305
4533
  }
4306
4534
 
4307
4535
  // src/event-tools.ts
4308
- import { z as z14 } from "zod";
4309
- var moment = z14.string().datetime({ offset: true }).optional().describe("An ISO timestamp with its offset, such as 2026-11-01T00:00:00Z.");
4536
+ import { z as z16 } from "zod";
4537
+ var moment = z16.string().datetime({ offset: true }).optional().describe("An ISO timestamp with its offset, such as 2026-11-01T00:00:00Z.");
4310
4538
  function registerEventTools(server, client) {
4311
4539
  server.registerTool(
4312
4540
  "list_events",
@@ -4334,7 +4562,7 @@ function registerEventTools(server, client) {
4334
4562
  title: "Read one event",
4335
4563
  description: "One event as its page needs it: description, doors and sales times, address, ticket types with their prices, and the texts for search engines. May be a minute old; ask get_event_availability for seats that must be current.",
4336
4564
  inputSchema: {
4337
- idOrSlug: z14.string().min(1).max(200).describe("The id or the address (slug) of the event.")
4565
+ idOrSlug: z16.string().min(1).max(200).describe("The id or the address (slug) of the event.")
4338
4566
  },
4339
4567
  annotations: { readOnlyHint: true, idempotentHint: true }
4340
4568
  },
@@ -4359,7 +4587,7 @@ function registerEventTools(server, client) {
4359
4587
  title: "Seats left for an event",
4360
4588
  description: "Live, not cached: how many seats are left for the event and for each ticket type, and whether it is sold out. A remaining of null means there is no ceiling.",
4361
4589
  inputSchema: {
4362
- eventId: z14.string().uuid().describe("The id of the event.")
4590
+ eventId: z16.string().uuid().describe("The id of the event.")
4363
4591
  },
4364
4592
  annotations: { readOnlyHint: true, idempotentHint: true }
4365
4593
  },
@@ -4387,8 +4615,8 @@ function describeEvent(event) {
4387
4615
  }
4388
4616
 
4389
4617
  // src/form-definition-tools.ts
4390
- import { z as z15 } from "zod";
4391
- var id3 = z15.string().uuid();
4618
+ import { z as z17 } from "zod";
4619
+ var id3 = z17.string().uuid();
4392
4620
  function registerFormDefinitionTools(server, client) {
4393
4621
  server.registerTool(
4394
4622
  "list_form_definitions",
@@ -4433,9 +4661,9 @@ function registerFormDefinitionTools(server, client) {
4433
4661
  title: "Make a form",
4434
4662
  description: "A new, empty draft form; its address follows from the name. Add fields with update_form.",
4435
4663
  inputSchema: {
4436
- name: z15.string().min(1).max(120),
4437
- submitLabel: z15.string().min(1).max(60).optional(),
4438
- successMessage: z15.string().min(1).max(500).optional()
4664
+ name: z17.string().min(1).max(120),
4665
+ submitLabel: z17.string().min(1).max(60).optional(),
4666
+ successMessage: z17.string().min(1).max(500).optional()
4439
4667
  }
4440
4668
  },
4441
4669
  async (input) => {
@@ -4454,11 +4682,11 @@ function registerFormDefinitionTools(server, client) {
4454
4682
  description: "Only what is sent changes; fields sent replace every field. status published puts the form live at once on every site it is placed on, and needs an e-mail field. What happens after a submission (deals, tasks, tags, mails) is set up in the app.",
4455
4683
  inputSchema: {
4456
4684
  id: id3,
4457
- name: z15.string().min(1).max(120).optional(),
4458
- fields: z15.array(z15.unknown()).max(500).optional(),
4459
- settings: z15.record(z15.string(), z15.unknown()).optional(),
4460
- spamSettings: z15.record(z15.string(), z15.unknown()).optional(),
4461
- status: z15.enum(["draft", "published", "archived"]).optional()
4685
+ name: z17.string().min(1).max(120).optional(),
4686
+ fields: z17.array(z17.unknown()).max(500).optional(),
4687
+ settings: z17.record(z17.string(), z17.unknown()).optional(),
4688
+ spamSettings: z17.record(z17.string(), z17.unknown()).optional(),
4689
+ status: z17.enum(["draft", "published", "archived"]).optional()
4462
4690
  },
4463
4691
  annotations: { idempotentHint: true }
4464
4692
  },
@@ -4477,7 +4705,7 @@ function describeForm(form) {
4477
4705
  }
4478
4706
 
4479
4707
  // src/hosting-order-page-tools.ts
4480
- import { z as z16 } from "zod";
4708
+ import { z as z18 } from "zod";
4481
4709
  function registerHostingOrderPageTools(server, client) {
4482
4710
  server.registerTool(
4483
4711
  "get_hosting_order_page",
@@ -4501,19 +4729,19 @@ function registerHostingOrderPageTools(server, client) {
4501
4729
  title: "Set up the hosting order page",
4502
4730
  description: "Changes the hosting order page; only what is sent changes. `packages` is the whole list in the order the page shows it (product ids from get_hosting_order_page candidates), `allowedOrigins` the whole list of sites the snippet may stand on -- add the site before placing the snippet. `enabled: true` opens real payments. It is refused while the page cannot deliver what it sells; the refusal names what the account owner has to fix in the app themselves (a registrar login, the renewal round still in shadow mode) -- pass that on, do not retry.",
4503
4731
  inputSchema: {
4504
- enabled: z16.boolean().optional(),
4505
- quickTlds: z16.array(z16.string().max(30)).max(12).optional().describe("Extensions without a dot, such as nl, com, be."),
4506
- defaultPeriod: z16.enum(["month", "year"]).optional(),
4507
- packages: z16.array(
4508
- z16.object({
4509
- productId: z16.string().uuid(),
4510
- service: z16.enum(["hosting", "email"]),
4511
- featured: z16.boolean().optional(),
4512
- badge: z16.string().max(40).nullable().optional(),
4513
- highlights: z16.array(z16.string().max(80)).max(4).optional()
4732
+ enabled: z18.boolean().optional(),
4733
+ quickTlds: z18.array(z18.string().max(30)).max(12).optional().describe("Extensions without a dot, such as nl, com, be."),
4734
+ defaultPeriod: z18.enum(["month", "year"]).optional(),
4735
+ packages: z18.array(
4736
+ z18.object({
4737
+ productId: z18.string().uuid(),
4738
+ service: z18.enum(["hosting", "email"]),
4739
+ featured: z18.boolean().optional(),
4740
+ badge: z18.string().max(40).nullable().optional(),
4741
+ highlights: z18.array(z18.string().max(80)).max(4).optional()
4514
4742
  })
4515
4743
  ).max(24).optional(),
4516
- allowedOrigins: z16.array(z16.string().max(255)).max(20).optional().describe(
4744
+ allowedOrigins: z18.array(z18.string().max(255)).max(20).optional().describe(
4517
4745
  "Origins such as https://example.com: no path, lower case."
4518
4746
  )
4519
4747
  },
@@ -4546,7 +4774,7 @@ function describe(page2) {
4546
4774
  }
4547
4775
 
4548
4776
  // src/order-tools.ts
4549
- import { z as z17 } from "zod";
4777
+ import { z as z19 } from "zod";
4550
4778
  function registerOrderTools(server, client) {
4551
4779
  server.registerTool(
4552
4780
  "get_order",
@@ -4554,7 +4782,7 @@ function registerOrderTools(server, client) {
4554
4782
  title: "Read one order",
4555
4783
  description: "One order by its number, its id or its Stripe PaymentIntent (pi_\u2026): payment status, whether it was sent, the lines and the totals. Live, never cached. It does not say who bought it or where it went, and it cannot change, ship or refund an order: that is done in the app.",
4556
4784
  inputSchema: {
4557
- ref: z17.string().min(1).max(200).describe("The order number, its id, or a pi_\u2026 PaymentIntent id.")
4785
+ ref: z19.string().min(1).max(200).describe("The order number, its id, or a pi_\u2026 PaymentIntent id.")
4558
4786
  },
4559
4787
  annotations: { readOnlyHint: true, idempotentHint: true }
4560
4788
  },
@@ -4570,29 +4798,59 @@ function registerOrderTools(server, client) {
4570
4798
  }
4571
4799
  }
4572
4800
  );
4801
+ server.registerTool(
4802
+ "list_orders",
4803
+ {
4804
+ title: "List orders",
4805
+ description: "The account\u2019s orders paged by id, in the shape get_order reads one. sellerRef narrows them to orders paid through a payment link that carried ?ref=<sellerRef> -- how whoever sent the link learns it was paid, and which customer account the order made (clientAccountId). Never who bought it.",
4806
+ inputSchema: {
4807
+ sellerRef: z19.string().regex(/^[A-Za-z0-9_-]{1,64}$/).optional().describe("The ?ref= the payment link carried."),
4808
+ ...page
4809
+ },
4810
+ annotations: { readOnlyHint: true, idempotentHint: true }
4811
+ },
4812
+ async (input) => {
4813
+ try {
4814
+ const result = await client.getOrders(input);
4815
+ return answer(
4816
+ result.data.length === 0 ? input.sellerRef ? `No order carries the mark "${input.sellerRef}".` : "No orders." : [
4817
+ ...result.data.map((order) => describeOrder(order)),
4818
+ more(result.nextCursor)
4819
+ ].filter(Boolean).join("\n\n"),
4820
+ result
4821
+ );
4822
+ } catch (error) {
4823
+ return refusal(error, "orders:read");
4824
+ }
4825
+ }
4826
+ );
4573
4827
  }
4574
4828
  function describeOrder(order) {
4575
4829
  const test = order.livemode ? "" : " (test)";
4576
4830
  const lines = order.lines.map(
4577
4831
  (line2) => `- ${line2.quantity} \xD7 ${line2.name}: ${money(line2.totalCents, order.currency)}`
4578
4832
  );
4833
+ const made = order.clientAccountId ? `Customer account: ${order.clientAccountId}.` : "";
4834
+ const mark = order.sellerRef ? `Mark: ${order.sellerRef}.` : "";
4579
4835
  return [
4580
4836
  `Order ${order.number}${test}: ${order.status}, ${order.fulfilmentStatus}, ${money(order.totalCents, order.currency)}.`,
4581
- ...lines
4582
- ].join("\n");
4837
+ ...lines,
4838
+ mark,
4839
+ made
4840
+ ].filter(Boolean).join("\n");
4583
4841
  }
4584
4842
 
4585
4843
  // src/payment-page-tools.ts
4586
- import { z as z18 } from "zod";
4587
- var id4 = z18.string().uuid();
4588
- var slug = z18.string().min(2).max(64).regex(/^[a-z0-9]+(-[a-z0-9]+)*$/).describe("Lowercase letters, digits and hyphens.");
4844
+ import { z as z20 } from "zod";
4845
+ var id4 = z20.string().uuid();
4846
+ var slug2 = z20.string().min(2).max(64).regex(/^[a-z0-9]+(-[a-z0-9]+)*$/).describe("Lowercase letters, digits and hyphens.");
4589
4847
  function registerPaymentPageTools(server, client) {
4590
4848
  server.registerTool(
4591
4849
  "list_payment_pages",
4592
4850
  {
4593
4851
  title: "List payment pages",
4594
4852
  description: "The account\u2019s payment pages, paged by id; archived ones only with archived: true.",
4595
- inputSchema: { archived: z18.boolean().optional(), ...page },
4853
+ inputSchema: { archived: z20.boolean().optional(), ...page },
4596
4854
  annotations: { readOnlyHint: true, idempotentHint: true }
4597
4855
  },
4598
4856
  async (input) => {
@@ -4635,8 +4893,8 @@ ${blockers}`, page2);
4635
4893
  title: "Make a payment page",
4636
4894
  description: "A draft payment page for one of the account\u2019s products. Nothing is live until a person publishes it in the app. Without priceId the buyer picks from the product\u2019s active price options.",
4637
4895
  inputSchema: {
4638
- name: z18.string().min(1).max(120),
4639
- slug: slug.optional(),
4896
+ name: z20.string().min(1).max(120),
4897
+ slug: slug2.optional(),
4640
4898
  productId: id4,
4641
4899
  priceId: id4.optional()
4642
4900
  }
@@ -4657,13 +4915,13 @@ ${blockers}`, page2);
4657
4915
  description: "Only what is sent changes. content takes whole blocks: hero {headline, subheadline}, bullets {title, items}, quote {text, author, role}, guarantee {title, body}, faq {items: [{question, answer}]}, trust {items}, paymentOptions {recommendedPriceId, note}; a block left out stays. settings takes termsUrl, requireFields, excludedPaymentMethods (what is switched OFF), thankYouMode, redirectUrl, createInvoice, maxQuantity, customFields, tagOnPurchase. status goes back to draft (off the web) or archived; publishing is done in the app. A new slug breaks links already sent.",
4658
4916
  inputSchema: {
4659
4917
  id: id4,
4660
- name: z18.string().min(1).max(120).optional(),
4661
- slug: slug.optional(),
4918
+ name: z20.string().min(1).max(120).optional(),
4919
+ slug: slug2.optional(),
4662
4920
  productId: id4.optional(),
4663
4921
  priceId: id4.nullable().optional(),
4664
- status: z18.enum(["draft", "archived"]).optional(),
4665
- content: z18.record(z18.string(), z18.unknown()).optional(),
4666
- settings: z18.record(z18.string(), z18.unknown()).optional()
4922
+ status: z20.enum(["draft", "archived"]).optional(),
4923
+ content: z20.record(z20.string(), z20.unknown()).optional(),
4924
+ settings: z20.record(z20.string(), z20.unknown()).optional()
4667
4925
  },
4668
4926
  annotations: { idempotentHint: true }
4669
4927
  },
@@ -4682,9 +4940,9 @@ function describePage(page2) {
4682
4940
  }
4683
4941
 
4684
4942
  // src/placement-tools.ts
4685
- import { z as z19 } from "zod";
4943
+ import { z as z21 } from "zod";
4686
4944
  var REACT_HINT = "On a React or Next.js site, prefer the components in `@solumflow-app/crm-client/react` (CrmForm, CrmBooking, CrmChatWidget, CrmSiteTracking) over pasting HTML.";
4687
- var origin = z19.string().regex(/^https?:\/\/[a-zA-Z0-9.-]+(:[0-9]{1,5})?$/).describe("Scheme, host and optional port; no path: https://www.example.com");
4945
+ var origin = z21.string().regex(/^https?:\/\/[a-zA-Z0-9.-]+(:[0-9]{1,5})?$/).describe("Scheme, host and optional port; no path: https://www.example.com");
4688
4946
  function registerPlacementTools(server, client) {
4689
4947
  server.registerTool(
4690
4948
  "list_forms",
@@ -4757,13 +5015,13 @@ function registerPlacementTools(server, client) {
4757
5015
  title: "Make or change a chat widget",
4758
5016
  description: "Makes the chat widget at this address when there is none, or changes it. Sets its name, whether it is live, and which sites it may run on. How it looks and what it says is done in the app\u2019s builder. Sites are added and removed, never replaced. Careful: an empty list means ANY site, so adding the first origin narrows the widget to that site only, and removing an origin takes the chat off a site that may be live.",
4759
5017
  inputSchema: {
4760
- slug: z19.string().regex(/^[a-z][a-z0-9-]*$/).max(100).describe(
5018
+ slug: z21.string().regex(/^[a-z][a-z0-9-]*$/).max(100).describe(
4761
5019
  'The widget\u2019s address on this account, such as "website-chat".'
4762
5020
  ),
4763
- name: z19.string().min(1).max(200).optional().describe("Required when the widget does not exist yet."),
4764
- status: z19.enum(["draft", "published"]).optional().describe("Only a published widget answers on a site."),
4765
- addAllowedOrigins: z19.array(origin).max(20).optional(),
4766
- removeAllowedOrigins: z19.array(origin).max(20).optional()
5021
+ name: z21.string().min(1).max(200).optional().describe("Required when the widget does not exist yet."),
5022
+ status: z21.enum(["draft", "published"]).optional().describe("Only a published widget answers on a site."),
5023
+ addAllowedOrigins: z21.array(origin).max(20).optional(),
5024
+ removeAllowedOrigins: z21.array(origin).max(20).optional()
4767
5025
  },
4768
5026
  annotations: {
4769
5027
  readOnlyHint: false,
@@ -4771,9 +5029,9 @@ function registerPlacementTools(server, client) {
4771
5029
  idempotentHint: true
4772
5030
  }
4773
5031
  },
4774
- async ({ slug: slug2, ...input }) => {
5032
+ async ({ slug: slug3, ...input }) => {
4775
5033
  try {
4776
- const widget = await client.upsertChatWidget(slug2, input);
5034
+ const widget = await client.upsertChatWidget(slug3, input);
4777
5035
  return answer(
4778
5036
  `${widget.created ? "Made" : "Updated"} the widget.
4779
5037
 
@@ -4811,9 +5069,9 @@ ${describeChatWidget(widget)}`,
4811
5069
  title: "Set up or change the tracking script",
4812
5070
  description: "Sets website tracking up when it is not there, adds or removes the hosts it counts visits from, and changes the consent it waits for. An empty list of hosts counts nothing, so add the host of every site the script is placed on. Hosts are added and removed, never replaced.",
4813
5071
  inputSchema: {
4814
- addAllowedHosts: z19.array(z19.string()).max(20).optional().describe('Hosts such as "www.example.com" or "*.example.com".'),
4815
- removeAllowedHosts: z19.array(z19.string()).max(20).optional(),
4816
- consentSignal: z19.enum([
5072
+ addAllowedHosts: z21.array(z21.string()).max(20).optional().describe('Hosts such as "www.example.com" or "*.example.com".'),
5073
+ removeAllowedHosts: z21.array(z21.string()).max(20).optional(),
5074
+ consentSignal: z21.enum([
4817
5075
  "ad_storage",
4818
5076
  "analytics_storage",
4819
5077
  "personalization_storage",
@@ -4874,14 +5132,14 @@ function describeSiteTracking(site) {
4874
5132
  }
4875
5133
 
4876
5134
  // src/record-tools.ts
4877
- import { z as z20 } from "zod";
4878
- var recordId = z20.string().uuid().describe("The id of the record.");
4879
- var values = z20.record(z20.string(), z20.unknown()).describe(
5135
+ import { z as z22 } from "zod";
5136
+ var recordId = z22.string().uuid().describe("The id of the record.");
5137
+ var values = z22.record(z22.string(), z22.unknown()).describe(
4880
5138
  "Field values by field slug, as list_record_lists names them. A field marked sensitive is refused."
4881
5139
  );
4882
- var tags = z20.object({
4883
- add: z20.array(z20.string().uuid()).max(50).optional(),
4884
- remove: z20.array(z20.string().uuid()).max(50).optional()
5140
+ var tags = z22.object({
5141
+ add: z22.array(z22.string().uuid()).max(50).optional(),
5142
+ remove: z22.array(z22.string().uuid()).max(50).optional()
4885
5143
  }).optional().describe("Tag ids to put on or take off; list_tags names them.");
4886
5144
  function registerRecordTools(server, client) {
4887
5145
  server.registerTool(
@@ -4906,8 +5164,8 @@ function registerRecordTools(server, client) {
4906
5164
  title: "Search the records of one list",
4907
5165
  description: "The records of one list, by its slug, paged. q searches the name and every value but a sensitive one. Records whose processing is restricted are left out.",
4908
5166
  inputSchema: {
4909
- list: z20.string().min(1).max(64).describe("The slug of the list."),
4910
- q: z20.string().max(200).optional(),
5167
+ list: z22.string().min(1).max(64).describe("The slug of the list."),
5168
+ q: z22.string().max(200).optional(),
4911
5169
  ...page
4912
5170
  },
4913
5171
  annotations: { readOnlyHint: true, idempotentHint: true }
@@ -4947,7 +5205,7 @@ function registerRecordTools(server, client) {
4947
5205
  title: "Make a record",
4948
5206
  description: "A new record in a list (left out: a person, where the account puts new contacts). A person whose e-mail or phone is already known is not made again: the answer gives only their id (matched), nothing on them changes, and get_record reads them; use update_record to change them. Automations that start on a new record run as they do for one made in the app.",
4949
5207
  inputSchema: {
4950
- list: z20.string().min(1).max(64).optional(),
5208
+ list: z22.string().min(1).max(64).optional(),
4951
5209
  values,
4952
5210
  tags
4953
5211
  }
@@ -4973,7 +5231,7 @@ function registerRecordTools(server, client) {
4973
5231
  id: recordId,
4974
5232
  values: values.optional(),
4975
5233
  tags,
4976
- ownerId: z20.string().uuid().nullable().optional()
5234
+ ownerId: z22.string().uuid().nullable().optional()
4977
5235
  },
4978
5236
  annotations: { idempotentHint: true }
4979
5237
  },
@@ -5037,7 +5295,7 @@ function registerRecordTools(server, client) {
5037
5295
  description: "A note on a record\u2019s timeline, shown as written through the API with the name of this key.",
5038
5296
  inputSchema: {
5039
5297
  recordId,
5040
- body: z20.string().min(1).max(2e4)
5298
+ body: z22.string().min(1).max(2e4)
5041
5299
  }
5042
5300
  },
5043
5301
  async ({ recordId: id7, body }) => {
@@ -5055,12 +5313,12 @@ function registerRecordTools(server, client) {
5055
5313
  title: "Add a contact, or find the one already known",
5056
5314
  description: "A person by e-mail address. Somebody already known by that address is matched rather than made twice (created: false), and the answer is their id. A field left out is never cleared on a contact already known.",
5057
5315
  inputSchema: {
5058
- email: z20.string().email().max(320),
5059
- firstName: z20.string().trim().min(1).max(200).optional(),
5060
- lastName: z20.string().trim().min(1).max(200).optional(),
5061
- phone: z20.string().trim().min(1).max(50).optional(),
5062
- company: z20.string().trim().min(1).max(200).optional(),
5063
- object: z20.string().trim().min(1).max(64).optional().describe(
5316
+ email: z22.string().email().max(320),
5317
+ firstName: z22.string().trim().min(1).max(200).optional(),
5318
+ lastName: z22.string().trim().min(1).max(200).optional(),
5319
+ phone: z22.string().trim().min(1).max(50).optional(),
5320
+ company: z22.string().trim().min(1).max(200).optional(),
5321
+ object: z22.string().trim().min(1).max(64).optional().describe(
5064
5322
  "The slug of the list for people a new contact goes into; left out, the account\u2019s own choice."
5065
5323
  )
5066
5324
  },
@@ -5142,20 +5400,20 @@ function registerServerInfoTool(server, info) {
5142
5400
  }
5143
5401
 
5144
5402
  // src/shop-setup-tools.ts
5145
- import { z as z21 } from "zod";
5146
- var id5 = z21.string().uuid();
5147
- var cents2 = z21.number().int().min(0).max(99999999);
5148
- var region = z21.object({
5149
- countryCode: z21.string().regex(/^[A-Z]{2}$/).describe("Two capital letters, ISO 3166 (NL, BE, DE)."),
5150
- postcodeFrom: z21.string().max(20).nullable().default(null).describe("With postcodeTo: only this range of the country."),
5151
- postcodeTo: z21.string().max(20).nullable().default(null)
5403
+ import { z as z23 } from "zod";
5404
+ var id5 = z23.string().uuid();
5405
+ var cents2 = z23.number().int().min(0).max(99999999);
5406
+ var region = z23.object({
5407
+ countryCode: z23.string().regex(/^[A-Z]{2}$/).describe("Two capital letters, ISO 3166 (NL, BE, DE)."),
5408
+ postcodeFrom: z23.string().max(20).nullable().default(null).describe("With postcodeTo: only this range of the country."),
5409
+ postcodeTo: z23.string().max(20).nullable().default(null)
5152
5410
  });
5153
- var discount = z21.object({
5154
- name: z21.string().min(1).max(120).describe("What the team sees it as."),
5155
- code: z21.string().max(40).nullable().describe(
5411
+ var discount = z23.object({
5412
+ name: z23.string().min(1).max(120).describe("What the team sees it as."),
5413
+ code: z23.string().max(40).nullable().describe(
5156
5414
  "What a buyer types (upper-cased), or null for one that applies on its own."
5157
5415
  ),
5158
- effect: z21.enum([
5416
+ effect: z23.enum([
5159
5417
  "tier_price",
5160
5418
  "percent_off_lines",
5161
5419
  "amount_off_lines",
@@ -5165,19 +5423,19 @@ var discount = z21.object({
5165
5423
  ]).describe(
5166
5424
  "tier_price: a lower price from tierMinQuantity of one product; *_lines: off each matching line; *_order: once off the whole order; free_shipping: no postage."
5167
5425
  ),
5168
- percent: z21.number().nullable().describe("For a percentage: above 0, at most 100."),
5169
- amountCents: z21.number().int().nullable().describe("For an amount, in currency, as the account enters prices."),
5170
- currency: z21.string().regex(/^[A-Z]{3}$/).nullable().describe("Required beside amountCents (EUR)."),
5171
- tierMinQuantity: z21.number().int().nullable(),
5172
- minSubtotalCents: z21.number().int().nullable().describe("Only from this basket value, before discount."),
5173
- productIds: z21.array(id5).max(500).describe("Empty: every product."),
5174
- categoryIds: z21.array(id5).max(100),
5175
- objectIds: z21.array(id5).max(20),
5176
- startsAt: z21.string().datetime({ offset: true }).nullable(),
5177
- endsAt: z21.string().datetime({ offset: true }).nullable(),
5178
- maxUses: z21.number().int().positive().nullable(),
5179
- maxUsesPerEmail: z21.number().int().positive().nullable(),
5180
- combinable: z21.boolean().describe(
5426
+ percent: z23.number().nullable().describe("For a percentage: above 0, at most 100."),
5427
+ amountCents: z23.number().int().nullable().describe("For an amount, in currency, as the account enters prices."),
5428
+ currency: z23.string().regex(/^[A-Z]{3}$/).nullable().describe("Required beside amountCents (EUR)."),
5429
+ tierMinQuantity: z23.number().int().nullable(),
5430
+ minSubtotalCents: z23.number().int().nullable().describe("Only from this basket value, before discount."),
5431
+ productIds: z23.array(id5).max(500).describe("Empty: every product."),
5432
+ categoryIds: z23.array(id5).max(100),
5433
+ objectIds: z23.array(id5).max(20),
5434
+ startsAt: z23.string().datetime({ offset: true }).nullable(),
5435
+ endsAt: z23.string().datetime({ offset: true }).nullable(),
5436
+ maxUses: z23.number().int().positive().nullable(),
5437
+ maxUsesPerEmail: z23.number().int().positive().nullable(),
5438
+ combinable: z23.boolean().describe(
5181
5439
  "Whether it may count beside another discount on the same order."
5182
5440
  )
5183
5441
  });
@@ -5230,8 +5488,8 @@ function registerShopSetupTools(server, client) {
5230
5488
  description: "A zone is a name and the countries (or postcode ranges) it covers. Without id a new zone; with one, that zone renamed and its places replaced by these. Answers the zone id, for upsert_shipping_method.",
5231
5489
  inputSchema: {
5232
5490
  id: id5.optional().describe("The zone to change; leave out for a new one."),
5233
- name: z21.string().min(1).max(80),
5234
- regions: z21.array(region).max(300).default([])
5491
+ name: z23.string().min(1).max(80),
5492
+ regions: z23.array(region).max(300).default([])
5235
5493
  },
5236
5494
  annotations: { idempotentHint: true }
5237
5495
  },
@@ -5255,14 +5513,14 @@ function registerShopSetupTools(server, client) {
5255
5513
  inputSchema: {
5256
5514
  id: id5.optional(),
5257
5515
  zoneId: id5,
5258
- kind: z21.enum(["flat_rate", "free_shipping", "local_pickup"]),
5259
- name: z21.string().min(1).max(80).describe("What the buyer chooses."),
5260
- enabled: z21.boolean().default(true),
5516
+ kind: z23.enum(["flat_rate", "free_shipping", "local_pickup"]),
5517
+ name: z23.string().min(1).max(80).describe("What the buyer chooses."),
5518
+ enabled: z23.boolean().default(true),
5261
5519
  amountCents: cents2.default(0),
5262
5520
  noClassAmountCents: cents2.default(0),
5263
5521
  taxRateId: id5.nullish(),
5264
5522
  freeThresholdCents: cents2.nullish(),
5265
- classRates: z21.array(z21.object({ classId: id5, amountCents: cents2 })).max(100).default([])
5523
+ classRates: z23.array(z23.object({ classId: id5, amountCents: cents2 })).max(100).default([])
5266
5524
  },
5267
5525
  annotations: { idempotentHint: true }
5268
5526
  },
@@ -5283,7 +5541,7 @@ function registerShopSetupTools(server, client) {
5283
5541
  {
5284
5542
  title: "List discounts",
5285
5543
  description: "The account discounts, newest first, at most 200: codes, the ones that apply on their own, and tier prices, with every condition and how many paid orders used each. Archived ones only with archived: true.",
5286
- inputSchema: { archived: z21.boolean().optional() },
5544
+ inputSchema: { archived: z23.boolean().optional() },
5287
5545
  annotations: { readOnlyHint: true, idempotentHint: true }
5288
5546
  },
5289
5547
  async ({ archived }) => {
@@ -5325,7 +5583,7 @@ function registerShopSetupTools(server, client) {
5325
5583
  description: "Stops a discount from giving anything to a new cart or order; orders that used it keep it. archived: false brings it back. Deleting is left to a person in the app.",
5326
5584
  inputSchema: {
5327
5585
  id: id5,
5328
- archived: z21.boolean().default(true)
5586
+ archived: z23.boolean().default(true)
5329
5587
  },
5330
5588
  annotations: { idempotentHint: true }
5331
5589
  },
@@ -5390,9 +5648,9 @@ function registerShopSetupTools(server, client) {
5390
5648
  description: "Point the account at the site revalidation route (with the SDK: https://<site>/api/solumflow/revalidate) so its cached pages follow a product the moment it changes. Without id a new address: the answer carries its signing key once -- put it in the site environment as SOLUMFLOW_WEBHOOK_KEY, it cannot be read back. https only, never a private network.",
5391
5649
  inputSchema: {
5392
5650
  id: id5.optional(),
5393
- name: z21.string().min(1).max(80),
5394
- url: z21.string().url().max(2048),
5395
- events: z21.array(z21.string().min(1).max(60)).min(1).max(20).describe(
5651
+ name: z23.string().min(1).max(80),
5652
+ url: z23.string().url().max(2048),
5653
+ events: z23.array(z23.string().min(1).max(60)).min(1).max(20).describe(
5396
5654
  "For a shop: product.changed, product.deleted, category.changed."
5397
5655
  )
5398
5656
  },
@@ -5428,7 +5686,7 @@ function describeDiscount(entry) {
5428
5686
  }
5429
5687
 
5430
5688
  // src/shop-test-order-tool.ts
5431
- import { z as z22 } from "zod";
5689
+ import { z as z24 } from "zod";
5432
5690
  var PAID_POLLS = 10;
5433
5691
  var PAID_POLL_MS = 1500;
5434
5692
  function registerShopTestOrderTool(server, client, options = {}) {
@@ -5439,25 +5697,25 @@ function registerShopTestOrderTool(server, client, options = {}) {
5439
5697
  title: "Place and pay a test order",
5440
5698
  description: "Proves the shop end to end in Stripe test mode: puts one product in a cart, chooses postage, places the order, pays it with Stripe test card 4242, and reads the order back until it is paid (the invoice and the confirmation mail follow from there). Refused when the account is live -- no real money can move through this tool. Needs a key with shop:manage, cart:write, orders:write and orders:read. Pass `extras` (products from the product\u2019s own `extras` list) and `options` (by option key: a text, true, or a choice key) to prove a product with an extra or a surcharge option; the cart must show them, priced by the server, before the order is placed. Never send an amount.",
5441
5699
  inputSchema: {
5442
- email: z22.string().email().describe(
5700
+ email: z24.string().email().describe(
5443
5701
  "Where the confirmation goes: the shop owner, never a customer."
5444
5702
  ),
5445
- productId: z22.string().uuid().optional().describe(
5703
+ productId: z24.string().uuid().optional().describe(
5446
5704
  "The product to buy; leave out for the first one in stock."
5447
5705
  ),
5448
- countryCode: z22.string().regex(/^[A-Z]{2}$/).default("NL").describe("Where it is posted, for a product that is posted."),
5449
- postalCode: z22.string().max(20).optional(),
5450
- extras: z22.array(
5451
- z22.object({
5452
- productId: z22.string().uuid(),
5453
- quantity: z22.number().int().min(1).max(99).default(1)
5706
+ countryCode: z24.string().regex(/^[A-Z]{2}$/).default("NL").describe("Where it is posted, for a product that is posted."),
5707
+ postalCode: z24.string().max(20).optional(),
5708
+ extras: z24.array(
5709
+ z24.object({
5710
+ productId: z24.string().uuid(),
5711
+ quantity: z24.number().int().min(1).max(99).default(1)
5454
5712
  })
5455
5713
  ).max(10).optional().describe(
5456
5714
  "Extras to take with the product, each a product from its `extras`; for one that follows its line the quantity is per piece."
5457
5715
  ),
5458
- options: z22.record(
5459
- z22.string().regex(/^[a-z0-9_]{1,40}$/),
5460
- z22.union([z22.string().max(2e3), z22.boolean()])
5716
+ options: z24.record(
5717
+ z24.string().regex(/^[a-z0-9_]{1,40}$/),
5718
+ z24.union([z24.string().max(2e3), z24.boolean()])
5461
5719
  ).optional().describe(
5462
5720
  "The choices for the product\u2019s options, by option key: a text, true for a ticked box, or the key of a choice."
5463
5721
  )
@@ -5584,9 +5842,9 @@ function registerShopTestOrderTool(server, client, options = {}) {
5584
5842
  }
5585
5843
 
5586
5844
  // src/task-tools.ts
5587
- import { z as z23 } from "zod";
5588
- var id6 = z23.string().uuid();
5589
- var moment2 = z23.string().datetime({ offset: true }).describe(
5845
+ import { z as z25 } from "zod";
5846
+ var id6 = z25.string().uuid();
5847
+ var moment2 = z25.string().datetime({ offset: true }).describe(
5590
5848
  "An ISO moment with its offset, such as 2026-11-01T09:00:00+01:00."
5591
5849
  );
5592
5850
  var OUTSIDE_PROJECTS = "Only tasks outside projects: a project\u2019s tasks are seen differently per member and are worked on in the app.";
@@ -5597,7 +5855,7 @@ function registerTaskTools(server, client) {
5597
5855
  title: "List tasks",
5598
5856
  description: `Tasks paged by id: open and in progress unless status says otherwise; recordId, dealId and assigneeId narrow them. ${OUTSIDE_PROJECTS}`,
5599
5857
  inputSchema: {
5600
- status: z23.enum(["open", "in_progress", "done", "all"]).optional(),
5858
+ status: z25.enum(["open", "in_progress", "done", "all"]).optional(),
5601
5859
  recordId: id6.optional(),
5602
5860
  dealId: id6.optional(),
5603
5861
  assigneeId: id6.optional(),
@@ -5643,14 +5901,14 @@ function registerTaskTools(server, client) {
5643
5901
  title: "Make a task",
5644
5902
  description: `A task on a contact (recordId), on a deal (dealId; with recordId one of that contact\u2019s deals), or on nothing, optionally due, prioritised and assigned to members. ${OUTSIDE_PROJECTS}`,
5645
5903
  inputSchema: {
5646
- title: z23.string().min(1).max(500),
5647
- description: z23.string().max(2e4).nullable().optional(),
5904
+ title: z25.string().min(1).max(500),
5905
+ description: z25.string().max(2e4).nullable().optional(),
5648
5906
  dueAt: moment2.nullable().optional(),
5649
- priority: z23.enum(["low", "normal", "high"]).optional(),
5907
+ priority: z25.enum(["low", "normal", "high"]).optional(),
5650
5908
  recordId: id6.nullable().optional(),
5651
5909
  dealId: id6.nullable().optional(),
5652
5910
  parentTaskId: id6.nullable().optional(),
5653
- assigneeIds: z23.array(id6).max(20).optional()
5911
+ assigneeIds: z25.array(id6).max(20).optional()
5654
5912
  }
5655
5913
  },
5656
5914
  async (input) => {
@@ -5669,12 +5927,12 @@ function registerTaskTools(server, client) {
5669
5927
  description: `Changes only what is sent; status done completes it. assigneeIds replaces who works on it. ${OUTSIDE_PROJECTS}`,
5670
5928
  inputSchema: {
5671
5929
  id: id6,
5672
- title: z23.string().min(1).max(500).optional(),
5673
- description: z23.string().max(2e4).nullable().optional(),
5930
+ title: z25.string().min(1).max(500).optional(),
5931
+ description: z25.string().max(2e4).nullable().optional(),
5674
5932
  dueAt: moment2.nullable().optional(),
5675
- priority: z23.enum(["low", "normal", "high"]).optional(),
5676
- status: z23.enum(["open", "in_progress", "done"]).optional(),
5677
- assigneeIds: z23.array(id6).max(20).optional()
5933
+ priority: z25.enum(["low", "normal", "high"]).optional(),
5934
+ status: z25.enum(["open", "in_progress", "done"]).optional(),
5935
+ assigneeIds: z25.array(id6).max(20).optional()
5678
5936
  },
5679
5937
  annotations: { idempotentHint: true }
5680
5938
  },
@@ -5695,7 +5953,7 @@ function registerTaskTools(server, client) {
5695
5953
  inputSchema: {
5696
5954
  from: moment2,
5697
5955
  to: moment2,
5698
- kind: z23.enum(["appointment", "block", "all"]).optional(),
5956
+ kind: z25.enum(["appointment", "block", "all"]).optional(),
5699
5957
  contactRecordId: id6.optional(),
5700
5958
  ...page
5701
5959
  },
@@ -5744,14 +6002,14 @@ function describeAppointment(appointment) {
5744
6002
  }
5745
6003
 
5746
6004
  // src/tool-definitions-version.ts
5747
- import { z as z24 } from "zod";
6005
+ import { z as z26 } from "zod";
5748
6006
  import { createHash } from "crypto";
5749
6007
  function toolDefinitionsHash(tools) {
5750
6008
  const definitions = [...tools].sort((left, right) => left.name.localeCompare(right.name)).map(({ name, config }) => ({
5751
6009
  name,
5752
6010
  title: config.title ?? null,
5753
6011
  description: config.description ?? null,
5754
- inputSchema: config.inputSchema ? z24.toJSONSchema(z24.object(config.inputSchema), {
6012
+ inputSchema: config.inputSchema ? z26.toJSONSchema(z26.object(config.inputSchema), {
5755
6013
  io: "input",
5756
6014
  unrepresentable: "any"
5757
6015
  }) : null,
@@ -5799,7 +6057,7 @@ function holdToolRegistrations(real) {
5799
6057
  description: `${config.description ?? ""} Definitions version ${version2}: send it as schemaHash and the answer tells you when these tool definitions are older than the server.`,
5800
6058
  inputSchema: {
5801
6059
  ...config.inputSchema,
5802
- schemaHash: z24.string().max(64).optional().describe(
6060
+ schemaHash: z26.string().max(64).optional().describe(
5803
6061
  `The definitions version named in this tool's description (${version2}).`
5804
6062
  )
5805
6063
  }
@@ -5872,6 +6130,8 @@ async function main() {
5872
6130
  registerConsentBannerTools(held.server, client);
5873
6131
  registerHostingOrderPageTools(held.server, client);
5874
6132
  registerTaskTools(held.server, client);
6133
+ registerClientAccountTools(held.server, client);
6134
+ registerCalendarSetupTools(held.server, client);
5875
6135
  held.publish();
5876
6136
  await server.connect(new StdioServerTransport());
5877
6137
  try {