@fraqjs/fraq 0.6.4 → 0.7.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/dist/index.d.mts CHANGED
@@ -5679,6 +5679,7 @@ declare class Context {
5679
5679
  private readonly services;
5680
5680
  private readonly subContexts;
5681
5681
  private readonly parentEventForwarder?;
5682
+ private readonly timers;
5682
5683
  private readonly initialReconnectDelayMs;
5683
5684
  private readonly maxReconnectDelayMs;
5684
5685
  private readonly logHandler?;
@@ -5700,12 +5701,17 @@ declare class Context {
5700
5701
  tryResolve<T extends object>(service: ServiceClass<T>): T | undefined;
5701
5702
  isProvided<T extends object>(service: ServiceClass<T>): boolean;
5702
5703
  fork(name: string, filter?: Filter): Context;
5704
+ timeout(delayMs: number, callback: () => void | Promise<void>): NodeJS.Timeout;
5705
+ interval(intervalMs: number, callback: () => void | Promise<void>): NodeJS.Timeout;
5703
5706
  createSession(message: IncomingMessage): Session;
5704
5707
  start(): Promise<void>;
5705
5708
  stop(): Promise<void>;
5706
5709
  private startInternal;
5707
5710
  private getState;
5708
5711
  private stopInternal;
5712
+ private assertCanScheduleTimer;
5713
+ private runTimerCallback;
5714
+ private clearTimers;
5709
5715
  private stopEventStream;
5710
5716
  private acceptsParentEvent;
5711
5717
  private applyPlugins;
package/dist/index.mjs CHANGED
@@ -382,6 +382,7 @@ var Context = class Context {
382
382
  services = /* @__PURE__ */ new Map();
383
383
  subContexts = [];
384
384
  parentEventForwarder;
385
+ timers = /* @__PURE__ */ new Set();
385
386
  initialReconnectDelayMs;
386
387
  maxReconnectDelayMs;
387
388
  logHandler;
@@ -466,6 +467,23 @@ and implement the dispose method to clean up resources when the context stops.
466
467
  this.subContexts.push(subContext);
467
468
  return subContext;
468
469
  }
470
+ timeout(delayMs, callback) {
471
+ this.assertCanScheduleTimer();
472
+ const timeout = setTimeout(() => {
473
+ this.timers.delete(timeout);
474
+ this.runTimerCallback(callback);
475
+ }, delayMs);
476
+ this.timers.add(timeout);
477
+ return timeout;
478
+ }
479
+ interval(intervalMs, callback) {
480
+ this.assertCanScheduleTimer();
481
+ const interval = setInterval(() => {
482
+ this.runTimerCallback(callback);
483
+ }, intervalMs);
484
+ this.timers.add(interval);
485
+ return interval;
486
+ }
469
487
  createSession(message) {
470
488
  return {
471
489
  raw: message,
@@ -508,10 +526,10 @@ and implement the dispose method to clean up resources when the context stops.
508
526
  }
509
527
  }
510
528
  async stop() {
511
- if (this.state === "idle" || this.state === "stopped") return;
529
+ if (this.state === "idle" && this.timers.size === 0 || this.state === "stopped") return;
512
530
  if (this.state === "starting") await this.startPromise;
513
531
  const stateAfterStart = this.getState();
514
- if (stateAfterStart === "idle" || stateAfterStart === "stopped") return;
532
+ if (stateAfterStart === "idle" && this.timers.size === 0 || stateAfterStart === "stopped") return;
515
533
  if (stateAfterStart === "stopping") {
516
534
  await this.stopPromise;
517
535
  return;
@@ -543,12 +561,13 @@ and implement the dispose method to clean up resources when the context stops.
543
561
  }
544
562
  async stopInternal() {
545
563
  const errors = [];
546
- await this.stopEventStream(errors);
564
+ this.clearTimers();
547
565
  for (const subContext of [...this.subContexts].reverse()) try {
548
566
  await subContext.stop();
549
567
  } catch (error) {
550
568
  errors.push(error);
551
569
  }
570
+ await this.stopEventStream(errors);
552
571
  if (this.parent && this.parentEventForwarder) this.parent.eventBus.off("*", this.parentEventForwarder);
553
572
  for (const service of [...this.services.values()].reverse()) {
554
573
  if (!isDisposable(service)) continue;
@@ -561,6 +580,22 @@ and implement the dispose method to clean up resources when the context stops.
561
580
  if (errors.length === 1) throw errors[0];
562
581
  if (errors.length > 1) throw new AggregateError(errors, `Context "${this.name}" failed to stop cleanly.`);
563
582
  }
583
+ assertCanScheduleTimer() {
584
+ if (this.state === "stopping") throw new Error(`Context "${this.name}" cannot schedule timers while it is stopping.`);
585
+ if (this.state === "stopped") throw new Error(`Context "${this.name}" cannot schedule timers after it has stopped.`);
586
+ }
587
+ async runTimerCallback(callback) {
588
+ if (this.state === "stopping" || this.state === "stopped") return;
589
+ try {
590
+ await callback();
591
+ } catch (error) {
592
+ this.logger.error("Error handling timer callback", error);
593
+ }
594
+ }
595
+ clearTimers() {
596
+ for (const timer of this.timers) clearTimeout(timer);
597
+ this.timers.clear();
598
+ }
564
599
  async stopEventStream(errors) {
565
600
  this.resolveReconnectDelay();
566
601
  const subscription = this.eventSubscription;
@@ -685,6 +720,10 @@ and implement the dispose method to clean up resources when the context stops.
685
720
  }
686
721
  createProxyContextForPlugin(plugin) {
687
722
  const proxyLogger = new Logger((message) => this.logHandler?.(message), plugin.name);
723
+ const proxyProvide = (service, instance) => {
724
+ this.provide(service, instance);
725
+ this.logger.debug(`Plugin ${plugin.name} provided ${service.name}`);
726
+ };
688
727
  let proxyInjections;
689
728
  if (plugin.inject) {
690
729
  proxyInjections = {};
@@ -694,10 +733,11 @@ and implement the dispose method to clean up resources when the context stops.
694
733
  proxyInjections ??= {};
695
734
  for (const [key, service] of Object.entries(plugin.optionalInject)) proxyInjections[key] = this.tryResolve(service);
696
735
  }
697
- return new Proxy(this, { get(target, prop) {
736
+ return new Proxy(this, { get(target, prop, receiver) {
698
737
  if (prop === "logger") return proxyLogger;
738
+ else if (prop === "provide") return proxyProvide;
699
739
  else if (proxyInjections && prop in proxyInjections) return proxyInjections[prop];
700
- else return target[prop];
740
+ else return Reflect.get(target, prop, receiver);
701
741
  } });
702
742
  }
703
743
  async runEventStream() {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fraqjs/fraq",
3
3
  "type": "module",
4
- "version": "0.6.4",
4
+ "version": "0.7.0",
5
5
  "description": "Milky Bot framework",
6
6
  "files": [
7
7
  "dist"