@classytic/primitives 0.21.0 → 0.22.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/CHANGELOG.md +934 -920
- package/dist/environment.d.mts +8 -3
- package/dist/environment.mjs +8 -3
- package/dist/memory-outbox.d.mts +1 -1
- package/dist/memory-outbox.mjs +0 -8
- package/dist/period.d.mts +25 -1
- package/dist/period.mjs +50 -1
- package/package.json +1 -1
package/dist/environment.d.mts
CHANGED
|
@@ -76,9 +76,14 @@ declare function classifyEnv(env: string | undefined | null): EnvClass;
|
|
|
76
76
|
/**
|
|
77
77
|
* `true` when the value classifies as production.
|
|
78
78
|
*
|
|
79
|
-
* A named predicate rather than a `classifyEnv(x) === 'production'` at each call site:
|
|
80
|
-
* comparison is the shape that caused every defect listed above, so
|
|
81
|
-
* one — even a correct one — for
|
|
79
|
+
* A named predicate rather than a `classifyEnv(x) === 'production'` at each call site: a literal
|
|
80
|
+
* comparison against an env string is the exact shape that caused every defect listed above, so
|
|
81
|
+
* this module should not contain one — even a correct one — for the next reader to copy.
|
|
82
|
+
*
|
|
83
|
+
* Deliberately the ONLY predicate. `isTest` / `isDevelopment` were added and removed the same day:
|
|
84
|
+
* they had zero importers, because consumers that need all three buckets build their own triple
|
|
85
|
+
* from `classifyEnv` (be-prod's `config.*`, gym's `businessMode()`). Speculative surface on a
|
|
86
|
+
* published package is not free — it has to be supported, and it invited a needless version bump.
|
|
82
87
|
*/
|
|
83
88
|
declare function isProductionEnv(env: string | undefined | null): boolean;
|
|
84
89
|
//#endregion
|
package/dist/environment.mjs
CHANGED
|
@@ -37,9 +37,14 @@ function classifyEnv(env) {
|
|
|
37
37
|
/**
|
|
38
38
|
* `true` when the value classifies as production.
|
|
39
39
|
*
|
|
40
|
-
* A named predicate rather than a `classifyEnv(x) === 'production'` at each call site:
|
|
41
|
-
* comparison is the shape that caused every defect listed above, so
|
|
42
|
-
* one — even a correct one — for
|
|
40
|
+
* A named predicate rather than a `classifyEnv(x) === 'production'` at each call site: a literal
|
|
41
|
+
* comparison against an env string is the exact shape that caused every defect listed above, so
|
|
42
|
+
* this module should not contain one — even a correct one — for the next reader to copy.
|
|
43
|
+
*
|
|
44
|
+
* Deliberately the ONLY predicate. `isTest` / `isDevelopment` were added and removed the same day:
|
|
45
|
+
* they had zero importers, because consumers that need all three buckets build their own triple
|
|
46
|
+
* from `classifyEnv` (be-prod's `config.*`, gym's `businessMode()`). Speculative surface on a
|
|
47
|
+
* published package is not free — it has to be supported, and it invited a needless version bump.
|
|
43
48
|
*/
|
|
44
49
|
function isProductionEnv(env) {
|
|
45
50
|
return classifyEnv(env) === "production";
|
package/dist/memory-outbox.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ import { OutboxAcknowledgeOptions, OutboxClaimOptions, OutboxErrorInfo, OutboxFa
|
|
|
3
3
|
//#region src/events/memory-outbox.d.ts
|
|
4
4
|
interface MemoryEntry {
|
|
5
5
|
event: DomainEvent;
|
|
6
|
-
status:
|
|
6
|
+
status: 'pending' | 'delivered' | 'dead_letter';
|
|
7
7
|
attempts: number;
|
|
8
8
|
visibleAt: number;
|
|
9
9
|
leaseOwner: string | null;
|
package/dist/memory-outbox.mjs
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import { InvalidOutboxEventError, OutboxOwnershipError } from "./outbox.mjs";
|
|
2
2
|
//#region src/events/memory-outbox.ts
|
|
3
|
-
/**
|
|
4
|
-
* In-memory outbox store — reference implementation for dev / testing.
|
|
5
|
-
*
|
|
6
|
-
* Supports the full `OutboxStore` capability set (claim/lease, fail/retry,
|
|
7
|
-
* dedupe, visibleAt). Production deployments should pass a `repository` to
|
|
8
|
-
* `EventOutbox` instead of using this; the memory store exists for unit
|
|
9
|
-
* tests and single-process dev where durable persistence is noise.
|
|
10
|
-
*/
|
|
11
3
|
const DEFAULT_LEASE_MS = 3e4;
|
|
12
4
|
var MemoryOutboxStore = class {
|
|
13
5
|
entries = [];
|
package/dist/period.d.mts
CHANGED
|
@@ -160,6 +160,30 @@ declare function resolvePeriod(period: Period, timezone?: string): DateRange;
|
|
|
160
160
|
* For the `$lte` call sites that predate half-open ranges. Derived from the
|
|
161
161
|
* resolved end rather than `start + 24h - 1`, so it stays DST-exact.
|
|
162
162
|
*/
|
|
163
|
+
/**
|
|
164
|
+
* Shift a MONTH or QUARTER period by `n` of its own units (negative = back).
|
|
165
|
+
*
|
|
166
|
+
* The arithmetic a caller would otherwise write inline, and the reason this is
|
|
167
|
+
* here rather than in each of them: "two filing months ago" is a `Period`
|
|
168
|
+
* question, and the shapes reachable without it are both wrong in the same way.
|
|
169
|
+
*
|
|
170
|
+
* `new Date(Date.UTC(y, m - 1 - n, 1))` — a UTC instant used to answer a
|
|
171
|
+
* BUSINESS-calendar question. Six hours off in Asia/Dhaka at both ends; the
|
|
172
|
+
* five silent defects in this module's header are all that shape.
|
|
173
|
+
*
|
|
174
|
+
* hand-rolled integer math (`y * 12 + (m - 1) - n`) — correct, but it is a
|
|
175
|
+
* third copy of a rule the `Period` type already owns, and the year rollover
|
|
176
|
+
* is exactly where a copy goes wrong.
|
|
177
|
+
*
|
|
178
|
+
* NO Date is constructed and no zone is consulted: shifting a month is pure
|
|
179
|
+
* calendar arithmetic on `(year, month)`. The `timezone` rides along unchanged,
|
|
180
|
+
* so the shifted period still resolves against the calendar it was defined in —
|
|
181
|
+
* `resolvePeriod` / {@link resolveMonth} remain the only places instants appear.
|
|
182
|
+
*
|
|
183
|
+
* A YEAR period shifts by years; a `custom` (ad-hoc start/end) period has no
|
|
184
|
+
* unit to shift and throws rather than guessing one.
|
|
185
|
+
*/
|
|
186
|
+
declare function shiftPeriod(period: Period, n: number): Period;
|
|
163
187
|
declare function inclusiveEnd(range: DateRange): Date;
|
|
164
188
|
/**
|
|
165
189
|
* The period an INSTANT falls in, on the local calendar.
|
|
@@ -185,4 +209,4 @@ declare function parsePeriod(label: string, timezone?: string): Period;
|
|
|
185
209
|
*/
|
|
186
210
|
declare function formatPeriod(period: Period): string;
|
|
187
211
|
//#endregion
|
|
188
|
-
export { DateRange, DateRangeError, Period, PeriodError, PeriodErrorCode, PeriodGranularity, dayStart, formatPeriod, granularityOf, inclusiveEnd, isDateRange, isWithin, parsePeriod, periodOf, periodTimeZone, rangeDurationMs, rangesOverlap, resolveDateSpan, resolveDay, resolveMonth, resolvePeriod, resolveQuarter, resolveYear };
|
|
212
|
+
export { DateRange, DateRangeError, Period, PeriodError, PeriodErrorCode, PeriodGranularity, dayStart, formatPeriod, granularityOf, inclusiveEnd, isDateRange, isWithin, parsePeriod, periodOf, periodTimeZone, rangeDurationMs, rangesOverlap, resolveDateSpan, resolveDay, resolveMonth, resolvePeriod, resolveQuarter, resolveYear, shiftPeriod };
|
package/dist/period.mjs
CHANGED
|
@@ -261,6 +261,55 @@ function resolvePeriod(period, timezone) {
|
|
|
261
261
|
* For the `$lte` call sites that predate half-open ranges. Derived from the
|
|
262
262
|
* resolved end rather than `start + 24h - 1`, so it stays DST-exact.
|
|
263
263
|
*/
|
|
264
|
+
/**
|
|
265
|
+
* Shift a MONTH or QUARTER period by `n` of its own units (negative = back).
|
|
266
|
+
*
|
|
267
|
+
* The arithmetic a caller would otherwise write inline, and the reason this is
|
|
268
|
+
* here rather than in each of them: "two filing months ago" is a `Period`
|
|
269
|
+
* question, and the shapes reachable without it are both wrong in the same way.
|
|
270
|
+
*
|
|
271
|
+
* `new Date(Date.UTC(y, m - 1 - n, 1))` — a UTC instant used to answer a
|
|
272
|
+
* BUSINESS-calendar question. Six hours off in Asia/Dhaka at both ends; the
|
|
273
|
+
* five silent defects in this module's header are all that shape.
|
|
274
|
+
*
|
|
275
|
+
* hand-rolled integer math (`y * 12 + (m - 1) - n`) — correct, but it is a
|
|
276
|
+
* third copy of a rule the `Period` type already owns, and the year rollover
|
|
277
|
+
* is exactly where a copy goes wrong.
|
|
278
|
+
*
|
|
279
|
+
* NO Date is constructed and no zone is consulted: shifting a month is pure
|
|
280
|
+
* calendar arithmetic on `(year, month)`. The `timezone` rides along unchanged,
|
|
281
|
+
* so the shifted period still resolves against the calendar it was defined in —
|
|
282
|
+
* `resolvePeriod` / {@link resolveMonth} remain the only places instants appear.
|
|
283
|
+
*
|
|
284
|
+
* A YEAR period shifts by years; a `custom` (ad-hoc start/end) period has no
|
|
285
|
+
* unit to shift and throws rather than guessing one.
|
|
286
|
+
*/
|
|
287
|
+
function shiftPeriod(period, n) {
|
|
288
|
+
if (!Number.isInteger(n)) throw new PeriodError("INVALID_FIELD", `shiftPeriod expects an integer offset, received ${String(n)}.`);
|
|
289
|
+
const granularity = granularityOf(period);
|
|
290
|
+
const zone = period.timezone !== void 0 ? { timezone: period.timezone } : {};
|
|
291
|
+
if (granularity === "month") {
|
|
292
|
+
const zeroBased = period.year * 12 + (period.month - 1) + n;
|
|
293
|
+
return {
|
|
294
|
+
year: Math.floor(zeroBased / 12),
|
|
295
|
+
month: zeroBased % 12 + 1,
|
|
296
|
+
...zone
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
if (granularity === "quarter") {
|
|
300
|
+
const zeroBased = period.year * 4 + (period.quarter - 1) + n;
|
|
301
|
+
return {
|
|
302
|
+
year: Math.floor(zeroBased / 4),
|
|
303
|
+
quarter: zeroBased % 4 + 1,
|
|
304
|
+
...zone
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
if (granularity === "year") return {
|
|
308
|
+
year: period.year + n,
|
|
309
|
+
...zone
|
|
310
|
+
};
|
|
311
|
+
throw new PeriodError("AMBIGUOUS_PERIOD", "shiftPeriod has no unit to shift for an ad-hoc start/end period — shift the instants, or use a calendar period.");
|
|
312
|
+
}
|
|
264
313
|
function inclusiveEnd(range) {
|
|
265
314
|
assertUsableRange(range, "range");
|
|
266
315
|
return /* @__PURE__ */ new Date(range.end.getTime() - 1);
|
|
@@ -339,4 +388,4 @@ function formatPeriod(period) {
|
|
|
339
388
|
throw new PeriodError("INVALID_LABEL", "An ad-hoc Period (start + end) has no canonical label.");
|
|
340
389
|
}
|
|
341
390
|
//#endregion
|
|
342
|
-
export { DateRangeError, PeriodError, dayStart, formatPeriod, granularityOf, inclusiveEnd, isDateRange, isWithin, parsePeriod, periodOf, periodTimeZone, rangeDurationMs, rangesOverlap, resolveDateSpan, resolveDay, resolveMonth, resolvePeriod, resolveQuarter, resolveYear };
|
|
391
|
+
export { DateRangeError, PeriodError, dayStart, formatPeriod, granularityOf, inclusiveEnd, isDateRange, isWithin, parsePeriod, periodOf, periodTimeZone, rangeDurationMs, rangesOverlap, resolveDateSpan, resolveDay, resolveMonth, resolvePeriod, resolveQuarter, resolveYear, shiftPeriod };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/primitives",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Framework-agnostic TypeScript primitives shared across Classytic packages — Money, events, pagination, tenant config, and other building blocks.",
|
|
5
5
|
"author": "Classytic",
|
|
6
6
|
"license": "MIT",
|