@mj-biz-apps/common-entities 5.42.0 → 5.43.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.
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Calendar days, and the business zone that decides which one it is today.
3
+ *
4
+ * A SQL `date` column is a calendar day with no time and no zone. The driver hands it back as a Date
5
+ * at UTC midnight, so its UTC parts are the stored day and its local parts are the previous day for
6
+ * anyone west of Greenwich. Reading and writing a stored day therefore never involves a zone.
7
+ *
8
+ * "Today" is the one thing that does. `new Date().toISOString().slice(0, 10)` is the UTC day, which is
9
+ * already tomorrow for the whole American evening; the browser's local day is wherever the user sits,
10
+ * not where the business books. These helpers take the zone explicitly; `BusinessTimeZoneEngine`
11
+ * supplies it from the instance configuration.
12
+ *
13
+ * No library. `Intl.DateTimeFormat` with a `timeZone` option is what every supported runtime ships,
14
+ * and the two things needed from it — the wall-clock parts at an instant, and the offset between wall
15
+ * clock and instant — are enough to go both ways.
16
+ */
17
+ export type CalendarDay = string;
18
+ export declare const UTC_ZONE = "UTC";
19
+ /** Whether a value is a real calendar day written as zero-padded `YYYY-MM-DD`. */
20
+ export declare function IsCalendarDay(value: unknown): value is CalendarDay;
21
+ /**
22
+ * The calendar day a stored value names, or null.
23
+ *
24
+ * A Date is read from its UTC parts. A string is taken as written when it begins with a day, never
25
+ * parsed and re-based: `2026-09-30T23:00:00-05:00` is the 30th as stored. Anything else is null rather
26
+ * than `Invalid Date`, which would print literally and destroy the evidence of what was held.
27
+ */
28
+ export declare function ToCalendarDay(value: unknown): CalendarDay | null;
29
+ /** UTC midnight of the day: the shape a `date` column round-trips as, safe to assign to a date field. */
30
+ export declare function FromCalendarDay(day: CalendarDay): Date;
31
+ /** The calendar day it is in `zone` at the given instant. */
32
+ export declare function CalendarDayIn(instant: Date, zone: string): CalendarDay;
33
+ /** Today in `zone`. `now` is a parameter so tests never read the clock. */
34
+ export declare function TodayIn(zone: string, now?: Date): CalendarDay;
35
+ export declare function AddDays(day: CalendarDay, days: number): CalendarDay;
36
+ /** Fixed-width ISO days sort lexically in chronological order, so a string compare is exact. */
37
+ export declare function CompareDays(a: CalendarDay, b: CalendarDay): number;
38
+ export declare function IsBeforeDay(a: CalendarDay, b: CalendarDay): boolean;
39
+ export declare function FirstDayOfMonth(day: CalendarDay): CalendarDay;
40
+ export declare function LastDayOfPriorMonth(day: CalendarDay): CalendarDay;
41
+ /**
42
+ * The instant a calendar day begins in `zone`.
43
+ *
44
+ * Two passes converge on local midnight for the ordinary case and for a day whose midnight sits on
45
+ * the other side of a transition that happens later in the day. A zone whose clocks change AT
46
+ * midnight is the case they cannot settle: spring-forward means the day has no 00:00 at all
47
+ * (America/Santiago, 2026-09-06) and fall-back means it has two. So the candidates are checked
48
+ * against the day they actually land on, and the EARLIEST one that is really on that day wins —
49
+ * the first instant the day exists, and the first of two midnights where there are two.
50
+ */
51
+ export declare function DayStartUtc(day: CalendarDay, zone: string): Date;
52
+ /** The last millisecond of a calendar day in `zone`: an end date covers its whole day. */
53
+ export declare function DayEndUtc(day: CalendarDay, zone: string): Date;
54
+ /** Whether the runtime knows the zone. `Intl` throws a RangeError for a name it cannot resolve. */
55
+ export declare function IsKnownTimeZone(zone: string): boolean;
56
+ //# sourceMappingURL=business-day.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"business-day.d.ts","sourceRoot":"","sources":["../src/business-day.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AAEjC,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAgD9B,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAMlE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAWhE;AAED,yGAAyG;AACzG,wBAAgB,eAAe,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAKtD;AAED,6DAA6D;AAC7D,wBAAgB,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAGtE;AAED,2EAA2E;AAC3E,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,IAAiB,GAAG,WAAW,CAEzE;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAMnE;AAED,gGAAgG;AAChG,wBAAgB,WAAW,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,MAAM,CAElE;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO,CAEnE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,WAAW,GAAG,WAAW,CAE7D;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,WAAW,CAEjE;AASD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAWhE;AAED,0FAA0F;AAC1F,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED,mGAAmG;AACnG,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAQrD"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Calendar days, and the business zone that decides which one it is today.
3
+ *
4
+ * A SQL `date` column is a calendar day with no time and no zone. The driver hands it back as a Date
5
+ * at UTC midnight, so its UTC parts are the stored day and its local parts are the previous day for
6
+ * anyone west of Greenwich. Reading and writing a stored day therefore never involves a zone.
7
+ *
8
+ * "Today" is the one thing that does. `new Date().toISOString().slice(0, 10)` is the UTC day, which is
9
+ * already tomorrow for the whole American evening; the browser's local day is wherever the user sits,
10
+ * not where the business books. These helpers take the zone explicitly; `BusinessTimeZoneEngine`
11
+ * supplies it from the instance configuration.
12
+ *
13
+ * No library. `Intl.DateTimeFormat` with a `timeZone` option is what every supported runtime ships,
14
+ * and the two things needed from it — the wall-clock parts at an instant, and the offset between wall
15
+ * clock and instant — are enough to go both ways.
16
+ */
17
+ export const UTC_ZONE = 'UTC';
18
+ const CALENDAR_DAY = /^\d{4}-\d{2}-\d{2}$/;
19
+ const LEADING_DAY = /^\d{4}-\d{2}-\d{2}/;
20
+ const formatters = new Map();
21
+ function formatterFor(zone) {
22
+ let formatter = formatters.get(zone);
23
+ if (!formatter) {
24
+ formatter = new Intl.DateTimeFormat('en-US', {
25
+ timeZone: zone,
26
+ hourCycle: 'h23',
27
+ year: 'numeric',
28
+ month: '2-digit',
29
+ day: '2-digit',
30
+ hour: '2-digit',
31
+ minute: '2-digit',
32
+ second: '2-digit',
33
+ });
34
+ formatters.set(zone, formatter);
35
+ }
36
+ return formatter;
37
+ }
38
+ function wallClock(instant, zone) {
39
+ const parts = formatterFor(zone).formatToParts(instant);
40
+ const read = (type) => Number(parts.find((p) => p.type === type)?.value ?? '0');
41
+ return { year: read('year'), month: read('month'), day: read('day'), hour: read('hour'), minute: read('minute'), second: read('second') };
42
+ }
43
+ function pad(value, width) {
44
+ return String(value).padStart(width, '0');
45
+ }
46
+ function dayOf(year, month, day) {
47
+ return `${pad(year, 4)}-${pad(month, 2)}-${pad(day, 2)}`;
48
+ }
49
+ /** Whether a value is a real calendar day written as zero-padded `YYYY-MM-DD`. */
50
+ export function IsCalendarDay(value) {
51
+ if (typeof value !== 'string' || !CALENDAR_DAY.test(value))
52
+ return false;
53
+ // The regex is shape only: '2026-02-30' and '2026-99-99' pass it. A date that survives the
54
+ // round trip through UTC parts is a day that exists.
55
+ const parsed = new Date(`${value}T00:00:00.000Z`);
56
+ return !Number.isNaN(parsed.getTime()) && parsed.toISOString().slice(0, 10) === value;
57
+ }
58
+ /**
59
+ * The calendar day a stored value names, or null.
60
+ *
61
+ * A Date is read from its UTC parts. A string is taken as written when it begins with a day, never
62
+ * parsed and re-based: `2026-09-30T23:00:00-05:00` is the 30th as stored. Anything else is null rather
63
+ * than `Invalid Date`, which would print literally and destroy the evidence of what was held.
64
+ */
65
+ export function ToCalendarDay(value) {
66
+ if (value === null || value === undefined || value === '')
67
+ return null;
68
+ if (value instanceof Date) {
69
+ if (Number.isNaN(value.getTime()))
70
+ return null;
71
+ return dayOf(value.getUTCFullYear(), value.getUTCMonth() + 1, value.getUTCDate());
72
+ }
73
+ if (typeof value === 'string') {
74
+ const candidate = LEADING_DAY.test(value) ? value.slice(0, 10) : null;
75
+ return candidate !== null && IsCalendarDay(candidate) ? candidate : null;
76
+ }
77
+ return null;
78
+ }
79
+ /** UTC midnight of the day: the shape a `date` column round-trips as, safe to assign to a date field. */
80
+ export function FromCalendarDay(day) {
81
+ if (!IsCalendarDay(day)) {
82
+ throw new RangeError(`Not a calendar day: ${day}`);
83
+ }
84
+ return new Date(`${day}T00:00:00.000Z`);
85
+ }
86
+ /** The calendar day it is in `zone` at the given instant. */
87
+ export function CalendarDayIn(instant, zone) {
88
+ const clock = wallClock(instant, zone);
89
+ return dayOf(clock.year, clock.month, clock.day);
90
+ }
91
+ /** Today in `zone`. `now` is a parameter so tests never read the clock. */
92
+ export function TodayIn(zone, now = new Date()) {
93
+ return CalendarDayIn(now, zone);
94
+ }
95
+ export function AddDays(day, days) {
96
+ const start = FromCalendarDay(day);
97
+ start.setUTCDate(start.getUTCDate() + days);
98
+ const moved = ToCalendarDay(start);
99
+ if (moved === null)
100
+ throw new RangeError(`Not a calendar day: ${day}`);
101
+ return moved;
102
+ }
103
+ /** Fixed-width ISO days sort lexically in chronological order, so a string compare is exact. */
104
+ export function CompareDays(a, b) {
105
+ return a < b ? -1 : a > b ? 1 : 0;
106
+ }
107
+ export function IsBeforeDay(a, b) {
108
+ return CompareDays(a, b) < 0;
109
+ }
110
+ export function FirstDayOfMonth(day) {
111
+ return `${day.slice(0, 7)}-01`;
112
+ }
113
+ export function LastDayOfPriorMonth(day) {
114
+ return AddDays(FirstDayOfMonth(day), -1);
115
+ }
116
+ /** Wall clock in `zone` at `instant`, expressed as if it were UTC, minus the instant: the zone's offset. */
117
+ function offsetMs(instant, zone) {
118
+ const clock = wallClock(instant, zone);
119
+ const asUtc = Date.UTC(clock.year, clock.month - 1, clock.day, clock.hour, clock.minute, clock.second);
120
+ return asUtc - Math.floor(instant.getTime() / 1000) * 1000;
121
+ }
122
+ /**
123
+ * The instant a calendar day begins in `zone`.
124
+ *
125
+ * Two passes converge on local midnight for the ordinary case and for a day whose midnight sits on
126
+ * the other side of a transition that happens later in the day. A zone whose clocks change AT
127
+ * midnight is the case they cannot settle: spring-forward means the day has no 00:00 at all
128
+ * (America/Santiago, 2026-09-06) and fall-back means it has two. So the candidates are checked
129
+ * against the day they actually land on, and the EARLIEST one that is really on that day wins —
130
+ * the first instant the day exists, and the first of two midnights where there are two.
131
+ */
132
+ export function DayStartUtc(day, zone) {
133
+ const guess = FromCalendarDay(day).getTime();
134
+ const first = guess - offsetMs(new Date(guess), zone);
135
+ const second = guess - offsetMs(new Date(first), zone);
136
+ const candidates = first === second ? [first] : [Math.min(first, second), Math.max(first, second)];
137
+ for (const candidate of candidates) {
138
+ if (CalendarDayIn(new Date(candidate), zone) === day) {
139
+ return new Date(candidate);
140
+ }
141
+ }
142
+ return new Date(first);
143
+ }
144
+ /** The last millisecond of a calendar day in `zone`: an end date covers its whole day. */
145
+ export function DayEndUtc(day, zone) {
146
+ return new Date(DayStartUtc(AddDays(day, 1), zone).getTime() - 1);
147
+ }
148
+ /** Whether the runtime knows the zone. `Intl` throws a RangeError for a name it cannot resolve. */
149
+ export function IsKnownTimeZone(zone) {
150
+ if (!zone)
151
+ return false;
152
+ try {
153
+ formatterFor(zone);
154
+ return true;
155
+ }
156
+ catch {
157
+ return false;
158
+ }
159
+ }
160
+ //# sourceMappingURL=business-day.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"business-day.js","sourceRoot":"","sources":["../src/business-day.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The business time zone: one instance-wide setting, cached, read on client and server.
3
+ *
4
+ * Stored as one `MJ: Instance Configurations` row whose JSON value carries the IANA name code uses
5
+ * (`Intl` knows only those) and the Windows name SQL Server's `AT TIME ZONE` accepts (it knows only
6
+ * those). bizapps-common defines the row; the host sets its value. MJ 6.2 is asked to define its
7
+ * own key, `Business.TimeZone`, with the same two-name shape (MemberJunction/MJ#4541); when that
8
+ * row exists it wins, so nothing here changes when the framework catches up — provided the shape
9
+ * matches, which is why that issue pins it.
10
+ *
11
+ * Fail open to UTC. A missing row, a blank value, unreadable JSON, an unknown zone, or a user
12
+ * without read permission on the configuration entity all resolve to UTC, with one warning per
13
+ * process, because a date default that throws is worse than a date default in the wrong zone.
14
+ */
15
+ import { BaseEngine, IMetadataProvider, UserInfo } from '@memberjunction/core';
16
+ import { CalendarDay } from './business-day.js';
17
+ export declare const BUSINESS_TIME_ZONE_KEYS: readonly ["Business.TimeZone", "BizApps.BusinessTimeZone"];
18
+ export type BusinessTimeZoneKey = (typeof BUSINESS_TIME_ZONE_KEYS)[number];
19
+ export declare const BUSINESS_TIME_ZONE_ENTITY = "MJ: Instance Configurations";
20
+ export interface InstanceConfigurationRow {
21
+ FeatureKey: string;
22
+ Value: string | null;
23
+ DefaultValue: string | null;
24
+ }
25
+ export interface BusinessTimeZoneSetting {
26
+ Iana: string;
27
+ Sql: string;
28
+ Source: BusinessTimeZoneKey | 'fallback';
29
+ Warning?: string;
30
+ }
31
+ /** The setting the rows describe, in key precedence order, or the UTC fallback. Pure, for tests. */
32
+ export declare function ResolveBusinessTimeZoneSetting(rows: ReadonlyArray<InstanceConfigurationRow>): BusinessTimeZoneSetting;
33
+ export declare class BusinessTimeZoneEngine extends BaseEngine<BusinessTimeZoneEngine> {
34
+ private _configurations;
35
+ private warned;
36
+ static get Instance(): BusinessTimeZoneEngine;
37
+ Config(forceRefresh?: boolean, contextUser?: UserInfo, provider?: IMetadataProvider): Promise<unknown>;
38
+ /** The resolved setting; UTC before load, on any unreadable row, or without read permission. */
39
+ get Setting(): BusinessTimeZoneSetting;
40
+ /** IANA zone name for code. */
41
+ get Zone(): string;
42
+ /** Windows zone name for SQL Server's AT TIME ZONE. */
43
+ get SqlZone(): string;
44
+ /**
45
+ * The zone for a record. `companyID` is accepted from day one and ignored until MJ carries a
46
+ * TimeZone column on Companies (MemberJunction/MJ#4541); call sites do not change when it
47
+ * arrives.
48
+ */
49
+ Resolve(companyID?: string): string;
50
+ Today(companyID?: string): CalendarDay;
51
+ TodayAsDate(companyID?: string): Date;
52
+ private warnOnce;
53
+ }
54
+ //# sourceMappingURL=business-time-zone-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"business-time-zone-engine.d.ts","sourceRoot":"","sources":["../src/business-time-zone-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACH,UAAU,EAEV,iBAAiB,EAGjB,QAAQ,EACX,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAuD,MAAM,mBAAmB,CAAC;AAErG,eAAO,MAAM,uBAAuB,4DAA6D,CAAC;AAElG,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3E,eAAO,MAAM,yBAAyB,gCAAgC,CAAC;AAEvE,MAAM,WAAW,wBAAwB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,mBAAmB,GAAG,UAAU,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAqCD,oGAAoG;AACpG,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,aAAa,CAAC,wBAAwB,CAAC,GAAG,uBAAuB,CASrH;AAED,qBACa,sBAAuB,SAAQ,UAAU,CAAC,sBAAsB,CAAC;IAC1E,OAAO,CAAC,eAAe,CAAkC;IACzD,OAAO,CAAC,MAAM,CAAqB;IAEnC,WAAkB,QAAQ,IAAI,sBAAsB,CAEnD;IAEY,MAAM,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAanH,gGAAgG;IAChG,IAAW,OAAO,IAAI,uBAAuB,CAa5C;IAED,+BAA+B;IAC/B,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,uDAAuD;IACvD,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED;;;;OAIG;IACI,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAKnC,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW;IAItC,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAI5C,OAAO,CAAC,QAAQ;CAOnB"}
@@ -0,0 +1,140 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ /**
8
+ * The business time zone: one instance-wide setting, cached, read on client and server.
9
+ *
10
+ * Stored as one `MJ: Instance Configurations` row whose JSON value carries the IANA name code uses
11
+ * (`Intl` knows only those) and the Windows name SQL Server's `AT TIME ZONE` accepts (it knows only
12
+ * those). bizapps-common defines the row; the host sets its value. MJ 6.2 is asked to define its
13
+ * own key, `Business.TimeZone`, with the same two-name shape (MemberJunction/MJ#4541); when that
14
+ * row exists it wins, so nothing here changes when the framework catches up — provided the shape
15
+ * matches, which is why that issue pins it.
16
+ *
17
+ * Fail open to UTC. A missing row, a blank value, unreadable JSON, an unknown zone, or a user
18
+ * without read permission on the configuration entity all resolve to UTC, with one warning per
19
+ * process, because a date default that throws is worse than a date default in the wrong zone.
20
+ */
21
+ import { BaseEngine, LogStatus, RegisterForStartup, } from '@memberjunction/core';
22
+ import { FromCalendarDay, IsKnownTimeZone, TodayIn, UTC_ZONE } from './business-day.js';
23
+ export const BUSINESS_TIME_ZONE_KEYS = ['Business.TimeZone', 'BizApps.BusinessTimeZone'];
24
+ export const BUSINESS_TIME_ZONE_ENTITY = 'MJ: Instance Configurations';
25
+ const FALLBACK = { Iana: UTC_ZONE, Sql: UTC_ZONE, Source: 'fallback' };
26
+ /** The UTC fallback, carrying why resolution landed there. */
27
+ function fallback(reason) {
28
+ return { Iana: UTC_ZONE, Sql: UTC_ZONE, Source: 'fallback', Warning: reason };
29
+ }
30
+ function parseZone(text) {
31
+ const trimmed = (text ?? '').trim();
32
+ if (trimmed.length === 0)
33
+ return null;
34
+ try {
35
+ const parsed = JSON.parse(trimmed);
36
+ return typeof parsed === 'object' && parsed !== null ? parsed : null;
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ function settingFrom(row, key) {
43
+ const raw = (row.Value ?? '').trim();
44
+ const parsed = raw.length === 0 ? parseZone(row.DefaultValue) : parseZone(raw);
45
+ if (!parsed || typeof parsed.iana !== 'string' || !IsKnownTimeZone(parsed.iana))
46
+ return null;
47
+ // BOTH names or neither. `iana` is what code reads and `sql` is what SQL Server's AT TIME ZONE
48
+ // takes, so a row carrying one of them would have code and views answering different days —
49
+ // and substituting the IANA name for the missing `sql` makes AT TIME ZONE throw, not fall back.
50
+ const sql = typeof parsed.sql === 'string' ? parsed.sql.trim() : '';
51
+ if (sql.length === 0)
52
+ return null;
53
+ return { Iana: parsed.iana, Sql: sql, Source: key };
54
+ }
55
+ /** The setting the rows describe, in key precedence order, or the UTC fallback. Pure, for tests. */
56
+ export function ResolveBusinessTimeZoneSetting(rows) {
57
+ for (const key of BUSINESS_TIME_ZONE_KEYS) {
58
+ const row = rows.find((r) => r.FeatureKey === key);
59
+ if (!row)
60
+ continue;
61
+ // The first key present wins, readable or not; an unreadable preferred row means UTC on
62
+ // every tier rather than a code/view split.
63
+ return settingFrom(row, key) ?? fallback(`row ${key} is unreadable, names an unknown zone, or sets only one of iana/sql; dates fall back to UTC`);
64
+ }
65
+ return fallback('no BizApps.BusinessTimeZone or Business.TimeZone row');
66
+ }
67
+ let BusinessTimeZoneEngine = class BusinessTimeZoneEngine extends BaseEngine {
68
+ constructor() {
69
+ super(...arguments);
70
+ this._configurations = [];
71
+ this.warned = new Set();
72
+ }
73
+ static get Instance() {
74
+ return super.getInstance();
75
+ }
76
+ async Config(forceRefresh, contextUser, provider) {
77
+ const keys = BUSINESS_TIME_ZONE_KEYS.map((k) => `'${k}'`).join(',');
78
+ const params = [
79
+ {
80
+ PropertyName: '_configurations',
81
+ EntityName: BUSINESS_TIME_ZONE_ENTITY,
82
+ Filter: `FeatureKey IN (${keys})`,
83
+ ResultType: 'simple',
84
+ },
85
+ ];
86
+ return await this.Load(params, provider, forceRefresh ?? false, contextUser);
87
+ }
88
+ /** The resolved setting; UTC before load, on any unreadable row, or without read permission. */
89
+ get Setting() {
90
+ if (!this.Loaded) {
91
+ return this.warnOnce('engine not configured — call BusinessTimeZoneEngine.Instance.Config() where you configure your other engines');
92
+ }
93
+ let rows;
94
+ try {
95
+ rows = this.GetConfigData('_configurations');
96
+ }
97
+ catch {
98
+ return this.warnOnce('the current user cannot read MJ: Instance Configurations');
99
+ }
100
+ const setting = ResolveBusinessTimeZoneSetting(rows);
101
+ if (setting.Warning)
102
+ this.warnOnce(setting.Warning);
103
+ return setting;
104
+ }
105
+ /** IANA zone name for code. */
106
+ get Zone() {
107
+ return this.Setting.Iana;
108
+ }
109
+ /** Windows zone name for SQL Server's AT TIME ZONE. */
110
+ get SqlZone() {
111
+ return this.Setting.Sql;
112
+ }
113
+ /**
114
+ * The zone for a record. `companyID` is accepted from day one and ignored until MJ carries a
115
+ * TimeZone column on Companies (MemberJunction/MJ#4541); call sites do not change when it
116
+ * arrives.
117
+ */
118
+ Resolve(companyID) {
119
+ void companyID;
120
+ return this.Zone;
121
+ }
122
+ Today(companyID) {
123
+ return TodayIn(this.Resolve(companyID));
124
+ }
125
+ TodayAsDate(companyID) {
126
+ return FromCalendarDay(this.Today(companyID));
127
+ }
128
+ warnOnce(reason) {
129
+ if (!this.warned.has(reason)) {
130
+ this.warned.add(reason);
131
+ LogStatus(`BusinessTimeZoneEngine: ${reason}; dates default to UTC until it is set.`);
132
+ }
133
+ return FALLBACK;
134
+ }
135
+ };
136
+ BusinessTimeZoneEngine = __decorate([
137
+ RegisterForStartup()
138
+ ], BusinessTimeZoneEngine);
139
+ export { BusinessTimeZoneEngine };
140
+ //# sourceMappingURL=business-time-zone-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"business-time-zone-engine.js","sourceRoot":"","sources":["../src/business-time-zone-engine.ts"],"names":[],"mappings":"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"}
@@ -541,6 +541,7 @@ export declare const mjBizAppsCommonActivitySyncRuleSchema: z.ZodObject<{
541
541
  ActivityType: z.ZodNullable<z.ZodString>;
542
542
  ActivitySyncRuleSet: z.ZodNullable<z.ZodString>;
543
543
  }, "strip", z.ZodTypeAny, {
544
+ Filter?: string;
544
545
  ID?: string;
545
546
  ActivityTypeID?: string;
546
547
  Direction?: "Inbound" | "Internal" | "Outbound";
@@ -559,9 +560,9 @@ export declare const mjBizAppsCommonActivitySyncRuleSchema: z.ZodObject<{
559
560
  DateFrom?: Date;
560
561
  DateTo?: Date;
561
562
  IncludeAttachments?: boolean;
562
- Filter?: string;
563
563
  ParticipantScope?: "AllExternal" | "AllInternal" | "Any" | "HasExternal" | "HasInternal" | "Mixed";
564
564
  }, {
565
+ Filter?: string;
565
566
  ID?: string;
566
567
  ActivityTypeID?: string;
567
568
  Direction?: "Inbound" | "Internal" | "Outbound";
@@ -580,7 +581,6 @@ export declare const mjBizAppsCommonActivitySyncRuleSchema: z.ZodObject<{
580
581
  DateFrom?: Date;
581
582
  DateTo?: Date;
582
583
  IncludeAttachments?: boolean;
583
- Filter?: string;
584
584
  ParticipantScope?: "AllExternal" | "AllInternal" | "Any" | "HasExternal" | "HasInternal" | "Mixed";
585
585
  }>;
586
586
  export type mjBizAppsCommonActivitySyncRuleEntityType = z.infer<typeof mjBizAppsCommonActivitySyncRuleSchema>;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export * from './generated/entity_subclasses.js';
2
2
  export type { ActivityDetails, ActivitySyncConnectionSettings, ActivitySyncRuleFilter, } from './activity-json-types.js';
3
+ export * from './business-day.js';
4
+ export * from './business-time-zone-engine.js';
3
5
  /**
4
6
  * This function is used to force the generated entities to be loaded. This is necessary because of the way that tree shaking works in webpack.
5
7
  * If you don't import this function and execute it, then the generated entities will not be included in the build. This is because the entities are not directly
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAC7C,YAAY,EACR,eAAe,EACf,8BAA8B,EAC9B,sBAAsB,GACzB,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,SACpC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAC7C,YAAY,EACR,eAAe,EACf,8BAA8B,EAC9B,sBAAsB,GACzB,MAAM,uBAAuB,CAAC;AAE/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gCAAgC,CAAC;AAE/C;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,SACpC"}
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from './generated/entity_subclasses.js';
2
+ export * from './business-day.js';
3
+ export * from './business-time-zone-engine.js';
2
4
  /**
3
5
  * This function is used to force the generated entities to be loaded. This is necessary because of the way that tree shaking works in webpack.
4
6
  * If you don't import this function and execute it, then the generated entities will not be included in the build. This is because the entities are not directly
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAO7C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB;AACrC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAO7C,cAAc,mBAAmB,CAAC;AAClC,cAAc,gCAAgC,CAAC;AAE/C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB;AACrC,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mj-biz-apps/common-entities",
3
3
  "type": "module",
4
- "version": "5.42.0",
4
+ "version": "5.43.0",
5
5
  "description": "MJ BizApps Common Entity Subclasses",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -15,14 +15,15 @@
15
15
  "license": "BUSL-1.1",
16
16
  "devDependencies": {
17
17
  "ts-node-dev": "^2.0.0",
18
- "typescript": "^5.9.3"
18
+ "typescript": "^5.9.3",
19
+ "vitest": "^3.2.4"
19
20
  },
20
21
  "dependencies": {
21
22
  "zod": "^3.25.76"
22
23
  },
23
24
  "peerDependencies": {
24
- "@memberjunction/core": "^6.1.0-edge.5",
25
- "@memberjunction/global": "^6.1.0-edge.5"
25
+ "@memberjunction/core": "^6.1.0-edge.6",
26
+ "@memberjunction/global": "^6.1.0-edge.6"
26
27
  },
27
28
  "repository": {
28
29
  "type": "git",
@@ -31,6 +32,7 @@
31
32
  "scripts": {
32
33
  "start": "ts-node-dev src/index.ts",
33
34
  "build": "tsc && tsc-alias -f",
34
- "test": "echo \"No tests configured yet\""
35
+ "test": "tsc -p tsconfig.typecheck.json && vitest run",
36
+ "typecheck": "tsc -p tsconfig.typecheck.json"
35
37
  }
36
38
  }