@happyvertical/smrt-events 0.30.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.
Files changed (64) hide show
  1. package/AGENTS.md +20 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +151 -0
  5. package/dist/__smrt-register__.d.ts +2 -0
  6. package/dist/__smrt-register__.d.ts.map +1 -0
  7. package/dist/collections/EventAssetCollection.d.ts +16 -0
  8. package/dist/collections/EventAssetCollection.d.ts.map +1 -0
  9. package/dist/collections/EventCollection.d.ts +108 -0
  10. package/dist/collections/EventCollection.d.ts.map +1 -0
  11. package/dist/collections/EventParticipantCollection.d.ts +42 -0
  12. package/dist/collections/EventParticipantCollection.d.ts.map +1 -0
  13. package/dist/collections/EventSeriesCollection.d.ts +62 -0
  14. package/dist/collections/EventSeriesCollection.d.ts.map +1 -0
  15. package/dist/collections/EventTypeCollection.d.ts +53 -0
  16. package/dist/collections/EventTypeCollection.d.ts.map +1 -0
  17. package/dist/index.d.ts +15 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +1419 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/manifest.json +4067 -0
  22. package/dist/models/Event.d.ts +92 -0
  23. package/dist/models/Event.d.ts.map +1 -0
  24. package/dist/models/EventAsset.d.ts +17 -0
  25. package/dist/models/EventAsset.d.ts.map +1 -0
  26. package/dist/models/EventParticipant.d.ts +65 -0
  27. package/dist/models/EventParticipant.d.ts.map +1 -0
  28. package/dist/models/EventSeries.d.ts +73 -0
  29. package/dist/models/EventSeries.d.ts.map +1 -0
  30. package/dist/models/EventType.d.ts +44 -0
  31. package/dist/models/EventType.d.ts.map +1 -0
  32. package/dist/playground.d.ts +2 -0
  33. package/dist/playground.d.ts.map +1 -0
  34. package/dist/playground.js +47 -0
  35. package/dist/playground.js.map +1 -0
  36. package/dist/smrt-knowledge.json +1662 -0
  37. package/dist/svelte/components/MeetingView.svelte +321 -0
  38. package/dist/svelte/components/MeetingView.svelte.d.ts +9 -0
  39. package/dist/svelte/components/MeetingView.svelte.d.ts.map +1 -0
  40. package/dist/svelte/i18n.d.ts +10 -0
  41. package/dist/svelte/i18n.d.ts.map +1 -0
  42. package/dist/svelte/i18n.js +11 -0
  43. package/dist/svelte/index.d.ts +11 -0
  44. package/dist/svelte/index.d.ts.map +1 -0
  45. package/dist/svelte/index.js +18 -0
  46. package/dist/svelte/playground.d.ts +40 -0
  47. package/dist/svelte/playground.d.ts.map +1 -0
  48. package/dist/svelte/playground.js +43 -0
  49. package/dist/svelte/types.d.ts +37 -0
  50. package/dist/svelte/types.d.ts.map +1 -0
  51. package/dist/svelte/types.js +6 -0
  52. package/dist/types.d.ts +127 -0
  53. package/dist/types.d.ts.map +1 -0
  54. package/dist/types.js +2 -0
  55. package/dist/types.js.map +1 -0
  56. package/dist/ui.d.ts +10 -0
  57. package/dist/ui.d.ts.map +1 -0
  58. package/dist/ui.js +28 -0
  59. package/dist/ui.js.map +1 -0
  60. package/dist/utils.d.ts +93 -0
  61. package/dist/utils.d.ts.map +1 -0
  62. package/dist/utils.js +127 -0
  63. package/dist/utils.js.map +1 -0
  64. package/package.json +102 -0
package/dist/index.js ADDED
@@ -0,0 +1,1419 @@
1
+ import { ObjectRegistry, foreignKey, crossPackageRef, field, smrt, SmrtObject, SmrtJunction, SmrtHierarchical, SmrtCollection } from "@happyvertical/smrt-core";
2
+ import { getOwnedAssetsFromCollection, addOwnedAssetFromCollection, removeOwnedAssetFromCollection, resolveOwnedAssetsById, assertValidOwnedAssetRelationship, assertValidOwnedAssetSortOrder } from "@happyvertical/smrt-assets";
3
+ import { tenantId, TenantScoped } from "@happyvertical/smrt-tenancy";
4
+ import { EVENTS_MODULE_META, EVENTS_UI_SLOTS } from "./ui.js";
5
+ import { calculateDuration, calculateNextOccurrence, checkSchedulingConflict, formatDuration, formatEventDateRange, generateEventSlug, getEventStatusFromDates, isEventNow, parseRecurrencePattern, sortEventsByDate, validateEventStatus } from "./utils.js";
6
+ ObjectRegistry.registerPackageManifest(
7
+ new URL("./manifest.json", import.meta.url)
8
+ );
9
+ var __defProp$6 = Object.defineProperty;
10
+ var __getOwnPropDesc$6 = Object.getOwnPropertyDescriptor;
11
+ var __decorateClass$6 = (decorators, target, key, kind) => {
12
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$6(target, key) : target;
13
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
14
+ if (decorator = decorators[i])
15
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
16
+ if (kind && result) __defProp$6(target, key, result);
17
+ return result;
18
+ };
19
+ let EventAsset = class extends SmrtObject {
20
+ tenantId = null;
21
+ eventId = "";
22
+ assetId = "";
23
+ relationship = "attachment";
24
+ sortOrder = 0;
25
+ constructor(options = {}) {
26
+ super(options);
27
+ if (options.eventId) this.eventId = options.eventId;
28
+ if (options.assetId) this.assetId = options.assetId;
29
+ if (options.relationship) this.relationship = options.relationship;
30
+ if (options.sortOrder !== void 0) this.sortOrder = options.sortOrder;
31
+ if (options.tenantId !== void 0) this.tenantId = options.tenantId;
32
+ }
33
+ };
34
+ __decorateClass$6([
35
+ tenantId({ nullable: true })
36
+ ], EventAsset.prototype, "tenantId", 2);
37
+ __decorateClass$6([
38
+ foreignKey("Event", { required: true })
39
+ ], EventAsset.prototype, "eventId", 2);
40
+ __decorateClass$6([
41
+ crossPackageRef("@happyvertical/smrt-assets:Asset", { required: true })
42
+ ], EventAsset.prototype, "assetId", 2);
43
+ __decorateClass$6([
44
+ field({ required: true })
45
+ ], EventAsset.prototype, "relationship", 2);
46
+ __decorateClass$6([
47
+ field()
48
+ ], EventAsset.prototype, "sortOrder", 2);
49
+ EventAsset = __decorateClass$6([
50
+ TenantScoped({ mode: "optional" }),
51
+ smrt({
52
+ tableName: "event_assets",
53
+ conflictColumns: ["event_id", "asset_id", "relationship"],
54
+ api: false,
55
+ mcp: false,
56
+ cli: false
57
+ })
58
+ ], EventAsset);
59
+ var __defProp$5 = Object.defineProperty;
60
+ var __getOwnPropDesc$5 = Object.getOwnPropertyDescriptor;
61
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
62
+ var __decorateClass$5 = (decorators, target, key, kind) => {
63
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$5(target, key) : target;
64
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
65
+ if (decorator = decorators[i])
66
+ result = decorator(result) || result;
67
+ return result;
68
+ };
69
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, key + "", value);
70
+ let EventAssetCollection = class extends SmrtJunction {
71
+ leftField = "eventId";
72
+ rightField = "assetId";
73
+ eventCollectionPromise = null;
74
+ async getEventCollection() {
75
+ if (!this.eventCollectionPromise) {
76
+ const { EventCollection: EventCollection2 } = await Promise.resolve().then(() => EventCollection$1);
77
+ this.eventCollectionPromise = EventCollection2.create({ db: this.db });
78
+ }
79
+ return this.eventCollectionPromise;
80
+ }
81
+ async getAssets(eventId, relationship) {
82
+ return getOwnedAssetsFromCollection(
83
+ await this.getEventCollection(),
84
+ eventId,
85
+ relationship
86
+ );
87
+ }
88
+ async addAsset(eventId, asset, relationship = "attachment", sortOrder = 0) {
89
+ await addOwnedAssetFromCollection(
90
+ await this.getEventCollection(),
91
+ "Event",
92
+ eventId,
93
+ asset,
94
+ relationship,
95
+ sortOrder
96
+ );
97
+ }
98
+ async removeAsset(eventId, assetId, relationship) {
99
+ await removeOwnedAssetFromCollection(
100
+ await this.getEventCollection(),
101
+ "Event",
102
+ eventId,
103
+ assetId,
104
+ relationship
105
+ );
106
+ }
107
+ };
108
+ __publicField$1(EventAssetCollection, "_itemClass", EventAsset);
109
+ EventAssetCollection = __decorateClass$5([
110
+ smrt({
111
+ api: false,
112
+ mcp: false,
113
+ cli: false
114
+ })
115
+ ], EventAssetCollection);
116
+ const EventAssetCollection$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
117
+ __proto__: null,
118
+ get EventAssetCollection() {
119
+ return EventAssetCollection;
120
+ }
121
+ }, Symbol.toStringTag, { value: "Module" }));
122
+ var __defProp$4 = Object.defineProperty;
123
+ var __getOwnPropDesc$4 = Object.getOwnPropertyDescriptor;
124
+ var __decorateClass$4 = (decorators, target, key, kind) => {
125
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$4(target, key) : target;
126
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
127
+ if (decorator = decorators[i])
128
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
129
+ if (kind && result) __defProp$4(target, key, result);
130
+ return result;
131
+ };
132
+ let Event = class extends SmrtHierarchical {
133
+ tenantId = null;
134
+ name = "";
135
+ seriesId = "";
136
+ typeId = "";
137
+ placeId = "";
138
+ // FK to Place (from @happyvertical/smrt-places)
139
+ description = "";
140
+ startDate = null;
141
+ endDate = null;
142
+ status = "scheduled";
143
+ round = null;
144
+ // Sequence/round number in series
145
+ metadata = "";
146
+ // JSON metadata (stored as text)
147
+ externalId = "";
148
+ // External system identifier
149
+ source = "";
150
+ // Source system
151
+ // Timestamps
152
+ createdAt = /* @__PURE__ */ new Date();
153
+ updatedAt = /* @__PURE__ */ new Date();
154
+ constructor(options = {}) {
155
+ super(options);
156
+ if (options.seriesId !== void 0) this.seriesId = options.seriesId;
157
+ if (options.parentId !== void 0)
158
+ this.parentId = options.parentId ?? null;
159
+ if (options.typeId) this.typeId = options.typeId;
160
+ if (options.placeId !== void 0) this.placeId = options.placeId;
161
+ if (options.description !== void 0)
162
+ this.description = options.description;
163
+ if (options.startDate !== void 0)
164
+ this.startDate = options.startDate || null;
165
+ if (options.endDate !== void 0) this.endDate = options.endDate || null;
166
+ if (options.status !== void 0) this.status = options.status;
167
+ if (options.round !== void 0) this.round = options.round;
168
+ if (options.externalId !== void 0) this.externalId = options.externalId;
169
+ if (options.source !== void 0) this.source = options.source;
170
+ if (options.metadata !== void 0) {
171
+ if (typeof options.metadata === "string") {
172
+ this.metadata = options.metadata;
173
+ } else {
174
+ this.metadata = JSON.stringify(options.metadata);
175
+ }
176
+ }
177
+ if (options.createdAt) this.createdAt = options.createdAt;
178
+ if (options.updatedAt) this.updatedAt = options.updatedAt;
179
+ }
180
+ /**
181
+ * Get metadata as parsed object
182
+ *
183
+ * @returns Parsed metadata object or empty object
184
+ */
185
+ getMetadata() {
186
+ if (!this.metadata) return {};
187
+ try {
188
+ return JSON.parse(this.metadata);
189
+ } catch {
190
+ return {};
191
+ }
192
+ }
193
+ /**
194
+ * Set metadata from object
195
+ *
196
+ * @param data - Metadata object to store
197
+ */
198
+ setMetadata(data) {
199
+ this.metadata = JSON.stringify(data);
200
+ }
201
+ /**
202
+ * Update metadata by merging with existing values
203
+ *
204
+ * @param updates - Partial metadata to merge
205
+ */
206
+ updateMetadata(updates) {
207
+ const current = this.getMetadata();
208
+ this.setMetadata({ ...current, ...updates });
209
+ }
210
+ /**
211
+ * Update event status
212
+ *
213
+ * @param newStatus - New status to set
214
+ */
215
+ async updateStatus(newStatus) {
216
+ this.status = newStatus;
217
+ this.updatedAt = /* @__PURE__ */ new Date();
218
+ await this.save();
219
+ }
220
+ /**
221
+ * Get the series for this event
222
+ *
223
+ * @returns EventSeries instance or null
224
+ */
225
+ async getSeries() {
226
+ if (!this.seriesId) return null;
227
+ const { EventSeriesCollection: EventSeriesCollection2 } = await Promise.resolve().then(() => EventSeriesCollection$1);
228
+ const collection = await EventSeriesCollection2.create(
229
+ this.options
230
+ );
231
+ return await collection.get({ id: this.seriesId });
232
+ }
233
+ /**
234
+ * Get the event type
235
+ *
236
+ * @returns EventType instance or null
237
+ */
238
+ async getType() {
239
+ if (!this.typeId) return null;
240
+ const { EventTypeCollection: EventTypeCollection2 } = await Promise.resolve().then(() => EventTypeCollection$1);
241
+ const collection = await EventTypeCollection2.create(this.options);
242
+ return await collection.get({ id: this.typeId });
243
+ }
244
+ /**
245
+ * Get the place for this event
246
+ *
247
+ * @returns Place instance or null
248
+ */
249
+ async getPlace() {
250
+ if (!this.placeId) return null;
251
+ try {
252
+ const { PlaceCollection } = await import("@happyvertical/smrt-places");
253
+ const collection = await PlaceCollection.create(this.options);
254
+ return await collection.get({ id: this.placeId });
255
+ } catch {
256
+ return null;
257
+ }
258
+ }
259
+ // Hierarchy traversal (getParent / getChildren / getAncestors /
260
+ // getDescendants / getHierarchy / moveTo) provided by SmrtHierarchical.
261
+ /**
262
+ * Get the root event (top-level ancestor) of this event's hierarchy.
263
+ *
264
+ * @returns Root event instance — `this` when already root
265
+ */
266
+ async getRootEvent() {
267
+ const ancestors = await this.getAncestors();
268
+ return ancestors.length > 0 ? ancestors[0] : this;
269
+ }
270
+ /**
271
+ * Get all participants for this event
272
+ *
273
+ * @returns Array of EventParticipant instances
274
+ */
275
+ async getParticipants() {
276
+ const { EventParticipantCollection: EventParticipantCollection2 } = await Promise.resolve().then(() => EventParticipantCollection$1);
277
+ const collection = await EventParticipantCollection2.create(
278
+ this.options
279
+ );
280
+ return await collection.list({ where: { eventId: this.id } });
281
+ }
282
+ async getEventAssetCollection() {
283
+ const { EventAssetCollection: EventAssetCollection2 } = await Promise.resolve().then(() => EventAssetCollection$1);
284
+ return EventAssetCollection2.create({ db: this.db });
285
+ }
286
+ async getAssets(relationship) {
287
+ if (!this.id) {
288
+ return [];
289
+ }
290
+ const eventAssets = await this.getEventAssetCollection();
291
+ const linkedAssets = await eventAssets.byLeft(
292
+ this.id,
293
+ relationship ? { relationship } : {}
294
+ );
295
+ return resolveOwnedAssetsById(
296
+ this.db,
297
+ linkedAssets.map((link) => link.assetId),
298
+ this.tenantId
299
+ );
300
+ }
301
+ async addAsset(asset, relationship = "attachment", sortOrder = 0) {
302
+ if (!this.id || !asset.id) {
303
+ throw new Error("Cannot associate unsaved event or asset");
304
+ }
305
+ assertValidOwnedAssetRelationship(relationship);
306
+ assertValidOwnedAssetSortOrder(sortOrder);
307
+ const eventAssets = await this.getEventAssetCollection();
308
+ await eventAssets.attach(this.id, asset.id, {
309
+ relationship,
310
+ sortOrder,
311
+ tenantId: this.tenantId
312
+ });
313
+ }
314
+ async removeAsset(assetId, relationship) {
315
+ if (!this.id) {
316
+ return;
317
+ }
318
+ const eventAssets = await this.getEventAssetCollection();
319
+ await eventAssets.detach(
320
+ this.id,
321
+ assetId,
322
+ relationship ? { relationship } : {}
323
+ );
324
+ }
325
+ /**
326
+ * Check if event is currently in progress
327
+ *
328
+ * @returns True if current time is between start and end
329
+ */
330
+ isInProgress() {
331
+ if (this.status !== "in_progress") return false;
332
+ const now = /* @__PURE__ */ new Date();
333
+ if (this.startDate && now < this.startDate) return false;
334
+ if (this.endDate && now > this.endDate) return false;
335
+ return true;
336
+ }
337
+ /**
338
+ * Check if event is a root event (no parent)
339
+ *
340
+ * @returns True if parentId is null/empty
341
+ */
342
+ isRoot() {
343
+ return !this.parentId;
344
+ }
345
+ };
346
+ __decorateClass$4([
347
+ tenantId({ nullable: true })
348
+ ], Event.prototype, "tenantId", 2);
349
+ __decorateClass$4([
350
+ foreignKey("EventSeries")
351
+ ], Event.prototype, "seriesId", 2);
352
+ __decorateClass$4([
353
+ foreignKey("EventType")
354
+ ], Event.prototype, "typeId", 2);
355
+ __decorateClass$4([
356
+ crossPackageRef("@happyvertical/smrt-places:Place")
357
+ ], Event.prototype, "placeId", 2);
358
+ Event = __decorateClass$4([
359
+ TenantScoped({ mode: "optional" }),
360
+ smrt({
361
+ tableStrategy: "sti",
362
+ api: { include: ["list", "get", "create", "update", "delete"] },
363
+ mcp: { include: ["list", "get", "create", "update"] },
364
+ cli: true
365
+ })
366
+ ], Event);
367
+ class EventCollection extends SmrtCollection {
368
+ static _itemClass = Event;
369
+ /**
370
+ * Get events by series
371
+ *
372
+ * @param seriesId - EventSeries ID
373
+ * @returns Array of Event instances
374
+ */
375
+ async getBySeriesId(seriesId) {
376
+ return await this.list({ where: { seriesId } });
377
+ }
378
+ /**
379
+ * Get events at a specific place
380
+ *
381
+ * @param placeId - Place ID
382
+ * @returns Array of Event instances
383
+ */
384
+ async getByPlace(placeId) {
385
+ return await this.list({ where: { placeId } });
386
+ }
387
+ /**
388
+ * Get events by date range
389
+ *
390
+ * @param startDate - Start of date range
391
+ * @param endDate - End of date range
392
+ * @returns Array of Event instances
393
+ */
394
+ async getByDateRange(startDate, endDate) {
395
+ const allEvents = await this.list({});
396
+ return allEvents.filter((event) => {
397
+ if (!event.startDate) return false;
398
+ return event.startDate >= startDate && event.startDate <= endDate;
399
+ });
400
+ }
401
+ /**
402
+ * Get upcoming events
403
+ *
404
+ * @param limit - Maximum number of events to return
405
+ * @returns Array of Event instances starting in the future
406
+ */
407
+ async getUpcoming(limit) {
408
+ const allEvents = await this.list({});
409
+ const now = /* @__PURE__ */ new Date();
410
+ const upcoming = allEvents.filter((event) => event.startDate && event.startDate > now).sort((a, b) => {
411
+ if (!a.startDate || !b.startDate) return 0;
412
+ return a.startDate.getTime() - b.startDate.getTime();
413
+ });
414
+ return limit ? upcoming.slice(0, limit) : upcoming;
415
+ }
416
+ /**
417
+ * Get events by status
418
+ *
419
+ * @param status - Event status to filter by
420
+ * @returns Array of Event instances
421
+ */
422
+ async getByStatus(status) {
423
+ return await this.list({ where: { status } });
424
+ }
425
+ /**
426
+ * Get events by type
427
+ *
428
+ * @param typeId - EventType ID
429
+ * @returns Array of Event instances
430
+ */
431
+ async getByType(typeId) {
432
+ return await this.list({ where: { typeId } });
433
+ }
434
+ /**
435
+ * Get root events (no parent)
436
+ *
437
+ * @returns Array of Event instances with no parent
438
+ */
439
+ async getRootEvents() {
440
+ const allEvents = await this.list({});
441
+ return allEvents.filter((event) => !event.parentId);
442
+ }
443
+ /**
444
+ * Get children of a parent event
445
+ *
446
+ * @param parentId - Parent event ID
447
+ * @returns Array of child Event instances
448
+ */
449
+ async getByParent(parentId) {
450
+ return await this.list({ where: { parentId } });
451
+ }
452
+ /**
453
+ * Get full event tree (hierarchy)
454
+ *
455
+ * @param eventId - Root event ID
456
+ * @returns Object with root event and nested children
457
+ */
458
+ async getEventTree(eventId) {
459
+ const event = await this.get({ id: eventId });
460
+ if (!event) return null;
461
+ return await event.getHierarchy().then((h) => h.current);
462
+ }
463
+ async getAssets(eventId, relationship) {
464
+ return getOwnedAssetsFromCollection(this, eventId, relationship);
465
+ }
466
+ async addAsset(eventId, asset, relationship = "attachment", sortOrder = 0) {
467
+ await addOwnedAssetFromCollection(
468
+ this,
469
+ "Event",
470
+ eventId,
471
+ asset,
472
+ relationship,
473
+ sortOrder
474
+ );
475
+ }
476
+ async removeAsset(eventId, assetId, relationship) {
477
+ await removeOwnedAssetFromCollection(
478
+ this,
479
+ "Event",
480
+ eventId,
481
+ assetId,
482
+ relationship
483
+ );
484
+ }
485
+ /**
486
+ * Search events with filters
487
+ *
488
+ * @param query - Search query for name/description
489
+ * @param filters - Additional filter criteria
490
+ * @returns Array of matching Event instances
491
+ */
492
+ async search(query, filters) {
493
+ let events = await this.list({});
494
+ if (query) {
495
+ const lowerQuery = query.toLowerCase();
496
+ events = events.filter(
497
+ (e) => e.name?.toLowerCase().includes(lowerQuery) || e.description?.toLowerCase().includes(lowerQuery)
498
+ );
499
+ }
500
+ if (filters) {
501
+ if (filters.typeId) {
502
+ events = events.filter((e) => e.typeId === filters.typeId);
503
+ }
504
+ if (filters.seriesId) {
505
+ events = events.filter((e) => e.seriesId === filters.seriesId);
506
+ }
507
+ if (filters.placeId) {
508
+ events = events.filter((e) => e.placeId === filters.placeId);
509
+ }
510
+ if (filters.status) {
511
+ if (Array.isArray(filters.status)) {
512
+ events = events.filter((e) => filters.status?.includes(e.status));
513
+ } else {
514
+ events = events.filter((e) => e.status === filters.status);
515
+ }
516
+ }
517
+ if (filters.startDate) {
518
+ const startDate = filters.startDate;
519
+ events = events.filter((e) => e.startDate && e.startDate >= startDate);
520
+ }
521
+ if (filters.endDate) {
522
+ const endDate = filters.endDate;
523
+ events = events.filter((e) => e.startDate && e.startDate <= endDate);
524
+ }
525
+ if (filters.organizerId) {
526
+ events = events.filter(async (e) => {
527
+ const series = await e.getSeries();
528
+ return series && series.organizerId === filters.organizerId;
529
+ });
530
+ }
531
+ }
532
+ return events;
533
+ }
534
+ /**
535
+ * Get events in progress
536
+ *
537
+ * @returns Array of Event instances currently in progress
538
+ */
539
+ async getInProgress() {
540
+ const inProgressEvents = await this.getByStatus("in_progress");
541
+ return inProgressEvents.filter((event) => event.isInProgress());
542
+ }
543
+ // ============================================
544
+ // Tenant Helper Methods
545
+ // ============================================
546
+ /**
547
+ * Find all events for a specific tenant
548
+ *
549
+ * @param tenantId - Tenant ID to filter by
550
+ * @returns Array of Event instances for the tenant
551
+ */
552
+ async findByTenant(tenantId2) {
553
+ return this.list({ where: { tenantId: tenantId2 } });
554
+ }
555
+ /**
556
+ * Find all global events (no tenant association)
557
+ *
558
+ * @returns Array of Event instances with no tenant
559
+ */
560
+ async findGlobal() {
561
+ return this.list({ where: { tenantId: null } });
562
+ }
563
+ /**
564
+ * Find events for a tenant including global events
565
+ *
566
+ * @param tenantId - Tenant ID to filter by
567
+ * @returns Array of Event instances for the tenant and global events
568
+ */
569
+ async findWithGlobals(tenantId2) {
570
+ return this.query(
571
+ `SELECT * FROM ${this.tableName} WHERE tenant_id = ? OR tenant_id IS NULL`,
572
+ [tenantId2]
573
+ );
574
+ }
575
+ }
576
+ const EventCollection$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
577
+ __proto__: null,
578
+ EventCollection
579
+ }, Symbol.toStringTag, { value: "Module" }));
580
+ var __defProp$3 = Object.defineProperty;
581
+ var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
582
+ var __decorateClass$3 = (decorators, target, key, kind) => {
583
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target;
584
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
585
+ if (decorator = decorators[i])
586
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
587
+ if (kind && result) __defProp$3(target, key, result);
588
+ return result;
589
+ };
590
+ let EventParticipant = class extends SmrtObject {
591
+ tenantId = null;
592
+ eventId = "";
593
+ profileId = "";
594
+ // FK to Profile (from @happyvertical/smrt-profiles)
595
+ role = "";
596
+ // Participant role (ParticipantRole or custom)
597
+ placement = null;
598
+ // Numeric position/placement
599
+ groupId = "";
600
+ // Optional grouping (e.g., team ID for individual players)
601
+ metadata = "";
602
+ // JSON metadata (stored as text)
603
+ externalId = "";
604
+ // External system identifier
605
+ source = "";
606
+ // Source system
607
+ // Timestamps
608
+ createdAt = /* @__PURE__ */ new Date();
609
+ updatedAt = /* @__PURE__ */ new Date();
610
+ constructor(options = {}) {
611
+ super(options);
612
+ if (options.eventId) this.eventId = options.eventId;
613
+ if (options.profileId) this.profileId = options.profileId;
614
+ if (options.role !== void 0) this.role = options.role;
615
+ if (options.placement !== void 0) this.placement = options.placement;
616
+ if (options.groupId !== void 0) this.groupId = options.groupId;
617
+ if (options.externalId !== void 0) this.externalId = options.externalId;
618
+ if (options.source !== void 0) this.source = options.source;
619
+ if (options.metadata !== void 0) {
620
+ if (typeof options.metadata === "string") {
621
+ this.metadata = options.metadata;
622
+ } else {
623
+ this.metadata = JSON.stringify(options.metadata);
624
+ }
625
+ }
626
+ if (options.createdAt) this.createdAt = options.createdAt;
627
+ if (options.updatedAt) this.updatedAt = options.updatedAt;
628
+ }
629
+ /**
630
+ * Get metadata as parsed object
631
+ *
632
+ * @returns Parsed metadata object or empty object
633
+ */
634
+ getMetadata() {
635
+ if (!this.metadata) return {};
636
+ try {
637
+ return JSON.parse(this.metadata);
638
+ } catch {
639
+ return {};
640
+ }
641
+ }
642
+ /**
643
+ * Set metadata from object
644
+ *
645
+ * @param data - Metadata object to store
646
+ */
647
+ setMetadata(data) {
648
+ this.metadata = JSON.stringify(data);
649
+ }
650
+ /**
651
+ * Update metadata by merging with existing values
652
+ *
653
+ * @param updates - Partial metadata to merge
654
+ */
655
+ updateMetadata(updates) {
656
+ const current = this.getMetadata();
657
+ this.setMetadata({ ...current, ...updates });
658
+ }
659
+ /**
660
+ * Get the event for this participant
661
+ *
662
+ * @returns Event instance or null
663
+ */
664
+ async getEvent() {
665
+ if (!this.eventId) return null;
666
+ const { EventCollection: EventCollection2 } = await Promise.resolve().then(() => EventCollection$1);
667
+ const collection = await EventCollection2.create(this.options);
668
+ return await collection.get({ id: this.eventId });
669
+ }
670
+ /**
671
+ * Get the profile for this participant
672
+ *
673
+ * @returns Profile instance or null
674
+ */
675
+ async getProfile() {
676
+ if (!this.profileId) return null;
677
+ try {
678
+ const { ProfileCollection } = await import("@happyvertical/smrt-profiles");
679
+ const collection = await ProfileCollection.create(this.options);
680
+ return await collection.get({ id: this.profileId });
681
+ } catch {
682
+ return null;
683
+ }
684
+ }
685
+ /**
686
+ * Get group participants (others with same groupId)
687
+ *
688
+ * @returns Array of EventParticipant instances
689
+ */
690
+ async getGroupParticipants() {
691
+ if (!this.groupId) return [];
692
+ const { EventParticipantCollection: EventParticipantCollection2 } = await Promise.resolve().then(() => EventParticipantCollection$1);
693
+ const collection = await EventParticipantCollection2.create(
694
+ this.options
695
+ );
696
+ const participants = await collection.list({
697
+ where: { eventId: this.eventId, groupId: this.groupId }
698
+ });
699
+ return participants.filter((p) => p.id !== this.id);
700
+ }
701
+ /**
702
+ * Check if this is a home participant (placement = 0)
703
+ *
704
+ * @returns True if placement is 0
705
+ */
706
+ isHome() {
707
+ return this.placement === 0;
708
+ }
709
+ /**
710
+ * Check if this is an away participant (placement = 1)
711
+ *
712
+ * @returns True if placement is 1
713
+ */
714
+ isAway() {
715
+ return this.placement === 1;
716
+ }
717
+ };
718
+ __decorateClass$3([
719
+ tenantId({ nullable: true })
720
+ ], EventParticipant.prototype, "tenantId", 2);
721
+ __decorateClass$3([
722
+ foreignKey("Event")
723
+ ], EventParticipant.prototype, "eventId", 2);
724
+ __decorateClass$3([
725
+ crossPackageRef("@happyvertical/smrt-profiles:Profile")
726
+ ], EventParticipant.prototype, "profileId", 2);
727
+ EventParticipant = __decorateClass$3([
728
+ TenantScoped({ mode: "optional" }),
729
+ smrt({
730
+ // Junction table - uses event_id + profile_id + role as natural key
731
+ // instead of slug-based conflict columns
732
+ conflictColumns: ["event_id", "profile_id", "role"],
733
+ api: { include: ["list", "get", "create", "update", "delete"] },
734
+ mcp: { include: ["list", "get", "create", "update"] },
735
+ cli: true
736
+ })
737
+ ], EventParticipant);
738
+ var __defProp$2 = Object.defineProperty;
739
+ var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
740
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
741
+ var __decorateClass$2 = (decorators, target, key, kind) => {
742
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
743
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
744
+ if (decorator = decorators[i])
745
+ result = decorator(result) || result;
746
+ return result;
747
+ };
748
+ var __publicField = (obj, key, value) => __defNormalProp(obj, key + "", value);
749
+ let EventParticipantCollection = class extends SmrtJunction {
750
+ leftField = "eventId";
751
+ rightField = "profileId";
752
+ // EventParticipant has no sortOrder column; `placement` is domain ordering
753
+ // (0=home, 1=away) and must not be auto-assigned by setLinks.
754
+ sortField = null;
755
+ positionField = null;
756
+ // ============================================
757
+ // Domain helpers
758
+ // ============================================
759
+ /**
760
+ * Get participants ordered by placement (nulls last).
761
+ */
762
+ async getByPlacement(eventId) {
763
+ const participants = await this.byLeft(eventId);
764
+ return participants.sort((a, b) => {
765
+ if (a.placement === null && b.placement === null) return 0;
766
+ if (a.placement === null) return 1;
767
+ if (b.placement === null) return -1;
768
+ return a.placement - b.placement;
769
+ });
770
+ }
771
+ /**
772
+ * Get participants by group within an event.
773
+ */
774
+ async getByGroup(eventId, groupId) {
775
+ return this.byLeft(eventId, { groupId });
776
+ }
777
+ /**
778
+ * Get the home participant(s) — placement = 0.
779
+ */
780
+ async getHome(eventId) {
781
+ return this.byLeft(eventId, { placement: 0 });
782
+ }
783
+ /**
784
+ * Get the away participant(s) — placement = 1.
785
+ */
786
+ async getAway(eventId) {
787
+ return this.byLeft(eventId, { placement: 1 });
788
+ }
789
+ /**
790
+ * Search participants with optional filters.
791
+ */
792
+ async search(filters) {
793
+ let participants = await this.list({});
794
+ if (filters.eventId) {
795
+ participants = participants.filter((p) => p.eventId === filters.eventId);
796
+ }
797
+ if (filters.profileId) {
798
+ participants = participants.filter(
799
+ (p) => p.profileId === filters.profileId
800
+ );
801
+ }
802
+ if (filters.role) {
803
+ participants = participants.filter((p) => p.role === filters.role);
804
+ }
805
+ if (filters.groupId) {
806
+ participants = participants.filter((p) => p.groupId === filters.groupId);
807
+ }
808
+ return participants;
809
+ }
810
+ /**
811
+ * Get participation statistics for a profile, optionally filtered by event type.
812
+ */
813
+ async getParticipantStats(profileId, eventTypeId) {
814
+ const participants = await this.byRight(profileId);
815
+ let filteredParticipants = participants;
816
+ if (eventTypeId) {
817
+ filteredParticipants = [];
818
+ for (const participant of participants) {
819
+ const event = await participant.getEvent();
820
+ if (event && event.typeId === eventTypeId) {
821
+ filteredParticipants.push(participant);
822
+ }
823
+ }
824
+ }
825
+ const byRole = {};
826
+ const byPlacement = {};
827
+ for (const participant of filteredParticipants) {
828
+ byRole[participant.role] = (byRole[participant.role] || 0) + 1;
829
+ if (participant.placement !== null) {
830
+ byPlacement[participant.placement] = (byPlacement[participant.placement] || 0) + 1;
831
+ }
832
+ }
833
+ return {
834
+ totalEvents: filteredParticipants.length,
835
+ byRole,
836
+ byPlacement
837
+ };
838
+ }
839
+ // ============================================
840
+ // Tenant helpers
841
+ // ============================================
842
+ async findByTenant(tenantId2) {
843
+ return this.list({ where: { tenantId: tenantId2 } });
844
+ }
845
+ async findGlobal() {
846
+ return this.list({ where: { tenantId: null } });
847
+ }
848
+ async findWithGlobals(tenantId2) {
849
+ return this.query(
850
+ `SELECT * FROM ${this.tableName} WHERE tenant_id = ? OR tenant_id IS NULL`,
851
+ [tenantId2]
852
+ );
853
+ }
854
+ };
855
+ __publicField(EventParticipantCollection, "_itemClass", EventParticipant);
856
+ EventParticipantCollection = __decorateClass$2([
857
+ smrt()
858
+ ], EventParticipantCollection);
859
+ const EventParticipantCollection$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
860
+ __proto__: null,
861
+ get EventParticipantCollection() {
862
+ return EventParticipantCollection;
863
+ }
864
+ }, Symbol.toStringTag, { value: "Module" }));
865
+ var __defProp$1 = Object.defineProperty;
866
+ var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
867
+ var __decorateClass$1 = (decorators, target, key, kind) => {
868
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
869
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
870
+ if (decorator = decorators[i])
871
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
872
+ if (kind && result) __defProp$1(target, key, result);
873
+ return result;
874
+ };
875
+ let EventSeries = class extends SmrtObject {
876
+ tenantId = null;
877
+ name = "";
878
+ typeId = "";
879
+ organizerId = "";
880
+ // FK to Profile (from @happyvertical/smrt-profiles)
881
+ description = "";
882
+ startDate = null;
883
+ endDate = null;
884
+ recurrence = "";
885
+ // JSON recurrence pattern (stored as text)
886
+ metadata = "";
887
+ // JSON metadata (stored as text)
888
+ externalId = "";
889
+ // External system identifier
890
+ source = "";
891
+ // Source system (e.g., 'ticketmaster', 'espn')
892
+ // Timestamps
893
+ createdAt = /* @__PURE__ */ new Date();
894
+ updatedAt = /* @__PURE__ */ new Date();
895
+ constructor(options = {}) {
896
+ super(options);
897
+ if (options.typeId) this.typeId = options.typeId;
898
+ if (options.organizerId) this.organizerId = options.organizerId;
899
+ if (options.description !== void 0)
900
+ this.description = options.description;
901
+ if (options.startDate !== void 0)
902
+ this.startDate = options.startDate || null;
903
+ if (options.endDate !== void 0) this.endDate = options.endDate || null;
904
+ if (options.externalId !== void 0) this.externalId = options.externalId;
905
+ if (options.source !== void 0) this.source = options.source;
906
+ if (options.recurrence !== void 0) {
907
+ if (typeof options.recurrence === "string") {
908
+ this.recurrence = options.recurrence;
909
+ } else {
910
+ this.recurrence = JSON.stringify(options.recurrence);
911
+ }
912
+ }
913
+ if (options.metadata !== void 0) {
914
+ if (typeof options.metadata === "string") {
915
+ this.metadata = options.metadata;
916
+ } else {
917
+ this.metadata = JSON.stringify(options.metadata);
918
+ }
919
+ }
920
+ if (options.createdAt) this.createdAt = options.createdAt;
921
+ if (options.updatedAt) this.updatedAt = options.updatedAt;
922
+ }
923
+ /**
924
+ * Get recurrence pattern as parsed object
925
+ *
926
+ * @returns Parsed recurrence pattern or null
927
+ */
928
+ getRecurrence() {
929
+ if (!this.recurrence) return null;
930
+ try {
931
+ return JSON.parse(this.recurrence);
932
+ } catch {
933
+ return null;
934
+ }
935
+ }
936
+ /**
937
+ * Set recurrence pattern from object
938
+ *
939
+ * @param pattern - Recurrence pattern to store
940
+ */
941
+ setRecurrence(pattern) {
942
+ this.recurrence = JSON.stringify(pattern);
943
+ }
944
+ /**
945
+ * Get metadata as parsed object
946
+ *
947
+ * @returns Parsed metadata object or empty object
948
+ */
949
+ getMetadata() {
950
+ if (!this.metadata) return {};
951
+ try {
952
+ return JSON.parse(this.metadata);
953
+ } catch {
954
+ return {};
955
+ }
956
+ }
957
+ /**
958
+ * Set metadata from object
959
+ *
960
+ * @param data - Metadata object to store
961
+ */
962
+ setMetadata(data) {
963
+ this.metadata = JSON.stringify(data);
964
+ }
965
+ /**
966
+ * Update metadata by merging with existing values
967
+ *
968
+ * @param updates - Partial metadata to merge
969
+ */
970
+ updateMetadata(updates) {
971
+ const current = this.getMetadata();
972
+ this.setMetadata({ ...current, ...updates });
973
+ }
974
+ /**
975
+ * Get the event type for this series
976
+ *
977
+ * @returns EventType instance or null
978
+ */
979
+ async getType() {
980
+ if (!this.typeId) return null;
981
+ const { EventTypeCollection: EventTypeCollection2 } = await Promise.resolve().then(() => EventTypeCollection$1);
982
+ const collection = await EventTypeCollection2.create(this.options);
983
+ return await collection.get({ id: this.typeId });
984
+ }
985
+ /**
986
+ * Get the organizer profile for this series
987
+ *
988
+ * @returns Profile instance or null
989
+ */
990
+ async getOrganizer() {
991
+ if (!this.organizerId) return null;
992
+ try {
993
+ const { ProfileCollection } = await import("@happyvertical/smrt-profiles");
994
+ const collection = await ProfileCollection.create(this.options);
995
+ return await collection.get({ id: this.organizerId });
996
+ } catch {
997
+ return null;
998
+ }
999
+ }
1000
+ /**
1001
+ * Get all events in this series
1002
+ *
1003
+ * @returns Array of Event instances
1004
+ */
1005
+ async getEvents() {
1006
+ const { EventCollection: EventCollection2 } = await Promise.resolve().then(() => EventCollection$1);
1007
+ const collection = await EventCollection2.create(this.options);
1008
+ return await collection.list({ where: { seriesId: this.id } });
1009
+ }
1010
+ /**
1011
+ * Check if series is currently active
1012
+ *
1013
+ * @returns True if current date is between start and end
1014
+ */
1015
+ isActive() {
1016
+ const now = /* @__PURE__ */ new Date();
1017
+ if (this.startDate && now < this.startDate) return false;
1018
+ if (this.endDate && now > this.endDate) return false;
1019
+ return true;
1020
+ }
1021
+ };
1022
+ __decorateClass$1([
1023
+ tenantId({ nullable: true })
1024
+ ], EventSeries.prototype, "tenantId", 2);
1025
+ __decorateClass$1([
1026
+ foreignKey("EventType")
1027
+ ], EventSeries.prototype, "typeId", 2);
1028
+ __decorateClass$1([
1029
+ crossPackageRef("@happyvertical/smrt-profiles:Profile")
1030
+ ], EventSeries.prototype, "organizerId", 2);
1031
+ EventSeries = __decorateClass$1([
1032
+ TenantScoped({ mode: "optional" }),
1033
+ smrt({
1034
+ tableStrategy: "sti",
1035
+ api: { include: ["list", "get", "create", "update", "delete"] },
1036
+ mcp: { include: ["list", "get", "create", "update"] },
1037
+ cli: true
1038
+ })
1039
+ ], EventSeries);
1040
+ class EventSeriesCollection extends SmrtCollection {
1041
+ static _itemClass = EventSeries;
1042
+ /**
1043
+ * Get series by organizer
1044
+ *
1045
+ * @param organizerId - Profile ID of the organizer
1046
+ * @returns Array of EventSeries instances
1047
+ */
1048
+ async getByOrganizer(organizerId) {
1049
+ return await this.list({ where: { organizerId } });
1050
+ }
1051
+ /**
1052
+ * Get currently active series
1053
+ *
1054
+ * @returns Array of EventSeries instances active today
1055
+ */
1056
+ async getActive() {
1057
+ const allSeries = await this.list({});
1058
+ const now = /* @__PURE__ */ new Date();
1059
+ return allSeries.filter((series) => {
1060
+ if (series.startDate && now < series.startDate) return false;
1061
+ if (series.endDate && now > series.endDate) return false;
1062
+ return true;
1063
+ });
1064
+ }
1065
+ /**
1066
+ * Get upcoming series
1067
+ *
1068
+ * @param limit - Maximum number of series to return
1069
+ * @returns Array of EventSeries instances starting in the future
1070
+ */
1071
+ async getUpcoming(limit) {
1072
+ const allSeries = await this.list({});
1073
+ const now = /* @__PURE__ */ new Date();
1074
+ const upcoming = allSeries.filter((series) => series.startDate && series.startDate > now).sort((a, b) => {
1075
+ if (!a.startDate || !b.startDate) return 0;
1076
+ return a.startDate.getTime() - b.startDate.getTime();
1077
+ });
1078
+ return limit ? upcoming.slice(0, limit) : upcoming;
1079
+ }
1080
+ /**
1081
+ * Get series by type
1082
+ *
1083
+ * @param typeId - EventType ID
1084
+ * @returns Array of EventSeries instances
1085
+ */
1086
+ async getByType(typeId) {
1087
+ return await this.list({ where: { typeId } });
1088
+ }
1089
+ /**
1090
+ * Search series with filters
1091
+ *
1092
+ * @param query - Search query for name/description
1093
+ * @param filters - Additional filter criteria
1094
+ * @returns Array of matching EventSeries instances
1095
+ */
1096
+ async search(query, filters) {
1097
+ let series = await this.list({});
1098
+ if (query) {
1099
+ const lowerQuery = query.toLowerCase();
1100
+ series = series.filter(
1101
+ (s) => s.name?.toLowerCase().includes(lowerQuery) || s.description?.toLowerCase().includes(lowerQuery)
1102
+ );
1103
+ }
1104
+ if (filters) {
1105
+ if (filters.typeId) {
1106
+ series = series.filter((s) => s.typeId === filters.typeId);
1107
+ }
1108
+ if (filters.organizerId) {
1109
+ series = series.filter((s) => s.organizerId === filters.organizerId);
1110
+ }
1111
+ if (filters.startDate) {
1112
+ const startDate = filters.startDate;
1113
+ series = series.filter((s) => s.startDate && s.startDate >= startDate);
1114
+ }
1115
+ if (filters.endDate) {
1116
+ const endDate = filters.endDate;
1117
+ series = series.filter((s) => s.endDate && s.endDate <= endDate);
1118
+ }
1119
+ }
1120
+ return series;
1121
+ }
1122
+ // ============================================
1123
+ // Tenant Helper Methods
1124
+ // ============================================
1125
+ /**
1126
+ * Find all event series for a specific tenant
1127
+ *
1128
+ * @param tenantId - Tenant ID to filter by
1129
+ * @returns Array of EventSeries instances for the tenant
1130
+ */
1131
+ async findByTenant(tenantId2) {
1132
+ return this.list({ where: { tenantId: tenantId2 } });
1133
+ }
1134
+ /**
1135
+ * Find all global event series (no tenant association)
1136
+ *
1137
+ * @returns Array of EventSeries instances with no tenant
1138
+ */
1139
+ async findGlobal() {
1140
+ return this.list({ where: { tenantId: null } });
1141
+ }
1142
+ /**
1143
+ * Find event series for a tenant including global series
1144
+ *
1145
+ * @param tenantId - Tenant ID to filter by
1146
+ * @returns Array of EventSeries instances for the tenant and global series
1147
+ */
1148
+ async findWithGlobals(tenantId2) {
1149
+ return this.query(
1150
+ `SELECT * FROM ${this.tableName} WHERE tenant_id = ? OR tenant_id IS NULL`,
1151
+ [tenantId2]
1152
+ );
1153
+ }
1154
+ }
1155
+ const EventSeriesCollection$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1156
+ __proto__: null,
1157
+ EventSeriesCollection
1158
+ }, Symbol.toStringTag, { value: "Module" }));
1159
+ var __defProp = Object.defineProperty;
1160
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
1161
+ var __decorateClass = (decorators, target, key, kind) => {
1162
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
1163
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
1164
+ if (decorator = decorators[i])
1165
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
1166
+ if (kind && result) __defProp(target, key, result);
1167
+ return result;
1168
+ };
1169
+ let EventType = class extends SmrtObject {
1170
+ tenantId = null;
1171
+ name = "";
1172
+ description = "";
1173
+ // Optional description
1174
+ schema = "";
1175
+ // JSON schema for event metadata (stored as text)
1176
+ participantSchema = "";
1177
+ // JSON schema for participant metadata (stored as text)
1178
+ // Timestamps
1179
+ createdAt = /* @__PURE__ */ new Date();
1180
+ updatedAt = /* @__PURE__ */ new Date();
1181
+ constructor(options = {}) {
1182
+ super(options);
1183
+ if (options.name) this.name = options.name;
1184
+ if (options.description !== void 0)
1185
+ this.description = options.description;
1186
+ if (options.schema !== void 0) {
1187
+ if (typeof options.schema === "string") {
1188
+ this.schema = options.schema;
1189
+ } else {
1190
+ this.schema = JSON.stringify(options.schema);
1191
+ }
1192
+ }
1193
+ if (options.participantSchema !== void 0) {
1194
+ if (typeof options.participantSchema === "string") {
1195
+ this.participantSchema = options.participantSchema;
1196
+ } else {
1197
+ this.participantSchema = JSON.stringify(options.participantSchema);
1198
+ }
1199
+ }
1200
+ if (options.createdAt) this.createdAt = options.createdAt;
1201
+ if (options.updatedAt) this.updatedAt = options.updatedAt;
1202
+ }
1203
+ /**
1204
+ * Get schema as parsed object
1205
+ *
1206
+ * @returns Parsed schema object or empty object if no schema
1207
+ */
1208
+ getSchema() {
1209
+ if (!this.schema) return {};
1210
+ try {
1211
+ return JSON.parse(this.schema);
1212
+ } catch {
1213
+ return {};
1214
+ }
1215
+ }
1216
+ /**
1217
+ * Set schema from object
1218
+ *
1219
+ * @param data - Schema object to store
1220
+ */
1221
+ setSchema(data) {
1222
+ this.schema = JSON.stringify(data);
1223
+ }
1224
+ /**
1225
+ * Get participant schema as parsed object
1226
+ *
1227
+ * @returns Parsed participant schema object or empty object
1228
+ */
1229
+ getParticipantSchema() {
1230
+ if (!this.participantSchema) return {};
1231
+ try {
1232
+ return JSON.parse(this.participantSchema);
1233
+ } catch {
1234
+ return {};
1235
+ }
1236
+ }
1237
+ /**
1238
+ * Set participant schema from object
1239
+ *
1240
+ * @param data - Participant schema object to store
1241
+ */
1242
+ setParticipantSchema(data) {
1243
+ this.participantSchema = JSON.stringify(data);
1244
+ }
1245
+ /**
1246
+ * Convenience method for slug-based lookup
1247
+ *
1248
+ * @param slug - The slug to search for
1249
+ * @returns EventType instance or null if not found
1250
+ */
1251
+ static async getBySlug(_slug) {
1252
+ return null;
1253
+ }
1254
+ };
1255
+ __decorateClass([
1256
+ tenantId({ nullable: true })
1257
+ ], EventType.prototype, "tenantId", 2);
1258
+ __decorateClass([
1259
+ field({ required: true })
1260
+ ], EventType.prototype, "name", 2);
1261
+ EventType = __decorateClass([
1262
+ TenantScoped({ mode: "optional" }),
1263
+ smrt({
1264
+ tableStrategy: "sti",
1265
+ api: { include: ["list", "get", "create", "update", "delete"] },
1266
+ mcp: { include: ["list", "get", "create"] },
1267
+ cli: true
1268
+ })
1269
+ ], EventType);
1270
+ class EventTypeCollection extends SmrtCollection {
1271
+ static _itemClass = EventType;
1272
+ /**
1273
+ * Get or create an event type by slug
1274
+ *
1275
+ * @param slug - EventType slug (e.g., 'basketball-game', 'concert')
1276
+ * @param name - Optional display name (defaults to capitalized slug)
1277
+ * @returns EventType instance
1278
+ */
1279
+ async getOrCreate(slug, name) {
1280
+ const existing = await this.get({ slug });
1281
+ if (existing) {
1282
+ return existing;
1283
+ }
1284
+ const displayName = name || slug.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase());
1285
+ return await this.create({
1286
+ slug,
1287
+ name: displayName
1288
+ });
1289
+ }
1290
+ /**
1291
+ * Get an event type by slug
1292
+ *
1293
+ * @param slug - EventType slug to search for
1294
+ * @returns EventType instance or null if not found
1295
+ */
1296
+ async getBySlug(slug) {
1297
+ return await this.get({ slug });
1298
+ }
1299
+ /**
1300
+ * Initialize default event types
1301
+ *
1302
+ * Creates common event types if they don't exist:
1303
+ * - Sports: game, period, goal, assist, penalty
1304
+ * - Entertainment: concert, performance, song
1305
+ * - Professional: conference, session, presentation, workshop
1306
+ * - Community: meeting, agenda-item, motion, vote
1307
+ *
1308
+ * @returns Array of created/existing event types
1309
+ */
1310
+ async initializeDefaults() {
1311
+ const defaults = [
1312
+ // Sports
1313
+ { slug: "game", name: "Game" },
1314
+ { slug: "match", name: "Match" },
1315
+ { slug: "period", name: "Period" },
1316
+ { slug: "quarter", name: "Quarter" },
1317
+ { slug: "inning", name: "Inning" },
1318
+ { slug: "goal", name: "Goal" },
1319
+ { slug: "assist", name: "Assist" },
1320
+ { slug: "penalty", name: "Penalty" },
1321
+ { slug: "substitution", name: "Substitution" },
1322
+ // Entertainment
1323
+ { slug: "concert", name: "Concert" },
1324
+ { slug: "performance", name: "Performance" },
1325
+ { slug: "set", name: "Set" },
1326
+ { slug: "song", name: "Song" },
1327
+ { slug: "theater", name: "Theater" },
1328
+ { slug: "show", name: "Show" },
1329
+ // Professional
1330
+ { slug: "conference", name: "Conference" },
1331
+ { slug: "session", name: "Session" },
1332
+ { slug: "presentation", name: "Presentation" },
1333
+ { slug: "workshop", name: "Workshop" },
1334
+ { slug: "seminar", name: "Seminar" },
1335
+ { slug: "keynote", name: "Keynote" },
1336
+ { slug: "panel", name: "Panel" },
1337
+ // Community
1338
+ { slug: "meeting", name: "Meeting" },
1339
+ { slug: "town-hall", name: "Town Hall" },
1340
+ { slug: "agenda-item", name: "Agenda Item" },
1341
+ { slug: "motion", name: "Motion" },
1342
+ { slug: "amendment", name: "Amendment" },
1343
+ { slug: "vote", name: "Vote" },
1344
+ { slug: "discussion", name: "Discussion" },
1345
+ // General
1346
+ { slug: "event", name: "Event" },
1347
+ { slug: "activity", name: "Activity" },
1348
+ { slug: "action", name: "Action" }
1349
+ ];
1350
+ const types = [];
1351
+ for (const def of defaults) {
1352
+ const type = await this.getOrCreate(def.slug, def.name);
1353
+ types.push(type);
1354
+ }
1355
+ return types;
1356
+ }
1357
+ // ============================================
1358
+ // Tenant Helper Methods
1359
+ // ============================================
1360
+ /**
1361
+ * Find all event types for a specific tenant
1362
+ *
1363
+ * @param tenantId - Tenant ID to filter by
1364
+ * @returns Array of EventType instances for the tenant
1365
+ */
1366
+ async findByTenant(tenantId2) {
1367
+ return this.list({ where: { tenantId: tenantId2 } });
1368
+ }
1369
+ /**
1370
+ * Find all global event types (no tenant association)
1371
+ *
1372
+ * @returns Array of EventType instances with no tenant
1373
+ */
1374
+ async findGlobal() {
1375
+ return this.list({ where: { tenantId: null } });
1376
+ }
1377
+ /**
1378
+ * Find event types for a tenant including global types
1379
+ *
1380
+ * @param tenantId - Tenant ID to filter by
1381
+ * @returns Array of EventType instances for the tenant and global types
1382
+ */
1383
+ async findWithGlobals(tenantId2) {
1384
+ return this.query(
1385
+ `SELECT * FROM ${this.tableName} WHERE tenant_id = ? OR tenant_id IS NULL`,
1386
+ [tenantId2]
1387
+ );
1388
+ }
1389
+ }
1390
+ const EventTypeCollection$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1391
+ __proto__: null,
1392
+ EventTypeCollection
1393
+ }, Symbol.toStringTag, { value: "Module" }));
1394
+ export {
1395
+ EVENTS_MODULE_META,
1396
+ EVENTS_UI_SLOTS,
1397
+ Event,
1398
+ EventAsset,
1399
+ EventAssetCollection,
1400
+ EventCollection,
1401
+ EventParticipant,
1402
+ EventParticipantCollection,
1403
+ EventSeries,
1404
+ EventSeriesCollection,
1405
+ EventType,
1406
+ EventTypeCollection,
1407
+ calculateDuration,
1408
+ calculateNextOccurrence,
1409
+ checkSchedulingConflict,
1410
+ formatDuration,
1411
+ formatEventDateRange,
1412
+ generateEventSlug,
1413
+ getEventStatusFromDates,
1414
+ isEventNow,
1415
+ parseRecurrencePattern,
1416
+ sortEventsByDate,
1417
+ validateEventStatus
1418
+ };
1419
+ //# sourceMappingURL=index.js.map