@systemfsoftware/stryker-js 15.0.0 → 15.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @systemfsoftware/stryker-js
2
2
 
3
+ ## 15.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - `cleanTempDir` now decides from how the run ended. With the default (`true`), a successful run removes its `.stryker-tmp/sandbox-*` directory and a failed run keeps it; previously every sandbox was kept, so `.stryker-tmp` grew with each run. `cleanTempDir: false` now keeps the sandbox after every run instead of deleting it. `'always'` still removes it after every run.
8
+
9
+ - A test runner, checker, or reporter process that stops responding no longer hangs the mutation run forever. When such a process does not exit within 5 seconds of being asked to stop, Stryker force-kills it, so the run ends with an error instead of waiting until something kills it from outside.
10
+
11
+ - A test runner, checker, or reporter process that starts but never accepts its connection no longer hangs the mutation run forever. Stryker gives each plugin worker 30 seconds to accept the connection on `STRYKER_SOCKET`; a worker that misses that window fails the run with a boot error naming its process id, and the process is stopped. The window does not depend on `dryRunTimeoutMinutes`. A worker that has already connected still reconnects after a dropped connection, as before.
12
+
3
13
  ## 15.0.0
4
14
 
5
15
  ### Major Changes
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
2
  import { i as Mutant_exports, l as Report_exports, n as mergeConfigs } from "./merge-config-zsGl1aWc.mjs";
3
- import { $ as WorkerLauncher, A as classifyWorkerExit, At as OutOfMemoryError, B as SurvivorRef, C as nodePlatformLayer, Ct as MergeResult, D as git_diff_schema_exports, Dt as survivorsPriorReport, E as git_diff_service_exports, Et as forkOptionsSchema, F as readConfig, Ft as CheckerAnsweredUnrequested, G as generateRunId, H as RunEvents, I as RunEnvironment, It as CheckerSkippedRequested, J as metricsResultFromFiles, K as VerdictEnvelope, L as IdGenerator, M as loadConfigCell, Mt as OutputMode_exports, N as describeErrors, Nt as RunEvent_exports$1, O as ClassifyWorkerExitCommand, Ot as checkGroupedPlans, P as forkCoreSchema, Pt as SpanTaxonomy_exports, Q as makeWorkerClient, R as surfacedSurvivorsOf, S as IncrementalReportSchema, St as MergeCommand, T as GitDiff, Tt as extendsPropertySchema, U as RunIdentity, V as StrykerPackage, W as buildVerdictEnvelope, X as reporterWorkerFactory, Y as MetricsResultFromReport, Z as spawnReporterWorker, _ as isCommandRunner, _t as defaultOptions, a as MachineConsole, at as initialExtendsStepState, b as readProjectCell, bt as ExtendsStepStateSchema, c as prepareCell, ct as ExtendsStepRead, d as buildTestRunner, dt as ConfigError, et as make, f as makeChildProcessTestRunner, ft as ConfigFileInvalidError, g as vmTestRunnerConfig, gt as createDefaultOptions, h as vmRunnerPluginUrl, ht as ConfigFileUnsupportedError, i as makeRunEventStream, it as importModule, j as validateOptions, jt as WorkerBootTimeoutError, k as ClassifyWorkerExitDecision, kt as ChildProcessCrashedError, l as mutantDetailEventsOf, lt as ExtendsStepRefused, m as testRunnerConfigOf, mt as ConfigFileUnreadableError, n as RunEventDrain, nt as FileMatcher, o as HtmlReporter_exports, ot as StrykerError, p as isVmRunner, pt as ConfigFileNotFoundError, q as staticVerdictOf, r as RunEventDrainLive, rt as decideExtendsStep, s as mutationTestCell, st as ExtendsStepDone, t as strykerCell, tt as ReproducerSchema, u as instrumentCell, ut as ExtendsStepResolve, v as import_closure_cell_exports, vt as ConfigDocumentSchema, w as layerWorkerProtocol, wt as ReadConfigCommand, x as concurrencyCell, xt as ImportedModuleSchema, y as relativeNormalizedFileName, yt as ExtendsStepDocumentSchema, z as SurfacingFields } from "./run-stages-aBT_QAfO.mjs";
3
+ import { $ as WorkerLauncher, A as classifyWorkerExit, At as OutOfMemoryError, B as SurvivorRef, C as nodePlatformLayer, Ct as MergeResult, D as git_diff_schema_exports, Dt as survivorsPriorReport, E as git_diff_service_exports, Et as forkOptionsSchema, F as readConfig, Ft as CheckerAnsweredUnrequested, G as generateRunId, H as RunEvents, I as RunEnvironment, It as CheckerSkippedRequested, J as metricsResultFromFiles, K as VerdictEnvelope, L as IdGenerator, M as loadConfigCell, Mt as OutputMode_exports, N as describeErrors, Nt as RunEvent_exports$1, O as ClassifyWorkerExitCommand, Ot as checkGroupedPlans, P as forkCoreSchema, Pt as SpanTaxonomy_exports, Q as makeWorkerClient, R as surfacedSurvivorsOf, S as IncrementalReportSchema, St as MergeCommand, T as GitDiff, Tt as extendsPropertySchema, U as RunIdentity, V as StrykerPackage, W as buildVerdictEnvelope, X as reporterWorkerFactory, Y as MetricsResultFromReport, Z as spawnReporterWorker, _ as isCommandRunner, _t as defaultOptions, a as MachineConsole, at as initialExtendsStepState, b as readProjectCell, bt as ExtendsStepStateSchema, c as prepareCell, ct as ExtendsStepRead, d as buildTestRunner, dt as ConfigError, et as make, f as makeChildProcessTestRunner, ft as ConfigFileInvalidError, g as vmTestRunnerConfig, gt as createDefaultOptions, h as vmRunnerPluginUrl, ht as ConfigFileUnsupportedError, i as makeRunEventStream, it as importModule, j as validateOptions, jt as WorkerBootTimeoutError, k as ClassifyWorkerExitDecision, kt as ChildProcessCrashedError, l as mutantDetailEventsOf, lt as ExtendsStepRefused, m as testRunnerConfigOf, mt as ConfigFileUnreadableError, n as RunEventDrain, nt as FileMatcher, o as HtmlReporter_exports, ot as StrykerError, p as isVmRunner, pt as ConfigFileNotFoundError, q as staticVerdictOf, r as RunEventDrainLive, rt as decideExtendsStep, s as mutationTestCell, st as ExtendsStepDone, t as strykerCell, tt as ReproducerSchema, u as instrumentCell, ut as ExtendsStepResolve, v as import_closure_cell_exports, vt as ConfigDocumentSchema, w as layerWorkerProtocol, wt as ReadConfigCommand, x as concurrencyCell, xt as ImportedModuleSchema, y as relativeNormalizedFileName, yt as ExtendsStepDocumentSchema, z as SurfacingFields } from "./run-stages-DdVQINP9.mjs";
4
4
  import { n as StageError } from "./Run.schema-DuaneDGd.mjs";
5
5
  import { Cell, Sandwich, Workflow } from "@systemfsoftware/effect-cell-types";
6
6
  import * as S from "effect/Schema";
package/dist/main.mjs CHANGED
@@ -12180,7 +12180,7 @@ const min$4 = (O) => dual(2, (self, that) => self === that || O(self, that) < 1
12180
12180
  * @category comparisons
12181
12181
  * @since 2.0.0
12182
12182
  */
12183
- const max$4 = (O) => dual(2, (self, that) => self === that || O(self, that) > -1 ? self : that);
12183
+ const max$2 = (O) => dual(2, (self, that) => self === that || O(self, that) > -1 ? self : that);
12184
12184
  //#endregion
12185
12185
  //#region ../../node_modules/.pnpm/effect@4.0.0/node_modules/effect/dist/Option.js
12186
12186
  /**
@@ -14270,21 +14270,6 @@ const Equivalence$2 = (self, that) => matchPair(self, that, {
14270
14270
  */
14271
14271
  const min$3 = /*#__PURE__*/ min$4(Order$3);
14272
14272
  /**
14273
- * Returns the larger of two Durations.
14274
- *
14275
- * **Example** (Selecting the longer duration)
14276
- *
14277
- * ```ts import.meta.vitest
14278
- * import { Duration } from "effect"
14279
- *
14280
- * Duration.max(Duration.seconds(5), Duration.seconds(3)) // => Duration.seconds(5)
14281
- * ```
14282
- *
14283
- * @category ordering
14284
- * @since 2.0.0
14285
- */
14286
- const max$3 = /*#__PURE__*/ max$4(Order$3);
14287
- /**
14288
14273
  * Checks whether two Durations are equal.
14289
14274
  *
14290
14275
  * **Example** (Checking duration equality)
@@ -23363,7 +23348,7 @@ const min$2 = /*#__PURE__*/ min$4(Order$2);
23363
23348
  * @category math
23364
23349
  * @since 2.0.0
23365
23350
  */
23366
- const max$2 = /*#__PURE__*/ max$4(Order$2);
23351
+ const max$1 = /*#__PURE__*/ max$2(Order$2);
23367
23352
  /**
23368
23353
  * Returns the next power of 2 from the given number.
23369
23354
  *
@@ -23801,44 +23786,6 @@ const toStepWithMetadata = (schedule) => clockWith$2((clock) => map$9(toStep(sch
23801
23786
  });
23802
23787
  }));
23803
23788
  /**
23804
- * Combines schedules by recurring while all schedules want to recur, using the
23805
- * maximum delay between recurrences and outputting that maximum delay.
23806
- *
23807
- * **When to use**
23808
- *
23809
- * Use when a combined policy should continue only while every schedule still
23810
- * recurs, and should wait for the slowest schedule between recurrences.
23811
- *
23812
- * **Example** (Combining retry schedules by their maximum delay)
23813
- *
23814
- * ```ts import.meta.vitest
23815
- * import { Schedule } from "effect"
23816
- *
23817
- * const schedule = Schedule.max([Schedule.fixed("5 seconds"), Schedule.spaced("10 seconds")])
23818
- * Schedule.isSchedule(schedule) // => true
23819
- * ```
23820
- *
23821
- * @category combining
23822
- * @since 4.0.0
23823
- */
23824
- const max$1 = (schedules) => fromStep(map$9(all$2(schedules.map(toStep)), (steps) => (now, input) => flatMap$6(forEach$2(steps, (step) => matchEffect$1(step(now, input), {
23825
- onSuccess: (result) => succeed$9(result[1]),
23826
- onDone: () => undefined_$2,
23827
- onFailure: failCause$6
23828
- })), (results) => {
23829
- const duration = maxDuration(results);
23830
- if (duration === void 0) return done(zero$1);
23831
- return succeed$9([duration, duration]);
23832
- })));
23833
- const maxDuration = (results) => {
23834
- let max = results[0];
23835
- for (let i = 1; i < results.length; i++) {
23836
- max = results[i] && max && max$3(max, results[i]);
23837
- if (max === void 0) break;
23838
- }
23839
- return max;
23840
- };
23841
- /**
23842
23789
  * Combines schedules by recurring while at least one schedule wants to recur,
23843
23790
  * using the minimum delay between recurrences and outputting that minimum delay.
23844
23791
  *
@@ -23933,41 +23880,6 @@ const passthrough$2 = (self) => fromStep(map$9(toStep(self), (step) => (now, inp
23933
23880
  onDone: () => done(input)
23934
23881
  })));
23935
23882
  /**
23936
- * Returns a `Schedule` which can only be stepped the specified number of
23937
- * `times` before it terminates.
23938
- *
23939
- * **When to use**
23940
- *
23941
- * Use when you need a counter schedule with no additional delay.
23942
- *
23943
- * **Gotchas**
23944
- *
23945
- * `recurs(n)` counts schedule recurrences, not the first evaluation of the
23946
- * effect being repeated or retried. For retrying, this means one initial
23947
- * attempt plus at most `n` retries.
23948
- *
23949
- * **Example** (Limiting recurrences)
23950
- *
23951
- * ```ts import.meta.vitest
23952
- * import { Effect, Schedule } from "effect"
23953
- * import { TestClock } from "effect/testing"
23954
- *
23955
- * const executions: Array<number> = []
23956
- * const program = Effect.sync(() => executions.push(executions.length + 1)).pipe(
23957
- * Effect.repeat(Schedule.recurs(3)),
23958
- * Effect.as(executions)
23959
- * )
23960
- *
23961
- * await Effect.runPromise(Effect.provide(program, TestClock.layer())) // => [1, 2, 3, 4]
23962
- * ```
23963
- *
23964
- * @see {@link upTo} for limiting an existing schedule
23965
- *
23966
- * @category constructors
23967
- * @since 2.0.0
23968
- */
23969
- const recurs = (times) => while_(forever$1, ({ attempt }) => succeed$9(attempt <= times));
23970
- /**
23971
23883
  * Returns a schedule that recurs continuously, each repetition spaced the
23972
23884
  * specified duration from the last run.
23973
23885
  *
@@ -64434,7 +64346,7 @@ const Position$1 = Struct({
64434
64346
  const positionOrder$1 = combine$2(mapInput$2(Number$7, (position) => position.line), mapInput$2(Number$7, (position) => position.column));
64435
64347
  const inOrder = (order) => (ends) => ({
64436
64348
  start: min$4(order)(ends.start, ends.end),
64437
- end: max$4(order)(ends.start, ends.end)
64349
+ end: max$2(order)(ends.start, ends.end)
64438
64350
  });
64439
64351
  const notReversed = (order) => (ends) => isLessThanOrEqualTo$1(order)(ends.start, ends.end);
64440
64352
  const PositionEndsSchema = Struct({
@@ -76626,7 +76538,7 @@ const makeHtmlReporter = dual(2, (options, _init) => (events) => build(nodeFsPat
76626
76538
  var HtmlReporter_exports = /* @__PURE__ */ __exportAll$3({ makeHtmlReporter: () => makeHtmlReporter });
76627
76539
  //#endregion
76628
76540
  //#region package.json
76629
- var version = "15.0.0";
76541
+ var version = "15.0.1";
76630
76542
  //#endregion
76631
76543
  //#region ../../node_modules/.pnpm/effect@4.0.0/node_modules/effect/dist/cli/CliOutput.js
76632
76544
  /**
@@ -88002,7 +87914,7 @@ var WorkerLauncher = class extends Service$1()("@systemfsoftware/stryker-js/Work
88002
87914
  //#endregion
88003
87915
  //#region src/worker-client.blueprint.ts
88004
87916
  const TypeId$16 = Symbol.for("~systemfsoftware/stryker-js/WorkerClient");
88005
- const connectRetry = max$1([spaced(50), recurs(100)]);
87917
+ const WORKER_BOOT_TIMEOUT = seconds(30);
88006
87918
  const WorkerClients = () => Blueprint_exports.make()(TypeId$16).steps({
88007
87919
  steps: {},
88008
87920
  targets: { scoped: fnUntraced(function* (params) {
@@ -88016,7 +87928,11 @@ const WorkerClients = () => Blueprint_exports.make()(TypeId$16).steps({
88016
87928
  tempDirPrefix: params.tempDirPrefix,
88017
87929
  env: params.env
88018
87930
  });
88019
- const protocol = yield* worker.pipe(clientLayer, build, retry(connectRetry), raceFirst(worker.exited), catchTag("SocketError", () => fail$4(WorkerBootTimeoutError.make({ pid: worker.pid }))));
87931
+ const bootTimedOut = () => fail$4(WorkerBootTimeoutError.make({ pid: worker.pid }));
87932
+ const protocol = yield* worker.pipe(clientLayer, build, raceFirst(worker.exited), timeoutOrElse({
87933
+ duration: WORKER_BOOT_TIMEOUT,
87934
+ orElse: bootTimedOut
87935
+ }), catchTag("SocketError", bootTimedOut));
88020
87936
  const traceContext = yield* build(Trace_exports.layerTraceContextClient);
88021
87937
  return yield* make$17(params.rpcs).pipe(provideContext$3(merge$4(protocol, traceContext)));
88022
87938
  }) }
@@ -89153,7 +89069,7 @@ const charWidth = (char) => value(char).pipe(when((candidate) => KNOWN_EMOJI[can
89153
89069
  const stringWidth = (text) => reduce$2(Array.from(text), 0, (width, char) => width + charWidth(char));
89154
89070
  const spanWidth = (span) => span.leftPad + span.rightPad + stringWidth(span.text) * span.repeat;
89155
89071
  const lineWidth = (line) => reduce$2(line, 0, (width, span) => width + spanWidth(span));
89156
- const widest = (values) => reduce$2(values, 0, (present, candidate) => max$2(present, candidate));
89072
+ const widest = (values) => reduce$2(values, 0, (present, candidate) => max$1(present, candidate));
89157
89073
  const isFirstColumn = (style) => style !== "inner";
89158
89074
  const paddingWidth = (style) => match$1(isFirstColumn(style), {
89159
89075
  onTrue: () => 1,
@@ -89161,12 +89077,12 @@ const paddingWidth = (style) => match$1(isFirstColumn(style), {
89161
89077
  });
89162
89078
  const padsOf = (style, contentWidth, netWidth) => value(style).pipe(when("file", () => ({
89163
89079
  leftPad: 0,
89164
- rightPad: max$2(netWidth + 1 - contentWidth, 0)
89080
+ rightPad: max$1(netWidth + 1 - contentWidth, 0)
89165
89081
  })), when("first", () => ({
89166
- leftPad: max$2(netWidth - contentWidth, 0),
89082
+ leftPad: max$1(netWidth - contentWidth, 0),
89167
89083
  rightPad: 1
89168
89084
  })), orElse$1(() => ({
89169
- leftPad: max$2(netWidth - contentWidth, 0) + 1,
89085
+ leftPad: max$1(netWidth - contentWidth, 0) + 1,
89170
89086
  rightPad: 1
89171
89087
  })));
89172
89088
  const slotWidthOf = (column) => column.netWidth + paddingWidth(column.style);
@@ -90397,7 +90313,7 @@ const stageLayerOf = (env, events) => {
90397
90313
  const eventsLayer = value(events).pipe(when(void 0, () => effect(RunEvents, bounded(RunEvent_exports.RunEvent.QUEUE_BOUND))), orElse$1((queue) => succeed$6(RunEvents, queue)));
90398
90314
  const stageLayer = mergeAll$1(succeed$6(RunEnvironment, env), eventsLayer, PhaseClock.layer(env.runStartedAt), IdGenerator.layer, ProjectFiles.layer, effect(Scope, gen(function* () {
90399
90315
  const stageScope = yield* make$66();
90400
- yield* addFinalizer(() => close(stageScope, void_$2));
90316
+ yield* addFinalizer((exit) => close(stageScope, exit));
90401
90317
  return stageScope;
90402
90318
  })));
90403
90319
  return mergeAll$1(stageLayer, MutationReporting.layer.pipe(provide$2(stageLayer)), Reporter.layer.pipe(provide$2(ReporterOutput.layer), provide$2(stageLayer)));
@@ -96047,11 +95963,13 @@ const failInFlightRequests = fn(SpanTaxonomy_exports.Spans.workerProtocolFailInF
96047
95963
  const makeWorkerProtocol = fn(SpanTaxonomy_exports.Spans.workerProtocolMake.name)(function* (socket) {
96048
95964
  const responseHandlers = yield* make$35(empty$9());
96049
95965
  const liveConnections = yield* make$37();
95966
+ const connected = yield* make$67();
96050
95967
  const hooks = succeed$6(ConnectionHooks, {
96051
- onConnect: run$2(liveConnections, never$1.pipe(onInterrupt(() => failInFlightRequests(responseHandlers)))).pipe(asVoid),
95968
+ onConnect: succeed$7(connected, void 0).pipe(andThen$1(run$2(liveConnections, never$1.pipe(onInterrupt(() => failInFlightRequests(responseHandlers))))), asVoid),
96052
95969
  onDisconnect: clear(liveConnections)
96053
95970
  });
96054
95971
  const protocol = yield* layerProtocolSocket({ retryTransientErrors: true }).pipe(provide$2(mergeAll$1(socket, layerNdjson, hooks)), build, map$7(get$13(Protocol)));
95972
+ yield* _await(connected);
96055
95973
  return Protocol.of({
96056
95974
  ...protocol,
96057
95975
  run: (clientId, handler) => update$1(responseHandlers, set$2(clientId, handler)).pipe(andThen$1(protocol.run(clientId, handler)))
@@ -96064,6 +95982,7 @@ const WorkerProtocol = Blueprint_exports.make()(TypeId$14).steps({
96064
95982
  const layerWorkerProtocol = (socket) => WorkerProtocol.of({ socket }).layer;
96065
95983
  //#endregion
96066
95984
  //#region src/drivers/node.ts
95985
+ const WORKER_TERMINATION_GRACE = seconds(5);
96067
95986
  const restrictToOwnerOrWarn = (fs, file) => fs.chmod(file, 384).pipe(tapError((cause) => logWarning(`Could not restrict "${file}" to its owner; the worker directory's own mode still protects it.`).pipe(annotateLogs("cause", cause))), catchTag("PlatformError", () => void_$1));
96068
95987
  const nodeWorkerLauncherLayer = (childEnv) => effect(WorkerLauncher, gen(function* () {
96069
95988
  const crypto = yield* Crypto$1;
@@ -96087,7 +96006,8 @@ const nodeWorkerLauncherLayer = (childEnv) => effect(WorkerLauncher, gen(functio
96087
96006
  ...childEnv,
96088
96007
  ...params.env
96089
96008
  },
96090
- stderr: "inherit"
96009
+ stderr: "inherit",
96010
+ forceKillAfter: WORKER_TERMINATION_GRACE
96091
96011
  }).pipe(provideService$1(ChildProcessSpawner, spawner));
96092
96012
  const clientLayer = layerWorkerProtocol(layerNet({ path: socketPath }));
96093
96013
  const exited = handle.exitCode.pipe(orDie, flatMap$4((exitCode) => match$6(classifyWorkerExit(ClassifyWorkerExitCommand.make({
@@ -110340,13 +110260,11 @@ const reporterInputsOf = dual(5, (names, choicesByName, loaded, projectBasePath,
110340
110260
  //#endregion
110341
110261
  //#region src/keep-temp-dir.workflow.ts
110342
110262
  const KeepTempDirTypeId = Symbol.for("@systemfsoftware/stryker-js/KeepTempDir");
110343
- var KeepTempDirAlways = class extends TaggedClass()("KeepTempDirAlways", {}) {
110344
- [KeepTempDirTypeId] = KeepTempDirTypeId;
110345
- };
110346
- var KeepTempDirOnFailure = class extends TaggedClass()("KeepTempDirOnFailure", { failed: Boolean$6 }) {
110347
- [KeepTempDirTypeId] = KeepTempDirTypeId;
110348
- };
110349
- const KeepTempDirOption = Union([KeepTempDirAlways, KeepTempDirOnFailure]);
110263
+ const CleanTempDirOption = Literals$3([
110264
+ "always",
110265
+ false,
110266
+ true
110267
+ ]);
110350
110268
  var TempDirKept = class extends TaggedClass()("TempDirKept", {}) {
110351
110269
  [KeepTempDirTypeId] = KeepTempDirTypeId;
110352
110270
  };
@@ -110354,13 +110272,13 @@ var TempDirRemoved = class extends TaggedClass()("TempDirRemoved", {}) {
110354
110272
  [KeepTempDirTypeId] = KeepTempDirTypeId;
110355
110273
  };
110356
110274
  var KeepTempDirCommand = class extends TaggedClass()("KeepTempDirCommand", {
110357
- cleanTempDir: KeepTempDirOption,
110275
+ cleanTempDir: CleanTempDirOption,
110358
110276
  failed: Boolean$6
110359
110277
  }) {
110360
110278
  static [Workflow_exports.InstrumentationBrand] = {};
110361
110279
  };
110362
- const keepOf = (failed) => value(failed).pipe(when(true, () => TempDirKept.make({})), when(false, () => TempDirRemoved.make({})), exhaustive, succeed$10);
110363
- const decide$1 = (command) => value(command.cleanTempDir).pipe(tag("KeepTempDirAlways", () => succeed$10(TempDirRemoved.make({}))), tag("KeepTempDirOnFailure", (option) => keepOf(option.failed)), exhaustive);
110280
+ const keptIff = (kept) => value(kept).pipe(when(true, () => TempDirKept.make({})), when(false, () => TempDirRemoved.make({})), exhaustive);
110281
+ const decide$1 = (command) => value(command.cleanTempDir).pipe(when(false, () => TempDirKept.make({})), when(true, () => keptIff(command.failed)), when("always", () => TempDirRemoved.make({})), exhaustive, succeed$10);
110364
110282
  const keepTempDir = Workflow_exports.make({
110365
110283
  command: KeepTempDirCommand,
110366
110284
  decision: Union([TempDirKept, TempDirRemoved]),
@@ -110369,11 +110287,10 @@ const keepTempDir = Workflow_exports.make({
110369
110287
  });
110370
110288
  //#endregion
110371
110289
  //#region src/Sandbox.service.ts
110372
- const keepTempDirCommand = (exit, cleanTempDir) => KeepTempDirCommand.make({
110373
- cleanTempDir: value(cleanTempDir).pipe(when("always", () => KeepTempDirAlways.make({})), orElse$1((onFailure) => KeepTempDirOnFailure.make({ failed: onFailure }))),
110290
+ const removesTempDir = (exit, cleanTempDir) => match$6(keepTempDir(KeepTempDirCommand.make({
110291
+ cleanTempDir,
110374
110292
  failed: isFailure(exit)
110375
- });
110376
- const removesTempDir = (exit, cleanTempDir) => match$6(keepTempDir(keepTempDirCommand(exit, cleanTempDir)), {
110293
+ })), {
110377
110294
  onFailure: () => false,
110378
110295
  onSuccess: (decision) => value(decision).pipe(tag("TempDirRemoved", () => true), tag("TempDirKept", () => false), exhaustive)
110379
110296
  });
@@ -110414,7 +110331,7 @@ const makeTemporaryDirectory = fn(SpanTaxonomy_exports.Spans.sandboxMakeTempDir.
110414
110331
  yield* logDebug(`Using temp directory "${tmp}"`);
110415
110332
  yield* addFinalizer((exit) => match$1(removesTempDir(exit, options.cleanTempDir), {
110416
110333
  onTrue: () => removeTempDirectory(tmp, parent, fs),
110417
- onFalse: () => logDebug("Not removing the temp dir because an error occurred")
110334
+ onFalse: () => logDebug(`Keeping stryker temp directory ${tmp}`)
110418
110335
  }).pipe(orDie));
110419
110336
  return { path: tmp };
110420
110337
  });
package/dist/promises.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { C as nodePlatformLayer, t as strykerCell } from "./run-stages-aBT_QAfO.mjs";
1
+ import { C as nodePlatformLayer, t as strykerCell } from "./run-stages-DdVQINP9.mjs";
2
2
  import * as Effect from "effect/Effect";
3
3
  import { dual } from "effect/Function";
4
4
  //#region src/drivers/promise.ts
@@ -28,7 +28,6 @@ import * as Path from "effect/Path";
28
28
  import * as Stream from "effect/Stream";
29
29
  import * as Config from "effect/Config";
30
30
  import * as Clock from "effect/Clock";
31
- import * as Exit from "effect/Exit";
32
31
  import * as Layer from "effect/Layer";
33
32
  import * as Queue from "effect/Queue";
34
33
  import * as Scope from "effect/Scope";
@@ -41,12 +40,12 @@ import * as RpcSerialization from "effect/rpc/RpcSerialization";
41
40
  import * as RpcServer from "effect/rpc/RpcServer";
42
41
  import * as SocketServer from "effect/socket/SocketServer";
43
42
  import * as Duration from "effect/Duration";
43
+ import * as Exit from "effect/Exit";
44
44
  import * as Fiber from "effect/Fiber";
45
45
  import * as HashSet from "effect/HashSet";
46
46
  import * as PubSub from "effect/PubSub";
47
47
  import * as SynchronizedRef from "effect/SynchronizedRef";
48
48
  import * as RpcClient from "effect/rpc/RpcClient";
49
- import * as Schedule from "effect/Schedule";
50
49
  import * as DateTime from "effect/DateTime";
51
50
  import * as Ref from "effect/Ref";
52
51
  import * as Sink from "effect/Sink";
@@ -60,6 +59,7 @@ import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto";
60
59
  import * as Crypto from "effect/Crypto";
61
60
  import * as ChildProcess from "effect/process/ChildProcess";
62
61
  import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
62
+ import * as Deferred from "effect/Deferred";
63
63
  import * as FiberSet from "effect/FiberSet";
64
64
  import { RpcClientError } from "effect/rpc/RpcClientError";
65
65
  import * as Socket from "effect/socket/Socket";
@@ -10741,7 +10741,7 @@ var WorkerLauncher = class extends Context.Service()("@systemfsoftware/stryker-j
10741
10741
  //#endregion
10742
10742
  //#region src/worker-client.blueprint.ts
10743
10743
  const TypeId$10 = Symbol.for("~systemfsoftware/stryker-js/WorkerClient");
10744
- const connectRetry = Schedule.max([Schedule.spaced(50), Schedule.recurs(100)]);
10744
+ const WORKER_BOOT_TIMEOUT = Duration.seconds(30);
10745
10745
  const WorkerClients = () => Blueprint.make()(TypeId$10).steps({
10746
10746
  steps: {},
10747
10747
  targets: { scoped: Effect$1.fnUntraced(function* (params) {
@@ -10755,7 +10755,11 @@ const WorkerClients = () => Blueprint.make()(TypeId$10).steps({
10755
10755
  tempDirPrefix: params.tempDirPrefix,
10756
10756
  env: params.env
10757
10757
  });
10758
- const protocol = yield* worker.pipe(clientLayer, Layer.build, Effect$1.retry(connectRetry), Effect$1.raceFirst(worker.exited), Effect$1.catchTag("SocketError", () => Effect$1.fail(WorkerBootTimeoutError.make({ pid: worker.pid }))));
10758
+ const bootTimedOut = () => Effect$1.fail(WorkerBootTimeoutError.make({ pid: worker.pid }));
10759
+ const protocol = yield* worker.pipe(clientLayer, Layer.build, Effect$1.raceFirst(worker.exited), Effect$1.timeoutOrElse({
10760
+ duration: WORKER_BOOT_TIMEOUT,
10761
+ orElse: bootTimedOut
10762
+ }), Effect$1.catchTag("SocketError", bootTimedOut));
10759
10763
  const traceContext = yield* Layer.build(Trace_exports.layerTraceContextClient);
10760
10764
  return yield* RpcClient.make(params.rpcs).pipe(Effect$1.provideContext(Context.merge(protocol, traceContext)));
10761
10765
  }) }
@@ -11225,7 +11229,7 @@ const strykerOutputFilesOf = (options) => [
11225
11229
  ];
11226
11230
  //#endregion
11227
11231
  //#region package.json
11228
- var version = "15.0.0";
11232
+ var version = "15.0.1";
11229
11233
  //#endregion
11230
11234
  //#region src/stryker-package.schema.ts
11231
11235
  var StrykerPackage = class extends S.Class("StrykerPackage")({
@@ -13142,7 +13146,7 @@ const stageLayerOf = (env, events) => {
13142
13146
  const eventsLayer = Match$1.value(events).pipe(Match$1.when(void 0, () => Layer.effect(RunEvents, Queue.bounded(RunEvent_exports.RunEvent.QUEUE_BOUND))), Match$1.orElse((queue) => Layer.succeed(RunEvents, queue)));
13143
13147
  const stageLayer = Layer.mergeAll(Layer.succeed(RunEnvironment, env), eventsLayer, PhaseClock.layer(env.runStartedAt), IdGenerator.layer, ProjectFiles.layer, Layer.effect(Scope.Scope, Effect$1.gen(function* () {
13144
13148
  const stageScope = yield* Scope.make();
13145
- yield* Effect$1.addFinalizer(() => Scope.close(stageScope, Exit.void));
13149
+ yield* Effect$1.addFinalizer((exit) => Scope.close(stageScope, exit));
13146
13150
  return stageScope;
13147
13151
  })));
13148
13152
  return Layer.mergeAll(stageLayer, MutationReporting.layer.pipe(Layer.provide(stageLayer)), Reporter.layer.pipe(Layer.provide(ReporterOutput.layer), Layer.provide(stageLayer)));
@@ -13728,11 +13732,13 @@ const failInFlightRequests = Effect$1.fn(SpanTaxonomy_exports.Spans.workerProtoc
13728
13732
  const makeWorkerProtocol = Effect$1.fn(SpanTaxonomy_exports.Spans.workerProtocolMake.name)(function* (socket) {
13729
13733
  const responseHandlers = yield* Ref.make(HashMap.empty());
13730
13734
  const liveConnections = yield* FiberSet.make();
13735
+ const connected = yield* Deferred.make();
13731
13736
  const hooks = Layer.succeed(RpcClient.ConnectionHooks, {
13732
- onConnect: FiberSet.run(liveConnections, Effect$1.never.pipe(Effect$1.onInterrupt(() => failInFlightRequests(responseHandlers)))).pipe(Effect$1.asVoid),
13737
+ onConnect: Deferred.succeed(connected, void 0).pipe(Effect$1.andThen(FiberSet.run(liveConnections, Effect$1.never.pipe(Effect$1.onInterrupt(() => failInFlightRequests(responseHandlers))))), Effect$1.asVoid),
13733
13738
  onDisconnect: FiberSet.clear(liveConnections)
13734
13739
  });
13735
13740
  const protocol = yield* RpcClient.layerProtocolSocket({ retryTransientErrors: true }).pipe(Layer.provide(Layer.mergeAll(socket, RpcSerialization.layerNdjson, hooks)), Layer.build, Effect$1.map(Context.get(RpcClient.Protocol)));
13741
+ yield* Deferred.await(connected);
13736
13742
  return RpcClient.Protocol.of({
13737
13743
  ...protocol,
13738
13744
  run: (clientId, handler) => Ref.update(responseHandlers, HashMap.set(clientId, handler)).pipe(Effect$1.andThen(protocol.run(clientId, handler)))
@@ -13745,6 +13751,7 @@ const WorkerProtocol = Blueprint.make()(TypeId$9).steps({
13745
13751
  const layerWorkerProtocol = (socket) => WorkerProtocol.of({ socket }).layer;
13746
13752
  //#endregion
13747
13753
  //#region src/drivers/node.ts
13754
+ const WORKER_TERMINATION_GRACE = Duration.seconds(5);
13748
13755
  const restrictToOwnerOrWarn = (fs, file) => fs.chmod(file, 384).pipe(Effect$1.tapError((cause) => Effect$1.logWarning(`Could not restrict "${file}" to its owner; the worker directory's own mode still protects it.`).pipe(Effect$1.annotateLogs("cause", cause))), Effect$1.catchTag("PlatformError", () => Effect$1.void));
13749
13756
  const nodeWorkerLauncherLayer = (childEnv) => Layer.effect(WorkerLauncher, Effect$1.gen(function* () {
13750
13757
  const crypto = yield* Crypto.Crypto;
@@ -13768,7 +13775,8 @@ const nodeWorkerLauncherLayer = (childEnv) => Layer.effect(WorkerLauncher, Effec
13768
13775
  ...childEnv,
13769
13776
  ...params.env
13770
13777
  },
13771
- stderr: "inherit"
13778
+ stderr: "inherit",
13779
+ forceKillAfter: WORKER_TERMINATION_GRACE
13772
13780
  }).pipe(Effect$1.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner));
13773
13781
  const clientLayer = layerWorkerProtocol(NodeSocket.layerNet({ path: socketPath }));
13774
13782
  const exited = handle.exitCode.pipe(Effect$1.orDie, Effect$1.flatMap((exitCode) => Result.match(classifyWorkerExit(ClassifyWorkerExitCommand.make({
@@ -19707,13 +19715,11 @@ const reporterInputsOf = dual(5, (names, choicesByName, loaded, projectBasePath,
19707
19715
  //#endregion
19708
19716
  //#region src/keep-temp-dir.workflow.ts
19709
19717
  const KeepTempDirTypeId = Symbol.for("@systemfsoftware/stryker-js/KeepTempDir");
19710
- var KeepTempDirAlways = class extends S.TaggedClass()("KeepTempDirAlways", {}) {
19711
- [KeepTempDirTypeId] = KeepTempDirTypeId;
19712
- };
19713
- var KeepTempDirOnFailure = class extends S.TaggedClass()("KeepTempDirOnFailure", { failed: S.Boolean }) {
19714
- [KeepTempDirTypeId] = KeepTempDirTypeId;
19715
- };
19716
- const KeepTempDirOption = S.Union([KeepTempDirAlways, KeepTempDirOnFailure]);
19718
+ const CleanTempDirOption = S.Literals([
19719
+ "always",
19720
+ false,
19721
+ true
19722
+ ]);
19717
19723
  var TempDirKept = class extends S.TaggedClass()("TempDirKept", {}) {
19718
19724
  [KeepTempDirTypeId] = KeepTempDirTypeId;
19719
19725
  };
@@ -19721,13 +19727,13 @@ var TempDirRemoved = class extends S.TaggedClass()("TempDirRemoved", {}) {
19721
19727
  [KeepTempDirTypeId] = KeepTempDirTypeId;
19722
19728
  };
19723
19729
  var KeepTempDirCommand = class extends S.TaggedClass()("KeepTempDirCommand", {
19724
- cleanTempDir: KeepTempDirOption,
19730
+ cleanTempDir: CleanTempDirOption,
19725
19731
  failed: S.Boolean
19726
19732
  }) {
19727
19733
  static [Workflow.InstrumentationBrand] = {};
19728
19734
  };
19729
- const keepOf = (failed) => Match$1.value(failed).pipe(Match$1.when(true, () => TempDirKept.make({})), Match$1.when(false, () => TempDirRemoved.make({})), Match$1.exhaustive, Result.succeed);
19730
- const decide = (command) => Match$1.value(command.cleanTempDir).pipe(Match$1.tag("KeepTempDirAlways", () => Result.succeed(TempDirRemoved.make({}))), Match$1.tag("KeepTempDirOnFailure", (option) => keepOf(option.failed)), Match$1.exhaustive);
19735
+ const keptIff = (kept) => Match$1.value(kept).pipe(Match$1.when(true, () => TempDirKept.make({})), Match$1.when(false, () => TempDirRemoved.make({})), Match$1.exhaustive);
19736
+ const decide = (command) => Match$1.value(command.cleanTempDir).pipe(Match$1.when(false, () => TempDirKept.make({})), Match$1.when(true, () => keptIff(command.failed)), Match$1.when("always", () => TempDirRemoved.make({})), Match$1.exhaustive, Result.succeed);
19731
19737
  const keepTempDir = Workflow.make({
19732
19738
  command: KeepTempDirCommand,
19733
19739
  decision: S.Union([TempDirKept, TempDirRemoved]),
@@ -19736,11 +19742,10 @@ const keepTempDir = Workflow.make({
19736
19742
  });
19737
19743
  //#endregion
19738
19744
  //#region src/Sandbox.service.ts
19739
- const keepTempDirCommand = (exit, cleanTempDir) => KeepTempDirCommand.make({
19740
- cleanTempDir: Match$1.value(cleanTempDir).pipe(Match$1.when("always", () => KeepTempDirAlways.make({})), Match$1.orElse((onFailure) => KeepTempDirOnFailure.make({ failed: onFailure }))),
19745
+ const removesTempDir = (exit, cleanTempDir) => Result.match(keepTempDir(KeepTempDirCommand.make({
19746
+ cleanTempDir,
19741
19747
  failed: Exit.isFailure(exit)
19742
- });
19743
- const removesTempDir = (exit, cleanTempDir) => Result.match(keepTempDir(keepTempDirCommand(exit, cleanTempDir)), {
19748
+ })), {
19744
19749
  onFailure: () => false,
19745
19750
  onSuccess: (decision) => Match$1.value(decision).pipe(Match$1.tag("TempDirRemoved", () => true), Match$1.tag("TempDirKept", () => false), Match$1.exhaustive)
19746
19751
  });
@@ -19781,7 +19786,7 @@ const makeTemporaryDirectory = Effect$1.fn(SpanTaxonomy_exports.Spans.sandboxMak
19781
19786
  yield* Effect$1.logDebug(`Using temp directory "${tmp}"`);
19782
19787
  yield* Effect$1.addFinalizer((exit) => Boolean$1.match(removesTempDir(exit, options.cleanTempDir), {
19783
19788
  onTrue: () => removeTempDirectory(tmp, parent, fs),
19784
- onFalse: () => Effect$1.logDebug("Not removing the temp dir because an error occurred")
19789
+ onFalse: () => Effect$1.logDebug(`Keeping stryker temp directory ${tmp}`)
19785
19790
  }).pipe(Effect$1.orDie));
19786
19791
  return { path: tmp };
19787
19792
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@systemfsoftware/stryker-js",
3
- "version": "15.0.0",
3
+ "version": "15.0.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/systemfsoftware/stryker-js-effect.git",
@@ -70,16 +70,16 @@
70
70
  "tsdown": "^0.23.0",
71
71
  "typescript": "^7",
72
72
  "vitest": "^5",
73
- "@systemfsoftware/stryker-framework-interface": "^0.0.0",
74
- "@systemfsoftware/stryker-ignorer-interface": "^0.1.1",
75
73
  "@systemfsoftware/stryker-config": "^0.1.0",
76
- "@systemfsoftware/stryker-js-cli-contract": "^0.2.0",
74
+ "@systemfsoftware/stryker-ignorer-interface": "^0.1.1",
77
75
  "@systemfsoftware/stryker-js-instrumenter": "^12.0.0",
78
- "@systemfsoftware/stryker-js-html-reporter": "^6.0.0",
76
+ "@systemfsoftware/stryker-js-cli-contract": "^0.2.0",
77
+ "@systemfsoftware/stryker-framework-interface": "^0.0.0",
79
78
  "@systemfsoftware/stryker-js-plugin-interface": "^12.0.0",
80
79
  "@systemfsoftware/stryker-js-plugin-runtime": "^7.0.0",
81
80
  "@systemfsoftware/tsdown-config": "^0.1.0",
82
- "@systemfsoftware/vitest-config": "^0.1.0"
81
+ "@systemfsoftware/vitest-config": "^0.1.0",
82
+ "@systemfsoftware/stryker-js-html-reporter": "^6.0.0"
83
83
  },
84
84
  "publishConfig": {
85
85
  "access": "public",
@@ -111,7 +111,7 @@
111
111
  },
112
112
  "scripts": {
113
113
  "clean": "rimraf dist",
114
- "build": "pnpm run typecheck && rimraf dist && tsdown --config tsdown.bin.config.ts && tsdown --config tsdown.config.ts",
114
+ "build": "pnpm run typecheck && tsdown",
115
115
  "typecheck": "tsc -b",
116
116
  "test": "vitest run",
117
117
  "mutation": "stryker run",