@cqrs-ddd/pipeline-job-context 0.5.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.
- package/COMMERCIAL_LICENSE.txt +34 -0
- package/LICENSE +661 -0
- package/README.md +42 -0
- package/dist/decorators/as-system.decorator.d.ts +36 -0
- package/dist/decorators/as-system.decorator.d.ts.map +1 -0
- package/dist/decorators/as-system.decorator.js +53 -0
- package/dist/decorators/as-system.decorator.js.map +1 -0
- package/dist/decorators/in-job-context.decorator.d.ts +35 -0
- package/dist/decorators/in-job-context.decorator.d.ts.map +1 -0
- package/dist/decorators/in-job-context.decorator.js +47 -0
- package/dist/decorators/in-job-context.decorator.js.map +1 -0
- package/dist/errors/invalid-job-context.error.d.ts +15 -0
- package/dist/errors/invalid-job-context.error.d.ts.map +1 -0
- package/dist/errors/invalid-job-context.error.js +20 -0
- package/dist/errors/invalid-job-context.error.js.map +1 -0
- package/dist/errors/missing-job-context.error.d.ts +14 -0
- package/dist/errors/missing-job-context.error.d.ts.map +1 -0
- package/dist/errors/missing-job-context.error.js +19 -0
- package/dist/errors/missing-job-context.error.js.map +1 -0
- package/dist/helpers/method-decorator.d.ts +13 -0
- package/dist/helpers/method-decorator.d.ts.map +1 -0
- package/dist/helpers/method-decorator.js +24 -0
- package/dist/helpers/method-decorator.js.map +1 -0
- package/dist/helpers/parse-job-context.d.ts +20 -0
- package/dist/helpers/parse-job-context.d.ts.map +1 -0
- package/dist/helpers/parse-job-context.js +68 -0
- package/dist/helpers/parse-job-context.js.map +1 -0
- package/dist/helpers/principal-reference.d.ts +12 -0
- package/dist/helpers/principal-reference.d.ts.map +1 -0
- package/dist/helpers/principal-reference.js +15 -0
- package/dist/helpers/principal-reference.js.map +1 -0
- package/dist/helpers/registration.d.ts +39 -0
- package/dist/helpers/registration.d.ts.map +1 -0
- package/dist/helpers/registration.js +44 -0
- package/dist/helpers/registration.js.map +1 -0
- package/dist/helpers/with-job-context.d.ts +21 -0
- package/dist/helpers/with-job-context.d.ts.map +1 -0
- package/dist/helpers/with-job-context.js +46 -0
- package/dist/helpers/with-job-context.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/context-source.interface.d.ts +23 -0
- package/dist/interfaces/context-source.interface.d.ts.map +1 -0
- package/dist/interfaces/context-source.interface.js +3 -0
- package/dist/interfaces/context-source.interface.js.map +1 -0
- package/dist/interfaces/job-context.interface.d.ts +12 -0
- package/dist/interfaces/job-context.interface.d.ts.map +1 -0
- package/dist/interfaces/job-context.interface.js +3 -0
- package/dist/interfaces/job-context.interface.js.map +1 -0
- package/dist/interfaces/job-principal.interface.d.ts +28 -0
- package/dist/interfaces/job-principal.interface.d.ts.map +1 -0
- package/dist/interfaces/job-principal.interface.js +3 -0
- package/dist/interfaces/job-principal.interface.js.map +1 -0
- package/dist/interfaces/principal-reference.interface.d.ts +12 -0
- package/dist/interfaces/principal-reference.interface.d.ts.map +1 -0
- package/dist/interfaces/principal-reference.interface.js +3 -0
- package/dist/interfaces/principal-reference.interface.js.map +1 -0
- package/dist/register-job-context.d.ts +34 -0
- package/dist/register-job-context.d.ts.map +1 -0
- package/dist/register-job-context.js +32 -0
- package/dist/register-job-context.js.map +1 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @cqrs-ddd/pipeline-job-context
|
|
2
|
+
|
|
3
|
+
Carries the tenant, correlation id and principal of a request into the queue jobs it
|
|
4
|
+
enqueues, and gives system-started work an explicit context: `registerJobContext()` once
|
|
5
|
+
at startup, `withJobContext()` when a job is enqueued, `@InJobContext()` on the consumer
|
|
6
|
+
and `@AsSystem()` on system work (both TypeScript decorator modes). No framework.
|
|
7
|
+
|
|
8
|
+
**Documentation:** [guide](https://aristoteliss.github.io/ddd-cqrs/packages/pipeline-job-context/) · [API reference](https://aristoteliss.github.io/ddd-cqrs/api/cqrs-ddd/pipeline-job-context/) · [all packages](https://aristoteliss.github.io/ddd-cqrs/)
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pnpm add @cqrs-ddd/pipeline-job-context
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Requires Node.js 22.12 or later. Published as an ES module; a CommonJS application loads
|
|
17
|
+
it with `require()`.
|
|
18
|
+
|
|
19
|
+
## Example
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
registerJobContext({
|
|
23
|
+
principal: new SessionJobPrincipal(sessions),
|
|
24
|
+
tenants: ['acme'],
|
|
25
|
+
sources: { tenantId: tenantSource, correlationId: correlationSource },
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
await queue.add('welcome', withJobContext({ userId }));
|
|
29
|
+
|
|
30
|
+
class WelcomeWorker {
|
|
31
|
+
@InJobContext()
|
|
32
|
+
async process(job: { data: { userId: string } }) {}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
A queue payload is untrusted data: it carries only the principal's identity, and the
|
|
37
|
+
principal is re-checked when the job runs.
|
|
38
|
+
|
|
39
|
+
## License
|
|
40
|
+
|
|
41
|
+
Dual-licensed under **AGPLv3** and a **Commercial License**. See `LICENSE` and
|
|
42
|
+
`COMMERCIAL_LICENSE.txt`.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type DualMethodDecorator } from '../helpers/method-decorator.js';
|
|
2
|
+
import type { PrincipalReference } from '../interfaces/principal-reference.interface.js';
|
|
3
|
+
/** Options of {@link AsSystem}. */
|
|
4
|
+
export interface AsSystemOptions<TGrant = unknown> {
|
|
5
|
+
/** The service principal the work acts as. */
|
|
6
|
+
principal: PrincipalReference;
|
|
7
|
+
/** The principal's complete authorization; nothing else grants it anything. */
|
|
8
|
+
grants: readonly TGrant[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Runs system-started work, such as a cron job, once per configured tenant.
|
|
12
|
+
* Each run has its own tenant, a new correlation id, and the declared service
|
|
13
|
+
* principal and grants, bound through the registered `IJobPrincipal`. Grants
|
|
14
|
+
* come only from this declaration, never from data.
|
|
15
|
+
*
|
|
16
|
+
* Tenants run one after another. A failing tenant does not stop the others;
|
|
17
|
+
* the method then rejects with an `AggregateError` of the failures. Its return
|
|
18
|
+
* values are discarded. Place it under the scheduling decorator.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* class Maintenance {
|
|
23
|
+
* @AsSystem({
|
|
24
|
+
* principal: { id: 'session-cleanup', type: 'service' },
|
|
25
|
+
* grants: [{ action: 'delete', subject: 'Auth' }],
|
|
26
|
+
* })
|
|
27
|
+
* async purgeSessions() {
|
|
28
|
+
* await purgeExpiredSessions();
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* cron.schedule('0 3 * * *', () => maintenance.purgeSessions());
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function AsSystem<TGrant>(options: AsSystemOptions<TGrant>): DualMethodDecorator;
|
|
36
|
+
//# sourceMappingURL=as-system.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"as-system.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/as-system.decorator.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,gCAAgC,CAAC;AAGxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAC;AAEzF,mCAAmC;AACnC,MAAM,WAAW,eAAe,CAAC,MAAM,GAAG,OAAO;IAC/C,8CAA8C;IAC9C,SAAS,EAAE,kBAAkB,CAAC;IAC9B,+EAA+E;IAC/E,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAC7B,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,GAC/B,mBAAmB,CAiCrB"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
import { methodDecorator, } from '../helpers/method-decorator.js';
|
|
3
|
+
import { toReference } from '../helpers/principal-reference.js';
|
|
4
|
+
import { activeRegistration } from '../helpers/registration.js';
|
|
5
|
+
/**
|
|
6
|
+
* Runs system-started work, such as a cron job, once per configured tenant.
|
|
7
|
+
* Each run has its own tenant, a new correlation id, and the declared service
|
|
8
|
+
* principal and grants, bound through the registered `IJobPrincipal`. Grants
|
|
9
|
+
* come only from this declaration, never from data.
|
|
10
|
+
*
|
|
11
|
+
* Tenants run one after another. A failing tenant does not stop the others;
|
|
12
|
+
* the method then rejects with an `AggregateError` of the failures. Its return
|
|
13
|
+
* values are discarded. Place it under the scheduling decorator.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* class Maintenance {
|
|
18
|
+
* @AsSystem({
|
|
19
|
+
* principal: { id: 'session-cleanup', type: 'service' },
|
|
20
|
+
* grants: [{ action: 'delete', subject: 'Auth' }],
|
|
21
|
+
* })
|
|
22
|
+
* async purgeSessions() {
|
|
23
|
+
* await purgeExpiredSessions();
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
*
|
|
27
|
+
* cron.schedule('0 3 * * *', () => maintenance.purgeSessions());
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function AsSystem(options) {
|
|
31
|
+
const reference = toReference(options.principal);
|
|
32
|
+
const grants = [...options.grants];
|
|
33
|
+
return methodDecorator((original) => {
|
|
34
|
+
return async function (...args) {
|
|
35
|
+
const { principal, tenants, sources } = activeRegistration();
|
|
36
|
+
const failures = [];
|
|
37
|
+
const failed = [];
|
|
38
|
+
for (const tenant of tenants) {
|
|
39
|
+
try {
|
|
40
|
+
await sources.tenantId.run(tenant, () => sources.correlationId.run(sources.correlationId.create(), () => principal.restore(reference, async () => original.apply(this, args), grants)));
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
failures.push(error);
|
|
44
|
+
failed.push(tenant);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (failures.length > 0) {
|
|
48
|
+
throw new AggregateError(failures, `System work failed in tenants: ${failed.join(', ')}`);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=as-system.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"as-system.decorator.js","sourceRoot":"","sources":["../../src/decorators/as-system.decorator.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,OAAO,EAEL,eAAe,GAChB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAWhE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,QAAQ,CACtB,OAAgC;IAEhC,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnC,OAAO,eAAe,CAAC,CAAC,QAAQ,EAAE,EAAE;QAClC,OAAO,KAAK,WAA0B,GAAG,IAAe;YACtD,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,kBAAkB,EAAE,CAAC;YAC7D,MAAM,QAAQ,GAAc,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,IAAI,CAAC;oBACH,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CACtC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,CAC7D,SAAS,CAAC,OAAO,CACf,SAAS,EACT,KAAK,IAAI,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,EACtC,MAAM,CACP,CACF,CACF,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACrB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;YACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,cAAc,CACtB,QAAQ,EACR,kCAAkC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACtD,CAAC;YACJ,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type DualMethodDecorator } from '../helpers/method-decorator.js';
|
|
2
|
+
/** Options of {@link InJobContext}. */
|
|
3
|
+
export interface InJobContextOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Dot path to the job context in the method's first argument.
|
|
6
|
+
*
|
|
7
|
+
* @default 'data.jobContext' (a BullMQ `Job`)
|
|
8
|
+
*/
|
|
9
|
+
path?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Runs a job-processing method inside the context `withJobContext` stamped on
|
|
13
|
+
* its payload: the tenant, the correlation id, and the principal the registered
|
|
14
|
+
* `IJobPrincipal` re-checks and binds. The method becomes async.
|
|
15
|
+
*
|
|
16
|
+
* It fails closed before the method runs: a payload without a context, with a
|
|
17
|
+
* malformed one, with an unconfigured tenant, or with a principal carrying
|
|
18
|
+
* anything beyond `id`, `type` and `sessionId` is refused, and so is a
|
|
19
|
+
* principal `restore` rejects. Place it under the transport decorator.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* class WelcomeEmailWorker {
|
|
24
|
+
* @InJobContext()
|
|
25
|
+
* async process(job: Job<WithJobContext<WelcomeEmail>>) {
|
|
26
|
+
* await sendWelcomeEmail(job.data);
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* const worker = new WelcomeEmailWorker();
|
|
31
|
+
* new Worker(WELCOME_EMAIL_QUEUE, (job) => worker.process(job));
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function InJobContext(options?: InJobContextOptions): DualMethodDecorator;
|
|
35
|
+
//# sourceMappingURL=in-job-context.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-job-context.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/in-job-context.decorator.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,gCAAgC,CAAC;AAIxC,uCAAuC;AACvC,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAWD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAC1B,OAAO,GAAE,mBAAwB,GAChC,mBAAmB,CAoBrB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
import { methodDecorator, } from '../helpers/method-decorator.js';
|
|
3
|
+
import { parseJobContext } from '../helpers/parse-job-context.js';
|
|
4
|
+
import { activeRegistration } from '../helpers/registration.js';
|
|
5
|
+
function readPath(value, segments) {
|
|
6
|
+
let current = value;
|
|
7
|
+
for (const segment of segments) {
|
|
8
|
+
if (typeof current !== 'object' || current === null)
|
|
9
|
+
return undefined;
|
|
10
|
+
current = current[segment];
|
|
11
|
+
}
|
|
12
|
+
return current;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Runs a job-processing method inside the context `withJobContext` stamped on
|
|
16
|
+
* its payload: the tenant, the correlation id, and the principal the registered
|
|
17
|
+
* `IJobPrincipal` re-checks and binds. The method becomes async.
|
|
18
|
+
*
|
|
19
|
+
* It fails closed before the method runs: a payload without a context, with a
|
|
20
|
+
* malformed one, with an unconfigured tenant, or with a principal carrying
|
|
21
|
+
* anything beyond `id`, `type` and `sessionId` is refused, and so is a
|
|
22
|
+
* principal `restore` rejects. Place it under the transport decorator.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* class WelcomeEmailWorker {
|
|
27
|
+
* @InJobContext()
|
|
28
|
+
* async process(job: Job<WithJobContext<WelcomeEmail>>) {
|
|
29
|
+
* await sendWelcomeEmail(job.data);
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* const worker = new WelcomeEmailWorker();
|
|
34
|
+
* new Worker(WELCOME_EMAIL_QUEUE, (job) => worker.process(job));
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export function InJobContext(options = {}) {
|
|
38
|
+
const segments = (options.path ?? 'data.jobContext').split('.');
|
|
39
|
+
return methodDecorator((original) => {
|
|
40
|
+
return async function (...args) {
|
|
41
|
+
const { principal, tenants, sources } = activeRegistration();
|
|
42
|
+
const context = parseJobContext(readPath(args[0], segments), tenants, sources.correlationId.accepts);
|
|
43
|
+
return sources.tenantId.run(context.tenantId, () => sources.correlationId.run(context.correlationId, () => principal.restore(context.principal, async () => original.apply(this, args))));
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=in-job-context.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-job-context.decorator.js","sourceRoot":"","sources":["../../src/decorators/in-job-context.decorator.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,OAAO,EAEL,eAAe,GAChB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAYhE,SAAS,QAAQ,CAAC,KAAc,EAAE,QAA2B;IAC3D,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,SAAS,CAAC;QACtE,OAAO,GAAI,OAAmC,CAAC,OAAO,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAO,GAAwB,EAAE;IAEjC,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,iBAAiB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAEhE,OAAO,eAAe,CAAC,CAAC,QAAQ,EAAE,EAAE;QAClC,OAAO,KAAK,WAA0B,GAAG,IAAe;YACtD,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,kBAAkB,EAAE,CAAC;YAC7D,MAAM,OAAO,GAAG,eAAe,CAC7B,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAC3B,OAAO,EACP,OAAO,CAAC,aAAa,CAAC,OAAO,CAC9B,CAAC;YACF,OAAO,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,EAAE,CACjD,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,EAAE,CACpD,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE,CAC9C,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAC3B,CACF,CACF,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raised when a job payload's context is malformed, names an unconfigured
|
|
3
|
+
* tenant, or carries fields a principal reference must not have, such as
|
|
4
|
+
* grants. A payload is data written by whoever can write to the queue.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* throw new InvalidJobContextError('tenantId is not a configured tenant');
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare class InvalidJobContextError extends Error {
|
|
12
|
+
readonly reason: string;
|
|
13
|
+
constructor(reason: string);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=invalid-job-context.error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invalid-job-context.error.d.ts","sourceRoot":"","sources":["../../src/errors/invalid-job-context.error.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAAnC,YAAqB,MAAM,EAAE,MAAM,EAGlC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
/**
|
|
3
|
+
* Raised when a job payload's context is malformed, names an unconfigured
|
|
4
|
+
* tenant, or carries fields a principal reference must not have, such as
|
|
5
|
+
* grants. A payload is data written by whoever can write to the queue.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* throw new InvalidJobContextError('tenantId is not a configured tenant');
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export class InvalidJobContextError extends Error {
|
|
13
|
+
reason;
|
|
14
|
+
constructor(reason) {
|
|
15
|
+
super(`Invalid job context: ${reason}.`);
|
|
16
|
+
this.reason = reason;
|
|
17
|
+
this.name = InvalidJobContextError.name;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=invalid-job-context.error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invalid-job-context.error.js","sourceRoot":"","sources":["../../src/errors/invalid-job-context.error.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE;;;;;;;;;GASG;AACH,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC1B,MAAM;IAA3B,YAAqB,MAAc;QACjC,KAAK,CAAC,wBAAwB,MAAM,GAAG,CAAC,CAAC;sBADtB,MAAM;QAEzB,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC,IAAI,CAAC;IAC1C,CAAC;CACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raised when a job would run, or be enqueued, without part of its execution
|
|
3
|
+
* context. A job never falls back to a default tenant or an anonymous principal.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* throw new MissingJobContextError('principal');
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export declare class MissingJobContextError extends Error {
|
|
11
|
+
readonly missing: string;
|
|
12
|
+
constructor(missing: string);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=missing-job-context.error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-job-context.error.d.ts","sourceRoot":"","sources":["../../src/errors/missing-job-context.error.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM;IAApC,YAAqB,OAAO,EAAE,MAAM,EAKnC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
/**
|
|
3
|
+
* Raised when a job would run, or be enqueued, without part of its execution
|
|
4
|
+
* context. A job never falls back to a default tenant or an anonymous principal.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* throw new MissingJobContextError('principal');
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export class MissingJobContextError extends Error {
|
|
12
|
+
missing;
|
|
13
|
+
constructor(missing) {
|
|
14
|
+
super(`Missing job context: ${missing}. A job never runs without it and never falls back to a default.`);
|
|
15
|
+
this.missing = missing;
|
|
16
|
+
this.name = MissingJobContextError.name;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=missing-job-context.error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-job-context.error.js","sourceRoot":"","sources":["../../src/errors/missing-job-context.error.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE;;;;;;;;GAQG;AACH,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC1B,OAAO;IAA5B,YAAqB,OAAe;QAClC,KAAK,CACH,wBAAwB,OAAO,kEAAkE,CAClG,CAAC;uBAHiB,OAAO;QAI1B,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC,IAAI,CAAC;IAC1C,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type AnyMethod = (this: unknown, ...args: any[]) => unknown;
|
|
2
|
+
/** A method decorator for the standard and the `experimentalDecorators` mode. */
|
|
3
|
+
export interface DualMethodDecorator {
|
|
4
|
+
<F extends AnyMethod>(method: F, context: ClassMethodDecoratorContext): F;
|
|
5
|
+
(target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Builds a decorator that replaces a method with `replace(method, name)`, keeping the
|
|
9
|
+
* method's own name for stack traces.
|
|
10
|
+
*/
|
|
11
|
+
export declare function methodDecorator(replace: (method: AnyMethod, name: string) => AnyMethod): DualMethodDecorator;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=method-decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"method-decorator.d.ts","sourceRoot":"","sources":["../../src/helpers/method-decorator.ts"],"names":[],"mappings":"AAGA,KAAK,SAAS,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC;AAE5D,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,2BAA2B,GAAG,CAAC,CAAC;IAC1E,CACE,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,EAC5B,UAAU,EAAE,kBAAkB,GAC7B,kBAAkB,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,KAAK,SAAS,GACtD,mBAAmB,CAiBrB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
/**
|
|
3
|
+
* Builds a decorator that replaces a method with `replace(method, name)`, keeping the
|
|
4
|
+
* method's own name for stack traces.
|
|
5
|
+
*/
|
|
6
|
+
export function methodDecorator(replace) {
|
|
7
|
+
const replaced = (method, name) => {
|
|
8
|
+
const replacement = replace(method, name);
|
|
9
|
+
Object.defineProperty(replacement, 'name', {
|
|
10
|
+
value: method.name,
|
|
11
|
+
configurable: true,
|
|
12
|
+
});
|
|
13
|
+
return replacement;
|
|
14
|
+
};
|
|
15
|
+
return ((target, key, descriptor) => {
|
|
16
|
+
if (typeof key === 'object' && key !== null && 'name' in key) {
|
|
17
|
+
return replaced(target, String(key.name));
|
|
18
|
+
}
|
|
19
|
+
const property = descriptor;
|
|
20
|
+
property.value = replaced(property.value, String(key));
|
|
21
|
+
return property;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=method-decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"method-decorator.js","sourceRoot":"","sources":["../../src/helpers/method-decorator.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAetE;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAuD;IAEvD,MAAM,QAAQ,GAAG,CAAC,MAAiB,EAAE,IAAY,EAAE,EAAE;QACnD,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC1C,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE;YACzC,KAAK,EAAE,MAAM,CAAC,IAAI;YAClB,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;QACH,OAAO,WAAW,CAAC;IACrB,CAAC,CAAC;IACF,OAAO,CAAC,CAAC,MAAe,EAAE,GAAY,EAAE,UAA+B,EAAE,EAAE;QACzE,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;YAC7D,OAAO,QAAQ,CAAC,MAAmB,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QACzD,CAAC;QACD,MAAM,QAAQ,GAAG,UAAgC,CAAC;QAClD,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACvD,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAwB,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { JobContext } from '../interfaces/job-context.interface.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validates a job payload's context before anything runs with it. Every field
|
|
4
|
+
* is checked, unknown fields are refused, the tenant must be configured, and
|
|
5
|
+
* the correlation id must be one `acceptsCorrelationId` accepts.
|
|
6
|
+
*
|
|
7
|
+
* @param value - The payload's `jobContext` value, as read from the queue.
|
|
8
|
+
* @param tenants - The configured tenants.
|
|
9
|
+
* @param acceptsCorrelationId - The correlation source's `accepts`.
|
|
10
|
+
* @returns A context holding only the validated fields.
|
|
11
|
+
* @throws {MissingJobContextError} When `value` is `undefined`.
|
|
12
|
+
* @throws {InvalidJobContextError} For any other value that is not a valid context.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const context = parseJobContext(job.data.jobContext, ['tenant_a'], sources.correlationId.accepts);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseJobContext(value: unknown, tenants: readonly string[], acceptsCorrelationId: (id: string) => boolean): JobContext;
|
|
20
|
+
//# sourceMappingURL=parse-job-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-job-context.d.ts","sourceRoot":"","sources":["../../src/helpers/parse-job-context.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAyBzE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,oBAAoB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GAC5C,UAAU,CAmCZ"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
import { InvalidJobContextError } from '../errors/invalid-job-context.error.js';
|
|
3
|
+
import { MissingJobContextError } from '../errors/missing-job-context.error.js';
|
|
4
|
+
import { toReference } from './principal-reference.js';
|
|
5
|
+
const CONTEXT_FIELDS = new Set(['tenantId', 'correlationId', 'principal']);
|
|
6
|
+
const PRINCIPAL_FIELDS = new Set(['id', 'type', 'sessionId']);
|
|
7
|
+
function isRecord(value) {
|
|
8
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
function isText(value) {
|
|
11
|
+
return typeof value === 'string' && value.trim() !== '';
|
|
12
|
+
}
|
|
13
|
+
function assertFields(value, allowed, name) {
|
|
14
|
+
const extra = Object.keys(value).find((key) => !allowed.has(key));
|
|
15
|
+
if (extra !== undefined) {
|
|
16
|
+
throw new InvalidJobContextError(`${name} carries the field "${extra}"`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validates a job payload's context before anything runs with it. Every field
|
|
21
|
+
* is checked, unknown fields are refused, the tenant must be configured, and
|
|
22
|
+
* the correlation id must be one `acceptsCorrelationId` accepts.
|
|
23
|
+
*
|
|
24
|
+
* @param value - The payload's `jobContext` value, as read from the queue.
|
|
25
|
+
* @param tenants - The configured tenants.
|
|
26
|
+
* @param acceptsCorrelationId - The correlation source's `accepts`.
|
|
27
|
+
* @returns A context holding only the validated fields.
|
|
28
|
+
* @throws {MissingJobContextError} When `value` is `undefined`.
|
|
29
|
+
* @throws {InvalidJobContextError} For any other value that is not a valid context.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const context = parseJobContext(job.data.jobContext, ['tenant_a'], sources.correlationId.accepts);
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function parseJobContext(value, tenants, acceptsCorrelationId) {
|
|
37
|
+
if (value === undefined) {
|
|
38
|
+
throw new MissingJobContextError('the payload has no jobContext');
|
|
39
|
+
}
|
|
40
|
+
if (!isRecord(value)) {
|
|
41
|
+
throw new InvalidJobContextError('jobContext is not an object');
|
|
42
|
+
}
|
|
43
|
+
assertFields(value, CONTEXT_FIELDS, 'jobContext');
|
|
44
|
+
const { tenantId, correlationId, principal } = value;
|
|
45
|
+
if (typeof tenantId !== 'string' || !tenants.includes(tenantId)) {
|
|
46
|
+
throw new InvalidJobContextError('tenantId is not a configured tenant');
|
|
47
|
+
}
|
|
48
|
+
if (typeof correlationId !== 'string' ||
|
|
49
|
+
!acceptsCorrelationId(correlationId)) {
|
|
50
|
+
throw new InvalidJobContextError('correlationId is malformed');
|
|
51
|
+
}
|
|
52
|
+
if (!isRecord(principal)) {
|
|
53
|
+
throw new InvalidJobContextError('principal is not an object');
|
|
54
|
+
}
|
|
55
|
+
assertFields(principal, PRINCIPAL_FIELDS, 'principal');
|
|
56
|
+
const { id, type, sessionId } = principal;
|
|
57
|
+
if (!isText(id) ||
|
|
58
|
+
!isText(type) ||
|
|
59
|
+
(sessionId !== undefined && !isText(sessionId))) {
|
|
60
|
+
throw new InvalidJobContextError('principal is malformed');
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
tenantId,
|
|
64
|
+
correlationId,
|
|
65
|
+
principal: toReference({ id, type, sessionId }),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=parse-job-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-job-context.js","sourceRoot":"","sources":["../../src/helpers/parse-job-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PrincipalReference } from '../interfaces/principal-reference.interface.js';
|
|
2
|
+
/**
|
|
3
|
+
* Copies only the identity fields of `principal`, so grants or session data an
|
|
4
|
+
* application object also holds never reach a payload or a restore call.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* toReference({ id: 'u-1', type: 'user', sid: 's-1', grants: [] }); // { id: 'u-1', type: 'user' }
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare function toReference(principal: PrincipalReference): PrincipalReference;
|
|
12
|
+
//# sourceMappingURL=principal-reference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principal-reference.d.ts","sourceRoot":"","sources":["../../src/helpers/principal-reference.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAC;AAEzF;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,kBAAkB,GAAG,kBAAkB,CAG7E"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
/**
|
|
3
|
+
* Copies only the identity fields of `principal`, so grants or session data an
|
|
4
|
+
* application object also holds never reach a payload or a restore call.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* toReference({ id: 'u-1', type: 'user', sid: 's-1', grants: [] }); // { id: 'u-1', type: 'user' }
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export function toReference(principal) {
|
|
12
|
+
const { id, type, sessionId } = principal;
|
|
13
|
+
return sessionId === undefined ? { id, type } : { id, type, sessionId };
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=principal-reference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principal-reference.js","sourceRoot":"","sources":["../../src/helpers/principal-reference.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAItE;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,SAA6B;IACvD,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;IAC1C,OAAO,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { JobContextSources } from '../interfaces/context-source.interface.js';
|
|
2
|
+
import type { IJobPrincipal } from '../interfaces/job-principal.interface.js';
|
|
3
|
+
/** What `registerJobContext` registers for the decorators. */
|
|
4
|
+
export interface Registration {
|
|
5
|
+
readonly principal: IJobPrincipal;
|
|
6
|
+
readonly tenants: readonly string[];
|
|
7
|
+
readonly sources: JobContextSources;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Makes `registration` the one the decorators and `withJobContext` use.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* register({ principal, tenants: ['tenant_a'], sources });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function register(registration: Registration): void;
|
|
18
|
+
/**
|
|
19
|
+
* Removes `registration` if it is still the active one, so closing one
|
|
20
|
+
* application does not remove another's.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* unregister(registration);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function unregister(registration: Registration): void;
|
|
28
|
+
/**
|
|
29
|
+
* The active registration.
|
|
30
|
+
*
|
|
31
|
+
* @throws {MissingJobContextError} When no job context is registered.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* const { principal, tenants, sources } = activeRegistration();
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function activeRegistration(): Registration;
|
|
39
|
+
//# sourceMappingURL=registration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../../src/helpers/registration.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2CAA2C,CAAC;AACnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AAE9E,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;CACrC;AAID;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAEzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAE3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAOjD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
import { MissingJobContextError } from '../errors/missing-job-context.error.js';
|
|
3
|
+
let active;
|
|
4
|
+
/**
|
|
5
|
+
* Makes `registration` the one the decorators and `withJobContext` use.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* register({ principal, tenants: ['tenant_a'], sources });
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export function register(registration) {
|
|
13
|
+
active = registration;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Removes `registration` if it is still the active one, so closing one
|
|
17
|
+
* application does not remove another's.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* unregister(registration);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function unregister(registration) {
|
|
25
|
+
if (active === registration)
|
|
26
|
+
active = undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The active registration.
|
|
30
|
+
*
|
|
31
|
+
* @throws {MissingJobContextError} When no job context is registered.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* const { principal, tenants, sources } = activeRegistration();
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function activeRegistration() {
|
|
39
|
+
if (active === undefined) {
|
|
40
|
+
throw new MissingJobContextError('a job context registered with registerJobContext');
|
|
41
|
+
}
|
|
42
|
+
return active;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=registration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registration.js","sourceRoot":"","sources":["../../src/helpers/registration.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAWhF,IAAI,MAAgC,CAAC;AAErC;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CAAC,YAA0B;IACjD,MAAM,GAAG,YAAY,CAAC;AACxB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,YAA0B;IACnD,IAAI,MAAM,KAAK,YAAY;QAAE,MAAM,GAAG,SAAS,CAAC;AAClD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB;IAChC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,sBAAsB,CAC9B,kDAAkD,CACnD,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { WithJobContext } from '../interfaces/job-context.interface.js';
|
|
2
|
+
/**
|
|
3
|
+
* Stamps the current execution context onto a job payload: the tenant and
|
|
4
|
+
* correlation id of the registered sources (a new one from the correlation
|
|
5
|
+
* source's `create()` when none is active), and the principal the registered `IJobPrincipal`
|
|
6
|
+
* captures, reduced to its identity. The processor restores it with
|
|
7
|
+
* `@InJobContext`.
|
|
8
|
+
*
|
|
9
|
+
* @param data - The payload. Must be a plain object; a shallow copy is returned.
|
|
10
|
+
* @returns A copy of `data` with `jobContext` added.
|
|
11
|
+
* @throws {TypeError} When `data` is not a plain object.
|
|
12
|
+
* @throws {MissingJobContextError} Without a `registerJobContext` registration, a
|
|
13
|
+
* current tenant, or a current principal.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* await queue.add('send', withJobContext({ userId, email }));
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function withJobContext<T extends Record<string, unknown>>(data: T): WithJobContext<T>;
|
|
21
|
+
//# sourceMappingURL=with-job-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-job-context.d.ts","sourceRoot":"","sources":["../../src/helpers/with-job-context.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAI7E;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,IAAI,EAAE,CAAC,GACN,cAAc,CAAC,CAAC,CAAC,CAwBnB"}
|