@interstellar-tools/temporal 0.1.1

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/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # @interstellar-tools/temporal
2
+
3
+ ## Installation
4
+
5
+ - [Node.js](https://nodejs.org/) version 22.9.0 or higher
6
+ - npm version 11.5.1 or higher
7
+
8
+ ::: code-group
9
+
10
+ ```shell [npm]
11
+ npm i --save @interstellar-tools/temporal
12
+ ```
13
+
14
+ ```shell [yarn]
15
+ yarn add @interstellar-tools/temporal
16
+ ```
17
+
18
+ :::
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=convert-temporal-unit.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert-temporal-unit.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/convert-temporal-unit.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,93 @@
1
+ import assert from 'node:assert/strict';
2
+ import test, { describe } from 'node:test';
3
+ import { convertTemporalUnit } from '../convert-temporal-unit';
4
+ import { JULIAN_YEAR_SECONDS, SECONDS_PER_DAY } from '@interstellar-tools/constants';
5
+ // Helpers
6
+ const EPS_ABS = 1e-9;
7
+ const EPS_REL = 1e-12;
8
+ const approxEqual = (a, b, msg) => {
9
+ const diff = Math.abs(a - b);
10
+ const scale = Math.max(1, Math.abs(a), Math.abs(b));
11
+ assert.ok(diff <= Math.max(EPS_ABS, EPS_REL * scale), msg ?? `expected ~${b}, got ${a}`);
12
+ };
13
+ const conv = (value, unit, target) => {
14
+ return convertTemporalUnit({ value, unit }, target);
15
+ };
16
+ const CANONICAL = [
17
+ 's',
18
+ 'ms',
19
+ 'μs',
20
+ 'ns',
21
+ 'ps',
22
+ 'fs',
23
+ 'as',
24
+ 'zs',
25
+ 'ys',
26
+ 'min',
27
+ 'h',
28
+ 'd',
29
+ 'yr',
30
+ 'kyr',
31
+ 'Myr',
32
+ 'Gyr'
33
+ ];
34
+ const roundTo3 = (v) => Math.round(v * 1000) / 1000;
35
+ describe('convert-temporal-unit', () => {
36
+ test('identity: all canonical units map to themselves', () => {
37
+ for (const u of CANONICAL) {
38
+ const out = conv(123.456, u, u);
39
+ assert.equal(out.unit, u);
40
+ assert.equal(roundTo3(out.value), 123.456);
41
+ }
42
+ });
43
+ test('SI submultiples: seconds ↔ ms/μs/ns', () => {
44
+ assert.equal(conv(2, 's', 'ms').value, 2000);
45
+ assert.equal(conv(2, 's', 'μs').value, 2000000);
46
+ approxEqual(conv(2, 's', 'ns').value, 2000000000);
47
+ approxEqual(conv(500, 'ms', 's').value, 0.5);
48
+ approxEqual(conv(250000, 'μs', 's').value, 0.25);
49
+ });
50
+ test('minutes/hours/days basics', () => {
51
+ assert.equal(conv(90, 'min', 'h').value, 1.5);
52
+ assert.equal(conv(2, 'h', 'min').value, 120);
53
+ assert.equal(conv(1, 'd', 'h').value, 24);
54
+ assert.equal(conv(0.5, 'd', 's').value, SECONDS_PER_DAY / 2);
55
+ });
56
+ test('Julian year family: yr ↔ d, kyr/Myr/Gyr scaling', () => {
57
+ // 1 yr = 365.25 d
58
+ approxEqual(conv(1, 'yr', 'd').value, 365.25);
59
+ approxEqual(conv(365.25, 'd', 'yr').value, 1);
60
+ // Scaling
61
+ assert.equal(conv(3, 'Myr', 'kyr').value, 3000);
62
+ assert.equal(conv(2, 'Gyr', 'yr').value, 2000000000);
63
+ // Seconds linkage
64
+ approxEqual(conv(1, 'Myr', 's').value, JULIAN_YEAR_SECONDS * 1e6);
65
+ approxEqual(conv(1e3, 'yr', 's').value, JULIAN_YEAR_SECONDS * 1e3);
66
+ });
67
+ test('extremes: yoctoseconds ↔ seconds round-trip', () => {
68
+ const s = conv(1, 'ys', 's').value;
69
+ approxEqual(s, 1e-24);
70
+ const back = conv(s, 's', 'ys').value;
71
+ approxEqual(back, 1);
72
+ });
73
+ test('round-trip property across units', () => {
74
+ const pairs = [
75
+ ['h', 's', 2.75],
76
+ ['d', 'min', 0.125],
77
+ ['yr', 'd', 3.5],
78
+ ['kyr', 'yr', 1.234],
79
+ ['Myr', 'kyr', 0.00042],
80
+ ['Gyr', 'yr', 0.009]
81
+ ];
82
+ for (const [from, mid, val] of pairs) {
83
+ const midVal = conv(val, from, mid).value;
84
+ const back = conv(midVal, mid, from).value;
85
+ approxEqual(back, val, `round-trip failed for ${from}↔${mid}`);
86
+ }
87
+ });
88
+ test('unit labels in output are canonical', () => {
89
+ const out = conv(42, 'h', 'min');
90
+ assert.equal(out.unit, 'min');
91
+ });
92
+ });
93
+ //# sourceMappingURL=convert-temporal-unit.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert-temporal-unit.spec.js","sourceRoot":"","sources":["../../src/__tests__/convert-temporal-unit.spec.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAEvC,UAAU;AACV,MAAM,OAAO,GAAG,IAAI,CAAC;AACrB,MAAM,OAAO,GAAG,KAAK,CAAC;AACtB,MAAM,WAAW,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,GAAY,EAAE,EAAE;IACzD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,EAAE,CACP,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,KAAK,CAAC,EAC1C,GAAG,IAAI,aAAa,CAAC,SAAS,CAAC,EAAE,CAClC,CAAC;AACJ,CAAC,CAAC;AACF,MAAM,IAAI,GAAG,CACX,KAAa,EACb,IAAsB,EACtB,MAAwB,EACxB,EAAE;IACF,OAAO,mBAAmB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAuB,EAAE,MAAM,CAAC,CAAC;AAC3E,CAAC,CAAC;AAEF,MAAM,SAAS,GAAuB;IACpC,GAAG;IACH,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,GAAG;IACH,GAAG;IACH,IAAI;IACJ,KAAK;IACL,KAAK;IACL,KAAK;CACN,CAAC;AAEF,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;AAE5D,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,CAAC,iDAAiD,EAAE,GAAG,EAAE;QAC3D,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAChC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YAC1B,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,OAAS,CAAC,CAAC;QAClD,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,UAAa,CAAC,CAAC;QACrD,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC7C,WAAW,CAAC,IAAI,CAAC,MAAO,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,eAAe,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,iDAAiD,EAAE,GAAG,EAAE;QAC3D,kBAAkB;QAClB,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC9C,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC9C,UAAU;QACV,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,UAAa,CAAC,CAAC;QACxD,kBAAkB;QAClB,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,mBAAmB,GAAG,GAAG,CAAC,CAAC;QAClE,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,mBAAmB,GAAG,GAAG,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACvD,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC;QACnC,WAAW,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC;QACtC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC5C,MAAM,KAAK,GAAmD;YAC5D,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC;YAChB,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC;YACnB,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC;YAChB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC;YACpB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC;YACvB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC;SACrB,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC;YACrC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC;YAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC;YAC3C,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE,yBAAyB,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=normalize-temporal-units.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-temporal-units.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/normalize-temporal-units.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,86 @@
1
+ import assert from 'node:assert/strict';
2
+ import test, { describe } from 'node:test';
3
+ import { normalizeTemporalUnit } from '../normalize-temporal-unit';
4
+ const canonical = [
5
+ 's',
6
+ 'ms',
7
+ 'μs',
8
+ 'ns',
9
+ 'ps',
10
+ 'fs',
11
+ 'as',
12
+ 'zs',
13
+ 'ys',
14
+ 'min',
15
+ 'h',
16
+ 'd',
17
+ 'yr',
18
+ 'kyr',
19
+ 'Myr',
20
+ 'Gyr'
21
+ ];
22
+ const aliasPairs = [
23
+ // seconds & submultiples
24
+ ['second', 's'],
25
+ ['seconds', 's'],
26
+ ['millisecond', 'ms'],
27
+ ['milliseconds', 'ms'],
28
+ ['microsecond', 'μs'],
29
+ ['microseconds', 'μs'],
30
+ ['us', 'μs'],
31
+ // clock units
32
+ ['minute', 'min'],
33
+ ['minutes', 'min'],
34
+ ['hour', 'h'],
35
+ ['hours', 'h'],
36
+ ['day', 'd'],
37
+ ['days', 'd'],
38
+ // years & multiples (Julian-year-based)
39
+ ['year', 'yr'],
40
+ ['years', 'yr'],
41
+ ['yr', 'yr'],
42
+ ['yrs', 'yr'],
43
+ ['kiloyear', 'kyr'],
44
+ ['kiloyears', 'kyr'],
45
+ ['kyr', 'kyr'],
46
+ // million years (geology/astro spellings)
47
+ ['megayear', 'Myr'],
48
+ ['megayears', 'Myr'],
49
+ ['megaannum', 'Myr'],
50
+ ['megaannums', 'Myr'],
51
+ ['Myr', 'Myr'],
52
+ ['Ma', 'Myr'],
53
+ // billion years
54
+ ['gigayear', 'Gyr'],
55
+ ['gigayears', 'Gyr'],
56
+ ['gigaannum', 'Gyr'],
57
+ ['gigaannums', 'Gyr'],
58
+ ['Gyr', 'Gyr'],
59
+ ['Ga', 'Gyr']
60
+ ];
61
+ describe('normalizeTemporalUnit', () => {
62
+ test('canonical units map to themselves', () => {
63
+ for (const u of canonical) {
64
+ assert.equal(normalizeTemporalUnit(u), u, `expected '${u}' → '${u}'`);
65
+ }
66
+ });
67
+ test('aliases map to canonical symbols', () => {
68
+ for (const [input, expected] of aliasPairs) {
69
+ assert.equal(normalizeTemporalUnit(input), expected, `expected '${input}' → '${expected}'`);
70
+ }
71
+ });
72
+ test('trims surrounding whitespace', () => {
73
+ assert.equal(normalizeTemporalUnit(' seconds '), 's');
74
+ assert.equal(normalizeTemporalUnit('\tus\n'), 'μs');
75
+ });
76
+ test('case-sensitive matching', () => {
77
+ assert.throws(() => normalizeTemporalUnit('Seconds'), /Unsupported unit: Seconds/, 'capitalized alias should be rejected');
78
+ assert.throws(() => normalizeTemporalUnit('US'), /Unsupported unit: US/, 'uppercase "US" should not be treated as microseconds');
79
+ });
80
+ test('rejects unknown or empty inputs', () => {
81
+ assert.throws(() => normalizeTemporalUnit(''), /Unsupported unit:/);
82
+ assert.throws(() => normalizeTemporalUnit(' '), /Unsupported unit:\s+/);
83
+ assert.throws(() => normalizeTemporalUnit('lightyear'), /Unsupported unit:/);
84
+ });
85
+ });
86
+ //# sourceMappingURL=normalize-temporal-units.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-temporal-units.spec.js","sourceRoot":"","sources":["../../src/__tests__/normalize-temporal-units.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import { TemporalInterface, TemporalUnitType } from '@interstellar-tools/types';
2
+ /**
3
+ * Seconds-per-unit lookup for all canonical {@link TemporalUnitType} symbols.
4
+ *
5
+ * ### Conventions
6
+ * - **Base**: conversions are performed via **seconds**.
7
+ * - **SI day**: `d = 86 400 s` (from {@link SECONDS_PER_DAY}).
8
+ * - **Julian year**: `yr = 365.25 d = 31 557 600 s`
9
+ * (from {@link JULIAN_YEAR_SECONDS}); `kyr/Myr/Gyr` are powers of 10 thereof.
10
+ * - Units are **canonical** and **case-sensitive** (e.g., `'μs'` uses the Unicode micro sign).
11
+ *
12
+ * $$
13
+ * \text{seconds}(u) \;=\; \text{value}\times \mathrm{SECONDS\_PER}[u]
14
+ * $$
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * // seconds per hour:
19
+ * SECONDS_PER.h; // 3600
20
+ *
21
+ * // seconds in a Julian year:
22
+ * SECONDS_PER.yr; // 31_557_600
23
+ * ```
24
+ * @hidden
25
+ */
26
+ export declare const SECONDS_PER: Record<TemporalUnitType, number>;
27
+ /**
28
+ * Convert a temporal **duration** between any two canonical {@link TemporalUnitType} units.
29
+ *
30
+ * - Uses {@link SECONDS_PER} with **seconds** as the intermediate unit.
31
+ * - Interprets `d` as the **SI day** and `yr/kyr/Myr/Gyr` via the **Julian year** convention.
32
+ * - The `time.unit` is expected to be **canonical**; if you accept aliases upstream,
33
+ * normalize them before calling (e.g., with `normalizeTemporalUnit`).
34
+ * - The `targetUnit` is normalized to a canonical symbol (idempotent for canonical input).
35
+ *
36
+ * $$
37
+ * \text{value}_{\text{target}}
38
+ * \;=\;
39
+ * \frac{\text{value}_{\text{in}} \cdot \mathrm{SECONDS\_PER}[u_{\text{in}}]}
40
+ * {\mathrm{SECONDS\_PER}[u_{\text{out}}]}
41
+ * $$
42
+ *
43
+ * @param time Input duration `{ value, unit }` in canonical units.
44
+ * @param targetUnit Desired canonical output unit (will be normalized).
45
+ * @returns A new `{ value, unit }` where `unit` is the canonical target symbol.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * convertTemporalUnit({ value: 2, unit: 'h' }, 'min');
50
+ * // → { value: 120, unit: 'min' }
51
+ *
52
+ * convertTemporalUnit({ value: 1, unit: 'd' }, 's');
53
+ * // → { value: 86_400, unit: 's' }
54
+ *
55
+ * convertTemporalUnit({ value: 3, unit: 'Myr' }, 'kyr');
56
+ * // → { value: 3000, unit: 'kyr' }
57
+ *
58
+ * convertTemporalUnit({ value: 1, unit: 'yr' }, 'd');
59
+ * // → { value: 365.25, unit: 'd' }
60
+ * ```
61
+ *
62
+ * @see SECONDS_PER_DAY
63
+ * @see JULIAN_YEAR_SECONDS
64
+ * @see normalizeTemporalUnit
65
+ */
66
+ export declare const convertTemporalUnit: (time: TemporalInterface, targetUnit: TemporalUnitType) => TemporalInterface;
67
+ //# sourceMappingURL=convert-temporal-unit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert-temporal-unit.d.ts","sourceRoot":"","sources":["../src/convert-temporal-unit.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAIhF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAsBxD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,mBAAmB,GAC9B,MAAM,iBAAiB,EACvB,YAAY,gBAAgB,KAC3B,iBASF,CAAC"}
@@ -0,0 +1,96 @@
1
+ import { JULIAN_YEAR_SECONDS, SECONDS_PER_DAY } from '@interstellar-tools/constants';
2
+ import { normalizeTemporalUnit } from './normalize-temporal-unit';
3
+ /**
4
+ * Seconds-per-unit lookup for all canonical {@link TemporalUnitType} symbols.
5
+ *
6
+ * ### Conventions
7
+ * - **Base**: conversions are performed via **seconds**.
8
+ * - **SI day**: `d = 86 400 s` (from {@link SECONDS_PER_DAY}).
9
+ * - **Julian year**: `yr = 365.25 d = 31 557 600 s`
10
+ * (from {@link JULIAN_YEAR_SECONDS}); `kyr/Myr/Gyr` are powers of 10 thereof.
11
+ * - Units are **canonical** and **case-sensitive** (e.g., `'μs'` uses the Unicode micro sign).
12
+ *
13
+ * $$
14
+ * \text{seconds}(u) \;=\; \text{value}\times \mathrm{SECONDS\_PER}[u]
15
+ * $$
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * // seconds per hour:
20
+ * SECONDS_PER.h; // 3600
21
+ *
22
+ * // seconds in a Julian year:
23
+ * SECONDS_PER.yr; // 31_557_600
24
+ * ```
25
+ * @hidden
26
+ */
27
+ export const SECONDS_PER = {
28
+ // SI base & submultiples
29
+ s: 1,
30
+ ms: 1e-3,
31
+ μs: 1e-6,
32
+ ns: 1e-9,
33
+ ps: 1e-12,
34
+ fs: 1e-15,
35
+ as: 1e-18,
36
+ zs: 1e-21,
37
+ ys: 1e-24,
38
+ // convenient larger units
39
+ min: 60,
40
+ h: 60 * 60,
41
+ d: SECONDS_PER_DAY,
42
+ // year family (Julian-year-based)
43
+ yr: JULIAN_YEAR_SECONDS,
44
+ kyr: JULIAN_YEAR_SECONDS * 1e3,
45
+ Myr: JULIAN_YEAR_SECONDS * 1e6,
46
+ Gyr: JULIAN_YEAR_SECONDS * 1e9
47
+ };
48
+ /**
49
+ * Convert a temporal **duration** between any two canonical {@link TemporalUnitType} units.
50
+ *
51
+ * - Uses {@link SECONDS_PER} with **seconds** as the intermediate unit.
52
+ * - Interprets `d` as the **SI day** and `yr/kyr/Myr/Gyr` via the **Julian year** convention.
53
+ * - The `time.unit` is expected to be **canonical**; if you accept aliases upstream,
54
+ * normalize them before calling (e.g., with `normalizeTemporalUnit`).
55
+ * - The `targetUnit` is normalized to a canonical symbol (idempotent for canonical input).
56
+ *
57
+ * $$
58
+ * \text{value}_{\text{target}}
59
+ * \;=\;
60
+ * \frac{\text{value}_{\text{in}} \cdot \mathrm{SECONDS\_PER}[u_{\text{in}}]}
61
+ * {\mathrm{SECONDS\_PER}[u_{\text{out}}]}
62
+ * $$
63
+ *
64
+ * @param time Input duration `{ value, unit }` in canonical units.
65
+ * @param targetUnit Desired canonical output unit (will be normalized).
66
+ * @returns A new `{ value, unit }` where `unit` is the canonical target symbol.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * convertTemporalUnit({ value: 2, unit: 'h' }, 'min');
71
+ * // → { value: 120, unit: 'min' }
72
+ *
73
+ * convertTemporalUnit({ value: 1, unit: 'd' }, 's');
74
+ * // → { value: 86_400, unit: 's' }
75
+ *
76
+ * convertTemporalUnit({ value: 3, unit: 'Myr' }, 'kyr');
77
+ * // → { value: 3000, unit: 'kyr' }
78
+ *
79
+ * convertTemporalUnit({ value: 1, unit: 'yr' }, 'd');
80
+ * // → { value: 365.25, unit: 'd' }
81
+ * ```
82
+ *
83
+ * @see SECONDS_PER_DAY
84
+ * @see JULIAN_YEAR_SECONDS
85
+ * @see normalizeTemporalUnit
86
+ */
87
+ export const convertTemporalUnit = (time, targetUnit) => {
88
+ const normalizedTargetUnit = normalizeTemporalUnit(targetUnit);
89
+ const { value, unit } = time;
90
+ // Convert input to seconds
91
+ const inSeconds = value * SECONDS_PER[unit];
92
+ // Convert seconds to target
93
+ const convertedValue = inSeconds / SECONDS_PER[normalizedTargetUnit];
94
+ return { value: convertedValue, unit: normalizedTargetUnit };
95
+ };
96
+ //# sourceMappingURL=convert-temporal-unit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert-temporal-unit.js","sourceRoot":"","sources":["../src/convert-temporal-unit.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAqC;IAC3D,yBAAyB;IACzB,CAAC,EAAE,CAAC;IACJ,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,KAAK;IACT,EAAE,EAAE,KAAK;IACT,EAAE,EAAE,KAAK;IACT,EAAE,EAAE,KAAK;IACT,EAAE,EAAE,KAAK;IAET,0BAA0B;IAC1B,GAAG,EAAE,EAAE;IACP,CAAC,EAAE,EAAE,GAAG,EAAE;IACV,CAAC,EAAE,eAAe;IAElB,kCAAkC;IAClC,EAAE,EAAE,mBAAmB;IACvB,GAAG,EAAE,mBAAmB,GAAG,GAAG;IAC9B,GAAG,EAAE,mBAAmB,GAAG,GAAG;IAC9B,GAAG,EAAE,mBAAmB,GAAG,GAAG;CAC/B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,IAAuB,EACvB,UAA4B,EACT,EAAE;IACrB,MAAM,oBAAoB,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAC/D,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;IAC7B,2BAA2B;IAC3B,MAAM,SAAS,GAAG,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC5C,4BAA4B;IAC5B,MAAM,cAAc,GAAG,SAAS,GAAG,WAAW,CAAC,oBAAoB,CAAC,CAAC;IAErE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;AAC/D,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './convert-temporal-unit';
2
+ export * from './normalize-temporal-unit';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AAExC,cAAc,2BAA2B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './convert-temporal-unit';
2
+ export * from './normalize-temporal-unit';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AAExC,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,116 @@
1
+ import type { TemporalUnitType } from '@interstellar-tools/types';
2
+ /**
3
+ * Lookup table that **normalizes user-facing time unit aliases** (and the canonical
4
+ * symbols themselves) to a single, canonical {@link TemporalUnitType}.
5
+ *
6
+ * ## Purpose
7
+ * - Centralizes all **string → symbol** normalization (e.g., `"seconds"` → `"s"`, `"us"` → `"μs"`).
8
+ * - Ensures downstream math uses only **canonical units** (`s`, `ms`, `μs`, `min`, `h`, `d`, `yr`, `kyr`, `Myr`, `Gyr`).
9
+ *
10
+ * ## Conventions & semantics
11
+ * - **Durations only** (no timestamp/"ago" meaning). Geology-style tokens (`Ma`, `Ga`, `megaannum`, `gigaannum`)
12
+ * are treated as **durations** and normalized to `Myr`/`Gyr`.
13
+ * - **Day** is [SI](https://en.wikipedia.org/wiki/International_System_of_Units) day: exactly **86 400 s**.
14
+ * - **Year family** (`yr`, `kyr`, `Myr`, `Gyr`) is the **Julian year** convention: **365.25 d = 31 557 600 s**.
15
+ * - **Case-sensitive** and exact matching. The ASCII alias `"us"` is accepted and normalized to the Unicode `μs`.
16
+ *
17
+ * ## Usage pattern
18
+ * - Accept `TemporalUnitAliasType | TemporalUnitType` at your boundaries.
19
+ * - Normalize with this map.
20
+ * - Store/compute exclusively with canonical {@link TemporalUnitType}.
21
+ *
22
+ * ::: tip
23
+ *
24
+ * If you require runtime immutability, wrap with `Object.freeze(NORMALIZE_UNIT)`.
25
+ *
26
+ * :::
27
+ *
28
+ * @see https://www.bipm.org/en/publications/si-brochure ([SI](https://en.wikipedia.org/wiki/International_System_of_Units) Brochure — second & day)
29
+ * @see https://en.wikipedia.org/wiki/Julian_year_(astronomy) (Julian year for yr/kyr/Myr/Gyr)
30
+ */
31
+ export declare const NORMALIZE_UNIT: {
32
+ readonly s: "s";
33
+ readonly ms: "ms";
34
+ readonly μs: "μs";
35
+ readonly ns: "ns";
36
+ readonly ps: "ps";
37
+ readonly fs: "fs";
38
+ readonly as: "as";
39
+ readonly zs: "zs";
40
+ readonly ys: "ys";
41
+ readonly min: "min";
42
+ readonly h: "h";
43
+ readonly d: "d";
44
+ readonly yr: "yr";
45
+ readonly kyr: "kyr";
46
+ readonly Myr: "Myr";
47
+ readonly Gyr: "Gyr";
48
+ readonly second: "s";
49
+ readonly seconds: "s";
50
+ readonly millisecond: "ms";
51
+ readonly milliseconds: "ms";
52
+ readonly microsecond: "μs";
53
+ readonly microseconds: "μs";
54
+ readonly us: "μs";
55
+ readonly minute: "min";
56
+ readonly minutes: "min";
57
+ readonly hour: "h";
58
+ readonly hours: "h";
59
+ readonly day: "d";
60
+ readonly days: "d";
61
+ readonly year: "yr";
62
+ readonly years: "yr";
63
+ readonly yrs: "yr";
64
+ readonly kiloyear: "kyr";
65
+ readonly kiloyears: "kyr";
66
+ readonly megayear: "Myr";
67
+ readonly megayears: "Myr";
68
+ readonly megaannum: "Myr";
69
+ readonly megaannums: "Myr";
70
+ readonly Ma: "Myr";
71
+ readonly gigayear: "Gyr";
72
+ readonly gigayears: "Gyr";
73
+ readonly gigaannum: "Gyr";
74
+ readonly gigaannums: "Gyr";
75
+ readonly Ga: "Gyr";
76
+ };
77
+ /**
78
+ * Normalize a user-provided **temporal unit string** into a canonical {@link TemporalUnitType}.
79
+ *
80
+ * - Trims surrounding whitespace.
81
+ * - Accepts both **canonical symbols** (e.g., `"s"`, `"ms"`, `"μs"`, `"min"`, `"h"`, `"d"`, `"yr"`, `"kyr"`, `"Myr"`, `"Gyr"`)
82
+ * and **aliases** (e.g., `"seconds"`, `"milliseconds"`, `"us"`, `"hours"`, `"years"`, `"Ma"`, `"Ga"`),
83
+ * using {@link NORMALIZE_UNIT} as the single source of truth.
84
+ * - Returns a **canonical** unit suitable for arithmetic, storage, and serialization.
85
+ *
86
+ * ### Conventions
87
+ * - **Durations only** (no timestamp or "ago" semantics). Geology-style tokens like `"Ma"`/`"Ga"` are
88
+ * interpreted as durations and normalized to `"Myr"`/`"Gyr"`.
89
+ * - **Case-sensitive** exact match against {@link NORMALIZE_UNIT}. For example, `"Seconds"` (capital S)
90
+ * will fail; use `"seconds"` instead, or pre-normalize casing upstream if desired.
91
+ * - The ASCII alias `"us"` is accepted and normalized to the Unicode microsecond symbol `"μs"`.
92
+ *
93
+ * @param u - The input unit string. Leading/trailing whitespace is ignored; content is **case-sensitive**.
94
+ * @returns The canonical {@link TemporalUnitType} (e.g., `"s"`, `"ms"`, `"μs"`, `"min"`, `"h"`, `"d"`, `"yr"`, `"kyr"`, `"Myr"`, `"Gyr"`).
95
+ *
96
+ * @throws {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} If `u` does not match any known key in {@link NORMALIZE_UNIT}.
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * // Canonical conversion using the normalized unit:
101
+ * const unit = normalizeTemporalUnit(' seconds '); // → 's'
102
+ * const valueInSeconds = 2 * (unit === 's' ? 1 : NaN); // 2
103
+ *
104
+ * normalizeTemporalUnit('us'); // → 'μs'
105
+ * normalizeTemporalUnit('Myr'); // → 'Myr' (already canonical)
106
+ * normalizeTemporalUnit('Ma'); // → 'Myr' (geology-style alias)
107
+ * normalizeTemporalUnit('Ga'); // → 'Gyr'
108
+ * // normalizeTemporalUnit('Seconds'); // throws (case-sensitive)
109
+ * ```
110
+ *
111
+ * @see {@link NORMALIZE_UNIT} for the complete alias→canonical mapping.
112
+ * @see https://www.bipm.org/en/publications/si-brochure (SI Brochure — second/day)
113
+ * @see https://en.wikipedia.org/wiki/Julian_year_(astronomy) (Julian year for yr/kyr/Myr/Gyr)
114
+ */
115
+ export declare const normalizeTemporalUnit: (u: string) => TemporalUnitType;
116
+ //# sourceMappingURL=normalize-temporal-unit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-temporal-unit.d.ts","sourceRoot":"","sources":["../src/normalize-temporal-unit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoD1B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,qBAAqB,GAAI,GAAG,MAAM,KAAG,gBAOjD,CAAC"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Lookup table that **normalizes user-facing time unit aliases** (and the canonical
3
+ * symbols themselves) to a single, canonical {@link TemporalUnitType}.
4
+ *
5
+ * ## Purpose
6
+ * - Centralizes all **string → symbol** normalization (e.g., `"seconds"` → `"s"`, `"us"` → `"μs"`).
7
+ * - Ensures downstream math uses only **canonical units** (`s`, `ms`, `μs`, `min`, `h`, `d`, `yr`, `kyr`, `Myr`, `Gyr`).
8
+ *
9
+ * ## Conventions & semantics
10
+ * - **Durations only** (no timestamp/"ago" meaning). Geology-style tokens (`Ma`, `Ga`, `megaannum`, `gigaannum`)
11
+ * are treated as **durations** and normalized to `Myr`/`Gyr`.
12
+ * - **Day** is [SI](https://en.wikipedia.org/wiki/International_System_of_Units) day: exactly **86 400 s**.
13
+ * - **Year family** (`yr`, `kyr`, `Myr`, `Gyr`) is the **Julian year** convention: **365.25 d = 31 557 600 s**.
14
+ * - **Case-sensitive** and exact matching. The ASCII alias `"us"` is accepted and normalized to the Unicode `μs`.
15
+ *
16
+ * ## Usage pattern
17
+ * - Accept `TemporalUnitAliasType | TemporalUnitType` at your boundaries.
18
+ * - Normalize with this map.
19
+ * - Store/compute exclusively with canonical {@link TemporalUnitType}.
20
+ *
21
+ * ::: tip
22
+ *
23
+ * If you require runtime immutability, wrap with `Object.freeze(NORMALIZE_UNIT)`.
24
+ *
25
+ * :::
26
+ *
27
+ * @see https://www.bipm.org/en/publications/si-brochure ([SI](https://en.wikipedia.org/wiki/International_System_of_Units) Brochure — second & day)
28
+ * @see https://en.wikipedia.org/wiki/Julian_year_(astronomy) (Julian year for yr/kyr/Myr/Gyr)
29
+ */
30
+ export const NORMALIZE_UNIT = {
31
+ // canonical already map to themselves:
32
+ s: 's',
33
+ ms: 'ms',
34
+ μs: 'μs',
35
+ ns: 'ns',
36
+ ps: 'ps',
37
+ fs: 'fs',
38
+ as: 'as',
39
+ zs: 'zs',
40
+ ys: 'ys',
41
+ min: 'min',
42
+ h: 'h',
43
+ d: 'd',
44
+ yr: 'yr',
45
+ kyr: 'kyr',
46
+ Myr: 'Myr',
47
+ Gyr: 'Gyr',
48
+ // aliases → canonical
49
+ second: 's',
50
+ seconds: 's',
51
+ millisecond: 'ms',
52
+ milliseconds: 'ms',
53
+ microsecond: 'μs',
54
+ microseconds: 'μs',
55
+ us: 'μs',
56
+ minute: 'min',
57
+ minutes: 'min',
58
+ hour: 'h',
59
+ hours: 'h',
60
+ day: 'd',
61
+ days: 'd',
62
+ year: 'yr',
63
+ years: 'yr',
64
+ yrs: 'yr',
65
+ kiloyear: 'kyr',
66
+ kiloyears: 'kyr',
67
+ megayear: 'Myr',
68
+ megayears: 'Myr',
69
+ megaannum: 'Myr',
70
+ megaannums: 'Myr',
71
+ Ma: 'Myr',
72
+ gigayear: 'Gyr',
73
+ gigayears: 'Gyr',
74
+ gigaannum: 'Gyr',
75
+ gigaannums: 'Gyr',
76
+ Ga: 'Gyr'
77
+ };
78
+ /**
79
+ * Normalize a user-provided **temporal unit string** into a canonical {@link TemporalUnitType}.
80
+ *
81
+ * - Trims surrounding whitespace.
82
+ * - Accepts both **canonical symbols** (e.g., `"s"`, `"ms"`, `"μs"`, `"min"`, `"h"`, `"d"`, `"yr"`, `"kyr"`, `"Myr"`, `"Gyr"`)
83
+ * and **aliases** (e.g., `"seconds"`, `"milliseconds"`, `"us"`, `"hours"`, `"years"`, `"Ma"`, `"Ga"`),
84
+ * using {@link NORMALIZE_UNIT} as the single source of truth.
85
+ * - Returns a **canonical** unit suitable for arithmetic, storage, and serialization.
86
+ *
87
+ * ### Conventions
88
+ * - **Durations only** (no timestamp or "ago" semantics). Geology-style tokens like `"Ma"`/`"Ga"` are
89
+ * interpreted as durations and normalized to `"Myr"`/`"Gyr"`.
90
+ * - **Case-sensitive** exact match against {@link NORMALIZE_UNIT}. For example, `"Seconds"` (capital S)
91
+ * will fail; use `"seconds"` instead, or pre-normalize casing upstream if desired.
92
+ * - The ASCII alias `"us"` is accepted and normalized to the Unicode microsecond symbol `"μs"`.
93
+ *
94
+ * @param u - The input unit string. Leading/trailing whitespace is ignored; content is **case-sensitive**.
95
+ * @returns The canonical {@link TemporalUnitType} (e.g., `"s"`, `"ms"`, `"μs"`, `"min"`, `"h"`, `"d"`, `"yr"`, `"kyr"`, `"Myr"`, `"Gyr"`).
96
+ *
97
+ * @throws {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} If `u` does not match any known key in {@link NORMALIZE_UNIT}.
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * // Canonical conversion using the normalized unit:
102
+ * const unit = normalizeTemporalUnit(' seconds '); // → 's'
103
+ * const valueInSeconds = 2 * (unit === 's' ? 1 : NaN); // 2
104
+ *
105
+ * normalizeTemporalUnit('us'); // → 'μs'
106
+ * normalizeTemporalUnit('Myr'); // → 'Myr' (already canonical)
107
+ * normalizeTemporalUnit('Ma'); // → 'Myr' (geology-style alias)
108
+ * normalizeTemporalUnit('Ga'); // → 'Gyr'
109
+ * // normalizeTemporalUnit('Seconds'); // throws (case-sensitive)
110
+ * ```
111
+ *
112
+ * @see {@link NORMALIZE_UNIT} for the complete alias→canonical mapping.
113
+ * @see https://www.bipm.org/en/publications/si-brochure (SI Brochure — second/day)
114
+ * @see https://en.wikipedia.org/wiki/Julian_year_(astronomy) (Julian year for yr/kyr/Myr/Gyr)
115
+ */
116
+ export const normalizeTemporalUnit = (u) => {
117
+ const k = u.trim();
118
+ const v = NORMALIZE_UNIT[k];
119
+ if (!v)
120
+ throw new Error(`Unsupported unit: ${u}`);
121
+ return v;
122
+ };
123
+ //# sourceMappingURL=normalize-temporal-unit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-temporal-unit.js","sourceRoot":"","sources":["../src/normalize-temporal-unit.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,uCAAuC;IACvC,CAAC,EAAE,GAAG;IACN,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,KAAK;IACV,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IAEV,sBAAsB;IACtB,MAAM,EAAE,GAAG;IACX,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,IAAI;IACjB,YAAY,EAAE,IAAI;IAClB,WAAW,EAAE,IAAI;IACjB,YAAY,EAAE,IAAI;IAClB,EAAE,EAAE,IAAI;IACR,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,KAAK;IACd,IAAI,EAAE,GAAG;IACT,KAAK,EAAE,GAAG;IACV,GAAG,EAAE,GAAG;IACR,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;IACX,GAAG,EAAE,IAAI;IAET,QAAQ,EAAE,KAAK;IACf,SAAS,EAAE,KAAK;IAChB,QAAQ,EAAE,KAAK;IACf,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE,KAAK;IACjB,EAAE,EAAE,KAAK;IACT,QAAQ,EAAE,KAAK;IACf,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE,KAAK;IACjB,EAAE,EAAE,KAAK;CAIV,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAS,EAAoB,EAAE;IACnE,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACnB,MAAM,CAAC,GAAG,cAAc,CAAC,CAAgC,CAAC,CAAC;IAE3D,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAElD,OAAO,CAAC,CAAC;AACX,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@interstellar-tools/temporal",
3
+ "version": "0.1.1",
4
+ "description": "temporal",
5
+ "keywords": [
6
+ "temporal"
7
+ ],
8
+ "homepage": "https://phun-ky.net/projects/interstellar-tools",
9
+ "bugs": {
10
+ "url": "https://github.com/phun-ky/interstellar-tools/issues"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/phun-ky/interstellar-tools.git"
15
+ },
16
+ "funding": "https://github.com/phun-ky/interstellar-tools?sponsor=1",
17
+ "license": "MIT",
18
+ "author": "Alexander Vassbotn Røyne-Helgesen <alexander@phun-ky.net>",
19
+ "type": "module",
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "default": "./dist/index.js"
26
+ }
27
+ },
28
+ "files": [
29
+ "dist"
30
+ ],
31
+ "sideEffects": false,
32
+ "scripts": {
33
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
34
+ "release": "release-it",
35
+ "test": "tsx --test **/__tests__/**/*.spec.ts",
36
+ "pretest:ci": "rm -rf coverage && mkdir -p coverage",
37
+ "test:ci": "glob -c \"node --import tsx --test --no-warnings --experimental-test-coverage --test-reporter=cobertura --test-reporter-destination=coverage/cobertura-coverage.xml --test-reporter=spec --test-reporter-destination=stdout\" \"**/__tests__/**/*.spec.ts\""
38
+ },
39
+ "dependencies": {
40
+ "@interstellar-tools/types": "^0.1.0",
41
+ "@interstellar-tools/constants": "^0.1.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^24.0.3",
45
+ "eslint": "^9.27.0",
46
+ "eslint-config-phun-ky": "^1.0.3",
47
+ "prettier": "^3.5.3",
48
+ "typescript": "^5.8.3"
49
+ },
50
+ "engines": {
51
+ "node": ">=22.9.0",
52
+ "npm": ">=11.5.1"
53
+ },
54
+ "publishConfig": {
55
+ "access": "public"
56
+ }
57
+ }