@syncbridge/common 0.6.1 → 0.6.2

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.
@@ -14,7 +14,7 @@ export declare abstract class BaseElement<TEvents extends BaseElement.Events = B
14
14
  get status(): ServiceStatus;
15
15
  get statusMessage(): string;
16
16
  protected _init(): Promise<void>;
17
- protected _start(abortSignal: AbortSignal): Promise<void>;
17
+ protected _start(abortSignal?: AbortSignal): Promise<void>;
18
18
  protected _stop(): Promise<void>;
19
19
  protected onStatusChange(): void;
20
20
  }
@@ -26,6 +26,7 @@ export class BaseElement extends Runnable {
26
26
  async _init() {
27
27
  for (const component of Object.values(this.components)) {
28
28
  component.on('status-change', (status, statusMessage) => {
29
+ component.on('component-status-change', (...args) => this.emitAsyncSafe('component-status-change', ...args));
29
30
  /** Reset counters */
30
31
  this._context.statusIndicators = this._context.statusIndicators || {};
31
32
  Object.keys(ServiceStatus).forEach(key => {
@@ -42,7 +43,8 @@ export class BaseElement extends Runnable {
42
43
  counter.componentNames.push(comp.name);
43
44
  });
44
45
  this.emitSafe('component-status-change', component, status, statusMessage);
45
- if (this._context.status !== this._context.calculatedStatus)
46
+ if (this._context.status !== this._context.calculatedStatus ||
47
+ this._context.statusMessage !== this._context.statusMessage)
46
48
  this.onStatusChange();
47
49
  });
48
50
  }
@@ -60,8 +62,6 @@ export class BaseElement extends Runnable {
60
62
  .map(component => component.stop()));
61
63
  }
62
64
  onStatusChange() {
63
- const oldStatus = this.status;
64
- const oldStatusMessage = this.statusMessage;
65
65
  this._context.calculatedStatus = this._context.status;
66
66
  this._context.calculatedStatusMessage = this._context.statusMessage;
67
67
  if (!(this.status === ServiceStatus.stopped ||
@@ -72,13 +72,10 @@ export class BaseElement extends Runnable {
72
72
  if (indicator?.count) {
73
73
  this._context.calculatedStatus = _status;
74
74
  this._context.calculatedStatusMessage = `${_status} components: ${indicator.componentNames}`;
75
- return;
75
+ break;
76
76
  }
77
77
  }
78
78
  }
79
- if (this.status !== oldStatus || this.statusMessage !== oldStatusMessage) {
80
- this.logger?.debug(this.status);
81
- super.onStatusChange();
82
- }
79
+ super.onStatusChange();
83
80
  }
84
81
  }
@@ -5,6 +5,7 @@ import { ServiceStatus } from '../models/index.js';
5
5
  */
6
6
  export declare abstract class Runnable<T extends Runnable.Events = Runnable.Events> extends AsyncEventEmitter<EventMap<T>> {
7
7
  protected _context: Runnable.Context;
8
+ private _startAbortController?;
8
9
  constructor(init?: Runnable.InitArgs);
9
10
  get status(): ServiceStatus;
10
11
  get statusMessage(): string;
@@ -34,7 +35,7 @@ export declare abstract class Runnable<T extends Runnable.Events = Runnable.Even
34
35
  /**
35
36
  *
36
37
  */
37
- protected abstract _start(abortSignal: AbortSignal): Promise<void>;
38
+ protected abstract _start(abortSignal?: AbortSignal): Promise<void>;
38
39
  /**
39
40
  *
40
41
  */
@@ -8,6 +8,7 @@ import { SbError } from './sb-error.js';
8
8
  */
9
9
  export class Runnable extends AsyncEventEmitter {
10
10
  _context;
11
+ _startAbortController;
11
12
  constructor(init) {
12
13
  super();
13
14
  this.setMaxListeners(1000);
@@ -67,6 +68,9 @@ export class Runnable extends AsyncEventEmitter {
67
68
  if (this.status === ServiceStatus.started)
68
69
  return;
69
70
  this.setStatus(ServiceStatus.starting);
71
+ const abortController = (this._startAbortController =
72
+ new AbortController());
73
+ abortSignal?.addEventListener('abort', () => abortController.abort());
70
74
  this._context.waitTimer = Promise.resolve()
71
75
  .then(async () => {
72
76
  await this.init();
@@ -74,8 +78,6 @@ export class Runnable extends AsyncEventEmitter {
74
78
  let promiseSettled = false;
75
79
  await new Promise((resolve, reject) => {
76
80
  let startWaitTimer;
77
- const abortController = new AbortController();
78
- abortSignal?.addEventListener('abort', () => abortController.abort());
79
81
  if (this._context.startMaxWaitMs) {
80
82
  startWaitTimer = setTimeout(() => {
81
83
  const err = new SbError('Start timeout', {
@@ -124,6 +126,7 @@ export class Runnable extends AsyncEventEmitter {
124
126
  });
125
127
  })
126
128
  .finally(() => {
129
+ this._startAbortController = undefined;
127
130
  this._context.waitTimer = undefined;
128
131
  });
129
132
  await this._context.waitTimer;
@@ -132,12 +135,13 @@ export class Runnable extends AsyncEventEmitter {
132
135
  *
133
136
  */
134
137
  async stop() {
135
- if (this._context.waitTimer)
136
- await this._context.waitTimer;
137
138
  if (this.status === ServiceStatus.stopped)
138
139
  return;
139
140
  this.setStatus(ServiceStatus.stopping);
140
141
  this.emit('stopping');
142
+ this._startAbortController?.abort();
143
+ if (this._context.waitTimer)
144
+ await this._context.waitTimer;
141
145
  this._context.waitTimer = Promise.resolve()
142
146
  .then(async () => {
143
147
  try {
@@ -5,6 +5,7 @@ export declare class SbError extends Error implements ErrorIssue {
5
5
  code?: string;
6
6
  [index: string]: any;
7
7
  constructor(message?: string | Error, options?: SbErrorOptions);
8
+ toJSON(): any;
8
9
  }
9
10
  export interface SbErrorOptions extends Partial<ErrorIssue> {
10
11
  cause?: Error;
@@ -42,6 +42,15 @@ export class SbError extends Error {
42
42
  }
43
43
  }
44
44
  }
45
+ toJSON() {
46
+ const out = {
47
+ message: this.message,
48
+ };
49
+ for (const k of Object.keys(this)) {
50
+ out[k] = this[k];
51
+ }
52
+ return out;
53
+ }
45
54
  }
46
55
  /**
47
56
  *
@@ -32,15 +32,22 @@ export class StackExecutor {
32
32
  if (e instanceof ValidationError) {
33
33
  e.issues.forEach(x => {
34
34
  const issue = new SbValidationError(x.message, x);
35
- x.severity = x.severity ?? 'error';
36
- x.location = location + (x.location ? '/' + x.location : '');
35
+ issue.severity = x.severity ?? 'error';
36
+ issue.location = location + (x.location ? '/' + x.location : '');
37
+ issue.stack = x.stack;
37
38
  this.issues.push(issue);
38
39
  });
39
40
  }
40
41
  else {
41
- e.severity = e.severity ?? 'error';
42
- e.location = location;
43
- this.issues.push(e);
42
+ const issue = {
43
+ message: e.message,
44
+ severity: e.severity || 'error',
45
+ location,
46
+ stack: e.stack,
47
+ ...e,
48
+ };
49
+ Object.setPrototypeOf(issue, Object.getPrototypeOf(e));
50
+ this.issues.push(issue);
44
51
  }
45
52
  }
46
53
  }
package/constants.js CHANGED
@@ -1,4 +1,4 @@
1
- export const version = '0.6.1';
1
+ export const version = '0.6.2';
2
2
  export const OWN_ELEMENT_METADATA = Symbol.for('OWN_ELEMENT_METADATA');
3
3
  export const COMPONENT_OPTIONS = Symbol.for('COMPONENT_OPTIONS');
4
4
  export const PROCESSOR_OPTIONS = Symbol.for('PROCESSOR_OPTIONS');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncbridge/common",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "SyncBridge Common utilities",
5
5
  "author": "Panates Inc",
6
6
  "license": "MIT",
@@ -97,7 +97,7 @@ export var ProcessorFactory;
97
97
  oldMetadata?.className !== newMetadata.className)
98
98
  throw new SbError('Cannot change component class while processor running. You should stop it first.');
99
99
  /** Validate sub components */
100
- if (childMetadata.components) {
100
+ if (childMetadata.components && componentInstance) {
101
101
  _validateComponents({
102
102
  ...ctx,
103
103
  owner: componentInstance,
@@ -14,6 +14,10 @@ export function decodeProfile(materializedMetadata, rawProfile, options) {
14
14
  issues
15
15
  .map(issue => `- ${issue.message}. Location: /${issue.location}`)
16
16
  .join('\n ');
17
+ issues.forEach(issue => {
18
+ if (issue instanceof SbValidationError)
19
+ delete issue.stack;
20
+ });
17
21
  throw new SbValidationError(msg, {
18
22
  workerId: rawProfile.id,
19
23
  issues,
@@ -13,6 +13,10 @@ export function materializeMetadata(profile) {
13
13
  issues
14
14
  .map(issue => `- ${issue.message}. Location: /${issue.location}`)
15
15
  .join('\n ');
16
+ issues.forEach(issue => {
17
+ if (issue instanceof SbValidationError)
18
+ delete issue.stack;
19
+ });
16
20
  throw new SbValidationError(msg, {
17
21
  workerId: profile.id,
18
22
  issues,