@queuebase/core 0.0.1
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/dist/handler.d.ts +15 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +53 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/job.d.ts +20 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +9 -0
- package/dist/job.js.map +1 -0
- package/dist/router.d.ts +45 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +7 -0
- package/dist/router.js.map +1 -0
- package/dist/types.d.ts +91 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +21 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +63 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.test.d.ts +2 -0
- package/dist/utils.test.d.ts.map +1 -0
- package/dist/utils.test.js +75 -0
- package/dist/utils.test.js.map +1 -0
- package/dist/webhook.d.ts +17 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/webhook.js +51 -0
- package/dist/webhook.js.map +1 -0
- package/dist/webhook.test.d.ts +2 -0
- package/dist/webhook.test.d.ts.map +1 -0
- package/dist/webhook.test.js +47 -0
- package/dist/webhook.test.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AnyJobDefinition } from './router.js';
|
|
2
|
+
import { WEBHOOK_HEADERS } from './webhook.js';
|
|
3
|
+
export { WEBHOOK_HEADERS };
|
|
4
|
+
export interface HandlerRequest {
|
|
5
|
+
body: string;
|
|
6
|
+
signatureHeader: string | null;
|
|
7
|
+
}
|
|
8
|
+
export interface HandlerResponse {
|
|
9
|
+
status: number;
|
|
10
|
+
body: unknown;
|
|
11
|
+
}
|
|
12
|
+
export declare function processJobCallback(router: Record<string, AnyJobDefinition>, request: HandlerRequest, options?: {
|
|
13
|
+
webhookSecret?: string;
|
|
14
|
+
}): Promise<HandlerResponse>;
|
|
15
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,EAAmB,eAAe,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,EAAE,eAAe,EAAE,CAAC;AAU3B,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACxC,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACnC,OAAO,CAAC,eAAe,CAAC,CAuD1B"}
|
package/dist/handler.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { verifySignature, WEBHOOK_HEADERS } from './webhook.js';
|
|
2
|
+
export { WEBHOOK_HEADERS };
|
|
3
|
+
export async function processJobCallback(router, request, options) {
|
|
4
|
+
const webhookSecret = options?.webhookSecret ?? process.env.QUEUEBASE_WEBHOOK_SECRET;
|
|
5
|
+
if (webhookSecret) {
|
|
6
|
+
if (!request.signatureHeader) {
|
|
7
|
+
return {
|
|
8
|
+
status: 401,
|
|
9
|
+
body: { success: false, error: 'Missing webhook signature' },
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
if (!verifySignature(request.body, request.signatureHeader, webhookSecret)) {
|
|
13
|
+
return {
|
|
14
|
+
status: 401,
|
|
15
|
+
body: { success: false, error: 'Invalid webhook signature' },
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
let parsed;
|
|
20
|
+
try {
|
|
21
|
+
parsed = JSON.parse(request.body);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return { status: 400, body: { success: false, error: 'Invalid JSON body' } };
|
|
25
|
+
}
|
|
26
|
+
const { jobId, name, payload, attempt, maxAttempts } = parsed;
|
|
27
|
+
const jobDef = router[name];
|
|
28
|
+
if (!jobDef) {
|
|
29
|
+
return { status: 404, body: { success: false, error: `Unknown job: ${name}` } };
|
|
30
|
+
}
|
|
31
|
+
const parseResult = jobDef.input.safeParse(payload);
|
|
32
|
+
if (!parseResult.success) {
|
|
33
|
+
return {
|
|
34
|
+
status: 400,
|
|
35
|
+
body: { success: false, error: `Invalid payload: ${parseResult.error.message}` },
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const context = {
|
|
39
|
+
input: parseResult.data,
|
|
40
|
+
jobId,
|
|
41
|
+
attempt,
|
|
42
|
+
maxAttempts,
|
|
43
|
+
};
|
|
44
|
+
try {
|
|
45
|
+
const output = await jobDef.handler(context);
|
|
46
|
+
return { status: 200, body: { success: true, output } };
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
50
|
+
return { status: 500, body: { success: false, error: message } };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,EAAE,eAAe,EAAE,CAAC;AAoB3B,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAwC,EACxC,OAAuB,EACvB,OAAoC;IAEpC,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAErF,IAAI,aAAa,EAAE,CAAC;QAClB,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YAC7B,OAAO;gBACL,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,2BAA2B,EAAE;aAC7D,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,eAAe,EAAE,aAAa,CAAC,EAAE,CAAC;YAC3E,OAAO;gBACL,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,2BAA2B,EAAE;aAC7D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,MAA0B,CAAC;IAC/B,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAuB,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,CAAC;IAC/E,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;IAE9D,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,IAAI,EAAE,EAAE,EAAE,CAAC;IAClF,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACpD,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QACzB,OAAO;YACL,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE;SACjF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAwB;QACnC,KAAK,EAAE,WAAW,CAAC,IAAI;QACvB,KAAK;QACL,OAAO;QACP,WAAW;KACZ,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC7C,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IAC1D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACzE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;IACnE,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { JobStatus, BackoffStrategy, EnqueueOptions, JobDefinition, JobContext, QueuedJob, JobResult, QueuebaseConfig, } from './types.js';
|
|
2
|
+
export { job, type InferJobInput, type InferJobOutput } from './job.js';
|
|
3
|
+
export { createJobRouter, type AnyJobDefinition, type JobRouter, type CallableJob, type CallableJobRouter, } from './router.js';
|
|
4
|
+
export { parseDelay, calculateBackoff, generateJobId, generatePublicId } from './utils.js';
|
|
5
|
+
export { signPayload, verifySignature, WEBHOOK_HEADERS } from './webhook.js';
|
|
6
|
+
export { processJobCallback, type HandlerRequest, type HandlerResponse, } from './handler.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,SAAS,EACT,eAAe,EACf,cAAc,EACd,aAAa,EACb,UAAU,EACV,SAAS,EACT,SAAS,EACT,eAAe,GAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,GAAG,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAGxE,OAAO,EACL,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG3F,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG7E,OAAO,EACL,kBAAkB,EAClB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Job creation
|
|
2
|
+
export { job } from './job.js';
|
|
3
|
+
// Router
|
|
4
|
+
export { createJobRouter, } from './router.js';
|
|
5
|
+
// Utilities
|
|
6
|
+
export { parseDelay, calculateBackoff, generateJobId, generatePublicId } from './utils.js';
|
|
7
|
+
// Webhook signing
|
|
8
|
+
export { signPayload, verifySignature, WEBHOOK_HEADERS } from './webhook.js';
|
|
9
|
+
// Handler
|
|
10
|
+
export { processJobCallback, } from './handler.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,eAAe;AACf,OAAO,EAAE,GAAG,EAA2C,MAAM,UAAU,CAAC;AAExE,SAAS;AACT,OAAO,EACL,eAAe,GAKhB,MAAM,aAAa,CAAC;AAErB,YAAY;AACZ,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE3F,kBAAkB;AAClB,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE7E,UAAU;AACV,OAAO,EACL,kBAAkB,GAGnB,MAAM,cAAc,CAAC"}
|
package/dist/job.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
import type { EnqueueOptions, JobContext } from './types.js';
|
|
3
|
+
import type { AnyJobDefinition } from './router.js';
|
|
4
|
+
/**
|
|
5
|
+
* Creates a job definition with typed input and handler
|
|
6
|
+
*/
|
|
7
|
+
export declare function job<TInput, TOutput>(definition: {
|
|
8
|
+
input: z.ZodType<TInput>;
|
|
9
|
+
handler: (ctx: JobContext<TInput>) => Promise<TOutput>;
|
|
10
|
+
defaults?: EnqueueOptions;
|
|
11
|
+
}): AnyJobDefinition;
|
|
12
|
+
/**
|
|
13
|
+
* Infer the input type from a job definition's Zod schema
|
|
14
|
+
*/
|
|
15
|
+
export type InferJobInput<T extends AnyJobDefinition> = T['input'] extends z.ZodType<infer I> ? I : never;
|
|
16
|
+
/**
|
|
17
|
+
* Infer the output type from a job definition's handler
|
|
18
|
+
*/
|
|
19
|
+
export type InferJobOutput<T extends AnyJobDefinition> = T['handler'] extends (ctx: JobContext<unknown>) => Promise<infer O> ? O : never;
|
|
20
|
+
//# sourceMappingURL=job.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD;;GAEG;AACH,wBAAgB,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;IAC/C,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,OAAO,EAAE,CAAC,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B,GAAG,gBAAgB,CAInB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,gBAAgB,IAAI,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GACzF,CAAC,GACD,KAAK,CAAC;AAEV;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,gBAAgB,IAAI,CAAC,CAAC,SAAS,CAAC,SAAS,CAC5E,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC,KACrB,OAAO,CAAC,MAAM,CAAC,CAAC,GACjB,CAAC,GACD,KAAK,CAAC"}
|
package/dist/job.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a job definition with typed input and handler
|
|
3
|
+
*/
|
|
4
|
+
export function job(definition) {
|
|
5
|
+
// Cast to AnyJobDefinition for storage in the router
|
|
6
|
+
// The actual types are preserved through the generic inference
|
|
7
|
+
return definition;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=job.js.map
|
package/dist/job.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job.js","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,UAAU,GAAG,CAAkB,UAIpC;IACC,qDAAqD;IACrD,+DAA+D;IAC/D,OAAO,UAAyC,CAAC;AACnD,CAAC"}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
import type { EnqueueOptions, JobContext } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* A job definition - the basic building block
|
|
5
|
+
*/
|
|
6
|
+
export interface AnyJobDefinition {
|
|
7
|
+
input: z.ZodTypeAny;
|
|
8
|
+
handler: (ctx: JobContext<unknown>) => Promise<unknown>;
|
|
9
|
+
defaults?: EnqueueOptions;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A collection of job definitions
|
|
13
|
+
*/
|
|
14
|
+
export type JobRouter = Record<string, AnyJobDefinition>;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a typed job router from job definitions
|
|
17
|
+
*/
|
|
18
|
+
export declare function createJobRouter<T extends Record<string, AnyJobDefinition>>(jobs: T): T;
|
|
19
|
+
/**
|
|
20
|
+
* Callable job that can be enqueued
|
|
21
|
+
*/
|
|
22
|
+
export interface CallableJob<TInput, TOutput> {
|
|
23
|
+
/** Enqueue this job for execution */
|
|
24
|
+
enqueue: (input: TInput, options?: EnqueueOptions) => Promise<{
|
|
25
|
+
jobId: string;
|
|
26
|
+
}>;
|
|
27
|
+
/** The underlying job definition */
|
|
28
|
+
_def: AnyJobDefinition;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Extract input type from a job definition
|
|
32
|
+
*/
|
|
33
|
+
type ExtractJobInput<T extends AnyJobDefinition> = T['input'] extends z.ZodType<infer I> ? I : never;
|
|
34
|
+
/**
|
|
35
|
+
* Extract output type from a job definition (from handler return type)
|
|
36
|
+
*/
|
|
37
|
+
type ExtractJobOutput<T extends AnyJobDefinition> = T['handler'] extends (ctx: JobContext<unknown>) => Promise<infer O> ? O : never;
|
|
38
|
+
/**
|
|
39
|
+
* Transform a job router into callable jobs
|
|
40
|
+
*/
|
|
41
|
+
export type CallableJobRouter<T extends Record<string, AnyJobDefinition>> = {
|
|
42
|
+
[K in keyof T]: CallableJob<ExtractJobInput<T[K]>, ExtractJobOutput<T[K]>>;
|
|
43
|
+
};
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,CAAC,CAAC,UAAU,CAAC;IACpB,OAAO,EAAE,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAEzD;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAEtF;AAED;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,MAAM,EAAE,OAAO;IAC1C,qCAAqC;IACrC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjF,oCAAoC;IACpC,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED;;GAEG;AACH,KAAK,eAAe,CAAC,CAAC,SAAS,gBAAgB,IAAI,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GACpF,CAAC,GACD,KAAK,CAAC;AAEV;;GAEG;AACH,KAAK,gBAAgB,CAAC,CAAC,SAAS,gBAAgB,IAAI,CAAC,CAAC,SAAS,CAAC,SAAS,CACvE,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC,KACrB,OAAO,CAAC,MAAM,CAAC,CAAC,GACjB,CAAC,GACD,KAAK,CAAC;AAEV;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,IAAI;KACzE,CAAC,IAAI,MAAM,CAAC,GAAG,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC3E,CAAC"}
|
package/dist/router.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAiBA;;GAEG;AACH,MAAM,UAAU,eAAe,CAA6C,IAAO;IACjF,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Status of a job in the queue
|
|
4
|
+
*/
|
|
5
|
+
export type JobStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
6
|
+
/**
|
|
7
|
+
* Backoff strategy for retries
|
|
8
|
+
*/
|
|
9
|
+
export type BackoffStrategy = 'linear' | 'exponential';
|
|
10
|
+
/**
|
|
11
|
+
* Options for enqueueing a job
|
|
12
|
+
*/
|
|
13
|
+
export interface EnqueueOptions {
|
|
14
|
+
/** Delay before running the job (e.g., '5m', '1h', or milliseconds) */
|
|
15
|
+
delay?: string | number;
|
|
16
|
+
/** Number of retry attempts on failure */
|
|
17
|
+
retries?: number;
|
|
18
|
+
/** Backoff strategy for retries */
|
|
19
|
+
backoff?: BackoffStrategy;
|
|
20
|
+
/** Initial delay between retries in ms (default: 1000) */
|
|
21
|
+
backoffDelay?: number;
|
|
22
|
+
/** Maximum concurrent jobs of this type (per worker) */
|
|
23
|
+
concurrency?: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A job definition with typed input/output
|
|
27
|
+
*/
|
|
28
|
+
export interface JobDefinition<TInput = unknown, TOutput = unknown> {
|
|
29
|
+
/** Zod schema for validating job input */
|
|
30
|
+
input: z.ZodType<TInput>;
|
|
31
|
+
/** The handler function that executes the job */
|
|
32
|
+
handler: (ctx: JobContext<TInput>) => Promise<TOutput>;
|
|
33
|
+
/** Default options for this job */
|
|
34
|
+
defaults?: EnqueueOptions;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Context passed to job handlers
|
|
38
|
+
*/
|
|
39
|
+
export interface JobContext<TInput = unknown> {
|
|
40
|
+
/** The validated input data */
|
|
41
|
+
input: TInput;
|
|
42
|
+
/** Unique ID for this job execution */
|
|
43
|
+
jobId: string;
|
|
44
|
+
/** Current attempt number (1-indexed) */
|
|
45
|
+
attempt: number;
|
|
46
|
+
/** Maximum attempts allowed */
|
|
47
|
+
maxAttempts: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Internal representation of a queued job
|
|
51
|
+
*/
|
|
52
|
+
export interface QueuedJob {
|
|
53
|
+
id: number;
|
|
54
|
+
publicId: string;
|
|
55
|
+
name: string;
|
|
56
|
+
payload: unknown;
|
|
57
|
+
status: JobStatus;
|
|
58
|
+
attempt: number;
|
|
59
|
+
maxAttempts: number;
|
|
60
|
+
runAt: Date;
|
|
61
|
+
createdAt: Date;
|
|
62
|
+
startedAt: Date | null;
|
|
63
|
+
completedAt: Date | null;
|
|
64
|
+
result: unknown | null;
|
|
65
|
+
error: string | null;
|
|
66
|
+
backoffStrategy: BackoffStrategy;
|
|
67
|
+
backoffDelay: number;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Result of a job execution
|
|
71
|
+
*/
|
|
72
|
+
export interface JobResult<TOutput = unknown> {
|
|
73
|
+
success: boolean;
|
|
74
|
+
output?: TOutput;
|
|
75
|
+
error?: string;
|
|
76
|
+
duration: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Configuration for queuebase
|
|
80
|
+
*/
|
|
81
|
+
export interface QueuebaseConfig {
|
|
82
|
+
/** Directory containing job definitions */
|
|
83
|
+
jobsDir: string;
|
|
84
|
+
/** URL where the queuebase API can callback to execute jobs */
|
|
85
|
+
callbackUrl?: string;
|
|
86
|
+
/** API key for production (from queuebase.io) */
|
|
87
|
+
apiKey?: string;
|
|
88
|
+
/** Override the API endpoint (auto-detected by NODE_ENV) */
|
|
89
|
+
apiUrl?: string;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAErF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,aAAa,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO;IAChE,0CAA0C;IAC1C,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,iDAAiD;IACjD,OAAO,EAAE,CAAC,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,mCAAmC;IACnC,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,MAAM,GAAG,OAAO;IAC1C,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,IAAI,CAAC;IACZ,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS,CAAC,OAAO,GAAG,OAAO;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a delay string into milliseconds
|
|
3
|
+
* Supports: '5s', '5m', '5h', '5d' or raw milliseconds
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseDelay(delay: string | number): number;
|
|
6
|
+
/**
|
|
7
|
+
* Calculate the next retry delay based on backoff strategy
|
|
8
|
+
*/
|
|
9
|
+
export declare function calculateBackoff(attempt: number, strategy: 'linear' | 'exponential', baseDelay: number): number;
|
|
10
|
+
/**
|
|
11
|
+
* Generate a unique job ID
|
|
12
|
+
* @deprecated Use `generatePublicId()` instead
|
|
13
|
+
*/
|
|
14
|
+
export declare function generateJobId(): string;
|
|
15
|
+
/**
|
|
16
|
+
* Generate a Stripe-style public ID for external use
|
|
17
|
+
* @param prefix - Prefix for the ID (default: 'job')
|
|
18
|
+
* @returns A string like `job_V1StGXR8kZ5jx...`
|
|
19
|
+
*/
|
|
20
|
+
export declare function generatePublicId(prefix?: string): string;
|
|
21
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CA6BzD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,GAAG,aAAa,EAClC,SAAS,EAAE,MAAM,GAChB,MAAM,CASR;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,SAAQ,GAAG,MAAM,CAEvD"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
2
|
+
/**
|
|
3
|
+
* Parse a delay string into milliseconds
|
|
4
|
+
* Supports: '5s', '5m', '5h', '5d' or raw milliseconds
|
|
5
|
+
*/
|
|
6
|
+
export function parseDelay(delay) {
|
|
7
|
+
if (typeof delay === 'number') {
|
|
8
|
+
return delay;
|
|
9
|
+
}
|
|
10
|
+
const match = delay.match(/^(\d+)(s|m|h|d)$/);
|
|
11
|
+
if (!match) {
|
|
12
|
+
const num = Number.parseInt(delay, 10);
|
|
13
|
+
if (Number.isNaN(num)) {
|
|
14
|
+
throw new Error(`Invalid delay format: ${delay}`);
|
|
15
|
+
}
|
|
16
|
+
return num;
|
|
17
|
+
}
|
|
18
|
+
const [, value, unit] = match;
|
|
19
|
+
const num = Number.parseInt(value, 10);
|
|
20
|
+
switch (unit) {
|
|
21
|
+
case 's':
|
|
22
|
+
return num * 1000;
|
|
23
|
+
case 'm':
|
|
24
|
+
return num * 60 * 1000;
|
|
25
|
+
case 'h':
|
|
26
|
+
return num * 60 * 60 * 1000;
|
|
27
|
+
case 'd':
|
|
28
|
+
return num * 24 * 60 * 60 * 1000;
|
|
29
|
+
default:
|
|
30
|
+
throw new Error(`Invalid delay unit: ${unit}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Calculate the next retry delay based on backoff strategy
|
|
35
|
+
*/
|
|
36
|
+
export function calculateBackoff(attempt, strategy, baseDelay) {
|
|
37
|
+
switch (strategy) {
|
|
38
|
+
case 'linear':
|
|
39
|
+
return baseDelay * attempt;
|
|
40
|
+
case 'exponential':
|
|
41
|
+
return baseDelay * 2 ** (attempt - 1);
|
|
42
|
+
default:
|
|
43
|
+
return baseDelay;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generate a unique job ID
|
|
48
|
+
* @deprecated Use `generatePublicId()` instead
|
|
49
|
+
*/
|
|
50
|
+
export function generateJobId() {
|
|
51
|
+
const timestamp = Date.now().toString(36);
|
|
52
|
+
const random = Math.random().toString(36).substring(2, 10);
|
|
53
|
+
return `job_${timestamp}_${random}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generate a Stripe-style public ID for external use
|
|
57
|
+
* @param prefix - Prefix for the ID (default: 'job')
|
|
58
|
+
* @returns A string like `job_V1StGXR8kZ5jx...`
|
|
59
|
+
*/
|
|
60
|
+
export function generatePublicId(prefix = 'job') {
|
|
61
|
+
return `${prefix}_${nanoid(21)}`;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACvC,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;IAC9B,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAM,EAAE,EAAE,CAAC,CAAC;IAExC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,GAAG;YACN,OAAO,GAAG,GAAG,IAAI,CAAC;QACpB,KAAK,GAAG;YACN,OAAO,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;QACzB,KAAK,GAAG;YACN,OAAO,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAC9B,KAAK,GAAG;YACN,OAAO,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QACnC;YACE,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EACf,QAAkC,EAClC,SAAiB;IAEjB,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,QAAQ;YACX,OAAO,SAAS,GAAG,OAAO,CAAC;QAC7B,KAAK,aAAa;YAChB,OAAO,SAAS,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QACxC;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3D,OAAO,OAAO,SAAS,IAAI,MAAM,EAAE,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAM,GAAG,KAAK;IAC7C,OAAO,GAAG,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../src/utils.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { calculateBackoff, generateJobId, generatePublicId, parseDelay } from './utils.js';
|
|
3
|
+
describe('parseDelay', () => {
|
|
4
|
+
it('should parse seconds', () => {
|
|
5
|
+
expect(parseDelay('5s')).toBe(5000);
|
|
6
|
+
expect(parseDelay('30s')).toBe(30000);
|
|
7
|
+
});
|
|
8
|
+
it('should parse minutes', () => {
|
|
9
|
+
expect(parseDelay('5m')).toBe(300000);
|
|
10
|
+
expect(parseDelay('1m')).toBe(60000);
|
|
11
|
+
});
|
|
12
|
+
it('should parse hours', () => {
|
|
13
|
+
expect(parseDelay('1h')).toBe(3600000);
|
|
14
|
+
expect(parseDelay('2h')).toBe(7200000);
|
|
15
|
+
});
|
|
16
|
+
it('should parse days', () => {
|
|
17
|
+
expect(parseDelay('1d')).toBe(86400000);
|
|
18
|
+
});
|
|
19
|
+
it('should handle raw milliseconds as number', () => {
|
|
20
|
+
expect(parseDelay(5000)).toBe(5000);
|
|
21
|
+
});
|
|
22
|
+
it('should handle raw milliseconds as string', () => {
|
|
23
|
+
expect(parseDelay('5000')).toBe(5000);
|
|
24
|
+
});
|
|
25
|
+
it('should throw on invalid format', () => {
|
|
26
|
+
expect(() => parseDelay('invalid')).toThrow('Invalid delay format');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('calculateBackoff', () => {
|
|
30
|
+
it('should calculate linear backoff', () => {
|
|
31
|
+
expect(calculateBackoff(1, 'linear', 1000)).toBe(1000);
|
|
32
|
+
expect(calculateBackoff(2, 'linear', 1000)).toBe(2000);
|
|
33
|
+
expect(calculateBackoff(3, 'linear', 1000)).toBe(3000);
|
|
34
|
+
});
|
|
35
|
+
it('should calculate exponential backoff', () => {
|
|
36
|
+
expect(calculateBackoff(1, 'exponential', 1000)).toBe(1000);
|
|
37
|
+
expect(calculateBackoff(2, 'exponential', 1000)).toBe(2000);
|
|
38
|
+
expect(calculateBackoff(3, 'exponential', 1000)).toBe(4000);
|
|
39
|
+
expect(calculateBackoff(4, 'exponential', 1000)).toBe(8000);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('generateJobId', () => {
|
|
43
|
+
it('should generate unique IDs', () => {
|
|
44
|
+
const id1 = generateJobId();
|
|
45
|
+
const id2 = generateJobId();
|
|
46
|
+
expect(id1).not.toBe(id2);
|
|
47
|
+
});
|
|
48
|
+
it('should start with job_ prefix', () => {
|
|
49
|
+
const id = generateJobId();
|
|
50
|
+
expect(id.startsWith('job_')).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('generatePublicId', () => {
|
|
54
|
+
it('should generate unique IDs', () => {
|
|
55
|
+
const id1 = generatePublicId();
|
|
56
|
+
const id2 = generatePublicId();
|
|
57
|
+
expect(id1).not.toBe(id2);
|
|
58
|
+
});
|
|
59
|
+
it('should use default job_ prefix', () => {
|
|
60
|
+
const id = generatePublicId();
|
|
61
|
+
expect(id.startsWith('job_')).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
it('should use custom prefix', () => {
|
|
64
|
+
const id = generatePublicId('proj');
|
|
65
|
+
expect(id.startsWith('proj_')).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
it('should have consistent length', () => {
|
|
68
|
+
const id1 = generatePublicId();
|
|
69
|
+
const id2 = generatePublicId();
|
|
70
|
+
expect(id1.length).toBe(id2.length);
|
|
71
|
+
// prefix (3) + underscore (1) + nanoid (21) = 25
|
|
72
|
+
expect(id1.length).toBe(25);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=utils.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../src/utils.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const WEBHOOK_HEADERS: {
|
|
2
|
+
readonly SIGNATURE: "X-Queuebase-Signature";
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* Sign a webhook payload using HMAC-SHA256.
|
|
6
|
+
* Returns a signature string in the format `t=<timestamp>,v1=<hmac>`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function signPayload(payload: string, secret: string): {
|
|
9
|
+
signature: string;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Verify a webhook signature against a payload.
|
|
14
|
+
* Uses timing-safe comparison and enforces a timestamp tolerance for replay protection.
|
|
15
|
+
*/
|
|
16
|
+
export declare function verifySignature(payload: string, signature: string, secret: string, toleranceSeconds?: number): boolean;
|
|
17
|
+
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe;;CAElB,CAAC;AAIX;;;GAGG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAQ1C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,gBAAgB,SAA4B,GAC3C,OAAO,CAmCT"}
|
package/dist/webhook.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
export const WEBHOOK_HEADERS = {
|
|
3
|
+
SIGNATURE: 'X-Queuebase-Signature',
|
|
4
|
+
};
|
|
5
|
+
const DEFAULT_TOLERANCE_SECONDS = 5 * 60; // 5 minutes
|
|
6
|
+
/**
|
|
7
|
+
* Sign a webhook payload using HMAC-SHA256.
|
|
8
|
+
* Returns a signature string in the format `t=<timestamp>,v1=<hmac>`.
|
|
9
|
+
*/
|
|
10
|
+
export function signPayload(payload, secret) {
|
|
11
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
12
|
+
const signedContent = `${timestamp}.${payload}`;
|
|
13
|
+
const hmac = createHmac('sha256', secret).update(signedContent).digest('hex');
|
|
14
|
+
return {
|
|
15
|
+
signature: `t=${timestamp},v1=${hmac}`,
|
|
16
|
+
timestamp,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Verify a webhook signature against a payload.
|
|
21
|
+
* Uses timing-safe comparison and enforces a timestamp tolerance for replay protection.
|
|
22
|
+
*/
|
|
23
|
+
export function verifySignature(payload, signature, secret, toleranceSeconds = DEFAULT_TOLERANCE_SECONDS) {
|
|
24
|
+
const parts = signature.split(',');
|
|
25
|
+
const tPart = parts.find((p) => p.startsWith('t='));
|
|
26
|
+
const v1Part = parts.find((p) => p.startsWith('v1='));
|
|
27
|
+
if (!tPart || !v1Part) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const timestamp = Number.parseInt(tPart.slice(2), 10);
|
|
31
|
+
const receivedHmac = v1Part.slice(3);
|
|
32
|
+
if (Number.isNaN(timestamp)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
// Check timestamp tolerance for replay protection
|
|
36
|
+
const now = Math.floor(Date.now() / 1000);
|
|
37
|
+
if (Math.abs(now - timestamp) > toleranceSeconds) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
// Recompute the expected HMAC
|
|
41
|
+
const signedContent = `${timestamp}.${payload}`;
|
|
42
|
+
const expectedHmac = createHmac('sha256', secret).update(signedContent).digest('hex');
|
|
43
|
+
// Timing-safe comparison
|
|
44
|
+
const expected = Buffer.from(expectedHmac, 'hex');
|
|
45
|
+
const received = Buffer.from(receivedHmac, 'hex');
|
|
46
|
+
if (expected.length !== received.length) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return timingSafeEqual(expected, received);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,SAAS,EAAE,uBAAuB;CAC1B,CAAC;AAEX,MAAM,yBAAyB,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,YAAY;AAEtD;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,OAAe,EACf,MAAc;IAEd,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC;IAChD,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9E,OAAO;QACL,SAAS,EAAE,KAAK,SAAS,OAAO,IAAI,EAAE;QACtC,SAAS;KACV,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,SAAiB,EACjB,MAAc,EACd,gBAAgB,GAAG,yBAAyB;IAE5C,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAEtD,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAErC,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kDAAkD;IAClD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,SAAS,CAAC,GAAG,gBAAgB,EAAE,CAAC;QACjD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8BAA8B;IAC9B,MAAM,aAAa,GAAG,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC;IAChD,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEtF,yBAAyB;IACzB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAElD,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.test.d.ts","sourceRoot":"","sources":["../src/webhook.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { signPayload, verifySignature } from './webhook.js';
|
|
3
|
+
const TEST_SECRET = 'qb_whsec_test_secret_key';
|
|
4
|
+
describe('webhook signing', () => {
|
|
5
|
+
it('should sign and verify a payload successfully', () => {
|
|
6
|
+
const payload = JSON.stringify({ jobId: 'job_123', name: 'sendEmail' });
|
|
7
|
+
const { signature } = signPayload(payload, TEST_SECRET);
|
|
8
|
+
expect(signature).toMatch(/^t=\d+,v1=[a-f0-9]{64}$/);
|
|
9
|
+
expect(verifySignature(payload, signature, TEST_SECRET)).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
it('should reject a tampered payload', () => {
|
|
12
|
+
const payload = JSON.stringify({ jobId: 'job_123' });
|
|
13
|
+
const { signature } = signPayload(payload, TEST_SECRET);
|
|
14
|
+
const tampered = JSON.stringify({ jobId: 'job_456' });
|
|
15
|
+
expect(verifySignature(tampered, signature, TEST_SECRET)).toBe(false);
|
|
16
|
+
});
|
|
17
|
+
it('should reject a wrong secret', () => {
|
|
18
|
+
const payload = JSON.stringify({ jobId: 'job_123' });
|
|
19
|
+
const { signature } = signPayload(payload, TEST_SECRET);
|
|
20
|
+
expect(verifySignature(payload, signature, 'wrong_secret')).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
it('should reject an invalid signature format', () => {
|
|
23
|
+
const payload = JSON.stringify({ jobId: 'job_123' });
|
|
24
|
+
expect(verifySignature(payload, 'invalid', TEST_SECRET)).toBe(false);
|
|
25
|
+
expect(verifySignature(payload, 't=abc,v1=def', TEST_SECRET)).toBe(false);
|
|
26
|
+
expect(verifySignature(payload, 'v1=abc', TEST_SECRET)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
it('should reject an expired timestamp', () => {
|
|
29
|
+
const payload = JSON.stringify({ jobId: 'job_123' });
|
|
30
|
+
const { signature } = signPayload(payload, TEST_SECRET);
|
|
31
|
+
// Move time forward 10 minutes
|
|
32
|
+
vi.useFakeTimers();
|
|
33
|
+
vi.setSystemTime(Date.now() + 10 * 60 * 1000);
|
|
34
|
+
expect(verifySignature(payload, signature, TEST_SECRET)).toBe(false);
|
|
35
|
+
vi.useRealTimers();
|
|
36
|
+
});
|
|
37
|
+
it('should accept within custom tolerance', () => {
|
|
38
|
+
const payload = JSON.stringify({ jobId: 'job_123' });
|
|
39
|
+
const { signature } = signPayload(payload, TEST_SECRET);
|
|
40
|
+
// Move time forward 2 minutes — within 10-minute tolerance
|
|
41
|
+
vi.useFakeTimers();
|
|
42
|
+
vi.setSystemTime(Date.now() + 2 * 60 * 1000);
|
|
43
|
+
expect(verifySignature(payload, signature, TEST_SECRET, 600)).toBe(true);
|
|
44
|
+
vi.useRealTimers();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=webhook.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.test.js","sourceRoot":"","sources":["../src/webhook.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@queuebase/core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"import": "./dist/index.js"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"nanoid": "^5.0.9",
|
|
19
|
+
"zod": "^3.24.1"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^22.19.9",
|
|
23
|
+
"typescript": "^5.7.2",
|
|
24
|
+
"vitest": "^2.1.8",
|
|
25
|
+
"@queuebase/tsconfig": "0.0.0"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc -b",
|
|
29
|
+
"dev": "tsc -b --watch",
|
|
30
|
+
"clean": "rm -rf dist .turbo *.tsbuildinfo",
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"lint": "biome lint ./src",
|
|
33
|
+
"lint:fix": "biome lint --write ./src",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"test:watch": "vitest"
|
|
36
|
+
}
|
|
37
|
+
}
|