effect-jobs 0.1.0-alpha.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/CHANGELOG.md +16 -0
- package/LICENSE +22 -0
- package/README.md +142 -0
- package/dist/Job.d.ts +33 -0
- package/dist/Job.d.ts.map +1 -0
- package/dist/Job.js +66 -0
- package/dist/Job.js.map +1 -0
- package/dist/JobConsumer.d.ts +34 -0
- package/dist/JobConsumer.d.ts.map +1 -0
- package/dist/JobConsumer.js +28 -0
- package/dist/JobConsumer.js.map +1 -0
- package/dist/JobContract.d.ts +128 -0
- package/dist/JobContract.d.ts.map +1 -0
- package/dist/JobContract.js +15 -0
- package/dist/JobContract.js.map +1 -0
- package/dist/JobFailure.d.ts +51 -0
- package/dist/JobFailure.d.ts.map +1 -0
- package/dist/JobFailure.js +34 -0
- package/dist/JobFailure.js.map +1 -0
- package/dist/JobId.d.ts +5 -0
- package/dist/JobId.d.ts.map +1 -0
- package/dist/JobId.js +4 -0
- package/dist/JobId.js.map +1 -0
- package/dist/JobIdentity.d.ts +54 -0
- package/dist/JobIdentity.d.ts.map +1 -0
- package/dist/JobIdentity.js +82 -0
- package/dist/JobIdentity.js.map +1 -0
- package/dist/JobLifecycle.d.ts +173 -0
- package/dist/JobLifecycle.d.ts.map +1 -0
- package/dist/JobLifecycle.js +234 -0
- package/dist/JobLifecycle.js.map +1 -0
- package/dist/JobPayload.d.ts +18 -0
- package/dist/JobPayload.d.ts.map +1 -0
- package/dist/JobPayload.js +10 -0
- package/dist/JobPayload.js.map +1 -0
- package/dist/JobPayloadCodec.d.ts +14 -0
- package/dist/JobPayloadCodec.d.ts.map +1 -0
- package/dist/JobPayloadCodec.js +78 -0
- package/dist/JobPayloadCodec.js.map +1 -0
- package/dist/JobPolicy.d.ts +50 -0
- package/dist/JobPolicy.d.ts.map +1 -0
- package/dist/JobPolicy.js +85 -0
- package/dist/JobPolicy.js.map +1 -0
- package/dist/JobProducer.d.ts +14 -0
- package/dist/JobProducer.d.ts.map +1 -0
- package/dist/JobProducer.js +23 -0
- package/dist/JobProducer.js.map +1 -0
- package/dist/JobQueue.d.ts +16 -0
- package/dist/JobQueue.d.ts.map +1 -0
- package/dist/JobQueue.js +16 -0
- package/dist/JobQueue.js.map +1 -0
- package/dist/JobRegistry.d.ts +37 -0
- package/dist/JobRegistry.d.ts.map +1 -0
- package/dist/JobRegistry.js +47 -0
- package/dist/JobRegistry.js.map +1 -0
- package/dist/JobStore.d.ts +348 -0
- package/dist/JobStore.d.ts.map +1 -0
- package/dist/JobStore.js +19 -0
- package/dist/JobStore.js.map +1 -0
- package/dist/JobTelemetry.d.ts +7 -0
- package/dist/JobTelemetry.d.ts.map +1 -0
- package/dist/JobTelemetry.js +61 -0
- package/dist/JobTelemetry.js.map +1 -0
- package/dist/JobTransaction.d.ts +24 -0
- package/dist/JobTransaction.d.ts.map +1 -0
- package/dist/JobTransaction.js +7 -0
- package/dist/JobTransaction.js.map +1 -0
- package/dist/JobWorker.d.ts +24 -0
- package/dist/JobWorker.d.ts.map +1 -0
- package/dist/JobWorker.js +155 -0
- package/dist/JobWorker.js.map +1 -0
- package/dist/JobWorkerRuntime.d.ts +18 -0
- package/dist/JobWorkerRuntime.d.ts.map +1 -0
- package/dist/JobWorkerRuntime.js +5 -0
- package/dist/JobWorkerRuntime.js.map +1 -0
- package/dist/PollingJobWorker.d.ts +9 -0
- package/dist/PollingJobWorker.d.ts.map +1 -0
- package/dist/PollingJobWorker.js +54 -0
- package/dist/PollingJobWorker.js.map +1 -0
- package/dist/PostgreSqlDrizzleSchema.d.ts +432 -0
- package/dist/PostgreSqlDrizzleSchema.d.ts.map +1 -0
- package/dist/PostgreSqlDrizzleSchema.js +72 -0
- package/dist/PostgreSqlDrizzleSchema.js.map +1 -0
- package/dist/PostgreSqlJobs.d.ts +25 -0
- package/dist/PostgreSqlJobs.d.ts.map +1 -0
- package/dist/PostgreSqlJobs.js +38 -0
- package/dist/PostgreSqlJobs.js.map +1 -0
- package/dist/PostgreSqlSchema.d.ts +30 -0
- package/dist/PostgreSqlSchema.d.ts.map +1 -0
- package/dist/PostgreSqlSchema.js +63 -0
- package/dist/PostgreSqlSchema.js.map +1 -0
- package/dist/PostgreSqlTransaction.d.ts +42 -0
- package/dist/PostgreSqlTransaction.d.ts.map +1 -0
- package/dist/PostgreSqlTransaction.js +9 -0
- package/dist/PostgreSqlTransaction.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/JobTransaction.d.ts +16 -0
- package/dist/internal/JobTransaction.d.ts.map +1 -0
- package/dist/internal/JobTransaction.js +21 -0
- package/dist/internal/JobTransaction.js.map +1 -0
- package/dist/internal/codec/CanonicalJson.d.ts +9 -0
- package/dist/internal/codec/CanonicalJson.d.ts.map +1 -0
- package/dist/internal/codec/CanonicalJson.js +184 -0
- package/dist/internal/codec/CanonicalJson.js.map +1 -0
- package/dist/internal/codec/ProtectedProjection.d.ts +12 -0
- package/dist/internal/codec/ProtectedProjection.d.ts.map +1 -0
- package/dist/internal/codec/ProtectedProjection.js +121 -0
- package/dist/internal/codec/ProtectedProjection.js.map +1 -0
- package/dist/internal/lifecycle/Artifacts.d.ts +6 -0
- package/dist/internal/lifecycle/Artifacts.d.ts.map +1 -0
- package/dist/internal/lifecycle/Artifacts.js +49 -0
- package/dist/internal/lifecycle/Artifacts.js.map +1 -0
- package/dist/internal/lifecycle/Reconciliation.d.ts +82 -0
- package/dist/internal/lifecycle/Reconciliation.d.ts.map +1 -0
- package/dist/internal/lifecycle/Reconciliation.js +98 -0
- package/dist/internal/lifecycle/Reconciliation.js.map +1 -0
- package/dist/internal/postgresql/Producer.d.ts +14 -0
- package/dist/internal/postgresql/Producer.d.ts.map +1 -0
- package/dist/internal/postgresql/Producer.js +55 -0
- package/dist/internal/postgresql/Producer.js.map +1 -0
- package/dist/internal/postgresql/Readiness.d.ts +5 -0
- package/dist/internal/postgresql/Readiness.d.ts.map +1 -0
- package/dist/internal/postgresql/Readiness.js +53 -0
- package/dist/internal/postgresql/Readiness.js.map +1 -0
- package/dist/internal/postgresql/Rows.d.ts +45 -0
- package/dist/internal/postgresql/Rows.d.ts.map +1 -0
- package/dist/internal/postgresql/Rows.js +75 -0
- package/dist/internal/postgresql/Rows.js.map +1 -0
- package/dist/internal/postgresql/Store.d.ts +5 -0
- package/dist/internal/postgresql/Store.d.ts.map +1 -0
- package/dist/internal/postgresql/Store.js +211 -0
- package/dist/internal/postgresql/Store.js.map +1 -0
- package/dist/internal/worker/Capability.d.ts +106 -0
- package/dist/internal/worker/Capability.d.ts.map +1 -0
- package/dist/internal/worker/Capability.js +11 -0
- package/dist/internal/worker/Capability.js.map +1 -0
- package/dist/internal/worker/Drain.d.ts +22 -0
- package/dist/internal/worker/Drain.d.ts.map +1 -0
- package/dist/internal/worker/Drain.js +59 -0
- package/dist/internal/worker/Drain.js.map +1 -0
- package/dist/internal/worker/Execution.d.ts +7 -0
- package/dist/internal/worker/Execution.d.ts.map +1 -0
- package/dist/internal/worker/Execution.js +125 -0
- package/dist/internal/worker/Execution.js.map +1 -0
- package/dist/internal/worker/Results.d.ts +108 -0
- package/dist/internal/worker/Results.d.ts.map +1 -0
- package/dist/internal/worker/Results.js +3 -0
- package/dist/internal/worker/Results.js.map +1 -0
- package/package.json +169 -0
- package/specs/architecture-decisions.md +841 -0
- package/specs/core-contract.md +323 -0
- package/specs/drizzle-compatibility.md +167 -0
- package/specs/postgresql-backend.md +291 -0
- package/specs/release-qualification.md +107 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Effect, Schema, SchemaAST } from "effect";
|
|
2
|
+
import { JobPayloadCodecError, jobPayloadFormatVersion, maximumJobPayloadBytes, maximumJobSemanticProjectionBytes } from "./JobContract.js";
|
|
3
|
+
import { bytesEqual, canonicalBytes, checkDecodedContainers } from "./internal/codec/CanonicalJson.js";
|
|
4
|
+
import { prepareProjection, project } from "./internal/codec/ProtectedProjection.js";
|
|
5
|
+
const strict = { onExcessProperty: "error" };
|
|
6
|
+
/**
|
|
7
|
+
* Encodes the validated wire representation, not the decoded domain object.
|
|
8
|
+
* Structs, arrays, absent optional keys and unions are supported. Domain
|
|
9
|
+
* transforms must have a JSON encoded side; transforms across protected markers,
|
|
10
|
+
* recursive/custom shapes, records and tuples fail with invalid-schema.
|
|
11
|
+
* Each returned buffer is owned independently by this execution. Receivers must
|
|
12
|
+
* copy buffers before retaining them; readonly properties do not freeze bytes.
|
|
13
|
+
*/
|
|
14
|
+
export const encodeJobPayload = Effect.fnUntraced(function* (schema, payload) {
|
|
15
|
+
const ast = yield* prepareProjection(schema);
|
|
16
|
+
yield* checkDecodedContainers(payload);
|
|
17
|
+
// Check own marker fields before Schema can rebuild inherited properties.
|
|
18
|
+
yield* project(SchemaAST.toType(schema.ast), payload);
|
|
19
|
+
const value = yield* Schema.encodeEffect(schema, strict)(payload).pipe(Effect.mapError(() => new JobPayloadCodecError({ reason: "invalid-schema" })));
|
|
20
|
+
const payloadBytes = yield* canonicalBytes(value, maximumJobPayloadBytes, "payload-too-large");
|
|
21
|
+
yield* Schema.decodeUnknownEffect(Schema.make(ast), strict)(value).pipe(Effect.mapError(() => new JobPayloadCodecError({ reason: "invalid-schema" })));
|
|
22
|
+
const projection = yield* project(ast, value);
|
|
23
|
+
const semanticProjectionBytes = yield* canonicalBytes(projection, maximumJobSemanticProjectionBytes, "projection-too-large",
|
|
24
|
+
// The representation envelope is not an application-data depth level.
|
|
25
|
+
-1);
|
|
26
|
+
return { formatVersion: jobPayloadFormatVersion, payloadBytes, semanticProjectionBytes };
|
|
27
|
+
});
|
|
28
|
+
const readArtifact = (encoded) => Effect.try({
|
|
29
|
+
try: () => {
|
|
30
|
+
if (encoded.formatVersion !== jobPayloadFormatVersion ||
|
|
31
|
+
!(encoded.payloadBytes instanceof Uint8Array) ||
|
|
32
|
+
!(encoded.semanticProjectionBytes instanceof Uint8Array)) {
|
|
33
|
+
throw new JobPayloadCodecError({ reason: "invalid-encoding" });
|
|
34
|
+
}
|
|
35
|
+
if (encoded.payloadBytes.byteLength > maximumJobPayloadBytes) {
|
|
36
|
+
throw new JobPayloadCodecError({ reason: "payload-too-large" });
|
|
37
|
+
}
|
|
38
|
+
if (encoded.semanticProjectionBytes.byteLength > maximumJobSemanticProjectionBytes) {
|
|
39
|
+
throw new JobPayloadCodecError({ reason: "projection-too-large" });
|
|
40
|
+
}
|
|
41
|
+
// Snapshot before any application service can yield or mutate retained input.
|
|
42
|
+
return {
|
|
43
|
+
payloadBytes: new Uint8Array(encoded.payloadBytes),
|
|
44
|
+
semanticProjectionBytes: new Uint8Array(encoded.semanticProjectionBytes)
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
catch: (error) => error instanceof JobPayloadCodecError
|
|
48
|
+
? error
|
|
49
|
+
: new JobPayloadCodecError({ reason: "invalid-encoding" })
|
|
50
|
+
});
|
|
51
|
+
const parse = (bytes) => Effect.try({
|
|
52
|
+
try: () => JSON.parse(new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes)),
|
|
53
|
+
catch: () => new JobPayloadCodecError({ reason: "invalid-encoding" })
|
|
54
|
+
});
|
|
55
|
+
/** Validates canonical format, bounds, schema and semantic projection before
|
|
56
|
+
* invoking domain decoding. Consistent projection bytes are not authenticity. */
|
|
57
|
+
export const decodeJobPayload = Effect.fnUntraced(function* (schema, encoded) {
|
|
58
|
+
const snapshot = yield* readArtifact(encoded);
|
|
59
|
+
const ast = yield* prepareProjection(schema);
|
|
60
|
+
const value = yield* parse(snapshot.payloadBytes);
|
|
61
|
+
const payloadBytes = yield* canonicalBytes(value, maximumJobPayloadBytes, "payload-too-large");
|
|
62
|
+
const suppliedProjection = yield* parse(snapshot.semanticProjectionBytes);
|
|
63
|
+
const suppliedBytes = yield* canonicalBytes(suppliedProjection, maximumJobSemanticProjectionBytes, "projection-too-large", -1);
|
|
64
|
+
if (!bytesEqual(payloadBytes, snapshot.payloadBytes) ||
|
|
65
|
+
!bytesEqual(suppliedBytes, snapshot.semanticProjectionBytes)) {
|
|
66
|
+
return yield* new JobPayloadCodecError({ reason: "invalid-encoding" });
|
|
67
|
+
}
|
|
68
|
+
yield* Schema.decodeUnknownEffect(Schema.make(ast), strict)(value).pipe(Effect.mapError(() => new JobPayloadCodecError({ reason: "invalid-schema" })));
|
|
69
|
+
const projection = yield* project(ast, value);
|
|
70
|
+
const projectionBytes = yield* canonicalBytes(projection, maximumJobSemanticProjectionBytes, "projection-too-large", -1);
|
|
71
|
+
if (!bytesEqual(projectionBytes, snapshot.semanticProjectionBytes)) {
|
|
72
|
+
return yield* new JobPayloadCodecError({ reason: "projection-mismatch" });
|
|
73
|
+
}
|
|
74
|
+
const decoded = yield* Schema.decodeUnknownEffect(schema, strict)(value).pipe(Effect.mapError(() => new JobPayloadCodecError({ reason: "invalid-schema" })));
|
|
75
|
+
yield* checkDecodedContainers(decoded);
|
|
76
|
+
return decoded;
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=JobPayloadCodec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobPayloadCodec.js","sourceRoot":"","sources":["../src/JobPayloadCodec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Duration, Schema } from "effect";
|
|
2
|
+
export declare const maximumMillis = 253402300799999;
|
|
3
|
+
export declare const PositiveMillis: Schema.Int;
|
|
4
|
+
/** Preserve the source's positive, bounded epoch-millisecond boundary. */
|
|
5
|
+
export declare const EpochMillis: Schema.Int;
|
|
6
|
+
export declare const JobRetention: Schema.Union<readonly [Schema.TaggedStruct<"Forever", {}>, Schema.TaggedStruct<"Duration", {
|
|
7
|
+
readonly millis: Schema.Int;
|
|
8
|
+
}>]>;
|
|
9
|
+
export type JobRetention = typeof JobRetention.Type;
|
|
10
|
+
export declare const FixedDelayV1: Schema.TaggedStruct<"FixedDelayV1", {
|
|
11
|
+
readonly delayMillis: Schema.Int;
|
|
12
|
+
}>;
|
|
13
|
+
/** Complete version-1 durable representation; never resolve defaults while decoding storage. */
|
|
14
|
+
export declare const PersistedJobPolicy: Schema.Struct<{
|
|
15
|
+
readonly leaseDurationMillis: Schema.Int;
|
|
16
|
+
readonly attemptTimeoutMillis: Schema.Int;
|
|
17
|
+
readonly maxAttempts: Schema.Int;
|
|
18
|
+
readonly maxStalledCount: Schema.Int;
|
|
19
|
+
readonly retrySchedule: Schema.TaggedStruct<"FixedDelayV1", {
|
|
20
|
+
readonly delayMillis: Schema.Int;
|
|
21
|
+
}>;
|
|
22
|
+
readonly completedRetention: Schema.Union<readonly [Schema.TaggedStruct<"Forever", {}>, Schema.TaggedStruct<"Duration", {
|
|
23
|
+
readonly millis: Schema.Int;
|
|
24
|
+
}>]>;
|
|
25
|
+
readonly deadRetention: Schema.Union<readonly [Schema.TaggedStruct<"Forever", {}>, Schema.TaggedStruct<"Duration", {
|
|
26
|
+
readonly millis: Schema.Int;
|
|
27
|
+
}>]>;
|
|
28
|
+
}>;
|
|
29
|
+
export type JobPolicy = typeof PersistedJobPolicy.Type;
|
|
30
|
+
export interface JobPolicyOptions {
|
|
31
|
+
readonly leaseDuration?: Duration.Duration;
|
|
32
|
+
readonly attemptTimeout?: Duration.Duration;
|
|
33
|
+
readonly retryDelay?: Duration.Duration;
|
|
34
|
+
readonly maxAttempts?: number;
|
|
35
|
+
readonly maxStalledCount?: number;
|
|
36
|
+
readonly completedRetention?: Duration.Duration;
|
|
37
|
+
readonly deadRetention?: Duration.Duration;
|
|
38
|
+
}
|
|
39
|
+
declare const JobPolicyConfigurationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
40
|
+
readonly _tag: "JobPolicyConfigurationError";
|
|
41
|
+
} & Readonly<A>;
|
|
42
|
+
export declare class JobPolicyConfigurationError extends JobPolicyConfigurationError_base<{
|
|
43
|
+
readonly field: keyof JobPolicyOptions;
|
|
44
|
+
readonly expected: string;
|
|
45
|
+
}> {
|
|
46
|
+
}
|
|
47
|
+
/** Synchronous immutable configuration, like job and producer declarations. */
|
|
48
|
+
export declare const make: (options?: JobPolicyOptions) => JobPolicy;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=JobPolicy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobPolicy.d.ts","sourceRoot":"","sources":["../src/JobPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/C,eAAO,MAAM,aAAa,kBAAsB,CAAA;AAChD,eAAO,MAAM,cAAc,YAE1B,CAAA;AACD,0EAA0E;AAC1E,eAAO,MAAM,WAAW,YAAiB,CAAA;AAEzC,eAAO,MAAM,YAAY;;IAGvB,CAAA;AACF,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAEnD,eAAO,MAAM,YAAY;;EAEvB,CAAA;AAcF,gGAAgG;AAChG,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;EAE9B,CAAA;AACD,MAAM,MAAM,SAAS,GAAG,OAAO,kBAAkB,CAAC,IAAI,CAAA;AAEtD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;IAC1C,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;IACvC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;IAC/C,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;CAC3C;;;;AAED,qBAAa,2BAA4B,SAAQ,iCAE/C;IACA,QAAQ,CAAC,KAAK,EAAE,MAAM,gBAAgB,CAAA;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B,CAAC;CAAG;AAgCL,+EAA+E;AAC/E,eAAO,MAAM,IAAI,aAAa,gBAAgB,KAAQ,SA4CrD,CAAA"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Data, Duration, Schema } from "effect";
|
|
2
|
+
export const maximumMillis = 253_402_300_799_999;
|
|
3
|
+
export const PositiveMillis = Schema.Int.pipe(Schema.check(Schema.isBetween({ minimum: 1, maximum: maximumMillis })));
|
|
4
|
+
/** Preserve the source's positive, bounded epoch-millisecond boundary. */
|
|
5
|
+
export const EpochMillis = PositiveMillis;
|
|
6
|
+
export const JobRetention = Schema.Union([
|
|
7
|
+
Schema.TaggedStruct("Forever", {}),
|
|
8
|
+
Schema.TaggedStruct("Duration", { millis: PositiveMillis })
|
|
9
|
+
]);
|
|
10
|
+
export const FixedDelayV1 = Schema.TaggedStruct("FixedDelayV1", {
|
|
11
|
+
delayMillis: PositiveMillis
|
|
12
|
+
});
|
|
13
|
+
const PolicyStruct = Schema.Struct({
|
|
14
|
+
leaseDurationMillis: PositiveMillis,
|
|
15
|
+
attemptTimeoutMillis: PositiveMillis,
|
|
16
|
+
maxAttempts: Schema.Int.pipe(Schema.check(Schema.isBetween({ minimum: 1, maximum: 100 }))),
|
|
17
|
+
maxStalledCount: Schema.Int.pipe(Schema.check(Schema.isBetween({ minimum: 0, maximum: 100 }))),
|
|
18
|
+
retrySchedule: FixedDelayV1,
|
|
19
|
+
completedRetention: JobRetention,
|
|
20
|
+
deadRetention: JobRetention
|
|
21
|
+
});
|
|
22
|
+
/** Complete version-1 durable representation; never resolve defaults while decoding storage. */
|
|
23
|
+
export const PersistedJobPolicy = PolicyStruct.pipe(Schema.check(Schema.makeFilter((p) => p.attemptTimeoutMillis < p.leaseDurationMillis)));
|
|
24
|
+
export class JobPolicyConfigurationError extends Data.TaggedError("JobPolicyConfigurationError") {
|
|
25
|
+
}
|
|
26
|
+
const millis = (value, field) => {
|
|
27
|
+
const n = Duration.match(value, {
|
|
28
|
+
onMillis: (n) => n,
|
|
29
|
+
onNanos: (nanos) => nanos % 1000000n === 0n &&
|
|
30
|
+
nanos > 0n &&
|
|
31
|
+
nanos <= BigInt(maximumMillis) * 1000000n
|
|
32
|
+
? Number(nanos / 1000000n)
|
|
33
|
+
: NaN,
|
|
34
|
+
onInfinity: () => Infinity,
|
|
35
|
+
onNegativeInfinity: () => -Infinity
|
|
36
|
+
});
|
|
37
|
+
if (!Schema.is(PositiveMillis)(n)) {
|
|
38
|
+
throw new JobPolicyConfigurationError({
|
|
39
|
+
field,
|
|
40
|
+
expected: `finite integer milliseconds in 1–${maximumMillis}`
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return n;
|
|
44
|
+
};
|
|
45
|
+
const retention = (value, field) => Object.freeze(!Duration.isFinite(value) && Duration.toMillis(value) === Infinity
|
|
46
|
+
? { _tag: "Forever" }
|
|
47
|
+
: { _tag: "Duration", millis: millis(value, field) });
|
|
48
|
+
/** Synchronous immutable configuration, like job and producer declarations. */
|
|
49
|
+
export const make = (options = {}) => {
|
|
50
|
+
const leaseDurationMillis = millis(options.leaseDuration ?? Duration.seconds(90), "leaseDuration");
|
|
51
|
+
const attemptTimeoutMillis = millis(options.attemptTimeout ?? Duration.seconds(30), "attemptTimeout");
|
|
52
|
+
if (attemptTimeoutMillis >= leaseDurationMillis) {
|
|
53
|
+
throw new JobPolicyConfigurationError({
|
|
54
|
+
field: "attemptTimeout",
|
|
55
|
+
expected: "strictly less than leaseDuration"
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const maxAttempts = options.maxAttempts ?? 3;
|
|
59
|
+
const maxStalledCount = options.maxStalledCount ?? 1;
|
|
60
|
+
if (!Schema.is(PolicyStruct.fields.maxAttempts)(maxAttempts)) {
|
|
61
|
+
throw new JobPolicyConfigurationError({
|
|
62
|
+
field: "maxAttempts",
|
|
63
|
+
expected: "integer in 1–100"
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (!Schema.is(PolicyStruct.fields.maxStalledCount)(maxStalledCount)) {
|
|
67
|
+
throw new JobPolicyConfigurationError({
|
|
68
|
+
field: "maxStalledCount",
|
|
69
|
+
expected: "integer in 0–100"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return Object.freeze({
|
|
73
|
+
leaseDurationMillis,
|
|
74
|
+
attemptTimeoutMillis,
|
|
75
|
+
maxAttempts,
|
|
76
|
+
maxStalledCount,
|
|
77
|
+
retrySchedule: Object.freeze({
|
|
78
|
+
_tag: "FixedDelayV1",
|
|
79
|
+
delayMillis: millis(options.retryDelay ?? Duration.seconds(5), "retryDelay")
|
|
80
|
+
}),
|
|
81
|
+
completedRetention: retention(options.completedRetention ?? Duration.days(90), "completedRetention"),
|
|
82
|
+
deadRetention: retention(options.deadRetention ?? Duration.infinity, "deadRetention")
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=JobPolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobPolicy.js","sourceRoot":"","sources":["../src/JobPolicy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ProducerIdentity } from "./JobIdentity.js";
|
|
2
|
+
export interface JobProducer<Operation extends string, Slots extends ReadonlyArray<string>> {
|
|
3
|
+
readonly operation: Operation;
|
|
4
|
+
readonly slots: Readonly<Slots>;
|
|
5
|
+
readonly identity: <const Slot extends Slots[number]>(input: {
|
|
6
|
+
readonly operationId: string;
|
|
7
|
+
readonly slot: Slot;
|
|
8
|
+
}) => ProducerIdentity<Operation, Slot>;
|
|
9
|
+
}
|
|
10
|
+
export declare const make: <const Operation extends string, const Slots extends ReadonlyArray<string>>(options: {
|
|
11
|
+
readonly operation: Operation;
|
|
12
|
+
readonly slots: Slots;
|
|
13
|
+
}) => JobProducer<Operation, Slots>;
|
|
14
|
+
//# sourceMappingURL=JobProducer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobProducer.d.ts","sourceRoot":"","sources":["../src/JobProducer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAExD,MAAM,WAAW,WAAW,CAC1B,SAAS,SAAS,MAAM,EACxB,KAAK,SAAS,aAAa,CAAC,MAAM,CAAC;IAEnC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC/B,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,IAAI,SAAS,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE;QAC3D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;QAC5B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;KACpB,KAAK,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;CACxC;AAED,eAAO,MAAM,IAAI,GACf,KAAK,CAAC,SAAS,SAAS,MAAM,EAC9B,KAAK,CAAC,KAAK,SAAS,aAAa,CAAC,MAAM,CAAC,WAChC;IACT,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CACtB,KAAG,WAAW,CAAC,SAAS,EAAE,KAAK,CAuB/B,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { JobDeclarationError, validateOperationId, validateProducerDeclaration } from "./JobIdentity.js";
|
|
2
|
+
export const make = (options) => {
|
|
3
|
+
validateProducerDeclaration(options);
|
|
4
|
+
const operation = options.operation;
|
|
5
|
+
// The copy retains tuple positions without retaining the caller's mutable array.
|
|
6
|
+
const slots = Object.freeze([...options.slots]);
|
|
7
|
+
return Object.freeze({
|
|
8
|
+
operation,
|
|
9
|
+
slots,
|
|
10
|
+
identity: (input) => {
|
|
11
|
+
validateOperationId(input.operationId);
|
|
12
|
+
if (!slots.includes(input.slot)) {
|
|
13
|
+
throw new JobDeclarationError({ field: "slots", expected: "a declared slot" });
|
|
14
|
+
}
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
operation,
|
|
17
|
+
operationId: input.operationId,
|
|
18
|
+
slot: input.slot
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=JobProducer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobProducer.js","sourceRoot":"","sources":["../src/JobProducer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,2BAA2B,EAC5B,MAAM,kBAAkB,CAAA;AAezB,MAAM,CAAC,MAAM,IAAI,GAAG,CAGlB,OAGD,EAAiC,EAAE;IAClC,2BAA2B,CAAC,OAAO,CAAC,CAAA;IACpC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAA;IACnC,iFAAiF;IACjF,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAA+B,CAAA;IAC7E,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,SAAS;QACT,KAAK;QACL,QAAQ,EAAE,CAAmC,KAG5C,EAAqC,EAAE;YACtC,mBAAmB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;YACtC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,mBAAmB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC,CAAA;YAChF,CAAC;YACD,OAAO,MAAM,CAAC,MAAM,CAAC;gBACnB,SAAS;gBACT,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;aACjB,CAAC,CAAA;QACJ,CAAC;KACF,CAAC,CAAA;AACJ,CAAC,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare const JobQueueTypeId: unique symbol;
|
|
2
|
+
export interface JobQueue<Name extends string = string> {
|
|
3
|
+
readonly [JobQueueTypeId]: typeof JobQueueTypeId;
|
|
4
|
+
readonly name: Name;
|
|
5
|
+
}
|
|
6
|
+
declare const InvalidJobQueue_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
7
|
+
readonly _tag: "InvalidJobQueue";
|
|
8
|
+
} & Readonly<A>;
|
|
9
|
+
export declare class InvalidJobQueue extends InvalidJobQueue_base<{
|
|
10
|
+
readonly expected: string;
|
|
11
|
+
}> {
|
|
12
|
+
}
|
|
13
|
+
/** Logical configuration only; creates no storage or worker. */
|
|
14
|
+
export declare const make: <const Name extends string>(name: Name) => JobQueue<Name>;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=JobQueue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobQueue.d.ts","sourceRoot":"","sources":["../src/JobQueue.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,cAAc,EAAE,OAAO,MAAuC,CAAA;AAEpE,MAAM,WAAW,QAAQ,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACpD,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,OAAO,cAAc,CAAA;IAChD,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;CACpB;;;;AAED,qBAAa,eAAgB,SAAQ,qBAAoC;IACvE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B,CAAC;CAAG;AAEL,gEAAgE;AAChE,eAAO,MAAM,IAAI,GAAI,KAAK,CAAC,IAAI,SAAS,MAAM,QAAQ,IAAI,KAAG,QAAQ,CAAC,IAAI,CAQzE,CAAA"}
|
package/dist/JobQueue.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Data, Schema } from "effect";
|
|
2
|
+
import { QueueName } from "./JobIdentity.js";
|
|
3
|
+
const JobQueueTypeId = Symbol("effect-jobs/JobQueue");
|
|
4
|
+
export class InvalidJobQueue extends Data.TaggedError("InvalidJobQueue") {
|
|
5
|
+
}
|
|
6
|
+
/** Logical configuration only; creates no storage or worker. */
|
|
7
|
+
export const make = (name) => {
|
|
8
|
+
if (!Schema.is(QueueName)(name)) {
|
|
9
|
+
throw new InvalidJobQueue({
|
|
10
|
+
expected: "1–64 ASCII characters matching ^[a-z][a-z0-9.-]*$"
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
const queue = { [JobQueueTypeId]: JobQueueTypeId, name };
|
|
14
|
+
return Object.freeze(queue);
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=JobQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobQueue.js","sourceRoot":"","sources":["../src/JobQueue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAE5C,MAAM,cAAc,GAAkB,MAAM,CAAC,sBAAsB,CAAC,CAAA;AAOpE,MAAM,OAAO,eAAgB,SAAQ,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAErE;CAAG;AAEL,gEAAgE;AAChE,MAAM,CAAC,MAAM,IAAI,GAAG,CAA4B,IAAU,EAAkB,EAAE;IAC5E,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,eAAe,CAAC;YACxB,QAAQ,EAAE,mDAAmD;SAC9D,CAAC,CAAA;IACJ,CAAC;IACD,MAAM,KAAK,GAAmB,EAAE,CAAC,cAAc,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAA;IACxE,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC7B,CAAC,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import type { EncodedJobPayload, HandlerContext, JobPayloadCodecError } from "./JobContract.js";
|
|
3
|
+
import type { JobFailure } from "./JobFailure.js";
|
|
4
|
+
import type { CatalogIdentity } from "./JobIdentity.js";
|
|
5
|
+
export interface JobHandler {
|
|
6
|
+
readonly catalog: CatalogIdentity;
|
|
7
|
+
/** Decodes first; services were captured by the definition's handler Layer. */
|
|
8
|
+
readonly execute: (encoded: EncodedJobPayload, context: HandlerContext) => Effect.Effect<void, JobFailure | JobPayloadCodecError>;
|
|
9
|
+
}
|
|
10
|
+
declare const DuplicateJobHandler_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
11
|
+
readonly _tag: "DuplicateJobHandler";
|
|
12
|
+
} & Readonly<A>;
|
|
13
|
+
export declare class DuplicateJobHandler extends DuplicateJobHandler_base<CatalogIdentity> {
|
|
14
|
+
get message(): string;
|
|
15
|
+
}
|
|
16
|
+
declare const DuplicateJobCatalogEntry_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
17
|
+
readonly _tag: "DuplicateJobCatalogEntry";
|
|
18
|
+
} & Readonly<A>;
|
|
19
|
+
export declare class DuplicateJobCatalogEntry extends DuplicateJobCatalogEntry_base<CatalogIdentity> {
|
|
20
|
+
get message(): string;
|
|
21
|
+
}
|
|
22
|
+
export interface JobRegistryService {
|
|
23
|
+
readonly install: (handler: JobHandler) => Effect.Effect<void, DuplicateJobHandler>;
|
|
24
|
+
readonly find: (catalog: CatalogIdentity) => JobHandler | undefined;
|
|
25
|
+
}
|
|
26
|
+
declare const JobRegistry_base: Context.ServiceClass<JobRegistry, "effect-jobs/JobRegistry", JobRegistryService>;
|
|
27
|
+
export declare class JobRegistry extends JobRegistry_base {
|
|
28
|
+
}
|
|
29
|
+
/** Each Layer build owns its registry; imports and construction start no fibers. */
|
|
30
|
+
export declare const layer: Layer.Layer<JobRegistry, never, never>;
|
|
31
|
+
export interface CatalogEntry {
|
|
32
|
+
readonly catalog: CatalogIdentity;
|
|
33
|
+
}
|
|
34
|
+
/** Preserve definition types; validate duplicate identities without a global catalog. */
|
|
35
|
+
export declare const catalog: <const Entries extends ReadonlyArray<CatalogEntry>>(...entries: Entries) => Effect.Effect<Readonly<Entries>, DuplicateJobCatalogEntry>;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=JobRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobRegistry.d.ts","sourceRoot":"","sources":["../src/JobRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AACrD,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACrB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAEvD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;IACjC,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,CAChB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,cAAc,KACpB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,oBAAoB,CAAC,CAAA;CAC5D;;;;AAED,qBAAa,mBAAoB,SAAQ,yBAEvC,eAAe,CAAC;IAChB,IAAa,OAAO,IAAI,MAAM,CAE7B;CACF;;;;AAED,qBAAa,wBAAyB,SAAQ,8BAE5C,eAAe,CAAC;IAChB,IAAa,OAAO,IAAI,MAAM,CAE7B;CACF;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAA;IACnF,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,UAAU,GAAG,SAAS,CAAA;CACpE;;AAED,qBAAa,WAAY,SAAQ,gBAEhC;CAAG;AAKJ,oFAAoF;AACpF,eAAO,MAAM,KAAK,wCAmBhB,CAAA;AAEF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;CAClC;AAED,yFAAyF;AACzF,eAAO,MAAM,OAAO,GAAI,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,YAAY,CAAC,cAC3D,OAAO,KAClB,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,wBAAwB,CAWxD,CAAA"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Context, Data, Effect, Layer } from "effect";
|
|
2
|
+
export class DuplicateJobHandler extends Data.TaggedError("DuplicateJobHandler") {
|
|
3
|
+
get message() {
|
|
4
|
+
return `Handler already installed for ${this.queue}/${this.kind}@${this.version}; install one handler per catalog entry`;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export class DuplicateJobCatalogEntry extends Data.TaggedError("DuplicateJobCatalogEntry") {
|
|
8
|
+
get message() {
|
|
9
|
+
return `Duplicate catalog entry ${this.queue}/${this.kind}@${this.version}; use a unique queue/kind/version`;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export class JobRegistry extends Context.Service()("effect-jobs/JobRegistry") {
|
|
13
|
+
}
|
|
14
|
+
const key = (catalog) => `${catalog.queue}\u0000${catalog.kind}\u0000${catalog.version}`;
|
|
15
|
+
/** Each Layer build owns its registry; imports and construction start no fibers. */
|
|
16
|
+
export const layer = Layer.sync(JobRegistry, () => {
|
|
17
|
+
const handlers = new Map();
|
|
18
|
+
return JobRegistry.of({
|
|
19
|
+
install: (handler) => Effect.suspend(() => {
|
|
20
|
+
const catalogKey = key(handler.catalog);
|
|
21
|
+
if (handlers.has(catalogKey)) {
|
|
22
|
+
return Effect.fail(new DuplicateJobHandler(handler.catalog));
|
|
23
|
+
}
|
|
24
|
+
const catalog = Object.freeze({
|
|
25
|
+
queue: handler.catalog.queue,
|
|
26
|
+
kind: handler.catalog.kind,
|
|
27
|
+
version: handler.catalog.version
|
|
28
|
+
});
|
|
29
|
+
handlers.set(catalogKey, Object.freeze({ catalog, execute: handler.execute }));
|
|
30
|
+
return Effect.void;
|
|
31
|
+
}),
|
|
32
|
+
find: (catalog) => handlers.get(key(catalog))
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
/** Preserve definition types; validate duplicate identities without a global catalog. */
|
|
36
|
+
export const catalog = (...entries) => Effect.suspend(() => {
|
|
37
|
+
const seen = new Set();
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
const catalogKey = key(entry.catalog);
|
|
40
|
+
if (seen.has(catalogKey)) {
|
|
41
|
+
return Effect.fail(new DuplicateJobCatalogEntry(entry.catalog));
|
|
42
|
+
}
|
|
43
|
+
seen.add(catalogKey);
|
|
44
|
+
}
|
|
45
|
+
return Effect.succeed(Object.freeze([...entries]));
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=JobRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobRegistry.js","sourceRoot":"","sources":["../src/JobRegistry.ts"],"names":[],"mappings":"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"}
|