@omen.foundation/node-microservice-runtime 0.1.0
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/.env +13 -0
- package/dist/auth.cjs +97 -0
- package/dist/auth.d.ts +14 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +93 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +588 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/decorators.cjs +181 -0
- package/dist/decorators.d.ts +23 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +155 -0
- package/dist/decorators.js.map +1 -0
- package/dist/dependency.cjs +165 -0
- package/dist/dependency.d.ts +56 -0
- package/dist/dependency.d.ts.map +1 -0
- package/dist/dependency.js +162 -0
- package/dist/dependency.js.map +1 -0
- package/dist/dev.cjs +34 -0
- package/dist/dev.d.ts +9 -0
- package/dist/dev.d.ts.map +1 -0
- package/dist/dev.js +32 -0
- package/dist/dev.js.map +1 -0
- package/dist/discovery.cjs +79 -0
- package/dist/discovery.d.ts +20 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +75 -0
- package/dist/discovery.js.map +1 -0
- package/dist/docs.cjs +206 -0
- package/dist/docs.d.ts +30 -0
- package/dist/docs.d.ts.map +1 -0
- package/dist/docs.js +209 -0
- package/dist/docs.js.map +1 -0
- package/dist/env.cjs +106 -0
- package/dist/env.d.ts +4 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +108 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.cjs +58 -0
- package/dist/errors.d.ts +26 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +48 -0
- package/dist/errors.js.map +1 -0
- package/dist/federation.cjs +356 -0
- package/dist/federation.d.ts +108 -0
- package/dist/federation.d.ts.map +1 -0
- package/dist/federation.js +341 -0
- package/dist/federation.js.map +1 -0
- package/dist/index.cjs +42 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/inventory.cjs +361 -0
- package/dist/inventory.d.ts +116 -0
- package/dist/inventory.d.ts.map +1 -0
- package/dist/inventory.js +351 -0
- package/dist/inventory.js.map +1 -0
- package/dist/logger.cjs +62 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +29 -0
- package/dist/logger.js.map +1 -0
- package/dist/message.cjs +19 -0
- package/dist/message.d.ts +5 -0
- package/dist/message.d.ts.map +1 -0
- package/dist/message.js +15 -0
- package/dist/message.js.map +1 -0
- package/dist/requester.cjs +100 -0
- package/dist/requester.d.ts +20 -0
- package/dist/requester.d.ts.map +1 -0
- package/dist/requester.js +99 -0
- package/dist/requester.js.map +1 -0
- package/dist/routing.cjs +39 -0
- package/dist/routing.d.ts +2 -0
- package/dist/routing.d.ts.map +1 -0
- package/dist/routing.js +36 -0
- package/dist/routing.js.map +1 -0
- package/dist/runtime.cjs +735 -0
- package/dist/runtime.d.ts +40 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +825 -0
- package/dist/runtime.js.map +1 -0
- package/dist/services.cjs +346 -0
- package/dist/services.d.ts +46 -0
- package/dist/services.d.ts.map +1 -0
- package/dist/services.js +343 -0
- package/dist/services.js.map +1 -0
- package/dist/storage.cjs +147 -0
- package/dist/storage.d.ts +46 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +144 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.cjs +2 -0
- package/dist/types.d.ts +108 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/urls.cjs +55 -0
- package/dist/utils/urls.d.ts +5 -0
- package/dist/utils/urls.d.ts.map +1 -0
- package/dist/utils/urls.js +50 -0
- package/dist/utils/urls.js.map +1 -0
- package/dist/websocket.cjs +142 -0
- package/dist/websocket.d.ts +33 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +139 -0
- package/dist/websocket.js.map +1 -0
- package/env.sample +13 -0
- package/package.json +49 -0
- package/scripts/generate-openapi.mjs +114 -0
- package/scripts/lib/cli-utils.mjs +58 -0
- package/scripts/prepare-cjs.mjs +44 -0
- package/scripts/publish-service.mjs +1126 -0
- package/scripts/validate-service.mjs +103 -0
- package/scripts/ws-test.mjs +25 -0
- package/src/auth.ts +117 -0
- package/src/cli/index.ts +699 -0
- package/src/decorators.ts +207 -0
- package/src/dependency.ts +211 -0
- package/src/dev.ts +17 -0
- package/src/discovery.ts +88 -0
- package/src/docs.ts +262 -0
- package/src/env.ts +125 -0
- package/src/errors.ts +55 -0
- package/src/federation.ts +559 -0
- package/src/index.ts +51 -0
- package/src/inventory.ts +491 -0
- package/src/logger.ts +38 -0
- package/src/message.ts +19 -0
- package/src/requester.ts +126 -0
- package/src/routing.ts +42 -0
- package/src/runtime.ts +967 -0
- package/src/services.ts +459 -0
- package/src/storage.ts +206 -0
- package/src/types/beamable-sdk-api.d.ts +5 -0
- package/src/types.ts +117 -0
- package/src/utils/urls.ts +53 -0
- package/src/websocket.ts +170 -0
- package/tsconfig.base.json +31 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.cjs.json +16 -0
- package/tsconfig.dev.json +14 -0
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAqFpD,wBAAgB,qBAAqB,IAAI,iBAAiB,CA4BzD;AAED,wBAAgB,2BAA2B,IAAI,MAAM,CAMpD"}
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { getDefaultRoutingKeyForMachine } from './routing.js';
|
|
5
|
+
function getBoolean(name, defaultValue = false) {
|
|
6
|
+
const raw = process.env[name];
|
|
7
|
+
if (!raw) {
|
|
8
|
+
return defaultValue;
|
|
9
|
+
}
|
|
10
|
+
return ['1', 'true', 'yes', 'on'].includes(raw.toLowerCase());
|
|
11
|
+
}
|
|
12
|
+
function getNumber(name, defaultValue) {
|
|
13
|
+
const raw = process.env[name];
|
|
14
|
+
if (!raw) {
|
|
15
|
+
return defaultValue;
|
|
16
|
+
}
|
|
17
|
+
const parsed = Number(raw);
|
|
18
|
+
return Number.isFinite(parsed) ? parsed : defaultValue;
|
|
19
|
+
}
|
|
20
|
+
function resolveHealthPort() {
|
|
21
|
+
// Always default to 6565 if HEALTH_PORT is not explicitly set
|
|
22
|
+
// This ensures the health check server starts in deployed environments
|
|
23
|
+
// even if container detection fails or HEALTH_PORT env var is missing
|
|
24
|
+
const preferred = getNumber('HEALTH_PORT', 6565);
|
|
25
|
+
if (preferred > 0) {
|
|
26
|
+
return preferred;
|
|
27
|
+
}
|
|
28
|
+
// Use PID-scoped pseudo random port to avoid collisions on dev machines.
|
|
29
|
+
const base = 45000;
|
|
30
|
+
const span = 2000;
|
|
31
|
+
const candidate = base + (process.pid % span);
|
|
32
|
+
return candidate;
|
|
33
|
+
}
|
|
34
|
+
function resolveRoutingKey() {
|
|
35
|
+
const raw = process.env.NAME_PREFIX ?? process.env.ROUTING_KEY;
|
|
36
|
+
if (raw && raw.trim().length > 0) {
|
|
37
|
+
return raw.trim();
|
|
38
|
+
}
|
|
39
|
+
// For deployed services (in containers), routing key should be undefined (None in Scala)
|
|
40
|
+
// Beamable sets CID, PID, HOST, SECRET in containers but NOT routing key
|
|
41
|
+
// If we have the required Beamable env vars but no routing key, we're in a deployed container
|
|
42
|
+
const hasBeamableEnvVars = process.env.CID && process.env.PID && process.env.HOST && process.env.SECRET;
|
|
43
|
+
const hasNoRoutingKey = !raw || raw.trim().length === 0;
|
|
44
|
+
if (hasBeamableEnvVars && hasNoRoutingKey) {
|
|
45
|
+
// We're in a deployed container - return undefined (becomes None in Scala)
|
|
46
|
+
// This allows the gateway to find bindings without routing key filter
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
// Local development - try to get a routing key
|
|
50
|
+
try {
|
|
51
|
+
return getDefaultRoutingKeyForMachine();
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error(`Unable to determine routing key automatically. Set NAME_PREFIX environment variable. ${error.message}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function resolveSdkVersionExecution() {
|
|
58
|
+
return process.env.BEAMABLE_SDK_VERSION_EXECUTION ?? '';
|
|
59
|
+
}
|
|
60
|
+
function resolveLogLevel() {
|
|
61
|
+
const candidate = process.env.LOG_LEVEL ?? 'info';
|
|
62
|
+
const allowed = new Set(['fatal', 'error', 'warn', 'info', 'debug', 'trace']);
|
|
63
|
+
return allowed.has(candidate.toLowerCase()) ? candidate.toLowerCase() : 'info';
|
|
64
|
+
}
|
|
65
|
+
function resolveWatchToken() {
|
|
66
|
+
const value = process.env.WATCH_TOKEN;
|
|
67
|
+
if (value === undefined) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return getBoolean('WATCH_TOKEN', false);
|
|
71
|
+
}
|
|
72
|
+
function resolveBeamInstanceCount() {
|
|
73
|
+
return getNumber('BEAM_INSTANCE_COUNT', 1);
|
|
74
|
+
}
|
|
75
|
+
export function loadEnvironmentConfig() {
|
|
76
|
+
const cid = process.env.CID ?? '';
|
|
77
|
+
const pid = process.env.PID ?? '';
|
|
78
|
+
const host = process.env.HOST ?? '';
|
|
79
|
+
if (!cid || !pid || !host) {
|
|
80
|
+
throw new Error('Missing required Beamable environment variables (CID, PID, HOST).');
|
|
81
|
+
}
|
|
82
|
+
const config = {
|
|
83
|
+
cid,
|
|
84
|
+
pid,
|
|
85
|
+
host,
|
|
86
|
+
secret: process.env.SECRET ?? undefined,
|
|
87
|
+
refreshToken: process.env.REFRESH_TOKEN ?? undefined,
|
|
88
|
+
routingKey: resolveRoutingKey(),
|
|
89
|
+
accountId: getNumber('USER_ACCOUNT_ID', 0) || undefined,
|
|
90
|
+
accountEmail: process.env.USER_EMAIL ?? undefined,
|
|
91
|
+
logLevel: resolveLogLevel(),
|
|
92
|
+
healthPort: resolveHealthPort(),
|
|
93
|
+
disableCustomInitializationHooks: getBoolean('DISABLE_CUSTOM_INITIALIZATION_HOOKS', false),
|
|
94
|
+
watchToken: resolveWatchToken(),
|
|
95
|
+
sdkVersionExecution: resolveSdkVersionExecution(),
|
|
96
|
+
beamInstanceCount: resolveBeamInstanceCount(),
|
|
97
|
+
logTruncateLimit: getNumber('LOG_TRUNCATE_LIMIT', 1000),
|
|
98
|
+
};
|
|
99
|
+
return config;
|
|
100
|
+
}
|
|
101
|
+
export function ensureWritableTempDirectory() {
|
|
102
|
+
const candidate = process.env.LOG_PATH ?? join(tmpdir(), 'beamable-node-runtime');
|
|
103
|
+
if (!existsSync(candidate)) {
|
|
104
|
+
return candidate;
|
|
105
|
+
}
|
|
106
|
+
return candidate;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from 'node:fs';\r\nimport { tmpdir } from 'node:os';\r\nimport { join } from 'node:path';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { getDefaultRoutingKeyForMachine } from './routing.js';\r\n\r\nfunction getBoolean(name: string, defaultValue = false): boolean {\r\n const raw = process.env[name];\r\n if (!raw) {\r\n return defaultValue;\r\n }\r\n return ['1', 'true', 'yes', 'on'].includes(raw.toLowerCase());\r\n}\r\n\r\nfunction getNumber(name: string, defaultValue: number): number {\r\n const raw = process.env[name];\r\n if (!raw) {\r\n return defaultValue;\r\n }\r\n const parsed = Number(raw);\r\n return Number.isFinite(parsed) ? parsed : defaultValue;\r\n}\r\n\r\nfunction resolveHealthPort(): number {\r\n // Always default to 6565 if HEALTH_PORT is not explicitly set\r\n // This ensures the health check server starts in deployed environments\r\n // even if container detection fails or HEALTH_PORT env var is missing\r\n const preferred = getNumber('HEALTH_PORT', 6565);\r\n if (preferred > 0) {\r\n return preferred;\r\n }\r\n // Use PID-scoped pseudo random port to avoid collisions on dev machines.\r\n const base = 45000;\r\n const span = 2000;\r\n const candidate = base + (process.pid % span);\r\n return candidate;\r\n}\r\n\r\nfunction resolveRoutingKey(): string | undefined {\r\n const raw = process.env.NAME_PREFIX ?? process.env.ROUTING_KEY;\r\n if (raw && raw.trim().length > 0) {\r\n return raw.trim();\r\n }\r\n\r\n // For deployed services (in containers), routing key should be undefined (None in Scala)\r\n // Beamable sets CID, PID, HOST, SECRET in containers but NOT routing key\r\n // If we have the required Beamable env vars but no routing key, we're in a deployed container\r\n const hasBeamableEnvVars = process.env.CID && process.env.PID && process.env.HOST && process.env.SECRET;\r\n const hasNoRoutingKey = !raw || raw.trim().length === 0;\r\n \r\n if (hasBeamableEnvVars && hasNoRoutingKey) {\r\n // We're in a deployed container - return undefined (becomes None in Scala)\r\n // This allows the gateway to find bindings without routing key filter\r\n return undefined;\r\n }\r\n\r\n // Local development - try to get a routing key\r\n try {\r\n return getDefaultRoutingKeyForMachine();\r\n } catch (error) {\r\n throw new Error(\r\n `Unable to determine routing key automatically. Set NAME_PREFIX environment variable. ${(error as Error).message}`,\r\n );\r\n }\r\n}\r\n\r\nfunction resolveSdkVersionExecution(): string {\r\n return process.env.BEAMABLE_SDK_VERSION_EXECUTION ?? '';\r\n}\r\n\r\nfunction resolveLogLevel(): string {\r\n const candidate = process.env.LOG_LEVEL ?? 'info';\r\n const allowed = new Set(['fatal', 'error', 'warn', 'info', 'debug', 'trace']);\r\n return allowed.has(candidate.toLowerCase()) ? candidate.toLowerCase() : 'info';\r\n}\r\n\r\nfunction resolveWatchToken(): boolean {\r\n const value = process.env.WATCH_TOKEN;\r\n if (value === undefined) {\r\n return false;\r\n }\r\n return getBoolean('WATCH_TOKEN', false);\r\n}\r\n\r\nfunction resolveBeamInstanceCount(): number {\r\n return getNumber('BEAM_INSTANCE_COUNT', 1);\r\n}\r\n\r\nexport function loadEnvironmentConfig(): EnvironmentConfig {\r\n const cid = process.env.CID ?? '';\r\n const pid = process.env.PID ?? '';\r\n const host = process.env.HOST ?? '';\r\n\r\n if (!cid || !pid || !host) {\r\n throw new Error('Missing required Beamable environment variables (CID, PID, HOST).');\r\n }\r\n\r\n const config: EnvironmentConfig = {\r\n cid,\r\n pid,\r\n host,\r\n secret: process.env.SECRET ?? undefined,\r\n refreshToken: process.env.REFRESH_TOKEN ?? undefined,\r\n routingKey: resolveRoutingKey(),\r\n accountId: getNumber('USER_ACCOUNT_ID', 0) || undefined,\r\n accountEmail: process.env.USER_EMAIL ?? undefined,\r\n logLevel: resolveLogLevel(),\r\n healthPort: resolveHealthPort(),\r\n disableCustomInitializationHooks: getBoolean('DISABLE_CUSTOM_INITIALIZATION_HOOKS', false),\r\n watchToken: resolveWatchToken(),\r\n sdkVersionExecution: resolveSdkVersionExecution(),\r\n beamInstanceCount: resolveBeamInstanceCount(),\r\n logTruncateLimit: getNumber('LOG_TRUNCATE_LIMIT', 1000),\r\n };\r\n\r\n return config;\r\n}\r\n\r\nexport function ensureWritableTempDirectory(): string {\r\n const candidate = process.env.LOG_PATH ?? join(tmpdir(), 'beamable-node-runtime');\r\n if (!existsSync(candidate)) {\r\n return candidate;\r\n }\r\n return candidate;\r\n}\r\n"]}
|
package/dist/errors.cjs
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InvalidConfigurationError = exports.SerializationError = exports.UnknownRouteError = exports.UnauthorizedUserError = exports.MissingScopesError = exports.TimeoutError = exports.AuthenticationError = exports.BeamableRuntimeError = void 0;
|
|
4
|
+
class BeamableRuntimeError extends Error {
|
|
5
|
+
constructor(code, message, cause) {
|
|
6
|
+
var _a;
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
if (cause !== undefined) {
|
|
10
|
+
this.cause = cause;
|
|
11
|
+
}
|
|
12
|
+
this.name = this.constructor.name;
|
|
13
|
+
(_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.BeamableRuntimeError = BeamableRuntimeError;
|
|
17
|
+
class AuthenticationError extends BeamableRuntimeError {
|
|
18
|
+
constructor(message, cause) {
|
|
19
|
+
super('AUTHENTICATION_FAILED', message, cause);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.AuthenticationError = AuthenticationError;
|
|
23
|
+
class TimeoutError extends BeamableRuntimeError {
|
|
24
|
+
constructor(message, cause) {
|
|
25
|
+
super('TIMEOUT', message, cause);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.TimeoutError = TimeoutError;
|
|
29
|
+
class MissingScopesError extends BeamableRuntimeError {
|
|
30
|
+
constructor(requiredScopes) {
|
|
31
|
+
super('MISSING_SCOPES', `Missing required scopes: ${Array.from(requiredScopes).join(', ')}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.MissingScopesError = MissingScopesError;
|
|
35
|
+
class UnauthorizedUserError extends BeamableRuntimeError {
|
|
36
|
+
constructor(route) {
|
|
37
|
+
super('UNAUTHORIZED_USER', `Route "${route}" requires an authenticated user.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.UnauthorizedUserError = UnauthorizedUserError;
|
|
41
|
+
class UnknownRouteError extends BeamableRuntimeError {
|
|
42
|
+
constructor(route) {
|
|
43
|
+
super('UNKNOWN_ROUTE', `No callable registered for route "${route}".`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.UnknownRouteError = UnknownRouteError;
|
|
47
|
+
class SerializationError extends BeamableRuntimeError {
|
|
48
|
+
constructor(message, cause) {
|
|
49
|
+
super('SERIALIZATION_ERROR', message, cause);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.SerializationError = SerializationError;
|
|
53
|
+
class InvalidConfigurationError extends BeamableRuntimeError {
|
|
54
|
+
constructor(message, cause) {
|
|
55
|
+
super('INVALID_CONFIGURATION', message, cause);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.InvalidConfigurationError = InvalidConfigurationError;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare class BeamableRuntimeError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
constructor(code: string, message: string, cause?: unknown);
|
|
4
|
+
}
|
|
5
|
+
export declare class AuthenticationError extends BeamableRuntimeError {
|
|
6
|
+
constructor(message: string, cause?: unknown);
|
|
7
|
+
}
|
|
8
|
+
export declare class TimeoutError extends BeamableRuntimeError {
|
|
9
|
+
constructor(message: string, cause?: unknown);
|
|
10
|
+
}
|
|
11
|
+
export declare class MissingScopesError extends BeamableRuntimeError {
|
|
12
|
+
constructor(requiredScopes: Iterable<string>);
|
|
13
|
+
}
|
|
14
|
+
export declare class UnauthorizedUserError extends BeamableRuntimeError {
|
|
15
|
+
constructor(route: string);
|
|
16
|
+
}
|
|
17
|
+
export declare class UnknownRouteError extends BeamableRuntimeError {
|
|
18
|
+
constructor(route: string);
|
|
19
|
+
}
|
|
20
|
+
export declare class SerializationError extends BeamableRuntimeError {
|
|
21
|
+
constructor(message: string, cause?: unknown);
|
|
22
|
+
}
|
|
23
|
+
export declare class InvalidConfigurationError extends BeamableRuntimeError {
|
|
24
|
+
constructor(message: string, cause?: unknown);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAEjB,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAS3D;AAED,qBAAa,mBAAoB,SAAQ,oBAAoB;gBAC/C,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAG7C;AAED,qBAAa,YAAa,SAAQ,oBAAoB;gBACxC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAG7C;AAED,qBAAa,kBAAmB,SAAQ,oBAAoB;gBAC9C,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC;CAG7C;AAED,qBAAa,qBAAsB,SAAQ,oBAAoB;gBACjD,KAAK,EAAE,MAAM;CAG1B;AAED,qBAAa,iBAAkB,SAAQ,oBAAoB;gBAC7C,KAAK,EAAE,MAAM;CAG1B;AAED,qBAAa,kBAAmB,SAAQ,oBAAoB;gBAC9C,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAG7C;AAED,qBAAa,yBAA0B,SAAQ,oBAAoB;gBACrD,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAG7C"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export class BeamableRuntimeError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
constructor(code, message, cause) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.code = code;
|
|
6
|
+
if (cause !== undefined) {
|
|
7
|
+
this.cause = cause;
|
|
8
|
+
}
|
|
9
|
+
this.name = this.constructor.name;
|
|
10
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class AuthenticationError extends BeamableRuntimeError {
|
|
14
|
+
constructor(message, cause) {
|
|
15
|
+
super('AUTHENTICATION_FAILED', message, cause);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class TimeoutError extends BeamableRuntimeError {
|
|
19
|
+
constructor(message, cause) {
|
|
20
|
+
super('TIMEOUT', message, cause);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export class MissingScopesError extends BeamableRuntimeError {
|
|
24
|
+
constructor(requiredScopes) {
|
|
25
|
+
super('MISSING_SCOPES', `Missing required scopes: ${Array.from(requiredScopes).join(', ')}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export class UnauthorizedUserError extends BeamableRuntimeError {
|
|
29
|
+
constructor(route) {
|
|
30
|
+
super('UNAUTHORIZED_USER', `Route "${route}" requires an authenticated user.`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class UnknownRouteError extends BeamableRuntimeError {
|
|
34
|
+
constructor(route) {
|
|
35
|
+
super('UNKNOWN_ROUTE', `No callable registered for route "${route}".`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export class SerializationError extends BeamableRuntimeError {
|
|
39
|
+
constructor(message, cause) {
|
|
40
|
+
super('SERIALIZATION_ERROR', message, cause);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export class InvalidConfigurationError extends BeamableRuntimeError {
|
|
44
|
+
constructor(message, cause) {
|
|
45
|
+
super('INVALID_CONFIGURATION', message, cause);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7B,IAAI,CAAS;IAE7B,YAAY,IAAY,EAAE,OAAe,EAAE,KAAe;QACxD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACvB,IAA4B,CAAC,KAAK,GAAG,KAAK,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,KAAK,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACpD,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,oBAAoB;IAC3D,YAAY,OAAe,EAAE,KAAe;QAC1C,KAAK,CAAC,uBAAuB,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;CACF;AAED,MAAM,OAAO,YAAa,SAAQ,oBAAoB;IACpD,YAAY,OAAe,EAAE,KAAe;QAC1C,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,oBAAoB;IAC1D,YAAY,cAAgC;QAC1C,KAAK,CAAC,gBAAgB,EAAE,4BAA4B,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/F,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,oBAAoB;IAC7D,YAAY,KAAa;QACvB,KAAK,CAAC,mBAAmB,EAAE,UAAU,KAAK,mCAAmC,CAAC,CAAC;IACjF,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,oBAAoB;IACzD,YAAY,KAAa;QACvB,KAAK,CAAC,eAAe,EAAE,qCAAqC,KAAK,IAAI,CAAC,CAAC;IACzE,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,oBAAoB;IAC1D,YAAY,OAAe,EAAE,KAAe;QAC1C,KAAK,CAAC,qBAAqB,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,oBAAoB;IACjE,YAAY,OAAe,EAAE,KAAe;QAC1C,KAAK,CAAC,uBAAuB,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;CACF","sourcesContent":["export class BeamableRuntimeError extends Error {\r\n public readonly code: string;\r\n\r\n constructor(code: string, message: string, cause?: unknown) {\r\n super(message);\r\n this.code = code;\r\n if (cause !== undefined) {\r\n (this as { cause?: unknown }).cause = cause;\r\n }\r\n this.name = this.constructor.name;\r\n Error.captureStackTrace?.(this, this.constructor);\r\n }\r\n}\r\n\r\nexport class AuthenticationError extends BeamableRuntimeError {\r\n constructor(message: string, cause?: unknown) {\r\n super('AUTHENTICATION_FAILED', message, cause);\r\n }\r\n}\r\n\r\nexport class TimeoutError extends BeamableRuntimeError {\r\n constructor(message: string, cause?: unknown) {\r\n super('TIMEOUT', message, cause);\r\n }\r\n}\r\n\r\nexport class MissingScopesError extends BeamableRuntimeError {\r\n constructor(requiredScopes: Iterable<string>) {\r\n super('MISSING_SCOPES', `Missing required scopes: ${Array.from(requiredScopes).join(', ')}`);\r\n }\r\n}\r\n\r\nexport class UnauthorizedUserError extends BeamableRuntimeError {\r\n constructor(route: string) {\r\n super('UNAUTHORIZED_USER', `Route \"${route}\" requires an authenticated user.`);\r\n }\r\n}\r\n\r\nexport class UnknownRouteError extends BeamableRuntimeError {\r\n constructor(route: string) {\r\n super('UNKNOWN_ROUTE', `No callable registered for route \"${route}\".`);\r\n }\r\n}\r\n\r\nexport class SerializationError extends BeamableRuntimeError {\r\n constructor(message: string, cause?: unknown) {\r\n super('SERIALIZATION_ERROR', message, cause);\r\n }\r\n}\r\n\r\nexport class InvalidConfigurationError extends BeamableRuntimeError {\r\n constructor(message: string, cause?: unknown) {\r\n super('INVALID_CONFIGURATION', message, cause);\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FederationRegistry = void 0;
|
|
4
|
+
exports.FederationComponent = FederationComponent;
|
|
5
|
+
exports.getFederationComponents = getFederationComponents;
|
|
6
|
+
exports.FederatedInventory = FederatedInventory;
|
|
7
|
+
exports.getFederatedInventoryMetadata = getFederatedInventoryMetadata;
|
|
8
|
+
const FEDERATION_COMPONENTS = new Map();
|
|
9
|
+
const FEDERATED_INVENTORY_MAP = new Map();
|
|
10
|
+
function FederationComponent(descriptor) {
|
|
11
|
+
validateDescriptor(descriptor);
|
|
12
|
+
return (target) => {
|
|
13
|
+
var _a;
|
|
14
|
+
const existing = (_a = FEDERATION_COMPONENTS.get(target)) !== null && _a !== void 0 ? _a : [];
|
|
15
|
+
existing.push({
|
|
16
|
+
federationNamespace: descriptor.federationNamespace,
|
|
17
|
+
federationType: descriptor.federationType,
|
|
18
|
+
localSettings: descriptor.localSettings,
|
|
19
|
+
});
|
|
20
|
+
FEDERATION_COMPONENTS.set(target, existing);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function getFederationComponents(target) {
|
|
24
|
+
var _a;
|
|
25
|
+
return (_a = FEDERATION_COMPONENTS.get(target)) !== null && _a !== void 0 ? _a : [];
|
|
26
|
+
}
|
|
27
|
+
function FederatedInventory(options) {
|
|
28
|
+
var _a, _b, _c;
|
|
29
|
+
const authenticate = (_a = options.authenticate) !== null && _a !== void 0 ? _a : 'Authenticate';
|
|
30
|
+
const getInventoryState = (_b = options.getInventoryState) !== null && _b !== void 0 ? _b : 'GetInventoryState';
|
|
31
|
+
const startInventoryTransaction = (_c = options.startInventoryTransaction) !== null && _c !== void 0 ? _c : 'StartInventoryTransaction';
|
|
32
|
+
return (target) => {
|
|
33
|
+
var _a;
|
|
34
|
+
const identityInstance = new options.identity();
|
|
35
|
+
if (!identityInstance || typeof identityInstance.getUniqueName !== 'function') {
|
|
36
|
+
throw new Error('@FederatedInventory identity must implement getUniqueName().');
|
|
37
|
+
}
|
|
38
|
+
const identityName = identityInstance.getUniqueName();
|
|
39
|
+
if (!identityName || !identityName.trim()) {
|
|
40
|
+
throw new Error('@FederatedInventory identity must provide a non-empty unique name.');
|
|
41
|
+
}
|
|
42
|
+
const existing = (_a = FEDERATED_INVENTORY_MAP.get(target)) !== null && _a !== void 0 ? _a : [];
|
|
43
|
+
existing.push({
|
|
44
|
+
identityCtor: options.identity,
|
|
45
|
+
identityName: identityName.trim(),
|
|
46
|
+
methods: {
|
|
47
|
+
authenticate,
|
|
48
|
+
getInventoryState,
|
|
49
|
+
startInventoryTransaction,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
FEDERATED_INVENTORY_MAP.set(target, existing);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function getFederatedInventoryMetadata(target) {
|
|
56
|
+
var _a;
|
|
57
|
+
return (_a = FEDERATED_INVENTORY_MAP.get(target)) !== null && _a !== void 0 ? _a : [];
|
|
58
|
+
}
|
|
59
|
+
function validateDescriptor(descriptor) {
|
|
60
|
+
if (!descriptor.federationNamespace || !descriptor.federationNamespace.trim()) {
|
|
61
|
+
throw new Error('@FederationComponent requires a non-empty federationNamespace.');
|
|
62
|
+
}
|
|
63
|
+
if (!descriptor.federationType || !descriptor.federationType.trim()) {
|
|
64
|
+
throw new Error('@FederationComponent requires a non-empty federationType.');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
class FederationRegistry {
|
|
68
|
+
constructor(logger) {
|
|
69
|
+
this.manualComponents = new Map();
|
|
70
|
+
this.autoComponents = new Map();
|
|
71
|
+
this.routeHandlers = new Map();
|
|
72
|
+
this.logger = logger.child({ component: 'FederationRegistry' });
|
|
73
|
+
}
|
|
74
|
+
register(component) {
|
|
75
|
+
var _a;
|
|
76
|
+
validateDescriptor(component);
|
|
77
|
+
const namespace = component.federationNamespace.trim();
|
|
78
|
+
const type = component.federationType.trim();
|
|
79
|
+
const existing = (_a = this.manualComponents.get(namespace)) !== null && _a !== void 0 ? _a : new Set();
|
|
80
|
+
existing.add(type);
|
|
81
|
+
this.manualComponents.set(namespace, existing);
|
|
82
|
+
this.logger.debug({ component }, 'Registered federation component.');
|
|
83
|
+
}
|
|
84
|
+
registerInventoryHandlers(service, metadata) {
|
|
85
|
+
for (const entry of metadata) {
|
|
86
|
+
const identity = entry.identityName;
|
|
87
|
+
this.addAutoComponent(identity, 'IFederatedInventory');
|
|
88
|
+
this.addAutoComponent(identity, 'IFederatedLogin');
|
|
89
|
+
const authenticateHandler = this.createInventoryHandler(service, entry.methods.authenticate, identity, 'authenticate');
|
|
90
|
+
const stateHandler = this.createInventoryHandler(service, entry.methods.getInventoryState, identity, 'inventory-state');
|
|
91
|
+
const transactionHandler = this.createInventoryHandler(service, entry.methods.startInventoryTransaction, identity, 'inventory-transaction');
|
|
92
|
+
this.routeHandlers.set(`${identity.toLowerCase()}/authenticate`, authenticateHandler);
|
|
93
|
+
this.routeHandlers.set(`${identity.toLowerCase()}/inventory/state`, stateHandler);
|
|
94
|
+
this.routeHandlers.set(`${identity.toLowerCase()}/inventory/put`, transactionHandler);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
list() {
|
|
98
|
+
const components = [];
|
|
99
|
+
for (const [namespace, types] of this.manualComponents.entries()) {
|
|
100
|
+
for (const type of types) {
|
|
101
|
+
components.push({ federationNamespace: namespace, federationType: type });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const [namespace, types] of this.autoComponents.entries()) {
|
|
105
|
+
for (const type of types) {
|
|
106
|
+
components.push({ federationNamespace: namespace, federationType: type });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return components;
|
|
110
|
+
}
|
|
111
|
+
resolve(path) {
|
|
112
|
+
return this.routeHandlers.get(path.toLowerCase());
|
|
113
|
+
}
|
|
114
|
+
addAutoComponent(namespace, type) {
|
|
115
|
+
var _a;
|
|
116
|
+
const existing = (_a = this.autoComponents.get(namespace)) !== null && _a !== void 0 ? _a : new Set();
|
|
117
|
+
existing.add(type);
|
|
118
|
+
this.autoComponents.set(namespace, existing);
|
|
119
|
+
}
|
|
120
|
+
createInventoryHandler(service, methodName, identity, type) {
|
|
121
|
+
const method = service[methodName];
|
|
122
|
+
if (typeof method !== 'function') {
|
|
123
|
+
throw new Error(`Federated inventory method "${methodName}" is not defined on service "${service.constructor.name}".`);
|
|
124
|
+
}
|
|
125
|
+
const paramTypes = getMethodParameterTypes(service, methodName);
|
|
126
|
+
return {
|
|
127
|
+
identityName: identity,
|
|
128
|
+
type,
|
|
129
|
+
invoke: async (ctx) => {
|
|
130
|
+
const federatedCtx = {
|
|
131
|
+
...ctx,
|
|
132
|
+
federation: { identity },
|
|
133
|
+
};
|
|
134
|
+
switch (type) {
|
|
135
|
+
case 'authenticate':
|
|
136
|
+
return invokeFederatedAuthenticate(method, service, federatedCtx, normalizeAuthenticationRequest(ctx.body), paramTypes);
|
|
137
|
+
case 'inventory-state':
|
|
138
|
+
return invokeFederatedGetInventoryState(method, service, federatedCtx, normalizeInventoryStateRequest(ctx.body), paramTypes);
|
|
139
|
+
case 'inventory-transaction':
|
|
140
|
+
return invokeFederatedStartInventoryTransaction(method, service, federatedCtx, normalizeInventoryTransactionRequest(ctx.body), paramTypes);
|
|
141
|
+
default:
|
|
142
|
+
throw new Error(`Unsupported federated handler type: ${type}`);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.FederationRegistry = FederationRegistry;
|
|
149
|
+
function normalizeAuthenticationRequest(payload) {
|
|
150
|
+
if (!payload || typeof payload !== 'object') {
|
|
151
|
+
return {};
|
|
152
|
+
}
|
|
153
|
+
const body = payload;
|
|
154
|
+
return {
|
|
155
|
+
token: typeof body.token === 'string' ? body.token : undefined,
|
|
156
|
+
challenge: typeof body.challenge === 'string' ? body.challenge : undefined,
|
|
157
|
+
solution: typeof body.solution === 'string' ? body.solution : undefined,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function normalizeInventoryStateRequest(payload) {
|
|
161
|
+
if (!payload || typeof payload !== 'object' || typeof payload.id !== 'string') {
|
|
162
|
+
throw new Error('Federated inventory state requests must include an "id" property.');
|
|
163
|
+
}
|
|
164
|
+
const body = payload;
|
|
165
|
+
return { id: String(body.id) };
|
|
166
|
+
}
|
|
167
|
+
function normalizeInventoryTransactionRequest(payload) {
|
|
168
|
+
if (!payload || typeof payload !== 'object') {
|
|
169
|
+
throw new Error('Federated inventory transaction requests require a JSON body.');
|
|
170
|
+
}
|
|
171
|
+
const body = payload;
|
|
172
|
+
if (typeof body.id !== 'string') {
|
|
173
|
+
throw new Error('Federated inventory transaction requests must include an "id" property.');
|
|
174
|
+
}
|
|
175
|
+
if (typeof body.transaction !== 'string') {
|
|
176
|
+
throw new Error('Federated inventory transaction requests must include a "transaction" property.');
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
id: body.id,
|
|
180
|
+
transaction: body.transaction,
|
|
181
|
+
currencies: normalizeRecordOfNumbers(body.currencies),
|
|
182
|
+
newItems: normalizeFederatedCreateRequests(body.newItems),
|
|
183
|
+
deleteItems: normalizeFederatedDeleteRequests(body.deleteItems),
|
|
184
|
+
updateItems: normalizeFederatedUpdateRequests(body.updateItems),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function normalizeRecordOfNumbers(value) {
|
|
188
|
+
if (!value || typeof value !== 'object') {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
const record = {};
|
|
192
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
193
|
+
const numeric = Number(raw);
|
|
194
|
+
if (Number.isFinite(numeric)) {
|
|
195
|
+
record[key] = numeric;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return Object.keys(record).length > 0 ? record : undefined;
|
|
199
|
+
}
|
|
200
|
+
function normalizeFederatedCreateRequests(value) {
|
|
201
|
+
if (!Array.isArray(value)) {
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
const normalized = [];
|
|
205
|
+
for (const item of value) {
|
|
206
|
+
if (!item || typeof item !== 'object') {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const record = item;
|
|
210
|
+
if (typeof record.contentId !== 'string') {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const properties = record.properties && typeof record.properties === 'object'
|
|
214
|
+
? Object.fromEntries(Object.entries(record.properties).map(([propKey, propVal]) => [
|
|
215
|
+
propKey,
|
|
216
|
+
String(propVal),
|
|
217
|
+
]))
|
|
218
|
+
: undefined;
|
|
219
|
+
normalized.push({
|
|
220
|
+
contentId: record.contentId,
|
|
221
|
+
requestId: typeof record.requestId === 'string' ? record.requestId : undefined,
|
|
222
|
+
properties,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
226
|
+
}
|
|
227
|
+
function normalizeFederatedDeleteRequests(value) {
|
|
228
|
+
if (!Array.isArray(value)) {
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
const normalized = [];
|
|
232
|
+
for (const item of value) {
|
|
233
|
+
if (!item || typeof item !== 'object') {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
const record = item;
|
|
237
|
+
if (typeof record.contentId !== 'string' || typeof record.proxyId !== 'string') {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
normalized.push({
|
|
241
|
+
contentId: record.contentId,
|
|
242
|
+
proxyId: record.proxyId,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
246
|
+
}
|
|
247
|
+
function normalizeFederatedUpdateRequests(value) {
|
|
248
|
+
if (!Array.isArray(value)) {
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
const normalized = [];
|
|
252
|
+
for (const item of value) {
|
|
253
|
+
if (!item || typeof item !== 'object') {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
const record = item;
|
|
257
|
+
if (typeof record.contentId !== 'string' || typeof record.proxyId !== 'string') {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
const properties = record.properties && typeof record.properties === 'object'
|
|
261
|
+
? Object.fromEntries(Object.entries(record.properties).map(([propKey, propVal]) => [
|
|
262
|
+
propKey,
|
|
263
|
+
String(propVal),
|
|
264
|
+
]))
|
|
265
|
+
: undefined;
|
|
266
|
+
normalized.push({
|
|
267
|
+
contentId: record.contentId,
|
|
268
|
+
proxyId: record.proxyId,
|
|
269
|
+
properties,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
273
|
+
}
|
|
274
|
+
function getMethodParameterTypes(service, methodName) {
|
|
275
|
+
var _a;
|
|
276
|
+
const prototype = Object.getPrototypeOf(service);
|
|
277
|
+
if (!prototype || typeof Reflect.getMetadata !== 'function') {
|
|
278
|
+
return [];
|
|
279
|
+
}
|
|
280
|
+
return (_a = Reflect.getMetadata('design:paramtypes', prototype, methodName)) !== null && _a !== void 0 ? _a : [];
|
|
281
|
+
}
|
|
282
|
+
function isStringType(type) {
|
|
283
|
+
return type === String;
|
|
284
|
+
}
|
|
285
|
+
function invokeFederatedAuthenticate(method, service, ctx, request, paramTypes) {
|
|
286
|
+
const argsWithoutContext = [request.token, request.challenge, request.solution];
|
|
287
|
+
if (method.length === argsWithoutContext.length) {
|
|
288
|
+
return method.call(service, ...argsWithoutContext);
|
|
289
|
+
}
|
|
290
|
+
if (method.length === argsWithoutContext.length + 1) {
|
|
291
|
+
return method.call(service, ctx, ...argsWithoutContext);
|
|
292
|
+
}
|
|
293
|
+
if (method.length === 1) {
|
|
294
|
+
const firstType = paramTypes[0];
|
|
295
|
+
if (isStringType(firstType)) {
|
|
296
|
+
return method.call(service, ...argsWithoutContext);
|
|
297
|
+
}
|
|
298
|
+
return method.call(service, request);
|
|
299
|
+
}
|
|
300
|
+
if (method.length === 2) {
|
|
301
|
+
const secondType = paramTypes[1];
|
|
302
|
+
if (isStringType(secondType)) {
|
|
303
|
+
return method.call(service, ctx, ...argsWithoutContext);
|
|
304
|
+
}
|
|
305
|
+
return method.call(service, ctx, request);
|
|
306
|
+
}
|
|
307
|
+
return method.call(service, ctx, request);
|
|
308
|
+
}
|
|
309
|
+
function invokeFederatedGetInventoryState(method, service, ctx, request, paramTypes) {
|
|
310
|
+
const argsWithoutContext = [request.id];
|
|
311
|
+
if (method.length === argsWithoutContext.length) {
|
|
312
|
+
const firstType = paramTypes[0];
|
|
313
|
+
if (isStringType(firstType)) {
|
|
314
|
+
return method.call(service, ...argsWithoutContext);
|
|
315
|
+
}
|
|
316
|
+
return method.call(service, request);
|
|
317
|
+
}
|
|
318
|
+
if (method.length === argsWithoutContext.length + 1) {
|
|
319
|
+
const secondType = paramTypes[1];
|
|
320
|
+
if (isStringType(secondType)) {
|
|
321
|
+
return method.call(service, ctx, ...argsWithoutContext);
|
|
322
|
+
}
|
|
323
|
+
return method.call(service, ctx, request);
|
|
324
|
+
}
|
|
325
|
+
if (method.length === 1) {
|
|
326
|
+
return method.call(service, request);
|
|
327
|
+
}
|
|
328
|
+
if (method.length === 2) {
|
|
329
|
+
return method.call(service, ctx, request);
|
|
330
|
+
}
|
|
331
|
+
return method.call(service, ctx, request);
|
|
332
|
+
}
|
|
333
|
+
function invokeFederatedStartInventoryTransaction(method, service, ctx, request, _paramTypes) {
|
|
334
|
+
var _a, _b, _c, _d;
|
|
335
|
+
const argsWithoutContext = [
|
|
336
|
+
request.id,
|
|
337
|
+
request.transaction,
|
|
338
|
+
(_a = request.currencies) !== null && _a !== void 0 ? _a : {},
|
|
339
|
+
(_b = request.newItems) !== null && _b !== void 0 ? _b : [],
|
|
340
|
+
(_c = request.deleteItems) !== null && _c !== void 0 ? _c : [],
|
|
341
|
+
(_d = request.updateItems) !== null && _d !== void 0 ? _d : [],
|
|
342
|
+
];
|
|
343
|
+
if (method.length === argsWithoutContext.length) {
|
|
344
|
+
return method.call(service, ...argsWithoutContext);
|
|
345
|
+
}
|
|
346
|
+
if (method.length === argsWithoutContext.length + 1) {
|
|
347
|
+
return method.call(service, ctx, ...argsWithoutContext);
|
|
348
|
+
}
|
|
349
|
+
if (method.length === 1) {
|
|
350
|
+
return method.call(service, request);
|
|
351
|
+
}
|
|
352
|
+
if (method.length === 2) {
|
|
353
|
+
return method.call(service, ctx, request);
|
|
354
|
+
}
|
|
355
|
+
return method.call(service, ctx, request);
|
|
356
|
+
}
|