@voltro/datetime 0.29.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/LICENSE ADDED
@@ -0,0 +1,57 @@
1
+ Voltro — Proprietary Software License
2
+
3
+ Copyright (c) 2026 Voltro UG. All rights reserved.
4
+
5
+ This software and all associated source code, documentation, and other
6
+ materials (the "Software") are the proprietary property of Voltro UG
7
+ ("Voltro"). This is NOT open-source software.
8
+
9
+ Your access to and use of the Software is governed exclusively by the Voltro
10
+ Terms of Service at:
11
+
12
+ https://voltro.cloud/legal/terms
13
+
14
+ By downloading, installing, or using the Software you agree to those Terms.
15
+ Subject to and conditioned on your continued compliance with them, Voltro
16
+ grants you a limited, non-exclusive, non-transferable, non-sublicensable,
17
+ revocable license to use the Software. All rights not expressly granted in the
18
+ Terms are reserved by Voltro. If you do not agree to the Terms, you have no
19
+ license and may not use the Software.
20
+
21
+ The Terms of Service — including the scope of permitted use, plan
22
+ entitlements, fees, and pricing — may change from time to time. The version in
23
+ force is the one published at the URL above. Commercial terms and pricing are
24
+ NOT part of this notice and are not fixed by, or granted in perpetuity by, the
25
+ version of the Software in which this file appears.
26
+
27
+ Permitted use — your own software. Voltro is a development framework. You may
28
+ use the Software to build, run, and commercially distribute your own
29
+ applications and services, and to charge your own customers for them, without
30
+ owing Voltro any share of that revenue or any further permission beyond the
31
+ Terms. Applications you build with the Software are yours.
32
+
33
+ Prohibited use — reselling Voltro. You may NOT redistribute, resell,
34
+ sublicense, publish, or otherwise provide the Software itself — in whole or in
35
+ part, in source or compiled form — to third parties as a library, framework,
36
+ SDK, template, starter, or development tool for them to build upon, whether
37
+ standalone or repackaged. Shipping the Software as a non-separable, bundled
38
+ dependency inside an application you deliver (for example, compiled into your
39
+ deployed app) is permitted; extracting or re-exposing it as a reusable
40
+ component for others is not.
41
+
42
+ Except as expressly permitted above or by the Terms, you may not copy, modify,
43
+ merge, publish, sublicense, sell, distribute, or create derivative works of the
44
+ Software, in whole or in part.
45
+
46
+ Third-party open-source components distributed alongside the Software are the
47
+ property of their respective owners and are licensed under their own terms; see
48
+ THIRD-PARTY-NOTICES.md where provided. Nothing in this notice limits your
49
+ rights, or extends Voltro's, in those components.
50
+
51
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
52
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
53
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL
54
+ VOLTRO BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM,
55
+ OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR ITS USE.
56
+
57
+ For licensing inquiries, contact Voltro UG.
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ <div align="center">
2
+
3
+ # @voltro/datetime
4
+
5
+ **The framework's opinion on time: UTC instants in storage, rendering in the viewer's timezone, and zone-aware arithmetic/formatting on the TC39 Temporal standard (via polyfill). Ships the request-scoped timezone-context seam plus pure, browser-safe date helpers.**
6
+
7
+ [📖 Documentation](https://docs.voltro.dev/docs/intro/getting-started) · [voltro.dev](https://voltro.dev) · [Voltro Cloud](https://voltro.cloud)
8
+
9
+ </div>
10
+
11
+ ---
12
+
13
+ ```sh
14
+ npm install @voltro/datetime
15
+ ```
16
+
17
+ > ### [→ Read the documentation for @voltro/datetime](https://docs.voltro.dev/docs/intro/getting-started)
18
+
19
+ Installation, guides, the full API reference, and examples all live in the
20
+ **[Voltro documentation](https://docs.voltro.dev/docs/intro/getting-started)** — the single source of truth. This README is
21
+ deliberately short so there is nothing here to drift out of date.
22
+
23
+ ## License
24
+
25
+ Proprietary. © 2026 Voltro UG. Your use is governed by the
26
+ [Terms of Service](https://voltro.cloud/legal/terms). See the bundled `LICENSE`.
package/SECURITY.md ADDED
@@ -0,0 +1,56 @@
1
+ # Security Policy
2
+
3
+ We take the security of Voltro and the applications built on it seriously. This
4
+ document explains how to report a vulnerability and what to expect in return.
5
+
6
+ ## Reporting a vulnerability
7
+
8
+ **Please do not open public issues or discuss suspected vulnerabilities in
9
+ public channels.** Report them privately by email:
10
+
11
+ **security contact: [support@voltro.dev](mailto:support@voltro.dev)**
12
+ (subject line: `SECURITY`).
13
+
14
+ Include, where you can:
15
+
16
+ - the affected package(s) and version(s) (e.g. `@voltro/runtime@x.y.z`);
17
+ - a description of the issue and its impact;
18
+ - a minimal reproduction or proof of concept;
19
+ - any suggested remediation.
20
+
21
+ If you'd like to encrypt your report, ask in a first plain email and we'll
22
+ arrange a key.
23
+
24
+ ## What to expect
25
+
26
+ - **Acknowledgement** of your report within **3 business days**.
27
+ - An initial assessment (severity, affected surface) and a remediation plan as
28
+ soon as we've reproduced the issue.
29
+ - **Coordinated disclosure:** we'll agree a disclosure timeline with you and
30
+ credit you in the release notes if you wish. Please give us reasonable time to
31
+ ship a fix before any public disclosure.
32
+
33
+ We do not currently run a paid bug-bounty program, but we genuinely appreciate
34
+ responsible disclosure and will credit reporters.
35
+
36
+ ## Software Bill of Materials (SBOM)
37
+
38
+ A CycloneDX SBOM of the third-party runtime dependency graph is generated for the
39
+ published packages (`pnpm gen:sbom` → `sbom.cdx.json`). If your procurement or
40
+ security team needs it, request it at
41
+ [support@voltro.dev](mailto:support@voltro.dev).
42
+
43
+ ## Supported versions
44
+
45
+ Voltro is pre-1.0 and ships in lockstep: **only the latest published minor of
46
+ each `@voltro/*` package receives security fixes.** Please upgrade to the latest
47
+ release before reporting, and pin exact versions in production.
48
+
49
+ ## Scope
50
+
51
+ In scope: the published `@voltro/*` packages and the framework's own code.
52
+
53
+ Out of scope: vulnerabilities in third-party dependencies that are already
54
+ tracked upstream (we monitor these via a production-dependency audit gate in
55
+ CI), and issues that require a non-default, explicitly-unsafe configuration. If
56
+ you're unsure, report it anyway — we'd rather hear about it.
@@ -0,0 +1,59 @@
1
+ # Third-Party Notices — @voltro/datetime
2
+
3
+ This package depends on the open-source software listed below. Each is the
4
+ property of its respective copyright holders and is used under the terms of
5
+ its license. This file is provided for attribution; it grants no rights in
6
+ @voltro/datetime itself, which is proprietary (see LICENSE).
7
+
8
+ Generated from the resolved runtime dependency closure (2 packages).
9
+
10
+ ---
11
+
12
+ ## temporal-polyfill@0.3.2
13
+
14
+ License: MIT
15
+
16
+ ```
17
+ MIT License
18
+
19
+ Copyright (c) 2024 Adam Shaw
20
+
21
+ Permission is hereby granted, free of charge, to any person obtaining a copy
22
+ of this software and associated documentation files (the "Software"), to deal
23
+ in the Software without restriction, including without limitation the rights
24
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25
+ copies of the Software, and to permit persons to whom the Software is
26
+ furnished to do so, subject to the following conditions:
27
+
28
+ The above copyright notice and this permission notice shall be included in all
29
+ copies or substantial portions of the Software.
30
+
31
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37
+ SOFTWARE.
38
+ ```
39
+
40
+ ## temporal-spec@0.3.1
41
+
42
+ License: ISC
43
+
44
+ ```
45
+ Copyright 2017, 2018, 2019, 2020 ECMA International
46
+
47
+ Permission to use, copy, modify, and/or distribute this software for any
48
+ purpose with or without fee is hereby granted, provided that the above
49
+ copyright notice and this permission notice appear in all copies.
50
+
51
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
52
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
53
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
54
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
55
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
56
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
57
+ PERFORMANCE OF THIS SOFTWARE.
58
+ ```
59
+
@@ -0,0 +1,45 @@
1
+ import { Context } from 'effect';
2
+ import { Effect } from 'effect';
3
+ import { Layer } from 'effect';
4
+
5
+ /**
6
+ * The effective timezone in the current context, or `UTC` when none was
7
+ * provided. Never fails — an absent context is the documented UTC default,
8
+ * so call sites don't have to handle a missing-service error.
9
+ */
10
+ export declare const currentTimezone: Effect.Effect<string>;
11
+
12
+ /**
13
+ * A layer that RESOLVES the timezone from the request signals (user
14
+ * profile → tenant → browser → UTC) and provides it. This is what the
15
+ * runtime wires per request.
16
+ */
17
+ export declare const resolvedTimezoneLayer: (args: ResolveTimezoneArgs) => Layer.Layer<TimezoneContext>;
18
+
19
+ declare interface ResolveTimezoneArgs {
20
+ /** The viewing user's stored profile timezone, if any. */
21
+ readonly userTimeZone?: string | null;
22
+ /** The tenant / org default timezone, if any. */
23
+ readonly tenantTimeZone?: string | null;
24
+ /** The browser-reported timezone (from the client), if any. */
25
+ readonly browserTimeZone?: string | null;
26
+ }
27
+
28
+ /** The carried value: the effective IANA timezone for the current request. */
29
+ export declare interface Timezone {
30
+ readonly timeZone: string;
31
+ }
32
+
33
+ /** Context tag holding the request's resolved timezone. */
34
+ export declare class TimezoneContext extends TimezoneContext_base {
35
+ }
36
+
37
+ declare const TimezoneContext_base: Context.TagClass<TimezoneContext, "@voltro/datetime/TimezoneContext", Timezone>;
38
+
39
+ /** A layer providing a fixed timezone. */
40
+ export declare const TimezoneContextLive: (timeZone: string) => Layer.Layer<TimezoneContext>;
41
+
42
+ /** Run `effect` with an explicit timezone in context. */
43
+ export declare const withTimezone: (timeZone: string) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, TimezoneContext>>;
44
+
45
+ export { }
@@ -0,0 +1,9 @@
1
+ import { n as e } from "./resolveTimezone-B67Y7K6d.js";
2
+ import { Context as t, Effect as n, Layer as r, Option as i } from "effect";
3
+ //#region src/context.ts
4
+ var a = class extends t.Tag("@voltro/datetime/TimezoneContext")() {}, o = n.map(n.serviceOption(a), (e) => i.match(e, {
5
+ onNone: () => "UTC",
6
+ onSome: (e) => e.timeZone
7
+ })), s = (e) => (t) => n.provideService(t, a, { timeZone: e }), c = (e) => r.succeed(a, { timeZone: e }), l = (t) => r.succeed(a, { timeZone: e(t) });
8
+ //#endregion
9
+ export { a as TimezoneContext, c as TimezoneContextLive, o as currentTimezone, l as resolvedTimezoneLayer, s as withTimezone };
@@ -0,0 +1,138 @@
1
+ import { Temporal } from 'temporal-polyfill';
2
+
3
+ /** DST-aware: same wall-clock time, `n` calendar days later in `timeZone`. */
4
+ export declare const addDays: (value: InstantInput, n: number, timeZone: string) => Temporal.Instant;
5
+
6
+ /** DST-UNAWARE: exactly `n × 3600` seconds later. No zone — an instant offset. */
7
+ export declare const addHours: (value: InstantInput, n: number) => Temporal.Instant;
8
+
9
+ /** DST-aware: same wall-clock time, `n` calendar months later in `timeZone`
10
+ * (clamps to the last day of a shorter month per Temporal's default). */
11
+ export declare const addMonths: (value: InstantInput, n: number, timeZone: string) => Temporal.Instant;
12
+
13
+ /** Throw unless `timeZone` is a valid IANA name. Storage rule: validate on
14
+ * input, never store an unverified zone string. */
15
+ export declare const assertTimeZone: (timeZone: string) => string;
16
+
17
+ /** The last-resort fallback. UTC is always valid and never surprising. */
18
+ export declare const DEFAULT_TIME_ZONE = "UTC";
19
+
20
+ /** Last instant (23:59:59.999999999) of the local day in `timeZone`. */
21
+ export declare const endOfDay: (value: InstantInput, timeZone: string) => Temporal.Instant;
22
+
23
+ /** Date only, in `timeZone`. Default `dateStyle: 'medium'`. */
24
+ export declare const formatDate: (value: InstantInput, timeZone: string, options?: FormatOptions) => string;
25
+
26
+ /** Date + time, in `timeZone`. Default `dateStyle`/`timeStyle: 'medium'`. */
27
+ export declare const formatDateTime: (value: InstantInput, timeZone: string, options?: FormatOptions) => string;
28
+
29
+ /** Options common to the absolute formatters: an explicit `locale` plus any
30
+ * `Intl.DateTimeFormatOptions` override (a `timeZone` in here wins over the
31
+ * positional `timeZone` argument). */
32
+ export declare type FormatOptions = {
33
+ readonly locale?: string;
34
+ } & Intl.DateTimeFormatOptions;
35
+
36
+ /**
37
+ * "3 hours ago", "in 2 days". Picks the largest unit that fits the signed
38
+ * distance between `value` and `now` (default: the current instant). This
39
+ * is zone-independent: it measures elapsed real time, not wall-clock days.
40
+ */
41
+ export declare const formatRelativeTime: (value: InstantInput, options?: RelativeTimeOptions) => string;
42
+
43
+ /** Time only, in `timeZone`. Default `timeStyle: 'medium'`. */
44
+ export declare const formatTime: (value: InstantInput, timeZone: string, options?: FormatOptions) => string;
45
+
46
+ /** Bridge a JS `Date` (DB read) to a `Temporal.Instant`. */
47
+ export declare const fromDate: (date: Date) => Temporal.Instant;
48
+
49
+ /** Parse an ISO-8601 instant (offset / `Z` required). Alias: `parseISO`. */
50
+ export declare const instant: (iso: string) => Temporal.Instant;
51
+
52
+ /** Anything that unambiguously denotes a UTC instant: a Temporal.Instant,
53
+ * a JS `Date` (what the DB layer produces), or an ISO-8601 string with an
54
+ * explicit offset / `Z`. */
55
+ export declare type InstantInput = Temporal.Instant | Date | string;
56
+
57
+ /** Is `a` strictly after `b`? Zone-independent (compares absolute instants). */
58
+ export declare const isAfter: (a: InstantInput, b: InstantInput) => boolean;
59
+
60
+ /** Is `a` strictly before `b`? Zone-independent (compares absolute instants). */
61
+ export declare const isBefore: (a: InstantInput, b: InstantInput) => boolean;
62
+
63
+ /** Do `a` and `b` fall on the same calendar day in `timeZone`? */
64
+ export declare const isSameDay: (a: InstantInput, b: InstantInput, timeZone: string) => boolean;
65
+
66
+ /** Is `timeZone` a valid IANA name this runtime knows? Uses `Intl`, which
67
+ * is the authority both Temporal and formatting defer to. */
68
+ export declare const isValidTimeZone: (timeZone: string) => boolean;
69
+
70
+ /** The current UTC instant. */
71
+ export declare const now: () => Temporal.Instant;
72
+
73
+ /** Parse a `YYYY-MM-DD` calendar date. */
74
+ export declare const parseDate: (iso: string) => Temporal.PlainDate;
75
+
76
+ /** Parse an ISO-8601 instant. Same as `instant`, named for parse sites. */
77
+ export declare const parseISO: (iso: string) => Temporal.Instant;
78
+
79
+ /** A calendar date with no time and no zone (birthdays, holidays, due dates). */
80
+ export declare const plainDate: (year: number, month: number, day: number) => Temporal.PlainDate;
81
+
82
+ /** Options for `formatRelativeTime`. */
83
+ export declare interface RelativeTimeOptions {
84
+ readonly locale?: string;
85
+ /** The instant to measure against. Defaults to "now". */
86
+ readonly now?: InstantInput;
87
+ readonly numeric?: Intl.RelativeTimeFormatNumeric;
88
+ readonly style?: Intl.RelativeTimeFormatStyle;
89
+ }
90
+
91
+ /**
92
+ * Resolve the effective IANA timezone for a request, in priority order.
93
+ * Returns a validated IANA name, never an unchecked string; falls back to
94
+ * `UTC` when no signal yields a known zone.
95
+ */
96
+ export declare const resolveTimezone: (args: ResolveTimezoneArgs) => string;
97
+
98
+ export declare interface ResolveTimezoneArgs {
99
+ /** The viewing user's stored profile timezone, if any. */
100
+ readonly userTimeZone?: string | null;
101
+ /** The tenant / org default timezone, if any. */
102
+ readonly tenantTimeZone?: string | null;
103
+ /** The browser-reported timezone (from the client), if any. */
104
+ readonly browserTimeZone?: string | null;
105
+ }
106
+
107
+ /** First instant of the local day containing `value` in `timeZone`. */
108
+ export declare const startOfDay: (value: InstantInput, timeZone: string) => Temporal.Instant;
109
+
110
+ /** First instant of the local month containing `value` in `timeZone`. */
111
+ export declare const startOfMonth: (value: InstantInput, timeZone: string) => Temporal.Instant;
112
+
113
+ export { Temporal }
114
+
115
+ /** Bridge a `Temporal.Instant` back to a JS `Date` for storage / interop. */
116
+ export declare const toDate: (instant: Temporal.Instant) => Date;
117
+
118
+ /** Today's calendar date in `timeZone` (no clock, no zone on the result). */
119
+ export declare const today: (timeZone: string) => Temporal.PlainDate;
120
+
121
+ /**
122
+ * Coerce a permissive instant input to a `Temporal.Instant`. This is the
123
+ * single funnel every helper runs its input through, so callers can pass
124
+ * the `Date` a query returned without a manual conversion.
125
+ *
126
+ * A string MUST carry an explicit offset or `Z` — a naive `2026-01-01T12:00`
127
+ * has no instant and throws, by design (the whole point is no silent
128
+ * zone-guessing).
129
+ */
130
+ export declare const toInstant: (value: InstantInput) => Temporal.Instant;
131
+
132
+ /** Project a UTC instant into a wall-clock `ZonedDateTime` in `timeZone`. */
133
+ export declare const toTimezone: (value: InstantInput, timeZone: string) => Temporal.ZonedDateTime;
134
+
135
+ /** The canonical wire / storage form: ISO-8601 in UTC (`…Z`). */
136
+ export declare const toUTCString: (value: InstantInput) => string;
137
+
138
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
1
+ import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c } from "./resolveTimezone-B67Y7K6d.js";
2
+ //#region src/helpers.ts
3
+ var l = () => r.Now.instant(), u = (e) => r.Now.plainDateISO(e), d = (e) => r.Instant.from(e), f = (e) => r.Instant.from(e), p = (e, t, n) => r.PlainDate.from({
4
+ year: e,
5
+ month: t,
6
+ day: n
7
+ }), m = (e) => r.PlainDate.from(e), h = (e, t) => s(e).toZonedDateTimeISO(t), g = (e, t, n) => s(e).toZonedDateTimeISO(n).add({ days: t }).toInstant(), _ = (e, t, n) => s(e).toZonedDateTimeISO(n).add({ months: t }).toInstant(), v = (e, t) => s(e).add({ hours: t }), y = (e, t) => s(e).toZonedDateTimeISO(t).startOfDay().toInstant(), b = (e, t) => s(e).toZonedDateTimeISO(t).add({ days: 1 }).startOfDay().subtract({ nanoseconds: 1 }).toInstant(), x = (e, t) => s(e).toZonedDateTimeISO(t).with({ day: 1 }).startOfDay().toInstant(), S = (e, t, n) => s(e).toZonedDateTimeISO(n).toPlainDate().equals(s(t).toZonedDateTimeISO(n).toPlainDate()), C = (e, t) => r.Instant.compare(s(e), s(t)) > 0, w = (e, t) => r.Instant.compare(s(e), s(t)) < 0, T = (e, t, n, r) => {
8
+ let { locale: i, ...o } = r ?? {};
9
+ return new Intl.DateTimeFormat(i, {
10
+ timeZone: t,
11
+ ...n,
12
+ ...o
13
+ }).format(a(s(e)));
14
+ }, E = (e, t, n) => T(e, t, { dateStyle: "medium" }, n), D = (e, t, n) => T(e, t, { timeStyle: "medium" }, n), O = (e, t, n) => T(e, t, {
15
+ dateStyle: "medium",
16
+ timeStyle: "medium"
17
+ }, n), k = [
18
+ ["year", 3600 * 24 * 365],
19
+ ["month", 3600 * 24 * 30],
20
+ ["week", 3600 * 24 * 7],
21
+ ["day", 3600 * 24],
22
+ ["hour", 3600],
23
+ ["minute", 60],
24
+ ["second", 1]
25
+ ], A = (e, t) => {
26
+ let { locale: n, now: r, numeric: i = "auto", style: a } = t ?? {}, o = s(e), c = r === void 0 ? Date.now() : s(r).epochMilliseconds, l = (o.epochMilliseconds - c) / 1e3, u = new Intl.RelativeTimeFormat(n, {
27
+ numeric: i,
28
+ ...a ? { style: a } : {}
29
+ }), d = Math.abs(l);
30
+ for (let [e, t] of k) if (d >= t || e === "second") {
31
+ let n = Math.round(l / t);
32
+ return u.format(n, e);
33
+ }
34
+ return u.format(Math.round(l), "second");
35
+ };
36
+ //#endregion
37
+ export { c as DEFAULT_TIME_ZONE, r as Temporal, g as addDays, v as addHours, _ as addMonths, o as assertTimeZone, b as endOfDay, E as formatDate, O as formatDateTime, A as formatRelativeTime, D as formatTime, n as fromDate, d as instant, C as isAfter, w as isBefore, S as isSameDay, e as isValidTimeZone, l as now, m as parseDate, f as parseISO, p as plainDate, i as resolveTimezone, y as startOfDay, x as startOfMonth, a as toDate, s as toInstant, h as toTimezone, t as toUTCString, u as today };
@@ -0,0 +1,22 @@
1
+ import { Temporal as e } from "temporal-polyfill";
2
+ //#region src/storage.ts
3
+ var t = (t) => t instanceof e.Instant ? t : t instanceof Date ? e.Instant.fromEpochMilliseconds(t.getTime()) : e.Instant.from(t), n = (t) => e.Instant.fromEpochMilliseconds(t.getTime()), r = (e) => new Date(e.epochMilliseconds), i = (e) => t(e).toString(), a = (e) => {
4
+ if (!e) return !1;
5
+ try {
6
+ return new Intl.DateTimeFormat("en-US", { timeZone: e }), !0;
7
+ } catch {
8
+ return !1;
9
+ }
10
+ }, o = (e) => {
11
+ if (!a(e)) throw RangeError(`Invalid IANA time zone: ${JSON.stringify(e)}`);
12
+ return e;
13
+ }, s = "UTC", c = (e) => {
14
+ for (let t of [
15
+ e.userTimeZone,
16
+ e.tenantTimeZone,
17
+ e.browserTimeZone
18
+ ]) if (t && a(t)) return t;
19
+ return "UTC";
20
+ };
21
+ //#endregion
22
+ export { a, i as c, n as i, e as l, c as n, r as o, o as r, t as s, s as t };
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@voltro/datetime",
3
+ "version": "0.29.0",
4
+ "description": "The framework's opinion on time: UTC instants in storage, rendering in the viewer's timezone, and zone-aware arithmetic/formatting on the TC39 Temporal standard (via polyfill). Ships the request-scoped timezone-context seam plus pure, browser-safe date helpers.",
5
+ "keywords": [
6
+ "voltro",
7
+ "typescript",
8
+ "framework"
9
+ ],
10
+ "license": "SEE LICENSE IN LICENSE",
11
+ "homepage": "https://voltro.dev",
12
+ "bugs": {
13
+ "email": "support@voltro.dev"
14
+ },
15
+ "author": {
16
+ "name": "Voltro UG",
17
+ "url": "https://voltro.dev"
18
+ },
19
+ "type": "module",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js",
24
+ "default": "./dist/index.js"
25
+ },
26
+ "./context": {
27
+ "types": "./dist/context.d.ts",
28
+ "import": "./dist/context.js",
29
+ "default": "./dist/context.js"
30
+ }
31
+ },
32
+ "main": "./dist/index.js",
33
+ "module": "./dist/index.js",
34
+ "types": "./dist/index.d.ts",
35
+ "sideEffects": false,
36
+ "engines": {
37
+ "node": ">=24.0.0"
38
+ },
39
+ "dependencies": {
40
+ "temporal-polyfill": "^0.3.0"
41
+ },
42
+ "peerDependencies": {
43
+ "effect": "^3.22.0"
44
+ },
45
+ "peerDependenciesMeta": {
46
+ "effect": {
47
+ "optional": true
48
+ }
49
+ },
50
+ "publishConfig": {
51
+ "access": "public"
52
+ }
53
+ }