@happyvertical/smrt-events 0.51.39 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -1
- package/README.md +37 -2
- package/dist/chunks/utils-DV00CoDY.js +320 -0
- package/dist/chunks/utils-DV00CoDY.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -3
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +61 -5
- package/dist/models/Event.d.ts +12 -0
- package/dist/models/Event.d.ts.map +1 -1
- package/dist/models/EventSeries.d.ts +16 -0
- package/dist/models/EventSeries.d.ts.map +1 -1
- package/dist/recurrence.d.ts +102 -0
- package/dist/recurrence.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +48 -6
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -96
- package/package.json +15 -15
- package/dist/utils.js.map +0 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time-zone-aware recurrence expansion for {@link RecurrencePattern}.
|
|
3
|
+
*
|
|
4
|
+
* Implements the RFC 5545 RRULE subset that EventSeries patterns use:
|
|
5
|
+
* `FREQ` daily / weekly / monthly / yearly, `INTERVAL`, `BYDAY` (weekly day
|
|
6
|
+
* lists and monthly ordinals such as `2TU` / `-1FR`), `BYMONTHDAY` (negative
|
|
7
|
+
* values count from the month end), `BYMONTH` (yearly), `BYSETPOS`
|
|
8
|
+
* (monthly), `UNTIL`, and `COUNT`.
|
|
9
|
+
*
|
|
10
|
+
* Occurrences keep the wall-clock time of the first occurrence in the given
|
|
11
|
+
* IANA time zone, so a 19:00 weekly meeting stays at 19:00 local across a
|
|
12
|
+
* daylight-saving change. All arithmetic runs on calendar dates; instants are
|
|
13
|
+
* produced only at the end through `Intl`, so the host time zone never leaks
|
|
14
|
+
* into the result.
|
|
15
|
+
*/
|
|
16
|
+
import type { RecurrencePattern } from './types';
|
|
17
|
+
/** Options for {@link expandRecurrence}. */
|
|
18
|
+
export interface ExpandRecurrenceOptions {
|
|
19
|
+
/** First occurrence (RRULE `DTSTART`); its local time is reused for every occurrence. */
|
|
20
|
+
start: Date;
|
|
21
|
+
/** Inclusive lower bound of the window to return occurrences for. */
|
|
22
|
+
rangeStart: Date;
|
|
23
|
+
/** Inclusive upper bound of the window to return occurrences for. */
|
|
24
|
+
rangeEnd: Date;
|
|
25
|
+
/** IANA time zone the pattern repeats in. Defaults to `pattern.timeZone`, then `UTC`. */
|
|
26
|
+
timeZone?: string;
|
|
27
|
+
/** Safety cap on returned occurrences. Defaults to 1000. */
|
|
28
|
+
limit?: number;
|
|
29
|
+
}
|
|
30
|
+
/** A calendar date with no time zone. */
|
|
31
|
+
export interface CivilDate {
|
|
32
|
+
year: number;
|
|
33
|
+
month: number;
|
|
34
|
+
day: number;
|
|
35
|
+
}
|
|
36
|
+
/** A local date and time with no time zone. */
|
|
37
|
+
export interface ZonedWallTime extends CivilDate {
|
|
38
|
+
hour: number;
|
|
39
|
+
minute: number;
|
|
40
|
+
second: number;
|
|
41
|
+
millisecond: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check whether a string is an IANA time zone this runtime recognizes.
|
|
45
|
+
*
|
|
46
|
+
* @param timeZone - Candidate zone name (e.g. `America/Edmonton`)
|
|
47
|
+
* @returns True when `Intl` accepts the zone
|
|
48
|
+
*/
|
|
49
|
+
export declare function isValidTimeZone(timeZone: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Wall-clock fields of an instant in a time zone.
|
|
52
|
+
*
|
|
53
|
+
* @param instant - Instant to project
|
|
54
|
+
* @param timeZone - IANA time zone
|
|
55
|
+
* @returns Local year/month/day/hour/minute/second/millisecond
|
|
56
|
+
*/
|
|
57
|
+
export declare function toZonedWallTime(instant: Date, timeZone: string): ZonedWallTime;
|
|
58
|
+
/**
|
|
59
|
+
* Instant for a wall-clock time in a time zone.
|
|
60
|
+
*
|
|
61
|
+
* - A time skipped by a daylight-saving jump (spring forward) resolves
|
|
62
|
+
* FORWARD by the size of the gap: 02:30 on a 02:00 -> 03:00 day is 03:30.
|
|
63
|
+
* - A time that occurs twice (fall back) resolves to its FIRST occurrence.
|
|
64
|
+
*
|
|
65
|
+
* These are the RFC 5545 / Temporal `compatible` rules, independent of the
|
|
66
|
+
* zone's sign or the host time zone.
|
|
67
|
+
*
|
|
68
|
+
* @param wall - Local date and time
|
|
69
|
+
* @param timeZone - IANA time zone
|
|
70
|
+
* @returns The matching instant
|
|
71
|
+
*/
|
|
72
|
+
export declare function fromZonedWallTime(wall: ZonedWallTime, timeZone: string): Date;
|
|
73
|
+
/**
|
|
74
|
+
* Expand a recurrence pattern into occurrence start instants inside a window.
|
|
75
|
+
*
|
|
76
|
+
* `count` counts from the first occurrence (`start`), including occurrences
|
|
77
|
+
* that fall before `rangeStart`; `until` is inclusive. Occurrences before
|
|
78
|
+
* `start` are never produced, and a `start` that does not itself match the
|
|
79
|
+
* pattern is not an occurrence (as in rrule.js, unlike a bare RFC 5545
|
|
80
|
+
* `DTSTART`). Invalid zones or `byDay` codes throw
|
|
81
|
+
* `RangeError`.
|
|
82
|
+
*
|
|
83
|
+
* @param pattern - Recurrence pattern (object or stored JSON string)
|
|
84
|
+
* @param options - First occurrence, window, and time zone
|
|
85
|
+
* @returns Occurrence start instants in ascending order
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* // Every second Tuesday at 19:00 Edmonton time, for October 2026
|
|
90
|
+
* expandRecurrence(
|
|
91
|
+
* { frequency: 'monthly', byDay: ['2TU'] },
|
|
92
|
+
* {
|
|
93
|
+
* start: new Date('2026-01-14T02:00:00Z'),
|
|
94
|
+
* rangeStart: new Date('2026-10-01T00:00:00Z'),
|
|
95
|
+
* rangeEnd: new Date('2026-10-31T23:59:59Z'),
|
|
96
|
+
* timeZone: 'America/Edmonton',
|
|
97
|
+
* },
|
|
98
|
+
* );
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export declare function expandRecurrence(pattern: RecurrencePattern | string | null | undefined, options: ExpandRecurrenceOptions): Date[];
|
|
102
|
+
//# sourceMappingURL=recurrence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurrence.d.ts","sourceRoot":"","sources":["../src/recurrence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD,4CAA4C;AAC5C,MAAM,WAAW,uBAAuB;IACtC,yFAAyF;IACzF,KAAK,EAAE,IAAI,CAAC;IACZ,qEAAqE;IACrE,UAAU,EAAE,IAAI,CAAC;IACjB,qEAAqE;IACrE,QAAQ,EAAE,IAAI,CAAC;IACf,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAOD,yCAAyC;AACzC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,+CAA+C;AAC/C,MAAM,WAAW,aAAc,SAAQ,SAAS;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAuBD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQzD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,IAAI,EACb,QAAQ,EAAE,MAAM,GACf,aAAa,CAaf;AAgBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CA4B7E;AA2KD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACtD,OAAO,EAAE,uBAAuB,GAC/B,IAAI,EAAE,CA+DR"}
|
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-events",
|
|
6
|
-
"packageVersion": "0.
|
|
6
|
+
"packageVersion": "0.53.0",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
10
|
+
"manifest": "26a89d6eeefcf9434cee4c3c8c92e115b078b3077534a4e7cc778050ef2e4c3d",
|
|
11
|
+
"packageJson": "09c4c5942d07957ed9d1d4467386bb328c1e8d925e1d1bd2ce74b7da7e64eac0",
|
|
12
|
+
"agents": "fd92563513c75d3b1f4107a239a7030bbcb8ac45e0e13e87afdbbebc84b0d4be"
|
|
13
13
|
},
|
|
14
14
|
"exports": [
|
|
15
15
|
".",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
39
39
|
"@types/node": "24.13.6",
|
|
40
40
|
"fast-glob": "^3.3.3",
|
|
41
|
-
"svelte": "^5.57.
|
|
41
|
+
"svelte": "^5.57.0",
|
|
42
42
|
"svelte-check": "^4.7.6",
|
|
43
43
|
"typescript": "6.0.3",
|
|
44
44
|
"vite": "8.1.4",
|
|
@@ -1706,6 +1706,19 @@
|
|
|
1706
1706
|
"required": false,
|
|
1707
1707
|
"columnType": "TIMESTAMP"
|
|
1708
1708
|
},
|
|
1709
|
+
{
|
|
1710
|
+
"name": "allDay",
|
|
1711
|
+
"type": "boolean",
|
|
1712
|
+
"required": false,
|
|
1713
|
+
"columnType": "BOOLEAN",
|
|
1714
|
+
"default": false
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
"name": "timeZone",
|
|
1718
|
+
"type": "text",
|
|
1719
|
+
"required": false,
|
|
1720
|
+
"columnType": "TEXT"
|
|
1721
|
+
},
|
|
1709
1722
|
{
|
|
1710
1723
|
"name": "status",
|
|
1711
1724
|
"type": "text",
|
|
@@ -2868,6 +2881,7 @@
|
|
|
2868
2881
|
"methods": [
|
|
2869
2882
|
"getEvents",
|
|
2870
2883
|
"getMetadata",
|
|
2884
|
+
"getOccurrences",
|
|
2871
2885
|
"getOrganizer",
|
|
2872
2886
|
"getRecurrence",
|
|
2873
2887
|
"getType",
|
|
@@ -2886,6 +2900,15 @@
|
|
|
2886
2900
|
"name": "getMetadata",
|
|
2887
2901
|
"returns": "Record<string, unknown>"
|
|
2888
2902
|
},
|
|
2903
|
+
{
|
|
2904
|
+
"name": "getOccurrences",
|
|
2905
|
+
"params": [
|
|
2906
|
+
"rangeStart: Date",
|
|
2907
|
+
"rangeEnd: Date",
|
|
2908
|
+
"options?: object"
|
|
2909
|
+
],
|
|
2910
|
+
"returns": "Date[]"
|
|
2911
|
+
},
|
|
2889
2912
|
{
|
|
2890
2913
|
"name": "getOrganizer",
|
|
2891
2914
|
"async": true,
|
|
@@ -3021,6 +3044,12 @@
|
|
|
3021
3044
|
"operation": "setRecurrence",
|
|
3022
3045
|
"objectName": "@happyvertical/smrt-events:EventSeries"
|
|
3023
3046
|
},
|
|
3047
|
+
{
|
|
3048
|
+
"kind": "cli",
|
|
3049
|
+
"name": "eventseries_getOccurrences",
|
|
3050
|
+
"operation": "getOccurrences",
|
|
3051
|
+
"objectName": "@happyvertical/smrt-events:EventSeries"
|
|
3052
|
+
},
|
|
3024
3053
|
{
|
|
3025
3054
|
"kind": "cli",
|
|
3026
3055
|
"name": "eventseries_getMetadata",
|
|
@@ -3103,6 +3132,13 @@
|
|
|
3103
3132
|
"reason": "not listed in api.include",
|
|
3104
3133
|
"objectName": "@happyvertical/smrt-events:EventSeries"
|
|
3105
3134
|
},
|
|
3135
|
+
{
|
|
3136
|
+
"kind": "api",
|
|
3137
|
+
"operation": "getOccurrences",
|
|
3138
|
+
"code": "not-included",
|
|
3139
|
+
"reason": "not listed in api.include",
|
|
3140
|
+
"objectName": "@happyvertical/smrt-events:EventSeries"
|
|
3141
|
+
},
|
|
3106
3142
|
{
|
|
3107
3143
|
"kind": "api",
|
|
3108
3144
|
"operation": "getOrganizer",
|
|
@@ -4784,6 +4820,12 @@
|
|
|
4784
4820
|
"operation": "setRecurrence",
|
|
4785
4821
|
"objectName": "@happyvertical/smrt-events:EventSeries"
|
|
4786
4822
|
},
|
|
4823
|
+
{
|
|
4824
|
+
"kind": "cli",
|
|
4825
|
+
"name": "eventseries_getOccurrences",
|
|
4826
|
+
"operation": "getOccurrences",
|
|
4827
|
+
"objectName": "@happyvertical/smrt-events:EventSeries"
|
|
4828
|
+
},
|
|
4787
4829
|
{
|
|
4788
4830
|
"kind": "cli",
|
|
4789
4831
|
"name": "eventseries_getMetadata",
|
|
@@ -4978,5 +5020,5 @@
|
|
|
4978
5020
|
"polymorphicAssociations": 0,
|
|
4979
5021
|
"uuidColumns": 40
|
|
4980
5022
|
},
|
|
4981
|
-
"agentDoc": "# @happyvertical/smrt-events\n\nInfinite-nesting event hierarchy with series, types, participants, and role/placement management.\n\n## Models\n\n- **Event** (STI, extends `SmrtHierarchical`): self-referencing parent-child via `parentId` (UUID). Links to `seriesId`, `typeId`, `placeId`. Status: scheduled/in_progress/completed/cancelled/postponed. Hierarchy traversal (`getParent()`, `getChildren()`, `getAncestors()`, `getDescendants()`, `getHierarchy()`, `moveTo()`) is provided by `SmrtHierarchical`; `getRootEvent()` and `isRoot()` remain on `Event`.\n- **EventAsset**: dedicated owned-asset join in `event_assets` with `relationship` and `sortOrder`.\n- **EventType**: classification with JSON schema for custom fields per type.\n- **EventSeries**: recurrence patterns (daily/weekly/monthly/yearly).\n- **EventParticipant**: junction with `role` (home/away/speaker/panelist/etc.), `placement` (numeric — team ordering and rankings), `groupId` (team grouping within event). `conflictColumns: ['event_id', 'profile_id', 'role']`.\n\n## Gotchas\n\n- **No depth limit** on event hierarchy — deep nesting can cause N+1 queries\n- **Placement is numeric**: used for both team ordering (0=home, 1=away) and rankings — context-dependent\n- **GroupId not enforced at DB level**: for logical grouping only (e.g., team members in a game)\n- **Optional tenancy** with nullable tenantId\n- **Event physical foreign keys**: `parentId`, `seriesId`, and `typeId` retain\n PostgreSQL/SQLite constraints. DuckDB/JSON omit only those explicitly scoped\n physical constraints because DuckDB cannot enforce Event's self-reference or\n generated `ON UPDATE CASCADE`; UUID fields, indexes, relationship loading,\n and application-side delete enforcement remain active on every engine.\n- **Metadata stored as JSON string** with get/set/update helpers\n- **Owned asset helpers**: use `Event.getAssets()` / `addAsset()` / `removeAsset()` or the matching `EventCollection` wrappers instead of generic `AssetAssociation`\n"
|
|
5023
|
+
"agentDoc": "# @happyvertical/smrt-events\n\nInfinite-nesting event hierarchy with series, types, participants, and role/placement management.\n\n## Models\n\n- **Event** (STI, extends `SmrtHierarchical`): self-referencing parent-child via `parentId` (UUID). Links to `seriesId`, `typeId`, `placeId`. Status: scheduled/in_progress/completed/cancelled/postponed. Hierarchy traversal (`getParent()`, `getChildren()`, `getAncestors()`, `getDescendants()`, `getHierarchy()`, `moveTo()`) is provided by `SmrtHierarchical`; `getRootEvent()` and `isRoot()` remain on `Event`.\n- **EventAsset**: dedicated owned-asset join in `event_assets` with `relationship` and `sortOrder`.\n- **EventType**: classification with JSON schema for custom fields per type.\n- **Event.allDay / Event.timeZone**: whole-day flag (`endDate` is the exclusive midnight after the last day) and IANA zone (empty = inherit). Manifest fields; consumers migrate with `db:migrate`.\n- **EventSeries**: recurrence patterns (daily/weekly/monthly/yearly). `expandRecurrence()` (`src/recurrence.ts`) / `EventSeries.getOccurrences()` expand them into instants, keeping the start's wall-clock time in the zone. Do all date math on calendar dates and convert through `Intl` at the end — never `Date#setDate`/`getDay` on host-local time (tests pin `TZ=UTC`, so host leaks only show in production).\n- **EventParticipant**: junction with `role` (home/away/speaker/panelist/etc.), `placement` (numeric — team ordering and rankings), `groupId` (team grouping within event). `conflictColumns: ['event_id', 'profile_id', 'role']`.\n\n## Gotchas\n\n- **No depth limit** on event hierarchy — deep nesting can cause N+1 queries\n- **Placement is numeric**: used for both team ordering (0=home, 1=away) and rankings — context-dependent\n- **GroupId not enforced at DB level**: for logical grouping only (e.g., team members in a game)\n- **Optional tenancy** with nullable tenantId\n- **Event physical foreign keys**: `parentId`, `seriesId`, and `typeId` retain\n PostgreSQL/SQLite constraints. DuckDB/JSON omit only those explicitly scoped\n physical constraints because DuckDB cannot enforce Event's self-reference or\n generated `ON UPDATE CASCADE`; UUID fields, indexes, relationship loading,\n and application-side delete enforcement remain active on every engine.\n- **Metadata stored as JSON string** with get/set/update helpers\n- **Owned asset helpers**: use `Event.getAssets()` / `addAsset()` / `removeAsset()` or the matching `EventCollection` wrappers instead of generic `AssetAssociation`\n"
|
|
4982
5024
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export interface RecurrencePattern {
|
|
|
26
26
|
byMonthDay?: number[];
|
|
27
27
|
byMonth?: number[];
|
|
28
28
|
bySetPos?: number[];
|
|
29
|
+
/** IANA zone the pattern repeats in (RRULE `DTSTART;TZID`); expansion falls back to it. */
|
|
30
|
+
timeZone?: string;
|
|
29
31
|
}
|
|
30
32
|
/**
|
|
31
33
|
* Options for creating EventType
|
|
@@ -73,6 +75,10 @@ export interface EventOptions extends SmrtObjectOptions {
|
|
|
73
75
|
description?: string;
|
|
74
76
|
startDate?: Date | null;
|
|
75
77
|
endDate?: Date | null;
|
|
78
|
+
/** Whole-day event; `endDate` is the exclusive end (midnight after the last day). */
|
|
79
|
+
allDay?: boolean;
|
|
80
|
+
/** IANA time zone (e.g. `America/Edmonton`); empty inherits from series/place/site. */
|
|
81
|
+
timeZone?: string;
|
|
76
82
|
status?: EventStatus;
|
|
77
83
|
round?: number | null;
|
|
78
84
|
metadata?: Record<string, unknown> | string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,aAAa,GACb,WAAW,GACX,WAAW,GACX,WAAW,CAAC;AAEhB;;GAEG;AACH,MAAM,MAAM,eAAe,GAEvB,MAAM,GACN,MAAM,GACN,YAAY,GAEZ,WAAW,GACX,QAAQ,GACR,WAAW,GAEX,SAAS,GACT,UAAU,GACV,WAAW,GACX,WAAW,GAEX,WAAW,GACX,UAAU,GACV,WAAW,GACX,MAAM,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,mBAAmB,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Utility functions for @have/events package
|
|
3
3
|
*/
|
|
4
4
|
import type { EventStatus, RecurrencePattern } from './types';
|
|
5
|
+
export type { CivilDate, ExpandRecurrenceOptions, ZonedWallTime, } from './recurrence';
|
|
6
|
+
export { expandRecurrence, fromZonedWallTime, isValidTimeZone, toZonedWallTime, } from './recurrence';
|
|
5
7
|
/**
|
|
6
8
|
* Validate event status transition
|
|
7
9
|
*
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE9D;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,WAAW,EAC1B,SAAS,EAAE,WAAW,GACrB,OAAO,CAWT;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,IAAI,EACf,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GACpB,MAAM,CAcR;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CASlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,IAAI,EACjB,SAAS,EAAE,IAAI,GAAG,IAAI,EACtB,WAAW,EAAE,IAAI,EACjB,SAAS,EAAE,IAAI,GAAG,IAAI,GACrB,OAAO,CAOT;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,GACzC,iBAAiB,GAAG,IAAI,CAY1B;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,IAAI,GACb,IAAI,GAAG,IAAI,CA8Bb;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAG,MAAM,CAExE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAgBzD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAO1E;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,IAAI,EACf,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,EACrB,aAAa,CAAC,EAAE,WAAW,GAC1B,WAAW,CAiBb;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS;IAAE,SAAS,EAAE,IAAI,GAAG,IAAI,CAAA;CAAE,EACnE,MAAM,EAAE,CAAC,EAAE,EACX,SAAS,GAAE,OAAc,GACxB,CAAC,EAAE,CASL"}
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE9D,YAAY,EACV,SAAS,EACT,uBAAuB,EACvB,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,eAAe,GAChB,MAAM,cAAc,CAAC;AAEtB;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,WAAW,EAC1B,SAAS,EAAE,WAAW,GACrB,OAAO,CAWT;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,IAAI,EACf,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GACpB,MAAM,CAcR;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CASlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,IAAI,EACjB,SAAS,EAAE,IAAI,GAAG,IAAI,EACtB,WAAW,EAAE,IAAI,EACjB,SAAS,EAAE,IAAI,GAAG,IAAI,GACrB,OAAO,CAOT;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,GACzC,iBAAiB,GAAG,IAAI,CAY1B;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,IAAI,GACb,IAAI,GAAG,IAAI,CA8Bb;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAG,MAAM,CAExE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAgBzD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAO1E;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,IAAI,EACf,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,EACrB,aAAa,CAAC,EAAE,WAAW,GAC1B,WAAW,CAiBb;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS;IAAE,SAAS,EAAE,IAAI,GAAG,IAAI,CAAA;CAAE,EACnE,MAAM,EAAE,CAAC,EAAE,EACX,SAAS,GAAE,OAAc,GACxB,CAAC,EAAE,CASL"}
|
package/dist/utils.js
CHANGED
|
@@ -1,96 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return {
|
|
4
|
-
scheduled: [
|
|
5
|
-
"in_progress",
|
|
6
|
-
"cancelled",
|
|
7
|
-
"postponed"
|
|
8
|
-
],
|
|
9
|
-
in_progress: ["completed", "cancelled"],
|
|
10
|
-
completed: [],
|
|
11
|
-
cancelled: ["scheduled"],
|
|
12
|
-
postponed: ["scheduled", "cancelled"]
|
|
13
|
-
}[currentStatus]?.includes(newStatus) || false;
|
|
14
|
-
}
|
|
15
|
-
function formatEventDateRange(startDate, endDate) {
|
|
16
|
-
const start = startDate.toLocaleDateString();
|
|
17
|
-
if (!endDate) return start;
|
|
18
|
-
if (startDate.toDateString() === endDate.toDateString()) return `${start} ${startDate.toLocaleTimeString()} - ${endDate.toLocaleTimeString()}`;
|
|
19
|
-
return `${start} - ${endDate.toLocaleDateString()}`;
|
|
20
|
-
}
|
|
21
|
-
function generateEventSlug(name, date) {
|
|
22
|
-
return `${name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")}-${date.toISOString().split("T")[0]}`;
|
|
23
|
-
}
|
|
24
|
-
function checkSchedulingConflict(event1Start, event1End, event2Start, event2End) {
|
|
25
|
-
return event1Start < (event2End || event2Start) && (event1End || event1Start) > event2Start;
|
|
26
|
-
}
|
|
27
|
-
function parseRecurrencePattern(pattern) {
|
|
28
|
-
if (!pattern) return null;
|
|
29
|
-
if (typeof pattern === "string") try {
|
|
30
|
-
return JSON.parse(pattern);
|
|
31
|
-
} catch {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
return pattern;
|
|
35
|
-
}
|
|
36
|
-
function calculateNextOccurrence(pattern, fromDate) {
|
|
37
|
-
const { frequency, interval = 1, until, count } = pattern;
|
|
38
|
-
if (until && fromDate >= until) return null;
|
|
39
|
-
const nextDate = new Date(fromDate);
|
|
40
|
-
switch (frequency) {
|
|
41
|
-
case "daily":
|
|
42
|
-
nextDate.setDate(nextDate.getDate() + interval);
|
|
43
|
-
break;
|
|
44
|
-
case "weekly":
|
|
45
|
-
nextDate.setDate(nextDate.getDate() + interval * 7);
|
|
46
|
-
break;
|
|
47
|
-
case "monthly":
|
|
48
|
-
nextDate.setMonth(nextDate.getMonth() + interval);
|
|
49
|
-
break;
|
|
50
|
-
case "yearly":
|
|
51
|
-
nextDate.setFullYear(nextDate.getFullYear() + interval);
|
|
52
|
-
break;
|
|
53
|
-
default: return null;
|
|
54
|
-
}
|
|
55
|
-
if (until && nextDate > until) return null;
|
|
56
|
-
return nextDate;
|
|
57
|
-
}
|
|
58
|
-
function calculateDuration(startDate, endDate) {
|
|
59
|
-
return endDate.getTime() - startDate.getTime();
|
|
60
|
-
}
|
|
61
|
-
function formatDuration(durationMs) {
|
|
62
|
-
const seconds = Math.floor(durationMs / 1e3);
|
|
63
|
-
const minutes = Math.floor(seconds / 60);
|
|
64
|
-
const hours = Math.floor(minutes / 60);
|
|
65
|
-
const days = Math.floor(hours / 24);
|
|
66
|
-
if (days > 0) return `${days}d ${hours % 24}h`;
|
|
67
|
-
if (hours > 0) return `${hours}h ${minutes % 60}m`;
|
|
68
|
-
if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
|
|
69
|
-
return `${seconds}s`;
|
|
70
|
-
}
|
|
71
|
-
function isEventNow(startDate, endDate) {
|
|
72
|
-
const now = /* @__PURE__ */ new Date();
|
|
73
|
-
if (now < startDate) return false;
|
|
74
|
-
if (endDate && now > endDate) return false;
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
function getEventStatusFromDates(startDate, endDate, currentStatus) {
|
|
78
|
-
if (currentStatus === "cancelled" || currentStatus === "postponed") return currentStatus;
|
|
79
|
-
const now = /* @__PURE__ */ new Date();
|
|
80
|
-
if (now < startDate) return "scheduled";
|
|
81
|
-
if (endDate && now > endDate) return "completed";
|
|
82
|
-
return "in_progress";
|
|
83
|
-
}
|
|
84
|
-
function sortEventsByDate(events, ascending = true) {
|
|
85
|
-
return events.sort((a, b) => {
|
|
86
|
-
if (!a.startDate && !b.startDate) return 0;
|
|
87
|
-
if (!a.startDate) return 1;
|
|
88
|
-
if (!b.startDate) return -1;
|
|
89
|
-
const diff = a.startDate.getTime() - b.startDate.getTime();
|
|
90
|
-
return ascending ? diff : -diff;
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
//#endregion
|
|
94
|
-
export { calculateDuration, calculateNextOccurrence, checkSchedulingConflict, formatDuration, formatEventDateRange, generateEventSlug, getEventStatusFromDates, isEventNow, parseRecurrencePattern, sortEventsByDate, validateEventStatus };
|
|
95
|
-
|
|
96
|
-
//# sourceMappingURL=utils.js.map
|
|
1
|
+
import { a as formatEventDateRange, c as isEventNow, d as validateEventStatus, f as expandRecurrence, h as toZonedWallTime, i as formatDuration, l as parseRecurrencePattern, m as isValidTimeZone, n as calculateNextOccurrence, o as generateEventSlug, p as fromZonedWallTime, r as checkSchedulingConflict, s as getEventStatusFromDates, t as calculateDuration, u as sortEventsByDate } from "./chunks/utils-DV00CoDY.js";
|
|
2
|
+
export { calculateDuration, calculateNextOccurrence, checkSchedulingConflict, expandRecurrence, formatDuration, formatEventDateRange, fromZonedWallTime, generateEventSlug, getEventStatusFromDates, isEventNow, isValidTimeZone, parseRecurrencePattern, sortEventsByDate, toZonedWallTime, validateEventStatus };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-events",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0",
|
|
4
4
|
"smrtJsdoc": "strict",
|
|
5
5
|
"description": "Hierarchical event management with participant tracking and SMRT framework support",
|
|
6
6
|
"type": "module",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"svelte": "^5.57.
|
|
40
|
+
"svelte": "^5.57.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependenciesMeta": {
|
|
43
43
|
"svelte": {
|
|
@@ -45,21 +45,21 @@
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@happyvertical/ai": "^0.
|
|
49
|
-
"@happyvertical/files": "^0.
|
|
50
|
-
"@happyvertical/logger": "^0.
|
|
51
|
-
"@happyvertical/smrt-assets": "0.
|
|
52
|
-
"@happyvertical/smrt-core": "0.
|
|
53
|
-
"@happyvertical/smrt-places": "0.
|
|
54
|
-
"@happyvertical/smrt-profiles": "0.
|
|
55
|
-
"@happyvertical/smrt-tenancy": "0.
|
|
56
|
-
"@happyvertical/smrt-types": "0.
|
|
57
|
-
"@happyvertical/smrt-ui": "0.
|
|
58
|
-
"@happyvertical/sql": "^0.
|
|
59
|
-
"@happyvertical/utils": "^0.
|
|
48
|
+
"@happyvertical/ai": "^0.98.0",
|
|
49
|
+
"@happyvertical/files": "^0.98.0",
|
|
50
|
+
"@happyvertical/logger": "^0.98.0",
|
|
51
|
+
"@happyvertical/smrt-assets": "0.53.0",
|
|
52
|
+
"@happyvertical/smrt-core": "0.53.0",
|
|
53
|
+
"@happyvertical/smrt-places": "0.53.0",
|
|
54
|
+
"@happyvertical/smrt-profiles": "0.53.0",
|
|
55
|
+
"@happyvertical/smrt-tenancy": "0.53.0",
|
|
56
|
+
"@happyvertical/smrt-types": "0.53.0",
|
|
57
|
+
"@happyvertical/smrt-ui": "0.53.0",
|
|
58
|
+
"@happyvertical/sql": "^0.98.0",
|
|
59
|
+
"@happyvertical/utils": "^0.98.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@happyvertical/smrt-vitest": "0.
|
|
62
|
+
"@happyvertical/smrt-vitest": "0.53.0",
|
|
63
63
|
"@sveltejs/package": "^2.5.8",
|
|
64
64
|
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
65
65
|
"@types/node": "24.13.6",
|
package/dist/utils.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["/**\n * Utility functions for @have/events package\n */\n\nimport type { EventStatus, RecurrencePattern } from './types';\n\n/**\n * Validate event status transition\n *\n * @param currentStatus - Current event status\n * @param newStatus - Proposed new status\n * @returns True if transition is valid\n */\nexport function validateEventStatus(\n currentStatus: EventStatus,\n newStatus: EventStatus,\n): boolean {\n // Define valid transitions\n const validTransitions: Record<EventStatus, EventStatus[]> = {\n scheduled: ['in_progress', 'cancelled', 'postponed'],\n in_progress: ['completed', 'cancelled'],\n completed: [], // Cannot transition from completed\n cancelled: ['scheduled'], // Can reschedule\n postponed: ['scheduled', 'cancelled'],\n };\n\n return validTransitions[currentStatus]?.includes(newStatus) || false;\n}\n\n/**\n * Format event date range as string\n *\n * @param startDate - Event start date\n * @param endDate - Event end date (optional)\n * @returns Formatted date range string\n */\nexport function formatEventDateRange(\n startDate: Date,\n endDate?: Date | null,\n): string {\n const start = startDate.toLocaleDateString();\n\n if (!endDate) {\n return start;\n }\n\n // Same day\n if (startDate.toDateString() === endDate.toDateString()) {\n return `${start} ${startDate.toLocaleTimeString()} - ${endDate.toLocaleTimeString()}`;\n }\n\n // Multi-day\n return `${start} - ${endDate.toLocaleDateString()}`;\n}\n\n/**\n * Generate unique slug for an event\n *\n * @param name - Event name\n * @param date - Event date\n * @returns URL-friendly slug\n */\nexport function generateEventSlug(name: string, date: Date): string {\n const namePart = name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n\n const datePart = date.toISOString().split('T')[0]; // YYYY-MM-DD\n\n return `${namePart}-${datePart}`;\n}\n\n/**\n * Check if events have scheduling conflict\n *\n * @param event1Start - First event start\n * @param event1End - First event end\n * @param event2Start - Second event start\n * @param event2End - Second event end\n * @returns True if events overlap\n */\nexport function checkSchedulingConflict(\n event1Start: Date,\n event1End: Date | null,\n event2Start: Date,\n event2End: Date | null,\n): boolean {\n // If either event has no end date, assume it's instantaneous\n const e1End = event1End || event1Start;\n const e2End = event2End || event2Start;\n\n // Check for overlap\n return event1Start < e2End && e1End > event2Start;\n}\n\n/**\n * Parse recurrence pattern from various formats\n *\n * @param pattern - Recurrence pattern (object or string)\n * @returns Parsed RecurrencePattern or null\n */\nexport function parseRecurrencePattern(\n pattern: RecurrencePattern | string | null,\n): RecurrencePattern | null {\n if (!pattern) return null;\n\n if (typeof pattern === 'string') {\n try {\n return JSON.parse(pattern) as RecurrencePattern;\n } catch {\n return null;\n }\n }\n\n return pattern;\n}\n\n/**\n * Calculate next occurrence for a recurring event\n *\n * @param pattern - Recurrence pattern\n * @param fromDate - Date to calculate from\n * @returns Next occurrence date or null\n */\nexport function calculateNextOccurrence(\n pattern: RecurrencePattern,\n fromDate: Date,\n): Date | null {\n const { frequency, interval = 1, until, count } = pattern;\n\n // Check if recurrence has ended\n if (until && fromDate >= until) return null;\n\n // Calculate next date based on frequency\n const nextDate = new Date(fromDate);\n\n switch (frequency) {\n case 'daily':\n nextDate.setDate(nextDate.getDate() + interval);\n break;\n case 'weekly':\n nextDate.setDate(nextDate.getDate() + interval * 7);\n break;\n case 'monthly':\n nextDate.setMonth(nextDate.getMonth() + interval);\n break;\n case 'yearly':\n nextDate.setFullYear(nextDate.getFullYear() + interval);\n break;\n default:\n return null;\n }\n\n // Check if we've exceeded until date\n if (until && nextDate > until) return null;\n\n return nextDate;\n}\n\n/**\n * Calculate duration between two dates\n *\n * @param startDate - Start date\n * @param endDate - End date\n * @returns Duration in milliseconds\n */\nexport function calculateDuration(startDate: Date, endDate: Date): number {\n return endDate.getTime() - startDate.getTime();\n}\n\n/**\n * Format duration as human-readable string\n *\n * @param durationMs - Duration in milliseconds\n * @returns Formatted duration string\n */\nexport function formatDuration(durationMs: number): string {\n const seconds = Math.floor(durationMs / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days}d ${hours % 24}h`;\n }\n if (hours > 0) {\n return `${hours}h ${minutes % 60}m`;\n }\n if (minutes > 0) {\n return `${minutes}m ${seconds % 60}s`;\n }\n return `${seconds}s`;\n}\n\n/**\n * Check if an event is happening now\n *\n * @param startDate - Event start date\n * @param endDate - Event end date (optional)\n * @returns True if event is currently in progress\n */\nexport function isEventNow(startDate: Date, endDate?: Date | null): boolean {\n const now = new Date();\n\n if (now < startDate) return false;\n if (endDate && now > endDate) return false;\n\n return true;\n}\n\n/**\n * Get event status based on dates\n *\n * @param startDate - Event start date\n * @param endDate - Event end date (optional)\n * @param currentStatus - Current status (optional)\n * @returns Suggested event status\n */\nexport function getEventStatusFromDates(\n startDate: Date,\n endDate?: Date | null,\n currentStatus?: EventStatus,\n): EventStatus {\n // Don't override cancelled or postponed status\n if (currentStatus === 'cancelled' || currentStatus === 'postponed') {\n return currentStatus;\n }\n\n const now = new Date();\n\n if (now < startDate) {\n return 'scheduled';\n }\n\n if (endDate && now > endDate) {\n return 'completed';\n }\n\n return 'in_progress';\n}\n\n/**\n * Sort events by start date\n *\n * @param events - Array of objects with startDate property\n * @param ascending - Sort ascending (default: true)\n * @returns Sorted array\n */\nexport function sortEventsByDate<T extends { startDate: Date | null }>(\n events: T[],\n ascending: boolean = true,\n): T[] {\n return events.sort((a, b) => {\n if (!a.startDate && !b.startDate) return 0;\n if (!a.startDate) return 1;\n if (!b.startDate) return -1;\n\n const diff = a.startDate.getTime() - b.startDate.getTime();\n return ascending ? diff : -diff;\n });\n}\n"],"mappings":"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"}
|