Skip to content

Feat/compt 75 typed job definitions ischeduler interface#2

Closed
saadmoumou wants to merge 2 commits intodevelopfrom
feat/COMPT-75-typed-job-definitions-ischeduler-interface
Closed

Feat/compt 75 typed job definitions ischeduler interface#2
saadmoumou wants to merge 2 commits intodevelopfrom
feat/COMPT-75-typed-job-definitions-ischeduler-interface

Conversation

@saadmoumou
Copy link
Copy Markdown
Contributor

Summary

  • What does this PR change?

Why

  • Why is this change needed?

Checklist

  • Added/updated tests (if behavior changed)
  • npm run lint passes
  • npm run typecheck passes
  • npm test passes
  • npm run build passes
  • Added a changeset (npx changeset) if this affects consumers

Notes

  • Anything reviewers should pay attention to?

- Add ScheduledJob type: name, handler, and one of cron | interval | timeout
- Add IScheduler interface: schedule, unschedule, reschedule, list
- Add ScheduledJobStatus type: name, cron, lastRun, nextRun, isRunning
- Add DuplicateJobError thrown when registering a duplicate job name
- Enforce cron/interval/timeout mutual exclusivity via discriminated union
- Add CronExpression named constants for human-readable schedules
- Add cron fluent builder: dailyAt, weeklyOn, monthlyOn, every().minutes()
- Update tsconfig.build.json: CommonJS output, Task 1 files only
- Update package.json: name @ciscode/scheduler-kit, version 0.0.0
@saadmoumou saadmoumou requested a review from a team as a code owner April 7, 2026 16:09
Copilot AI review requested due to automatic review settings April 7, 2026 16:09
@saadmoumou saadmoumou closed this Apr 7, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refocuses the package’s public API toward a scheduler “kit” surface by adding typed job definitions (IScheduler/ScheduledJob), a duplicate-job error type, and cron helper utilities (constants + a fluent cron builder), while adjusting build/package configuration to match the new exported entrypoints.

Changes:

  • Added typed scheduler contracts (IScheduler, ScheduledJob, discriminated schedule timing types) and a DuplicateJobError.
  • Introduced cron helpers: CronExpression constants and a fluent cron builder with unit tests.
  • Updated build config/public exports and adjusted package metadata + git hooks.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tsconfig.build.json Narrows build entrypoints and sets CJS output settings for published artifacts.
src/interfaces/scheduler.interface.ts Adds the public scheduler type contract (job + timing union + interface).
src/index.ts Updates the package’s public exports to expose new interfaces/errors/helpers.
src/errors/duplicate-job.error.ts Introduces a dedicated error type for duplicate job registration.
src/errors/duplicate-job.error.spec.ts Adds unit tests for DuplicateJobError.
src/cron-expression.ts Adds readable cron-expression constants for consumers.
src/cron-expression.spec.ts Adds unit tests for cron-expression constants.
src/cron-builder.ts Adds a fluent cron builder and internal time parsing helper.
src/cron-builder.spec.ts Adds unit tests for the cron builder behavior.
package.json Updates description/repo metadata and dependency declarations.
.husky/pre-push Modifies the pre-push hook commands.

Comment thread package.json
"repository": {
"type": "git",
"url": "git+https://github.com/CISCODE-MA/SchedulerKit.git"
"url": "git+https://github.com/CISCODE-MA/"
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The repository URL was changed to the GitHub org root ("git+https://github.com/CISCODE-MA/") rather than the actual repository. This breaks npm metadata (and tooling that links back to source). Update it to the full repo URL (typically including the repo name and .git suffix).

Suggested change
"url": "git+https://github.com/CISCODE-MA/"
"url": "git+https://github.com/CISCODE-MA/scheduler-kit.git"

Copilot uses AI. Check for mistakes.
Comment thread package.json
Comment on lines 60 to +67
"@nestjs/testing": "^10.4.0",
"@types/jest": "^29.5.14",
"@types/node": "^22.10.7",
"cron": "^4.4.0",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.5",
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "cron" package is listed in devDependencies, but there are no imports/usages of it anywhere in the repo. If this kit doesn’t directly use the library, drop the dependency (or add the intended usage) to avoid unnecessary install surface area.

Copilot uses AI. Check for mistakes.
Comment thread .husky/pre-push
Comment on lines 1 to 2
npm run typecheck
npm run test:cov No newline at end of file
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Husky hook no longer has a shebang or Husky bootstrap (the removed lines). Without a shebang, Git may fail to execute the hook with an "exec format" error, and without husky.sh you lose Husky’s environment setup/opt-out behavior. Restore the standard Husky header at the top of this hook.

Copilot uses AI. Check for mistakes.
Comment thread src/cron-builder.ts
Comment on lines +60 to +61
* cron.every(5).minutes() // "* /5 * * * *"
* cron.every(2).hours() // "0 * /2 * * *"
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example outputs in this docblock have extra spaces (e.g. "* /5" and "0 * /2") which are not valid cron syntax and don’t match what the functions actually return ("*/5", "0 */2"). Please correct the example strings to avoid misleading consumers.

Suggested change
* cron.every(5).minutes() // "* /5 * * * *"
* cron.every(2).hours() // "0 * /2 * * *"
* cron.every(5).minutes() // "*/5 * * * * *"
* cron.every(2).hours() // "0 */2 * * * *"

Copilot uses AI. Check for mistakes.
Comment thread src/cron-builder.ts
Comment on lines +36 to +47
const ampm = /^(\d{1,2})(?::(\d{2}))?(am|pm)$/i.exec(time.trim());
if (ampm) {
let hour = parseInt(ampm[1] as string, 10);
const minute = ampm[2] ? parseInt(ampm[2], 10) : 0;
const period = (ampm[3] as string).toLowerCase();
if (period === "pm" && hour !== 12) hour += 12;
if (period === "am" && hour === 12) hour = 0;
return { hour, minute };
}
const h24 = /^(\d{1,2}):(\d{2})$/.exec(time.trim());
if (h24) {
return { hour: parseInt(h24[1] as string, 10), minute: parseInt(h24[2] as string, 10) };
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseTime() accepts out-of-range times like "99:99" or "25pm" because it only validates format, not numeric bounds. This can generate invalid cron expressions that fail at runtime. Add range checks (hour 0–23, minute 0–59; plus 1–12 for am/pm input) and throw a clear error when out of range.

Suggested change
const ampm = /^(\d{1,2})(?::(\d{2}))?(am|pm)$/i.exec(time.trim());
if (ampm) {
let hour = parseInt(ampm[1] as string, 10);
const minute = ampm[2] ? parseInt(ampm[2], 10) : 0;
const period = (ampm[3] as string).toLowerCase();
if (period === "pm" && hour !== 12) hour += 12;
if (period === "am" && hour === 12) hour = 0;
return { hour, minute };
}
const h24 = /^(\d{1,2}):(\d{2})$/.exec(time.trim());
if (h24) {
return { hour: parseInt(h24[1] as string, 10), minute: parseInt(h24[2] as string, 10) };
const trimmedTime = time.trim();
const ampm = /^(\d{1,2})(?::(\d{2}))?(am|pm)$/i.exec(trimmedTime);
if (ampm) {
const rawHour = parseInt(ampm[1] as string, 10);
const minute = ampm[2] ? parseInt(ampm[2], 10) : 0;
if (rawHour < 1 || rawHour > 12) {
throw new Error(`Cannot parse time: "${time}". Hour must be between 1 and 12 for am/pm input.`);
}
if (minute < 0 || minute > 59) {
throw new Error(`Cannot parse time: "${time}". Minute must be between 0 and 59.`);
}
let hour = rawHour;
const period = (ampm[3] as string).toLowerCase();
if (period === "pm" && hour !== 12) hour += 12;
if (period === "am" && hour === 12) hour = 0;
return { hour, minute };
}
const h24 = /^(\d{1,2}):(\d{2})$/.exec(trimmedTime);
if (h24) {
const hour = parseInt(h24[1] as string, 10);
const minute = parseInt(h24[2] as string, 10);
if (hour < 0 || hour > 23) {
throw new Error(`Cannot parse time: "${time}". Hour must be between 0 and 23 for 24-hour input.`);
}
if (minute < 0 || minute > 59) {
throw new Error(`Cannot parse time: "${time}". Minute must be between 0 and 59.`);
}
return { hour, minute };

Copilot uses AI. Check for mistakes.
Comment thread src/cron-builder.ts
Comment on lines +77 to +82
every(n: number) {
return {
minutes: (): string => `*/${n} * * * *`,
hours: (): string => `0 */${n} * * *`,
};
},
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cron.every(n) and cron.monthlyOn(dayOfMonth, ...) don’t validate inputs (e.g., n <= 0 / non-integers, dayOfMonth outside 1–31). These produce invalid cron strings. Validate these arguments and throw an error for invalid values.

Copilot uses AI. Check for mistakes.
Comment thread package.json
Comment on lines 45 to 60
"peerDependencies": {
"@nestjs/common": "^10 || ^11",
"@nestjs/core": "^10 || ^11",
"@nestjs/platform-express": "^10 || ^11",
"@nestjs/schedule": "^4 || ^5",
"reflect-metadata": "^0.2.2",
"rxjs": "^7"
},
"dependencies": {
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1"
},
"devDependencies": {
"@changesets/cli": "^2.27.7",
"@eslint/js": "^9.18.0",
"@nestjs/common": "^10.4.0",
"@nestjs/core": "^10.4.0",
"@nestjs/mapped-types": "^2.0.0",
"@nestjs/platform-express": "^10.4.0",
"@nestjs/schedule": "^6.1.1",
"@nestjs/testing": "^10.4.0",
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nestjs/schedule version ranges are inconsistent: peerDependencies restrict to "^4 || ^5", but devDependencies installs "^6.1.1". Align these (either bump the peer range to include the dev version, or downgrade devDependency) to avoid local builds passing while consumers hit peer/dependency conflicts.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +21
export type IntervalSchedule = {
interval: number;
cron?: never;
timeout?: never;
};

export type TimeoutSchedule = {
timeout: number;
cron?: never;
interval?: never;
};
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The numeric timing fields (interval/timeout) don’t specify units (ms vs seconds) in their doc comments. Since these are part of the public types, please document the expected unit to prevent consumers from scheduling jobs at the wrong cadence.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants