@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.
Files changed (44) hide show
  1. package/dist/collector-manager.cjs +17 -1
  2. package/dist/collector-manager.d.ts +3 -0
  3. package/dist/collector-manager.d.ts.map +1 -1
  4. package/dist/collector-manager.js +21 -1
  5. package/dist/collector-manager.js.map +1 -1
  6. package/package.json +4 -1
  7. package/.env +0 -13
  8. package/env.sample +0 -13
  9. package/scripts/generate-openapi.mjs +0 -114
  10. package/scripts/lib/cli-utils.mjs +0 -58
  11. package/scripts/prepare-cjs.mjs +0 -44
  12. package/scripts/publish-service.mjs +0 -1119
  13. package/scripts/validate-service.mjs +0 -103
  14. package/scripts/ws-test.mjs +0 -25
  15. package/src/auth.ts +0 -117
  16. package/src/cli/index.ts +0 -725
  17. package/src/collector-manager.ts +0 -1240
  18. package/src/decorators.ts +0 -207
  19. package/src/dependency.ts +0 -211
  20. package/src/dev.ts +0 -17
  21. package/src/discovery.ts +0 -88
  22. package/src/docs.ts +0 -262
  23. package/src/env.ts +0 -148
  24. package/src/errors.ts +0 -55
  25. package/src/federation.ts +0 -559
  26. package/src/index.ts +0 -84
  27. package/src/inventory.ts +0 -491
  28. package/src/logger.ts +0 -727
  29. package/src/message.ts +0 -19
  30. package/src/requester.ts +0 -126
  31. package/src/routing.ts +0 -42
  32. package/src/runtime.ts +0 -1071
  33. package/src/services.ts +0 -459
  34. package/src/storage.ts +0 -206
  35. package/src/types/beamable-sdk-api.d.ts +0 -5
  36. package/src/types.ts +0 -117
  37. package/src/utils/urls.ts +0 -53
  38. package/src/websocket.ts +0 -170
  39. package/test-downloads/collector-test +0 -0
  40. package/test-downloads/collector-test.gz +0 -0
  41. package/tsconfig.base.json +0 -31
  42. package/tsconfig.build.json +0 -10
  43. package/tsconfig.cjs.json +0 -16
  44. package/tsconfig.dev.json +0 -14
package/src/decorators.ts DELETED
@@ -1,207 +0,0 @@
1
- import 'reflect-metadata';
2
- import type { ServiceCallableMetadata, ServiceDefinition, MicroserviceOptions, CallableOptions, ServiceAccess } from './types.js';
3
- import type { DependencyBuilder, DependencyScope } from './dependency.js';
4
-
5
- type ConfigureServicesHandler = (builder: DependencyBuilder) => void | Promise<void>;
6
- type InitializeServicesHandler = (provider: DependencyScope) => void | Promise<void>;
7
-
8
- export type { ConfigureServicesHandler, InitializeServicesHandler };
9
-
10
- const SERVICE_METADATA = new Map<Function, MutableServiceDefinition>();
11
- const PENDING_REGISTRATIONS = new Map<Function, Array<(meta: MutableServiceDefinition) => void>>();
12
- const SWAGGER_TAGS_METADATA_KEY = Symbol('beamable:swaggerTags');
13
- const CONFIGURE_SERVICES_METADATA = new Map<Function, ConfigureServicesHandler[]>();
14
- const INITIALIZE_SERVICES_METADATA = new Map<Function, InitializeServicesHandler[]>();
15
-
16
- interface MutableServiceDefinition {
17
- name: string;
18
- qualifiedName: string;
19
- ctor: new (...args: unknown[]) => unknown;
20
- callables: Map<string, ServiceCallableMetadata>;
21
- options: MicroserviceOptions;
22
- }
23
-
24
- export function Microservice(name: string, options: MicroserviceOptions = {}) {
25
- if (!name || !/^[A-Za-z0-9_]+$/.test(name)) {
26
- throw new Error(`Invalid microservice name "${name}". Only alphanumeric and underscore characters are allowed.`);
27
- }
28
- return function decorator<T extends new (...args: unknown[]) => unknown>(ctor: T): void {
29
- const qualifiedName = `micro_${name}`;
30
- const entry: MutableServiceDefinition = {
31
- name,
32
- qualifiedName,
33
- ctor,
34
- callables: new Map(),
35
- options,
36
- };
37
- SERVICE_METADATA.set(ctor, entry);
38
-
39
- const pending = PENDING_REGISTRATIONS.get(ctor);
40
- if (pending) {
41
- pending.forEach((fn) => fn(entry));
42
- PENDING_REGISTRATIONS.delete(ctor);
43
- }
44
- };
45
- }
46
-
47
- export function Callable(options: CallableOptions = {}) {
48
- return function decorator(
49
- target: unknown,
50
- propertyKey: string,
51
- _descriptor: PropertyDescriptor,
52
- ): void {
53
- let ctorCandidate: unknown;
54
- if (typeof target === 'function') {
55
- ctorCandidate = target;
56
- } else if (target !== null && typeof target === 'object') {
57
- const obj = target as { constructor?: Function };
58
- ctorCandidate = obj.constructor;
59
- }
60
-
61
- if (typeof ctorCandidate !== 'function') {
62
- throw new Error('@Callable can only be applied to methods on a class.');
63
- }
64
- const ctor = ctorCandidate as new (...args: unknown[]) => unknown;
65
- const metadataTarget =
66
- typeof target === 'function'
67
- ? (target as object)
68
- : target !== null && typeof target === 'object'
69
- ? (target as object)
70
- : undefined;
71
-
72
- if (!metadataTarget) {
73
- throw new Error('@Callable decorator received an invalid target.');
74
- }
75
-
76
- const meta = SERVICE_METADATA.get(ctor);
77
- if (!meta) {
78
- const queue = PENDING_REGISTRATIONS.get(ctor) ?? [];
79
- queue.push((lateMeta) => registerCallable(lateMeta, propertyKey, options, metadataTarget));
80
- PENDING_REGISTRATIONS.set(ctor, queue);
81
- return;
82
- }
83
-
84
- registerCallable(meta, propertyKey, options, metadataTarget);
85
- };
86
- }
87
-
88
- function registerCallable(
89
- meta: MutableServiceDefinition,
90
- propertyKey: string,
91
- options: CallableOptions,
92
- metadataTarget: object,
93
- ): void {
94
- const access: ServiceAccess = options.access ?? 'public';
95
- const paramTypes = Reflect.getMetadata('design:paramtypes', metadataTarget, propertyKey) as ReadonlyArray<unknown> | undefined;
96
- const route = options.route ?? propertyKey;
97
- const decoratorTags = (Reflect.getMetadata(SWAGGER_TAGS_METADATA_KEY, metadataTarget, propertyKey) as string[] | undefined) ?? [];
98
- const combinedTags = options.tags ?? decoratorTags;
99
- const tags = Array.from(new Set(combinedTags ?? []));
100
- const metadata: ServiceCallableMetadata = {
101
- route,
102
- displayName: propertyKey,
103
- requireAuth: options.requireAuth ?? access !== 'public',
104
- requiredScopes: options.requiredScopes ?? defaultScopesForAccess(access),
105
- useLegacySerialization: options.useLegacySerialization ?? meta.options.useLegacySerialization ?? false,
106
- parameterTypes: paramTypes ?? [],
107
- access,
108
- tags,
109
- };
110
- const key = route.toLowerCase();
111
- if (meta.callables.has(key)) {
112
- throw new Error(`Duplicate callable route "${route}" on ${meta.ctor.name}.`);
113
- }
114
- meta.callables.set(key, metadata);
115
- }
116
-
117
- function defaultScopesForAccess(access: ServiceAccess): string[] {
118
- switch (access) {
119
- case 'admin':
120
- return ['admin'];
121
- case 'server':
122
- return ['server'];
123
- default:
124
- return [];
125
- }
126
- }
127
-
128
- export function listRegisteredServices(): ServiceDefinition[] {
129
- return Array.from(SERVICE_METADATA.values()).map((entry) => ({
130
- name: entry.name,
131
- qualifiedName: entry.qualifiedName,
132
- ctor: entry.ctor,
133
- callables: new Map(entry.callables),
134
- options: entry.options,
135
- }));
136
- }
137
-
138
- export function getServiceOptions(ctor: Function): MicroserviceOptions | undefined {
139
- return SERVICE_METADATA.get(ctor)?.options;
140
- }
141
-
142
- export type { MicroserviceOptions, CallableOptions };
143
-
144
- export function ClientCallable(options: CallableOptions = {}) {
145
- return Callable({ ...options, access: 'client', requireAuth: true });
146
- }
147
-
148
- export function ServerCallable(options: CallableOptions = {}) {
149
- return Callable({ ...options, access: 'server', requireAuth: true });
150
- }
151
-
152
- export function AdminCallable(options: CallableOptions = {}) {
153
- return Callable({ ...options, access: 'admin', requireAuth: true });
154
- }
155
-
156
- export function SwaggerCategory(category: string) {
157
- return SwaggerTags(category);
158
- }
159
-
160
- export function SwaggerTags(...tags: string[]) {
161
- return function decorator(
162
- target: object,
163
- propertyKey: string,
164
- _descriptor: PropertyDescriptor,
165
- ): void {
166
- if (tags.length === 0) {
167
- return;
168
- }
169
- const current = (Reflect.getMetadata(SWAGGER_TAGS_METADATA_KEY, target, propertyKey) as string[] | undefined) ?? [];
170
- const merged = Array.from(new Set([...current, ...tags]));
171
- Reflect.defineMetadata(SWAGGER_TAGS_METADATA_KEY, merged, target, propertyKey);
172
- };
173
- }
174
-
175
- export function configureServices(target: Function): ConfigureServicesHandler[] {
176
- return CONFIGURE_SERVICES_METADATA.get(target) ?? [];
177
- }
178
-
179
- export function initializeServices(target: Function): InitializeServicesHandler[] {
180
- return INITIALIZE_SERVICES_METADATA.get(target) ?? [];
181
- }
182
-
183
- export function ConfigureServices(target: Function, _propertyKey: string, descriptor: PropertyDescriptor): void {
184
- if (typeof descriptor.value !== 'function') {
185
- throw new Error('@ConfigureServices can only decorate static methods.');
186
- }
187
- const handlers = CONFIGURE_SERVICES_METADATA.get(target) ?? [];
188
- handlers.push(descriptor.value.bind(target));
189
- CONFIGURE_SERVICES_METADATA.set(target, handlers);
190
- }
191
-
192
- export function InitializeServices(target: Function, _propertyKey: string, descriptor: PropertyDescriptor): void {
193
- if (typeof descriptor.value !== 'function') {
194
- throw new Error('@InitializeServices can only decorate static methods.');
195
- }
196
- const handlers = INITIALIZE_SERVICES_METADATA.get(target) ?? [];
197
- handlers.push(descriptor.value.bind(target));
198
- INITIALIZE_SERVICES_METADATA.set(target, handlers);
199
- }
200
-
201
- export function getConfigureServicesHandlers(target: Function): ConfigureServicesHandler[] {
202
- return CONFIGURE_SERVICES_METADATA.get(target) ?? [];
203
- }
204
-
205
- export function getInitializeServicesHandlers(target: Function): InitializeServicesHandler[] {
206
- return INITIALIZE_SERVICES_METADATA.get(target) ?? [];
207
- }
package/src/dependency.ts DELETED
@@ -1,211 +0,0 @@
1
- import 'reflect-metadata';
2
-
3
- export type Constructor<T> = new (...args: any[]) => T;
4
- export type DependencyKey<T = unknown> = Constructor<T> | symbol | string;
5
-
6
- export enum ServiceLifetime {
7
- Singleton = 'singleton',
8
- Scoped = 'scoped',
9
- Transient = 'transient',
10
- }
11
-
12
- export interface DependencyScope {
13
- resolve<T>(key: DependencyKey<T>): T;
14
- }
15
-
16
- export interface MutableDependencyScope extends DependencyScope {
17
- setInstance<T>(key: DependencyKey<T>, value: T): void;
18
- }
19
-
20
- type ServiceFactory<T> = (scope: DependencyScope) => T;
21
-
22
- interface ServiceDescriptor<T = unknown> {
23
- key: DependencyKey<T>;
24
- lifetime: ServiceLifetime;
25
- factory: ServiceFactory<T>;
26
- }
27
-
28
- function isConstructor<T>(key: DependencyKey<T>): key is Constructor<T> {
29
- return typeof key === 'function';
30
- }
31
-
32
- function instantiate<T>(ctor: Constructor<T>, scope: DependencyScope): T {
33
- const paramTypes: Array<Constructor<unknown>> = Reflect.getMetadata('design:paramtypes', ctor) ?? [];
34
- if (paramTypes.length === 0) {
35
- return new ctor();
36
- }
37
- const dependencies = paramTypes.map((param) => {
38
- if (param === Object || param === Array || param === Promise) {
39
- throw new Error(
40
- `Cannot resolve dependency '${param && param.name ? param.name : String(param)}' for ${ctor.name}. ` +
41
- 'Use ConfigureServices to register a factory explicitly.',
42
- );
43
- }
44
- return scope.resolve(param as Constructor<unknown>);
45
- });
46
- return new ctor(...dependencies);
47
- }
48
-
49
- export class DependencyBuilder {
50
- private readonly descriptors = new Map<DependencyKey, ServiceDescriptor<unknown>>();
51
-
52
- addSingleton<T>(key: DependencyKey<T>, factory: ServiceFactory<T>): this {
53
- return this.addDescriptor(key, ServiceLifetime.Singleton, factory);
54
- }
55
-
56
- addSingletonClass<T>(ctor: Constructor<T>): this {
57
- return this.addSingleton(ctor, (scope) => instantiate(ctor, scope));
58
- }
59
-
60
- addSingletonInstance<T>(key: DependencyKey<T>, instance: T): this {
61
- return this.addSingleton(key, () => instance);
62
- }
63
-
64
- addScoped<T>(key: DependencyKey<T>, factory: ServiceFactory<T>): this {
65
- return this.addDescriptor(key, ServiceLifetime.Scoped, factory);
66
- }
67
-
68
- addScopedClass<T>(ctor: Constructor<T>): this {
69
- return this.addScoped(ctor, (scope) => instantiate(ctor, scope));
70
- }
71
-
72
- addTransient<T>(key: DependencyKey<T>, factory: ServiceFactory<T>): this {
73
- return this.addDescriptor(key, ServiceLifetime.Transient, factory);
74
- }
75
-
76
- addTransientClass<T>(ctor: Constructor<T>): this {
77
- return this.addTransient(ctor, (scope) => instantiate(ctor, scope));
78
- }
79
-
80
- tryAddSingleton<T>(key: DependencyKey<T>, factory: ServiceFactory<T>): this {
81
- if (!this.descriptors.has(key)) {
82
- this.addSingleton(key, factory);
83
- }
84
- return this;
85
- }
86
-
87
- tryAddSingletonInstance<T>(key: DependencyKey<T>, instance: T): this {
88
- if (!this.descriptors.has(key)) {
89
- this.addSingletonInstance(key, instance);
90
- }
91
- return this;
92
- }
93
-
94
- build(): ServiceProvider {
95
- return new ServiceProvider(this.descriptors);
96
- }
97
-
98
- private addDescriptor<T>(key: DependencyKey<T>, lifetime: ServiceLifetime, factory: ServiceFactory<T>): this {
99
- if (!key) {
100
- throw new Error('Dependency registration requires a non-empty key.');
101
- }
102
- this.descriptors.set(key, { key, lifetime, factory } as ServiceDescriptor<unknown>);
103
- return this;
104
- }
105
- }
106
-
107
- export class ServiceProvider implements DependencyScope {
108
- private readonly descriptors: Map<DependencyKey, ServiceDescriptor<unknown>>;
109
- private readonly singletons = new Map<DependencyKey, unknown>();
110
-
111
- constructor(descriptors: Map<DependencyKey, ServiceDescriptor<unknown>>) {
112
- this.descriptors = new Map(descriptors);
113
- }
114
-
115
- resolve<T>(key: DependencyKey<T>): T {
116
- const descriptor = this.descriptors.get(key) as ServiceDescriptor<T> | undefined;
117
- if (!descriptor && isConstructor(key)) {
118
- const implicitDescriptor: ServiceDescriptor<T> = {
119
- key,
120
- lifetime: ServiceLifetime.Transient,
121
- factory: (scope) => instantiate(key, scope),
122
- };
123
- this.descriptors.set(key, implicitDescriptor as ServiceDescriptor<unknown>);
124
- return this.resolve(key);
125
- }
126
- if (!descriptor) {
127
- throw new Error(`No service registered for key '${typeof key === 'symbol' ? key.toString() : String(key)}'.`);
128
- }
129
-
130
- switch (descriptor.lifetime) {
131
- case ServiceLifetime.Singleton: {
132
- if (!this.singletons.has(descriptor.key)) {
133
- const value = descriptor.factory(this);
134
- this.singletons.set(descriptor.key, value);
135
- }
136
- return this.singletons.get(descriptor.key) as T;
137
- }
138
- case ServiceLifetime.Scoped:
139
- return descriptor.factory(this);
140
- case ServiceLifetime.Transient:
141
- default:
142
- return descriptor.factory(this);
143
- }
144
- }
145
-
146
- createScope(): ScopedServiceProvider {
147
- return new ScopedServiceProvider(this.descriptors, this.singletons, this);
148
- }
149
- }
150
-
151
- class ScopedServiceProvider implements MutableDependencyScope {
152
- private readonly descriptors: Map<DependencyKey, ServiceDescriptor<unknown>>;
153
- private readonly rootSingletons: Map<DependencyKey, unknown>;
154
- private readonly scopedInstances = new Map<DependencyKey, unknown>();
155
- private readonly rootProvider: ServiceProvider;
156
-
157
- constructor(
158
- descriptors: Map<DependencyKey, ServiceDescriptor<unknown>>,
159
- rootSingletons: Map<DependencyKey, unknown>,
160
- rootProvider: ServiceProvider,
161
- ) {
162
- this.descriptors = descriptors;
163
- this.rootSingletons = rootSingletons;
164
- this.rootProvider = rootProvider;
165
- }
166
-
167
- resolve<T>(key: DependencyKey<T>): T {
168
- const descriptor = this.descriptors.get(key) as ServiceDescriptor<T> | undefined;
169
- if (!descriptor && isConstructor(key)) {
170
- const implicitDescriptor: ServiceDescriptor<T> = {
171
- key,
172
- lifetime: ServiceLifetime.Transient,
173
- factory: (scope) => instantiate(key, scope),
174
- };
175
- this.descriptors.set(key, implicitDescriptor as ServiceDescriptor<unknown>);
176
- return this.resolve(key);
177
- }
178
- if (!descriptor) {
179
- throw new Error(`No service registered for key '${typeof key === 'symbol' ? key.toString() : String(key)}'.`);
180
- }
181
-
182
- switch (descriptor.lifetime) {
183
- case ServiceLifetime.Singleton: {
184
- if (!this.rootSingletons.has(descriptor.key)) {
185
- const value = descriptor.factory(this.rootProvider);
186
- this.rootSingletons.set(descriptor.key, value);
187
- }
188
- return this.rootSingletons.get(descriptor.key) as T;
189
- }
190
- case ServiceLifetime.Scoped: {
191
- if (!this.scopedInstances.has(descriptor.key)) {
192
- const value = descriptor.factory(this);
193
- this.scopedInstances.set(descriptor.key, value);
194
- }
195
- return this.scopedInstances.get(descriptor.key) as T;
196
- }
197
- case ServiceLifetime.Transient:
198
- default:
199
- return descriptor.factory(this);
200
- }
201
- }
202
-
203
- setInstance<T>(key: DependencyKey<T>, value: T): void {
204
- this.scopedInstances.set(key, value);
205
- }
206
- }
207
-
208
- export const LOGGER_TOKEN = Symbol('beamable:logger');
209
- export const ENVIRONMENT_CONFIG_TOKEN = Symbol('beamable:environment');
210
- export const REQUEST_CONTEXT_TOKEN = Symbol('beamable:requestContext');
211
- export const BEAMABLE_SERVICES_TOKEN = Symbol('beamable:services');
package/src/dev.ts DELETED
@@ -1,17 +0,0 @@
1
- import 'dotenv/config';
2
- import { Microservice, Callable } from './decorators.js';
3
- import { runMicroservice } from './runtime.js';
4
- import type { RequestContext } from './types.js';
5
-
6
- @Microservice('ExampleNodeService')
7
- export class ExampleService {
8
- @Callable()
9
- async echo(ctx: RequestContext, message: string): Promise<{ message: string; playerId: number }> {
10
- return {
11
- message,
12
- playerId: ctx.userId,
13
- };
14
- }
15
- }
16
-
17
- void runMicroservice();
package/src/discovery.ts DELETED
@@ -1,88 +0,0 @@
1
- import dgram from 'node:dgram';
2
- import type { Logger } from 'pino';
3
- import type { EnvironmentConfig } from './types.js';
4
-
5
- const DISCOVERY_PORT = 8624;
6
- const BROADCAST_PERIOD_MS = 10;
7
-
8
- interface DiscoveryOptions {
9
- env: EnvironmentConfig;
10
- serviceName: string;
11
- routingKey: string | undefined; // undefined for deployed services
12
- logger: Logger;
13
- }
14
-
15
- export class DiscoveryBroadcaster {
16
- private readonly socket = dgram.createSocket('udp4');
17
- private readonly payload: Buffer;
18
- private interval?: NodeJS.Timeout;
19
- private disposed = false;
20
-
21
- constructor(private readonly options: DiscoveryOptions) {
22
- const message = {
23
- processId: process.pid,
24
- cid: options.env.cid,
25
- pid: options.env.pid,
26
- prefix: options.routingKey,
27
- serviceName: options.serviceName,
28
- healthPort: options.env.healthPort,
29
- serviceType: 'service',
30
- startedByAccountId: options.env.accountId ?? 0,
31
- isContainer: false,
32
- dataPort: 0,
33
- containerId: '',
34
- } satisfies Record<string, unknown>;
35
-
36
- this.payload = Buffer.from(JSON.stringify(message), 'utf8');
37
-
38
- this.socket.on('error', (err) => {
39
- options.logger.warn({ err }, 'Discovery broadcaster socket error.');
40
- });
41
- }
42
-
43
- async start(): Promise<void> {
44
- if (this.disposed) {
45
- return;
46
- }
47
-
48
- await new Promise<void>((resolve, reject) => {
49
- const onError = (error: Error) => {
50
- this.socket.off('error', onError);
51
- reject(error);
52
- };
53
- this.socket.once('error', onError);
54
- this.socket.bind(0, undefined, () => {
55
- try {
56
- this.socket.setBroadcast(true);
57
- this.socket.off('error', onError);
58
- resolve();
59
- } catch (error) {
60
- this.socket.off('error', onError);
61
- reject(error);
62
- }
63
- });
64
- });
65
-
66
- this.interval = setInterval(() => {
67
- this.socket.send(this.payload, DISCOVERY_PORT, '255.255.255.255', (error) => {
68
- if (error) {
69
- this.options.logger.debug({ err: error }, 'Discovery broadcast send failed.');
70
- }
71
- });
72
- }, BROADCAST_PERIOD_MS);
73
- this.interval.unref();
74
- }
75
-
76
- stop(): void {
77
- this.disposed = true;
78
- if (this.interval) {
79
- clearInterval(this.interval);
80
- this.interval = undefined;
81
- }
82
- try {
83
- this.socket.close();
84
- } catch (error) {
85
- this.options.logger.debug({ err: error }, 'Error closing discovery broadcaster socket.');
86
- }
87
- }
88
- }