@omen.foundation/node-microservice-runtime 0.1.75 → 0.1.77
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/auth.cjs +97 -0
- package/dist/cli/commands/scaffold.js +17 -1
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/collector-manager.cjs +957 -0
- package/dist/decorators.cjs +181 -0
- package/dist/dependency.cjs +165 -0
- package/dist/dev.cjs +34 -0
- package/dist/discovery.cjs +79 -0
- package/dist/docs.cjs +206 -0
- package/dist/env-loader.cjs +187 -0
- package/dist/env-loader.d.ts +7 -0
- package/dist/env-loader.d.ts.map +1 -1
- package/dist/env-loader.js +20 -0
- package/dist/env-loader.js.map +1 -1
- package/dist/env.cjs +125 -0
- package/dist/errors.cjs +58 -0
- package/dist/federation.cjs +356 -0
- package/dist/index.cjs +66 -0
- package/dist/inventory.cjs +361 -0
- package/dist/logger.cjs +545 -0
- package/dist/message.cjs +19 -0
- package/dist/requester.cjs +100 -0
- package/dist/routing.cjs +39 -0
- package/dist/runtime.cjs +841 -0
- package/dist/runtime.d.ts +13 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +74 -21
- package/dist/runtime.js.map +1 -1
- package/dist/services.cjs +356 -0
- package/dist/storage.cjs +147 -0
- package/dist/types.cjs +2 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/urls.cjs +55 -0
- package/dist/websocket.cjs +142 -0
- package/package.json +1 -1
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Microservice = Microservice;
|
|
4
|
+
exports.Callable = Callable;
|
|
5
|
+
exports.listRegisteredServices = listRegisteredServices;
|
|
6
|
+
exports.getServiceOptions = getServiceOptions;
|
|
7
|
+
exports.ClientCallable = ClientCallable;
|
|
8
|
+
exports.ServerCallable = ServerCallable;
|
|
9
|
+
exports.AdminCallable = AdminCallable;
|
|
10
|
+
exports.SwaggerCategory = SwaggerCategory;
|
|
11
|
+
exports.SwaggerTags = SwaggerTags;
|
|
12
|
+
exports.configureServices = configureServices;
|
|
13
|
+
exports.initializeServices = initializeServices;
|
|
14
|
+
exports.ConfigureServices = ConfigureServices;
|
|
15
|
+
exports.InitializeServices = InitializeServices;
|
|
16
|
+
exports.getConfigureServicesHandlers = getConfigureServicesHandlers;
|
|
17
|
+
exports.getInitializeServicesHandlers = getInitializeServicesHandlers;
|
|
18
|
+
require("reflect-metadata");
|
|
19
|
+
const SERVICE_METADATA = new Map();
|
|
20
|
+
const PENDING_REGISTRATIONS = new Map();
|
|
21
|
+
const SWAGGER_TAGS_METADATA_KEY = Symbol('beamable:swaggerTags');
|
|
22
|
+
const CONFIGURE_SERVICES_METADATA = new Map();
|
|
23
|
+
const INITIALIZE_SERVICES_METADATA = new Map();
|
|
24
|
+
function Microservice(name, options = {}) {
|
|
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(ctor) {
|
|
29
|
+
const qualifiedName = `micro_${name}`;
|
|
30
|
+
const entry = {
|
|
31
|
+
name,
|
|
32
|
+
qualifiedName,
|
|
33
|
+
ctor,
|
|
34
|
+
callables: new Map(),
|
|
35
|
+
options,
|
|
36
|
+
};
|
|
37
|
+
SERVICE_METADATA.set(ctor, entry);
|
|
38
|
+
const pending = PENDING_REGISTRATIONS.get(ctor);
|
|
39
|
+
if (pending) {
|
|
40
|
+
pending.forEach((fn) => fn(entry));
|
|
41
|
+
PENDING_REGISTRATIONS.delete(ctor);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function Callable(options = {}) {
|
|
46
|
+
return function decorator(target, propertyKey, _descriptor) {
|
|
47
|
+
var _a;
|
|
48
|
+
let ctorCandidate;
|
|
49
|
+
if (typeof target === 'function') {
|
|
50
|
+
ctorCandidate = target;
|
|
51
|
+
}
|
|
52
|
+
else if (target !== null && typeof target === 'object') {
|
|
53
|
+
const obj = target;
|
|
54
|
+
ctorCandidate = obj.constructor;
|
|
55
|
+
}
|
|
56
|
+
if (typeof ctorCandidate !== 'function') {
|
|
57
|
+
throw new Error('@Callable can only be applied to methods on a class.');
|
|
58
|
+
}
|
|
59
|
+
const ctor = ctorCandidate;
|
|
60
|
+
const metadataTarget = typeof target === 'function'
|
|
61
|
+
? target
|
|
62
|
+
: target !== null && typeof target === 'object'
|
|
63
|
+
? target
|
|
64
|
+
: undefined;
|
|
65
|
+
if (!metadataTarget) {
|
|
66
|
+
throw new Error('@Callable decorator received an invalid target.');
|
|
67
|
+
}
|
|
68
|
+
const meta = SERVICE_METADATA.get(ctor);
|
|
69
|
+
if (!meta) {
|
|
70
|
+
const queue = (_a = PENDING_REGISTRATIONS.get(ctor)) !== null && _a !== void 0 ? _a : [];
|
|
71
|
+
queue.push((lateMeta) => registerCallable(lateMeta, propertyKey, options, metadataTarget));
|
|
72
|
+
PENDING_REGISTRATIONS.set(ctor, queue);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
registerCallable(meta, propertyKey, options, metadataTarget);
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function registerCallable(meta, propertyKey, options, metadataTarget) {
|
|
79
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
80
|
+
const access = (_a = options.access) !== null && _a !== void 0 ? _a : 'public';
|
|
81
|
+
const paramTypes = Reflect.getMetadata('design:paramtypes', metadataTarget, propertyKey);
|
|
82
|
+
const route = (_b = options.route) !== null && _b !== void 0 ? _b : propertyKey;
|
|
83
|
+
const decoratorTags = (_c = Reflect.getMetadata(SWAGGER_TAGS_METADATA_KEY, metadataTarget, propertyKey)) !== null && _c !== void 0 ? _c : [];
|
|
84
|
+
const combinedTags = (_d = options.tags) !== null && _d !== void 0 ? _d : decoratorTags;
|
|
85
|
+
const tags = Array.from(new Set(combinedTags !== null && combinedTags !== void 0 ? combinedTags : []));
|
|
86
|
+
const metadata = {
|
|
87
|
+
route,
|
|
88
|
+
displayName: propertyKey,
|
|
89
|
+
requireAuth: (_e = options.requireAuth) !== null && _e !== void 0 ? _e : access !== 'public',
|
|
90
|
+
requiredScopes: (_f = options.requiredScopes) !== null && _f !== void 0 ? _f : defaultScopesForAccess(access),
|
|
91
|
+
useLegacySerialization: (_h = (_g = options.useLegacySerialization) !== null && _g !== void 0 ? _g : meta.options.useLegacySerialization) !== null && _h !== void 0 ? _h : false,
|
|
92
|
+
parameterTypes: paramTypes !== null && paramTypes !== void 0 ? paramTypes : [],
|
|
93
|
+
access,
|
|
94
|
+
tags,
|
|
95
|
+
};
|
|
96
|
+
const key = route.toLowerCase();
|
|
97
|
+
if (meta.callables.has(key)) {
|
|
98
|
+
throw new Error(`Duplicate callable route "${route}" on ${meta.ctor.name}.`);
|
|
99
|
+
}
|
|
100
|
+
meta.callables.set(key, metadata);
|
|
101
|
+
}
|
|
102
|
+
function defaultScopesForAccess(access) {
|
|
103
|
+
switch (access) {
|
|
104
|
+
case 'admin':
|
|
105
|
+
return ['admin'];
|
|
106
|
+
case 'server':
|
|
107
|
+
return ['server'];
|
|
108
|
+
default:
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function listRegisteredServices() {
|
|
113
|
+
return Array.from(SERVICE_METADATA.values()).map((entry) => ({
|
|
114
|
+
name: entry.name,
|
|
115
|
+
qualifiedName: entry.qualifiedName,
|
|
116
|
+
ctor: entry.ctor,
|
|
117
|
+
callables: new Map(entry.callables),
|
|
118
|
+
options: entry.options,
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
function getServiceOptions(ctor) {
|
|
122
|
+
var _a;
|
|
123
|
+
return (_a = SERVICE_METADATA.get(ctor)) === null || _a === void 0 ? void 0 : _a.options;
|
|
124
|
+
}
|
|
125
|
+
function ClientCallable(options = {}) {
|
|
126
|
+
return Callable({ ...options, access: 'client', requireAuth: true });
|
|
127
|
+
}
|
|
128
|
+
function ServerCallable(options = {}) {
|
|
129
|
+
return Callable({ ...options, access: 'server', requireAuth: true });
|
|
130
|
+
}
|
|
131
|
+
function AdminCallable(options = {}) {
|
|
132
|
+
return Callable({ ...options, access: 'admin', requireAuth: true });
|
|
133
|
+
}
|
|
134
|
+
function SwaggerCategory(category) {
|
|
135
|
+
return SwaggerTags(category);
|
|
136
|
+
}
|
|
137
|
+
function SwaggerTags(...tags) {
|
|
138
|
+
return function decorator(target, propertyKey, _descriptor) {
|
|
139
|
+
var _a;
|
|
140
|
+
if (tags.length === 0) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const current = (_a = Reflect.getMetadata(SWAGGER_TAGS_METADATA_KEY, target, propertyKey)) !== null && _a !== void 0 ? _a : [];
|
|
144
|
+
const merged = Array.from(new Set([...current, ...tags]));
|
|
145
|
+
Reflect.defineMetadata(SWAGGER_TAGS_METADATA_KEY, merged, target, propertyKey);
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function configureServices(target) {
|
|
149
|
+
var _a;
|
|
150
|
+
return (_a = CONFIGURE_SERVICES_METADATA.get(target)) !== null && _a !== void 0 ? _a : [];
|
|
151
|
+
}
|
|
152
|
+
function initializeServices(target) {
|
|
153
|
+
var _a;
|
|
154
|
+
return (_a = INITIALIZE_SERVICES_METADATA.get(target)) !== null && _a !== void 0 ? _a : [];
|
|
155
|
+
}
|
|
156
|
+
function ConfigureServices(target, _propertyKey, descriptor) {
|
|
157
|
+
var _a;
|
|
158
|
+
if (typeof descriptor.value !== 'function') {
|
|
159
|
+
throw new Error('@ConfigureServices can only decorate static methods.');
|
|
160
|
+
}
|
|
161
|
+
const handlers = (_a = CONFIGURE_SERVICES_METADATA.get(target)) !== null && _a !== void 0 ? _a : [];
|
|
162
|
+
handlers.push(descriptor.value.bind(target));
|
|
163
|
+
CONFIGURE_SERVICES_METADATA.set(target, handlers);
|
|
164
|
+
}
|
|
165
|
+
function InitializeServices(target, _propertyKey, descriptor) {
|
|
166
|
+
var _a;
|
|
167
|
+
if (typeof descriptor.value !== 'function') {
|
|
168
|
+
throw new Error('@InitializeServices can only decorate static methods.');
|
|
169
|
+
}
|
|
170
|
+
const handlers = (_a = INITIALIZE_SERVICES_METADATA.get(target)) !== null && _a !== void 0 ? _a : [];
|
|
171
|
+
handlers.push(descriptor.value.bind(target));
|
|
172
|
+
INITIALIZE_SERVICES_METADATA.set(target, handlers);
|
|
173
|
+
}
|
|
174
|
+
function getConfigureServicesHandlers(target) {
|
|
175
|
+
var _a;
|
|
176
|
+
return (_a = CONFIGURE_SERVICES_METADATA.get(target)) !== null && _a !== void 0 ? _a : [];
|
|
177
|
+
}
|
|
178
|
+
function getInitializeServicesHandlers(target) {
|
|
179
|
+
var _a;
|
|
180
|
+
return (_a = INITIALIZE_SERVICES_METADATA.get(target)) !== null && _a !== void 0 ? _a : [];
|
|
181
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BEAMABLE_SERVICES_TOKEN = exports.REQUEST_CONTEXT_TOKEN = exports.ENVIRONMENT_CONFIG_TOKEN = exports.LOGGER_TOKEN = exports.ServiceProvider = exports.DependencyBuilder = exports.ServiceLifetime = void 0;
|
|
4
|
+
require("reflect-metadata");
|
|
5
|
+
var ServiceLifetime;
|
|
6
|
+
(function (ServiceLifetime) {
|
|
7
|
+
ServiceLifetime["Singleton"] = "singleton";
|
|
8
|
+
ServiceLifetime["Scoped"] = "scoped";
|
|
9
|
+
ServiceLifetime["Transient"] = "transient";
|
|
10
|
+
})(ServiceLifetime || (exports.ServiceLifetime = ServiceLifetime = {}));
|
|
11
|
+
function isConstructor(key) {
|
|
12
|
+
return typeof key === 'function';
|
|
13
|
+
}
|
|
14
|
+
function instantiate(ctor, scope) {
|
|
15
|
+
var _a;
|
|
16
|
+
const paramTypes = (_a = Reflect.getMetadata('design:paramtypes', ctor)) !== null && _a !== void 0 ? _a : [];
|
|
17
|
+
if (paramTypes.length === 0) {
|
|
18
|
+
return new ctor();
|
|
19
|
+
}
|
|
20
|
+
const dependencies = paramTypes.map((param) => {
|
|
21
|
+
if (param === Object || param === Array || param === Promise) {
|
|
22
|
+
throw new Error(`Cannot resolve dependency '${param && param.name ? param.name : String(param)}' for ${ctor.name}. ` +
|
|
23
|
+
'Use ConfigureServices to register a factory explicitly.');
|
|
24
|
+
}
|
|
25
|
+
return scope.resolve(param);
|
|
26
|
+
});
|
|
27
|
+
return new ctor(...dependencies);
|
|
28
|
+
}
|
|
29
|
+
class DependencyBuilder {
|
|
30
|
+
constructor() {
|
|
31
|
+
this.descriptors = new Map();
|
|
32
|
+
}
|
|
33
|
+
addSingleton(key, factory) {
|
|
34
|
+
return this.addDescriptor(key, ServiceLifetime.Singleton, factory);
|
|
35
|
+
}
|
|
36
|
+
addSingletonClass(ctor) {
|
|
37
|
+
return this.addSingleton(ctor, (scope) => instantiate(ctor, scope));
|
|
38
|
+
}
|
|
39
|
+
addSingletonInstance(key, instance) {
|
|
40
|
+
return this.addSingleton(key, () => instance);
|
|
41
|
+
}
|
|
42
|
+
addScoped(key, factory) {
|
|
43
|
+
return this.addDescriptor(key, ServiceLifetime.Scoped, factory);
|
|
44
|
+
}
|
|
45
|
+
addScopedClass(ctor) {
|
|
46
|
+
return this.addScoped(ctor, (scope) => instantiate(ctor, scope));
|
|
47
|
+
}
|
|
48
|
+
addTransient(key, factory) {
|
|
49
|
+
return this.addDescriptor(key, ServiceLifetime.Transient, factory);
|
|
50
|
+
}
|
|
51
|
+
addTransientClass(ctor) {
|
|
52
|
+
return this.addTransient(ctor, (scope) => instantiate(ctor, scope));
|
|
53
|
+
}
|
|
54
|
+
tryAddSingleton(key, factory) {
|
|
55
|
+
if (!this.descriptors.has(key)) {
|
|
56
|
+
this.addSingleton(key, factory);
|
|
57
|
+
}
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
tryAddSingletonInstance(key, instance) {
|
|
61
|
+
if (!this.descriptors.has(key)) {
|
|
62
|
+
this.addSingletonInstance(key, instance);
|
|
63
|
+
}
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
build() {
|
|
67
|
+
return new ServiceProvider(this.descriptors);
|
|
68
|
+
}
|
|
69
|
+
addDescriptor(key, lifetime, factory) {
|
|
70
|
+
if (!key) {
|
|
71
|
+
throw new Error('Dependency registration requires a non-empty key.');
|
|
72
|
+
}
|
|
73
|
+
this.descriptors.set(key, { key, lifetime, factory });
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.DependencyBuilder = DependencyBuilder;
|
|
78
|
+
class ServiceProvider {
|
|
79
|
+
constructor(descriptors) {
|
|
80
|
+
this.singletons = new Map();
|
|
81
|
+
this.descriptors = new Map(descriptors);
|
|
82
|
+
}
|
|
83
|
+
resolve(key) {
|
|
84
|
+
const descriptor = this.descriptors.get(key);
|
|
85
|
+
if (!descriptor && isConstructor(key)) {
|
|
86
|
+
const implicitDescriptor = {
|
|
87
|
+
key,
|
|
88
|
+
lifetime: ServiceLifetime.Transient,
|
|
89
|
+
factory: (scope) => instantiate(key, scope),
|
|
90
|
+
};
|
|
91
|
+
this.descriptors.set(key, implicitDescriptor);
|
|
92
|
+
return this.resolve(key);
|
|
93
|
+
}
|
|
94
|
+
if (!descriptor) {
|
|
95
|
+
throw new Error(`No service registered for key '${typeof key === 'symbol' ? key.toString() : String(key)}'.`);
|
|
96
|
+
}
|
|
97
|
+
switch (descriptor.lifetime) {
|
|
98
|
+
case ServiceLifetime.Singleton: {
|
|
99
|
+
if (!this.singletons.has(descriptor.key)) {
|
|
100
|
+
const value = descriptor.factory(this);
|
|
101
|
+
this.singletons.set(descriptor.key, value);
|
|
102
|
+
}
|
|
103
|
+
return this.singletons.get(descriptor.key);
|
|
104
|
+
}
|
|
105
|
+
case ServiceLifetime.Scoped:
|
|
106
|
+
return descriptor.factory(this);
|
|
107
|
+
case ServiceLifetime.Transient:
|
|
108
|
+
default:
|
|
109
|
+
return descriptor.factory(this);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
createScope() {
|
|
113
|
+
return new ScopedServiceProvider(this.descriptors, this.singletons, this);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.ServiceProvider = ServiceProvider;
|
|
117
|
+
class ScopedServiceProvider {
|
|
118
|
+
constructor(descriptors, rootSingletons, rootProvider) {
|
|
119
|
+
this.scopedInstances = new Map();
|
|
120
|
+
this.descriptors = descriptors;
|
|
121
|
+
this.rootSingletons = rootSingletons;
|
|
122
|
+
this.rootProvider = rootProvider;
|
|
123
|
+
}
|
|
124
|
+
resolve(key) {
|
|
125
|
+
const descriptor = this.descriptors.get(key);
|
|
126
|
+
if (!descriptor && isConstructor(key)) {
|
|
127
|
+
const implicitDescriptor = {
|
|
128
|
+
key,
|
|
129
|
+
lifetime: ServiceLifetime.Transient,
|
|
130
|
+
factory: (scope) => instantiate(key, scope),
|
|
131
|
+
};
|
|
132
|
+
this.descriptors.set(key, implicitDescriptor);
|
|
133
|
+
return this.resolve(key);
|
|
134
|
+
}
|
|
135
|
+
if (!descriptor) {
|
|
136
|
+
throw new Error(`No service registered for key '${typeof key === 'symbol' ? key.toString() : String(key)}'.`);
|
|
137
|
+
}
|
|
138
|
+
switch (descriptor.lifetime) {
|
|
139
|
+
case ServiceLifetime.Singleton: {
|
|
140
|
+
if (!this.rootSingletons.has(descriptor.key)) {
|
|
141
|
+
const value = descriptor.factory(this.rootProvider);
|
|
142
|
+
this.rootSingletons.set(descriptor.key, value);
|
|
143
|
+
}
|
|
144
|
+
return this.rootSingletons.get(descriptor.key);
|
|
145
|
+
}
|
|
146
|
+
case ServiceLifetime.Scoped: {
|
|
147
|
+
if (!this.scopedInstances.has(descriptor.key)) {
|
|
148
|
+
const value = descriptor.factory(this);
|
|
149
|
+
this.scopedInstances.set(descriptor.key, value);
|
|
150
|
+
}
|
|
151
|
+
return this.scopedInstances.get(descriptor.key);
|
|
152
|
+
}
|
|
153
|
+
case ServiceLifetime.Transient:
|
|
154
|
+
default:
|
|
155
|
+
return descriptor.factory(this);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
setInstance(key, value) {
|
|
159
|
+
this.scopedInstances.set(key, value);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.LOGGER_TOKEN = Symbol('beamable:logger');
|
|
163
|
+
exports.ENVIRONMENT_CONFIG_TOKEN = Symbol('beamable:environment');
|
|
164
|
+
exports.REQUEST_CONTEXT_TOKEN = Symbol('beamable:requestContext');
|
|
165
|
+
exports.BEAMABLE_SERVICES_TOKEN = Symbol('beamable:services');
|
package/dist/dev.cjs
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ExampleService = void 0;
|
|
13
|
+
require("dotenv/config");
|
|
14
|
+
const decorators_js_1 = require("./decorators.js");
|
|
15
|
+
const runtime_js_1 = require("./runtime.js");
|
|
16
|
+
let ExampleService = class ExampleService {
|
|
17
|
+
async echo(ctx, message) {
|
|
18
|
+
return {
|
|
19
|
+
message,
|
|
20
|
+
playerId: ctx.userId,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
exports.ExampleService = ExampleService;
|
|
25
|
+
__decorate([
|
|
26
|
+
(0, decorators_js_1.Callable)(),
|
|
27
|
+
__metadata("design:type", Function),
|
|
28
|
+
__metadata("design:paramtypes", [Object, String]),
|
|
29
|
+
__metadata("design:returntype", Promise)
|
|
30
|
+
], ExampleService.prototype, "echo", null);
|
|
31
|
+
exports.ExampleService = ExampleService = __decorate([
|
|
32
|
+
(0, decorators_js_1.Microservice)('ExampleNodeService')
|
|
33
|
+
], ExampleService);
|
|
34
|
+
void (0, runtime_js_1.runMicroservice)();
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DiscoveryBroadcaster = void 0;
|
|
7
|
+
const node_dgram_1 = __importDefault(require("node:dgram"));
|
|
8
|
+
const DISCOVERY_PORT = 8624;
|
|
9
|
+
const BROADCAST_PERIOD_MS = 10;
|
|
10
|
+
class DiscoveryBroadcaster {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
var _a;
|
|
13
|
+
this.options = options;
|
|
14
|
+
this.socket = node_dgram_1.default.createSocket('udp4');
|
|
15
|
+
this.disposed = false;
|
|
16
|
+
const message = {
|
|
17
|
+
processId: process.pid,
|
|
18
|
+
cid: options.env.cid,
|
|
19
|
+
pid: options.env.pid,
|
|
20
|
+
prefix: options.routingKey,
|
|
21
|
+
serviceName: options.serviceName,
|
|
22
|
+
healthPort: options.env.healthPort,
|
|
23
|
+
serviceType: 'service',
|
|
24
|
+
startedByAccountId: (_a = options.env.accountId) !== null && _a !== void 0 ? _a : 0,
|
|
25
|
+
isContainer: false,
|
|
26
|
+
dataPort: 0,
|
|
27
|
+
containerId: '',
|
|
28
|
+
};
|
|
29
|
+
this.payload = Buffer.from(JSON.stringify(message), 'utf8');
|
|
30
|
+
this.socket.on('error', (err) => {
|
|
31
|
+
options.logger.warn({ err }, 'Discovery broadcaster socket error.');
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async start() {
|
|
35
|
+
if (this.disposed) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
await new Promise((resolve, reject) => {
|
|
39
|
+
const onError = (error) => {
|
|
40
|
+
this.socket.off('error', onError);
|
|
41
|
+
reject(error);
|
|
42
|
+
};
|
|
43
|
+
this.socket.once('error', onError);
|
|
44
|
+
this.socket.bind(0, undefined, () => {
|
|
45
|
+
try {
|
|
46
|
+
this.socket.setBroadcast(true);
|
|
47
|
+
this.socket.off('error', onError);
|
|
48
|
+
resolve();
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
this.socket.off('error', onError);
|
|
52
|
+
reject(error);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
this.interval = setInterval(() => {
|
|
57
|
+
this.socket.send(this.payload, DISCOVERY_PORT, '255.255.255.255', (error) => {
|
|
58
|
+
if (error) {
|
|
59
|
+
this.options.logger.debug({ err: error }, 'Discovery broadcast send failed.');
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}, BROADCAST_PERIOD_MS);
|
|
63
|
+
this.interval.unref();
|
|
64
|
+
}
|
|
65
|
+
stop() {
|
|
66
|
+
this.disposed = true;
|
|
67
|
+
if (this.interval) {
|
|
68
|
+
clearInterval(this.interval);
|
|
69
|
+
this.interval = undefined;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
this.socket.close();
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
this.options.logger.debug({ err: error }, 'Error closing discovery broadcaster socket.');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.DiscoveryBroadcaster = DiscoveryBroadcaster;
|
package/dist/docs.cjs
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateOpenApiDocument = generateOpenApiDocument;
|
|
4
|
+
const urls_js_1 = require("./utils/urls.js");
|
|
5
|
+
const JSON_CONTENT_TYPE = 'application/json';
|
|
6
|
+
const ADMIN_TAG = 'Administration';
|
|
7
|
+
const SCOPE_SECURITY_SCHEME = {
|
|
8
|
+
type: 'apiKey',
|
|
9
|
+
name: 'X-DE-SCOPE',
|
|
10
|
+
in: 'header',
|
|
11
|
+
description: "Customer and project scope. This should contain the '<customer-id>.<project-id>'. Required for all microservice calls.",
|
|
12
|
+
};
|
|
13
|
+
const BEAM_SCOPE_SECURITY_SCHEME = {
|
|
14
|
+
type: 'apiKey',
|
|
15
|
+
name: 'X-BEAM-SCOPE',
|
|
16
|
+
in: 'header',
|
|
17
|
+
description: "Customer and project scope. This should contain the '<customer-id>.<project-id>'. Required for all microservice calls. Alternative to X-DE-SCOPE.",
|
|
18
|
+
};
|
|
19
|
+
const USER_SECURITY_SCHEME = {
|
|
20
|
+
type: 'http',
|
|
21
|
+
scheme: 'bearer',
|
|
22
|
+
bearerFormat: 'Bearer <Access Token>',
|
|
23
|
+
description: 'Bearer authentication with a player access token in the Authorization header.',
|
|
24
|
+
};
|
|
25
|
+
function generateOpenApiDocument(service, env, runtimeVersion) {
|
|
26
|
+
const serverBase = buildServiceBaseUrl(env, service);
|
|
27
|
+
const doc = {
|
|
28
|
+
openapi: '3.0.1',
|
|
29
|
+
info: {
|
|
30
|
+
title: service.name,
|
|
31
|
+
version: runtimeVersion || process.env.BEAMABLE_RUNTIME_VERSION || '0.0.0',
|
|
32
|
+
},
|
|
33
|
+
servers: serverBase ? [{ url: serverBase }] : [],
|
|
34
|
+
paths: {},
|
|
35
|
+
components: {
|
|
36
|
+
securitySchemes: {
|
|
37
|
+
scope: SCOPE_SECURITY_SCHEME,
|
|
38
|
+
beamScope: BEAM_SCOPE_SECURITY_SCHEME,
|
|
39
|
+
user: USER_SECURITY_SCHEME,
|
|
40
|
+
},
|
|
41
|
+
schemas: {},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
for (const callable of service.callables) {
|
|
45
|
+
const normalizedRoute = normalizeRoute(callable.route);
|
|
46
|
+
const pathKey = `/${normalizedRoute}`;
|
|
47
|
+
const payload = buildRequestSchema(callable.handler);
|
|
48
|
+
const securityEntry = { scope: [], beamScope: [] };
|
|
49
|
+
if (callable.metadata.requireAuth) {
|
|
50
|
+
securityEntry.user = [];
|
|
51
|
+
}
|
|
52
|
+
const operation = {
|
|
53
|
+
operationId: callable.name,
|
|
54
|
+
summary: callable.name,
|
|
55
|
+
tags: callable.metadata.tags.length > 0 ? callable.metadata.tags : ['Callables'],
|
|
56
|
+
responses: {
|
|
57
|
+
'200': {
|
|
58
|
+
description: 'Success',
|
|
59
|
+
content: {
|
|
60
|
+
[JSON_CONTENT_TYPE]: {
|
|
61
|
+
schema: {
|
|
62
|
+
oneOf: [{ type: 'object' }, { type: 'array' }, { type: 'string' }, { type: 'number' }, { type: 'boolean' }, { type: 'null' }],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
security: [securityEntry],
|
|
69
|
+
'x-beamable-access': callable.metadata.access,
|
|
70
|
+
};
|
|
71
|
+
if (callable.metadata.requiredScopes.length > 0) {
|
|
72
|
+
operation['x-beamable-required-scopes'] = callable.metadata.requiredScopes;
|
|
73
|
+
}
|
|
74
|
+
if (payload) {
|
|
75
|
+
operation.requestBody = {
|
|
76
|
+
required: payload.required,
|
|
77
|
+
content: {
|
|
78
|
+
[JSON_CONTENT_TYPE]: {
|
|
79
|
+
schema: payload.schema,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
doc.paths[pathKey] = {
|
|
85
|
+
post: operation,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
addAdminOperations(doc);
|
|
89
|
+
return JSON.parse(JSON.stringify(doc));
|
|
90
|
+
}
|
|
91
|
+
function buildRequestSchema(handler) {
|
|
92
|
+
if (typeof handler !== 'function') {
|
|
93
|
+
return {
|
|
94
|
+
required: false,
|
|
95
|
+
schema: {
|
|
96
|
+
type: 'object',
|
|
97
|
+
properties: {
|
|
98
|
+
payload: {
|
|
99
|
+
type: 'array',
|
|
100
|
+
description: 'Callable arguments in invocation order.',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
additionalProperties: false,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const expectedParams = handler.length;
|
|
108
|
+
const payloadCount = Math.max(expectedParams - 1, 0);
|
|
109
|
+
if (payloadCount <= 0) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
required: true,
|
|
114
|
+
schema: {
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: {
|
|
117
|
+
payload: {
|
|
118
|
+
type: 'array',
|
|
119
|
+
minItems: payloadCount,
|
|
120
|
+
description: 'Callable arguments in invocation order.',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
required: ['payload'],
|
|
124
|
+
additionalProperties: false,
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function buildServiceBaseUrl(env, service) {
|
|
129
|
+
const host = (0, urls_js_1.hostToHttpUrl)(env.host).replace(/\/$/, '');
|
|
130
|
+
return `${host}/basic/${env.cid}.${env.pid}.${service.qualifiedName}/`;
|
|
131
|
+
}
|
|
132
|
+
function normalizeRoute(route) {
|
|
133
|
+
if (!route) {
|
|
134
|
+
return '';
|
|
135
|
+
}
|
|
136
|
+
return route.replace(/^\/+/, '');
|
|
137
|
+
}
|
|
138
|
+
function addAdminOperations(doc) {
|
|
139
|
+
const requiredScopeSecurity = { scope: [], beamScope: [] };
|
|
140
|
+
doc.paths['/admin/HealthCheck'] = {
|
|
141
|
+
post: {
|
|
142
|
+
operationId: 'adminHealthCheck',
|
|
143
|
+
summary: 'HealthCheck',
|
|
144
|
+
tags: [ADMIN_TAG],
|
|
145
|
+
responses: {
|
|
146
|
+
'200': {
|
|
147
|
+
description: 'The word "responsive" if all is well.',
|
|
148
|
+
content: {
|
|
149
|
+
[JSON_CONTENT_TYPE]: {
|
|
150
|
+
schema: {
|
|
151
|
+
type: 'string',
|
|
152
|
+
example: 'responsive',
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
security: [requiredScopeSecurity],
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
const adminSecurity = { scope: ['admin'], beamScope: ['admin'] };
|
|
162
|
+
doc.paths['/admin/Docs'] = {
|
|
163
|
+
post: {
|
|
164
|
+
operationId: 'adminDocs',
|
|
165
|
+
summary: 'Docs',
|
|
166
|
+
description: 'Generates an OpenAPI/Swagger 3.0 document that describes the available service endpoints.',
|
|
167
|
+
tags: [ADMIN_TAG],
|
|
168
|
+
responses: {
|
|
169
|
+
'200': {
|
|
170
|
+
description: 'Swagger JSON document.',
|
|
171
|
+
content: {
|
|
172
|
+
[JSON_CONTENT_TYPE]: {
|
|
173
|
+
schema: {
|
|
174
|
+
type: 'object',
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
security: [adminSecurity],
|
|
181
|
+
'x-beamable-required-scopes': ['admin'],
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
doc.paths['/admin/Metadata'] = {
|
|
185
|
+
post: {
|
|
186
|
+
operationId: 'adminMetadata',
|
|
187
|
+
summary: 'Metadata',
|
|
188
|
+
description: 'Fetch various Beamable SDK metadata for the Microservice.',
|
|
189
|
+
tags: [ADMIN_TAG],
|
|
190
|
+
responses: {
|
|
191
|
+
'200': {
|
|
192
|
+
description: 'Service metadata.',
|
|
193
|
+
content: {
|
|
194
|
+
[JSON_CONTENT_TYPE]: {
|
|
195
|
+
schema: {
|
|
196
|
+
type: 'object',
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
security: [adminSecurity],
|
|
203
|
+
'x-beamable-required-scopes': ['admin'],
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
}
|