@camstack/system 1.2.17 → 1.2.18

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.
@@ -118,10 +118,32 @@ var LokiDestination = class {
118
118
  }
119
119
  async initialize(config) {
120
120
  this.config = config ?? null;
121
- if (!this.isActive()) return;
121
+ this.startTimerIfActive();
122
+ }
123
+ /**
124
+ * Re-apply configuration to an already-initialized destination after a
125
+ * settings change, without dropping the queued tail. Stops the current flush
126
+ * timer, swaps the config in, and starts a fresh timer only when the new
127
+ * config is active. This is what makes the addon's "enable without a restart"
128
+ * contract real: `initialize()` starts a timer, so calling it twice would leak
129
+ * the first one — `reconfigure()` clears it first.
130
+ */
131
+ async reconfigure(config) {
132
+ this.stopTimer();
133
+ this.config = config;
134
+ this.startTimerIfActive();
135
+ }
136
+ stopTimer() {
137
+ if (this.timer !== void 0) {
138
+ this.clearIntervalFn(this.timer);
139
+ this.timer = void 0;
140
+ }
141
+ }
142
+ startTimerIfActive() {
143
+ if (!this.isActive() || this.config === null) return;
122
144
  this.timer = this.setIntervalFn(() => {
123
145
  this.flush();
124
- }, Math.max(250, config?.batchIntervalMs ?? 5e3));
146
+ }, Math.max(250, this.config.batchIntervalMs));
125
147
  const timer = this.timer;
126
148
  if (typeof timer === "object" && timer !== null && "unref" in timer) timer.unref();
127
149
  }
@@ -254,10 +276,7 @@ var LokiDestination = class {
254
276
  return [];
255
277
  }
256
278
  async shutdown() {
257
- if (this.timer !== void 0) {
258
- this.clearIntervalFn(this.timer);
259
- this.timer = void 0;
260
- }
279
+ this.stopTimer();
261
280
  await this.flush();
262
281
  this.config = null;
263
282
  }
@@ -296,6 +315,17 @@ var LokiLoggingAddon = class extends require_dist.BaseAddon {
296
315
  this.destination = null;
297
316
  }
298
317
  /**
318
+ * React to a settings change (enable/disable, URL, level, batching) without a
319
+ * restart — the contract this addon advertises. `BaseAddon` has already
320
+ * reloaded `this.config` by the time this runs; re-apply it to the live
321
+ * destination so toggling `enabled` on actually starts pushing (and off stops
322
+ * it). Without this the destination keeps its boot-time config forever.
323
+ */
324
+ async onConfigChanged() {
325
+ await this.destination?.reconfigure(this.destinationConfig());
326
+ this.ctx.logger.info(this.config.enabled && this.config.url.length > 0 ? `Loki logging reconfigured → ${this.config.url}` : "Loki logging now inactive (disabled or no URL)");
327
+ }
328
+ /**
299
329
  * `node` is a Loki LABEL, so it must be the node's real identity and must not
300
330
  * be operator-editable — a typo would fork the stream and split a node's history
301
331
  * in two. `kernel.localNodeId` is the Moleculer node id (`'hub'` on the hub, the
@@ -113,10 +113,32 @@ var LokiDestination = class {
113
113
  }
114
114
  async initialize(config) {
115
115
  this.config = config ?? null;
116
- if (!this.isActive()) return;
116
+ this.startTimerIfActive();
117
+ }
118
+ /**
119
+ * Re-apply configuration to an already-initialized destination after a
120
+ * settings change, without dropping the queued tail. Stops the current flush
121
+ * timer, swaps the config in, and starts a fresh timer only when the new
122
+ * config is active. This is what makes the addon's "enable without a restart"
123
+ * contract real: `initialize()` starts a timer, so calling it twice would leak
124
+ * the first one — `reconfigure()` clears it first.
125
+ */
126
+ async reconfigure(config) {
127
+ this.stopTimer();
128
+ this.config = config;
129
+ this.startTimerIfActive();
130
+ }
131
+ stopTimer() {
132
+ if (this.timer !== void 0) {
133
+ this.clearIntervalFn(this.timer);
134
+ this.timer = void 0;
135
+ }
136
+ }
137
+ startTimerIfActive() {
138
+ if (!this.isActive() || this.config === null) return;
117
139
  this.timer = this.setIntervalFn(() => {
118
140
  this.flush();
119
- }, Math.max(250, config?.batchIntervalMs ?? 5e3));
141
+ }, Math.max(250, this.config.batchIntervalMs));
120
142
  const timer = this.timer;
121
143
  if (typeof timer === "object" && timer !== null && "unref" in timer) timer.unref();
122
144
  }
@@ -249,10 +271,7 @@ var LokiDestination = class {
249
271
  return [];
250
272
  }
251
273
  async shutdown() {
252
- if (this.timer !== void 0) {
253
- this.clearIntervalFn(this.timer);
254
- this.timer = void 0;
255
- }
274
+ this.stopTimer();
256
275
  await this.flush();
257
276
  this.config = null;
258
277
  }
@@ -291,6 +310,17 @@ var LokiLoggingAddon = class extends BaseAddon {
291
310
  this.destination = null;
292
311
  }
293
312
  /**
313
+ * React to a settings change (enable/disable, URL, level, batching) without a
314
+ * restart — the contract this addon advertises. `BaseAddon` has already
315
+ * reloaded `this.config` by the time this runs; re-apply it to the live
316
+ * destination so toggling `enabled` on actually starts pushing (and off stops
317
+ * it). Without this the destination keeps its boot-time config forever.
318
+ */
319
+ async onConfigChanged() {
320
+ await this.destination?.reconfigure(this.destinationConfig());
321
+ this.ctx.logger.info(this.config.enabled && this.config.url.length > 0 ? `Loki logging reconfigured → ${this.config.url}` : "Loki logging now inactive (disabled or no URL)");
322
+ }
323
+ /**
294
324
  * `node` is a Loki LABEL, so it must be the node's real identity and must not
295
325
  * be operator-editable — a typo would fork the stream and split a node's history
296
326
  * in two. `kernel.localNodeId` is the Moleculer node id (`'hub'` on the hub, the
@@ -60,6 +60,17 @@ export declare class LokiDestination implements ILogDestination {
60
60
  private readonly clearIntervalFn;
61
61
  constructor(deps?: LokiDestinationDeps);
62
62
  initialize(config?: LokiConfig): Promise<void>;
63
+ /**
64
+ * Re-apply configuration to an already-initialized destination after a
65
+ * settings change, without dropping the queued tail. Stops the current flush
66
+ * timer, swaps the config in, and starts a fresh timer only when the new
67
+ * config is active. This is what makes the addon's "enable without a restart"
68
+ * contract real: `initialize()` starts a timer, so calling it twice would leak
69
+ * the first one — `reconfigure()` clears it first.
70
+ */
71
+ reconfigure(config: LokiConfig): Promise<void>;
72
+ private stopTimer;
73
+ private startTimerIfActive;
63
74
  /** Enabled AND pointed somewhere. An enabled destination with no URL is inert. */
64
75
  private isActive;
65
76
  write(entry: LogEntry): void;
@@ -18,6 +18,14 @@ export declare class LokiLoggingAddon extends BaseAddon<LokiAddonConfig> {
18
18
  constructor();
19
19
  protected onInitialize(): Promise<ProviderRegistration[]>;
20
20
  protected onShutdown(): Promise<void>;
21
+ /**
22
+ * React to a settings change (enable/disable, URL, level, batching) without a
23
+ * restart — the contract this addon advertises. `BaseAddon` has already
24
+ * reloaded `this.config` by the time this runs; re-apply it to the live
25
+ * destination so toggling `enabled` on actually starts pushing (and off stops
26
+ * it). Without this the destination keeps its boot-time config forever.
27
+ */
28
+ protected onConfigChanged(): Promise<void>;
21
29
  /**
22
30
  * `node` is a Loki LABEL, so it must be the node's real identity and must not
23
31
  * be operator-editable — a typo would fork the stream and split a node's history
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.17",
3
+ "version": "1.2.18",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",