Skip to content

πŸ“œ Version 3.x History ​

[v3.5.0] - 2026-06-28 ​

✨ What's New β€” Unified Plugin API ​

Tempo v3.5.0 introduces a brand new barrel export for plugin developers: @magmacomputing/tempo/plugin-api.

This new endpoint centralizes all plugin-authoring utilities (defineModule, defineExtension, defineTerm) and internal types into a single location. This architecture significantly cleans up application-level code by formally separating end-user imports from Plugin Developer imports.

If you are developing a custom plugin, you simply update your imports:

typescript
// Old Way
// import { defineModule } from '@magmacomputing/tempo/plugin';

// New Way
import { defineModule } from '@magmacomputing/tempo/plugin-api';

πŸ“š Documentation & Ecosystem ​

  • Static vs Smart CDNs: We have completely overhauled the installation documentation to clarify the distinction between using Smart CDNs (like esm.sh which automatically resolve dependencies) for prototyping, versus Static CDNs (with manual importmap configurations) for hardened production environments.
  • Evergreen Temporal Wording: Removed explicit version claims for upcoming Node.js native Temporal support, future-proofing our guides against shifting V8 release timelines.

[v3.4.0] - 2026-06-26 ​

✨ What's New β€” Dynamic Format Tokens ​

Tempo's formatting engine now supports completely custom format evaluators via the registry.tokens configuration. This allows you to define your own syntax tokens that execute complex math or delegate deeply localized formatting directly to the native Intl API.

typescript
Tempo.init({
	locale: 'fr-FR',
	registry: {
		tokens: {
			'wkd-fr': (zdt, { config }) => {
				const dtOptions = config?.intl?.dateTimeFormat ?? {};
				return zdt.toLocaleString(config?.locale ?? 'en', { ...dtOptions, weekday: 'long' });
			}
		}
	}
});

const t = new Tempo('2024-05-20');
t.format('{wkd-fr}'); // "lundi"

✨ Compound Token Modifiers ​

The compound date tokens ({dmy}, {mdy}, {ymd}) now support the :yy modifier to easily truncate their internal year components to 2 digits.

typescript
t.format('{dmy:yy}'); // "200524"

This officially supersedes the legacy *6 tokens (e.g., {dmy6}) which have now been deprecated from documentation to keep the API clean, though they remain fully supported in the engine for backwards compatibility.


[v3.3.1] - 2026-06-22 ​

✨ What's New β€” Slick Object Mutations ​

Tempo has always allowed jumping to boundaries using the Slick Shorthand (#qtr.>2q1) or semantic strings (next Friday). v3.3.1 extends this power directly to .set() object properties.

You can now use SLICK_KEYS (yy, mm, ww, dd, hh, mi, ss, wkd) as object keys in .set(), passing a directional string payload:

typescript
const t = new Tempo('2024-05-20'); // Monday

// Jump forward two months
t.set({ mm: '>2' }); // July 20

// Jump to the next Friday
t.set({ wkd: '>Fri' }); // May 24

// "Double-negation" math is fully supported:
t.set({ mm: '<-3' }); // Equivalent to >3

This makes relative programmatic date construction cleaner and keeps numeric jumps distinct from absolute assignments.

⚑ Extended Shorthand Modifiers ​

The Slick Regex parser has been upgraded to natively support equality logic and aliases. Modifiers like >=, <=, =, + (alias for >), and - (alias for <) are now fully supported for both numeric offsets and semantic loops (like wkd).

typescript
// Jump to next Monday, or stay on Monday if today is Monday
t.set({ wkd: '>=Mon' });

[v3.3.0] - 2026-06-21 ​

✨ What's New β€” Localized Modifier Registry ​

Tempo's relative-date keywords (next, last, this, ago, hence) were previously hardcoded as English-only constructs built into the core regex engine. v3.3.0 opens this up completely.

You can now register your own locale-specific words for any directional operator using registry.modifiers. These words integrate transparently with all standard parsing paths β€” prefix position, suffix position, and the high-performance # slick shorthand:

typescript
Tempo.init({
  locale: 'fr-FR',            // teaches Tempo French months & weekdays via Intl
  registry: {
    modifiers: {
      '>': ['prochain', 'suivant'],   // "next" synonyms
      '<': ['dernier', 'passΓ©'],      // "last / previous" synonyms
      '=': ['ce', 'cette'],           // "this" synonyms
    }
  }
});

new Tempo('vendredi prochain');    // βœ… "next Friday" β€” fully French
new Tempo('1 mai prochain');       // βœ… "next May 1st"
new Tempo('#qtr.dernier');         // βœ… "previous quarter" via slick shorthand

English keywords (next, last, ago, hence, this) remain active by default and are additively merged β€” you never lose built-in behaviour when adding your own.

πŸ—οΈ Internal Refactoring ​

  • Frozen Default Registry Fixed: The internal Default configuration object is wrapped in a deep-freeze Proxy (secure()). Previously, every Tempo.init() call silently failed to write formats, locales, and modifiers into the frozen registry sub-object, logging three setProperty warnings per call and abandoning the writes. The registry is now correctly shallow-cloned into a mutable copy on initialization.

  • Lexer Token Cleanup: All hardcoded English modifier keywords have been stripped from the core regex tokens (Match.modifier, Match.shorthand, Match.slick). The engine now operates purely on symbolic operators (>, <, =, +, -) internally and resolves all natural-language words through the registry at runtime.

  • Pre-filter Guard Accuracy: Refined the numeric-safety guard bypass to trigger only when the input actually contains a registered modifier keyword. Previously the guard was bypassed unconditionally whenever modifier config was present, which could silently accept invalid nanosecond epoch strings.

⚑ Slick Modifier Semantics ​

Localized slick modifiers behave identically to their symbolic counterparts. #qtr.prochain is an exact alias for #qtr.>:

  • From inside Q2 (any day from April 1 to June 29) β†’ July 1 (start of Q3)
  • From June 30 (last day of Q2) β†’ July 1 (start of Q3)
  • From July 1 (first day of Q3) β†’ October 1 (start of Q4)

This mirrors how next Friday works: from any non-Friday you get the very next Friday; if you are already on Friday, you get the following Friday. Fully deterministic β€” "next" always means "the start of the next occurrence of this term".


[v3.2.3] - 2026-06-20 ​

✨ What's New β€” Project Scaffolding ​

  • tempo.config.ts Pattern: Introduced centralized project configuration via a discoverable tempo.config.ts / tempo.config.js file. This mirrors the vite.config.ts / tailwind.config.js convention β€” one file, one place, loaded once.
  • Tempo.bootstrap(): A new async entry point that auto-discovers and loads your tempo.config.ts before any domain logic runs. Safe to await at application startup.
  • CLI Scaffold: npx @magmacomputing/tempo scaffold:all bootstraps a tempo.config.ts and HTML sandbox into your project in seconds.

[v3.2.2] - 2026-06-18 ​

✨ What's New ​

  • Compact Date Tokens: New 6-digit compact format tokens {dmy6}, {mdy6}, {ymd6} (e.g. 200626), plus ISO week-of-year helpers {yywy} and {yyww}.
  • {wy} Rename: The former {ww} token is now {wy} (week-of-year) to eliminate visual ambiguity with structural format tokens.

πŸ—οΈ Internal Refactoring ​

  • Recursive deepMerge Hardened: The Intl options merge pipeline now uses a fully recursive deepMerge rather than a shallow spread, preventing nested keys like intl.dateTimeFormat from clobbering intl.relativeTimeFormat.
  • Prototype Pollution Guards: Added strict guards against __proto__, constructor, and prototype key assignments in deepMerge and deepFreeze utilities.

[v3.2.1] - 2026-06-17 ​

✨ What's New ​

  • Ordinal Localization Fallback: Added support for custom Intl.PluralRules dictionaries. By supplying an ordinal dictionary inside your global locales registry, Tempo natively evaluates the active plural category (e.g., 'one', 'other') and appends the localized suffix automatically (such as '1er' and '15e' for French).

πŸ“š Documentation & Ecosystem ​

  • Improved Cookbook Ergonomics: Extensively reorganized the tempo.cookbook.md to make it easier to read. Related functionality is now logically grouped togetherβ€”for example, merging native and semantic .add() math examples, and expanding on boundary .set() capabilities.
  • Clarified Configurations: Updated tempo.config.md to remove outdated properties and explicitly document nested options like intl.durationFormat.
  • REPL Traps: Added prominent warnings to the documentation about the strict idempotency of Tempo.init(), helping new developers avoid silent configuration failures in hot-reload and REPL environments.

πŸ—οΈ Internal Refactoring ​

  • Alias Collision Prevention: Hardened the sandbox alias detection engine to prevent redundant collision warnings in the console when Tempo.init is invoked in sandboxed contexts.

[v3.2.0] - 2026-06-16 ​

✨ What's New ​

  • Multi-lingual Parsing: The locale configuration property now officially accepts an array of strings (string | string[]). This enables the ParseModule to intelligently extract terminology from multiple languages simultaneously, generating a single engine capable of parsing dates from any of the specified locales interchangeably.
  • Intl.DateTimeFormatOptions Passthrough: The .format() method now officially supports passing a native Intl.DateTimeFormatOptions object. This provides a highly flexible, "humanized" wrapper around the rigid Temporal API for complex cultural formatting (e.g., Arabic numerals, Japanese Reiwa eras).
  • BigInt Overload for Epoch Nanoseconds: The {nano} formatting token (epoch nanoseconds) correctly coerces to and returns a precision-preserving BigInt instead of a string, bypassing standard Number limits.

πŸ“š Documentation & Ecosystem ​

  • Domain-Locked Licensing: Stabilized the premium plugin licensing engine with a robust domain-locked validation mechanism.
  • SSR & VitePress Fixes: Fixed Temporal is not defined crashes during SSR builds and simplified our documentation pipeline by removing heavy Markdown plugins.
  • New Locale Guides: Added comprehensive Internationalization (tempo.locale.md) guides to the primary navigation structure.

πŸ—οΈ Internal Refactoring ​

  • O(1) Locale Traceability: Upgraded the internal dictionary architecture. The Normalizer can now resolve the winning language of a matched token in pure O(1) time without any expensive Regex sub-capture scanning.
  • Polyfill Formatting Bypass: Bypassed a known bug in the Temporal polyfill's toLocaleString() method that incorrectly dropped Kanji constraints in Japanese formatting contexts, guaranteeing precise Intl fallback correctness.
  • Parser Map Safety: Architecturally split the internal reverse-lookup into distinct monthMap and weekdayMap dictionaries, eliminating the risk of cross-locale abbreviation collisions (e.g., if "mai" is a month in one language but a weekday in another).

[v3.1.0] - 2026-06-13 ​

✨ What's New ​

  • Chained Formatting Modifiers: A powerful new format modifier engine ({mon:locale:upper}) allowing dynamic casing (:upper, :lower), ordinal suffixes (:ord), and deep localization (:locale) dynamically via the native Intl API.
  • Auto-Localization Engine: Global configurations for format: { localize: true } and parse: { localize: true } provide a massive leap forward in out-of-the-box internationalization. Tempo can now intelligently parse localized input (months, weekdays, relative terms like 'demain') and automatically format localized output using memoized, high-performance Intl strategies.
  • Global locales Registry: Centralized management for augmenting specific term strings per locale globally across instances via Tempo.init({ locale: 'fr-FR', registry: { locales: { ... } } }).

πŸ—οΈ Internal Refactoring ​

  • Intl Instantiation: Upgraded internal architectures to memoize and pool Intl.DateTimeFormat objects seamlessly, ensuring parsing localization generation and output formatting impose virtually zero performance hit on hot execution paths.
  • Term Localization: Upgraded the Term formatting resolution pipeline to support falling back across a strict precedence: Global Registry > Plugin Bundled Dictionary > term's existing label/value.

[v3.0.0] - 2026-06-08 ​

🚨 Major Breaking Changes ​

  • Term Registry Consolidation: Removed the legacy and deprecated term property from the Discovery configuration object. All Term-based plugins must now be registered via the terms (plural) array.
  • Shorthand Configuration Removal: Removed support for shorthand root-level properties in the Discovery object that have been superseded by nested configuration groups:
    • relativeTime shorthand has been removed; use intl.relativeTime instead.
    • term shorthand has been removed; use terms instead.
  • Strict Parsing Mode: The parser now enforces a stricter guard check by default, reducing the likelihood of "false positive" matches on ambiguous strings.
  • Ticker Module Extraction: To lighten the core bundle, the TickerModule has been extracted into its own standalone premium plugin (@magmacomputing/tempo-plugin-ticker). It is protected by a License Key via the Tempo Registry.

✨ What's New ​

  • Formatting Module Additions: Added new compact date tokens ({dmy}, {mdy}, {ymd}) for generating 8-digit compact date strings (e.g. 24102026). {hhmiss} has been renamed to {hms} for consistency.
  • Ordinal Tokens: Uppercase variants of standard date tokens ({DAY}, {WW}, {MM}) now output their ordinal string representation (e.g., 24th, 1st, 2nd).

πŸ“¦ Migration Path for Tempo.ticker() Users ​

If you are upgrading from v2.x and your application relies on Tempo.ticker(), you will need to update your integration:

  1. Install the Plugin: npm install @magmacomputing/tempo-plugin-ticker
  2. Activate your License: Obtain your free JWT license key.
    Tempo License Registry
    πŸ‘‰ Go to the Tempo License Registry πŸ‘ˆ
    Manage your subscriptions and retrieve your license key.
  3. Register the Plugin: Wire the key into your application and extend Tempo:
    javascript
    import { Tempo } from '@magmacomputing/tempo';
    import { TickerModule } from '@magmacomputing/tempo-plugin-ticker';
    
    Tempo.init({ license: 'YOUR_JWT_KEY' });
    Tempo.extend(TickerModule);

πŸ—οΈ Internal Refactoring ​

  • Zero-Fallback Initialization: Cleaned up the Tempo.init() bootstrap logic to remove legacy compatibility layers, resulting in a cleaner internal state and reduced bundle size.
  • Build Pipelines: Fully synchronized build pipelines and TS declarations to ensure vitest and tsc operate seamlessly across local and premium workspaces.
  • ISO Getter Precision: Upgraded the .iso property getter from native Date.toISOString() to Temporal's Instant.toString(). This provides full ISO 8601 nanosecond precision and conforms to RFC 3339 by gracefully omitting fractional seconds when they evaluate to exactly zero.

Released under the MIT License.