@donkeylabs/server 0.3.0 → 0.4.0

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.
Files changed (49) hide show
  1. package/LICENSE +1 -1
  2. package/docs/api-client.md +7 -7
  3. package/docs/cache.md +1 -74
  4. package/docs/core-services.md +4 -116
  5. package/docs/cron.md +1 -1
  6. package/docs/errors.md +2 -2
  7. package/docs/events.md +3 -98
  8. package/docs/handlers.md +13 -48
  9. package/docs/logger.md +3 -58
  10. package/docs/middleware.md +2 -2
  11. package/docs/plugins.md +13 -64
  12. package/docs/project-structure.md +4 -142
  13. package/docs/rate-limiter.md +4 -136
  14. package/docs/router.md +6 -14
  15. package/docs/sse.md +1 -99
  16. package/docs/sveltekit-adapter.md +420 -0
  17. package/package.json +8 -11
  18. package/registry.d.ts +15 -14
  19. package/src/core/cache.ts +0 -75
  20. package/src/core/cron.ts +3 -96
  21. package/src/core/errors.ts +78 -11
  22. package/src/core/events.ts +1 -47
  23. package/src/core/index.ts +0 -4
  24. package/src/core/jobs.ts +0 -112
  25. package/src/core/logger.ts +12 -79
  26. package/src/core/rate-limiter.ts +29 -108
  27. package/src/core/sse.ts +1 -84
  28. package/src/core.ts +13 -104
  29. package/src/generator/index.ts +566 -0
  30. package/src/generator/zod-to-ts.ts +114 -0
  31. package/src/handlers.ts +14 -110
  32. package/src/index.ts +30 -24
  33. package/src/middleware.ts +2 -5
  34. package/src/registry.ts +4 -0
  35. package/src/router.ts +47 -1
  36. package/src/server.ts +618 -332
  37. package/README.md +0 -254
  38. package/cli/commands/dev.ts +0 -134
  39. package/cli/commands/generate.ts +0 -605
  40. package/cli/commands/init.ts +0 -205
  41. package/cli/commands/interactive.ts +0 -417
  42. package/cli/commands/plugin.ts +0 -192
  43. package/cli/commands/route.ts +0 -195
  44. package/cli/donkeylabs +0 -2
  45. package/cli/index.ts +0 -114
  46. package/docs/svelte-frontend.md +0 -324
  47. package/docs/testing.md +0 -438
  48. package/mcp/donkeylabs-mcp +0 -3238
  49. package/mcp/server.ts +0 -3238
package/src/core/cache.ts CHANGED
@@ -24,17 +24,6 @@ export interface Cache {
24
24
  clear(): Promise<void>;
25
25
  keys(pattern?: string): Promise<string[]>;
26
26
  getOrSet<T>(key: string, factory: () => Promise<T>, ttlMs?: number): Promise<T>;
27
-
28
- /** Create a namespaced cache with automatic key prefixing */
29
- namespace(prefix: string): NamespacedCache;
30
- }
31
-
32
- /** A cache namespace with automatic key prefixing and optional TTL policy */
33
- export interface NamespacedCache extends Omit<Cache, "namespace"> {
34
- /** The namespace prefix */
35
- readonly prefix: string;
36
- /** Clear only keys in this namespace */
37
- clearNamespace(): Promise<void>;
38
27
  }
39
28
 
40
29
  interface CacheEntry<T> {
@@ -187,70 +176,6 @@ class CacheImpl implements Cache {
187
176
  await this.set(key, value, ttlMs);
188
177
  return value;
189
178
  }
190
-
191
- namespace(prefix: string): NamespacedCache {
192
- return new NamespacedCacheImpl(this, prefix);
193
- }
194
- }
195
-
196
- /** Namespaced cache that automatically prefixes all keys */
197
- class NamespacedCacheImpl implements NamespacedCache {
198
- readonly prefix: string;
199
- private parent: Cache;
200
-
201
- constructor(parent: Cache, prefix: string) {
202
- this.parent = parent;
203
- this.prefix = prefix.endsWith(":") ? prefix : `${prefix}:`;
204
- }
205
-
206
- private prefixKey(key: string): string {
207
- return `${this.prefix}${key}`;
208
- }
209
-
210
- async get<T>(key: string): Promise<T | null> {
211
- return this.parent.get<T>(this.prefixKey(key));
212
- }
213
-
214
- async set<T>(key: string, value: T, ttlMs?: number): Promise<void> {
215
- return this.parent.set(this.prefixKey(key), value, ttlMs);
216
- }
217
-
218
- async delete(key: string): Promise<boolean> {
219
- return this.parent.delete(this.prefixKey(key));
220
- }
221
-
222
- async has(key: string): Promise<boolean> {
223
- return this.parent.has(this.prefixKey(key));
224
- }
225
-
226
- async clear(): Promise<void> {
227
- // Clear the entire cache (same as parent)
228
- return this.parent.clear();
229
- }
230
-
231
- async clearNamespace(): Promise<void> {
232
- // Clear only keys with this namespace prefix
233
- const keys = await this.parent.keys(`${this.prefix}*`);
234
- for (const key of keys) {
235
- await this.parent.delete(key);
236
- }
237
- }
238
-
239
- async keys(pattern?: string): Promise<string[]> {
240
- // Get keys with namespace prefix, then strip the prefix from results
241
- const fullPattern = pattern ? `${this.prefix}${pattern}` : `${this.prefix}*`;
242
- const keys = await this.parent.keys(fullPattern);
243
- return keys.map(k => k.slice(this.prefix.length));
244
- }
245
-
246
- async getOrSet<T>(key: string, factory: () => Promise<T>, ttlMs?: number): Promise<T> {
247
- const existing = await this.get<T>(key);
248
- if (existing !== null) return existing;
249
-
250
- const value = await factory();
251
- await this.set(key, value, ttlMs);
252
- return value;
253
- }
254
179
  }
255
180
 
256
181
  export function createCache(config?: CacheConfig): Cache {
package/src/core/cron.ts CHANGED
@@ -9,22 +9,6 @@ export interface CronTask {
9
9
  enabled: boolean;
10
10
  lastRun?: Date;
11
11
  nextRun?: Date;
12
- /** Plugin that registered this task */
13
- pluginName?: string;
14
- /** Optional description */
15
- description?: string;
16
- }
17
-
18
- /** Declarative cron task definition for plugin registration */
19
- export interface CronTaskDefinition {
20
- /** Cron expression (5 or 6 fields) */
21
- expression: string;
22
- /** Task handler function */
23
- handler: () => void | Promise<void>;
24
- /** Whether task starts enabled (default: true) */
25
- enabled?: boolean;
26
- /** Optional description */
27
- description?: string;
28
12
  }
29
13
 
30
14
  export interface CronConfig {
@@ -32,39 +16,16 @@ export interface CronConfig {
32
16
  }
33
17
 
34
18
  export interface Cron {
35
- /** Schedule a cron task (imperative API) */
36
19
  schedule(
37
20
  expression: string,
38
21
  handler: () => void | Promise<void>,
39
- options?: { name?: string; enabled?: boolean; pluginName?: string; description?: string }
22
+ options?: { name?: string; enabled?: boolean }
40
23
  ): string;
41
-
42
- /** Register a named cron task (declarative API) */
43
- registerTask(
44
- name: string,
45
- definition: CronTaskDefinition,
46
- pluginName?: string
47
- ): string;
48
-
49
- /** Register multiple cron tasks (for plugins) */
50
- registerTasks(
51
- tasks: Record<string, CronTaskDefinition>,
52
- pluginName?: string
53
- ): string[];
54
-
55
24
  unschedule(taskId: string): boolean;
56
25
  pause(taskId: string): void;
57
26
  resume(taskId: string): void;
58
27
  list(): CronTask[];
59
-
60
- /** List tasks registered by a specific plugin */
61
- listByPlugin(pluginName: string): CronTask[];
62
-
63
28
  get(taskId: string): CronTask | undefined;
64
-
65
- /** Get task by name */
66
- getByName(name: string): CronTask | undefined;
67
-
68
29
  trigger(taskId: string): Promise<void>;
69
30
  start(): void;
70
31
  stop(): Promise<void>;
@@ -170,12 +131,8 @@ interface InternalCronTask extends CronTask {
170
131
  _cronExpr: CronExpression;
171
132
  }
172
133
 
173
- /** Index tasks by name for quick lookup */
174
- type TaskNameIndex = Map<string, string>; // name -> id
175
-
176
134
  class CronImpl implements Cron {
177
135
  private tasks = new Map<string, InternalCronTask>();
178
- private taskNameIndex: TaskNameIndex = new Map();
179
136
  private running = false;
180
137
  private timer: ReturnType<typeof setInterval> | null = null;
181
138
  private taskCounter = 0;
@@ -187,63 +144,27 @@ class CronImpl implements Cron {
187
144
  schedule(
188
145
  expression: string,
189
146
  handler: () => void | Promise<void>,
190
- options: { name?: string; enabled?: boolean; pluginName?: string; description?: string } = {}
147
+ options: { name?: string; enabled?: boolean } = {}
191
148
  ): string {
192
149
  const id = `cron_${++this.taskCounter}_${Date.now()}`;
193
150
  const cronExpr = new CronExpression(expression);
194
- const name = options.name ?? id;
195
151
 
196
152
  const task: InternalCronTask = {
197
153
  id,
198
- name,
154
+ name: options.name ?? id,
199
155
  expression,
200
156
  handler,
201
157
  enabled: options.enabled ?? true,
202
158
  nextRun: cronExpr.getNextRun(),
203
- pluginName: options.pluginName,
204
- description: options.description,
205
159
  _cronExpr: cronExpr,
206
160
  };
207
161
 
208
162
  this.tasks.set(id, task);
209
- this.taskNameIndex.set(name, id);
210
163
 
211
164
  return id;
212
165
  }
213
166
 
214
- registerTask(
215
- name: string,
216
- definition: CronTaskDefinition,
217
- pluginName?: string
218
- ): string {
219
- if (this.taskNameIndex.has(name)) {
220
- throw new Error(`Cron task "${name}" is already registered`);
221
- }
222
-
223
- return this.schedule(definition.expression, definition.handler, {
224
- name,
225
- enabled: definition.enabled,
226
- pluginName,
227
- description: definition.description,
228
- });
229
- }
230
-
231
- registerTasks(
232
- tasks: Record<string, CronTaskDefinition>,
233
- pluginName?: string
234
- ): string[] {
235
- const ids: string[] = [];
236
- for (const [name, definition] of Object.entries(tasks)) {
237
- ids.push(this.registerTask(name, definition, pluginName));
238
- }
239
- return ids;
240
- }
241
-
242
167
  unschedule(taskId: string): boolean {
243
- const task = this.tasks.get(taskId);
244
- if (task) {
245
- this.taskNameIndex.delete(task.name);
246
- }
247
168
  return this.tasks.delete(taskId);
248
169
  }
249
170
 
@@ -270,15 +191,9 @@ class CronImpl implements Cron {
270
191
  enabled: t.enabled,
271
192
  lastRun: t.lastRun,
272
193
  nextRun: t.nextRun,
273
- pluginName: t.pluginName,
274
- description: t.description,
275
194
  }));
276
195
  }
277
196
 
278
- listByPlugin(pluginName: string): CronTask[] {
279
- return this.list().filter(task => task.pluginName === pluginName);
280
- }
281
-
282
197
  get(taskId: string): CronTask | undefined {
283
198
  const task = this.tasks.get(taskId);
284
199
  if (!task) return undefined;
@@ -290,17 +205,9 @@ class CronImpl implements Cron {
290
205
  enabled: task.enabled,
291
206
  lastRun: task.lastRun,
292
207
  nextRun: task.nextRun,
293
- pluginName: task.pluginName,
294
- description: task.description,
295
208
  };
296
209
  }
297
210
 
298
- getByName(name: string): CronTask | undefined {
299
- const id = this.taskNameIndex.get(name);
300
- if (!id) return undefined;
301
- return this.get(id);
302
- }
303
-
304
211
  async trigger(taskId: string): Promise<void> {
305
212
  const task = this.tasks.get(taskId);
306
213
  if (!task) throw new Error(`Task ${taskId} not found`);
@@ -3,9 +3,21 @@
3
3
  *
4
4
  * Provides throwable HTTP errors that are automatically caught by the server
5
5
  * and converted to proper HTTP responses with status codes and error bodies.
6
+ *
7
+ * Usage:
8
+ * throw ctx.errors.BadRequest("Invalid user ID");
9
+ * throw ctx.errors.NotFound("User not found", { userId: 123 });
10
+ * throw ctx.errors.Unauthorized("Please log in");
6
11
  */
7
12
 
8
- /** Base class for all HTTP errors */
13
+ // ==========================================
14
+ // Base HTTP Error
15
+ // ==========================================
16
+
17
+ /**
18
+ * Base class for all HTTP errors.
19
+ * Thrown errors are caught by the server and converted to HTTP responses.
20
+ */
9
21
  export class HttpError extends Error {
10
22
  /** HTTP status code */
11
23
  readonly status: number;
@@ -56,6 +68,10 @@ export class HttpError extends Error {
56
68
  }
57
69
  }
58
70
 
71
+ // ==========================================
72
+ // Standard HTTP Error Classes
73
+ // ==========================================
74
+
59
75
  /** 400 Bad Request */
60
76
  export class BadRequestError extends HttpError {
61
77
  constructor(message: string = "Bad Request", details?: Record<string, any>, cause?: Error) {
@@ -168,35 +184,65 @@ export class GatewayTimeoutError extends HttpError {
168
184
  }
169
185
  }
170
186
 
171
- /** Factory function signature for creating errors */
187
+ // ==========================================
188
+ // Error Factory Type
189
+ // ==========================================
190
+
191
+ /**
192
+ * Factory function signature for creating errors
193
+ */
172
194
  export type ErrorFactory<T extends HttpError = HttpError> = (
173
195
  message?: string,
174
196
  details?: Record<string, any>,
175
197
  cause?: Error
176
198
  ) => T;
177
199
 
178
- /** Base error factories available on ctx.errors */
200
+ /**
201
+ * Base error factories available on ctx.errors
202
+ */
179
203
  export interface BaseErrorFactories {
204
+ /** 400 Bad Request */
180
205
  BadRequest: ErrorFactory<BadRequestError>;
206
+ /** 401 Unauthorized */
181
207
  Unauthorized: ErrorFactory<UnauthorizedError>;
208
+ /** 403 Forbidden */
182
209
  Forbidden: ErrorFactory<ForbiddenError>;
210
+ /** 404 Not Found */
183
211
  NotFound: ErrorFactory<NotFoundError>;
212
+ /** 405 Method Not Allowed */
184
213
  MethodNotAllowed: ErrorFactory<MethodNotAllowedError>;
214
+ /** 409 Conflict */
185
215
  Conflict: ErrorFactory<ConflictError>;
216
+ /** 410 Gone */
186
217
  Gone: ErrorFactory<GoneError>;
218
+ /** 422 Unprocessable Entity */
187
219
  UnprocessableEntity: ErrorFactory<UnprocessableEntityError>;
220
+ /** 429 Too Many Requests */
188
221
  TooManyRequests: ErrorFactory<TooManyRequestsError>;
222
+ /** 500 Internal Server Error */
189
223
  InternalServer: ErrorFactory<InternalServerError>;
224
+ /** 501 Not Implemented */
190
225
  NotImplemented: ErrorFactory<NotImplementedError>;
226
+ /** 502 Bad Gateway */
191
227
  BadGateway: ErrorFactory<BadGatewayError>;
228
+ /** 503 Service Unavailable */
192
229
  ServiceUnavailable: ErrorFactory<ServiceUnavailableError>;
230
+ /** 504 Gateway Timeout */
193
231
  GatewayTimeout: ErrorFactory<GatewayTimeoutError>;
194
232
  }
195
233
 
196
- /** Extended error factories (augmented by plugins and user) */
234
+ /**
235
+ * Extended error factories (augmented by plugins and user)
236
+ */
197
237
  export interface ErrorFactories extends BaseErrorFactories {}
198
238
 
199
- /** Definition for a custom error type */
239
+ // ==========================================
240
+ // Custom Error Definition
241
+ // ==========================================
242
+
243
+ /**
244
+ * Definition for a custom error type
245
+ */
200
246
  export interface CustomErrorDefinition {
201
247
  /** HTTP status code */
202
248
  status: number;
@@ -206,9 +252,15 @@ export interface CustomErrorDefinition {
206
252
  defaultMessage?: string;
207
253
  }
208
254
 
209
- /** Registry of custom error definitions */
255
+ /**
256
+ * Registry of custom error definitions
257
+ */
210
258
  export type CustomErrorRegistry = Record<string, CustomErrorDefinition>;
211
259
 
260
+ // ==========================================
261
+ // Error Service
262
+ // ==========================================
263
+
212
264
  export interface ErrorsConfig {
213
265
  /** Include stack traces in error responses (default: false in production) */
214
266
  includeStackTrace?: boolean;
@@ -217,7 +269,9 @@ export interface ErrorsConfig {
217
269
  }
218
270
 
219
271
  export interface Errors extends ErrorFactories {
220
- /** Create a custom HTTP error */
272
+ /**
273
+ * Create a custom HTTP error
274
+ */
221
275
  custom(
222
276
  status: number,
223
277
  code: string,
@@ -226,17 +280,23 @@ export interface Errors extends ErrorFactories {
226
280
  cause?: Error
227
281
  ): HttpError;
228
282
 
229
- /** Check if an error is an HttpError */
283
+ /**
284
+ * Check if an error is an HttpError
285
+ */
230
286
  isHttpError(error: unknown): error is HttpError;
231
287
 
232
- /** Register a custom error type */
288
+ /**
289
+ * Register a custom error type
290
+ */
233
291
  register<K extends string>(
234
292
  name: K,
235
293
  definition: CustomErrorDefinition
236
294
  ): void;
237
295
  }
238
296
 
239
- /** Create the errors service */
297
+ /**
298
+ * Create the errors service
299
+ */
240
300
  export function createErrors(config: ErrorsConfig = {}): Errors {
241
301
  const customErrors = new Map<string, CustomErrorDefinition>(
242
302
  Object.entries(config.customErrors || {})
@@ -307,7 +367,14 @@ export function createErrors(config: ErrorsConfig = {}): Errors {
307
367
  return errors;
308
368
  }
309
369
 
310
- /** Create a BadRequestError with validation details (useful for Zod validation errors) */
370
+ // ==========================================
371
+ // Validation Error Helper
372
+ // ==========================================
373
+
374
+ /**
375
+ * Create a BadRequestError with validation details
376
+ * Useful for Zod validation errors
377
+ */
311
378
  export function createValidationError(
312
379
  issues: Array<{ path: (string | number)[]; message: string }>
313
380
  ): BadRequestError {
@@ -1,7 +1,5 @@
1
1
  // Core Events Service
2
- // Pub/sub async event queue with schema validation
3
-
4
- import { z } from "zod";
2
+ // Pub/sub async event queue
5
3
 
6
4
  export interface EventHandler<T = any> {
7
5
  (data: T): void | Promise<void>;
@@ -28,15 +26,6 @@ export interface EventsConfig {
28
26
  }
29
27
 
30
28
  export interface Events {
31
- // Schema registration (strict - events must be registered before emit)
32
- register<T>(event: string, schema: z.ZodType<T>): void;
33
- registerMany(schemas: Record<string, z.ZodType<any>>): void;
34
- isRegistered(event: string): boolean;
35
- getSchema(event: string): z.ZodType<any> | undefined;
36
- /** List all registered event names */
37
- listRegistered(): string[];
38
-
39
- // Event operations
40
29
  emit<T = any>(event: string, data: T): Promise<void>;
41
30
  on<T = any>(event: string, handler: EventHandler<T>): Subscription;
42
31
  once<T = any>(event: string, handler: EventHandler<T>): Subscription;
@@ -78,47 +67,12 @@ export class MemoryEventAdapter implements EventAdapter {
78
67
  class EventsImpl implements Events {
79
68
  private handlers = new Map<string, Set<EventHandler>>();
80
69
  private adapter: EventAdapter;
81
- private schemas = new Map<string, z.ZodType<any>>();
82
70
 
83
71
  constructor(config: EventsConfig = {}) {
84
72
  this.adapter = config.adapter ?? new MemoryEventAdapter(config.maxHistorySize);
85
73
  }
86
74
 
87
- register<T>(event: string, schema: z.ZodType<T>): void {
88
- this.schemas.set(event, schema);
89
- }
90
-
91
- registerMany(schemas: Record<string, z.ZodType<any>>): void {
92
- for (const [name, schema] of Object.entries(schemas)) {
93
- this.schemas.set(name, schema);
94
- }
95
- }
96
-
97
- isRegistered(event: string): boolean {
98
- return this.schemas.has(event);
99
- }
100
-
101
- getSchema(event: string): z.ZodType<any> | undefined {
102
- return this.schemas.get(event);
103
- }
104
-
105
- listRegistered(): string[] {
106
- return Array.from(this.schemas.keys());
107
- }
108
-
109
75
  async emit<T = any>(event: string, data: T): Promise<void> {
110
- // Strict mode: event must be registered
111
- const schema = this.schemas.get(event);
112
- if (!schema) {
113
- throw new Error(`Event '${event}' is not registered. Register it first with events.register() or in plugin events config.`);
114
- }
115
-
116
- // Validate data against schema
117
- const result = schema.safeParse(data);
118
- if (!result.success) {
119
- throw new Error(`Event '${event}' validation failed: ${result.error.message}`);
120
- }
121
-
122
76
  // Store in adapter (for history/persistence)
123
77
  await this.adapter.publish(event, data);
124
78
 
package/src/core/index.ts CHANGED
@@ -12,7 +12,6 @@ export {
12
12
 
13
13
  export {
14
14
  type Cache,
15
- type NamespacedCache,
16
15
  type CacheAdapter,
17
16
  type CacheConfig,
18
17
  MemoryCacheAdapter,
@@ -33,7 +32,6 @@ export {
33
32
  export {
34
33
  type Cron,
35
34
  type CronTask,
36
- type CronTaskDefinition,
37
35
  type CronConfig,
38
36
  createCron,
39
37
  } from "./cron";
@@ -43,8 +41,6 @@ export {
43
41
  type Job,
44
42
  type JobStatus,
45
43
  type JobHandler,
46
- type JobDefinition,
47
- type RegisteredJob,
48
44
  type JobAdapter,
49
45
  type JobsConfig,
50
46
  MemoryJobAdapter,
package/src/core/jobs.ts CHANGED
@@ -2,7 +2,6 @@
2
2
  // Background job queue with scheduling
3
3
 
4
4
  import type { Events } from "./events";
5
- import type { z } from "zod";
6
5
 
7
6
  export type JobStatus = "pending" | "running" | "completed" | "failed" | "scheduled";
8
7
 
@@ -43,53 +42,8 @@ export interface JobsConfig {
43
42
  maxAttempts?: number; // Default retry attempts, default 3
44
43
  }
45
44
 
46
- export interface JobDefinition<T = any, R = any> {
47
- /** Zod schema for validating job payloads */
48
- schema: z.ZodType<T>;
49
- /** Job handler function */
50
- handler: JobHandler<T, R>;
51
- /** Optional description */
52
- description?: string;
53
- }
54
-
55
- export interface RegisteredJob {
56
- name: string;
57
- schema: z.ZodType<any>;
58
- handler: JobHandler;
59
- description?: string;
60
- /** Plugin that registered this job */
61
- pluginName?: string;
62
- }
63
-
64
45
  export interface Jobs {
65
- /** Register a job with handler only (backward compatible, but no payload validation) */
66
46
  register<T = any, R = any>(name: string, handler: JobHandler<T, R>): void;
67
-
68
- /** Register a job with schema validation and handler */
69
- registerJob<T = any, R = any>(
70
- name: string,
71
- definition: JobDefinition<T, R>,
72
- pluginName?: string
73
- ): void;
74
-
75
- /** Register multiple jobs at once (for plugins) */
76
- registerJobs(
77
- jobs: Record<string, JobDefinition>,
78
- pluginName?: string
79
- ): void;
80
-
81
- /** Check if a job is registered */
82
- isRegistered(name: string): boolean;
83
-
84
- /** Get registered job info */
85
- getRegisteredJob(name: string): RegisteredJob | undefined;
86
-
87
- /** List all registered jobs */
88
- listRegisteredJobs(): RegisteredJob[];
89
-
90
- /** List registered jobs by plugin */
91
- listJobsByPlugin(pluginName: string): RegisteredJob[];
92
-
93
47
  enqueue<T = any>(name: string, data: T, options?: { maxAttempts?: number }): Promise<string>;
94
48
  schedule<T = any>(name: string, data: T, runAt: Date, options?: { maxAttempts?: number }): Promise<string>;
95
49
  get(jobId: string): Promise<Job | null>;
@@ -162,7 +116,6 @@ class JobsImpl implements Jobs {
162
116
  private adapter: JobAdapter;
163
117
  private events?: Events;
164
118
  private handlers = new Map<string, JobHandler>();
165
- private registeredJobs = new Map<string, RegisteredJob>();
166
119
  private running = false;
167
120
  private timer: ReturnType<typeof setInterval> | null = null;
168
121
  private activeJobs = 0;
@@ -185,67 +138,11 @@ class JobsImpl implements Jobs {
185
138
  this.handlers.set(name, handler);
186
139
  }
187
140
 
188
- registerJob<T = any, R = any>(
189
- name: string,
190
- definition: JobDefinition<T, R>,
191
- pluginName?: string
192
- ): void {
193
- if (this.registeredJobs.has(name)) {
194
- throw new Error(`Job "${name}" is already registered`);
195
- }
196
-
197
- this.registeredJobs.set(name, {
198
- name,
199
- schema: definition.schema,
200
- handler: definition.handler,
201
- description: definition.description,
202
- pluginName,
203
- });
204
-
205
- // Also register the handler in the handlers map for backward compatibility
206
- this.handlers.set(name, definition.handler);
207
- }
208
-
209
- registerJobs(
210
- jobs: Record<string, JobDefinition>,
211
- pluginName?: string
212
- ): void {
213
- for (const [name, definition] of Object.entries(jobs)) {
214
- this.registerJob(name, definition, pluginName);
215
- }
216
- }
217
-
218
- isRegistered(name: string): boolean {
219
- return this.registeredJobs.has(name) || this.handlers.has(name);
220
- }
221
-
222
- getRegisteredJob(name: string): RegisteredJob | undefined {
223
- return this.registeredJobs.get(name);
224
- }
225
-
226
- listRegisteredJobs(): RegisteredJob[] {
227
- return Array.from(this.registeredJobs.values());
228
- }
229
-
230
- listJobsByPlugin(pluginName: string): RegisteredJob[] {
231
- return Array.from(this.registeredJobs.values())
232
- .filter(job => job.pluginName === pluginName);
233
- }
234
-
235
141
  async enqueue<T = any>(name: string, data: T, options: { maxAttempts?: number } = {}): Promise<string> {
236
142
  if (!this.handlers.has(name)) {
237
143
  throw new Error(`No handler registered for job "${name}"`);
238
144
  }
239
145
 
240
- // Validate payload if schema is registered
241
- const registered = this.registeredJobs.get(name);
242
- if (registered) {
243
- const result = registered.schema.safeParse(data);
244
- if (!result.success) {
245
- throw new Error(`Job "${name}" payload validation failed: ${result.error.message}`);
246
- }
247
- }
248
-
249
146
  const job = await this.adapter.create({
250
147
  name,
251
148
  data,
@@ -268,15 +165,6 @@ class JobsImpl implements Jobs {
268
165
  throw new Error(`No handler registered for job "${name}"`);
269
166
  }
270
167
 
271
- // Validate payload if schema is registered
272
- const registered = this.registeredJobs.get(name);
273
- if (registered) {
274
- const result = registered.schema.safeParse(data);
275
- if (!result.success) {
276
- throw new Error(`Job "${name}" payload validation failed: ${result.error.message}`);
277
- }
278
- }
279
-
280
168
  const job = await this.adapter.create({
281
169
  name,
282
170
  data,