@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/storage.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { MongoClient } from 'mongodb';
|
|
2
|
+
const STORAGE_OBJECT_METADATA = new Map();
|
|
3
|
+
export function StorageObject(storageName) {
|
|
4
|
+
if (!storageName || !storageName.trim()) {
|
|
5
|
+
throw new Error('@StorageObject requires a non-empty storage name.');
|
|
6
|
+
}
|
|
7
|
+
return (target) => {
|
|
8
|
+
STORAGE_OBJECT_METADATA.set(target, { storageName: storageName.trim() });
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function getStorageMetadata(target) {
|
|
12
|
+
return STORAGE_OBJECT_METADATA.get(target);
|
|
13
|
+
}
|
|
14
|
+
export function listRegisteredStorageObjects() {
|
|
15
|
+
return Array.from(STORAGE_OBJECT_METADATA.values());
|
|
16
|
+
}
|
|
17
|
+
const CONNECTION_STRING_ENV_PREFIX = 'STORAGE_CONNSTR_';
|
|
18
|
+
export class StorageService {
|
|
19
|
+
requester;
|
|
20
|
+
api;
|
|
21
|
+
env;
|
|
22
|
+
logger;
|
|
23
|
+
databaseCache = new Map();
|
|
24
|
+
clientCache = new Map();
|
|
25
|
+
cachedConnectionString;
|
|
26
|
+
constructor(dependencies) {
|
|
27
|
+
this.requester = dependencies.requester;
|
|
28
|
+
this.api = dependencies.api;
|
|
29
|
+
this.env = dependencies.env;
|
|
30
|
+
this.logger = dependencies.logger.child({ component: 'StorageService' });
|
|
31
|
+
}
|
|
32
|
+
async getDatabase(storageName, options = {}) {
|
|
33
|
+
const normalized = this.normalizeStorageName(storageName);
|
|
34
|
+
if (!options.useCache) {
|
|
35
|
+
this.databaseCache.delete(normalized);
|
|
36
|
+
}
|
|
37
|
+
const cached = this.databaseCache.get(normalized);
|
|
38
|
+
if (cached) {
|
|
39
|
+
return cached;
|
|
40
|
+
}
|
|
41
|
+
const connectionString = await this.getConnectionString(normalized);
|
|
42
|
+
const client = await this.getMongoClient(connectionString);
|
|
43
|
+
const databaseName = this.buildDatabaseName(normalized);
|
|
44
|
+
const database = client.db(databaseName);
|
|
45
|
+
this.databaseCache.set(normalized, database);
|
|
46
|
+
return database;
|
|
47
|
+
}
|
|
48
|
+
async getDatabaseFor(storageCtor, options = {}) {
|
|
49
|
+
const metadata = getStorageMetadata(storageCtor);
|
|
50
|
+
if (!metadata) {
|
|
51
|
+
throw new Error(`Storage metadata for ${storageCtor.name} not found. Did you decorate the class with @StorageObject('Name')?`);
|
|
52
|
+
}
|
|
53
|
+
return this.getDatabase(metadata.storageName, options);
|
|
54
|
+
}
|
|
55
|
+
async getCollection(storageName, options = {}) {
|
|
56
|
+
const database = await this.getDatabase(storageName, options);
|
|
57
|
+
const collectionName = options.collectionName?.trim();
|
|
58
|
+
if (!collectionName) {
|
|
59
|
+
throw new Error('Collection name must be provided when using getCollection with raw storage name.');
|
|
60
|
+
}
|
|
61
|
+
return database.collection(collectionName);
|
|
62
|
+
}
|
|
63
|
+
async getCollectionFor(storageCtor, collectionCtor, options = {}) {
|
|
64
|
+
const metadata = getStorageMetadata(storageCtor);
|
|
65
|
+
if (!metadata) {
|
|
66
|
+
throw new Error(`Storage metadata for ${storageCtor.name} not found. Did you decorate the class with @StorageObject('Name')?`);
|
|
67
|
+
}
|
|
68
|
+
const collectionName = options.collectionName?.trim() ?? collectionCtor.name;
|
|
69
|
+
const database = await this.getDatabase(metadata.storageName, options);
|
|
70
|
+
return database.collection(collectionName);
|
|
71
|
+
}
|
|
72
|
+
async getMongoClient(connectionString) {
|
|
73
|
+
if (this.clientCache.has(connectionString)) {
|
|
74
|
+
return this.clientCache.get(connectionString);
|
|
75
|
+
}
|
|
76
|
+
const client = new MongoClient(connectionString, {
|
|
77
|
+
maxPoolSize: 20,
|
|
78
|
+
});
|
|
79
|
+
await client.connect();
|
|
80
|
+
this.clientCache.set(connectionString, client);
|
|
81
|
+
return client;
|
|
82
|
+
}
|
|
83
|
+
async getConnectionString(storageName) {
|
|
84
|
+
const variableName = `${CONNECTION_STRING_ENV_PREFIX}${storageName}`;
|
|
85
|
+
const envValue = process.env[variableName];
|
|
86
|
+
if (envValue && envValue.trim()) {
|
|
87
|
+
return envValue.trim();
|
|
88
|
+
}
|
|
89
|
+
if (this.cachedConnectionString) {
|
|
90
|
+
return this.cachedConnectionString;
|
|
91
|
+
}
|
|
92
|
+
const response = await this.fetchConnectionString();
|
|
93
|
+
if (!response.connectionString || !response.connectionString.trim()) {
|
|
94
|
+
throw new Error(`Connection string for storage "${storageName}" is empty.`);
|
|
95
|
+
}
|
|
96
|
+
this.cachedConnectionString = response.connectionString.trim();
|
|
97
|
+
return this.cachedConnectionString;
|
|
98
|
+
}
|
|
99
|
+
async fetchConnectionString() {
|
|
100
|
+
if (typeof this.api.beamoGetStorageConnectionBasic === 'function') {
|
|
101
|
+
const result = await this.api.beamoGetStorageConnectionBasic();
|
|
102
|
+
if (result && typeof result === 'object' && 'body' in result) {
|
|
103
|
+
return result.body;
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
this.logger.warn('beamable-sdk does not expose beamoGetStorageConnectionBasic; falling back to manual requester call.');
|
|
108
|
+
const response = await this.requester.request({
|
|
109
|
+
method: 'GET',
|
|
110
|
+
url: '/basic/beamo/storage/connection',
|
|
111
|
+
withAuth: true,
|
|
112
|
+
});
|
|
113
|
+
const body = response.body;
|
|
114
|
+
if (!body || typeof body.connectionString !== 'string') {
|
|
115
|
+
throw new Error('Failed to retrieve Beamable storage connection string.');
|
|
116
|
+
}
|
|
117
|
+
return body;
|
|
118
|
+
}
|
|
119
|
+
buildDatabaseName(storageName) {
|
|
120
|
+
const cid = this.sanitize(this.env.cid);
|
|
121
|
+
const pid = this.sanitize(this.env.pid);
|
|
122
|
+
const storage = this.sanitize(storageName);
|
|
123
|
+
return `${cid}${pid}_${storage}`;
|
|
124
|
+
}
|
|
125
|
+
sanitize(value) {
|
|
126
|
+
return value.replace(/[^A-Za-z0-9_]/g, '_');
|
|
127
|
+
}
|
|
128
|
+
normalizeStorageName(storageName) {
|
|
129
|
+
const normalized = storageName.trim();
|
|
130
|
+
if (!normalized) {
|
|
131
|
+
throw new Error('Storage name cannot be empty.');
|
|
132
|
+
}
|
|
133
|
+
return normalized;
|
|
134
|
+
}
|
|
135
|
+
async dispose() {
|
|
136
|
+
for (const client of this.clientCache.values()) {
|
|
137
|
+
await client.close();
|
|
138
|
+
}
|
|
139
|
+
this.clientCache.clear();
|
|
140
|
+
this.databaseCache.clear();
|
|
141
|
+
this.cachedConnectionString = undefined;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Logger } from 'pino';\r\nimport { MongoClient, type Db, type Collection, type Document } from 'mongodb';\r\nimport type { BoundBeamApi } from './services.js';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport type { HttpRequester } from 'beamable-sdk';\r\n\r\nexport interface StorageConnectionOptions {\r\n useCache?: boolean;\r\n}\r\n\r\nexport interface StorageCollectionOptions extends StorageConnectionOptions {\r\n collectionName?: string;\r\n}\r\n\r\nexport interface StorageMetadata {\r\n storageName: string;\r\n}\r\n\r\nconst STORAGE_OBJECT_METADATA = new Map<Function, StorageMetadata>();\r\n\r\nexport function StorageObject(storageName: string): ClassDecorator {\r\n if (!storageName || !storageName.trim()) {\r\n throw new Error('@StorageObject requires a non-empty storage name.');\r\n }\r\n return (target) => {\r\n STORAGE_OBJECT_METADATA.set(target, { storageName: storageName.trim() });\r\n };\r\n}\r\n\r\nexport function getStorageMetadata(target: Function): StorageMetadata | undefined {\r\n return STORAGE_OBJECT_METADATA.get(target);\r\n}\r\n\r\nexport function listRegisteredStorageObjects(): StorageMetadata[] {\r\n return Array.from(STORAGE_OBJECT_METADATA.values());\r\n}\r\n\r\ninterface StorageServiceDependencies {\r\n requester: HttpRequester;\r\n api: BoundBeamApi;\r\n env: EnvironmentConfig;\r\n logger: Logger;\r\n}\r\n\r\ninterface ConnectionStringResponse {\r\n connectionString: string;\r\n}\r\n\r\nconst CONNECTION_STRING_ENV_PREFIX = 'STORAGE_CONNSTR_';\r\n\r\nexport class StorageService {\r\n private readonly requester: HttpRequester;\r\n private readonly api: BoundBeamApi;\r\n private readonly env: EnvironmentConfig;\r\n private readonly logger: Logger;\r\n private readonly databaseCache = new Map<string, Db>();\r\n private readonly clientCache = new Map<string, MongoClient>();\r\n private cachedConnectionString?: string;\r\n\r\n constructor(dependencies: StorageServiceDependencies) {\r\n this.requester = dependencies.requester;\r\n this.api = dependencies.api;\r\n this.env = dependencies.env;\r\n this.logger = dependencies.logger.child({ component: 'StorageService' });\r\n }\r\n\r\n async getDatabase(storageName: string, options: StorageConnectionOptions = {}): Promise<Db> {\r\n const normalized = this.normalizeStorageName(storageName);\r\n if (!options.useCache) {\r\n this.databaseCache.delete(normalized);\r\n }\r\n const cached = this.databaseCache.get(normalized);\r\n if (cached) {\r\n return cached;\r\n }\r\n\r\n const connectionString = await this.getConnectionString(normalized);\r\n const client = await this.getMongoClient(connectionString);\r\n const databaseName = this.buildDatabaseName(normalized);\r\n const database = client.db(databaseName);\r\n this.databaseCache.set(normalized, database);\r\n return database;\r\n }\r\n\r\n async getDatabaseFor<T>(storageCtor: new () => T, options: StorageConnectionOptions = {}): Promise<Db> {\r\n const metadata = getStorageMetadata(storageCtor);\r\n if (!metadata) {\r\n throw new Error(\r\n `Storage metadata for ${storageCtor.name} not found. Did you decorate the class with @StorageObject('Name')?`,\r\n );\r\n }\r\n return this.getDatabase(metadata.storageName, options);\r\n }\r\n\r\n async getCollection<TDocument extends Document>(\r\n storageName: string,\r\n options: StorageCollectionOptions = {},\r\n ): Promise<Collection<TDocument>> {\r\n const database = await this.getDatabase(storageName, options);\r\n const collectionName = options.collectionName?.trim();\r\n if (!collectionName) {\r\n throw new Error('Collection name must be provided when using getCollection with raw storage name.');\r\n }\r\n return database.collection<TDocument>(collectionName);\r\n }\r\n\r\n async getCollectionFor<TStorage, TDocument extends Document>(\r\n storageCtor: new () => TStorage,\r\n collectionCtor: new () => TDocument,\r\n options: StorageCollectionOptions = {},\r\n ): Promise<Collection<TDocument>> {\r\n const metadata = getStorageMetadata(storageCtor);\r\n if (!metadata) {\r\n throw new Error(\r\n `Storage metadata for ${storageCtor.name} not found. Did you decorate the class with @StorageObject('Name')?`,\r\n );\r\n }\r\n const collectionName = options.collectionName?.trim() ?? collectionCtor.name;\r\n const database = await this.getDatabase(metadata.storageName, options);\r\n return database.collection<TDocument>(collectionName);\r\n }\r\n\r\n private async getMongoClient(connectionString: string): Promise<MongoClient> {\r\n if (this.clientCache.has(connectionString)) {\r\n return this.clientCache.get(connectionString) as MongoClient;\r\n }\r\n const client = new MongoClient(connectionString, {\r\n maxPoolSize: 20,\r\n });\r\n await client.connect();\r\n this.clientCache.set(connectionString, client);\r\n return client;\r\n }\r\n\r\n private async getConnectionString(storageName: string): Promise<string> {\r\n const variableName = `${CONNECTION_STRING_ENV_PREFIX}${storageName}`;\r\n const envValue = process.env[variableName];\r\n if (envValue && envValue.trim()) {\r\n return envValue.trim();\r\n }\r\n\r\n if (this.cachedConnectionString) {\r\n return this.cachedConnectionString;\r\n }\r\n\r\n const response = await this.fetchConnectionString();\r\n if (!response.connectionString || !response.connectionString.trim()) {\r\n throw new Error(`Connection string for storage \"${storageName}\" is empty.`);\r\n }\r\n this.cachedConnectionString = response.connectionString.trim();\r\n return this.cachedConnectionString;\r\n }\r\n\r\n private async fetchConnectionString(): Promise<ConnectionStringResponse> {\r\n if (typeof this.api.beamoGetStorageConnectionBasic === 'function') {\r\n const result = await this.api.beamoGetStorageConnectionBasic();\r\n if (result && typeof result === 'object' && 'body' in result) {\r\n return (result as { body: ConnectionStringResponse }).body;\r\n }\r\n return result as ConnectionStringResponse;\r\n }\r\n\r\n this.logger.warn(\r\n 'beamable-sdk does not expose beamoGetStorageConnectionBasic; falling back to manual requester call.',\r\n );\r\n const response = await this.requester.request({\r\n method: 'GET',\r\n url: '/basic/beamo/storage/connection',\r\n withAuth: true,\r\n });\r\n const body = response.body as ConnectionStringResponse | undefined;\r\n if (!body || typeof body.connectionString !== 'string') {\r\n throw new Error('Failed to retrieve Beamable storage connection string.');\r\n }\r\n return body;\r\n }\r\n\r\n private buildDatabaseName(storageName: string): string {\r\n const cid = this.sanitize(this.env.cid);\r\n const pid = this.sanitize(this.env.pid);\r\n const storage = this.sanitize(storageName);\r\n return `${cid}${pid}_${storage}`;\r\n }\r\n\r\n private sanitize(value: string): string {\r\n return value.replace(/[^A-Za-z0-9_]/g, '_');\r\n }\r\n\r\n private normalizeStorageName(storageName: string): string {\r\n const normalized = storageName.trim();\r\n if (!normalized) {\r\n throw new Error('Storage name cannot be empty.');\r\n }\r\n return normalized;\r\n }\r\n\r\n async dispose(): Promise<void> {\r\n for (const client of this.clientCache.values()) {\r\n await client.close();\r\n }\r\n this.clientCache.clear();\r\n this.databaseCache.clear();\r\n this.cachedConnectionString = undefined;\r\n }\r\n}\r\n\r\n"]}
|
package/dist/types.cjs
ADDED
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { Logger } from 'pino';
|
|
2
|
+
import type { BeamableMicroserviceServices } from './services.js';
|
|
3
|
+
import type { DependencyScope } from './dependency.js';
|
|
4
|
+
export type ServiceAccess = 'public' | 'client' | 'server' | 'admin';
|
|
5
|
+
export interface MicroserviceOptions {
|
|
6
|
+
/** When true, legacy serialization is enabled for every callable unless overridden per method. */
|
|
7
|
+
useLegacySerialization?: boolean;
|
|
8
|
+
/** When true the runtime will skip auto-registration for Beamable events. */
|
|
9
|
+
disableAllBeamableEvents?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface CallableOptions {
|
|
12
|
+
/** Optional explicit route name. Defaults to the method name. */
|
|
13
|
+
route?: string;
|
|
14
|
+
/** Whether an authenticated user is required for invocation. */
|
|
15
|
+
requireAuth?: boolean;
|
|
16
|
+
/** Scopes required for the invocation. */
|
|
17
|
+
requiredScopes?: string[];
|
|
18
|
+
/** Override legacy serialization behaviour for this callable. */
|
|
19
|
+
useLegacySerialization?: boolean;
|
|
20
|
+
access?: ServiceAccess;
|
|
21
|
+
/** Optional OpenAPI/Swagger tags to apply to the callable. */
|
|
22
|
+
tags?: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface EnvironmentConfig {
|
|
25
|
+
cid: string;
|
|
26
|
+
pid: string;
|
|
27
|
+
host: string;
|
|
28
|
+
secret?: string;
|
|
29
|
+
refreshToken?: string;
|
|
30
|
+
routingKey?: string;
|
|
31
|
+
accountId?: number;
|
|
32
|
+
accountEmail?: string;
|
|
33
|
+
logLevel: string;
|
|
34
|
+
healthPort: number;
|
|
35
|
+
disableCustomInitializationHooks: boolean;
|
|
36
|
+
watchToken: boolean;
|
|
37
|
+
sdkVersionExecution: string;
|
|
38
|
+
beamInstanceCount: number;
|
|
39
|
+
logTruncateLimit: number;
|
|
40
|
+
}
|
|
41
|
+
export interface GatewayRequest {
|
|
42
|
+
id: number;
|
|
43
|
+
method: string;
|
|
44
|
+
path: string;
|
|
45
|
+
from?: number;
|
|
46
|
+
body?: unknown;
|
|
47
|
+
scopes?: string[];
|
|
48
|
+
headers?: Record<string, string>;
|
|
49
|
+
}
|
|
50
|
+
export interface GatewayResponse<T = unknown> {
|
|
51
|
+
id: number;
|
|
52
|
+
status: number;
|
|
53
|
+
body: T;
|
|
54
|
+
}
|
|
55
|
+
export interface WebsocketEventEnvelope {
|
|
56
|
+
id: number;
|
|
57
|
+
status: number;
|
|
58
|
+
path?: string;
|
|
59
|
+
method?: string;
|
|
60
|
+
body?: unknown;
|
|
61
|
+
from?: number;
|
|
62
|
+
scopes?: string[];
|
|
63
|
+
headers?: Record<string, string>;
|
|
64
|
+
}
|
|
65
|
+
export interface RequestContext {
|
|
66
|
+
id: number;
|
|
67
|
+
path: string;
|
|
68
|
+
method: string;
|
|
69
|
+
status: number;
|
|
70
|
+
userId: number;
|
|
71
|
+
payload?: unknown;
|
|
72
|
+
body?: Record<string, unknown>;
|
|
73
|
+
scopes: Set<string>;
|
|
74
|
+
headers: Record<string, string>;
|
|
75
|
+
cid: string;
|
|
76
|
+
pid: string;
|
|
77
|
+
services: BeamableMicroserviceServices;
|
|
78
|
+
throwIfCancelled(): void;
|
|
79
|
+
isCancelled(): boolean;
|
|
80
|
+
hasScopes(...scopes: string[]): boolean;
|
|
81
|
+
requireScopes(...scopes: string[]): void;
|
|
82
|
+
provider: DependencyScope;
|
|
83
|
+
}
|
|
84
|
+
export interface ServiceCallableMetadata {
|
|
85
|
+
route: string;
|
|
86
|
+
displayName: string;
|
|
87
|
+
requireAuth: boolean;
|
|
88
|
+
requiredScopes: string[];
|
|
89
|
+
useLegacySerialization: boolean;
|
|
90
|
+
parameterTypes: ReadonlyArray<unknown>;
|
|
91
|
+
access: ServiceAccess;
|
|
92
|
+
tags: string[];
|
|
93
|
+
}
|
|
94
|
+
export interface ServiceDefinition {
|
|
95
|
+
name: string;
|
|
96
|
+
qualifiedName: string;
|
|
97
|
+
ctor: new (...args: unknown[]) => unknown;
|
|
98
|
+
callables: Map<string, ServiceCallableMetadata>;
|
|
99
|
+
options?: MicroserviceOptions;
|
|
100
|
+
}
|
|
101
|
+
export interface RuntimeComponents {
|
|
102
|
+
env: EnvironmentConfig;
|
|
103
|
+
logger: Logger;
|
|
104
|
+
}
|
|
105
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
106
|
+
[key: string]: JsonValue;
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAClC,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,6EAA6E;IAC7E,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,iEAAiE;IACjE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC,EAAE,OAAO,CAAC;IAC1C,UAAU,EAAE,OAAO,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,CAAC;CACT;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,4BAA4B,CAAC;IACvC,gBAAgB,IAAI,IAAI,CAAC;IACzB,WAAW,IAAI,OAAO,CAAC;IACvB,SAAS,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACxC,aAAa,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACzC,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,sBAAsB,EAAE,OAAO,CAAC;IAChC,cAAc,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC1C,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IAChD,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,iBAAiB,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Logger } from 'pino';\r\nimport type { BeamableMicroserviceServices } from './services.js';\r\nimport type { DependencyScope } from './dependency.js';\r\n\r\nexport type ServiceAccess = 'public' | 'client' | 'server' | 'admin';\r\n\r\nexport interface MicroserviceOptions {\r\n /** When true, legacy serialization is enabled for every callable unless overridden per method. */\r\n useLegacySerialization?: boolean;\r\n /** When true the runtime will skip auto-registration for Beamable events. */\r\n disableAllBeamableEvents?: boolean;\r\n}\r\n\r\nexport interface CallableOptions {\r\n /** Optional explicit route name. Defaults to the method name. */\r\n route?: string;\r\n /** Whether an authenticated user is required for invocation. */\r\n requireAuth?: boolean;\r\n /** Scopes required for the invocation. */\r\n requiredScopes?: string[];\r\n /** Override legacy serialization behaviour for this callable. */\r\n useLegacySerialization?: boolean;\r\n access?: ServiceAccess;\r\n /** Optional OpenAPI/Swagger tags to apply to the callable. */\r\n tags?: string[];\r\n}\r\n\r\nexport interface EnvironmentConfig {\r\n cid: string;\r\n pid: string;\r\n host: string;\r\n secret?: string;\r\n refreshToken?: string;\r\n routingKey?: string; // undefined for deployed services (becomes None in Scala)\r\n accountId?: number;\r\n accountEmail?: string;\r\n logLevel: string;\r\n healthPort: number;\r\n disableCustomInitializationHooks: boolean;\r\n watchToken: boolean;\r\n sdkVersionExecution: string;\r\n beamInstanceCount: number;\r\n logTruncateLimit: number;\r\n}\r\n\r\nexport interface GatewayRequest {\r\n id: number;\r\n method: string;\r\n path: string;\r\n from?: number;\r\n body?: unknown;\r\n scopes?: string[];\r\n headers?: Record<string, string>;\r\n}\r\n\r\nexport interface GatewayResponse<T = unknown> {\r\n id: number;\r\n status: number;\r\n body: T;\r\n}\r\n\r\nexport interface WebsocketEventEnvelope {\r\n id: number;\r\n status: number;\r\n path?: string;\r\n method?: string;\r\n body?: unknown;\r\n from?: number;\r\n scopes?: string[];\r\n headers?: Record<string, string>;\r\n}\r\n\r\nexport interface RequestContext {\r\n id: number;\r\n path: string;\r\n method: string;\r\n status: number;\r\n userId: number;\r\n payload?: unknown;\r\n body?: Record<string, unknown>;\r\n scopes: Set<string>;\r\n headers: Record<string, string>;\r\n cid: string;\r\n pid: string;\r\n services: BeamableMicroserviceServices;\r\n throwIfCancelled(): void;\r\n isCancelled(): boolean;\r\n hasScopes(...scopes: string[]): boolean;\r\n requireScopes(...scopes: string[]): void;\r\n provider: DependencyScope;\r\n}\r\n\r\nexport interface ServiceCallableMetadata {\r\n route: string;\r\n displayName: string;\r\n requireAuth: boolean;\r\n requiredScopes: string[];\r\n useLegacySerialization: boolean;\r\n parameterTypes: ReadonlyArray<unknown>;\r\n access: ServiceAccess;\r\n tags: string[];\r\n}\r\n\r\nexport interface ServiceDefinition {\r\n name: string;\r\n qualifiedName: string;\r\n ctor: new (...args: unknown[]) => unknown;\r\n callables: Map<string, ServiceCallableMetadata>;\r\n options?: MicroserviceOptions;\r\n}\r\n\r\nexport interface RuntimeComponents {\r\n env: EnvironmentConfig;\r\n logger: Logger;\r\n}\r\n\r\nexport type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };\r\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hostToHttpUrl = hostToHttpUrl;
|
|
4
|
+
exports.hostToPortalUrl = hostToPortalUrl;
|
|
5
|
+
exports.hostToStorageUrl = hostToStorageUrl;
|
|
6
|
+
exports.hostToMicroserviceRegistryUrl = hostToMicroserviceRegistryUrl;
|
|
7
|
+
function hostToHttpUrl(host) {
|
|
8
|
+
const normalized = host.replace(/\/$/, '');
|
|
9
|
+
if (normalized.startsWith('wss://')) {
|
|
10
|
+
return `https://${normalized.substring('wss://'.length).replace(/\/socket$/, '')}`;
|
|
11
|
+
}
|
|
12
|
+
if (normalized.startsWith('ws://')) {
|
|
13
|
+
return `http://${normalized.substring('ws://'.length).replace(/\/socket$/, '')}`;
|
|
14
|
+
}
|
|
15
|
+
return normalized.replace(/\/socket$/, '');
|
|
16
|
+
}
|
|
17
|
+
function transformApiHostname(hostname, replacement) {
|
|
18
|
+
let host = hostname;
|
|
19
|
+
if (host.startsWith('dev.')) {
|
|
20
|
+
host = host.replace('dev.', 'dev-');
|
|
21
|
+
}
|
|
22
|
+
if (host.startsWith('api.')) {
|
|
23
|
+
return host.replace('api.', `${replacement}.`);
|
|
24
|
+
}
|
|
25
|
+
if (host.startsWith('api-')) {
|
|
26
|
+
return host.replace('api-', `${replacement}-`);
|
|
27
|
+
}
|
|
28
|
+
const index = host.indexOf('api');
|
|
29
|
+
if (index >= 0) {
|
|
30
|
+
return `${host.slice(0, index)}${replacement}${host.slice(index + 3)}`;
|
|
31
|
+
}
|
|
32
|
+
return host;
|
|
33
|
+
}
|
|
34
|
+
function transformHost(httpHost, replacement) {
|
|
35
|
+
try {
|
|
36
|
+
const url = new URL(httpHost);
|
|
37
|
+
url.hostname = transformApiHostname(url.hostname, replacement);
|
|
38
|
+
url.pathname = '/';
|
|
39
|
+
url.search = '';
|
|
40
|
+
url.hash = '';
|
|
41
|
+
return url.toString().replace(/\/$/, '');
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return transformApiHostname(httpHost, replacement);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function hostToPortalUrl(httpHost) {
|
|
48
|
+
return transformHost(httpHost, 'portal');
|
|
49
|
+
}
|
|
50
|
+
function hostToStorageUrl(httpHost) {
|
|
51
|
+
return transformHost(httpHost, 'storage');
|
|
52
|
+
}
|
|
53
|
+
function hostToMicroserviceRegistryUrl(httpHost) {
|
|
54
|
+
return transformHost(httpHost, 'microservices');
|
|
55
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function hostToHttpUrl(host: string): string;
|
|
2
|
+
export declare function hostToPortalUrl(httpHost: string): string;
|
|
3
|
+
export declare function hostToStorageUrl(httpHost: string): string;
|
|
4
|
+
export declare function hostToMicroserviceRegistryUrl(httpHost: string): string;
|
|
5
|
+
//# sourceMappingURL=urls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"urls.d.ts","sourceRoot":"","sources":["../../src/utils/urls.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASlD;AAiCD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtE"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export function hostToHttpUrl(host) {
|
|
2
|
+
const normalized = host.replace(/\/$/, '');
|
|
3
|
+
if (normalized.startsWith('wss://')) {
|
|
4
|
+
return `https://${normalized.substring('wss://'.length).replace(/\/socket$/, '')}`;
|
|
5
|
+
}
|
|
6
|
+
if (normalized.startsWith('ws://')) {
|
|
7
|
+
return `http://${normalized.substring('ws://'.length).replace(/\/socket$/, '')}`;
|
|
8
|
+
}
|
|
9
|
+
return normalized.replace(/\/socket$/, '');
|
|
10
|
+
}
|
|
11
|
+
function transformApiHostname(hostname, replacement) {
|
|
12
|
+
let host = hostname;
|
|
13
|
+
if (host.startsWith('dev.')) {
|
|
14
|
+
host = host.replace('dev.', 'dev-');
|
|
15
|
+
}
|
|
16
|
+
if (host.startsWith('api.')) {
|
|
17
|
+
return host.replace('api.', `${replacement}.`);
|
|
18
|
+
}
|
|
19
|
+
if (host.startsWith('api-')) {
|
|
20
|
+
return host.replace('api-', `${replacement}-`);
|
|
21
|
+
}
|
|
22
|
+
const index = host.indexOf('api');
|
|
23
|
+
if (index >= 0) {
|
|
24
|
+
return `${host.slice(0, index)}${replacement}${host.slice(index + 3)}`;
|
|
25
|
+
}
|
|
26
|
+
return host;
|
|
27
|
+
}
|
|
28
|
+
function transformHost(httpHost, replacement) {
|
|
29
|
+
try {
|
|
30
|
+
const url = new URL(httpHost);
|
|
31
|
+
url.hostname = transformApiHostname(url.hostname, replacement);
|
|
32
|
+
url.pathname = '/';
|
|
33
|
+
url.search = '';
|
|
34
|
+
url.hash = '';
|
|
35
|
+
return url.toString().replace(/\/$/, '');
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return transformApiHostname(httpHost, replacement);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function hostToPortalUrl(httpHost) {
|
|
42
|
+
return transformHost(httpHost, 'portal');
|
|
43
|
+
}
|
|
44
|
+
export function hostToStorageUrl(httpHost) {
|
|
45
|
+
return transformHost(httpHost, 'storage');
|
|
46
|
+
}
|
|
47
|
+
export function hostToMicroserviceRegistryUrl(httpHost) {
|
|
48
|
+
return transformHost(httpHost, 'microservices');
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=urls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"urls.js","sourceRoot":"","sources":["../../src/utils/urls.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3C,IAAI,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,OAAO,WAAW,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,CAAC;IACrF,CAAC;IACD,IAAI,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,OAAO,UAAU,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,CAAC;IACnF,CAAC;IACD,OAAO,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,oBAAoB,CAAC,QAAgB,EAAE,WAAmB;IACjE,IAAI,IAAI,GAAG,QAAQ,CAAC;IACpB,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,WAAW,GAAG,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,WAAW,GAAG,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACf,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;IACzE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB,EAAE,WAAmB;IAC1D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9B,GAAG,CAAC,QAAQ,GAAG,oBAAoB,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC/D,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC;QACnB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;QAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QACd,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,oBAAoB,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,QAAgB;IAC5D,OAAO,aAAa,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;AAClD,CAAC","sourcesContent":["export function hostToHttpUrl(host: string): string {\r\n const normalized = host.replace(/\\/$/, '');\r\n if (normalized.startsWith('wss://')) {\r\n return `https://${normalized.substring('wss://'.length).replace(/\\/socket$/, '')}`;\r\n }\r\n if (normalized.startsWith('ws://')) {\r\n return `http://${normalized.substring('ws://'.length).replace(/\\/socket$/, '')}`;\r\n }\r\n return normalized.replace(/\\/socket$/, '');\r\n}\r\n\r\nfunction transformApiHostname(hostname: string, replacement: string): string {\r\n let host = hostname;\r\n if (host.startsWith('dev.')) {\r\n host = host.replace('dev.', 'dev-');\r\n }\r\n if (host.startsWith('api.')) {\r\n return host.replace('api.', `${replacement}.`);\r\n }\r\n if (host.startsWith('api-')) {\r\n return host.replace('api-', `${replacement}-`);\r\n }\r\n const index = host.indexOf('api');\r\n if (index >= 0) {\r\n return `${host.slice(0, index)}${replacement}${host.slice(index + 3)}`;\r\n }\r\n return host;\r\n}\r\n\r\nfunction transformHost(httpHost: string, replacement: string): string {\r\n try {\r\n const url = new URL(httpHost);\r\n url.hostname = transformApiHostname(url.hostname, replacement);\r\n url.pathname = '/';\r\n url.search = '';\r\n url.hash = '';\r\n return url.toString().replace(/\\/$/, '');\r\n } catch (error) {\r\n return transformApiHostname(httpHost, replacement);\r\n }\r\n}\r\n\r\nexport function hostToPortalUrl(httpHost: string): string {\r\n return transformHost(httpHost, 'portal');\r\n}\r\n\r\nexport function hostToStorageUrl(httpHost: string): string {\r\n return transformHost(httpHost, 'storage');\r\n}\r\n\r\nexport function hostToMicroserviceRegistryUrl(httpHost: string): string {\r\n return transformHost(httpHost, 'microservices');\r\n}\r\n"]}
|
|
@@ -0,0 +1,142 @@
|
|
|
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.BeamableWebSocket = void 0;
|
|
7
|
+
const promises_1 = require("node:timers/promises");
|
|
8
|
+
const node_events_1 = require("node:events");
|
|
9
|
+
const ws_1 = __importDefault(require("ws"));
|
|
10
|
+
class BeamableWebSocket {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
this.emitter = new node_events_1.EventEmitter();
|
|
14
|
+
this.socket = null;
|
|
15
|
+
this.isDisposed = false;
|
|
16
|
+
this.logger = options.logger.child({ component: 'BeamableWebSocket' });
|
|
17
|
+
this.url = options.url;
|
|
18
|
+
this.maxRetries = (_a = options.maxRetries) !== null && _a !== void 0 ? _a : 20;
|
|
19
|
+
this.retryDelayMs = (_b = options.retryDelayMs) !== null && _b !== void 0 ? _b : 1000;
|
|
20
|
+
}
|
|
21
|
+
on(event, listener) {
|
|
22
|
+
this.emitter.on(event, listener);
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
off(event, listener) {
|
|
26
|
+
this.emitter.off(event, listener);
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
emit(event, ...args) {
|
|
30
|
+
this.emitter.emit(event, ...args);
|
|
31
|
+
}
|
|
32
|
+
async connect() {
|
|
33
|
+
let attempt = 0;
|
|
34
|
+
while (!this.isDisposed) {
|
|
35
|
+
try {
|
|
36
|
+
attempt += 1;
|
|
37
|
+
await this.createSocket();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
42
|
+
this.logger.warn({ err, attempt }, 'WebSocket connection attempt failed.');
|
|
43
|
+
if (attempt >= this.maxRetries) {
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
await (0, promises_1.setTimeout)(this.retryDelayMs * attempt);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
throw new Error('WebSocket disposed before connection could be established.');
|
|
50
|
+
}
|
|
51
|
+
async createSocket() {
|
|
52
|
+
if (this.socket) {
|
|
53
|
+
this.socket.removeAllListeners();
|
|
54
|
+
this.socket.terminate();
|
|
55
|
+
this.socket = null;
|
|
56
|
+
}
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
const ws = new ws_1.default(this.url, {
|
|
59
|
+
perMessageDeflate: true,
|
|
60
|
+
handshakeTimeout: 30000,
|
|
61
|
+
});
|
|
62
|
+
const handleOpen = () => {
|
|
63
|
+
this.logger.info({ url: this.url }, 'WebSocket connected.');
|
|
64
|
+
this.socket = ws;
|
|
65
|
+
ws.off('error', handleError);
|
|
66
|
+
ws.off('close', handlePrematureClose);
|
|
67
|
+
this.registerSocketHandlers(ws);
|
|
68
|
+
this.emit('open');
|
|
69
|
+
resolve();
|
|
70
|
+
};
|
|
71
|
+
const handleError = (error) => {
|
|
72
|
+
ws.off('open', handleOpen);
|
|
73
|
+
ws.off('close', handlePrematureClose);
|
|
74
|
+
reject(error);
|
|
75
|
+
};
|
|
76
|
+
const handlePrematureClose = (code, reason) => {
|
|
77
|
+
ws.off('open', handleOpen);
|
|
78
|
+
ws.off('error', handleError);
|
|
79
|
+
const err = new Error(`WebSocket closed before open handshake. code=${code} reason=${reason.toString()}`);
|
|
80
|
+
reject(err);
|
|
81
|
+
};
|
|
82
|
+
ws.on('open', handleOpen);
|
|
83
|
+
ws.on('error', handleError);
|
|
84
|
+
ws.on('close', handlePrematureClose);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
registerSocketHandlers(ws) {
|
|
88
|
+
ws.on('message', (data) => {
|
|
89
|
+
const payload = typeof data === 'string' ? data : data.toString('utf8');
|
|
90
|
+
this.logger.debug({ payload }, 'WebSocket received frame.');
|
|
91
|
+
this.emit('message', payload);
|
|
92
|
+
});
|
|
93
|
+
ws.on('close', (code, reason) => {
|
|
94
|
+
this.logger.warn({ code, reason: reason.toString() }, 'WebSocket closed.');
|
|
95
|
+
this.emit('close', code === 1000);
|
|
96
|
+
if (!this.isDisposed) {
|
|
97
|
+
void this.reconnect();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
ws.on('error', (error) => {
|
|
101
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
102
|
+
this.logger.error({ err }, 'WebSocket error.');
|
|
103
|
+
this.emit('error', err);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async reconnect() {
|
|
107
|
+
this.logger.info('Attempting to reconnect websocket.');
|
|
108
|
+
let attempt = 0;
|
|
109
|
+
while (!this.isDisposed) {
|
|
110
|
+
try {
|
|
111
|
+
attempt += 1;
|
|
112
|
+
await this.createSocket();
|
|
113
|
+
this.emit('open');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
118
|
+
this.logger.warn({ err, attempt }, 'Retrying websocket connection.');
|
|
119
|
+
await (0, promises_1.setTimeout)(this.retryDelayMs * Math.min(attempt, 10));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async send(text) {
|
|
124
|
+
if (!this.socket || this.socket.readyState !== ws_1.default.OPEN) {
|
|
125
|
+
throw new Error('WebSocket is not connected.');
|
|
126
|
+
}
|
|
127
|
+
this.logger.debug({ message: text }, 'Sending websocket frame.');
|
|
128
|
+
this.socket.send(text);
|
|
129
|
+
}
|
|
130
|
+
async close() {
|
|
131
|
+
this.isDisposed = true;
|
|
132
|
+
if (!this.socket) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const ws = this.socket;
|
|
136
|
+
if (ws.readyState === ws_1.default.CLOSED || ws.readyState === ws_1.default.CLOSING) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
ws.close(1000, 'shutdown');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.BeamableWebSocket = BeamableWebSocket;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Logger } from 'pino';
|
|
2
|
+
export interface WebSocketOptions {
|
|
3
|
+
logger: Logger;
|
|
4
|
+
url: string;
|
|
5
|
+
maxRetries?: number;
|
|
6
|
+
retryDelayMs?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface WebSocketEvents {
|
|
9
|
+
open: [];
|
|
10
|
+
close: [wasClean: boolean];
|
|
11
|
+
message: [payload: string];
|
|
12
|
+
error: [error: Error];
|
|
13
|
+
}
|
|
14
|
+
export declare class BeamableWebSocket {
|
|
15
|
+
private readonly logger;
|
|
16
|
+
private readonly url;
|
|
17
|
+
private readonly maxRetries;
|
|
18
|
+
private readonly retryDelayMs;
|
|
19
|
+
private readonly emitter;
|
|
20
|
+
private socket;
|
|
21
|
+
private isDisposed;
|
|
22
|
+
constructor(options: WebSocketOptions);
|
|
23
|
+
on(event: string, listener: (...args: unknown[]) => void): this;
|
|
24
|
+
off(event: string, listener: (...args: unknown[]) => void): this;
|
|
25
|
+
private emit;
|
|
26
|
+
connect(): Promise<void>;
|
|
27
|
+
private createSocket;
|
|
28
|
+
private registerSocketHandlers;
|
|
29
|
+
private reconnect;
|
|
30
|
+
send(text: string): Promise<void>;
|
|
31
|
+
close(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=websocket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,EAAE,CAAC;IACT,KAAK,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3B,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC3B,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;CACvB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAE9C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,EAAE,gBAAgB;IAOrC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI;IAK/D,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI;IAKhE,OAAO,CAAC,IAAI;IAIN,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAmBhB,YAAY;IA0C1B,OAAO,CAAC,sBAAsB;YAsBhB,SAAS;IAiBjB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAW7B"}
|