@objectstack/core@16.0.0
Minor Changes
-
dd9f223: feat(analytics): scope a datetime date-bucket drill to the reference-tz midnight instants (#1752 follow-up)
Closes the one gap left by the initial #1752 change: a
datetimedate dimension
bucketed under a non-UTC reference timezone previously fell back to a superset
drill (its bucket boundary is that tz's midnight instant, whichYYYY-MM-DD
calendar bounds can't express).@objectstack/coreaddszonedDateStartToUtcMs(ymd, tz)— the UTC instant
at which a calendar day begins in a reference timezone (the inverse of
calendarPartsInTz). DST-safe: the offset is read from the platform tz
database viaIntl, with a two-pass resolution for the rare offset-boundary
case; an unset/'UTC'/invalid zone returns plain UTC midnight.@objectstack/service-analyticsnow emitsdrillRangesbounds per the
field's temporal type (ADR-0053): adatetimefield → ISO instant bounds
at the reference tz's midnight (works under any tz, incl. DST); adatefield
→YYYY-MM-DDcalendar bounds (tz-naive, exact under any tz). An unknown field
type is still emitted only under UTC and omitted (superset) under a non-UTC tz.
No objectui change is needed — the client already forwards whatever bound values
the server sends into the drill filter and thefilter[field][gte|lt]URL. -
290e2f0: feat(analytics): emit a half-open date-range drill scope for granularity-bucketed date dimensions (#1752)
A report/dashboard cell grouped by a
dateGranularitydate dimension ("2026-Q2")
covers a SPAN of records, so drilling it needs a range (>= start AND < nextStart),
which the equality drill contract (drillRawRows) can't express — date dims were
therefore excluded from drill metadata and a drill landed on an unscoped superset.@objectstack/coreaddsbucketKeyToCalendarRange(key, granularity), the
inverse ofbucketDateValue: it turns a canonical bucket key into its half-open
[start, end)calendar span (YYYY-MM-DD,endexclusive). Pure, timezone-naive
calendar arithmetic; returnsnullfor unbucketable / out-of-range keys so the
caller falls back to an unscoped (superset) drill rather than emit a wrong bound.@objectstack/service-analyticsemits adrillRangessidecar (aligned to
rowsby index — the range companion todrillRawRows) fordate+
dateGranularitydimensions, computed from the canonical bucket key in the
pre-label-resolution snapshot pass. Adatetimefield under a non-UTC reference
timezone is omitted (host drills a superset) until instant-boundary support
lands; a tz-naivedatefield is exact under any timezone (ADR-0053).
Consumed by objectui's report drill-through to scope the drilled record list to the
clicked time bucket.
Patch Changes
-
e057f42: fix: harden the bulk-write path — retries, idempotency, contracts, and summary visibility (#3147–#3152)
Six reliability fixes to the batched seed/import +
engine.insert(array)path
introduced by the #2678 bulk-write rework:- #3151
bulkWritevalidates thatwriteBatchreturns one record per input
row (a short/long/non-array return is degraded per-row, not backfilled as
phantom success);engine.insert(array)likewise rejects a short driver
bulkCreatereturn instead of padding afterInsert withundefined. - #3150 wraps the two remaining un-retried write points (seed
writeRecord/resolveDeferredUpdates, import's no-createManyData
fallback) inwithTransientRetry;defaultIsTransientErrorshort-circuits
definitive logical errors to non-transient. - #3148 import
resolveRefflushes pending creates on a same-object miss so
a later row can reference an earlier same-file CREATE, and no longer
negatively caches a miss. - #3149 threads an
attemptcounter throughbulkWrite; seed rechecks by
externalIdand import bymatchFieldsbefore re-writing, so a
commit-then-lost-response retry cannot duplicate a batch. - #3147
recomputeSummariesretries transient failures and, on exhaustion,
surfacesSummaryRecomputeError(ERR_SUMMARY_RECOMPUTE) instead of a
silent warn; seed/import recover it to a warning without re-writing. - #3152 autonumbers are assigned after validation, so a batch that dies in
validation consumes no sequence value (no number-range gaps).
- #3151
-
5f05de2:
createLogger({ file })now actually writes the file under ESM.openFileStreamloadedfswith a lazyrequire()to keep the browser-safe logger entry out of thefsbundle graph; esbuild rewrites that to its__requireshim in the ESM output, which throwsDynamic require of "fs" is not supported, and a barecatch {}swallowed it. Since the workspace istype: module, every Node ESM consumer —os serve,os dev— silently got no file logging at all, while the CJS build kept working. The builtin now loads viaprocess.getBuiltinModule(opaque to bundlers, works in both module systems, with arequirefallback for Node < 20.16), and afiledestination that cannot be opened reports itself on stderr instead of disappearing.Turning the destination back on also fixed three faults that were unreachable while it never opened:
child()opened a second stream per child and orphaned it, destroying a child logger closed the stream its parent and siblings were still writing to, and an async open failure (e.g. an unwritable path) hit an'error'event with no listener and took the process down. -
021ba4c: fix(core): ObjectLogger honors NO_COLOR and TTY detection before emitting ANSI colors
The kernel/plugin logger (
ctx.logger, wired byos serve/os dev) colorized its
pretty-format level tags unconditionally, soNO_COLOR=1runs and piped/CI output
still carried ANSI escapes (e.g.\x1b[31m…ERROR\x1b[0m), breaking plain-text log
scanners (see scripts/publish-smoke.sh, which had to strip ANSI before grepping).Per the no-color.org convention, color is now emitted only when the destination stream
(stdout, or stderr for error/fatal) is an interactive TTY andNO_COLORis unset or
empty — any non-emptyNO_COLORvalue disables color. Interactive terminals keep the
existing colorized output. The optional file destination now always receives plain text. -
Updated dependencies [f972574]
-
Updated dependencies [6289ec3]
-
Updated dependencies [22013aa]
-
Updated dependencies [3ad3dd5]
-
Updated dependencies [8efa395]
-
Updated dependencies [3a18b60]
-
Updated dependencies [a8aa34c]
-
Updated dependencies [a3823b2]
-
Updated dependencies [43a3efb]
-
Updated dependencies [524696a]
-
Updated dependencies [bfa3c3f]
-
Updated dependencies [5e3301d]
-
Updated dependencies [46e876c]
-
Updated dependencies [158aa14]
-
Updated dependencies [62a2117]
-
Updated dependencies [d2723e2]
-
Updated dependencies [fefcd54]
-
Updated dependencies [beaf2de]
-
Updated dependencies [369eb6e]
-
Updated dependencies [06ff734]
-
Updated dependencies [b659111]
-
Updated dependencies [5754a23]
-
Updated dependencies [6c270a6]
-
Updated dependencies [668dd17]
-
Updated dependencies [8abf133]
-
Updated dependencies [e0859b1]
-
Updated dependencies [04ecd4e]
-
Updated dependencies [4d5a892]
-
Updated dependencies [16cebeb]
-
Updated dependencies [86d30af]
-
Updated dependencies [8923843]
-
Updated dependencies [a2795f6]
-
Updated dependencies [f16b492]
-
Updated dependencies [4b6fde8]
-
Updated dependencies [2018df9]
-
Updated dependencies [fc5a3a2]
-
Updated dependencies [8ff9210]
- @objectstack/spec@16.0.0