@spine-event-engine/testing 2.0.0-snapshot.21 → 2.0.0-snapshot.22

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.
@@ -54,6 +54,7 @@ export interface BlackBoxScope extends ClientRequest {
54
54
  * @param schema The schema of the event message.
55
55
  * @param message The event message to post.
56
56
  * @returns A promise that resolves after the event is posted.
57
+ * @typeParam Schema The domain schema that determines the accepted message shape.
57
58
  */
58
59
  postEvent<Schema extends GenMessage<Message>>(schema: Schema, message: MessageShape<Schema>): Promise<void>;
59
60
  /**
@@ -62,6 +63,7 @@ export interface BlackBoxScope extends ClientRequest {
62
63
  * @param schema The schema of the external event message.
63
64
  * @param message The external event message.
64
65
  * @returns A promise that resolves after external event admission.
66
+ * @typeParam Schema The domain schema that determines the accepted message shape.
65
67
  */
66
68
  postExternalEvent<Schema extends GenMessage<Message>>(schema: Schema, message: MessageShape<Schema>): Promise<void>;
67
69
  }
@@ -70,6 +72,15 @@ export interface BlackBoxScope extends ClientRequest {
70
72
  */
71
73
  export declare class BlackBox {
72
74
  #private;
75
+ /**
76
+ * Captures the server, client, test options, and produced-signal observation.
77
+ *
78
+ * @param context The bounded context under test.
79
+ * @param server The started local server.
80
+ * @param client The client connected to that server.
81
+ * @param options The validated tenant, zone, and wait settings.
82
+ * @param observation The optional produced-signal observer.
83
+ */
73
84
  private constructor();
74
85
  /**
75
86
  * Starts an ephemeral local server and public client for a context or builder.
@@ -111,14 +122,20 @@ export declare class BlackBox {
111
122
  * @param accept The predicate that accepts a produced value.
112
123
  * @param options Optional wait limits for this operation.
113
124
  * @returns The first accepted value.
125
+ * @typeParam Value The value type carried through reading or delivery.
114
126
  */
115
127
  eventually<Value>(read: () => Value | Promise<Value>, accept: (value: Value) => boolean, options?: Pick<BlackBoxOptions, "timeoutMs" | "intervalMs">): Promise<Value>;
116
128
  /**
117
- * Stops admission, cancels owned subscriptions, and closes the client and server once.
129
+ * Stops admission, cancels registered subscriptions, and closes the client and server once.
118
130
  *
119
131
  * @returns A shared promise that resolves after cleanup completes.
120
132
  */
121
133
  close(): Promise<void>;
134
+ /**
135
+ * Stops admission and waits, cancels subscriptions, and closes the client and server.
136
+ *
137
+ * @returns Completion after all cleanup settles, or an aggregate of failures.
138
+ */
122
139
  private closeOnce;
123
140
  }
124
141
  /**
@@ -129,13 +146,13 @@ export interface BlackBoxTestAccess {
129
146
  * Creates a BlackBox with supplied closeable resources.
130
147
  *
131
148
  * @param resources The test client, server, and optional subscriptions.
132
- * @returns A BlackBox that owns the supplied resources.
149
+ * @returns A BlackBox configured with the supplied resources.
133
150
  */
134
151
  create(resources: BlackBoxTestResources): BlackBox;
135
152
  /**
136
153
  * Returns a generic subscription-like handle for lifecycle regression tests.
137
154
  *
138
- * @param blackBox The BlackBox that owns the handle.
155
+ * @param blackBox The BlackBox tracking the handle.
139
156
  * @param handle The cancelable async handle to track.
140
157
  * @returns The tracked handle.
141
158
  */
@@ -1 +1 @@
1
- {"version":3,"file":"black-box.d.ts","sourceRoot":"","sources":["../../src/black-box/black-box.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"black-box.d.ts","sourceRoot":"","sources":["../../src/black-box/black-box.ts"],"names":[],"mappings":"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"}
@@ -11,8 +11,8 @@
11
11
  * or implied. See the License for the specific language governing permissions and limitations under
12
12
  * the License.
13
13
  */
14
+ import { Time } from "@spine-event-engine/core/time";
14
15
  import { clone, create } from "@bufbuild/protobuf";
15
- import { TimestampSchema } from "@bufbuild/protobuf/wkt";
16
16
  import { Client as NodeClient, } from "@spine-event-engine/client-node";
17
17
  import { SignalEnvelopes } from "@spine-event-engine/core";
18
18
  import { ActorContextSchema, CommandSchema, EventContextSchema, EventSchema, TenantIdSchema, UserIdSchema, ZoneIdSchema, } from "@spine-event-engine/proto";
@@ -64,6 +64,15 @@ export class BlackBox {
64
64
  #observation;
65
65
  #admitting = true;
66
66
  #closing;
67
+ /**
68
+ * Captures the server, client, test options, and produced-signal observation.
69
+ *
70
+ * @param context The bounded context under test.
71
+ * @param server The started local server.
72
+ * @param client The client connected to that server.
73
+ * @param options The validated tenant, zone, and wait settings.
74
+ * @param observation The optional produced-signal observer.
75
+ */
67
76
  constructor(context, server, client, options, observation) {
68
77
  this.#context = context;
69
78
  this.#server = server;
@@ -151,24 +160,25 @@ export class BlackBox {
151
160
  * @param accept The predicate that accepts a produced value.
152
161
  * @param options Optional wait limits for this operation.
153
162
  * @returns The first accepted value.
163
+ * @typeParam Value The value type carried through reading or delivery.
154
164
  */
155
165
  async eventually(read, accept, options = {}) {
156
166
  this.#assertOpen();
157
167
  const timeoutMs = BlackBoxOptionsValues.positiveInteger(options.timeoutMs ?? this.#timeoutMs, "timeoutMs");
158
168
  const intervalMs = BlackBoxOptionsValues.positiveInteger(options.intervalMs ?? this.#intervalMs, "intervalMs");
159
- const deadline = Date.now() + timeoutMs;
169
+ const deadline = Time.monotonicTime() + timeoutMs;
160
170
  for (;;) {
161
171
  const value = await read();
162
172
  this.#assertOpen();
163
173
  if (accept(value))
164
174
  return value;
165
- if (Date.now() >= deadline)
175
+ if (Time.monotonicTime() >= deadline)
166
176
  throw new BlackBoxTimeoutError(timeoutMs);
167
- await BlackBoxClock.wait(Math.min(intervalMs, deadline - Date.now()), this.#waits.signal);
177
+ await BlackBoxClock.wait(Math.min(intervalMs, deadline - Time.monotonicTime()), this.#waits.signal);
168
178
  }
169
179
  }
170
180
  /**
171
- * Stops admission, cancels owned subscriptions, and closes the client and server once.
181
+ * Stops admission, cancels registered subscriptions, and closes the client and server once.
172
182
  *
173
183
  * @returns A shared promise that resolves after cleanup completes.
174
184
  */
@@ -176,10 +186,22 @@ export class BlackBox {
176
186
  this.#closing ??= this.closeOnce();
177
187
  return this.#closing;
178
188
  }
189
+ /**
190
+ * Rejects calls once BlackBox cleanup has begun.
191
+ */
179
192
  #assertOpen() {
180
193
  if (!this.#admitting)
181
194
  throw new BlackBoxClosedError();
182
195
  }
196
+ /**
197
+ * Posts a direct event with a controlled occurrence timestamp and actor context.
198
+ *
199
+ * @typeParam Schema The domain schema that determines the accepted message shape.
200
+ * @param actor The actor identifier recorded in signal contexts.
201
+ * @param schema The domain message schema used to encode the payload.
202
+ * @param message The domain payload to post.
203
+ * @returns Completion after the event bus accepts the direct event.
204
+ */
183
205
  async #postEvent(actor, schema, message) {
184
206
  this.#assertOpen();
185
207
  await this.#context.eventBus().post(SignalEnvelopes.event({
@@ -191,6 +213,15 @@ export class BlackBox {
191
213
  message,
192
214
  }));
193
215
  }
216
+ /**
217
+ * Admits an external event with controlled occurrence time through server intake.
218
+ *
219
+ * @typeParam Schema The domain schema that determines the accepted message shape.
220
+ * @param actor The actor identifier recorded in signal contexts.
221
+ * @param schema The domain message schema used to encode the payload.
222
+ * @param message The domain payload to post.
223
+ * @returns Completion after server intake accepts the external event.
224
+ */
194
225
  async #postExternalEvent(actor, schema, message) {
195
226
  this.#assertOpen();
196
227
  await postExternalEvent(this.#context, SignalEnvelopes.event({
@@ -202,14 +233,31 @@ export class BlackBox {
202
233
  message,
203
234
  }));
204
235
  }
236
+ /**
237
+ * Registers a cancelable subscription for session cleanup.
238
+ *
239
+ * @typeParam Handle The cancelable handle type retained when tracking it.
240
+ * @param handle The cancelable handle to track.
241
+ * @returns The same handle registered for cleanup.
242
+ */
205
243
  #track(handle) {
206
244
  this.#assertOpen();
207
245
  this.#subscriptions.add(handle);
208
246
  return handle;
209
247
  }
248
+ /**
249
+ * Removes a completed subscription from session cleanup.
250
+ *
251
+ * @param handle The cancelable handle to track.
252
+ */
210
253
  #release(handle) {
211
254
  this.#subscriptions.delete(handle);
212
255
  }
256
+ /**
257
+ * Creates a test actor context with cloned tenant and zone and controlled occurrence time.
258
+ *
259
+ * @param actor The actor identifier recorded in signal contexts.
260
+ */
213
261
  #actorContext(actor) {
214
262
  return create(ActorContextSchema, {
215
263
  ...(this.#tenant === undefined ? {} : { tenantId: clone(TenantIdSchema, this.#tenant) }),
@@ -218,6 +266,11 @@ export class BlackBox {
218
266
  timestamp: BlackBoxClock.timestamp(),
219
267
  });
220
268
  }
269
+ /**
270
+ * Stops admission and waits, cancels subscriptions, and closes the client and server.
271
+ *
272
+ * @returns Completion after all cleanup settles, or an aggregate of failures.
273
+ */
221
274
  async closeOnce() {
222
275
  this.#admitting = false;
223
276
  this.#waits.abort(new BlackBoxClosedError());
@@ -249,13 +302,19 @@ const BlackBoxAccess = (() => {
249
302
  return Object.freeze({
250
303
  // prettier-ignore
251
304
  /**
252
- * Associates internal operations with a BlackBox.
305
+ * Stores private lifecycle operations for the corresponding BlackBox instance.
306
+ *
307
+ * @param blackBox The BlackBox instance associated with these internals.
308
+ * @param internals The private operations for that instance.
253
309
  */
254
310
  set(blackBox, internals) {
255
311
  values.set(blackBox, internals);
256
312
  },
257
313
  /**
258
- * Obtains the internal operations for a BlackBox.
314
+ * Returns private lifecycle operations or rejects an unregistered instance.
315
+ *
316
+ * @param blackBox The BlackBox instance associated with these internals.
317
+ * @returns The private operations registered for this instance.
259
318
  */
260
319
  get(blackBox) {
261
320
  const internals = values.get(blackBox);
@@ -274,7 +333,7 @@ export const BlackBoxTestAccess = Object.freeze({
274
333
  * Creates a BlackBox with supplied closeable resources.
275
334
  *
276
335
  * @param resources The test client, server, and optional subscriptions.
277
- * @returns A BlackBox that owns the supplied resources.
336
+ * @returns A BlackBox configured with the supplied resources.
278
337
  */
279
338
  create(resources) {
280
339
  const blackBox = BlackBoxLifecycle.instantiate({}, resources.server, resources.client, BlackBoxOptionsValues.defaults(), resources.observation ?? Object.freeze({ close: () => undefined }));
@@ -285,7 +344,7 @@ export const BlackBoxTestAccess = Object.freeze({
285
344
  /**
286
345
  * Returns a generic subscription-like handle for lifecycle regression tests.
287
346
  *
288
- * @param blackBox The BlackBox that owns the handle.
347
+ * @param blackBox The BlackBox tracking the handle.
289
348
  * @param handle The cancelable async handle to track.
290
349
  * @returns The tracked handle.
291
350
  */
@@ -306,12 +365,18 @@ export const BlackBoxTestAccess = Object.freeze({
306
365
  },
307
366
  });
308
367
  /**
309
- * Constructs BlackBox instances and compensates for failed startup.
368
+ * Creates BlackBox instances and compensates for failed startup.
310
369
  */
311
370
  const BlackBoxLifecycle = Object.freeze({
312
371
  // prettier-ignore
313
372
  /**
314
373
  * Opens the server and client before constructing a BlackBox.
374
+ *
375
+ * @param context The bounded context used to start the test server.
376
+ * @param options The validated tenant, zone, and wait settings.
377
+ * @param start The operation that starts the test server.
378
+ * @param connect The operation that connects a client to the started server.
379
+ * @returns The started BlackBox or a startup cleanup failure.
315
380
  */
316
381
  async open(context, options, start, connect) {
317
382
  let server;
@@ -339,36 +404,92 @@ const BlackBoxLifecycle = Object.freeze({
339
404
  }
340
405
  },
341
406
  /**
342
- * Instantiates a BlackBox through its deliberately private constructor.
407
+ * Creates a BlackBox through its deliberately private constructor.
408
+ *
409
+ * @param context The bounded context under test.
410
+ * @param server The started local server.
411
+ * @param client The client connected to that server.
412
+ * @param options The validated tenant, zone, and wait settings.
413
+ * @param observation The optional produced-signal observer.
414
+ * @returns A BlackBox containing the supplied resources.
343
415
  */
344
416
  instantiate(context, server, client, options, observation) {
345
417
  const Constructor = BlackBox;
346
418
  return new Constructor(context, server, client, options, observation);
347
419
  },
348
420
  });
421
+ /**
422
+ * Keeps an actor and fixed tenant and zone settings for fresh request contexts.
423
+ */
349
424
  class Request {
350
425
  #internals;
351
426
  #request;
352
427
  #actor;
428
+ /**
429
+ * Captures the selected actor and immutable request settings.
430
+ *
431
+ * @param blackBox The BlackBox instance associated with these internals.
432
+ * @param request The scoped client request used for public operations.
433
+ * @param actor The actor identifier recorded in signal contexts.
434
+ */
353
435
  constructor(blackBox, request, actor) {
354
436
  this.#internals = BlackBoxAccess.get(blackBox);
355
437
  this.#request = request;
356
438
  this.#actor = actor;
357
439
  }
440
+ /**
441
+ * Posts a command with a fresh actor context and validates the acknowledged command ID.
442
+ *
443
+ * @typeParam Schema The domain schema that determines the accepted message shape.
444
+ * @param schema The domain message schema used to encode the payload.
445
+ * @param message The domain payload to post.
446
+ * @param options The optional signal that cancels the command request.
447
+ * @returns The acknowledged application outcome.
448
+ */
358
449
  post(schema, message, options = {}) {
359
450
  this.#internals.assertOpen();
360
451
  return this.#request.post(schema, message, options);
361
452
  }
453
+ /**
454
+ * Posts a domain Event through the BlackBox context for this actor.
455
+ *
456
+ * @typeParam Schema The domain schema that determines the accepted message shape.
457
+ * @param schema The domain message schema used to encode the payload.
458
+ * @param message The domain payload to post.
459
+ * @returns Completion after the direct event is posted.
460
+ */
362
461
  postEvent(schema, message) {
363
462
  return this.#internals.postEvent(this.#actor, schema, message);
364
463
  }
464
+ /**
465
+ * Posts an external domain Event through the BlackBox context for this actor.
466
+ *
467
+ * @typeParam Schema The domain schema that determines the accepted message shape.
468
+ * @param schema The domain message schema used to encode the payload.
469
+ * @param message The domain payload to post.
470
+ * @returns Completion after external event admission.
471
+ */
365
472
  postExternalEvent(schema, message) {
366
473
  return this.#internals.postExternalEvent(this.#actor, schema, message);
367
474
  }
475
+ /**
476
+ * Reads through the scoped client after confirming the BlackBox remains open.
477
+ *
478
+ * @param query The query message or builder to read.
479
+ * @param options The cancellation settings for this read.
480
+ * @returns The query response from the scoped client.
481
+ */
368
482
  send(query, options) {
369
483
  this.#internals.assertOpen();
370
484
  return this.#request.send(query, options);
371
485
  }
486
+ /**
487
+ * Validates the subscription kind and creates an inactive, client-managed topic stream.
488
+ *
489
+ * @param topic The requested topic with its target.
490
+ * @param options The subscription kind, recovery query, and optional cancellation signal.
491
+ * @returns The inactive tracked subscription.
492
+ */
372
493
  async createSubscription(topic, options) {
373
494
  this.#internals.assertOpen();
374
495
  const subscription = await this.#request.createSubscription(topic, options);
@@ -378,24 +499,54 @@ class Request {
378
499
  return this.#internals.track(tracked);
379
500
  }
380
501
  }
502
+ /**
503
+ * Tracks stream completion and cancellation for BlackBox cleanup.
504
+ */
381
505
  class TrackedSubscription {
382
506
  #handle;
383
507
  #onRelease;
384
508
  #released = false;
385
509
  #cancellation;
510
+ /**
511
+ * Wraps a subscription and registers its release callback.
512
+ *
513
+ * @param handle The cancelable handle to track.
514
+ * @param onRelease The callback removing a completed handle from cleanup tracking.
515
+ */
386
516
  constructor(handle, onRelease) {
387
517
  this.#handle = handle;
388
518
  this.#onRelease = onRelease;
389
519
  }
520
+ /**
521
+ * Wraps live updates so terminal iteration releases cleanup tracking.
522
+ *
523
+ * @returns An iterable of live updates and authoritative recovery values.
524
+ */
390
525
  get updates() {
391
526
  return this.trackStream(this.#handle.updates);
392
527
  }
528
+ /**
529
+ * Wraps lifecycle notices so terminal iteration releases cleanup tracking.
530
+ *
531
+ * @returns An iterable of lifecycle notices for this subscription.
532
+ */
393
533
  get lifecycle() {
394
534
  return this.trackStream(this.#handle.lifecycle);
395
535
  }
536
+ /**
537
+ * Sends activation to the underlying subscription.
538
+ *
539
+ * @param options The optional signal that cancels activation.
540
+ * @returns Completion after remote activation.
541
+ */
396
542
  activate(options) {
397
543
  return this.#handle.activate(options);
398
544
  }
545
+ /**
546
+ * Cancels the underlying subscription once and releases cleanup tracking.
547
+ *
548
+ * @returns Completion after remote cleanup.
549
+ */
399
550
  async cancel() {
400
551
  try {
401
552
  this.#cancellation ??= this.#handle.cancel();
@@ -405,12 +556,24 @@ class TrackedSubscription {
405
556
  this.release();
406
557
  }
407
558
  }
559
+ /**
560
+ * Removes cleanup tracking when iteration ends, fails, or returns early.
561
+ *
562
+ * @typeParam Value The update or lifecycle value yielded by the tracked stream.
563
+ * @param source The subscription stream whose terminal iteration releases tracking.
564
+ * @returns An iterable that releases tracking on terminal iteration.
565
+ */
408
566
  trackStream(source) {
409
567
  const onRelease = () => {
410
568
  this.release();
411
569
  };
412
570
  const onCancel = () => this.cancel();
413
571
  return {
572
+ /**
573
+ * Returns an iterator that releases subscription tracking when it terminates.
574
+ *
575
+ * @returns An iterator that releases tracking when it terminates.
576
+ */
414
577
  [Symbol.asyncIterator]() {
415
578
  const iterator = source[Symbol.asyncIterator]();
416
579
  return {
@@ -451,6 +614,9 @@ class TrackedSubscription {
451
614
  },
452
615
  };
453
616
  }
617
+ /**
618
+ * Executes the release callback at most once.
619
+ */
454
620
  release() {
455
621
  if (this.#released)
456
622
  return;
@@ -458,14 +624,31 @@ class TrackedSubscription {
458
624
  this.#onRelease();
459
625
  }
460
626
  }
627
+ /**
628
+ * Wraps a cancelable test handle and tracks its completion.
629
+ *
630
+ * @typeParam Handle The cancelable handle type retained when tracking it.
631
+ */
461
632
  class Tracked {
462
633
  #handle;
463
634
  #onRelease;
464
635
  #cancellation;
636
+ /**
637
+ * Captures the handle and callback that removes it from cleanup tracking.
638
+ *
639
+ * @param handle The cancelable handle to track.
640
+ * @param onRelease The callback removing a completed handle from cleanup tracking.
641
+ */
465
642
  constructor(handle, onRelease) {
466
643
  this.#handle = handle;
467
644
  this.#onRelease = onRelease;
468
645
  }
646
+ /**
647
+ * Activates a subscription-like test handle or rejects an unsupported handle.
648
+ *
649
+ * @param arguments_ The arguments forwarded to the wrapped activation.
650
+ * @returns Completion after remote activation.
651
+ */
469
652
  async activate(...arguments_) {
470
653
  const subscription = this.#handle;
471
654
  if (subscription.activate === undefined) {
@@ -473,6 +656,11 @@ class Tracked {
473
656
  }
474
657
  await subscription.activate(...arguments_);
475
658
  }
659
+ /**
660
+ * Removes a tracked handle when iteration ends or fails.
661
+ *
662
+ * @returns An iterator that releases tracking when it terminates.
663
+ */
476
664
  [Symbol.asyncIterator]() {
477
665
  const iterator = this.#handle[Symbol.asyncIterator]();
478
666
  return {
@@ -513,6 +701,11 @@ class Tracked {
513
701
  },
514
702
  };
515
703
  }
704
+ /**
705
+ * Cancels the wrapped handle once and releases it even after failure.
706
+ *
707
+ * @returns Completion after remote cleanup.
708
+ */
516
709
  async cancel() {
517
710
  try {
518
711
  this.#cancellation ??= this.#handle.cancel();
@@ -530,6 +723,10 @@ const BlackBoxOptionsValues = Object.freeze({
530
723
  // prettier-ignore
531
724
  /**
532
725
  * Normalizes options for one context.
726
+ *
727
+ * @param context The bounded context whose tenant mode is validated.
728
+ * @param options The requested tenant and wait settings.
729
+ * @returns Validated immutable test settings.
533
730
  */
534
731
  normalize(context, options) {
535
732
  const multi = context instanceof BoundedContext ? context.isMultitenant : context.isMultitenant();
@@ -546,13 +743,18 @@ const BlackBoxOptionsValues = Object.freeze({
546
743
  });
547
744
  },
548
745
  /**
549
- * Clones an optional tenant message.
746
+ * Returns a separate tenant message when a tenant was selected.
747
+ *
748
+ * @param value The optional tenant message to clone.
749
+ * @returns A clone of the tenant or undefined.
550
750
  */
551
751
  cloneTenant(value) {
552
752
  return value === undefined ? undefined : clone(TenantIdSchema, value);
553
753
  },
554
754
  /**
555
755
  * Creates default normalized options for internal test seams.
756
+ *
757
+ * @returns Immutable tenant, zone, and wait defaults for test seams.
556
758
  */
557
759
  defaults() {
558
760
  return Object.freeze({
@@ -564,6 +766,9 @@ const BlackBoxOptionsValues = Object.freeze({
564
766
  },
565
767
  /**
566
768
  * Converts a tenant option to its message form.
769
+ *
770
+ * @param value The optional tenant string or identifier to validate and clone.
771
+ * @returns A cloned tenant identifier or undefined.
567
772
  */
568
773
  tenant(value) {
569
774
  if (value === undefined)
@@ -579,6 +784,9 @@ const BlackBoxOptionsValues = Object.freeze({
579
784
  },
580
785
  /**
581
786
  * Converts a zone option to its message form.
787
+ *
788
+ * @param value The optional zone string or identifier; omitted values use current Time.
789
+ * @returns A cloned zone identifier.
582
790
  */
583
791
  zoneId(value) {
584
792
  if (typeof value !== "string" && value !== undefined) {
@@ -586,13 +794,17 @@ const BlackBoxOptionsValues = Object.freeze({
586
794
  throw new TypeError("BlackBox zoneId must not be empty.");
587
795
  return clone(ZoneIdSchema, value);
588
796
  }
589
- const zone = value ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
797
+ const zone = value ?? Time.currentTimeZone();
590
798
  if (zone.length === 0)
591
799
  throw new TypeError("BlackBox zoneId must not be empty.");
592
800
  return create(ZoneIdSchema, { value: zone });
593
801
  },
594
802
  /**
595
803
  * Validates a positive whole-number duration.
804
+ *
805
+ * @param value The configured wait duration in milliseconds.
806
+ * @param name The duration option named in validation errors.
807
+ * @returns The validated positive integer.
596
808
  */
597
809
  positiveInteger(value, name) {
598
810
  if (!Number.isInteger(value) || value <= 0)
@@ -606,13 +818,19 @@ const BlackBoxOptionsValues = Object.freeze({
606
818
  const BlackBoxClock = Object.freeze({
607
819
  // prettier-ignore
608
820
  /**
609
- * Creates the current Protobuf timestamp.
821
+ * Returns the configured occurrence Time for posted events and actor contexts.
822
+ *
823
+ * @returns The current controlled Protobuf timestamp.
610
824
  */
611
825
  timestamp() {
612
- return create(TimestampSchema, { seconds: BigInt(Math.floor(Date.now() / 1_000)) });
826
+ return Time.currentTime();
613
827
  },
614
828
  /**
615
829
  * Waits for a delay or rejects when the supplied signal aborts.
830
+ *
831
+ * @param milliseconds The timer delay in milliseconds.
832
+ * @param signal The abort signal for this operation.
833
+ * @returns Completion when the timer expires unless aborted.
616
834
  */
617
835
  wait(milliseconds, signal) {
618
836
  return new Promise((resolve, reject) => {
@@ -635,6 +853,9 @@ const BlackBoxFailures = Object.freeze({
635
853
  // prettier-ignore
636
854
  /**
637
855
  * Returns reasons from rejected promises.
856
+ *
857
+ * @param results The settled cleanup operation results.
858
+ * @returns Failure reasons in their settled result order.
638
859
  */
639
860
  rejected(results) {
640
861
  const failures = [];