@promise-watch/core
Advanced tools
Comparing version 0.0.9 to 0.0.10
@@ -1,16 +0,2 @@ | ||
import { Notifier } from "./notifications"; | ||
export declare type RunPage = { | ||
name?: string; | ||
options: RunOptions; | ||
run(): Promise<void>; | ||
}; | ||
export declare type RunOptions = { | ||
notifiers?: Notifier[]; | ||
interval: number; | ||
}; | ||
export declare type ExecuteOptions = { | ||
dir: string; | ||
globPath?: string; | ||
notifiers?: Notifier[]; | ||
}; | ||
export declare function executeJobs(options: ExecuteOptions): Promise<void>; | ||
import { RunPage } from "./types"; | ||
export declare function filterRunsWithoutRequiredFields(pages: RunPage[]): RunPage[]; |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.executeJobs = void 0; | ||
const path_1 = require("path"); | ||
const glob_promise_1 = require("./utils/glob-promise"); | ||
const time_1 = require("./utils/time"); | ||
let alive = true; | ||
function sleep(ms) { | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
} | ||
async function fetchRuns(globPath, dir) { | ||
const files = await (0, glob_promise_1.glob)(globPath); | ||
const imports = await Promise.all(files.map(f => Promise.resolve().then(() => __importStar(require((0, path_1.resolve)(dir, "../", f)))))); | ||
return imports.map(({ name, run, options }, idx) => { | ||
name = name !== null && name !== void 0 ? name : files[idx].replace("runs/", ""); | ||
return { name, run, options }; | ||
}).reduce((prev, next) => { | ||
exports.filterRunsWithoutRequiredFields = void 0; | ||
function filterRunsWithoutRequiredFields(pages) { | ||
return pages.reduce((prev, next) => { | ||
var _a; | ||
@@ -51,52 +20,3 @@ const errors = []; | ||
} | ||
async function sendNotifications({ title, body, notifiers, isSuccess = false }) { | ||
for (const notify of notifiers) { | ||
await notify.send({ title, body, isSuccess }).catch(console.error); | ||
} | ||
} | ||
const errors = {}; | ||
async function recursiveRun(page, globalNotifiers = []) { | ||
var _a; | ||
const { name, run, options } = page; | ||
const notifiers = (_a = options.notifiers) !== null && _a !== void 0 ? _a : globalNotifiers; | ||
try { | ||
await run(); | ||
if (errors[name]) { | ||
const message = `Recovered after ${(0, time_1.millisecondsToStr)(errors[name])}`; | ||
await sendNotifications({ | ||
title: name, | ||
body: message, | ||
notifiers, | ||
isSuccess: true, | ||
}); | ||
delete errors[name]; | ||
} | ||
} | ||
catch (err) { | ||
if (!errors[name]) { | ||
errors[name] = Date.now(); | ||
await sendNotifications({ | ||
title: name, | ||
body: err.message, | ||
notifiers, | ||
}); | ||
} | ||
} | ||
if (alive) { | ||
await sleep(options.interval * 1000); | ||
await recursiveRun({ name, run, options }, notifiers); | ||
} | ||
} | ||
async function executeJobs(options) { | ||
const { dir, notifiers = [], globPath = "runs/**/*.{js,ts}", } = options; | ||
const runs = await fetchRuns(globPath, dir); | ||
await Promise.allSettled(runs.map(run => recursiveRun(run, notifiers))); | ||
} | ||
exports.executeJobs = executeJobs; | ||
function shutdown() { | ||
alive = false; | ||
process.exit(0); | ||
} | ||
process.on("SIGINT", shutdown); | ||
process.on("SIGTERM", shutdown); | ||
exports.filterRunsWithoutRequiredFields = filterRunsWithoutRequiredFields; | ||
//# sourceMappingURL=execute.js.map |
@@ -1,2 +0,2 @@ | ||
export * from "./execute"; | ||
export * from "./notifications"; | ||
import { ExecuteOptions } from "./types"; | ||
export declare function executeJobs(options: ExecuteOptions): Promise<void>; |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__exportStar(require("./execute"), exports); | ||
__exportStar(require("./notifications"), exports); | ||
exports.executeJobs = void 0; | ||
const run_1 = require("./run"); | ||
const files_1 = require("./files"); | ||
const execute_1 = require("./execute"); | ||
async function executeJobs(options) { | ||
const { dir, notifiers = [], globPath = "runs/**/*.{js,ts}", } = options; | ||
const files = await (0, files_1.importRunsFromPath)(globPath, dir); | ||
const runs = (0, execute_1.filterRunsWithoutRequiredFields)(files); | ||
await Promise.allSettled(runs.map(run => (0, run_1.recursivelyRun)(run, notifiers))); | ||
} | ||
exports.executeJobs = executeJobs; | ||
function shutdown() { | ||
(0, run_1.haltRecursion)(); | ||
process.exit(0); | ||
} | ||
process.on("SIGINT", shutdown); | ||
process.on("SIGTERM", shutdown); | ||
//# sourceMappingURL=index.js.map |
@@ -1,11 +0,3 @@ | ||
export declare type SendOptions = { | ||
title: string; | ||
body: string; | ||
isSuccess?: boolean; | ||
}; | ||
export declare type Notifier = { | ||
send(options: SendOptions): Promise<void>; | ||
}; | ||
export declare class ConsoleNotifier { | ||
send(options: SendOptions): Promise<void>; | ||
} | ||
import { Notifier } from "./types"; | ||
export declare function sendErrorNotifications(title: string, body: any, notifiers: Notifier[]): Promise<void>; | ||
export declare function sendSuccessNotifications(title: string, notifiers: Notifier[]): Promise<void>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ConsoleNotifier = void 0; | ||
class ConsoleNotifier { | ||
async send(options) { | ||
console.log(`${options.title}: ${options.body}`); | ||
exports.sendSuccessNotifications = exports.sendErrorNotifications = void 0; | ||
const time_1 = require("./utils/time"); | ||
async function sendNotifications({ title, body, notifiers, isSuccess = false }) { | ||
for (const notify of notifiers) { | ||
await notify.send({ title, body, isSuccess }).catch(console.error); | ||
} | ||
} | ||
exports.ConsoleNotifier = ConsoleNotifier; | ||
const errors = {}; | ||
async function sendErrorNotifications(title, body, notifiers) { | ||
if (!errors[title]) { | ||
errors[title] = Date.now(); | ||
await sendNotifications({ title, body, notifiers }); | ||
} | ||
} | ||
exports.sendErrorNotifications = sendErrorNotifications; | ||
async function sendSuccessNotifications(title, notifiers) { | ||
if (errors[title]) { | ||
const body = `Recovered after ${(0, time_1.howLongAgo)(errors[title])}`; | ||
await sendNotifications({ title, body, notifiers, isSuccess: true }); | ||
delete errors[title]; | ||
} | ||
} | ||
exports.sendSuccessNotifications = sendSuccessNotifications; | ||
//# sourceMappingURL=notifications.js.map |
@@ -1,1 +0,1 @@ | ||
export declare function millisecondsToStr(milliseconds: number): string; | ||
export declare function howLongAgo(milliseconds: number): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.millisecondsToStr = void 0; | ||
function numberEnding(number) { | ||
return (number > 1) ? "s" : ""; | ||
} | ||
function millisecondsToStr(milliseconds) { | ||
exports.howLongAgo = void 0; | ||
function howLongAgo(milliseconds) { | ||
const numberEnding = (n) => (n > 1) ? "s" : ""; | ||
const seconds = Math.floor((Date.now() - milliseconds) / 1000); | ||
if (seconds > 60) { | ||
const minutes = Math.floor(seconds / 60); | ||
const secondsLeft = Math.floor(seconds % 60); | ||
return minutes + " minute" + numberEnding(minutes) + " " + secondsLeft + " second" + numberEnding(secondsLeft); | ||
} | ||
if (seconds) { | ||
@@ -14,3 +17,3 @@ return seconds + " second" + numberEnding(seconds); | ||
} | ||
exports.millisecondsToStr = millisecondsToStr; | ||
exports.howLongAgo = howLongAgo; | ||
//# sourceMappingURL=time.js.map |
{ | ||
"name": "@promise-watch/core", | ||
"version": "0.0.9", | ||
"version": "0.0.10", | ||
"main": "dist/index.js", | ||
@@ -27,2 +27,3 @@ "author": "Jason Raimondi <jason@raimondi.us> (https://jasonraimondi.com)", | ||
"scripts": { | ||
"test": "jest", | ||
"build": "tsc", | ||
@@ -29,0 +30,0 @@ "prepublish": "rm -rf ./dist && pnpm build" |
@@ -1,36 +0,5 @@ | ||
import { resolve } from "path"; | ||
import { glob } from "./utils/glob-promise"; | ||
import { Notifier } from "./notifications"; | ||
import { millisecondsToStr } from "./utils/time"; | ||
import { RunPage } from "./types"; | ||
export type RunPage = { | ||
name?: string; | ||
options: RunOptions; | ||
run(): Promise<void>; | ||
}; | ||
export type RunOptions = { | ||
notifiers?: Notifier[]; | ||
interval: number; | ||
}; | ||
export type ExecuteOptions = { | ||
dir: string; | ||
globPath?: string; | ||
notifiers?: Notifier[]; | ||
}; | ||
let alive = true; | ||
function sleep(ms: number) { | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
} | ||
async function fetchRuns(globPath: string, dir: string) { | ||
const files = await glob(globPath); | ||
const imports = await Promise.all(files.map(f => import(resolve(dir, "../", f)))); | ||
return imports.map(({ name, run, options }: RunPage, idx) => { | ||
name = name ?? files[idx].replace("runs/", "") | ||
return { name, run, options } | ||
}).reduce((prev, next) => { | ||
export function filterRunsWithoutRequiredFields(pages: RunPage[]): RunPage[] { | ||
return pages.reduce((prev, next) => { | ||
const errors = []; | ||
@@ -42,3 +11,3 @@ | ||
if (errors.length) { | ||
console.log(`${next.name} has errors and was skipped:`); | ||
console.log(`${next.name} has errors and was skipped:`) | ||
console.log(errors.join("\n"), "\n"); | ||
@@ -49,68 +18,4 @@ return [...prev]; | ||
return [...prev, next]; | ||
}, [] as Required<RunPage>[]) | ||
} | ||
}, [] as RunPage[]); | ||
type SendNotifications = { title: string; body: string; notifiers: Notifier[]; isSuccess?: boolean; } | ||
async function sendNotifications({ title, body, notifiers, isSuccess = false }: SendNotifications) { | ||
for (const notify of notifiers) { | ||
await notify.send({ title, body, isSuccess }).catch(console.error); | ||
} | ||
} | ||
const errors: Record<string, number> = {}; | ||
async function recursiveRun(page: Required<RunPage>, globalNotifiers: Notifier[] = []) { | ||
const { name, run, options } = page; | ||
const notifiers = options.notifiers ?? globalNotifiers; | ||
try { | ||
await run(); | ||
if (errors[name]) { | ||
const message = `Recovered after ${millisecondsToStr(errors[name])}`; | ||
await sendNotifications({ | ||
title: name, | ||
body: message, | ||
notifiers, | ||
isSuccess: true, | ||
}); | ||
delete errors[name]; | ||
} | ||
} catch (err: any) { | ||
// if we have already notified about the error, | ||
// wait until success before sending another notification | ||
if (!errors[name]) { | ||
errors[name] = Date.now(); | ||
await sendNotifications({ | ||
title: name, | ||
body: err.message, | ||
notifiers, | ||
}); | ||
} | ||
} | ||
if (alive) { | ||
await sleep(options.interval * 1000); | ||
await recursiveRun({ name, run, options }, notifiers); | ||
} | ||
} | ||
export async function executeJobs(options: ExecuteOptions) { | ||
const { | ||
dir, | ||
notifiers = [], | ||
globPath = "runs/**/*.{js,ts}", | ||
} = options; | ||
const runs = await fetchRuns(globPath, dir); | ||
await Promise.allSettled(runs.map(run => recursiveRun(run, notifiers))); | ||
} | ||
function shutdown() { | ||
alive = false; | ||
process.exit(0); | ||
} | ||
process.on("SIGINT", shutdown); | ||
process.on("SIGTERM", shutdown); |
@@ -1,2 +0,23 @@ | ||
export * from "./execute"; | ||
export * from "./notifications"; | ||
import { haltRecursion, recursivelyRun } from "./run"; | ||
import { ExecuteOptions } from "./types"; | ||
import { importRunsFromPath } from "./files"; | ||
import { filterRunsWithoutRequiredFields } from "./execute"; | ||
export async function executeJobs(options: ExecuteOptions) { | ||
const { | ||
dir, | ||
notifiers = [], | ||
globPath = "runs/**/*.{js,ts}", | ||
} = options; | ||
const files = await importRunsFromPath(globPath, dir); | ||
const runs = filterRunsWithoutRequiredFields(files); | ||
await Promise.allSettled(runs.map(run => recursivelyRun(run, notifiers))); | ||
} | ||
function shutdown() { | ||
haltRecursion(); | ||
process.exit(0); | ||
} | ||
process.on("SIGINT", shutdown); | ||
process.on("SIGTERM", shutdown); |
@@ -1,15 +0,27 @@ | ||
export type SendOptions = { | ||
title: string; | ||
body: string; | ||
isSuccess?: boolean; | ||
}; | ||
import { Notifier, SendNotifications } from "./types"; | ||
import { howLongAgo } from "./utils/time"; | ||
export type Notifier = { | ||
send(options: SendOptions): Promise<void>; | ||
}; | ||
export class ConsoleNotifier { | ||
async send(options: SendOptions) { | ||
console.log(`${options.title}: ${options.body}`); | ||
async function sendNotifications({ title, body, notifiers, isSuccess = false }: SendNotifications) { | ||
for (const notify of notifiers) { | ||
await notify.send({ title, body, isSuccess }).catch(console.error); | ||
} | ||
} | ||
const errors: Record<string, number> = {}; | ||
export async function sendErrorNotifications(title: string, body: any, notifiers: Notifier[]) { | ||
// if we have already notified about the error, wait until success before sending another notification | ||
if (!errors[title]) { | ||
errors[title] = Date.now(); | ||
await sendNotifications({ title, body, notifiers }); | ||
} | ||
} | ||
export async function sendSuccessNotifications(title: string, notifiers: Notifier[]) { | ||
if (errors[title]) { | ||
const body = `Recovered after ${howLongAgo(errors[title])}`; | ||
await sendNotifications({ title, body, notifiers, isSuccess: true }); | ||
delete errors[title]; | ||
} | ||
} |
@@ -1,8 +0,12 @@ | ||
function numberEnding(number: number) { | ||
return (number > 1) ? "s" : ""; | ||
} | ||
export function howLongAgo(milliseconds: number) { | ||
const numberEnding = (n: number) => (n > 1) ? "s" : ""; | ||
export function millisecondsToStr(milliseconds: number) { | ||
const seconds = Math.floor((Date.now() - milliseconds) / 1000); | ||
if (seconds > 60) { | ||
const minutes = Math.floor(seconds / 60) | ||
const secondsLeft = Math.floor(seconds % 60) | ||
return minutes + " minute" + numberEnding(minutes) + " " + secondsLeft + " second" + numberEnding(secondsLeft); | ||
} | ||
if (seconds) { | ||
@@ -13,2 +17,2 @@ return seconds + " second" + numberEnding(seconds); | ||
return "less than a second"; | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
26268
47
435
1