@commandkit/tasks 0.0.0-dev.20250724145623
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/LICENSE +11 -0
- package/README.md +301 -0
- package/dist/context.d.ts +103 -0
- package/dist/context.js +101 -0
- package/dist/driver-manager.d.ts +126 -0
- package/dist/driver-manager.js +154 -0
- package/dist/driver.d.ts +74 -0
- package/dist/driver.js +3 -0
- package/dist/drivers/bullmq.d.ts +77 -0
- package/dist/drivers/bullmq.js +110 -0
- package/dist/drivers/hypercron.d.ts +69 -0
- package/dist/drivers/hypercron.js +90 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +54 -0
- package/dist/plugin.d.ts +79 -0
- package/dist/plugin.js +223 -0
- package/dist/task.d.ts +108 -0
- package/dist/task.js +129 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.js +3 -0
- package/package.json +59 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.taskDriverManager = exports.TaskDriverManager = void 0;
|
|
4
|
+
exports.setDriver = setDriver;
|
|
5
|
+
exports.createTask = createTask;
|
|
6
|
+
exports.deleteTask = deleteTask;
|
|
7
|
+
/**
|
|
8
|
+
* Manages the active task driver and provides a unified interface for task operations.
|
|
9
|
+
*
|
|
10
|
+
* This class acts as a facade for the underlying task driver, providing methods
|
|
11
|
+
* to create, delete, and manage tasks. It ensures that a driver is set before
|
|
12
|
+
* any operations are performed.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { TaskDriverManager } from '@commandkit/tasks';
|
|
17
|
+
* import { HyperCronDriver } from '@commandkit/tasks/hypercron';
|
|
18
|
+
*
|
|
19
|
+
* const manager = new TaskDriverManager();
|
|
20
|
+
* manager.setDriver(new HyperCronDriver());
|
|
21
|
+
*
|
|
22
|
+
* // Now you can create and manage tasks
|
|
23
|
+
* const taskId = await manager.createTask({
|
|
24
|
+
* name: 'my-task',
|
|
25
|
+
* data: { userId: '123' },
|
|
26
|
+
* schedule: { type: 'date', value: Date.now() + 60000 },
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
class TaskDriverManager {
|
|
31
|
+
constructor() {
|
|
32
|
+
this.driver = null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Sets the active task driver.
|
|
36
|
+
*
|
|
37
|
+
* This method must be called before any task operations can be performed.
|
|
38
|
+
* The driver handles all scheduling, persistence, and execution timing.
|
|
39
|
+
*
|
|
40
|
+
* @param driver - The task driver to use for all operations
|
|
41
|
+
*/
|
|
42
|
+
setDriver(driver) {
|
|
43
|
+
this.driver = driver;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new scheduled task.
|
|
47
|
+
*
|
|
48
|
+
* This method delegates to the active driver to schedule the task according
|
|
49
|
+
* to its configuration. The task will be executed when its schedule is due.
|
|
50
|
+
*
|
|
51
|
+
* @param task - The task data containing name, schedule, and custom data
|
|
52
|
+
* @returns A unique identifier for the created task
|
|
53
|
+
* @throws {Error} If no driver has been set
|
|
54
|
+
*/
|
|
55
|
+
async createTask(task) {
|
|
56
|
+
if (!this.driver)
|
|
57
|
+
throw new Error('Task driver has not been set');
|
|
58
|
+
return await this.driver.create(task);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Deletes a scheduled task by its identifier.
|
|
62
|
+
*
|
|
63
|
+
* This method delegates to the active driver to remove the task from the
|
|
64
|
+
* scheduling system and cancel any pending executions.
|
|
65
|
+
*
|
|
66
|
+
* @param identifier - The unique identifier of the task to delete
|
|
67
|
+
* @throws {Error} If no driver has been set
|
|
68
|
+
*/
|
|
69
|
+
async deleteTask(identifier) {
|
|
70
|
+
if (!this.driver)
|
|
71
|
+
throw new Error('Task driver has not been set');
|
|
72
|
+
await this.driver.delete(identifier);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Sets the task execution runner function.
|
|
76
|
+
*
|
|
77
|
+
* This method delegates to the active driver to set up the execution handler
|
|
78
|
+
* that will be called when tasks are due to run.
|
|
79
|
+
*
|
|
80
|
+
* @param runner - The function to call when a task should be executed
|
|
81
|
+
* @throws {Error} If no driver has been set
|
|
82
|
+
*/
|
|
83
|
+
async setTaskRunner(runner) {
|
|
84
|
+
if (!this.driver)
|
|
85
|
+
throw new Error('Task driver has not been set');
|
|
86
|
+
await this.driver.setTaskRunner(runner);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.TaskDriverManager = TaskDriverManager;
|
|
90
|
+
/**
|
|
91
|
+
* Global task driver manager instance.
|
|
92
|
+
*
|
|
93
|
+
* This is the default instance used by the tasks plugin for managing task operations.
|
|
94
|
+
* You can use this instance directly or create your own TaskDriverManager instance.
|
|
95
|
+
*/
|
|
96
|
+
exports.taskDriverManager = new TaskDriverManager();
|
|
97
|
+
/**
|
|
98
|
+
* Sets the global task driver.
|
|
99
|
+
*
|
|
100
|
+
* This is a convenience function that sets the driver on the global task driver manager.
|
|
101
|
+
*
|
|
102
|
+
* @param driver - The task driver to use for all operations
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* import { setDriver } from '@commandkit/tasks';
|
|
107
|
+
* import { HyperCronDriver } from '@commandkit/tasks/hypercron';
|
|
108
|
+
*
|
|
109
|
+
* setDriver(new HyperCronDriver());
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
function setDriver(driver) {
|
|
113
|
+
exports.taskDriverManager.setDriver(driver);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Creates a new scheduled task using the global driver manager.
|
|
117
|
+
*
|
|
118
|
+
* This is a convenience function that creates a task using the global task driver manager.
|
|
119
|
+
*
|
|
120
|
+
* @param task - The task data containing name, schedule, and custom data
|
|
121
|
+
* @returns A unique identifier for the created task
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* import { createTask } from '@commandkit/tasks';
|
|
126
|
+
*
|
|
127
|
+
* const taskId = await createTask({
|
|
128
|
+
* name: 'reminder',
|
|
129
|
+
* data: { userId: '123', message: 'Hello!' },
|
|
130
|
+
* schedule: { type: 'date', value: Date.now() + 60000 },
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
function createTask(task) {
|
|
135
|
+
return exports.taskDriverManager.createTask(task);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Deletes a scheduled task using the global driver manager.
|
|
139
|
+
*
|
|
140
|
+
* This is a convenience function that deletes a task using the global task driver manager.
|
|
141
|
+
*
|
|
142
|
+
* @param identifier - The unique identifier of the task to delete
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* import { deleteTask } from '@commandkit/tasks';
|
|
147
|
+
*
|
|
148
|
+
* await deleteTask('task-123');
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
function deleteTask(identifier) {
|
|
152
|
+
return exports.taskDriverManager.deleteTask(identifier);
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHJpdmVyLW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZHJpdmVyLW1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBK0dBLDhCQUVDO0FBcUJELGdDQUVDO0FBZ0JELGdDQUVDO0FBdkpEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBQ0gsTUFBYSxpQkFBaUI7SUFBOUI7UUFDVSxXQUFNLEdBQXNCLElBQUksQ0FBQztJQTJEM0MsQ0FBQztJQXpEQzs7Ozs7OztPQU9HO0lBQ0ksU0FBUyxDQUFDLE1BQWtCO1FBQ2pDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7Ozs7Ozs7O09BU0c7SUFDSSxLQUFLLENBQUMsVUFBVSxDQUFDLElBQWM7UUFDcEMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO1FBRWxFLE9BQU8sTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSSxLQUFLLENBQUMsVUFBVSxDQUFDLFVBQWtCO1FBQ3hDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTTtZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQztRQUVsRSxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNJLEtBQUssQ0FBQyxhQUFhLENBQUMsTUFBa0I7UUFDM0MsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO1FBRWxFLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDMUMsQ0FBQztDQUNGO0FBNURELDhDQTREQztBQUVEOzs7OztHQUtHO0FBQ1UsUUFBQSxpQkFBaUIsR0FBRyxJQUFJLGlCQUFpQixFQUFFLENBQUM7QUFFekQ7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxTQUFnQixTQUFTLENBQUMsTUFBa0I7SUFDMUMseUJBQWlCLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQ3RDLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBQ0gsU0FBZ0IsVUFBVSxDQUFDLElBQWM7SUFDdkMsT0FBTyx5QkFBaUIsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDNUMsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxTQUFnQixVQUFVLENBQUMsVUFBa0I7SUFDM0MsT0FBTyx5QkFBaUIsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUM7QUFDbEQsQ0FBQyJ9
|
package/dist/driver.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { TaskData, TaskExecutionData } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Interface for task persistence and scheduling drivers.
|
|
4
|
+
*
|
|
5
|
+
* Drivers handle the actual scheduling, persistence, and execution timing of tasks.
|
|
6
|
+
* Different drivers can provide different persistence mechanisms (in-memory, database, etc.)
|
|
7
|
+
* and scheduling capabilities.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { TaskDriver } from '@commandkit/tasks';
|
|
12
|
+
*
|
|
13
|
+
* class CustomDriver implements TaskDriver {
|
|
14
|
+
* async create(task: TaskData): Promise<string> {
|
|
15
|
+
* // Schedule the task in your system
|
|
16
|
+
* const id = await this.scheduler.schedule(task);
|
|
17
|
+
* return id;
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* async delete(task: string): Promise<void> {
|
|
21
|
+
* // Remove the task from your system
|
|
22
|
+
* await this.scheduler.cancel(task);
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* async setTaskRunner(runner: TaskRunner): Promise<void> {
|
|
26
|
+
* // Set up the execution handler
|
|
27
|
+
* this.runner = runner;
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export interface TaskDriver {
|
|
33
|
+
/**
|
|
34
|
+
* Creates a new scheduled task.
|
|
35
|
+
*
|
|
36
|
+
* This method should schedule the task according to its schedule configuration
|
|
37
|
+
* and return a unique identifier that can be used to delete the task later.
|
|
38
|
+
* Multiple tasks may be created with the same name.
|
|
39
|
+
*
|
|
40
|
+
* @param task - The task data containing name, schedule, and custom data
|
|
41
|
+
* @returns A unique identifier for the created task
|
|
42
|
+
*/
|
|
43
|
+
create(task: TaskData): Promise<string>;
|
|
44
|
+
/**
|
|
45
|
+
* Deletes a scheduled task by its identifier.
|
|
46
|
+
*
|
|
47
|
+
* This method should remove the task from the scheduling system and cancel
|
|
48
|
+
* any pending executions. If the task doesn't exist, this method should
|
|
49
|
+
* complete successfully without throwing an error.
|
|
50
|
+
*
|
|
51
|
+
* @param task - The unique identifier of the task to delete
|
|
52
|
+
*/
|
|
53
|
+
delete(task: string): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Sets the task execution runner function.
|
|
56
|
+
*
|
|
57
|
+
* This method should store the provided runner function and call it whenever
|
|
58
|
+
* a task is due for execution. The runner function receives the task execution
|
|
59
|
+
* data and should handle any errors that occur during execution.
|
|
60
|
+
*
|
|
61
|
+
* @param runner - The function to call when a task should be executed
|
|
62
|
+
*/
|
|
63
|
+
setTaskRunner(runner: TaskRunner): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Function type for executing tasks.
|
|
67
|
+
*
|
|
68
|
+
* This function is called by the driver when a task is scheduled to run.
|
|
69
|
+
* It receives the task execution data and should handle the actual execution
|
|
70
|
+
* of the task logic.
|
|
71
|
+
*
|
|
72
|
+
* @param task - The task execution data containing name, custom data, and timestamp
|
|
73
|
+
*/
|
|
74
|
+
export type TaskRunner = (task: TaskExecutionData) => Promise<void>;
|
package/dist/driver.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { TaskDriver, TaskRunner } from '../driver';
|
|
2
|
+
import { ConnectionOptions, Queue, Worker } from 'bullmq';
|
|
3
|
+
import { TaskData } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* BullMQ-based task driver for distributed task scheduling.
|
|
6
|
+
*
|
|
7
|
+
* This driver uses BullMQ to provide robust, distributed task scheduling with Redis
|
|
8
|
+
* as the backend. It supports both cron expressions and date-based scheduling, with
|
|
9
|
+
* built-in retry mechanisms and job persistence.
|
|
10
|
+
*
|
|
11
|
+
* **Requirements**: Requires the `bullmq` package to be installed.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { BullMQDriver } from '@commandkit/tasks/bullmq';
|
|
16
|
+
* import { setDriver } from '@commandkit/tasks';
|
|
17
|
+
*
|
|
18
|
+
* const driver = new BullMQDriver({
|
|
19
|
+
* host: 'localhost',
|
|
20
|
+
* port: 6379,
|
|
21
|
+
* }, 'my-tasks-queue');
|
|
22
|
+
*
|
|
23
|
+
* setDriver(driver);
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* // With custom Redis connection options
|
|
29
|
+
* const driver = new BullMQDriver({
|
|
30
|
+
* host: 'redis.example.com',
|
|
31
|
+
* port: 6379,
|
|
32
|
+
* password: 'your-password',
|
|
33
|
+
* tls: true,
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare class BullMQDriver implements TaskDriver {
|
|
38
|
+
private readonly queueName;
|
|
39
|
+
private runner;
|
|
40
|
+
/** The BullMQ queue instance for managing tasks */
|
|
41
|
+
readonly queue: Queue;
|
|
42
|
+
/** The BullMQ worker instance for processing tasks */
|
|
43
|
+
readonly worker: Worker;
|
|
44
|
+
/**
|
|
45
|
+
* Creates a new BullMQ driver instance.
|
|
46
|
+
*
|
|
47
|
+
* @param connection - Redis connection options for BullMQ
|
|
48
|
+
* @param queueName - Optional queue name, defaults to 'commandkit-tasks'
|
|
49
|
+
*/
|
|
50
|
+
constructor(connection: ConnectionOptions, queueName?: string);
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new scheduled task in BullMQ.
|
|
53
|
+
*
|
|
54
|
+
* For cron tasks, this creates a repeating job with the specified cron pattern.
|
|
55
|
+
* For date tasks, this creates a delayed job that executes at the specified time.
|
|
56
|
+
*
|
|
57
|
+
* @param task - The task data containing name, schedule, and custom data
|
|
58
|
+
* @returns A unique job identifier
|
|
59
|
+
*/
|
|
60
|
+
create(task: TaskData): Promise<string>;
|
|
61
|
+
/**
|
|
62
|
+
* Deletes a scheduled task from BullMQ.
|
|
63
|
+
*
|
|
64
|
+
* This removes the job and all its children (for repeating jobs) from the queue.
|
|
65
|
+
*
|
|
66
|
+
* @param identifier - The job identifier to delete
|
|
67
|
+
*/
|
|
68
|
+
delete(identifier: string): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Sets the task execution runner function.
|
|
71
|
+
*
|
|
72
|
+
* This function will be called by the BullMQ worker when a job is due for execution.
|
|
73
|
+
*
|
|
74
|
+
* @param runner - The function to call when a task should be executed
|
|
75
|
+
*/
|
|
76
|
+
setTaskRunner(runner: TaskRunner): Promise<void>;
|
|
77
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BullMQDriver = void 0;
|
|
4
|
+
const bullmq_1 = require("bullmq");
|
|
5
|
+
/**
|
|
6
|
+
* BullMQ-based task driver for distributed task scheduling.
|
|
7
|
+
*
|
|
8
|
+
* This driver uses BullMQ to provide robust, distributed task scheduling with Redis
|
|
9
|
+
* as the backend. It supports both cron expressions and date-based scheduling, with
|
|
10
|
+
* built-in retry mechanisms and job persistence.
|
|
11
|
+
*
|
|
12
|
+
* **Requirements**: Requires the `bullmq` package to be installed.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { BullMQDriver } from '@commandkit/tasks/bullmq';
|
|
17
|
+
* import { setDriver } from '@commandkit/tasks';
|
|
18
|
+
*
|
|
19
|
+
* const driver = new BullMQDriver({
|
|
20
|
+
* host: 'localhost',
|
|
21
|
+
* port: 6379,
|
|
22
|
+
* }, 'my-tasks-queue');
|
|
23
|
+
*
|
|
24
|
+
* setDriver(driver);
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* // With custom Redis connection options
|
|
30
|
+
* const driver = new BullMQDriver({
|
|
31
|
+
* host: 'redis.example.com',
|
|
32
|
+
* port: 6379,
|
|
33
|
+
* password: 'your-password',
|
|
34
|
+
* tls: true,
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
class BullMQDriver {
|
|
39
|
+
/**
|
|
40
|
+
* Creates a new BullMQ driver instance.
|
|
41
|
+
*
|
|
42
|
+
* @param connection - Redis connection options for BullMQ
|
|
43
|
+
* @param queueName - Optional queue name, defaults to 'commandkit-tasks'
|
|
44
|
+
*/
|
|
45
|
+
constructor(connection, queueName = 'commandkit-tasks') {
|
|
46
|
+
this.queueName = queueName;
|
|
47
|
+
this.runner = null;
|
|
48
|
+
this.queue = new bullmq_1.Queue(this.queueName, { connection });
|
|
49
|
+
this.worker = new bullmq_1.Worker(this.queueName, async (job) => {
|
|
50
|
+
if (!this.runner)
|
|
51
|
+
throw new Error('Task runner has not been set');
|
|
52
|
+
await this.runner({
|
|
53
|
+
name: job.name,
|
|
54
|
+
data: job.data,
|
|
55
|
+
timestamp: job.timestamp,
|
|
56
|
+
});
|
|
57
|
+
}, { connection });
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Creates a new scheduled task in BullMQ.
|
|
61
|
+
*
|
|
62
|
+
* For cron tasks, this creates a repeating job with the specified cron pattern.
|
|
63
|
+
* For date tasks, this creates a delayed job that executes at the specified time.
|
|
64
|
+
*
|
|
65
|
+
* @param task - The task data containing name, schedule, and custom data
|
|
66
|
+
* @returns A unique job identifier
|
|
67
|
+
*/
|
|
68
|
+
async create(task) {
|
|
69
|
+
const jobId = crypto.randomUUID();
|
|
70
|
+
const job = await this.queue.add(task.name, task.data, {
|
|
71
|
+
jobId,
|
|
72
|
+
...(task.schedule.type === 'cron'
|
|
73
|
+
? {
|
|
74
|
+
repeat: {
|
|
75
|
+
pattern: task.schedule.value,
|
|
76
|
+
tz: task.schedule.timezone,
|
|
77
|
+
immediately: !!task.immediate,
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
: {
|
|
81
|
+
delay: (task.schedule.value instanceof Date
|
|
82
|
+
? task.schedule.value.getTime()
|
|
83
|
+
: task.schedule.value) - Date.now(),
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
86
|
+
return job.id ?? jobId;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Deletes a scheduled task from BullMQ.
|
|
90
|
+
*
|
|
91
|
+
* This removes the job and all its children (for repeating jobs) from the queue.
|
|
92
|
+
*
|
|
93
|
+
* @param identifier - The job identifier to delete
|
|
94
|
+
*/
|
|
95
|
+
async delete(identifier) {
|
|
96
|
+
await this.queue.remove(identifier, { removeChildren: true });
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Sets the task execution runner function.
|
|
100
|
+
*
|
|
101
|
+
* This function will be called by the BullMQ worker when a job is due for execution.
|
|
102
|
+
*
|
|
103
|
+
* @param runner - The function to call when a task should be executed
|
|
104
|
+
*/
|
|
105
|
+
async setTaskRunner(runner) {
|
|
106
|
+
this.runner = runner;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.BullMQDriver = BullMQDriver;
|
|
110
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVsbG1xLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2RyaXZlcnMvYnVsbG1xLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLG1DQUEwRDtBQUcxRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQ0c7QUFDSCxNQUFhLFlBQVk7SUFTdkI7Ozs7O09BS0c7SUFDSCxZQUNFLFVBQTZCLEVBQ1osWUFBb0Isa0JBQWtCO1FBQXRDLGNBQVMsR0FBVCxTQUFTLENBQTZCO1FBaEJqRCxXQUFNLEdBQXNCLElBQUksQ0FBQztRQWtCdkMsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLGNBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUN2RCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksZUFBTSxDQUN0QixJQUFJLENBQUMsU0FBUyxFQUNkLEtBQUssRUFBRSxHQUFHLEVBQUUsRUFBRTtZQUNaLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTTtnQkFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixDQUFDLENBQUM7WUFFbEUsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDO2dCQUNoQixJQUFJLEVBQUUsR0FBRyxDQUFDLElBQUk7Z0JBQ2QsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJO2dCQUNkLFNBQVMsRUFBRSxHQUFHLENBQUMsU0FBUzthQUN6QixDQUFDLENBQUM7UUFDTCxDQUFDLEVBQ0QsRUFBRSxVQUFVLEVBQUUsQ0FDZixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7Ozs7OztPQVFHO0lBQ0ksS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFjO1FBQ2hDLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNsQyxNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRTtZQUNyRCxLQUFLO1lBQ0wsR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxLQUFLLE1BQU07Z0JBQy9CLENBQUMsQ0FBQztvQkFDRSxNQUFNLEVBQUU7d0JBQ04sT0FBTyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSzt3QkFDNUIsRUFBRSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUTt3QkFDMUIsV0FBVyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUztxQkFDOUI7aUJBQ0Y7Z0JBQ0gsQ0FBQyxDQUFDO29CQUNFLEtBQUssRUFDSCxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxZQUFZLElBQUk7d0JBQ2xDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUU7d0JBQy9CLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUU7aUJBQ3hDLENBQUM7U0FDUCxDQUFDLENBQUM7UUFFSCxPQUFPLEdBQUcsQ0FBQyxFQUFFLElBQUksS0FBSyxDQUFDO0lBQ3pCLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSSxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQWtCO1FBQ3BDLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDaEUsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNJLEtBQUssQ0FBQyxhQUFhLENBQUMsTUFBa0I7UUFDM0MsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7SUFDdkIsQ0FBQztDQUNGO0FBeEZELG9DQXdGQyJ9
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { TaskDriver, TaskRunner } from '../driver';
|
|
2
|
+
import { TaskData } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* HyperCron-based task driver for lightweight task scheduling.
|
|
5
|
+
*
|
|
6
|
+
* This driver uses HyperCron to provide simple, in-memory task scheduling.
|
|
7
|
+
* It's ideal for single-instance applications or development environments
|
|
8
|
+
* where you don't need distributed task scheduling.
|
|
9
|
+
*
|
|
10
|
+
* **Requirements**: Requires the `hypercron` package to be installed.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { HyperCronDriver } from '@commandkit/tasks/hypercron';
|
|
15
|
+
* import { setDriver } from '@commandkit/tasks';
|
|
16
|
+
*
|
|
17
|
+
* const driver = new HyperCronDriver();
|
|
18
|
+
* setDriver(driver);
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* // With custom cron service
|
|
24
|
+
* import { cronService } from 'hypercron';
|
|
25
|
+
*
|
|
26
|
+
* const customService = cronService.create({
|
|
27
|
+
* // Custom configuration
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* const driver = new HyperCronDriver(customService);
|
|
31
|
+
* setDriver(driver);
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare class HyperCronDriver implements TaskDriver {
|
|
35
|
+
private readonly service;
|
|
36
|
+
private runner;
|
|
37
|
+
/**
|
|
38
|
+
* Creates a new HyperCron driver instance.
|
|
39
|
+
*
|
|
40
|
+
* @param service - Optional custom cron service instance, defaults to the global cronService
|
|
41
|
+
*/
|
|
42
|
+
constructor(service?: import("hypercron").CronService);
|
|
43
|
+
/**
|
|
44
|
+
* Creates a new scheduled task in HyperCron.
|
|
45
|
+
*
|
|
46
|
+
* This schedules the task using the HyperCron service and starts the service
|
|
47
|
+
* if it's not already running.
|
|
48
|
+
*
|
|
49
|
+
* @param task - The task data containing name, schedule, and custom data
|
|
50
|
+
* @returns A unique schedule identifier
|
|
51
|
+
*/
|
|
52
|
+
create(task: TaskData): Promise<string>;
|
|
53
|
+
/**
|
|
54
|
+
* Deletes a scheduled task from HyperCron.
|
|
55
|
+
*
|
|
56
|
+
* This cancels the scheduled task and removes it from the cron service.
|
|
57
|
+
*
|
|
58
|
+
* @param identifier - The schedule identifier to delete
|
|
59
|
+
*/
|
|
60
|
+
delete(identifier: string): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Sets the task execution runner function.
|
|
63
|
+
*
|
|
64
|
+
* This function will be called by the HyperCron service when a task is due for execution.
|
|
65
|
+
*
|
|
66
|
+
* @param runner - The function to call when a task should be executed
|
|
67
|
+
*/
|
|
68
|
+
setTaskRunner(runner: TaskRunner): Promise<void>;
|
|
69
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HyperCronDriver = void 0;
|
|
4
|
+
const hypercron_1 = require("hypercron");
|
|
5
|
+
/**
|
|
6
|
+
* HyperCron-based task driver for lightweight task scheduling.
|
|
7
|
+
*
|
|
8
|
+
* This driver uses HyperCron to provide simple, in-memory task scheduling.
|
|
9
|
+
* It's ideal for single-instance applications or development environments
|
|
10
|
+
* where you don't need distributed task scheduling.
|
|
11
|
+
*
|
|
12
|
+
* **Requirements**: Requires the `hypercron` package to be installed.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { HyperCronDriver } from '@commandkit/tasks/hypercron';
|
|
17
|
+
* import { setDriver } from '@commandkit/tasks';
|
|
18
|
+
*
|
|
19
|
+
* const driver = new HyperCronDriver();
|
|
20
|
+
* setDriver(driver);
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* // With custom cron service
|
|
26
|
+
* import { cronService } from 'hypercron';
|
|
27
|
+
*
|
|
28
|
+
* const customService = cronService.create({
|
|
29
|
+
* // Custom configuration
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* const driver = new HyperCronDriver(customService);
|
|
33
|
+
* setDriver(driver);
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
class HyperCronDriver {
|
|
37
|
+
/**
|
|
38
|
+
* Creates a new HyperCron driver instance.
|
|
39
|
+
*
|
|
40
|
+
* @param service - Optional custom cron service instance, defaults to the global cronService
|
|
41
|
+
*/
|
|
42
|
+
constructor(service = hypercron_1.cronService) {
|
|
43
|
+
this.service = service;
|
|
44
|
+
this.runner = null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Creates a new scheduled task in HyperCron.
|
|
48
|
+
*
|
|
49
|
+
* This schedules the task using the HyperCron service and starts the service
|
|
50
|
+
* if it's not already running.
|
|
51
|
+
*
|
|
52
|
+
* @param task - The task data containing name, schedule, and custom data
|
|
53
|
+
* @returns A unique schedule identifier
|
|
54
|
+
*/
|
|
55
|
+
async create(task) {
|
|
56
|
+
const id = await this.service.schedule(task.schedule.value, task.name, async () => {
|
|
57
|
+
if (!this.runner)
|
|
58
|
+
throw new Error('Task runner has not been set');
|
|
59
|
+
await this.runner({
|
|
60
|
+
name: task.name,
|
|
61
|
+
data: task.data,
|
|
62
|
+
timestamp: Date.now(),
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
await this.service.start();
|
|
66
|
+
return id;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Deletes a scheduled task from HyperCron.
|
|
70
|
+
*
|
|
71
|
+
* This cancels the scheduled task and removes it from the cron service.
|
|
72
|
+
*
|
|
73
|
+
* @param identifier - The schedule identifier to delete
|
|
74
|
+
*/
|
|
75
|
+
async delete(identifier) {
|
|
76
|
+
await this.service.cancel(identifier);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Sets the task execution runner function.
|
|
80
|
+
*
|
|
81
|
+
* This function will be called by the HyperCron service when a task is due for execution.
|
|
82
|
+
*
|
|
83
|
+
* @param runner - The function to call when a task should be executed
|
|
84
|
+
*/
|
|
85
|
+
async setTaskRunner(runner) {
|
|
86
|
+
this.runner = runner;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.HyperCronDriver = HyperCronDriver;
|
|
90
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHlwZXJjcm9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2RyaXZlcnMvaHlwZXJjcm9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHlDQUF3QztBQUl4Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBOEJHO0FBQ0gsTUFBYSxlQUFlO0lBRzFCOzs7O09BSUc7SUFDSCxZQUFvQyxVQUFVLHVCQUFXO1FBQXJCLFlBQU8sR0FBUCxPQUFPLENBQWM7UUFQakQsV0FBTSxHQUFzQixJQUFJLENBQUM7SUFPbUIsQ0FBQztJQUU3RDs7Ozs7Ozs7T0FRRztJQUNJLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBYztRQUNoQyxNQUFNLEVBQUUsR0FBRyxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUNwQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFDbkIsSUFBSSxDQUFDLElBQUksRUFDVCxLQUFLLElBQUksRUFBRTtZQUNULElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTTtnQkFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixDQUFDLENBQUM7WUFFbEUsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDO2dCQUNoQixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUk7Z0JBQ2YsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJO2dCQUNmLFNBQVMsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFO2FBQ3RCLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FDRixDQUFDO1FBRUYsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBRTNCLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNJLEtBQUssQ0FBQyxNQUFNLENBQUMsVUFBa0I7UUFDcEMsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ksS0FBSyxDQUFDLGFBQWEsQ0FBQyxNQUFrQjtRQUMzQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztJQUN2QixDQUFDO0NBQ0Y7QUE1REQsMENBNERDIn0=
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { TasksPlugin, TasksPluginOptions } from './plugin';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a tasks plugin instance for CommandKit.
|
|
4
|
+
*
|
|
5
|
+
* This plugin provides task management capabilities including:
|
|
6
|
+
* - Static task definitions with cron and date-based scheduling
|
|
7
|
+
* - Dynamic task creation and management
|
|
8
|
+
* - Hot module replacement (HMR) support for development
|
|
9
|
+
* - Multiple persistence drivers (in-memory, SQLite, BullMQ)
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { tasks } from '@commandkit/tasks';
|
|
14
|
+
*
|
|
15
|
+
* export default {
|
|
16
|
+
* plugins: [
|
|
17
|
+
* tasks({
|
|
18
|
+
* tasksPath: 'app/tasks',
|
|
19
|
+
* enableHMR: true,
|
|
20
|
+
* }),
|
|
21
|
+
* ],
|
|
22
|
+
* };
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @param options - Configuration options for the tasks plugin
|
|
26
|
+
* @returns A configured tasks plugin instance
|
|
27
|
+
*/
|
|
28
|
+
export declare function tasks(options?: TasksPluginOptions): TasksPlugin;
|
|
29
|
+
export * from './plugin';
|
|
30
|
+
export * from './task';
|
|
31
|
+
export * from './types';
|
|
32
|
+
export * from './driver';
|
|
33
|
+
export * from './driver-manager';
|
|
34
|
+
export * from './context';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.tasks = tasks;
|
|
18
|
+
const plugin_1 = require("./plugin");
|
|
19
|
+
/**
|
|
20
|
+
* Creates a tasks plugin instance for CommandKit.
|
|
21
|
+
*
|
|
22
|
+
* This plugin provides task management capabilities including:
|
|
23
|
+
* - Static task definitions with cron and date-based scheduling
|
|
24
|
+
* - Dynamic task creation and management
|
|
25
|
+
* - Hot module replacement (HMR) support for development
|
|
26
|
+
* - Multiple persistence drivers (in-memory, SQLite, BullMQ)
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { tasks } from '@commandkit/tasks';
|
|
31
|
+
*
|
|
32
|
+
* export default {
|
|
33
|
+
* plugins: [
|
|
34
|
+
* tasks({
|
|
35
|
+
* tasksPath: 'app/tasks',
|
|
36
|
+
* enableHMR: true,
|
|
37
|
+
* }),
|
|
38
|
+
* ],
|
|
39
|
+
* };
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @param options - Configuration options for the tasks plugin
|
|
43
|
+
* @returns A configured tasks plugin instance
|
|
44
|
+
*/
|
|
45
|
+
function tasks(options) {
|
|
46
|
+
return new plugin_1.TasksPlugin(options ?? {});
|
|
47
|
+
}
|
|
48
|
+
__exportStar(require("./plugin"), exports);
|
|
49
|
+
__exportStar(require("./task"), exports);
|
|
50
|
+
__exportStar(require("./types"), exports);
|
|
51
|
+
__exportStar(require("./driver"), exports);
|
|
52
|
+
__exportStar(require("./driver-manager"), exports);
|
|
53
|
+
__exportStar(require("./context"), exports);
|
|
54
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQTRCQSxzQkFFQztBQTlCRCxxQ0FBMkQ7QUFFM0Q7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Qkc7QUFDSCxTQUFnQixLQUFLLENBQUMsT0FBNEI7SUFDaEQsT0FBTyxJQUFJLG9CQUFXLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0FBQ3hDLENBQUM7QUFFRCwyQ0FBeUI7QUFDekIseUNBQXVCO0FBQ3ZCLDBDQUF3QjtBQUN4QiwyQ0FBeUI7QUFDekIsbURBQWlDO0FBQ2pDLDRDQUEwQiJ9
|