UNPKG

@trap_stevo/timetide

Version:

Master the flow of time with the ultimate solution for precision scheduling, real-time synchronization, and temporal control. Designed for developers who demand flexibility and power, this system blends intuitive time parsing, dynamic countdowns, and pers

547 lines (408 loc) 15.5 kB
# ⏱️ @trap_stevo/timetide **Master the flow of time with the ultimate solution for precision scheduling, real-time synchronization, and temporal control.** Designed for developers who demand flexibility and power, TimeTide blends intuitive time parsing, dynamic countdowns, persistent task handling, natural-language date interpretation, and nanosecond-to-millennia resolution—all into a seamless, elegant toolkit. Schedule events using human-readable commands, manage durations with clarity, and broadcast tick events to dashboards or distributed systems. Whether you build responsive interfaces, backend automation, or temporal workflows, **TimeTide equips you to orchestrate time itself—with legendary elegance and unmatched control.** --- ## 🚀 Features - ⏱️ **Human-readable durations** — `"30m"`, `"1.5h"`, `"2w"`, `"10y"`, `"3gen"`, `"1mil"` - 📅 **Natural-language dates** — `"next Friday"`, `"in 3 days"`, `"end of day"`, `"tomorrow"` - 🔁 **Repeating & persistent timers** — recurring jobs that can survive restarts - 📦 **Named timers** — pause, resume, extend, reduce, reschedule, chain follow-ups - 📡 **Tick streams** — global ticks for dashboards, schedulers, analytics - 🎯 **Threshold comparison helpers** — `exceedsDuration`, `exceedsTime` - 🧠 **Advanced parsing helpers** — `normalizeDateInput`, `parseDateTime` - 🧮 **High-precision units** — nanoseconds → millennia - ⚙️ **Configurable persistence** — store timers anywhere --- # ⚙️ Initialization ```js const TimeTide = require("@trap_stevo/timetide"); TimeTide.initializeTimers({ persistPath : "./.timers.json", disablePersistence : false }); ``` ### Initialization Options | Key | Type | Description | Default | |-----|------|-------------|---------| | `persistPath` | `string` | Where persistent timers are stored | `"./.timers.json"` | | `disablePersistence` | `boolean` | Disable reading/writing named timers | `false` | | `onLoadTimersError` | `function` | Called if persisted state cannot be loaded | `undefined` | --- # 📡 Scheduling API (One-Time & Named Tasks) ### Methods | Method | Description | Persisted? | |--------|-------------|------------| | `schedule(name, dur, cb, meta?)` | Named timer with persistence | ✔ | | `schedule(dur, cb)` | Simple one-time timer | ❌ | | `countdown(dur, cb)` | Alias of `schedule(dur, cb)` | ❌ | | `then(name, cb)` | Chain a follow-up after a named timer fires | ✔ | | `clear(idOrName)` | Cancel timer by ID or name | ✔ | | `extend(name, dur)` | Add time to a named timer | ✔ | | `reduce(name, dur)` | Subtract time from a named timer | ✔ | | `reschedule(name, dur)` | Replace remaining time with new duration | ✔ | | `pause(name)` | Freeze a named timer and store remaining time | ✔ | | `resume(name)` | Resume a paused named timer | ✔ | | `pauseAll()` | Pause all named timers | ✔ | | `resumeAll()` | Resume all named timers | ✔ | ### Example — Named, persistent timer ```js TimeTide.schedule("backupJob", "45m", () => { console.log("Backup finished!"); }, { priority : "high" }); TimeTide.then("backupJob", () => { console.log("Follow-up job triggered."); }); ``` --- # 🔁 Recurring Tasks ### Non-persistent recurring tasks | Method | Description | |--------|-------------| | `onEvery(interval, cb)` | Run a callback every interval | | `repeat(interval, cb)` | Alias of `onEvery` | ```js const id = TimeTide.onEvery("10s", () => { console.log("Heartbeat"); }); // Later TimeTide.clear(id); ``` ### Persistent recurring tasks (cron-like loop) ```js function hourly() { console.log("Hourly job fired"); } function scheduleHourly() { TimeTide.schedule("hourlyJob", "1h", () => { hourly(); scheduleHourly(); }); } scheduleHourly(); ``` - Recurs forever - Can be paused / resumed via `pause("hourlyJob")` / `resume("hourlyJob")` - Keeps the same named timer #### Example — Auto-grading loop (safer pattern) ```js function autoGrade() { console.log("Auto-grade fired at", new Date().toISOString()); } function chainAutoGrade() { TimeTide.schedule("auto-grade", "1m", () => { try { autoGrade(); } finally { // Always re-schedule, even if autoGrade throws chainAutoGrade(); } }); } chainAutoGrade(); ``` --- # 📡 Tick Events | Method | Description | |--------|-------------| | `startTick(interval)` | Create a global ticker emitting events | | `stopTick(interval)` | Stop a global ticker | | `events.on("tick:interval", cb)` | Subscribe to a specific tick label | | `events.on("tick", cb)` | Subscribe to all ticks, receives label | ```js TimeTide.startTick("1s"); TimeTide.events.on("tick:1s", () => { console.log("Second tick"); }); TimeTide.events.on("tick", (label) => { // label could be "1s", "5m", "1000ms", etc. }); ``` Stop: ```js TimeTide.stopTick("1s"); ``` --- # ⏳ Countdown & Expiration Helpers | Method | Description | |--------|-------------| | `countdown(dur, cb)` | One-shot countdown (alias of `schedule(dur, cb)`) | | `expired(date)` | `true` if `date` is earlier than now | | `getTimeUntil(date)` | Milliseconds until given date | | `addTime(date, dur)` | Returns new Date: `date + duration` | | `subtractTime(date, dur)` | Returns new Date: `date - duration` | ### Example — Time until a deadline ```js const deadline = "2025-12-01T17:00:00Z"; const msUntil = TimeTide.getTimeUntil(deadline); console.log("Remaining:", TimeTide.toReadable(msUntil)); if (TimeTide.expired(deadline)) { console.log("Deadline already passed"); } ``` --- # ⚖️ Duration & Time Comparison ## `exceedsDuration(timeInput, threshold, options?)` Generic threshold comparison between a time and a reference. **Parameters** | Name | Type | Description | |------|------|-------------| | `timeInput` | `Date \| number \| string` | Target time to compare | | `threshold` | `number \| string` | Milliseconds or duration string (`"30m"`, `"1h"`, `"3d"`, `"5y"`, `"2gen"`, etc.) | | `options.reference` | `Date \| number \| string` | Time to compare against (default: now) | **Return** ```js { valid : boolean, // false if inputs could not be parsed exceeded : boolean, // true if |target - reference| > threshold diffMs : number | null, // absolute difference in milliseconds thresholdMs : number | null } ``` **Example** ```js const result = TimeTide.exceedsDuration("in 90m", "1h"); if (result.valid && result.exceeded) { console.log("Over 1 hour difference"); } else if (result.valid) { console.log("Within 1 hour:", TimeTide.toReadable(result.diffMs)); } ``` ## `exceedsTime(timeInput, threshold, options?)` Alias of `exceedsDuration`. ```js const result = TimeTide.exceedsTime(lastPingAt, "30m", { reference : Date.now() }); if (result.exceeded) { console.log("Last ping is older than 30 minutes"); } ``` ### Example — Eligibility gate within 1 hour ```js function inspectEligibility(gradeAtInput) { // gradeAtInput can be Date, ms, numeric string, ISO string, or natural language const result = TimeTide.exceedsDuration(gradeAtInput, "1h", { reference : Date.now() }); if (!result.valid) { return { eligible : false, reason : "Invalid gradeAt input" }; } if (result.exceeded) { return { eligible : true, reason : "Grade time exceeded 1 hour threshold" }; } return { eligible : false, reason : `Still within 1 hour window (${TimeTide.toReadable(result.diffMs)} difference)` }; } ``` --- # 🧠 Time Parsing, Conversion & Utilities All time utilities are provided directly on `TimeTide`. | Method | Description | |--------|-------------| | `parseDuration(str)` | Parse `"1h 30m"` → ms | | `toMilliseconds(str)` | Duration string → milliseconds | | `toSeconds(str)` | Duration string → seconds | | `toReadable(ms)` | Convert ms to `"2h 3m 10s"` style string | | `toETA(seconds)` | Convert seconds (numeric) to a readable ETA string | | `parseDate(str)` | Parse natural-language / ISO date into `Date` | | `normalizeDateInput(input)` | Normalize Date / ms / numeric / string input into `Date` or `null` | | `parseDateTime(input, unit)` | Parse date-like input into a specific time unit | | `validDate(input)` | Returns `true` if input can be parsed into a valid date | --- ## `parseDateTime(input, unit = "ms")` Convert any supported date-like input into the desired time unit using a **unit + alias map** that mirrors the duration model. **Supported input types** - `Date` - millisecond `number` - numeric timestamp string (e.g. `"1763754901019"`) - ISO date string - natural language (`"in 1 hour"`, `"tomorrow"`, `"next Friday 6pm"`, etc.) **Supported units** | Unit | Aliases | Output | |------|---------|--------| | `ms` | `millisecond`, `milliseconds` | Milliseconds since epoch | | `s` | `sec`, `second`, `seconds` | Whole seconds since epoch | | `m` | `min`, `minute`, `minutes` | Whole minutes since epoch | | `h` | `hr`, `hour`, `hours` | Whole hours since epoch | | `d` | `day`, `days` | Whole days since epoch | | `w` | `week`, `weeks` | Whole weeks since epoch | | `mo` | `month`, `months` | Approx. months since epoch | | `y` | `yr`, `year`, `years` | Approx. years since epoch | | `dec` | `decade`, `decades` | Approx. decades since epoch | | `cen` | `century`, `centuries` | Approx. centuries since epoch | | `gen` | `generation`, `generations` | Approx. generations since epoch | | `mil` | `millennium`, `millennia` | Approx. millennia since epoch | | `iso` | — | ISO string | | `date` | — | `Date` object | Internally, `parseDateTime`: 1. Normalizes the input into a `Date` 2. Converts that `Date` to milliseconds (`ms`) 3. Uses a **factor map + alias map** to divide into the requested unit 4. Returns a rounded-down integer for numeric units **Examples** ```js // 1) Millisecond timestamp from ISO string const ts = TimeTide.parseDateTime("2025-11-21T20:46:59.495Z", "ms"); // 2) Unix-style seconds from natural language const unix = TimeTide.parseDateTime("next Friday", "seconds"); // "seconds" → "s" // 3) Days since epoch const days = TimeTide.parseDateTime("today", "days"); // 4) ISO from natural language const iso = TimeTide.parseDateTime("in 2 weeks", "iso"); // 5) Using a numeric ms timestamp input and converting to days const createdAtMs = Date.now() - TimeTide.toMilliseconds("3d 2h"); const ageDays = TimeTide.parseDateTime(createdAtMs, "days"); // ⭐ 6) Raw millisecond timestamp directly from DB / storage const dbTs = 1763754901019; const normalized = TimeTide.parseDateTime(dbTs, "ms"); console.log(normalized); // → 1763754901019 // 7) Gating based on a future point in time const gradeAt = TimeTide.parseDateTime("in 1 hour", "ms"); const remainingMs = gradeAt - Date.now(); console.log("Remaining until grade:", TimeTide.toReadable(remainingMs)); ``` --- # 🔥 Supported Duration Units TimeTide supports mixed & stacked units in `parseDuration` / `toMilliseconds`: ```js "1h 30m" "2d 4h 20m 5s" "1.5h" "3gen 5y 2mo" "10y 2w 3d 4h 5m 6s" ``` ### Unit Table | Unit | Tokens | Approximate ms | |------|--------|----------------| | Nanoseconds | `ns`, `nanoseconds` | `1e-6` | | Milliseconds | `ms`, `milliseconds` | `1` | | Seconds | `s`, `seconds` | `1000` | | Minutes | `m`, `minutes` | `60000` | | Hours | `h`, `hours` | `3600000` | | Days | `d`, `days` | `86400000` | | Weeks | `w`, `weeks` | `604800000` | | Months | `mo`, `months` | `2629800000` | | Years | `y`, `years` | `31557600000` | | Decades | `dec`, `decades` | `315576000000` | | Centuries | `cen`, `centuries` | `3155760000000` | | Generations | `gen`, `generations` | `788940000000` | | Millennia | `mil`, `millennia` | `31557600000000` | --- # 🌙 Natural-Language Date Phrases Examples of phrases `parseDate` / `parseDateTime` can understand include: - `"now"`, `"today"`, `"tonight"` - `"end of day"`, `"midnight"`, `"noon"` - `"yesterday"`, `"tomorrow"` - `"in 3 hours"`, `"in 5 days"`, `"in 2 weeks"` - `"10 minutes ago"`, `"3 days ago"` - `"next Monday"`, `"last Friday"`, `"this Friday"` - `"this month"`, `"next month"`, `"last year"` - `"next weekend"` - `"January 6, 2025 13:45"` - `"2025-01-06T13:45:00Z"` --- ## 📦 Installation ```bash npm install @trap_stevo/timetide ``` --- ## ⚡ Quick Start (Step-by-Step) ### 1) Initialize TimeTide ```js const TimeTide = require("@trap_stevo/timetide"); TimeTide.initializeTimers({ persistPath : "./.timers.json", disablePersistence : false }); ``` ### 2) Schedule a simple one-time task ```js TimeTide.schedule("10s", () => { console.log("⏰ Fired after 10 seconds"); }); ``` ### 3) Create a named, persistent task ```js TimeTide.schedule("daily-report", "24h", () => { console.log("📊 Daily report generated"); }, { type : "report", priority : "high" }); TimeTide.then("daily-report", () => { console.log("✅ Daily report follow-up"); }); ``` If your app restarts and you call `initializeTimers` again with the same `persistPath`, `daily-report` will be restored (as long as it hasn’t fired yet and its callback is registered again). ### 4) Create a recurring heartbeat ```js const heartbeatID = TimeTide.onEvery("5s", () => { console.log("💓 Heartbeat:", new Date().toISOString()); }); // Later: TimeTide.clear(heartbeatID); ``` ### 5) Use natural-language dates and duration comparison ```js // "next Friday 18:00" as a millisecond timestamp const launchAtMs = TimeTide.parseDateTime("next Friday 6pm", "ms"); const remainingMs = launchAtMs - Date.now(); console.log("Time until launch:", TimeTide.toReadable(remainingMs)); // Check if something is more than 1 hour away from now const result = TimeTide.exceedsDuration("in 90m", "1h"); if (result.valid && result.exceeded) { console.log("⏳ More than 1 hour difference"); } ``` --- # 🗂️ Inspect Active Timers ```js const timers = TimeTide.getTimers(); console.log(timers); /* { backupJob : { createdAt : Date, remainingMs : 120000, readable : "2m", meta : { priority : "high" } } } */ ``` --- # 🧼 Cleanup Pattern ```js const id = TimeTide.onEvery("5s", () => { console.log("tick"); }); TimeTide.startTick("1m"); function cleanup() { TimeTide.clear(id); TimeTide.stopTick("1m"); } process.on("SIGINT", cleanup); process.on("SIGTERM", cleanup); ``` --- # 📜 License See [LICENSE.md](./LICENSE.md) --- # ⏱️ Control Time. Shape Systems. From millisecond-precision scheduling to natural-language parsing, from duration comparison to recurring, persistent, restart-safe timers—**TimeTide** gives you complete command over time itself.