@forklaunch/interfaces-worker 1.0.2 → 1.0.4
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/lib/eject/domain/interfaces/decryptingWorker.consumer.ts +99 -0
- package/lib/eject/domain/interfaces/encryptingWorker.producer.ts +56 -0
- package/lib/eject/domain/interfaces/index.ts +2 -0
- package/lib/eject/domain/types/eventEncryptor.types.ts +21 -0
- package/lib/eject/domain/types/index.ts +1 -0
- package/lib/interfaces/index.d.mts +43 -1
- package/lib/interfaces/index.d.ts +43 -1
- package/lib/interfaces/index.js +104 -0
- package/lib/interfaces/index.mjs +92 -0
- package/lib/types/index.d.mts +27 -8
- package/lib/types/index.d.ts +27 -8
- package/package.json +1 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { WorkerEventEntity } from '../types/workerEventEntity.types';
|
|
2
|
+
import type {
|
|
3
|
+
WorkerProcessFunction,
|
|
4
|
+
WorkerProcessFailureResult,
|
|
5
|
+
WorkerFailureHandler
|
|
6
|
+
} from '../types/worker.consumer.types';
|
|
7
|
+
import type {
|
|
8
|
+
EventEncryptor,
|
|
9
|
+
EncryptedEventEnvelope
|
|
10
|
+
} from '../types/eventEncryptor.types';
|
|
11
|
+
import type { WorkerConsumer } from './worker.consumer.interface';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Wraps a WorkerConsumer that reads EncryptedEventEnvelope and exposes
|
|
15
|
+
* the decrypted user-typed event T.
|
|
16
|
+
*/
|
|
17
|
+
export class DecryptingWorkerConsumer<T extends WorkerEventEntity>
|
|
18
|
+
implements WorkerConsumer<T>
|
|
19
|
+
{
|
|
20
|
+
constructor(
|
|
21
|
+
private readonly inner: WorkerConsumer<EncryptedEventEnvelope>,
|
|
22
|
+
private readonly encryptor: EventEncryptor
|
|
23
|
+
) {}
|
|
24
|
+
|
|
25
|
+
async peekEvents(): Promise<T[]> {
|
|
26
|
+
const events = await this.inner.peekEvents();
|
|
27
|
+
return events.map((event) => decryptEvent<T>(event, this.encryptor));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async start(): Promise<void> {
|
|
31
|
+
await this.inner.start();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Wraps a user-typed WorkerProcessFunction to accept EncryptedEventEnvelope,
|
|
37
|
+
* decrypt before processing, and map failures back to the envelope type.
|
|
38
|
+
*/
|
|
39
|
+
export function withDecryption<T extends WorkerEventEntity>(
|
|
40
|
+
processFn: WorkerProcessFunction<T>,
|
|
41
|
+
encryptor: EventEncryptor
|
|
42
|
+
): WorkerProcessFunction<EncryptedEventEnvelope> {
|
|
43
|
+
return async (events: EncryptedEventEnvelope[]) => {
|
|
44
|
+
const decrypted = events.map((e) => decryptEvent<T>(e, encryptor));
|
|
45
|
+
const failures = await processFn(decrypted);
|
|
46
|
+
// Map failures back: find the original envelope by id
|
|
47
|
+
return failures.map((f) => ({
|
|
48
|
+
value: events.find((e) => e.id === f.value.id)!,
|
|
49
|
+
error: f.error
|
|
50
|
+
}));
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Wraps a user-typed WorkerFailureHandler to accept EncryptedEventEnvelope failures,
|
|
56
|
+
* decrypting before passing to the user handler.
|
|
57
|
+
*/
|
|
58
|
+
export function withDecryptionFailureHandler<T extends WorkerEventEntity>(
|
|
59
|
+
handler: WorkerFailureHandler<T>,
|
|
60
|
+
encryptor: EventEncryptor
|
|
61
|
+
): WorkerFailureHandler<EncryptedEventEnvelope> {
|
|
62
|
+
return async (
|
|
63
|
+
results: WorkerProcessFailureResult<EncryptedEventEnvelope>[]
|
|
64
|
+
) => {
|
|
65
|
+
const decrypted = results.map((r) => ({
|
|
66
|
+
...r,
|
|
67
|
+
value: decryptEvent<T>(r.value, encryptor)
|
|
68
|
+
}));
|
|
69
|
+
return handler(decrypted);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function decryptEvent<T extends WorkerEventEntity>(
|
|
74
|
+
envelope: EncryptedEventEnvelope,
|
|
75
|
+
encryptor: EventEncryptor
|
|
76
|
+
): T {
|
|
77
|
+
const {
|
|
78
|
+
id,
|
|
79
|
+
tenantId,
|
|
80
|
+
retryCount,
|
|
81
|
+
processed,
|
|
82
|
+
createdAt,
|
|
83
|
+
updatedAt,
|
|
84
|
+
encryptedPayload
|
|
85
|
+
} = envelope;
|
|
86
|
+
|
|
87
|
+
const decrypted = encryptor.decrypt(encryptedPayload, tenantId);
|
|
88
|
+
const payload = JSON.parse(decrypted!);
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
id,
|
|
92
|
+
tenantId,
|
|
93
|
+
retryCount,
|
|
94
|
+
processed,
|
|
95
|
+
createdAt,
|
|
96
|
+
updatedAt,
|
|
97
|
+
...payload
|
|
98
|
+
} as T;
|
|
99
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { WorkerEventEntity } from '../types/workerEventEntity.types';
|
|
2
|
+
import type {
|
|
3
|
+
EventEncryptor,
|
|
4
|
+
EncryptedEventEnvelope
|
|
5
|
+
} from '../types/eventEncryptor.types';
|
|
6
|
+
import type { WorkerProducer } from './worker.producer.interface';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Wraps any WorkerProducer to encrypt the entire event payload before enqueueing.
|
|
10
|
+
* Base WorkerEventEntity fields (id, retryCount, processed, createdAt, updatedAt)
|
|
11
|
+
* are preserved in the clear for queue infrastructure. All remaining fields are
|
|
12
|
+
* JSON-serialized and encrypted into a single `encryptedPayload` field.
|
|
13
|
+
*
|
|
14
|
+
* tenantId is injected at construction (from request scope context) and stored
|
|
15
|
+
* on the envelope for key derivation during decryption.
|
|
16
|
+
*/
|
|
17
|
+
export class EncryptingWorkerProducer<T extends WorkerEventEntity>
|
|
18
|
+
implements WorkerProducer<T>
|
|
19
|
+
{
|
|
20
|
+
constructor(
|
|
21
|
+
private readonly inner: WorkerProducer<EncryptedEventEnvelope>,
|
|
22
|
+
private readonly encryptor: EventEncryptor,
|
|
23
|
+
private readonly tenantId: string
|
|
24
|
+
) {}
|
|
25
|
+
|
|
26
|
+
async enqueueJob(job: T): Promise<void> {
|
|
27
|
+
await this.inner.enqueueJob(
|
|
28
|
+
encryptEvent(job, this.encryptor, this.tenantId)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async enqueueBatchJobs(jobs: T[]): Promise<void> {
|
|
33
|
+
await this.inner.enqueueBatchJobs(
|
|
34
|
+
jobs.map((job) => encryptEvent(job, this.encryptor, this.tenantId))
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function encryptEvent<T extends WorkerEventEntity>(
|
|
40
|
+
event: T,
|
|
41
|
+
encryptor: EventEncryptor,
|
|
42
|
+
tenantId: string
|
|
43
|
+
): EncryptedEventEnvelope {
|
|
44
|
+
const { id, retryCount, processed, createdAt, updatedAt, ...payload } =
|
|
45
|
+
event as WorkerEventEntity & Record<string, unknown>;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
id,
|
|
49
|
+
tenantId,
|
|
50
|
+
retryCount,
|
|
51
|
+
processed,
|
|
52
|
+
createdAt,
|
|
53
|
+
updatedAt,
|
|
54
|
+
encryptedPayload: encryptor.encrypt(JSON.stringify(payload), tenantId)!
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { WorkerEventEntity } from './workerEventEntity.types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal encryptor interface for worker event payload encryption.
|
|
5
|
+
* Keeps interfaces-worker free of @forklaunch/core dependency.
|
|
6
|
+
* Implement with FieldEncryptor from @forklaunch/core/persistence.
|
|
7
|
+
*/
|
|
8
|
+
export interface EventEncryptor {
|
|
9
|
+
encrypt(plaintext: string | null, tenantId: string): string | null;
|
|
10
|
+
decrypt(ciphertext: string | null, tenantId: string): string | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The on-wire shape stored in the queue. Base fields are in the clear
|
|
15
|
+
* for queue infrastructure (retry logic, dedup, etc.). The user's
|
|
16
|
+
* payload fields are serialized and encrypted into `encryptedPayload`.
|
|
17
|
+
*/
|
|
18
|
+
export type EncryptedEventEnvelope = WorkerEventEntity & {
|
|
19
|
+
tenantId: string;
|
|
20
|
+
encryptedPayload: string;
|
|
21
|
+
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { WorkerEventEntity, EncryptedEventEnvelope, EventEncryptor, WorkerProcessFunction, WorkerFailureHandler } from '../types/index.mjs';
|
|
2
|
+
|
|
1
3
|
interface WorkerConsumer<T> {
|
|
2
4
|
peekEvents: () => Promise<T[]>;
|
|
3
5
|
start: () => Promise<void>;
|
|
@@ -8,4 +10,44 @@ interface WorkerProducer<T> {
|
|
|
8
10
|
enqueueBatchJobs: (jobs: T[]) => Promise<void>;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Wraps any WorkerProducer to encrypt the entire event payload before enqueueing.
|
|
15
|
+
* Base WorkerEventEntity fields (id, retryCount, processed, createdAt, updatedAt)
|
|
16
|
+
* are preserved in the clear for queue infrastructure. All remaining fields are
|
|
17
|
+
* JSON-serialized and encrypted into a single `encryptedPayload` field.
|
|
18
|
+
*
|
|
19
|
+
* tenantId is injected at construction (from request scope context) and stored
|
|
20
|
+
* on the envelope for key derivation during decryption.
|
|
21
|
+
*/
|
|
22
|
+
declare class EncryptingWorkerProducer<T extends WorkerEventEntity> implements WorkerProducer<T> {
|
|
23
|
+
private readonly inner;
|
|
24
|
+
private readonly encryptor;
|
|
25
|
+
private readonly tenantId;
|
|
26
|
+
constructor(inner: WorkerProducer<EncryptedEventEnvelope>, encryptor: EventEncryptor, tenantId: string);
|
|
27
|
+
enqueueJob(job: T): Promise<void>;
|
|
28
|
+
enqueueBatchJobs(jobs: T[]): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Wraps a WorkerConsumer that reads EncryptedEventEnvelope and exposes
|
|
33
|
+
* the decrypted user-typed event T.
|
|
34
|
+
*/
|
|
35
|
+
declare class DecryptingWorkerConsumer<T extends WorkerEventEntity> implements WorkerConsumer<T> {
|
|
36
|
+
private readonly inner;
|
|
37
|
+
private readonly encryptor;
|
|
38
|
+
constructor(inner: WorkerConsumer<EncryptedEventEnvelope>, encryptor: EventEncryptor);
|
|
39
|
+
peekEvents(): Promise<T[]>;
|
|
40
|
+
start(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Wraps a user-typed WorkerProcessFunction to accept EncryptedEventEnvelope,
|
|
44
|
+
* decrypt before processing, and map failures back to the envelope type.
|
|
45
|
+
*/
|
|
46
|
+
declare function withDecryption<T extends WorkerEventEntity>(processFn: WorkerProcessFunction<T>, encryptor: EventEncryptor): WorkerProcessFunction<EncryptedEventEnvelope>;
|
|
47
|
+
/**
|
|
48
|
+
* Wraps a user-typed WorkerFailureHandler to accept EncryptedEventEnvelope failures,
|
|
49
|
+
* decrypting before passing to the user handler.
|
|
50
|
+
*/
|
|
51
|
+
declare function withDecryptionFailureHandler<T extends WorkerEventEntity>(handler: WorkerFailureHandler<T>, encryptor: EventEncryptor): WorkerFailureHandler<EncryptedEventEnvelope>;
|
|
52
|
+
|
|
53
|
+
export { DecryptingWorkerConsumer, EncryptingWorkerProducer, type WorkerConsumer, type WorkerProducer, withDecryption, withDecryptionFailureHandler };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { WorkerEventEntity, EncryptedEventEnvelope, EventEncryptor, WorkerProcessFunction, WorkerFailureHandler } from '../types/index.js';
|
|
2
|
+
|
|
1
3
|
interface WorkerConsumer<T> {
|
|
2
4
|
peekEvents: () => Promise<T[]>;
|
|
3
5
|
start: () => Promise<void>;
|
|
@@ -8,4 +10,44 @@ interface WorkerProducer<T> {
|
|
|
8
10
|
enqueueBatchJobs: (jobs: T[]) => Promise<void>;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Wraps any WorkerProducer to encrypt the entire event payload before enqueueing.
|
|
15
|
+
* Base WorkerEventEntity fields (id, retryCount, processed, createdAt, updatedAt)
|
|
16
|
+
* are preserved in the clear for queue infrastructure. All remaining fields are
|
|
17
|
+
* JSON-serialized and encrypted into a single `encryptedPayload` field.
|
|
18
|
+
*
|
|
19
|
+
* tenantId is injected at construction (from request scope context) and stored
|
|
20
|
+
* on the envelope for key derivation during decryption.
|
|
21
|
+
*/
|
|
22
|
+
declare class EncryptingWorkerProducer<T extends WorkerEventEntity> implements WorkerProducer<T> {
|
|
23
|
+
private readonly inner;
|
|
24
|
+
private readonly encryptor;
|
|
25
|
+
private readonly tenantId;
|
|
26
|
+
constructor(inner: WorkerProducer<EncryptedEventEnvelope>, encryptor: EventEncryptor, tenantId: string);
|
|
27
|
+
enqueueJob(job: T): Promise<void>;
|
|
28
|
+
enqueueBatchJobs(jobs: T[]): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Wraps a WorkerConsumer that reads EncryptedEventEnvelope and exposes
|
|
33
|
+
* the decrypted user-typed event T.
|
|
34
|
+
*/
|
|
35
|
+
declare class DecryptingWorkerConsumer<T extends WorkerEventEntity> implements WorkerConsumer<T> {
|
|
36
|
+
private readonly inner;
|
|
37
|
+
private readonly encryptor;
|
|
38
|
+
constructor(inner: WorkerConsumer<EncryptedEventEnvelope>, encryptor: EventEncryptor);
|
|
39
|
+
peekEvents(): Promise<T[]>;
|
|
40
|
+
start(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Wraps a user-typed WorkerProcessFunction to accept EncryptedEventEnvelope,
|
|
44
|
+
* decrypt before processing, and map failures back to the envelope type.
|
|
45
|
+
*/
|
|
46
|
+
declare function withDecryption<T extends WorkerEventEntity>(processFn: WorkerProcessFunction<T>, encryptor: EventEncryptor): WorkerProcessFunction<EncryptedEventEnvelope>;
|
|
47
|
+
/**
|
|
48
|
+
* Wraps a user-typed WorkerFailureHandler to accept EncryptedEventEnvelope failures,
|
|
49
|
+
* decrypting before passing to the user handler.
|
|
50
|
+
*/
|
|
51
|
+
declare function withDecryptionFailureHandler<T extends WorkerEventEntity>(handler: WorkerFailureHandler<T>, encryptor: EventEncryptor): WorkerFailureHandler<EncryptedEventEnvelope>;
|
|
52
|
+
|
|
53
|
+
export { DecryptingWorkerConsumer, EncryptingWorkerProducer, type WorkerConsumer, type WorkerProducer, withDecryption, withDecryptionFailureHandler };
|
package/lib/interfaces/index.js
CHANGED
|
@@ -3,6 +3,10 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
6
10
|
var __copyProps = (to, from, except, desc) => {
|
|
7
11
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
12
|
for (let key of __getOwnPropNames(from))
|
|
@@ -15,4 +19,104 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
15
19
|
|
|
16
20
|
// interfaces/index.ts
|
|
17
21
|
var interfaces_exports = {};
|
|
22
|
+
__export(interfaces_exports, {
|
|
23
|
+
DecryptingWorkerConsumer: () => DecryptingWorkerConsumer,
|
|
24
|
+
EncryptingWorkerProducer: () => EncryptingWorkerProducer,
|
|
25
|
+
withDecryption: () => withDecryption,
|
|
26
|
+
withDecryptionFailureHandler: () => withDecryptionFailureHandler
|
|
27
|
+
});
|
|
18
28
|
module.exports = __toCommonJS(interfaces_exports);
|
|
29
|
+
|
|
30
|
+
// interfaces/encryptingWorker.producer.ts
|
|
31
|
+
var EncryptingWorkerProducer = class {
|
|
32
|
+
constructor(inner, encryptor, tenantId) {
|
|
33
|
+
this.inner = inner;
|
|
34
|
+
this.encryptor = encryptor;
|
|
35
|
+
this.tenantId = tenantId;
|
|
36
|
+
}
|
|
37
|
+
async enqueueJob(job) {
|
|
38
|
+
await this.inner.enqueueJob(
|
|
39
|
+
encryptEvent(job, this.encryptor, this.tenantId)
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
async enqueueBatchJobs(jobs) {
|
|
43
|
+
await this.inner.enqueueBatchJobs(
|
|
44
|
+
jobs.map((job) => encryptEvent(job, this.encryptor, this.tenantId))
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
function encryptEvent(event, encryptor, tenantId) {
|
|
49
|
+
const { id, retryCount, processed, createdAt, updatedAt, ...payload } = event;
|
|
50
|
+
return {
|
|
51
|
+
id,
|
|
52
|
+
tenantId,
|
|
53
|
+
retryCount,
|
|
54
|
+
processed,
|
|
55
|
+
createdAt,
|
|
56
|
+
updatedAt,
|
|
57
|
+
encryptedPayload: encryptor.encrypt(JSON.stringify(payload), tenantId)
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// interfaces/decryptingWorker.consumer.ts
|
|
62
|
+
var DecryptingWorkerConsumer = class {
|
|
63
|
+
constructor(inner, encryptor) {
|
|
64
|
+
this.inner = inner;
|
|
65
|
+
this.encryptor = encryptor;
|
|
66
|
+
}
|
|
67
|
+
async peekEvents() {
|
|
68
|
+
const events = await this.inner.peekEvents();
|
|
69
|
+
return events.map((event) => decryptEvent(event, this.encryptor));
|
|
70
|
+
}
|
|
71
|
+
async start() {
|
|
72
|
+
await this.inner.start();
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
function withDecryption(processFn, encryptor) {
|
|
76
|
+
return async (events) => {
|
|
77
|
+
const decrypted = events.map((e) => decryptEvent(e, encryptor));
|
|
78
|
+
const failures = await processFn(decrypted);
|
|
79
|
+
return failures.map((f) => ({
|
|
80
|
+
value: events.find((e) => e.id === f.value.id),
|
|
81
|
+
error: f.error
|
|
82
|
+
}));
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function withDecryptionFailureHandler(handler, encryptor) {
|
|
86
|
+
return async (results) => {
|
|
87
|
+
const decrypted = results.map((r) => ({
|
|
88
|
+
...r,
|
|
89
|
+
value: decryptEvent(r.value, encryptor)
|
|
90
|
+
}));
|
|
91
|
+
return handler(decrypted);
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function decryptEvent(envelope, encryptor) {
|
|
95
|
+
const {
|
|
96
|
+
id,
|
|
97
|
+
tenantId,
|
|
98
|
+
retryCount,
|
|
99
|
+
processed,
|
|
100
|
+
createdAt,
|
|
101
|
+
updatedAt,
|
|
102
|
+
encryptedPayload
|
|
103
|
+
} = envelope;
|
|
104
|
+
const decrypted = encryptor.decrypt(encryptedPayload, tenantId);
|
|
105
|
+
const payload = JSON.parse(decrypted);
|
|
106
|
+
return {
|
|
107
|
+
id,
|
|
108
|
+
tenantId,
|
|
109
|
+
retryCount,
|
|
110
|
+
processed,
|
|
111
|
+
createdAt,
|
|
112
|
+
updatedAt,
|
|
113
|
+
...payload
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
117
|
+
0 && (module.exports = {
|
|
118
|
+
DecryptingWorkerConsumer,
|
|
119
|
+
EncryptingWorkerProducer,
|
|
120
|
+
withDecryption,
|
|
121
|
+
withDecryptionFailureHandler
|
|
122
|
+
});
|
package/lib/interfaces/index.mjs
CHANGED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// interfaces/encryptingWorker.producer.ts
|
|
2
|
+
var EncryptingWorkerProducer = class {
|
|
3
|
+
constructor(inner, encryptor, tenantId) {
|
|
4
|
+
this.inner = inner;
|
|
5
|
+
this.encryptor = encryptor;
|
|
6
|
+
this.tenantId = tenantId;
|
|
7
|
+
}
|
|
8
|
+
async enqueueJob(job) {
|
|
9
|
+
await this.inner.enqueueJob(
|
|
10
|
+
encryptEvent(job, this.encryptor, this.tenantId)
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
async enqueueBatchJobs(jobs) {
|
|
14
|
+
await this.inner.enqueueBatchJobs(
|
|
15
|
+
jobs.map((job) => encryptEvent(job, this.encryptor, this.tenantId))
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
function encryptEvent(event, encryptor, tenantId) {
|
|
20
|
+
const { id, retryCount, processed, createdAt, updatedAt, ...payload } = event;
|
|
21
|
+
return {
|
|
22
|
+
id,
|
|
23
|
+
tenantId,
|
|
24
|
+
retryCount,
|
|
25
|
+
processed,
|
|
26
|
+
createdAt,
|
|
27
|
+
updatedAt,
|
|
28
|
+
encryptedPayload: encryptor.encrypt(JSON.stringify(payload), tenantId)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// interfaces/decryptingWorker.consumer.ts
|
|
33
|
+
var DecryptingWorkerConsumer = class {
|
|
34
|
+
constructor(inner, encryptor) {
|
|
35
|
+
this.inner = inner;
|
|
36
|
+
this.encryptor = encryptor;
|
|
37
|
+
}
|
|
38
|
+
async peekEvents() {
|
|
39
|
+
const events = await this.inner.peekEvents();
|
|
40
|
+
return events.map((event) => decryptEvent(event, this.encryptor));
|
|
41
|
+
}
|
|
42
|
+
async start() {
|
|
43
|
+
await this.inner.start();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
function withDecryption(processFn, encryptor) {
|
|
47
|
+
return async (events) => {
|
|
48
|
+
const decrypted = events.map((e) => decryptEvent(e, encryptor));
|
|
49
|
+
const failures = await processFn(decrypted);
|
|
50
|
+
return failures.map((f) => ({
|
|
51
|
+
value: events.find((e) => e.id === f.value.id),
|
|
52
|
+
error: f.error
|
|
53
|
+
}));
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function withDecryptionFailureHandler(handler, encryptor) {
|
|
57
|
+
return async (results) => {
|
|
58
|
+
const decrypted = results.map((r) => ({
|
|
59
|
+
...r,
|
|
60
|
+
value: decryptEvent(r.value, encryptor)
|
|
61
|
+
}));
|
|
62
|
+
return handler(decrypted);
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function decryptEvent(envelope, encryptor) {
|
|
66
|
+
const {
|
|
67
|
+
id,
|
|
68
|
+
tenantId,
|
|
69
|
+
retryCount,
|
|
70
|
+
processed,
|
|
71
|
+
createdAt,
|
|
72
|
+
updatedAt,
|
|
73
|
+
encryptedPayload
|
|
74
|
+
} = envelope;
|
|
75
|
+
const decrypted = encryptor.decrypt(encryptedPayload, tenantId);
|
|
76
|
+
const payload = JSON.parse(decrypted);
|
|
77
|
+
return {
|
|
78
|
+
id,
|
|
79
|
+
tenantId,
|
|
80
|
+
retryCount,
|
|
81
|
+
processed,
|
|
82
|
+
createdAt,
|
|
83
|
+
updatedAt,
|
|
84
|
+
...payload
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export {
|
|
88
|
+
DecryptingWorkerConsumer,
|
|
89
|
+
EncryptingWorkerProducer,
|
|
90
|
+
withDecryption,
|
|
91
|
+
withDecryptionFailureHandler
|
|
92
|
+
};
|
package/lib/types/index.d.mts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
type WorkerProcessFailureResult<T> = {
|
|
2
|
-
value: T;
|
|
3
|
-
error: Error;
|
|
4
|
-
};
|
|
5
|
-
type WorkerProcessFunction<T> = (events: T[]) => Promise<WorkerProcessFailureResult<T>[]>;
|
|
6
|
-
type WorkerFailureHandler<T> = (results: WorkerProcessFailureResult<T>[]) => Promise<void>;
|
|
7
|
-
|
|
8
1
|
type WorkerEventEntity = {
|
|
9
2
|
id: string;
|
|
10
3
|
retryCount: number;
|
|
@@ -13,4 +6,30 @@ type WorkerEventEntity = {
|
|
|
13
6
|
updatedAt: Date;
|
|
14
7
|
};
|
|
15
8
|
|
|
16
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Minimal encryptor interface for worker event payload encryption.
|
|
11
|
+
* Keeps interfaces-worker free of @forklaunch/core dependency.
|
|
12
|
+
* Implement with FieldEncryptor from @forklaunch/core/persistence.
|
|
13
|
+
*/
|
|
14
|
+
interface EventEncryptor {
|
|
15
|
+
encrypt(plaintext: string | null, tenantId: string): string | null;
|
|
16
|
+
decrypt(ciphertext: string | null, tenantId: string): string | null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The on-wire shape stored in the queue. Base fields are in the clear
|
|
20
|
+
* for queue infrastructure (retry logic, dedup, etc.). The user's
|
|
21
|
+
* payload fields are serialized and encrypted into `encryptedPayload`.
|
|
22
|
+
*/
|
|
23
|
+
type EncryptedEventEnvelope = WorkerEventEntity & {
|
|
24
|
+
tenantId: string;
|
|
25
|
+
encryptedPayload: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
type WorkerProcessFailureResult<T> = {
|
|
29
|
+
value: T;
|
|
30
|
+
error: Error;
|
|
31
|
+
};
|
|
32
|
+
type WorkerProcessFunction<T> = (events: T[]) => Promise<WorkerProcessFailureResult<T>[]>;
|
|
33
|
+
type WorkerFailureHandler<T> = (results: WorkerProcessFailureResult<T>[]) => Promise<void>;
|
|
34
|
+
|
|
35
|
+
export type { EncryptedEventEnvelope, EventEncryptor, WorkerEventEntity, WorkerFailureHandler, WorkerProcessFailureResult, WorkerProcessFunction };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
type WorkerProcessFailureResult<T> = {
|
|
2
|
-
value: T;
|
|
3
|
-
error: Error;
|
|
4
|
-
};
|
|
5
|
-
type WorkerProcessFunction<T> = (events: T[]) => Promise<WorkerProcessFailureResult<T>[]>;
|
|
6
|
-
type WorkerFailureHandler<T> = (results: WorkerProcessFailureResult<T>[]) => Promise<void>;
|
|
7
|
-
|
|
8
1
|
type WorkerEventEntity = {
|
|
9
2
|
id: string;
|
|
10
3
|
retryCount: number;
|
|
@@ -13,4 +6,30 @@ type WorkerEventEntity = {
|
|
|
13
6
|
updatedAt: Date;
|
|
14
7
|
};
|
|
15
8
|
|
|
16
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Minimal encryptor interface for worker event payload encryption.
|
|
11
|
+
* Keeps interfaces-worker free of @forklaunch/core dependency.
|
|
12
|
+
* Implement with FieldEncryptor from @forklaunch/core/persistence.
|
|
13
|
+
*/
|
|
14
|
+
interface EventEncryptor {
|
|
15
|
+
encrypt(plaintext: string | null, tenantId: string): string | null;
|
|
16
|
+
decrypt(ciphertext: string | null, tenantId: string): string | null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The on-wire shape stored in the queue. Base fields are in the clear
|
|
20
|
+
* for queue infrastructure (retry logic, dedup, etc.). The user's
|
|
21
|
+
* payload fields are serialized and encrypted into `encryptedPayload`.
|
|
22
|
+
*/
|
|
23
|
+
type EncryptedEventEnvelope = WorkerEventEntity & {
|
|
24
|
+
tenantId: string;
|
|
25
|
+
encryptedPayload: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
type WorkerProcessFailureResult<T> = {
|
|
29
|
+
value: T;
|
|
30
|
+
error: Error;
|
|
31
|
+
};
|
|
32
|
+
type WorkerProcessFunction<T> = (events: T[]) => Promise<WorkerProcessFailureResult<T>[]>;
|
|
33
|
+
type WorkerFailureHandler<T> = (results: WorkerProcessFailureResult<T>[]) => Promise<void>;
|
|
34
|
+
|
|
35
|
+
export type { EncryptedEventEnvelope, EventEncryptor, WorkerEventEntity, WorkerFailureHandler, WorkerProcessFailureResult, WorkerProcessFunction };
|