@open-mercato/core 0.8.1-develop.7454.1.010095490f → 0.8.1-develop.7455.1.8f7e53badb

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities/customer_dictionary_entry/index.js +2 -0
  3. package/dist/generated/entities/customer_dictionary_entry/index.js.map +2 -2
  4. package/dist/generated/entities/customer_interaction/index.js +2 -0
  5. package/dist/generated/entities/customer_interaction/index.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +2 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/modules/customers/api/activity-types/route.js +151 -0
  9. package/dist/modules/customers/api/activity-types/route.js.map +7 -0
  10. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +13 -5
  11. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
  12. package/dist/modules/customers/api/dictionaries/[kind]/route.js +20 -5
  13. package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
  14. package/dist/modules/customers/api/interactions/route.js +3 -0
  15. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  16. package/dist/modules/customers/api/interactions/tasks/route.js +1 -0
  17. package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
  18. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js +18 -0
  19. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js.map +2 -2
  20. package/dist/modules/customers/calendar-event-types.js +548 -0
  21. package/dist/modules/customers/calendar-event-types.js.map +7 -0
  22. package/dist/modules/customers/commands/dictionaries.js +70 -10
  23. package/dist/modules/customers/commands/dictionaries.js.map +2 -2
  24. package/dist/modules/customers/commands/interactions.js +187 -22
  25. package/dist/modules/customers/commands/interactions.js.map +3 -3
  26. package/dist/modules/customers/components/ActivityTypeEditor.js +288 -0
  27. package/dist/modules/customers/components/ActivityTypeEditor.js.map +7 -0
  28. package/dist/modules/customers/components/DictionarySettings.js +3 -1
  29. package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
  30. package/dist/modules/customers/components/calendar/CalendarEventEditor.js +391 -297
  31. package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +3 -3
  32. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +9 -74
  33. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
  34. package/dist/modules/customers/components/calendar/TimeGrid.js +20 -16
  35. package/dist/modules/customers/components/calendar/TimeGrid.js.map +2 -2
  36. package/dist/modules/customers/components/calendar/editor/EventTypePanel.js +218 -0
  37. package/dist/modules/customers/components/calendar/editor/EventTypePanel.js.map +7 -0
  38. package/dist/modules/customers/components/calendar/editor/LocationField.js +7 -3
  39. package/dist/modules/customers/components/calendar/editor/LocationField.js.map +2 -2
  40. package/dist/modules/customers/components/calendar/editor/PeopleField.js +5 -2
  41. package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
  42. package/dist/modules/customers/components/calendar/editor/PriorityField.js +3 -1
  43. package/dist/modules/customers/components/calendar/editor/PriorityField.js.map +2 -2
  44. package/dist/modules/customers/components/calendar/editor/RepeatField.js +9 -1
  45. package/dist/modules/customers/components/calendar/editor/RepeatField.js.map +2 -2
  46. package/dist/modules/customers/components/calendar/editor/ResourcesField.js +4 -1
  47. package/dist/modules/customers/components/calendar/editor/ResourcesField.js.map +2 -2
  48. package/dist/modules/customers/components/calendar/editor/ScheduleSection.js +15 -7
  49. package/dist/modules/customers/components/calendar/editor/ScheduleSection.js.map +2 -2
  50. package/dist/modules/customers/components/calendar/editor/SegmentGroup.js +3 -1
  51. package/dist/modules/customers/components/calendar/editor/SegmentGroup.js.map +2 -2
  52. package/dist/modules/customers/components/calendar/editor/hooks.js +28 -13
  53. package/dist/modules/customers/components/calendar/editor/hooks.js.map +3 -3
  54. package/dist/modules/customers/components/calendar/editor/inputs.js +14 -6
  55. package/dist/modules/customers/components/calendar/editor/inputs.js.map +2 -2
  56. package/dist/modules/customers/components/calendar/editor/useCalendarCustomFields.js +54 -0
  57. package/dist/modules/customers/components/calendar/editor/useCalendarCustomFields.js.map +7 -0
  58. package/dist/modules/customers/components/calendar/editor/useEventTypeCatalog.js +82 -0
  59. package/dist/modules/customers/components/calendar/editor/useEventTypeCatalog.js.map +7 -0
  60. package/dist/modules/customers/components/calendar/types.js +1 -0
  61. package/dist/modules/customers/components/calendar/types.js.map +2 -2
  62. package/dist/modules/customers/data/entities.js +6 -0
  63. package/dist/modules/customers/data/entities.js.map +2 -2
  64. package/dist/modules/customers/data/validators.js +39 -10
  65. package/dist/modules/customers/data/validators.js.map +2 -2
  66. package/dist/modules/customers/di.js +20 -1
  67. package/dist/modules/customers/di.js.map +2 -2
  68. package/dist/modules/customers/extension-points.js +13 -0
  69. package/dist/modules/customers/extension-points.js.map +2 -2
  70. package/dist/modules/customers/lib/calendar/conflicts.js +59 -16
  71. package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
  72. package/dist/modules/customers/lib/calendar/editorPayload.js +34 -16
  73. package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
  74. package/dist/modules/customers/lib/calendar/eventTypeResolver.js +197 -0
  75. package/dist/modules/customers/lib/calendar/eventTypeResolver.js.map +7 -0
  76. package/dist/modules/customers/lib/calendar/interactionApplicability.js +67 -0
  77. package/dist/modules/customers/lib/calendar/interactionApplicability.js.map +7 -0
  78. package/dist/modules/customers/lib/calendar/mapItem.js +5 -2
  79. package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
  80. package/dist/modules/customers/lib/calendar/recurrence.js +62 -1
  81. package/dist/modules/customers/lib/calendar/recurrence.js.map +2 -2
  82. package/dist/modules/customers/lib/calendar/timezone.js +111 -0
  83. package/dist/modules/customers/lib/calendar/timezone.js.map +7 -0
  84. package/dist/modules/customers/lib/interactionReadModel.js +1 -0
  85. package/dist/modules/customers/lib/interactionReadModel.js.map +2 -2
  86. package/dist/modules/customers/lib/todoCompatibility.js +1 -0
  87. package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
  88. package/dist/modules/customers/migrations/Migration20260928175058_customers.js +17 -0
  89. package/dist/modules/customers/migrations/Migration20260928175058_customers.js.map +7 -0
  90. package/dist/modules/customers/migrations/Migration20260930110235_customers.js +17 -0
  91. package/dist/modules/customers/migrations/Migration20260930110235_customers.js.map +7 -0
  92. package/dist/modules/dictionaries/components/DictionaryTable.js +60 -51
  93. package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
  94. package/dist/modules/planner/lib/availabilityMerge.js +101 -38
  95. package/dist/modules/planner/lib/availabilityMerge.js.map +3 -3
  96. package/dist/modules/planner/services/plannerAvailabilityService.js.map +2 -2
  97. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +12 -7
  98. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +2 -2
  99. package/generated/entities/customer_dictionary_entry/index.ts +1 -0
  100. package/generated/entities/customer_interaction/index.ts +1 -0
  101. package/generated/entity-fields-registry.ts +2 -0
  102. package/package.json +7 -7
  103. package/src/modules/customers/api/activity-types/route.ts +154 -0
  104. package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +9 -1
  105. package/src/modules/customers/api/dictionaries/[kind]/route.ts +18 -2
  106. package/src/modules/customers/api/interactions/route.ts +4 -0
  107. package/src/modules/customers/api/interactions/tasks/route.ts +1 -0
  108. package/src/modules/customers/backend/config/customers/pipeline-stages/page.meta.ts +20 -0
  109. package/src/modules/customers/calendar-event-types.ts +674 -0
  110. package/src/modules/customers/commands/dictionaries.ts +84 -8
  111. package/src/modules/customers/commands/interactions.ts +244 -21
  112. package/src/modules/customers/components/ActivityTypeEditor.tsx +239 -0
  113. package/src/modules/customers/components/DictionarySettings.tsx +5 -3
  114. package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +347 -218
  115. package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +18 -96
  116. package/src/modules/customers/components/calendar/TimeGrid.tsx +20 -18
  117. package/src/modules/customers/components/calendar/editor/EventTypePanel.tsx +230 -0
  118. package/src/modules/customers/components/calendar/editor/LocationField.tsx +7 -1
  119. package/src/modules/customers/components/calendar/editor/PeopleField.tsx +4 -0
  120. package/src/modules/customers/components/calendar/editor/PriorityField.tsx +3 -0
  121. package/src/modules/customers/components/calendar/editor/RepeatField.tsx +10 -0
  122. package/src/modules/customers/components/calendar/editor/ResourcesField.tsx +4 -0
  123. package/src/modules/customers/components/calendar/editor/ScheduleSection.tsx +16 -4
  124. package/src/modules/customers/components/calendar/editor/SegmentGroup.tsx +3 -0
  125. package/src/modules/customers/components/calendar/editor/hooks.ts +29 -13
  126. package/src/modules/customers/components/calendar/editor/inputs.tsx +17 -5
  127. package/src/modules/customers/components/calendar/editor/useCalendarCustomFields.ts +49 -0
  128. package/src/modules/customers/components/calendar/editor/useEventTypeCatalog.ts +100 -0
  129. package/src/modules/customers/components/calendar/types.ts +1 -0
  130. package/src/modules/customers/components/detail/types.ts +1 -0
  131. package/src/modules/customers/data/entities.ts +8 -1
  132. package/src/modules/customers/data/validators.ts +42 -7
  133. package/src/modules/customers/di.ts +21 -0
  134. package/src/modules/customers/extension-points.ts +13 -0
  135. package/src/modules/customers/i18n/de.json +83 -0
  136. package/src/modules/customers/i18n/en.json +83 -0
  137. package/src/modules/customers/i18n/es.json +83 -0
  138. package/src/modules/customers/i18n/ko.json +83 -0
  139. package/src/modules/customers/i18n/pl.json +83 -0
  140. package/src/modules/customers/lib/calendar/conflicts.ts +106 -27
  141. package/src/modules/customers/lib/calendar/editorPayload.ts +39 -19
  142. package/src/modules/customers/lib/calendar/eventTypeResolver.ts +258 -0
  143. package/src/modules/customers/lib/calendar/interactionApplicability.ts +99 -0
  144. package/src/modules/customers/lib/calendar/mapItem.ts +6 -2
  145. package/src/modules/customers/lib/calendar/recurrence.ts +65 -1
  146. package/src/modules/customers/lib/calendar/timezone.ts +117 -0
  147. package/src/modules/customers/lib/interactionReadModel.ts +1 -0
  148. package/src/modules/customers/lib/todoCompatibility.ts +2 -0
  149. package/src/modules/customers/migrations/.snapshot-open-mercato.json +34 -0
  150. package/src/modules/customers/migrations/Migration20260928175058_customers.ts +15 -0
  151. package/src/modules/customers/migrations/Migration20260930110235_customers.ts +15 -0
  152. package/src/modules/dictionaries/components/DictionaryTable.tsx +63 -56
  153. package/src/modules/planner/lib/availabilityMerge.ts +106 -41
  154. package/src/modules/planner/services/plannerAvailabilityService.ts +4 -0
  155. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +25 -13
@@ -0,0 +1,548 @@
1
+ import { z } from "zod";
2
+ const calendarEventBaseKindSchema = z.enum(["meeting", "call", "email", "note", "event", "task"]);
3
+ const calendarEventTypeFieldsSchema = z.strictObject({
4
+ endTime: z.boolean(),
5
+ allDay: z.boolean(),
6
+ recurrence: z.boolean(),
7
+ location: z.enum(["none", "location", "phoneLink"]),
8
+ people: z.enum(["none", "attendees", "participants", "recipients", "assignee"]),
9
+ priority: z.boolean(),
10
+ resources: z.boolean()
11
+ });
12
+ const calendarEventTypeBehaviorSchema = z.strictObject({
13
+ schemaVersion: z.literal(1),
14
+ baseKind: calendarEventBaseKindSchema,
15
+ selectable: z.boolean(),
16
+ order: z.number().int().min(0).max(1e4),
17
+ fields: calendarEventTypeFieldsSchema,
18
+ customFieldsetIds: z.array(z.string().trim().min(1).max(100)).max(32).refine(
19
+ (values) => new Set(values).size === values.length,
20
+ "Custom fieldset ids must be unique"
21
+ )
22
+ });
23
+ const calendarEventTypeKeySchema = z.string().trim().min(1).max(100).regex(
24
+ /^[a-z0-9]+(?:[-_][a-z0-9]+)*$/,
25
+ "Calendar event type keys must be lowercase dictionary keys"
26
+ );
27
+ const calendarEventTypeDefinitionSchema = z.strictObject({
28
+ key: calendarEventTypeKeySchema,
29
+ label: z.string().trim().min(1).max(150),
30
+ labelKey: z.string().trim().min(1).max(200).optional(),
31
+ icon: z.string().trim().max(100).nullable().optional(),
32
+ color: z.string().trim().max(100).nullable().optional(),
33
+ behavior: calendarEventTypeBehaviorSchema,
34
+ adminConfigurable: z.boolean().optional(),
35
+ panelKey: z.string().trim().min(1).max(150).optional()
36
+ });
37
+ const calendarEventTypeBehaviorOverrideSchema = z.strictObject({
38
+ schemaVersion: z.literal(1).optional(),
39
+ baseKind: calendarEventBaseKindSchema.optional(),
40
+ selectable: z.boolean().optional(),
41
+ order: z.number().int().min(0).max(1e4).optional(),
42
+ fields: calendarEventTypeFieldsSchema.partial().strict().optional(),
43
+ customFieldsetIds: z.array(z.string().trim().min(1).max(100)).max(32).refine(
44
+ (values) => new Set(values).size === values.length,
45
+ "Custom fieldset ids must be unique"
46
+ ).optional()
47
+ });
48
+ const calendarEventTypeDefinitionOverrideSchema = z.strictObject({
49
+ label: z.string().trim().min(1).max(150).optional(),
50
+ labelKey: z.string().trim().min(1).max(200).optional(),
51
+ icon: z.string().trim().max(100).nullable().optional(),
52
+ color: z.string().trim().max(100).nullable().optional(),
53
+ behavior: calendarEventTypeBehaviorOverrideSchema.optional(),
54
+ adminConfigurable: z.boolean().optional(),
55
+ panelKey: z.string().trim().min(1).max(150).optional()
56
+ });
57
+ const calendarEventTypePatchSchema = z.strictObject({
58
+ targetEventTypeKey: calendarEventTypeKeySchema,
59
+ replaceLabel: z.string().trim().min(1).max(150).optional(),
60
+ replaceLabelKey: z.string().trim().min(1).max(200).nullable().optional(),
61
+ replaceIcon: z.string().trim().max(100).nullable().optional(),
62
+ replaceColor: z.string().trim().max(100).nullable().optional(),
63
+ replaceBaseKind: calendarEventBaseKindSchema.optional(),
64
+ replaceSelectable: z.boolean().optional(),
65
+ replaceOrder: z.number().int().min(0).max(1e4).optional(),
66
+ replaceFields: calendarEventTypeFieldsSchema.partial().strict().optional(),
67
+ replaceAdminConfigurable: z.boolean().optional(),
68
+ replacePanelKey: z.string().trim().min(1).max(150).nullable().optional(),
69
+ replaceCustomFieldsetIds: calendarEventTypeBehaviorSchema.shape.customFieldsetIds.optional(),
70
+ deleteCustomFieldsetIds: calendarEventTypeBehaviorSchema.shape.customFieldsetIds.optional(),
71
+ appendCustomFieldsetIds: calendarEventTypeBehaviorSchema.shape.customFieldsetIds.optional()
72
+ });
73
+ const calendarEventTypeProvenanceSchema = z.strictObject({
74
+ moduleId: z.string().trim().min(1).max(100),
75
+ sourcePath: z.string().trim().min(1).max(500),
76
+ moduleOrder: z.number().int().min(0),
77
+ phase: z.enum(["core", "widget", "module", "programmatic", "fallback"])
78
+ });
79
+ const calendarEventTypeTombstoneSchema = z.strictObject({
80
+ key: calendarEventTypeKeySchema,
81
+ provenance: calendarEventTypeProvenanceSchema
82
+ });
83
+ const calendarEventTypeHistoricalFallbackSchema = z.strictObject({
84
+ key: calendarEventTypeKeySchema,
85
+ reason: z.enum(["tombstoned", "module-unavailable", "unknown"]),
86
+ definition: calendarEventTypeDefinitionSchema
87
+ });
88
+ const behavior = (baseKind, order, fields) => ({
89
+ schemaVersion: 1,
90
+ baseKind,
91
+ selectable: true,
92
+ order,
93
+ fields,
94
+ customFieldsetIds: []
95
+ });
96
+ const resources = true;
97
+ const calendarEventTypes = deepFreeze([
98
+ { key: "meeting", label: "Meeting", labelKey: "customers.calendar.editor.types.meeting", icon: "lucide:users", color: "#f59e0b", behavior: behavior("meeting", 0, { endTime: true, allDay: true, recurrence: true, location: "location", people: "attendees", priority: false, resources }) },
99
+ { key: "call", label: "Call", labelKey: "customers.calendar.editor.types.call", icon: "lucide:phone-call", color: "#2563eb", behavior: behavior("call", 100, { endTime: true, allDay: true, recurrence: true, location: "phoneLink", people: "participants", priority: false, resources }) },
100
+ { key: "email", label: "Email", labelKey: "customers.calendar.editor.types.email", icon: "lucide:mail", color: "#16a34a", behavior: behavior("email", 200, { endTime: false, allDay: true, recurrence: true, location: "none", people: "recipients", priority: false, resources }) },
101
+ { key: "note", label: "Note", labelKey: "customers.calendar.editor.types.note", icon: "lucide:notebook", color: "#a855f7", behavior: behavior("note", 300, { endTime: false, allDay: false, recurrence: false, location: "none", people: "none", priority: false, resources }) },
102
+ { key: "event", label: "Event", labelKey: "customers.calendar.editor.types.event", icon: "lucide:calendar", color: "#6366f1", behavior: behavior("event", 400, { endTime: true, allDay: true, recurrence: true, location: "location", people: "attendees", priority: false, resources }) },
103
+ { key: "task", label: "Task", labelKey: "customers.calendar.editor.types.task", icon: "lucide:check-square", color: "#ef4444", behavior: behavior("task", 500, { endTime: true, allDay: true, recurrence: true, location: "none", people: "assignee", priority: true, resources }) }
104
+ ]);
105
+ const calendarEventTypeOverrides = Object.freeze({});
106
+ const REGISTRY_KEY = /* @__PURE__ */ Symbol.for("open-mercato.customers.calendar-event-types.v1");
107
+ function getRegistryState() {
108
+ const globalRegistry = globalThis;
109
+ globalRegistry[REGISTRY_KEY] ??= {
110
+ widgets: Object.freeze([]),
111
+ modules: Object.freeze([]),
112
+ sources: /* @__PURE__ */ new Map(),
113
+ historicalDefinitions: /* @__PURE__ */ new Map(),
114
+ version: 0,
115
+ diagnostics: Object.freeze([])
116
+ };
117
+ return globalRegistry[REGISTRY_KEY];
118
+ }
119
+ function deepFreeze(value) {
120
+ if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
121
+ Object.freeze(value);
122
+ for (const child of Object.values(value)) deepFreeze(child);
123
+ }
124
+ return value;
125
+ }
126
+ function sourceOf(moduleId, sourcePath, moduleOrder, phase) {
127
+ return Object.freeze({ moduleId, sourcePath, moduleOrder, phase });
128
+ }
129
+ function allPropertyPaths(definition) {
130
+ const paths = ["key", "label", "behavior.schemaVersion", "behavior.baseKind", "behavior.selectable", "behavior.order"];
131
+ if (definition.labelKey !== void 0) paths.push("labelKey");
132
+ if (definition.icon !== void 0) paths.push("icon");
133
+ if (definition.color !== void 0) paths.push("color");
134
+ if (definition.adminConfigurable !== void 0) paths.push("adminConfigurable");
135
+ if (definition.panelKey !== void 0) paths.push("panelKey");
136
+ for (const key of Object.keys(definition.behavior.fields)) paths.push(`behavior.fields.${key}`);
137
+ paths.push("behavior.customFieldsetIds");
138
+ return paths;
139
+ }
140
+ const widgetContributionSchema = z.strictObject({
141
+ moduleId: z.string().trim().min(1).max(100),
142
+ widgetId: z.string().trim().min(1).max(200),
143
+ priority: z.number().int().optional(),
144
+ definitions: z.array(calendarEventTypeDefinitionSchema).optional(),
145
+ overrides: z.record(calendarEventTypeKeySchema, calendarEventTypeDefinitionSchema.nullable()).optional(),
146
+ patches: z.array(calendarEventTypePatchSchema).optional()
147
+ }).superRefine((entry, context) => {
148
+ const keys = /* @__PURE__ */ new Set();
149
+ for (const definition of entry.definitions ?? []) {
150
+ if (keys.has(definition.key)) {
151
+ context.addIssue({ code: "custom", message: "Duplicate source definition", path: ["definitions"] });
152
+ }
153
+ keys.add(definition.key);
154
+ }
155
+ for (const [key, definition] of Object.entries(entry.overrides ?? {})) {
156
+ if (definition !== null && definition.key !== key) {
157
+ context.addIssue({ code: "custom", message: "Replacement key must match target key", path: ["overrides", key] });
158
+ }
159
+ }
160
+ });
161
+ const moduleOverrideEntrySchema = z.strictObject({
162
+ moduleId: z.string().trim().min(1).max(100),
163
+ overrides: z.strictObject({
164
+ eventTypes: z.record(calendarEventTypeKeySchema, calendarEventTypeDefinitionSchema.nullable()).optional(),
165
+ patches: z.array(calendarEventTypePatchSchema).optional()
166
+ })
167
+ }).superRefine((entry, context) => {
168
+ for (const [key, definition] of Object.entries(entry.overrides.eventTypes ?? {})) {
169
+ if (definition !== null && definition.key !== key) {
170
+ context.addIssue({ code: "custom", message: "Replacement key must match target key", path: ["overrides", "eventTypes", key] });
171
+ }
172
+ }
173
+ });
174
+ function copyDefinition(definition) {
175
+ return calendarEventTypeDefinitionSchema.parse(definition);
176
+ }
177
+ function copyPatch(patch) {
178
+ return calendarEventTypePatchSchema.parse(patch);
179
+ }
180
+ function programmaticSource(sourceId) {
181
+ return getRegistryState().sources.get(sourceId) ?? {
182
+ definitions: /* @__PURE__ */ new Map(),
183
+ overrides: /* @__PURE__ */ new Map(),
184
+ patches: /* @__PURE__ */ new Map()
185
+ };
186
+ }
187
+ function replaceProgrammaticSource(sourceId, source) {
188
+ const state = getRegistryState();
189
+ archiveCurrentDefinitions();
190
+ state.sources.set(sourceId, source);
191
+ state.version += 1;
192
+ }
193
+ function markDefinitionProvenance(definition, source) {
194
+ return Object.fromEntries(allPropertyPaths(definition).map((path) => [path, source]));
195
+ }
196
+ function applyPatch(definition, patch, provenance, source) {
197
+ const next = {
198
+ ...definition,
199
+ behavior: { ...definition.behavior, fields: { ...definition.behavior.fields }, customFieldsetIds: [...definition.behavior.customFieldsetIds] }
200
+ };
201
+ if (patch.replaceLabel !== void 0) {
202
+ next.label = patch.replaceLabel;
203
+ provenance.label = source;
204
+ }
205
+ if (patch.replaceLabelKey !== void 0) {
206
+ next.labelKey = patch.replaceLabelKey ?? void 0;
207
+ provenance.labelKey = source;
208
+ }
209
+ if (patch.replaceIcon !== void 0) {
210
+ next.icon = patch.replaceIcon;
211
+ provenance.icon = source;
212
+ }
213
+ if (patch.replaceColor !== void 0) {
214
+ next.color = patch.replaceColor;
215
+ provenance.color = source;
216
+ }
217
+ if (patch.replaceAdminConfigurable !== void 0) {
218
+ next.adminConfigurable = patch.replaceAdminConfigurable;
219
+ provenance.adminConfigurable = source;
220
+ }
221
+ if (patch.replacePanelKey !== void 0) {
222
+ next.panelKey = patch.replacePanelKey ?? void 0;
223
+ provenance.panelKey = source;
224
+ }
225
+ if (patch.replaceBaseKind !== void 0) {
226
+ next.behavior.baseKind = patch.replaceBaseKind;
227
+ provenance["behavior.baseKind"] = source;
228
+ }
229
+ if (patch.replaceSelectable !== void 0) {
230
+ next.behavior.selectable = patch.replaceSelectable;
231
+ provenance["behavior.selectable"] = source;
232
+ }
233
+ if (patch.replaceOrder !== void 0) {
234
+ next.behavior.order = patch.replaceOrder;
235
+ provenance["behavior.order"] = source;
236
+ }
237
+ if (patch.replaceFields) {
238
+ next.behavior.fields = { ...next.behavior.fields, ...patch.replaceFields };
239
+ for (const field of Object.keys(patch.replaceFields)) provenance[`behavior.fields.${field}`] = source;
240
+ }
241
+ if (patch.replaceCustomFieldsetIds || patch.deleteCustomFieldsetIds || patch.appendCustomFieldsetIds) {
242
+ const fieldsets = patch.replaceCustomFieldsetIds ?? next.behavior.customFieldsetIds;
243
+ const deleted = new Set(patch.deleteCustomFieldsetIds ?? []);
244
+ next.behavior.customFieldsetIds = [.../* @__PURE__ */ new Set([...fieldsets.filter((id) => !deleted.has(id)), ...patch.appendCustomFieldsetIds ?? []])];
245
+ provenance["behavior.customFieldsetIds"] = source;
246
+ }
247
+ return calendarEventTypeDefinitionSchema.parse(next);
248
+ }
249
+ function compose(excludedSources = /* @__PURE__ */ new Set(), rejectedSources = []) {
250
+ const definitions = /* @__PURE__ */ new Map();
251
+ const owners = /* @__PURE__ */ new Map();
252
+ const provenance = /* @__PURE__ */ new Map();
253
+ const tombstones = /* @__PURE__ */ new Map();
254
+ const diagnostics = [...getRegistryState().diagnostics, ...rejectedSources];
255
+ const coreSource = Object.freeze({ moduleId: "customers", sourcePath: "calendar-event-types.ts", moduleOrder: 0, phase: "core" });
256
+ for (const definition of calendarEventTypes) {
257
+ definitions.set(definition.key, definition);
258
+ owners.set(definition.key, coreSource);
259
+ provenance.set(definition.key, markDefinitionProvenance(definition, coreSource));
260
+ }
261
+ const state = getRegistryState();
262
+ const widgets = state.widgets.map((entry, moduleOrder) => ({ entry, moduleOrder })).filter(({ entry }) => !excludedSources.has(entry));
263
+ const modules = state.modules.map((entry, moduleOrder) => ({ entry, moduleOrder })).filter(({ entry }) => !excludedSources.has(entry));
264
+ const programmatic = [...state.sources.entries()].filter(([, contribution]) => !excludedSources.has(contribution));
265
+ for (const { entry, moduleOrder } of widgets) {
266
+ const source = sourceOf(entry.moduleId, `widgets/injection/${entry.widgetId}/widget.ts`, moduleOrder, "widget");
267
+ for (const definition of entry.definitions ?? []) {
268
+ const existing = owners.get(definition.key);
269
+ if (existing) {
270
+ diagnostics.push({ code: "duplicate-definition", key: definition.key, moduleId: entry.moduleId, widgetId: entry.widgetId, owner: existing.moduleId });
271
+ continue;
272
+ }
273
+ definitions.set(definition.key, definition);
274
+ owners.set(definition.key, source);
275
+ provenance.set(definition.key, markDefinitionProvenance(definition, source));
276
+ }
277
+ }
278
+ for (const [sourceId, contribution] of programmatic) {
279
+ const source = sourceOf(sourceId, `di:${sourceId}`, 0, "programmatic");
280
+ for (const definition of contribution.definitions.values()) {
281
+ const existing = owners.get(definition.key);
282
+ if (existing && existing.moduleId !== sourceId) {
283
+ diagnostics.push({ code: "duplicate-definition", key: definition.key, moduleId: sourceId, owner: existing.moduleId });
284
+ continue;
285
+ }
286
+ definitions.set(definition.key, definition);
287
+ owners.set(definition.key, source);
288
+ provenance.set(definition.key, markDefinitionProvenance(definition, source));
289
+ }
290
+ }
291
+ const applyOverrides = (overrides, source, widgetId) => {
292
+ for (const [key, override] of Object.entries(overrides)) {
293
+ if (!definitions.has(key)) {
294
+ if (override === null) {
295
+ diagnostics.push({ code: "unknown-override", key, moduleId: source.moduleId, widgetId });
296
+ continue;
297
+ }
298
+ diagnostics.push({ code: "unknown-override", key, moduleId: source.moduleId, widgetId });
299
+ }
300
+ if (override === null) {
301
+ tombstones.set(key, deepFreeze({ key, provenance: source }));
302
+ } else {
303
+ definitions.set(key, override);
304
+ owners.set(key, source);
305
+ provenance.set(key, markDefinitionProvenance(override, source));
306
+ tombstones.delete(key);
307
+ }
308
+ }
309
+ };
310
+ for (const { entry, moduleOrder } of widgets) {
311
+ applyOverrides(entry.overrides ?? {}, sourceOf(entry.moduleId, `widgets/injection/${entry.widgetId}/widget.ts`, moduleOrder, "widget"), entry.widgetId);
312
+ }
313
+ for (const { entry, moduleOrder } of modules) {
314
+ applyOverrides(entry.overrides.eventTypes ?? {}, sourceOf(entry.moduleId, "modules.ts", moduleOrder, "module"));
315
+ }
316
+ for (const [sourceId, contribution] of programmatic) {
317
+ applyOverrides(Object.fromEntries(contribution.overrides), sourceOf(sourceId, `di:${sourceId}`, 0, "programmatic"));
318
+ }
319
+ const applyPatches = (patches, source, widgetId) => {
320
+ for (const patch of patches) {
321
+ const key = patch.targetEventTypeKey;
322
+ const definition = definitions.get(key);
323
+ if (!definition || tombstones.has(key)) {
324
+ diagnostics.push({ code: "unknown-patch", key, moduleId: source.moduleId, widgetId });
325
+ continue;
326
+ }
327
+ const propertyProvenance = { ...provenance.get(key) };
328
+ try {
329
+ const patched = applyPatch(definition, patch, propertyProvenance, source);
330
+ definitions.set(key, patched);
331
+ provenance.set(key, propertyProvenance);
332
+ } catch {
333
+ return { code: "invalid-source", key, moduleId: source.moduleId, widgetId };
334
+ }
335
+ }
336
+ return null;
337
+ };
338
+ for (const { entry, moduleOrder } of widgets) {
339
+ const failure = applyPatches(entry.patches ?? [], sourceOf(entry.moduleId, `widgets/injection/${entry.widgetId}/widget.ts`, moduleOrder, "widget"), entry.widgetId);
340
+ if (failure) return compose(/* @__PURE__ */ new Set([...excludedSources, entry]), [...rejectedSources, failure]);
341
+ }
342
+ for (const { entry, moduleOrder } of modules) {
343
+ const failure = applyPatches(entry.overrides.patches ?? [], sourceOf(entry.moduleId, "modules.ts", moduleOrder, "module"));
344
+ if (failure) return compose(/* @__PURE__ */ new Set([...excludedSources, entry]), [...rejectedSources, failure]);
345
+ }
346
+ for (const [sourceId, contribution] of programmatic) {
347
+ const failure = applyPatches([...contribution.patches.values()], sourceOf(sourceId, `di:${sourceId}`, 0, "programmatic"));
348
+ if (failure) return compose(/* @__PURE__ */ new Set([...excludedSources, contribution]), [...rejectedSources, failure]);
349
+ }
350
+ const items = [...definitions.values()].filter((definition) => !tombstones.has(definition.key)).map((definition) => deepFreeze({
351
+ ...definition,
352
+ provenance: Object.freeze({ ...provenance.get(definition.key) ?? {} }),
353
+ historical: false
354
+ })).sort((left, right) => left.behavior.order - right.behavior.order || left.key.localeCompare(right.key));
355
+ return deepFreeze({ items, tombstones: [...tombstones.values()], diagnostics });
356
+ }
357
+ function archiveCurrentDefinitions() {
358
+ const state = getRegistryState();
359
+ for (const item of compose().items) {
360
+ const { provenance: _provenance, historical: _historical, fallbackReason: _fallbackReason, ...definition } = item;
361
+ state.historicalDefinitions.set(item.key, deepFreeze(definition));
362
+ }
363
+ }
364
+ function registerWidgetCalendarEventTypeContributions(entries) {
365
+ const state = getRegistryState();
366
+ const diagnostics = [];
367
+ const parsed = [];
368
+ for (const entry of entries) {
369
+ const result = widgetContributionSchema.safeParse(entry);
370
+ if (result.success) parsed.push(result.data);
371
+ else diagnostics.push({ code: "invalid-source", moduleId: entry.moduleId, widgetId: entry.widgetId });
372
+ }
373
+ const moduleOrder = /* @__PURE__ */ new Map();
374
+ entries.forEach((entry) => {
375
+ if (!moduleOrder.has(entry.moduleId)) moduleOrder.set(entry.moduleId, moduleOrder.size);
376
+ });
377
+ parsed.sort((left, right) => (moduleOrder.get(left.moduleId) ?? 0) - (moduleOrder.get(right.moduleId) ?? 0) || (left.priority ?? 0) - (right.priority ?? 0) || left.widgetId.localeCompare(right.widgetId));
378
+ const moduleDiagnostics = state.diagnostics.filter((diagnostic) => !diagnostic.widgetId);
379
+ if (JSON.stringify(state.widgets) === JSON.stringify(parsed) && JSON.stringify(state.diagnostics.filter((diagnostic) => diagnostic.widgetId)) === JSON.stringify(diagnostics)) return;
380
+ archiveCurrentDefinitions();
381
+ state.widgets = deepFreeze(parsed);
382
+ state.diagnostics = deepFreeze([...diagnostics, ...moduleDiagnostics]);
383
+ state.version += 1;
384
+ }
385
+ function registerCalendarModuleOverrides(entries) {
386
+ const state = getRegistryState();
387
+ const diagnostics = [];
388
+ const parsed = [];
389
+ for (const entry of entries) {
390
+ const result = moduleOverrideEntrySchema.safeParse(entry);
391
+ if (result.success) parsed.push(result.data);
392
+ else diagnostics.push({ code: "invalid-source", moduleId: entry.moduleId });
393
+ }
394
+ const widgetDiagnostics = state.diagnostics.filter((diagnostic) => diagnostic.widgetId);
395
+ if (JSON.stringify(state.modules) === JSON.stringify(parsed) && JSON.stringify(state.diagnostics.filter((diagnostic) => !diagnostic.widgetId)) === JSON.stringify(diagnostics)) return;
396
+ archiveCurrentDefinitions();
397
+ state.modules = deepFreeze(parsed);
398
+ state.diagnostics = deepFreeze([...widgetDiagnostics, ...diagnostics]);
399
+ state.version += 1;
400
+ }
401
+ function validatedSourceId(sourceId) {
402
+ return z.string().trim().min(1).max(100).parse(sourceId);
403
+ }
404
+ function baseOwnerOf(key) {
405
+ if (calendarEventTypes.some((definition) => definition.key === key)) return "customers";
406
+ const invalidSources = compose().diagnostics.filter((diagnostic) => diagnostic.code === "invalid-source");
407
+ for (const widget of getRegistryState().widgets) {
408
+ if (invalidSources.some((diagnostic) => diagnostic.moduleId === widget.moduleId && diagnostic.widgetId === widget.widgetId)) continue;
409
+ if (widget.definitions?.some((definition) => definition.key === key)) return widget.moduleId;
410
+ }
411
+ for (const [sourceId, contribution] of getRegistryState().sources) {
412
+ if (invalidSources.some((diagnostic) => diagnostic.moduleId === sourceId && !diagnostic.widgetId)) continue;
413
+ if (contribution.definitions.has(key)) return sourceId;
414
+ }
415
+ return compose().items.find((definition) => definition.key === key)?.provenance.key?.moduleId;
416
+ }
417
+ function createCalendarEventTypeRegistry() {
418
+ return {
419
+ upsert(sourceId, definition) {
420
+ const id = validatedSourceId(sourceId);
421
+ const nextDefinition = copyDefinition(definition);
422
+ const owner = baseOwnerOf(nextDefinition.key);
423
+ if (owner && owner !== id) {
424
+ throw new Error(`[internal] Calendar event type "${nextDefinition.key}" is owned by "${owner}"`);
425
+ }
426
+ const current = programmaticSource(id);
427
+ if (JSON.stringify(current.definitions.get(nextDefinition.key)) === JSON.stringify(nextDefinition)) return;
428
+ replaceProgrammaticSource(id, { ...current, definitions: new Map(current.definitions).set(nextDefinition.key, nextDefinition) });
429
+ },
430
+ replace(sourceId, key, definition) {
431
+ const id = validatedSourceId(sourceId);
432
+ const parsedKey = calendarEventTypeKeySchema.parse(key);
433
+ const nextDefinition = definition === null ? null : copyDefinition(definition);
434
+ if (nextDefinition && nextDefinition.key !== parsedKey) throw new Error("[internal] Replacement key must match target key");
435
+ const current = programmaticSource(id);
436
+ if (JSON.stringify(current.overrides.get(parsedKey)) === JSON.stringify(nextDefinition)) return;
437
+ replaceProgrammaticSource(id, { ...current, overrides: new Map(current.overrides).set(parsedKey, nextDefinition) });
438
+ },
439
+ patch(sourceId, patch) {
440
+ const id = validatedSourceId(sourceId);
441
+ const nextPatch = copyPatch(patch);
442
+ const current = programmaticSource(id);
443
+ if (JSON.stringify(current.patches.get(nextPatch.targetEventTypeKey)) === JSON.stringify(nextPatch)) return;
444
+ replaceProgrammaticSource(id, { ...current, patches: new Map(current.patches).set(nextPatch.targetEventTypeKey, nextPatch) });
445
+ },
446
+ remove(sourceId, key) {
447
+ const id = validatedSourceId(sourceId);
448
+ const parsedKey = calendarEventTypeKeySchema.parse(key);
449
+ const current = getRegistryState().sources.get(id);
450
+ if (!current || !(current.definitions.has(parsedKey) || current.overrides.has(parsedKey) || current.patches.has(parsedKey))) return;
451
+ const next = { definitions: new Map(current.definitions), overrides: new Map(current.overrides), patches: new Map(current.patches) };
452
+ next.definitions.delete(parsedKey);
453
+ next.overrides.delete(parsedKey);
454
+ next.patches.delete(parsedKey);
455
+ replaceProgrammaticSource(id, next);
456
+ },
457
+ removeSource(sourceId) {
458
+ const id = validatedSourceId(sourceId);
459
+ const state = getRegistryState();
460
+ if (!state.sources.has(id)) return;
461
+ archiveCurrentDefinitions();
462
+ state.sources.delete(id);
463
+ state.version += 1;
464
+ },
465
+ snapshot() {
466
+ const state = getRegistryState();
467
+ return deepFreeze({ version: state.version, ...compose() });
468
+ }
469
+ };
470
+ }
471
+ function getCalendarEventTypeRegistryVersion() {
472
+ return getRegistryState().version;
473
+ }
474
+ function getCalendarEventTypes() {
475
+ return compose().items;
476
+ }
477
+ function resolveCalendarEventTypes() {
478
+ return getCalendarEventTypes();
479
+ }
480
+ function getCalendarEventTypeTombstones() {
481
+ return compose().tombstones;
482
+ }
483
+ function getCalendarEventTypeDiagnostics() {
484
+ return compose().diagnostics;
485
+ }
486
+ function resolveCalendarEventType(rawKey, options = {}) {
487
+ const parsedKey = calendarEventTypeKeySchema.safeParse(rawKey.trim().toLowerCase());
488
+ if (!parsedKey.success) return void 0;
489
+ const key = parsedKey.data;
490
+ const current = compose();
491
+ const resolved = current.items.find((item) => item.key === key);
492
+ if (resolved || !options.includeHistorical) return resolved;
493
+ const stored = getRegistryState().historicalDefinitions.get(key);
494
+ const reason = current.tombstones.some((entry) => entry.key === key) ? "tombstoned" : stored ? "module-unavailable" : "unknown";
495
+ const definition = stored ?? {
496
+ ...calendarEventTypes[0],
497
+ key,
498
+ label: rawKey,
499
+ labelKey: void 0,
500
+ behavior: { ...calendarEventTypes[0].behavior, selectable: false }
501
+ };
502
+ const fallbackSource = Object.freeze({ moduleId: "customers", sourcePath: "calendar-event-types.ts", moduleOrder: 0, phase: "fallback" });
503
+ const historicalDefinition = calendarEventTypeDefinitionSchema.parse({
504
+ ...definition,
505
+ behavior: { ...definition.behavior, selectable: false }
506
+ });
507
+ return deepFreeze({
508
+ ...historicalDefinition,
509
+ provenance: Object.fromEntries(allPropertyPaths(historicalDefinition).map((path) => [path, fallbackSource])),
510
+ historical: true,
511
+ fallbackReason: reason
512
+ });
513
+ }
514
+ function resetCalendarEventTypeRegistryForTests() {
515
+ const state = getRegistryState();
516
+ state.widgets = Object.freeze([]);
517
+ state.modules = Object.freeze([]);
518
+ state.sources.clear();
519
+ state.historicalDefinitions.clear();
520
+ state.version = 0;
521
+ state.diagnostics = Object.freeze([]);
522
+ }
523
+ export {
524
+ calendarEventBaseKindSchema,
525
+ calendarEventTypeBehaviorOverrideSchema,
526
+ calendarEventTypeBehaviorSchema,
527
+ calendarEventTypeDefinitionOverrideSchema,
528
+ calendarEventTypeDefinitionSchema,
529
+ calendarEventTypeFieldsSchema,
530
+ calendarEventTypeHistoricalFallbackSchema,
531
+ calendarEventTypeKeySchema,
532
+ calendarEventTypeOverrides,
533
+ calendarEventTypePatchSchema,
534
+ calendarEventTypeProvenanceSchema,
535
+ calendarEventTypeTombstoneSchema,
536
+ calendarEventTypes,
537
+ createCalendarEventTypeRegistry,
538
+ getCalendarEventTypeDiagnostics,
539
+ getCalendarEventTypeRegistryVersion,
540
+ getCalendarEventTypeTombstones,
541
+ getCalendarEventTypes,
542
+ registerCalendarModuleOverrides,
543
+ registerWidgetCalendarEventTypeContributions,
544
+ resetCalendarEventTypeRegistryForTests,
545
+ resolveCalendarEventType,
546
+ resolveCalendarEventTypes
547
+ };
548
+ //# sourceMappingURL=calendar-event-types.js.map