@omen.foundation/node-microservice-runtime 0.1.64 → 0.1.67
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/collector-manager.cjs +17 -1
- package/dist/collector-manager.d.ts +3 -0
- package/dist/collector-manager.d.ts.map +1 -1
- package/dist/collector-manager.js +21 -1
- package/dist/collector-manager.js.map +1 -1
- package/package.json +4 -1
- package/.env +0 -13
- package/env.sample +0 -13
- package/scripts/generate-openapi.mjs +0 -114
- package/scripts/lib/cli-utils.mjs +0 -58
- package/scripts/prepare-cjs.mjs +0 -44
- package/scripts/publish-service.mjs +0 -1119
- package/scripts/validate-service.mjs +0 -103
- package/scripts/ws-test.mjs +0 -25
- package/src/auth.ts +0 -117
- package/src/cli/index.ts +0 -725
- package/src/collector-manager.ts +0 -1240
- package/src/decorators.ts +0 -207
- package/src/dependency.ts +0 -211
- package/src/dev.ts +0 -17
- package/src/discovery.ts +0 -88
- package/src/docs.ts +0 -262
- package/src/env.ts +0 -148
- package/src/errors.ts +0 -55
- package/src/federation.ts +0 -559
- package/src/index.ts +0 -84
- package/src/inventory.ts +0 -491
- package/src/logger.ts +0 -727
- package/src/message.ts +0 -19
- package/src/requester.ts +0 -126
- package/src/routing.ts +0 -42
- package/src/runtime.ts +0 -1071
- package/src/services.ts +0 -459
- package/src/storage.ts +0 -206
- package/src/types/beamable-sdk-api.d.ts +0 -5
- package/src/types.ts +0 -117
- package/src/utils/urls.ts +0 -53
- package/src/websocket.ts +0 -170
- package/test-downloads/collector-test +0 -0
- package/test-downloads/collector-test.gz +0 -0
- package/tsconfig.base.json +0 -31
- package/tsconfig.build.json +0 -10
- package/tsconfig.cjs.json +0 -16
- package/tsconfig.dev.json +0 -14
package/src/types.ts
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import type { Logger } from 'pino';
|
|
2
|
-
import type { BeamableMicroserviceServices } from './services.js';
|
|
3
|
-
import type { DependencyScope } from './dependency.js';
|
|
4
|
-
|
|
5
|
-
export type ServiceAccess = 'public' | 'client' | 'server' | 'admin';
|
|
6
|
-
|
|
7
|
-
export interface MicroserviceOptions {
|
|
8
|
-
/** When true, legacy serialization is enabled for every callable unless overridden per method. */
|
|
9
|
-
useLegacySerialization?: boolean;
|
|
10
|
-
/** When true the runtime will skip auto-registration for Beamable events. */
|
|
11
|
-
disableAllBeamableEvents?: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface CallableOptions {
|
|
15
|
-
/** Optional explicit route name. Defaults to the method name. */
|
|
16
|
-
route?: string;
|
|
17
|
-
/** Whether an authenticated user is required for invocation. */
|
|
18
|
-
requireAuth?: boolean;
|
|
19
|
-
/** Scopes required for the invocation. */
|
|
20
|
-
requiredScopes?: string[];
|
|
21
|
-
/** Override legacy serialization behaviour for this callable. */
|
|
22
|
-
useLegacySerialization?: boolean;
|
|
23
|
-
access?: ServiceAccess;
|
|
24
|
-
/** Optional OpenAPI/Swagger tags to apply to the callable. */
|
|
25
|
-
tags?: string[];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface EnvironmentConfig {
|
|
29
|
-
cid: string;
|
|
30
|
-
pid: string;
|
|
31
|
-
host: string;
|
|
32
|
-
secret?: string;
|
|
33
|
-
refreshToken?: string;
|
|
34
|
-
routingKey?: string; // undefined for deployed services (becomes None in Scala)
|
|
35
|
-
accountId?: number;
|
|
36
|
-
accountEmail?: string;
|
|
37
|
-
logLevel: string;
|
|
38
|
-
healthPort: number;
|
|
39
|
-
disableCustomInitializationHooks: boolean;
|
|
40
|
-
watchToken: boolean;
|
|
41
|
-
sdkVersionExecution: string;
|
|
42
|
-
beamInstanceCount: number;
|
|
43
|
-
logTruncateLimit: number;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface GatewayRequest {
|
|
47
|
-
id: number;
|
|
48
|
-
method: string;
|
|
49
|
-
path: string;
|
|
50
|
-
from?: number;
|
|
51
|
-
body?: unknown;
|
|
52
|
-
scopes?: string[];
|
|
53
|
-
headers?: Record<string, string>;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface GatewayResponse<T = unknown> {
|
|
57
|
-
id: number;
|
|
58
|
-
status: number;
|
|
59
|
-
body: T;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface WebsocketEventEnvelope {
|
|
63
|
-
id: number;
|
|
64
|
-
status: number;
|
|
65
|
-
path?: string;
|
|
66
|
-
method?: string;
|
|
67
|
-
body?: unknown;
|
|
68
|
-
from?: number;
|
|
69
|
-
scopes?: string[];
|
|
70
|
-
headers?: Record<string, string>;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface RequestContext {
|
|
74
|
-
id: number;
|
|
75
|
-
path: string;
|
|
76
|
-
method: string;
|
|
77
|
-
status: number;
|
|
78
|
-
userId: number;
|
|
79
|
-
payload?: unknown;
|
|
80
|
-
body?: Record<string, unknown>;
|
|
81
|
-
scopes: Set<string>;
|
|
82
|
-
headers: Record<string, string>;
|
|
83
|
-
cid: string;
|
|
84
|
-
pid: string;
|
|
85
|
-
services: BeamableMicroserviceServices;
|
|
86
|
-
throwIfCancelled(): void;
|
|
87
|
-
isCancelled(): boolean;
|
|
88
|
-
hasScopes(...scopes: string[]): boolean;
|
|
89
|
-
requireScopes(...scopes: string[]): void;
|
|
90
|
-
provider: DependencyScope;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export interface ServiceCallableMetadata {
|
|
94
|
-
route: string;
|
|
95
|
-
displayName: string;
|
|
96
|
-
requireAuth: boolean;
|
|
97
|
-
requiredScopes: string[];
|
|
98
|
-
useLegacySerialization: boolean;
|
|
99
|
-
parameterTypes: ReadonlyArray<unknown>;
|
|
100
|
-
access: ServiceAccess;
|
|
101
|
-
tags: string[];
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export interface ServiceDefinition {
|
|
105
|
-
name: string;
|
|
106
|
-
qualifiedName: string;
|
|
107
|
-
ctor: new (...args: unknown[]) => unknown;
|
|
108
|
-
callables: Map<string, ServiceCallableMetadata>;
|
|
109
|
-
options?: MicroserviceOptions;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export interface RuntimeComponents {
|
|
113
|
-
env: EnvironmentConfig;
|
|
114
|
-
logger: Logger;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };
|
package/src/utils/urls.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
export function hostToHttpUrl(host: string): string {
|
|
2
|
-
const normalized = host.replace(/\/$/, '');
|
|
3
|
-
if (normalized.startsWith('wss://')) {
|
|
4
|
-
return `https://${normalized.substring('wss://'.length).replace(/\/socket$/, '')}`;
|
|
5
|
-
}
|
|
6
|
-
if (normalized.startsWith('ws://')) {
|
|
7
|
-
return `http://${normalized.substring('ws://'.length).replace(/\/socket$/, '')}`;
|
|
8
|
-
}
|
|
9
|
-
return normalized.replace(/\/socket$/, '');
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function transformApiHostname(hostname: string, replacement: string): string {
|
|
13
|
-
let host = hostname;
|
|
14
|
-
if (host.startsWith('dev.')) {
|
|
15
|
-
host = host.replace('dev.', 'dev-');
|
|
16
|
-
}
|
|
17
|
-
if (host.startsWith('api.')) {
|
|
18
|
-
return host.replace('api.', `${replacement}.`);
|
|
19
|
-
}
|
|
20
|
-
if (host.startsWith('api-')) {
|
|
21
|
-
return host.replace('api-', `${replacement}-`);
|
|
22
|
-
}
|
|
23
|
-
const index = host.indexOf('api');
|
|
24
|
-
if (index >= 0) {
|
|
25
|
-
return `${host.slice(0, index)}${replacement}${host.slice(index + 3)}`;
|
|
26
|
-
}
|
|
27
|
-
return host;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function transformHost(httpHost: string, replacement: string): string {
|
|
31
|
-
try {
|
|
32
|
-
const url = new URL(httpHost);
|
|
33
|
-
url.hostname = transformApiHostname(url.hostname, replacement);
|
|
34
|
-
url.pathname = '/';
|
|
35
|
-
url.search = '';
|
|
36
|
-
url.hash = '';
|
|
37
|
-
return url.toString().replace(/\/$/, '');
|
|
38
|
-
} catch (error) {
|
|
39
|
-
return transformApiHostname(httpHost, replacement);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function hostToPortalUrl(httpHost: string): string {
|
|
44
|
-
return transformHost(httpHost, 'portal');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function hostToStorageUrl(httpHost: string): string {
|
|
48
|
-
return transformHost(httpHost, 'storage');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function hostToMicroserviceRegistryUrl(httpHost: string): string {
|
|
52
|
-
return transformHost(httpHost, 'microservices');
|
|
53
|
-
}
|
package/src/websocket.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import { setTimeout as sleep } from 'node:timers/promises';
|
|
2
|
-
import { EventEmitter } from 'node:events';
|
|
3
|
-
import WebSocket from 'ws';
|
|
4
|
-
import type { Logger } from 'pino';
|
|
5
|
-
|
|
6
|
-
export interface WebSocketOptions {
|
|
7
|
-
logger: Logger;
|
|
8
|
-
url: string;
|
|
9
|
-
maxRetries?: number;
|
|
10
|
-
retryDelayMs?: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface WebSocketEvents {
|
|
14
|
-
open: [];
|
|
15
|
-
close: [wasClean: boolean];
|
|
16
|
-
message: [payload: string];
|
|
17
|
-
error: [error: Error];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class BeamableWebSocket {
|
|
21
|
-
private readonly logger: Logger;
|
|
22
|
-
private readonly url: string;
|
|
23
|
-
private readonly maxRetries: number;
|
|
24
|
-
private readonly retryDelayMs: number;
|
|
25
|
-
private readonly emitter = new EventEmitter();
|
|
26
|
-
|
|
27
|
-
private socket: WebSocket | null = null;
|
|
28
|
-
private isDisposed = false;
|
|
29
|
-
|
|
30
|
-
constructor(options: WebSocketOptions) {
|
|
31
|
-
this.logger = options.logger.child({ component: 'BeamableWebSocket' });
|
|
32
|
-
this.url = options.url;
|
|
33
|
-
this.maxRetries = options.maxRetries ?? 20;
|
|
34
|
-
this.retryDelayMs = options.retryDelayMs ?? 1000;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
on(event: string, listener: (...args: unknown[]) => void): this {
|
|
38
|
-
this.emitter.on(event, listener);
|
|
39
|
-
return this;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
off(event: string, listener: (...args: unknown[]) => void): this {
|
|
43
|
-
this.emitter.off(event, listener);
|
|
44
|
-
return this;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
private emit<Event extends keyof WebSocketEvents>(event: Event, ...args: WebSocketEvents[Event]): void {
|
|
48
|
-
this.emitter.emit(event, ...args);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async connect(): Promise<void> {
|
|
52
|
-
let attempt = 0;
|
|
53
|
-
while (!this.isDisposed) {
|
|
54
|
-
try {
|
|
55
|
-
attempt += 1;
|
|
56
|
-
await this.createSocket();
|
|
57
|
-
return;
|
|
58
|
-
} catch (error) {
|
|
59
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
60
|
-
this.logger.warn({ err, attempt }, 'WebSocket connection attempt failed.');
|
|
61
|
-
if (attempt >= this.maxRetries) {
|
|
62
|
-
throw err;
|
|
63
|
-
}
|
|
64
|
-
await sleep(this.retryDelayMs * attempt);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
throw new Error('WebSocket disposed before connection could be established.');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private async createSocket(): Promise<void> {
|
|
71
|
-
if (this.socket) {
|
|
72
|
-
this.socket.removeAllListeners();
|
|
73
|
-
this.socket.terminate();
|
|
74
|
-
this.socket = null;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return new Promise((resolve, reject) => {
|
|
78
|
-
const ws = new WebSocket(this.url, {
|
|
79
|
-
perMessageDeflate: true,
|
|
80
|
-
handshakeTimeout: 30_000,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const handleOpen = () => {
|
|
84
|
-
this.logger.info({ url: this.url }, 'WebSocket connected.');
|
|
85
|
-
this.socket = ws;
|
|
86
|
-
ws.off('error', handleError);
|
|
87
|
-
ws.off('close', handlePrematureClose);
|
|
88
|
-
this.registerSocketHandlers(ws);
|
|
89
|
-
this.emit('open');
|
|
90
|
-
resolve();
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const handleError = (error: Error) => {
|
|
94
|
-
ws.off('open', handleOpen);
|
|
95
|
-
ws.off('close', handlePrematureClose);
|
|
96
|
-
reject(error);
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const handlePrematureClose = (code: number, reason: Buffer) => {
|
|
100
|
-
ws.off('open', handleOpen);
|
|
101
|
-
ws.off('error', handleError);
|
|
102
|
-
const err = new Error(`WebSocket closed before open handshake. code=${code} reason=${reason.toString()}`);
|
|
103
|
-
reject(err);
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
ws.on('open', handleOpen);
|
|
107
|
-
ws.on('error', handleError);
|
|
108
|
-
ws.on('close', handlePrematureClose);
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
private registerSocketHandlers(ws: WebSocket): void {
|
|
113
|
-
ws.on('message', (data) => {
|
|
114
|
-
const payload = typeof data === 'string' ? data : data.toString('utf8');
|
|
115
|
-
this.logger.debug({ payload }, 'WebSocket received frame.');
|
|
116
|
-
this.emit('message', payload);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
ws.on('close', (code, reason) => {
|
|
120
|
-
this.logger.warn({ code, reason: reason.toString() }, 'WebSocket closed.');
|
|
121
|
-
this.emit('close', code === 1000);
|
|
122
|
-
if (!this.isDisposed) {
|
|
123
|
-
void this.reconnect();
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
ws.on('error', (error) => {
|
|
128
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
129
|
-
this.logger.error({ err }, 'WebSocket error.');
|
|
130
|
-
this.emit('error', err);
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private async reconnect(): Promise<void> {
|
|
135
|
-
this.logger.info('Attempting to reconnect websocket.');
|
|
136
|
-
let attempt = 0;
|
|
137
|
-
while (!this.isDisposed) {
|
|
138
|
-
try {
|
|
139
|
-
attempt += 1;
|
|
140
|
-
await this.createSocket();
|
|
141
|
-
this.emit('open');
|
|
142
|
-
return;
|
|
143
|
-
} catch (error) {
|
|
144
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
145
|
-
this.logger.warn({ err, attempt }, 'Retrying websocket connection.');
|
|
146
|
-
await sleep(this.retryDelayMs * Math.min(attempt, 10));
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async send(text: string): Promise<void> {
|
|
152
|
-
if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
|
|
153
|
-
throw new Error('WebSocket is not connected.');
|
|
154
|
-
}
|
|
155
|
-
this.logger.debug({ message: text }, 'Sending websocket frame.');
|
|
156
|
-
this.socket.send(text);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async close(): Promise<void> {
|
|
160
|
-
this.isDisposed = true;
|
|
161
|
-
if (!this.socket) {
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
const ws = this.socket;
|
|
165
|
-
if (ws.readyState === WebSocket.CLOSED || ws.readyState === WebSocket.CLOSING) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
ws.close(1000, 'shutdown');
|
|
169
|
-
}
|
|
170
|
-
}
|
|
Binary file
|
|
Binary file
|
package/tsconfig.base.json
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"esModuleInterop": true,
|
|
7
|
-
"forceConsistentCasingInFileNames": true,
|
|
8
|
-
"strict": true,
|
|
9
|
-
"skipLibCheck": false,
|
|
10
|
-
"noImplicitOverride": true,
|
|
11
|
-
"noUnusedLocals": true,
|
|
12
|
-
"noUnusedParameters": true,
|
|
13
|
-
"resolveJsonModule": true,
|
|
14
|
-
"sourceMap": true,
|
|
15
|
-
"inlineSources": true,
|
|
16
|
-
"experimentalDecorators": true,
|
|
17
|
-
"emitDecoratorMetadata": true,
|
|
18
|
-
"types": [
|
|
19
|
-
"node"
|
|
20
|
-
],
|
|
21
|
-
"rootDir": "src"
|
|
22
|
-
},
|
|
23
|
-
"include": [
|
|
24
|
-
"src/**/*.ts",
|
|
25
|
-
"src/**/*.d.ts"
|
|
26
|
-
],
|
|
27
|
-
"exclude": [
|
|
28
|
-
"dist",
|
|
29
|
-
"node_modules"
|
|
30
|
-
]
|
|
31
|
-
}
|
package/tsconfig.build.json
DELETED
package/tsconfig.cjs.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "dist-cjs",
|
|
5
|
-
"declaration": false,
|
|
6
|
-
"sourceMap": false,
|
|
7
|
-
"inlineSources": false,
|
|
8
|
-
"module": "CommonJS",
|
|
9
|
-
"moduleResolution": "Node",
|
|
10
|
-
"target": "ES2019",
|
|
11
|
-
"removeComments": true
|
|
12
|
-
},
|
|
13
|
-
"exclude": [
|
|
14
|
-
"src/cli/**/*"
|
|
15
|
-
]
|
|
16
|
-
}
|
package/tsconfig.dev.json
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.base.json",
|
|
3
|
-
"ts-node": {
|
|
4
|
-
"esm": true,
|
|
5
|
-
"experimentalSpecifierResolution": "node"
|
|
6
|
-
},
|
|
7
|
-
"compilerOptions": {
|
|
8
|
-
"module": "NodeNext",
|
|
9
|
-
"moduleResolution": "NodeNext",
|
|
10
|
-
"sourceMap": true,
|
|
11
|
-
"inlineSourceMap": false,
|
|
12
|
-
"outDir": "dist-dev"
|
|
13
|
-
}
|
|
14
|
-
}
|