@omen.foundation/node-microservice-runtime 0.1.73 → 0.1.76
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/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +41 -3
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/env-loader.d.ts +32 -0
- package/dist/env-loader.d.ts.map +1 -0
- package/dist/env-loader.js +256 -0
- package/dist/env-loader.js.map +1 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +19 -1
- package/dist/runtime.js.map +1 -1
- package/package.json +1 -1
- package/scripts/publish-service.mjs +19 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/scaffold.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH;;GAEG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/scaffold.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH;;GAEG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkElE"}
|
|
@@ -57,8 +57,9 @@ export async function handleScaffold(args) {
|
|
|
57
57
|
console.log(`\nNext steps:`);
|
|
58
58
|
console.log(` 1. cd ${serviceName}`);
|
|
59
59
|
console.log(` 2. npm install`);
|
|
60
|
-
console.log(` 3. Copy .env.sample to .env and configure your credentials`);
|
|
61
|
-
console.log(` 4.
|
|
60
|
+
console.log(` 3. Copy .env.sample to .env and configure your Beamable credentials`);
|
|
61
|
+
console.log(` 4. (Optional) Copy beam.env.example to beam.env for custom environment variables`);
|
|
62
|
+
console.log(` 5. npm run dev`);
|
|
62
63
|
}
|
|
63
64
|
/**
|
|
64
65
|
* Generates the complete project structure.
|
|
@@ -73,6 +74,7 @@ async function generateProjectStructure(targetDir, options) {
|
|
|
73
74
|
await fs.writeFile(path.join(targetDir, 'package.json'), generatePackageJson(options));
|
|
74
75
|
await fs.writeFile(path.join(targetDir, 'tsconfig.json'), generateTsConfig());
|
|
75
76
|
await fs.writeFile(path.join(targetDir, '.env.sample'), generateEnvSample());
|
|
77
|
+
await fs.writeFile(path.join(targetDir, 'beam.env.example'), generateBeamEnvExample());
|
|
76
78
|
await fs.writeFile(path.join(targetDir, '.gitignore'), generateGitIgnore());
|
|
77
79
|
await fs.writeFile(path.join(targetDir, 'src', 'main.ts'), generateMainTs(options));
|
|
78
80
|
await fs.writeFile(path.join(targetDir, 'src', `${toPascalCase(options.serviceName)}Service.ts`), generateServiceTs(options));
|
|
@@ -134,7 +136,11 @@ function generateTsConfig() {
|
|
|
134
136
|
* Generates .env.sample content.
|
|
135
137
|
*/
|
|
136
138
|
function generateEnvSample() {
|
|
137
|
-
return
|
|
139
|
+
return `# Beamable Authentication & Configuration
|
|
140
|
+
# This file is for Beamable-specific credentials (CID, PID, SECRET, etc.)
|
|
141
|
+
# For custom environment variables, use beam.env instead (see beam.env.example)
|
|
142
|
+
|
|
143
|
+
CID=
|
|
138
144
|
PID=
|
|
139
145
|
HOST=wss://api.beamable.com/socket
|
|
140
146
|
SECRET=
|
|
@@ -145,6 +151,35 @@ BEAMABLE_API_HOST=https://api.beamable.com
|
|
|
145
151
|
BEAMABLE_GAME_PID=
|
|
146
152
|
`;
|
|
147
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Generates beam.env.example content.
|
|
156
|
+
*/
|
|
157
|
+
function generateBeamEnvExample() {
|
|
158
|
+
return `# Beamable Microservice Environment Variables
|
|
159
|
+
#
|
|
160
|
+
# This file defines developer-specific environment variables that will be
|
|
161
|
+
# loaded into the container at runtime.
|
|
162
|
+
#
|
|
163
|
+
# These variables take priority over Beamable Config values but will NOT
|
|
164
|
+
# overwrite existing process.env values.
|
|
165
|
+
#
|
|
166
|
+
# Format: KEY=value (one per line)
|
|
167
|
+
# Comments start with #
|
|
168
|
+
# Empty lines are ignored
|
|
169
|
+
|
|
170
|
+
# Example: BetterStack Logging Configuration
|
|
171
|
+
# BEAM_BETTERSTACK_ENABLED=true
|
|
172
|
+
# BEAM_BETTERSTACK_TOKEN=your-token-here
|
|
173
|
+
|
|
174
|
+
# Example: Custom configuration
|
|
175
|
+
# MY_API_KEY=your-api-key-here
|
|
176
|
+
# MY_FEATURE_FLAG=true
|
|
177
|
+
|
|
178
|
+
# Example: Service-specific settings
|
|
179
|
+
# LOG_LEVEL=debug
|
|
180
|
+
# MAX_CONNECTIONS=100
|
|
181
|
+
`;
|
|
182
|
+
}
|
|
148
183
|
/**
|
|
149
184
|
* Generates .gitignore content.
|
|
150
185
|
*/
|
|
@@ -152,6 +187,9 @@ function generateGitIgnore() {
|
|
|
152
187
|
return `node_modules/
|
|
153
188
|
dist/
|
|
154
189
|
.env
|
|
190
|
+
.env.local
|
|
191
|
+
beam.env
|
|
192
|
+
.beam.env
|
|
155
193
|
*.log
|
|
156
194
|
.DS_Store
|
|
157
195
|
`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../../src/cli/commands/scaffold.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Command handler for scaffolding new microservice projects.\r\n */\r\n\r\nimport fs from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport { toPascalCase, toKebabCase, validateServiceName } from '../utils/name-utils.js';\r\nimport { fetchLatestRuntimeVersion } from '../utils/version-utils.js';\r\nimport { promptInput } from '../utils/prompt-utils.js';\r\n\r\ninterface ScaffoldOptions {\r\n serviceName: string;\r\n displayName?: string;\r\n beamoId?: string;\r\n runtimeVersion: string;\r\n}\r\n\r\n/**\r\n * Handles the scaffold command.\r\n */\r\nexport async function handleScaffold(args: string[]): Promise<void> {\r\n let serviceName = args[0];\r\n\r\n // Interactive prompt for service name if not provided\r\n if (!serviceName) {\r\n serviceName = await promptInput('Enter microservice name (alphanumeric and underscores only)');\r\n }\r\n\r\n // Validate service name\r\n if (!serviceName || !validateServiceName(serviceName)) {\r\n throw new Error(\r\n `Invalid microservice name \"${serviceName}\". Only alphanumeric and underscore characters are allowed.`,\r\n );\r\n }\r\n\r\n // Fetch latest runtime version\r\n console.log('Fetching latest runtime version...');\r\n const runtimeVersion = await fetchLatestRuntimeVersion();\r\n console.log(`Using @omen.foundation/node-microservice-runtime version ${runtimeVersion}`);\r\n\r\n // Prompt for optional values\r\n const displayName = await promptInput('Enter display name for the service (optional)', serviceName);\r\n const beamoId = await promptInput('Enter Beamable Beamo ID (optional, defaults to service name)', serviceName);\r\n\r\n // Validate beamoId\r\n if (beamoId && !validateServiceName(beamoId)) {\r\n throw new Error(\r\n `Invalid Beamo ID \"${beamoId}\". Only alphanumeric and underscore characters are allowed.`,\r\n );\r\n }\r\n\r\n const options: ScaffoldOptions = {\r\n serviceName,\r\n displayName: displayName || serviceName,\r\n beamoId: beamoId || serviceName,\r\n runtimeVersion,\r\n };\r\n\r\n // Check if directory already exists\r\n const targetDir = path.resolve(process.cwd(), serviceName);\r\n try {\r\n await fs.access(targetDir);\r\n const overwrite = await promptInput(\r\n `Directory \"${serviceName}\" already exists. Overwrite? (y/n)`,\r\n 'n',\r\n );\r\n if (overwrite.toLowerCase() !== 'y' && overwrite.toLowerCase() !== 'yes') {\r\n console.log('Scaffold cancelled.');\r\n return;\r\n }\r\n // Remove existing directory\r\n await fs.rm(targetDir, { recursive: true, force: true });\r\n } catch {\r\n // Directory doesn't exist, that's fine\r\n }\r\n\r\n // Generate project structure\r\n await generateProjectStructure(targetDir, options);\r\n\r\n console.log(`\\n✅ Successfully scaffolded microservice \"${serviceName}\"!`);\r\n console.log(`\\nNext steps:`);\r\n console.log(` 1. cd ${serviceName}`);\r\n console.log(` 2. npm install`);\r\n console.log(` 3. Copy .env.sample to .env and configure your credentials`);\r\n console.log(` 4. npm run dev`);\r\n}\r\n\r\n/**\r\n * Generates the complete project structure.\r\n */\r\nasync function generateProjectStructure(targetDir: string, options: ScaffoldOptions): Promise<void> {\r\n // Create directories\r\n await fs.mkdir(targetDir, { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'src'), { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'src', 'services'), { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'dist'), { recursive: true });\r\n\r\n // Generate files\r\n await fs.writeFile(path.join(targetDir, 'package.json'), generatePackageJson(options));\r\n await fs.writeFile(path.join(targetDir, 'tsconfig.json'), generateTsConfig());\r\n await fs.writeFile(path.join(targetDir, '.env.sample'), generateEnvSample());\r\n await fs.writeFile(path.join(targetDir, '.gitignore'), generateGitIgnore());\r\n await fs.writeFile(path.join(targetDir, 'src', 'main.ts'), generateMainTs(options));\r\n await fs.writeFile(\r\n path.join(targetDir, 'src', `${toPascalCase(options.serviceName)}Service.ts`),\r\n generateServiceTs(options),\r\n );\r\n await fs.writeFile(\r\n path.join(targetDir, 'src', 'services', 'example-domain-service.ts'),\r\n generateDomainServiceTs(),\r\n );\r\n}\r\n\r\n/**\r\n * Generates package.json content.\r\n */\r\nfunction generatePackageJson(options: ScaffoldOptions): string {\r\n const serviceNameKebab = toKebabCase(options.serviceName);\r\n const packageName = `@beamable/${serviceNameKebab}-node-microservice`;\r\n\r\n return JSON.stringify(\r\n {\r\n name: packageName,\r\n version: '0.1.0',\r\n private: true,\r\n type: 'module',\r\n main: 'dist/main.js',\r\n types: 'dist/main.d.ts',\r\n scripts: {\r\n dev: 'tsx --env-file .env src/main.ts',\r\n build: 'tsc -p tsconfig.json',\r\n validate: 'npx beamo-node validate --env-file .env',\r\n publish: 'npx beamo-node publish --env-file .env',\r\n },\r\n dependencies: {\r\n '@omen.foundation/node-microservice-runtime': `^${options.runtimeVersion}`,\r\n dotenv: '^16.4.7',\r\n mongodb: '^6.10.0',\r\n },\r\n devDependencies: {\r\n '@types/node': '^20.11.30',\r\n 'pino-pretty': '^13.0.0',\r\n tsx: '^4.19.2',\r\n typescript: '^5.4.5',\r\n },\r\n beamable: {\r\n beamoId: options.beamoId,\r\n projectType: 'service',\r\n },\r\n },\r\n null,\r\n 2,\r\n );\r\n}\r\n\r\n/**\r\n * Generates tsconfig.json content.\r\n */\r\nfunction generateTsConfig(): string {\r\n return JSON.stringify(\r\n {\r\n extends: '../Microservice/tsconfig.base.json',\r\n compilerOptions: {\r\n outDir: 'dist',\r\n rootDir: 'src',\r\n declaration: true,\r\n declarationMap: true,\r\n },\r\n include: ['src/**/*.ts'],\r\n exclude: ['dist', 'node_modules'],\r\n },\r\n null,\r\n 2,\r\n );\r\n}\r\n\r\n/**\r\n * Generates .env.sample content.\r\n */\r\nfunction generateEnvSample(): string {\r\n return `CID=\r\nPID=\r\nHOST=wss://api.beamable.com/socket\r\nSECRET=\r\nNAME_PREFIX=\r\nLOG_LEVEL=info\r\nBEAMABLE_TOKEN=\r\nBEAMABLE_API_HOST=https://api.beamable.com\r\nBEAMABLE_GAME_PID=\r\n`;\r\n}\r\n\r\n/**\r\n * Generates .gitignore content.\r\n */\r\nfunction generateGitIgnore(): string {\r\n return `node_modules/\r\ndist/\r\n.env\r\n*.log\r\n.DS_Store\r\n`;\r\n}\r\n\r\n/**\r\n * Generates main.ts content.\r\n */\r\nfunction generateMainTs(options: ScaffoldOptions): string {\r\n const serviceNamePascal = toPascalCase(options.serviceName);\r\n return `import 'dotenv/config';\r\nimport './${serviceNamePascal}Service.js';\r\nimport { runMicroservice } from '@omen.foundation/node-microservice-runtime';\r\n\r\nvoid runMicroservice();\r\n`;\r\n}\r\n\r\n/**\r\n * Generates the main service class file.\r\n */\r\nfunction generateServiceTs(options: ScaffoldOptions): string {\r\n const serviceNamePascal = toPascalCase(options.serviceName);\r\n return `import {\r\n Microservice,\r\n Callable,\r\n ClientCallable,\r\n ServerCallable,\r\n SwaggerCategory,\r\n ConfigureServices,\r\n type DependencyBuilder,\r\n type RequestContext,\r\n} from '@omen.foundation/node-microservice-runtime';\r\nimport { ExampleDomainService } from './services/example-domain-service.js';\r\n\r\n@Microservice('${options.serviceName}')\r\nexport class ${serviceNamePascal}Service {\r\n @ConfigureServices\r\n static register(builder: DependencyBuilder): void {\r\n builder.addSingletonClass(ExampleDomainService);\r\n }\r\n\r\n /**\r\n * Example of a public Callable endpoint.\r\n * No authentication required.\r\n */\r\n @Callable({ route: 'isTwo' })\r\n @SwaggerCategory('Examples')\r\n async isTwo(_ctx: RequestContext): Promise<boolean> {\r\n return 1 + 1 === 2;\r\n }\r\n\r\n /**\r\n * Example of a ClientCallable endpoint.\r\n * Requires user authentication (client scope).\r\n */\r\n @ClientCallable({ route: 'isThree' })\r\n @SwaggerCategory('Examples')\r\n async isThree(_ctx: RequestContext): Promise<boolean> {\r\n return 1 + 2 === 3;\r\n }\r\n\r\n /**\r\n * Example of a ServerCallable endpoint.\r\n * Requires server authentication (server scope).\r\n */\r\n @ServerCallable({ route: 'isFour' })\r\n @SwaggerCategory('Examples')\r\n async isFour(_ctx: RequestContext): Promise<boolean> {\r\n return 2 + 2 === 4;\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * Generates example domain service content.\r\n */\r\nfunction generateDomainServiceTs(): string {\r\n return `import type { RequestContext } from '@omen.foundation/node-microservice-runtime';\r\n\r\nexport class ExampleDomainService {\r\n greet(userId: number): string {\r\n return \\`Hello from Node microservices, user \\${userId}!\\`;\r\n }\r\n\r\n async getServiceInfo(_ctx: RequestContext): Promise<{ service: string; version: string }> {\r\n return {\r\n service: 'ExampleDomainService',\r\n version: '1.0.0',\r\n };\r\n }\r\n}\r\n`;\r\n}\r\n\r\n"]}
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../../src/cli/commands/scaffold.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Command handler for scaffolding new microservice projects.\r\n */\r\n\r\nimport fs from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport { toPascalCase, toKebabCase, validateServiceName } from '../utils/name-utils.js';\r\nimport { fetchLatestRuntimeVersion } from '../utils/version-utils.js';\r\nimport { promptInput } from '../utils/prompt-utils.js';\r\n\r\ninterface ScaffoldOptions {\r\n serviceName: string;\r\n displayName?: string;\r\n beamoId?: string;\r\n runtimeVersion: string;\r\n}\r\n\r\n/**\r\n * Handles the scaffold command.\r\n */\r\nexport async function handleScaffold(args: string[]): Promise<void> {\r\n let serviceName = args[0];\r\n\r\n // Interactive prompt for service name if not provided\r\n if (!serviceName) {\r\n serviceName = await promptInput('Enter microservice name (alphanumeric and underscores only)');\r\n }\r\n\r\n // Validate service name\r\n if (!serviceName || !validateServiceName(serviceName)) {\r\n throw new Error(\r\n `Invalid microservice name \"${serviceName}\". Only alphanumeric and underscore characters are allowed.`,\r\n );\r\n }\r\n\r\n // Fetch latest runtime version\r\n console.log('Fetching latest runtime version...');\r\n const runtimeVersion = await fetchLatestRuntimeVersion();\r\n console.log(`Using @omen.foundation/node-microservice-runtime version ${runtimeVersion}`);\r\n\r\n // Prompt for optional values\r\n const displayName = await promptInput('Enter display name for the service (optional)', serviceName);\r\n const beamoId = await promptInput('Enter Beamable Beamo ID (optional, defaults to service name)', serviceName);\r\n\r\n // Validate beamoId\r\n if (beamoId && !validateServiceName(beamoId)) {\r\n throw new Error(\r\n `Invalid Beamo ID \"${beamoId}\". Only alphanumeric and underscore characters are allowed.`,\r\n );\r\n }\r\n\r\n const options: ScaffoldOptions = {\r\n serviceName,\r\n displayName: displayName || serviceName,\r\n beamoId: beamoId || serviceName,\r\n runtimeVersion,\r\n };\r\n\r\n // Check if directory already exists\r\n const targetDir = path.resolve(process.cwd(), serviceName);\r\n try {\r\n await fs.access(targetDir);\r\n const overwrite = await promptInput(\r\n `Directory \"${serviceName}\" already exists. Overwrite? (y/n)`,\r\n 'n',\r\n );\r\n if (overwrite.toLowerCase() !== 'y' && overwrite.toLowerCase() !== 'yes') {\r\n console.log('Scaffold cancelled.');\r\n return;\r\n }\r\n // Remove existing directory\r\n await fs.rm(targetDir, { recursive: true, force: true });\r\n } catch {\r\n // Directory doesn't exist, that's fine\r\n }\r\n\r\n // Generate project structure\r\n await generateProjectStructure(targetDir, options);\r\n\r\n console.log(`\\n✅ Successfully scaffolded microservice \"${serviceName}\"!`);\r\n console.log(`\\nNext steps:`);\r\n console.log(` 1. cd ${serviceName}`);\r\n console.log(` 2. npm install`);\r\n console.log(` 3. Copy .env.sample to .env and configure your Beamable credentials`);\r\n console.log(` 4. (Optional) Copy beam.env.example to beam.env for custom environment variables`);\r\n console.log(` 5. npm run dev`);\r\n}\r\n\r\n/**\r\n * Generates the complete project structure.\r\n */\r\nasync function generateProjectStructure(targetDir: string, options: ScaffoldOptions): Promise<void> {\r\n // Create directories\r\n await fs.mkdir(targetDir, { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'src'), { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'src', 'services'), { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'dist'), { recursive: true });\r\n\r\n // Generate files\r\n await fs.writeFile(path.join(targetDir, 'package.json'), generatePackageJson(options));\r\n await fs.writeFile(path.join(targetDir, 'tsconfig.json'), generateTsConfig());\r\n await fs.writeFile(path.join(targetDir, '.env.sample'), generateEnvSample());\r\n await fs.writeFile(path.join(targetDir, 'beam.env.example'), generateBeamEnvExample());\r\n await fs.writeFile(path.join(targetDir, '.gitignore'), generateGitIgnore());\r\n await fs.writeFile(path.join(targetDir, 'src', 'main.ts'), generateMainTs(options));\r\n await fs.writeFile(\r\n path.join(targetDir, 'src', `${toPascalCase(options.serviceName)}Service.ts`),\r\n generateServiceTs(options),\r\n );\r\n await fs.writeFile(\r\n path.join(targetDir, 'src', 'services', 'example-domain-service.ts'),\r\n generateDomainServiceTs(),\r\n );\r\n}\r\n\r\n/**\r\n * Generates package.json content.\r\n */\r\nfunction generatePackageJson(options: ScaffoldOptions): string {\r\n const serviceNameKebab = toKebabCase(options.serviceName);\r\n const packageName = `@beamable/${serviceNameKebab}-node-microservice`;\r\n\r\n return JSON.stringify(\r\n {\r\n name: packageName,\r\n version: '0.1.0',\r\n private: true,\r\n type: 'module',\r\n main: 'dist/main.js',\r\n types: 'dist/main.d.ts',\r\n scripts: {\r\n dev: 'tsx --env-file .env src/main.ts',\r\n build: 'tsc -p tsconfig.json',\r\n validate: 'npx beamo-node validate --env-file .env',\r\n publish: 'npx beamo-node publish --env-file .env',\r\n },\r\n dependencies: {\r\n '@omen.foundation/node-microservice-runtime': `^${options.runtimeVersion}`,\r\n dotenv: '^16.4.7',\r\n mongodb: '^6.10.0',\r\n },\r\n devDependencies: {\r\n '@types/node': '^20.11.30',\r\n 'pino-pretty': '^13.0.0',\r\n tsx: '^4.19.2',\r\n typescript: '^5.4.5',\r\n },\r\n beamable: {\r\n beamoId: options.beamoId,\r\n projectType: 'service',\r\n },\r\n },\r\n null,\r\n 2,\r\n );\r\n}\r\n\r\n/**\r\n * Generates tsconfig.json content.\r\n */\r\nfunction generateTsConfig(): string {\r\n return JSON.stringify(\r\n {\r\n extends: '../Microservice/tsconfig.base.json',\r\n compilerOptions: {\r\n outDir: 'dist',\r\n rootDir: 'src',\r\n declaration: true,\r\n declarationMap: true,\r\n },\r\n include: ['src/**/*.ts'],\r\n exclude: ['dist', 'node_modules'],\r\n },\r\n null,\r\n 2,\r\n );\r\n}\r\n\r\n/**\r\n * Generates .env.sample content.\r\n */\r\nfunction generateEnvSample(): string {\r\n return `# Beamable Authentication & Configuration\r\n# This file is for Beamable-specific credentials (CID, PID, SECRET, etc.)\r\n# For custom environment variables, use beam.env instead (see beam.env.example)\r\n\r\nCID=\r\nPID=\r\nHOST=wss://api.beamable.com/socket\r\nSECRET=\r\nNAME_PREFIX=\r\nLOG_LEVEL=info\r\nBEAMABLE_TOKEN=\r\nBEAMABLE_API_HOST=https://api.beamable.com\r\nBEAMABLE_GAME_PID=\r\n`;\r\n}\r\n\r\n/**\r\n * Generates beam.env.example content.\r\n */\r\nfunction generateBeamEnvExample(): string {\r\n return `# Beamable Microservice Environment Variables\r\n# \r\n# This file defines developer-specific environment variables that will be\r\n# loaded into the container at runtime.\r\n#\r\n# These variables take priority over Beamable Config values but will NOT\r\n# overwrite existing process.env values.\r\n#\r\n# Format: KEY=value (one per line)\r\n# Comments start with #\r\n# Empty lines are ignored\r\n\r\n# Example: BetterStack Logging Configuration\r\n# BEAM_BETTERSTACK_ENABLED=true\r\n# BEAM_BETTERSTACK_TOKEN=your-token-here\r\n\r\n# Example: Custom configuration\r\n# MY_API_KEY=your-api-key-here\r\n# MY_FEATURE_FLAG=true\r\n\r\n# Example: Service-specific settings\r\n# LOG_LEVEL=debug\r\n# MAX_CONNECTIONS=100\r\n`;\r\n}\r\n\r\n/**\r\n * Generates .gitignore content.\r\n */\r\nfunction generateGitIgnore(): string {\r\n return `node_modules/\r\ndist/\r\n.env\r\n.env.local\r\nbeam.env\r\n.beam.env\r\n*.log\r\n.DS_Store\r\n`;\r\n}\r\n\r\n/**\r\n * Generates main.ts content.\r\n */\r\nfunction generateMainTs(options: ScaffoldOptions): string {\r\n const serviceNamePascal = toPascalCase(options.serviceName);\r\n return `import 'dotenv/config';\r\nimport './${serviceNamePascal}Service.js';\r\nimport { runMicroservice } from '@omen.foundation/node-microservice-runtime';\r\n\r\nvoid runMicroservice();\r\n`;\r\n}\r\n\r\n/**\r\n * Generates the main service class file.\r\n */\r\nfunction generateServiceTs(options: ScaffoldOptions): string {\r\n const serviceNamePascal = toPascalCase(options.serviceName);\r\n return `import {\r\n Microservice,\r\n Callable,\r\n ClientCallable,\r\n ServerCallable,\r\n SwaggerCategory,\r\n ConfigureServices,\r\n type DependencyBuilder,\r\n type RequestContext,\r\n} from '@omen.foundation/node-microservice-runtime';\r\nimport { ExampleDomainService } from './services/example-domain-service.js';\r\n\r\n@Microservice('${options.serviceName}')\r\nexport class ${serviceNamePascal}Service {\r\n @ConfigureServices\r\n static register(builder: DependencyBuilder): void {\r\n builder.addSingletonClass(ExampleDomainService);\r\n }\r\n\r\n /**\r\n * Example of a public Callable endpoint.\r\n * No authentication required.\r\n */\r\n @Callable({ route: 'isTwo' })\r\n @SwaggerCategory('Examples')\r\n async isTwo(_ctx: RequestContext): Promise<boolean> {\r\n return 1 + 1 === 2;\r\n }\r\n\r\n /**\r\n * Example of a ClientCallable endpoint.\r\n * Requires user authentication (client scope).\r\n */\r\n @ClientCallable({ route: 'isThree' })\r\n @SwaggerCategory('Examples')\r\n async isThree(_ctx: RequestContext): Promise<boolean> {\r\n return 1 + 2 === 3;\r\n }\r\n\r\n /**\r\n * Example of a ServerCallable endpoint.\r\n * Requires server authentication (server scope).\r\n */\r\n @ServerCallable({ route: 'isFour' })\r\n @SwaggerCategory('Examples')\r\n async isFour(_ctx: RequestContext): Promise<boolean> {\r\n return 2 + 2 === 4;\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * Generates example domain service content.\r\n */\r\nfunction generateDomainServiceTs(): string {\r\n return `import type { RequestContext } from '@omen.foundation/node-microservice-runtime';\r\n\r\nexport class ExampleDomainService {\r\n greet(userId: number): string {\r\n return \\`Hello from Node microservices, user \\${userId}!\\`;\r\n }\r\n\r\n async getServiceInfo(_ctx: RequestContext): Promise<{ service: string; version: string }> {\r\n return {\r\n service: 'ExampleDomainService',\r\n version: '1.0.0',\r\n };\r\n }\r\n}\r\n`;\r\n}\r\n\r\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Variable Loader
|
|
3
|
+
*
|
|
4
|
+
* This module handles loading environment variables from two sources:
|
|
5
|
+
* 1. Developer-defined variables (from beam.env file)
|
|
6
|
+
* 2. Beamable Config values (from API: namespace -> environment -> key-value pairs)
|
|
7
|
+
*
|
|
8
|
+
* All variables are injected into process.env before service initialization.
|
|
9
|
+
*/
|
|
10
|
+
import type { EnvironmentConfig } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Loads developer-defined environment variables from beam.env file
|
|
13
|
+
* Supports standard .env format: KEY=value
|
|
14
|
+
*
|
|
15
|
+
* This is exported for synchronous loading before logger initialization
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadDeveloperEnvVarsSync(beamEnvPath?: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Loads all environment variables from both sources and injects them into process.env
|
|
20
|
+
*
|
|
21
|
+
* Priority (highest to lowest):
|
|
22
|
+
* 1. Existing process.env values (never overwrite)
|
|
23
|
+
* 2. Developer-defined variables (beam.env)
|
|
24
|
+
* 3. Beamable Config values (API)
|
|
25
|
+
*
|
|
26
|
+
* @param env - Environment configuration (CID, PID, HOST, SECRET)
|
|
27
|
+
* @param beamEnvPath - Optional path to beam.env file
|
|
28
|
+
* @param waitForConfig - If true, waits up to timeoutMs for Beamable Config. If false, returns immediately after developer vars.
|
|
29
|
+
* @param timeoutMs - Maximum time to wait for Beamable Config (default: 2000ms)
|
|
30
|
+
*/
|
|
31
|
+
export declare function loadAndInjectEnvironmentVariables(env: EnvironmentConfig, beamEnvPath?: string, waitForConfig?: boolean, timeoutMs?: number): Promise<void>;
|
|
32
|
+
//# sourceMappingURL=env-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-loader.d.ts","sourceRoot":"","sources":["../src/env-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAsBpD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAenE;AA2KD;;;;;;;;;;;;GAYG;AACH,wBAAsB,iCAAiC,CACrD,GAAG,EAAE,iBAAiB,EACtB,WAAW,CAAC,EAAE,MAAM,EACpB,aAAa,GAAE,OAAc,EAC7B,SAAS,GAAE,MAAa,GACvB,OAAO,CAAC,IAAI,CAAC,CAoEf"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Variable Loader
|
|
3
|
+
*
|
|
4
|
+
* This module handles loading environment variables from two sources:
|
|
5
|
+
* 1. Developer-defined variables (from beam.env file)
|
|
6
|
+
* 2. Beamable Config values (from API: namespace -> environment -> key-value pairs)
|
|
7
|
+
*
|
|
8
|
+
* All variables are injected into process.env before service initialization.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { createHash } from 'node:crypto';
|
|
13
|
+
import { URL } from 'node:url';
|
|
14
|
+
import { hostToHttpUrl } from './utils/urls.js';
|
|
15
|
+
/**
|
|
16
|
+
* Calculates Beamable signature for signed requests
|
|
17
|
+
* Signature format: MD5(secret + pid + version + uriPathAndQuery + body) as Base64
|
|
18
|
+
*/
|
|
19
|
+
function calculateSignature(pid, secret, uriPathAndQuery, body = null, version = '1') {
|
|
20
|
+
let dataToSign = `${secret}${pid}${version}${uriPathAndQuery}`;
|
|
21
|
+
if (body) {
|
|
22
|
+
dataToSign += body;
|
|
23
|
+
}
|
|
24
|
+
const hash = createHash('md5').update(dataToSign, 'utf8').digest('base64');
|
|
25
|
+
return hash;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Loads developer-defined environment variables from beam.env file
|
|
29
|
+
* Supports standard .env format: KEY=value
|
|
30
|
+
*
|
|
31
|
+
* This is exported for synchronous loading before logger initialization
|
|
32
|
+
*/
|
|
33
|
+
export function loadDeveloperEnvVarsSync(beamEnvPath) {
|
|
34
|
+
const envVars = loadDeveloperEnvVars(beamEnvPath);
|
|
35
|
+
// Inject immediately into process.env
|
|
36
|
+
let injectedCount = 0;
|
|
37
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
38
|
+
if (!(key in process.env)) {
|
|
39
|
+
process.env[key] = value;
|
|
40
|
+
injectedCount++;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (injectedCount > 0) {
|
|
44
|
+
console.log(`[EnvLoader] Synchronously injected ${injectedCount} developer-defined variables from beam.env`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Loads developer-defined environment variables from beam.env file
|
|
49
|
+
* Supports standard .env format: KEY=value
|
|
50
|
+
*/
|
|
51
|
+
function loadDeveloperEnvVars(beamEnvPath) {
|
|
52
|
+
const envVars = {};
|
|
53
|
+
// Try to find beam.env file
|
|
54
|
+
const possiblePaths = [
|
|
55
|
+
beamEnvPath,
|
|
56
|
+
join(process.cwd(), 'beam.env'),
|
|
57
|
+
join(process.cwd(), '.beam.env'),
|
|
58
|
+
'/beam/service/beam.env', // Container path
|
|
59
|
+
'/beam/service/.beam.env',
|
|
60
|
+
].filter((path) => !!path && existsSync(path));
|
|
61
|
+
if (possiblePaths.length === 0) {
|
|
62
|
+
return envVars;
|
|
63
|
+
}
|
|
64
|
+
const envFilePath = possiblePaths[0];
|
|
65
|
+
try {
|
|
66
|
+
const content = readFileSync(envFilePath, 'utf-8');
|
|
67
|
+
const lines = content.split('\n');
|
|
68
|
+
for (const line of lines) {
|
|
69
|
+
const trimmed = line.trim();
|
|
70
|
+
// Skip empty lines and comments
|
|
71
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
// Parse KEY=value format
|
|
75
|
+
const match = trimmed.match(/^([^=#]+)=(.*)$/);
|
|
76
|
+
if (match) {
|
|
77
|
+
const key = match[1].trim();
|
|
78
|
+
let value = match[2].trim();
|
|
79
|
+
// Remove quotes if present
|
|
80
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
81
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
82
|
+
value = value.slice(1, -1);
|
|
83
|
+
}
|
|
84
|
+
if (key) {
|
|
85
|
+
envVars[key] = value;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
console.log(`[EnvLoader] Loaded ${Object.keys(envVars).length} variables from ${envFilePath}`);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
console.warn(`[EnvLoader] Failed to load beam.env from ${envFilePath}:`, error instanceof Error ? error.message : String(error));
|
|
93
|
+
}
|
|
94
|
+
return envVars;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Fetches Beamable Config values from the API
|
|
98
|
+
*
|
|
99
|
+
* The endpoint can be configured via BEAM_CONFIG_API_PATH environment variable.
|
|
100
|
+
* Default: /api/basic/realms/config
|
|
101
|
+
*
|
|
102
|
+
* Note: The exact endpoint format may vary. The API should return a structure like:
|
|
103
|
+
* {
|
|
104
|
+
* "config": {
|
|
105
|
+
* "key1": {
|
|
106
|
+
* "environment": "value1"
|
|
107
|
+
* }
|
|
108
|
+
* }
|
|
109
|
+
* }
|
|
110
|
+
*
|
|
111
|
+
* Returns key-value pairs from the current realm's config namespace/environment
|
|
112
|
+
*/
|
|
113
|
+
async function fetchBeamableConfig(env) {
|
|
114
|
+
const configVars = {};
|
|
115
|
+
// Skip if we don't have required credentials
|
|
116
|
+
if (!env.secret || !env.cid || !env.pid) {
|
|
117
|
+
console.log('[EnvLoader] Skipping Beamable Config fetch - missing SECRET, CID, or PID');
|
|
118
|
+
return configVars;
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const apiUrl = hostToHttpUrl(env.host);
|
|
122
|
+
// Allow endpoint to be configured via environment variable (for flexibility)
|
|
123
|
+
const uriPath = process.env.BEAM_CONFIG_API_PATH || '/api/basic/realms/config';
|
|
124
|
+
const configUrl = new URL(uriPath, apiUrl).toString();
|
|
125
|
+
// Calculate signature for signed request
|
|
126
|
+
const pathAndQuery = uriPath;
|
|
127
|
+
const signature = calculateSignature(env.pid, env.secret, pathAndQuery, null, '1');
|
|
128
|
+
console.log(`[EnvLoader] Fetching Beamable Config from ${configUrl}...`);
|
|
129
|
+
const response = await fetch(configUrl, {
|
|
130
|
+
method: 'GET',
|
|
131
|
+
headers: {
|
|
132
|
+
'Content-Type': 'application/json',
|
|
133
|
+
Accept: 'application/json',
|
|
134
|
+
'X-BEAM-SCOPE': `${env.cid}.${env.pid}`,
|
|
135
|
+
'X-BEAM-SIGNATURE': signature,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
if (!response.ok) {
|
|
139
|
+
const errorText = await response.text().catch(() => 'Unknown error');
|
|
140
|
+
console.warn(`[EnvLoader] Failed to fetch Beamable Config: ${response.status} ${response.statusText} - ${errorText.substring(0, 200)}`);
|
|
141
|
+
return configVars;
|
|
142
|
+
}
|
|
143
|
+
const data = (await response.json());
|
|
144
|
+
// Parse config structure: config[key][environment] = value
|
|
145
|
+
// We need to determine the current environment - typically it's the PID or a specific env var
|
|
146
|
+
const currentEnvironment = process.env.BEAM_ENVIRONMENT || process.env.ENVIRONMENT || env.pid;
|
|
147
|
+
if (data.config) {
|
|
148
|
+
for (const [key, environments] of Object.entries(data.config)) {
|
|
149
|
+
// Try to get value for current environment, fallback to first available
|
|
150
|
+
let value;
|
|
151
|
+
if (environments && typeof environments === 'object') {
|
|
152
|
+
value = environments[currentEnvironment];
|
|
153
|
+
// If no value for current environment, try common environment names
|
|
154
|
+
if (value === undefined) {
|
|
155
|
+
value = environments['production'] ||
|
|
156
|
+
environments['staging'] ||
|
|
157
|
+
environments['development'] ||
|
|
158
|
+
environments['dev'] ||
|
|
159
|
+
Object.values(environments)[0];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Convert value to string and add to env vars
|
|
163
|
+
if (value !== undefined && value !== null) {
|
|
164
|
+
// Use BEAM_CONFIG_ prefix to avoid conflicts
|
|
165
|
+
const envKey = `BEAM_CONFIG_${key.toUpperCase()}`;
|
|
166
|
+
configVars[envKey] = String(value);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
console.log(`[EnvLoader] Loaded ${Object.keys(configVars).length} variables from Beamable Config`);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
console.log('[EnvLoader] Beamable Config response contains no config object');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
console.warn('[EnvLoader] Failed to fetch Beamable Config:', error instanceof Error ? error.message : String(error));
|
|
177
|
+
}
|
|
178
|
+
return configVars;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Loads all environment variables from both sources and injects them into process.env
|
|
182
|
+
*
|
|
183
|
+
* Priority (highest to lowest):
|
|
184
|
+
* 1. Existing process.env values (never overwrite)
|
|
185
|
+
* 2. Developer-defined variables (beam.env)
|
|
186
|
+
* 3. Beamable Config values (API)
|
|
187
|
+
*
|
|
188
|
+
* @param env - Environment configuration (CID, PID, HOST, SECRET)
|
|
189
|
+
* @param beamEnvPath - Optional path to beam.env file
|
|
190
|
+
* @param waitForConfig - If true, waits up to timeoutMs for Beamable Config. If false, returns immediately after developer vars.
|
|
191
|
+
* @param timeoutMs - Maximum time to wait for Beamable Config (default: 2000ms)
|
|
192
|
+
*/
|
|
193
|
+
export async function loadAndInjectEnvironmentVariables(env, beamEnvPath, waitForConfig = true, timeoutMs = 2000) {
|
|
194
|
+
console.log('[EnvLoader] Starting environment variable loading...');
|
|
195
|
+
// Load developer-defined variables from beam.env (synchronous, immediate)
|
|
196
|
+
const developerVars = loadDeveloperEnvVars(beamEnvPath);
|
|
197
|
+
// Inject developer vars immediately
|
|
198
|
+
let injectedCount = 0;
|
|
199
|
+
for (const [key, value] of Object.entries(developerVars)) {
|
|
200
|
+
if (!(key in process.env)) {
|
|
201
|
+
process.env[key] = value;
|
|
202
|
+
injectedCount++;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (injectedCount > 0) {
|
|
206
|
+
console.log(`[EnvLoader] Injected ${injectedCount} developer-defined variables from beam.env`);
|
|
207
|
+
}
|
|
208
|
+
// Fetch Beamable Config values (async, with optional timeout)
|
|
209
|
+
if (waitForConfig) {
|
|
210
|
+
try {
|
|
211
|
+
const configPromise = fetchBeamableConfig(env);
|
|
212
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
213
|
+
setTimeout(() => {
|
|
214
|
+
console.warn(`[EnvLoader] Beamable Config fetch timed out after ${timeoutMs}ms, continuing without it`);
|
|
215
|
+
resolve({});
|
|
216
|
+
}, timeoutMs);
|
|
217
|
+
});
|
|
218
|
+
const beamableConfigVars = await Promise.race([configPromise, timeoutPromise]);
|
|
219
|
+
// Inject Beamable Config vars
|
|
220
|
+
let configInjectedCount = 0;
|
|
221
|
+
for (const [key, value] of Object.entries(beamableConfigVars)) {
|
|
222
|
+
if (!(key in process.env)) {
|
|
223
|
+
process.env[key] = value;
|
|
224
|
+
configInjectedCount++;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (configInjectedCount > 0) {
|
|
228
|
+
console.log(`[EnvLoader] Injected ${configInjectedCount} variables from Beamable Config`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
console.warn('[EnvLoader] Error loading Beamable Config (continuing anyway):', error instanceof Error ? error.message : String(error));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
// Start fetch in background (non-blocking)
|
|
237
|
+
fetchBeamableConfig(env)
|
|
238
|
+
.then((beamableConfigVars) => {
|
|
239
|
+
let configInjectedCount = 0;
|
|
240
|
+
for (const [key, value] of Object.entries(beamableConfigVars)) {
|
|
241
|
+
if (!(key in process.env)) {
|
|
242
|
+
process.env[key] = value;
|
|
243
|
+
configInjectedCount++;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (configInjectedCount > 0) {
|
|
247
|
+
console.log(`[EnvLoader] Injected ${configInjectedCount} variables from Beamable Config (loaded asynchronously)`);
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
.catch((error) => {
|
|
251
|
+
console.warn('[EnvLoader] Failed to load Beamable Config in background:', error instanceof Error ? error.message : String(error));
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
console.log('[EnvLoader] Environment variable loading completed');
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=env-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-loader.js","sourceRoot":"","sources":["../src/env-loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Environment Variable Loader\r\n * \r\n * This module handles loading environment variables from two sources:\r\n * 1. Developer-defined variables (from beam.env file)\r\n * 2. Beamable Config values (from API: namespace -> environment -> key-value pairs)\r\n * \r\n * All variables are injected into process.env before service initialization.\r\n */\r\n\r\nimport { existsSync, readFileSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { createHash } from 'node:crypto';\r\nimport { URL } from 'node:url';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { hostToHttpUrl } from './utils/urls.js';\r\n\r\n/**\r\n * Calculates Beamable signature for signed requests\r\n * Signature format: MD5(secret + pid + version + uriPathAndQuery + body) as Base64\r\n */\r\nfunction calculateSignature(\r\n pid: string,\r\n secret: string,\r\n uriPathAndQuery: string,\r\n body: string | null = null,\r\n version: string = '1'\r\n): string {\r\n let dataToSign = `${secret}${pid}${version}${uriPathAndQuery}`;\r\n if (body) {\r\n dataToSign += body;\r\n }\r\n const hash = createHash('md5').update(dataToSign, 'utf8').digest('base64');\r\n return hash;\r\n}\r\n\r\n/**\r\n * Loads developer-defined environment variables from beam.env file\r\n * Supports standard .env format: KEY=value\r\n * \r\n * This is exported for synchronous loading before logger initialization\r\n */\r\nexport function loadDeveloperEnvVarsSync(beamEnvPath?: string): void {\r\n const envVars = loadDeveloperEnvVars(beamEnvPath);\r\n \r\n // Inject immediately into process.env\r\n let injectedCount = 0;\r\n for (const [key, value] of Object.entries(envVars)) {\r\n if (!(key in process.env)) {\r\n process.env[key] = value;\r\n injectedCount++;\r\n }\r\n }\r\n \r\n if (injectedCount > 0) {\r\n console.log(`[EnvLoader] Synchronously injected ${injectedCount} developer-defined variables from beam.env`);\r\n }\r\n}\r\n\r\n/**\r\n * Loads developer-defined environment variables from beam.env file\r\n * Supports standard .env format: KEY=value\r\n */\r\nfunction loadDeveloperEnvVars(beamEnvPath?: string): Record<string, string> {\r\n const envVars: Record<string, string> = {};\r\n \r\n // Try to find beam.env file\r\n const possiblePaths = [\r\n beamEnvPath,\r\n join(process.cwd(), 'beam.env'),\r\n join(process.cwd(), '.beam.env'),\r\n '/beam/service/beam.env', // Container path\r\n '/beam/service/.beam.env',\r\n ].filter((path): path is string => !!path && existsSync(path));\r\n\r\n if (possiblePaths.length === 0) {\r\n return envVars;\r\n }\r\n\r\n const envFilePath = possiblePaths[0];\r\n try {\r\n const content = readFileSync(envFilePath, 'utf-8');\r\n const lines = content.split('\\n');\r\n \r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n // Skip empty lines and comments\r\n if (!trimmed || trimmed.startsWith('#')) {\r\n continue;\r\n }\r\n \r\n // Parse KEY=value format\r\n const match = trimmed.match(/^([^=#]+)=(.*)$/);\r\n if (match) {\r\n const key = match[1].trim();\r\n let value = match[2].trim();\r\n \r\n // Remove quotes if present\r\n if ((value.startsWith('\"') && value.endsWith('\"')) || \r\n (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\r\n value = value.slice(1, -1);\r\n }\r\n \r\n if (key) {\r\n envVars[key] = value;\r\n }\r\n }\r\n }\r\n \r\n console.log(`[EnvLoader] Loaded ${Object.keys(envVars).length} variables from ${envFilePath}`);\r\n } catch (error) {\r\n console.warn(`[EnvLoader] Failed to load beam.env from ${envFilePath}:`, error instanceof Error ? error.message : String(error));\r\n }\r\n \r\n return envVars;\r\n}\r\n\r\n/**\r\n * Beamable Config API response structure\r\n */\r\ninterface BeamableConfigResponse {\r\n config?: {\r\n [key: string]: {\r\n [environment: string]: string | number | boolean | null;\r\n };\r\n };\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * Fetches Beamable Config values from the API\r\n * \r\n * The endpoint can be configured via BEAM_CONFIG_API_PATH environment variable.\r\n * Default: /api/basic/realms/config\r\n * \r\n * Note: The exact endpoint format may vary. The API should return a structure like:\r\n * {\r\n * \"config\": {\r\n * \"key1\": {\r\n * \"environment\": \"value1\"\r\n * }\r\n * }\r\n * }\r\n * \r\n * Returns key-value pairs from the current realm's config namespace/environment\r\n */\r\nasync function fetchBeamableConfig(\r\n env: EnvironmentConfig\r\n): Promise<Record<string, string>> {\r\n const configVars: Record<string, string> = {};\r\n \r\n // Skip if we don't have required credentials\r\n if (!env.secret || !env.cid || !env.pid) {\r\n console.log('[EnvLoader] Skipping Beamable Config fetch - missing SECRET, CID, or PID');\r\n return configVars;\r\n }\r\n\r\n try {\r\n const apiUrl = hostToHttpUrl(env.host);\r\n // Allow endpoint to be configured via environment variable (for flexibility)\r\n const uriPath = process.env.BEAM_CONFIG_API_PATH || '/api/basic/realms/config';\r\n const configUrl = new URL(uriPath, apiUrl).toString();\r\n \r\n // Calculate signature for signed request\r\n const pathAndQuery = uriPath;\r\n const signature = calculateSignature(env.pid, env.secret, pathAndQuery, null, '1');\r\n \r\n console.log(`[EnvLoader] Fetching Beamable Config from ${configUrl}...`);\r\n \r\n const response = await fetch(configUrl, {\r\n method: 'GET',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json',\r\n 'X-BEAM-SCOPE': `${env.cid}.${env.pid}`,\r\n 'X-BEAM-SIGNATURE': signature,\r\n },\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'Unknown error');\r\n console.warn(`[EnvLoader] Failed to fetch Beamable Config: ${response.status} ${response.statusText} - ${errorText.substring(0, 200)}`);\r\n return configVars;\r\n }\r\n\r\n const data = (await response.json()) as BeamableConfigResponse;\r\n \r\n // Parse config structure: config[key][environment] = value\r\n // We need to determine the current environment - typically it's the PID or a specific env var\r\n const currentEnvironment = process.env.BEAM_ENVIRONMENT || process.env.ENVIRONMENT || env.pid;\r\n \r\n if (data.config) {\r\n for (const [key, environments] of Object.entries(data.config)) {\r\n // Try to get value for current environment, fallback to first available\r\n let value: string | number | boolean | null | undefined;\r\n \r\n if (environments && typeof environments === 'object') {\r\n value = environments[currentEnvironment];\r\n \r\n // If no value for current environment, try common environment names\r\n if (value === undefined) {\r\n value = environments['production'] || \r\n environments['staging'] || \r\n environments['development'] ||\r\n environments['dev'] ||\r\n Object.values(environments)[0];\r\n }\r\n }\r\n \r\n // Convert value to string and add to env vars\r\n if (value !== undefined && value !== null) {\r\n // Use BEAM_CONFIG_ prefix to avoid conflicts\r\n const envKey = `BEAM_CONFIG_${key.toUpperCase()}`;\r\n configVars[envKey] = String(value);\r\n }\r\n }\r\n \r\n console.log(`[EnvLoader] Loaded ${Object.keys(configVars).length} variables from Beamable Config`);\r\n } else {\r\n console.log('[EnvLoader] Beamable Config response contains no config object');\r\n }\r\n } catch (error) {\r\n console.warn('[EnvLoader] Failed to fetch Beamable Config:', error instanceof Error ? error.message : String(error));\r\n }\r\n \r\n return configVars;\r\n}\r\n\r\n/**\r\n * Loads all environment variables from both sources and injects them into process.env\r\n * \r\n * Priority (highest to lowest):\r\n * 1. Existing process.env values (never overwrite)\r\n * 2. Developer-defined variables (beam.env)\r\n * 3. Beamable Config values (API)\r\n * \r\n * @param env - Environment configuration (CID, PID, HOST, SECRET)\r\n * @param beamEnvPath - Optional path to beam.env file\r\n * @param waitForConfig - If true, waits up to timeoutMs for Beamable Config. If false, returns immediately after developer vars.\r\n * @param timeoutMs - Maximum time to wait for Beamable Config (default: 2000ms)\r\n */\r\nexport async function loadAndInjectEnvironmentVariables(\r\n env: EnvironmentConfig,\r\n beamEnvPath?: string,\r\n waitForConfig: boolean = true,\r\n timeoutMs: number = 2000\r\n): Promise<void> {\r\n console.log('[EnvLoader] Starting environment variable loading...');\r\n \r\n // Load developer-defined variables from beam.env (synchronous, immediate)\r\n const developerVars = loadDeveloperEnvVars(beamEnvPath);\r\n \r\n // Inject developer vars immediately\r\n let injectedCount = 0;\r\n for (const [key, value] of Object.entries(developerVars)) {\r\n if (!(key in process.env)) {\r\n process.env[key] = value;\r\n injectedCount++;\r\n }\r\n }\r\n \r\n if (injectedCount > 0) {\r\n console.log(`[EnvLoader] Injected ${injectedCount} developer-defined variables from beam.env`);\r\n }\r\n \r\n // Fetch Beamable Config values (async, with optional timeout)\r\n if (waitForConfig) {\r\n try {\r\n const configPromise = fetchBeamableConfig(env);\r\n const timeoutPromise = new Promise<Record<string, string>>((resolve) => {\r\n setTimeout(() => {\r\n console.warn(`[EnvLoader] Beamable Config fetch timed out after ${timeoutMs}ms, continuing without it`);\r\n resolve({});\r\n }, timeoutMs);\r\n });\r\n \r\n const beamableConfigVars = await Promise.race([configPromise, timeoutPromise]);\r\n \r\n // Inject Beamable Config vars\r\n let configInjectedCount = 0;\r\n for (const [key, value] of Object.entries(beamableConfigVars)) {\r\n if (!(key in process.env)) {\r\n process.env[key] = value;\r\n configInjectedCount++;\r\n }\r\n }\r\n \r\n if (configInjectedCount > 0) {\r\n console.log(`[EnvLoader] Injected ${configInjectedCount} variables from Beamable Config`);\r\n }\r\n } catch (error) {\r\n console.warn('[EnvLoader] Error loading Beamable Config (continuing anyway):', error instanceof Error ? error.message : String(error));\r\n }\r\n } else {\r\n // Start fetch in background (non-blocking)\r\n fetchBeamableConfig(env)\r\n .then((beamableConfigVars) => {\r\n let configInjectedCount = 0;\r\n for (const [key, value] of Object.entries(beamableConfigVars)) {\r\n if (!(key in process.env)) {\r\n process.env[key] = value;\r\n configInjectedCount++;\r\n }\r\n }\r\n if (configInjectedCount > 0) {\r\n console.log(`[EnvLoader] Injected ${configInjectedCount} variables from Beamable Config (loaded asynchronously)`);\r\n }\r\n })\r\n .catch((error) => {\r\n console.warn('[EnvLoader] Failed to load Beamable Config in background:', error instanceof Error ? error.message : String(error));\r\n });\r\n }\r\n \r\n console.log('[EnvLoader] Environment variable loading completed');\r\n}\r\n\r\n"]}
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,iBAAiB,EAOlB,MAAM,YAAY,CAAC;AA2BpB,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAuB;IAClD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;IACxD,OAAO,CAAC,iBAAiB,CAAC,CAAS;IACnC,OAAO,CAAC,OAAO,CAAkB;gBAErB,GAAG,CAAC,EAAE,iBAAiB;IA2H7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6DtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YASjB,sBAAsB;YA2CtB,qBAAqB;YAarB,eAAe;YA+Gf,WAAW;IA8BzB,OAAO,CAAC,gBAAgB;IAkFxB,OAAO,CAAC,kBAAkB;YAUZ,QAAQ;IAsDtB,OAAO,CAAC,wBAAwB;YAmBlB,mBAAmB;YAiBnB,sBAAsB;YAStB,wBAAwB;YAoBxB,mBAAmB;IA2GjC,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,gBAAgB;YA+BV,6BAA6B;IA6B3C,OAAO,CAAC,kBAAkB;CAK3B;AA+GD,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAoDrD;AAED,UAAU,sBAAsB;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,4CAA4C,CAC1D,SAAS,GAAE,OAAO,CAAC,iBAAiB,CAAM,EAC1C,OAAO,GAAE,sBAA2B,GACnC,OAAO,CA6BT"}
|
package/dist/runtime.js
CHANGED
|
@@ -4,6 +4,7 @@ import { GatewayRequester } from './requester.js';
|
|
|
4
4
|
import { AuthManager } from './auth.js';
|
|
5
5
|
import { createLogger } from './logger.js';
|
|
6
6
|
import { loadEnvironmentConfig } from './env.js';
|
|
7
|
+
import { loadAndInjectEnvironmentVariables, loadDeveloperEnvVarsSync } from './env-loader.js';
|
|
7
8
|
import { startCollectorAndWaitForReady } from './collector-manager.js';
|
|
8
9
|
import pino from 'pino';
|
|
9
10
|
// Removed deasync - using non-blocking async pattern instead
|
|
@@ -31,7 +32,11 @@ export class MicroserviceRuntime {
|
|
|
31
32
|
isReady = false;
|
|
32
33
|
constructor(env) {
|
|
33
34
|
this.env = env ?? loadEnvironmentConfig();
|
|
34
|
-
|
|
35
|
+
const envConfig = this.env; // Capture for async IIFE to satisfy TypeScript
|
|
36
|
+
// STEP 1: Load developer-defined environment variables SYNCHRONOUSLY before logger creation
|
|
37
|
+
// This ensures BetterStack and other env vars are available when the logger initializes
|
|
38
|
+
loadDeveloperEnvVarsSync();
|
|
39
|
+
// STEP 2: Create minimal console logger for startup messages (before collector setup)
|
|
35
40
|
// This ensures we have logging available immediately, even before collector is ready
|
|
36
41
|
const startupLogger = pino({
|
|
37
42
|
name: 'beamable-runtime-startup',
|
|
@@ -39,6 +44,19 @@ export class MicroserviceRuntime {
|
|
|
39
44
|
}, process.stdout);
|
|
40
45
|
// Display runtime version at startup (VERSION is imported synchronously at top of file)
|
|
41
46
|
startupLogger.info(`Starting Beamable Node microservice runtime (version: ${VERSION}).`);
|
|
47
|
+
// STEP 2.5: Load Beamable Config asynchronously (in background, non-blocking)
|
|
48
|
+
// Developer-defined vars are already loaded synchronously above
|
|
49
|
+
// Beamable Config is fetched via API with a 2-second timeout
|
|
50
|
+
(async () => {
|
|
51
|
+
try {
|
|
52
|
+
startupLogger.info('Loading Beamable Config environment variables...');
|
|
53
|
+
await loadAndInjectEnvironmentVariables(envConfig, undefined, true, 2000);
|
|
54
|
+
startupLogger.info('Beamable Config loading completed');
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
startupLogger.warn(`Beamable Config loading completed with warnings: ${error instanceof Error ? error.message : String(error)}`);
|
|
58
|
+
}
|
|
59
|
+
})();
|
|
42
60
|
// STEP 2: Get registered services to extract service name
|
|
43
61
|
const registered = listRegisteredServices();
|
|
44
62
|
if (registered.length === 0) {
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { BeamableWebSocket } from './websocket.js';\nimport { GatewayRequester } from './requester.js';\nimport { AuthManager } from './auth.js';\nimport { createLogger } from './logger.js';\nimport { loadEnvironmentConfig } from './env.js';\nimport { startCollectorAndWaitForReady } from './collector-manager.js';\nimport pino from 'pino';\n// Removed deasync - using non-blocking async pattern instead\nimport { listRegisteredServices, getServiceOptions, getConfigureServicesHandlers, getInitializeServicesHandlers } from './decorators.js';\nimport { generateOpenApiDocument } from './docs.js';\nimport { VERSION } from './index.js';\nimport { DiscoveryBroadcaster } from './discovery.js';\nimport { BeamableRuntimeError, MissingScopesError, UnauthorizedUserError, UnknownRouteError } from './errors.js';\nimport type {\n EnvironmentConfig,\n RequestContext,\n ServiceDefinition,\n ServiceCallableMetadata,\n GatewayResponse,\n WebsocketEventEnvelope,\n ServiceAccess,\n} from './types.js';\nimport type { Logger } from 'pino';\nimport { BeamableServiceManager } from './services.js';\nimport {\n DependencyBuilder,\n LOGGER_TOKEN,\n ENVIRONMENT_CONFIG_TOKEN,\n REQUEST_CONTEXT_TOKEN,\n BEAMABLE_SERVICES_TOKEN,\n ServiceProvider,\n MutableDependencyScope,\n} from './dependency.js';\nimport { hostToHttpUrl, hostToPortalUrl } from './utils/urls.js';\nimport { FederationRegistry, getFederationComponents, getFederatedInventoryMetadata } from './federation.js';\nimport type { FederatedRequestContext } from './federation.js';\nimport { createServer, type Server } from 'node:http';\n\ninterface ServiceInstance {\n definition: ServiceDefinition;\n instance: Record<string, unknown>;\n configureHandlers: ReturnType<typeof getConfigureServicesHandlers>;\n initializeHandlers: ReturnType<typeof getInitializeServicesHandlers>;\n provider?: ServiceProvider;\n logger: Logger;\n federationRegistry: FederationRegistry;\n}\n\nexport class MicroserviceRuntime {\n private readonly env: EnvironmentConfig;\n private logger: Logger; // Mutable to allow upgrading from console logger to structured logger when collector is ready\n private readonly services: ServiceInstance[];\n private readonly webSocket: BeamableWebSocket;\n private readonly requester: GatewayRequester;\n private readonly authManager: AuthManager;\n private readonly discovery?: DiscoveryBroadcaster;\n private readonly microServiceId = randomUUID();\n private readonly serviceManager: BeamableServiceManager;\n private healthCheckServer?: Server;\n private isReady: boolean = false;\n\n constructor(env?: EnvironmentConfig) {\n this.env = env ?? loadEnvironmentConfig();\n \n // STEP 1: Create minimal console logger for startup messages (before collector setup)\n // This ensures we have logging available immediately, even before collector is ready\n const startupLogger = pino({\n name: 'beamable-runtime-startup',\n level: 'info',\n }, process.stdout);\n // Display runtime version at startup (VERSION is imported synchronously at top of file)\n startupLogger.info(`Starting Beamable Node microservice runtime (version: ${VERSION}).`);\n \n // STEP 2: Get registered services to extract service name\n const registered = listRegisteredServices();\n if (registered.length === 0) {\n throw new Error('No microservices registered. Use the @Microservice decorator to register at least one class.');\n }\n \n // Use the first service's name for the main logger (for CloudWatch filtering and ClickHouse compatibility)\n const primaryService = registered[0];\n const qualifiedServiceName = `micro_${primaryService.qualifiedName}`;\n \n // STEP 3: Create logger immediately (non-blocking pattern, matching C#)\n // Start with minimal console logger, upgrade to structured logger when collector is ready\n // This allows the service to start immediately without blocking\n startupLogger.info('Setting up OpenTelemetry collector in background (non-blocking)...');\n \n // Create logger immediately with console output (no OTLP yet)\n // This ensures we have logging available right away\n this.logger = createLogger(this.env, {\n name: 'beamable-node-microservice',\n serviceName: primaryService.name,\n qualifiedServiceName: qualifiedServiceName,\n // No otlpEndpoint - will use console logger initially\n });\n \n // STEP 4: Start collector setup in background (non-blocking)\n // When collector is ready, upgrade logger to structured logger with OTLP\n // This matches C# pattern: collector starts in background, service starts immediately\n startCollectorAndWaitForReady(this.env)\n .then((endpoint) => {\n if (endpoint) {\n // Collector is ready - upgrade to structured logger with OTLP support\n this.logger.info(`Collector ready at ${endpoint}, upgrading to structured logger for Portal logs...`);\n this.logger = createLogger(this.env, {\n name: 'beamable-node-microservice',\n serviceName: primaryService.name,\n qualifiedServiceName: qualifiedServiceName,\n otlpEndpoint: endpoint, // Collector is ready, Portal logs will now work\n });\n this.logger.info('Portal logs enabled - structured logs will now appear in Beamable Portal');\n } else {\n this.logger.warn('Collector setup completed but no endpoint was returned. Continuing with console logs. Portal logs will not be available.');\n }\n })\n .catch((error) => {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.logger.error(`Failed to setup collector: ${errorMsg}. Continuing with console logs. Portal logs will not be available.`);\n // Service continues to work with console logger - graceful degradation\n });\n \n // Continue immediately - don't wait for collector!\n // Service can start accepting requests right away\n // Collector setup happens in background, logger upgrades automatically when ready\n this.serviceManager = new BeamableServiceManager(this.env, this.logger);\n\n this.services = registered.map((definition) => {\n const instance = new definition.ctor() as Record<string, unknown>;\n const configureHandlers = getConfigureServicesHandlers(definition.ctor);\n const initializeHandlers = getInitializeServicesHandlers(definition.ctor);\n const logger = this.logger.child({ service: definition.name });\n const federationRegistry = new FederationRegistry(logger);\n const decoratedFederations = getFederationComponents(definition.ctor);\n for (const component of decoratedFederations) {\n federationRegistry.register(component);\n }\n const inventoryMetadata = getFederatedInventoryMetadata(definition.ctor);\n if (inventoryMetadata.length > 0) {\n federationRegistry.registerInventoryHandlers(instance, inventoryMetadata);\n }\n this.serviceManager.registerFederationRegistry(definition.name, federationRegistry);\n return { definition, instance, configureHandlers, initializeHandlers, logger, federationRegistry };\n });\n\n const socketUrl = this.env.host.endsWith('/socket') ? this.env.host : `${this.env.host}/socket`;\n this.webSocket = new BeamableWebSocket({ url: socketUrl, logger: this.logger });\n this.webSocket.on('message', (payload) => {\n this.logger.debug({ payload }, 'Runtime observed websocket frame.');\n });\n this.requester = new GatewayRequester(this.webSocket, this.logger);\n this.authManager = new AuthManager(this.env, this.requester);\n this.requester.on('event', (envelope) => this.handleEvent(envelope));\n\n // Discovery broadcaster only runs in local development (not in containers)\n // This allows the portal to detect that the service is running locally\n if (!isRunningInContainer() && this.services.length > 0) {\n this.discovery = new DiscoveryBroadcaster({\n env: this.env,\n serviceName: this.services[0].definition.name,\n routingKey: this.env.routingKey,\n logger: this.logger.child({ component: 'DiscoveryBroadcaster' }),\n });\n }\n }\n\n async start(): Promise<void> {\n // Immediate console output for container logs (before logger is ready)\n debugLog('[BEAMABLE-NODE] MicroserviceRuntime.start() called');\n debugLog(`[BEAMABLE-NODE] Service count: ${this.services.length}`);\n \n this.printHelpfulUrls(this.services[0]);\n this.logger.info('Starting Beamable Node microservice runtime.');\n \n // Start health check server FIRST - this is critical for container health checks\n // Even if startup fails, the health check server must be running so we can debug\n debugLog('[BEAMABLE-NODE] Starting health check server...');\n await this.startHealthCheckServer();\n debugLog('[BEAMABLE-NODE] Health check server started');\n \n try {\n this.logger.info('Connecting to Beamable gateway...');\n await this.webSocket.connect();\n await new Promise((resolve) => setTimeout(resolve, 250));\n \n this.logger.info('Authenticating with Beamable...');\n await this.authManager.authenticate();\n \n this.logger.info('Initializing Beamable SDK services...');\n await this.serviceManager.initialize();\n \n this.logger.info('Initializing dependency providers...');\n await this.initializeDependencyProviders();\n \n this.logger.info('Registering service with gateway...');\n await this.registerService();\n \n this.logger.info('Starting discovery broadcaster...');\n await this.discovery?.start();\n \n // Mark as ready only after service is fully registered and discovery is started\n this.isReady = true;\n this.logger.info('Beamable microservice runtime is ready to accept traffic.');\n } catch (error) {\n // Log the error with full context but don't crash - health check server is running\n // This allows the container to stay alive so we can debug the issue\n // Debug output for local development only (in containers, logger handles this)\n debugLog('[BEAMABLE-NODE] FATAL ERROR during startup:');\n debugLog(`[BEAMABLE-NODE] Error message: ${error instanceof Error ? error.message : String(error)}`);\n debugLog(`[BEAMABLE-NODE] Error stack: ${error instanceof Error ? error.stack : 'No stack trace'}`);\n debugLog(`[BEAMABLE-NODE] isReady: ${this.isReady}`);\n \n this.logger.error(\n { \n err: error,\n errorMessage: error instanceof Error ? error.message : String(error),\n errorStack: error instanceof Error ? error.stack : undefined,\n isReady: this.isReady,\n },\n 'Failed to fully initialize microservice runtime. Health check will continue to return 503 until initialization completes.'\n );\n // DON'T re-throw - keep process alive so health check can show 503\n // This allows us to see the error in logs\n this.isReady = false;\n }\n }\n\n async shutdown(): Promise<void> {\n this.logger.info('Shutting down microservice runtime.');\n this.isReady = false; // Mark as not ready during shutdown\n this.discovery?.stop();\n await this.stopHealthCheckServer();\n this.requester.dispose();\n await this.webSocket.close();\n }\n\n private async startHealthCheckServer(): Promise<void> {\n // For deployed services, always start health check server (required for container health checks)\n // For local development, only start if healthPort is explicitly set\n // IMPORTANT: Always default to 6565 if HEALTH_PORT env var is not set, as this is the standard port\n const healthPort = this.env.healthPort || 6565;\n \n // Always start health check server if we have a valid port\n // The container orchestrator expects this endpoint to be available\n if (!healthPort || healthPort === 0) {\n // Health check server not needed (local development without explicit port)\n this.logger.debug('Health check server skipped (no healthPort set)');\n return;\n }\n\n this.healthCheckServer = createServer((req, res) => {\n if (req.url === '/health' && req.method === 'GET') {\n // Only return success if service is fully ready (registered and accepting traffic)\n if (this.isReady) {\n res.writeHead(200, { 'Content-Type': 'text/plain' });\n res.end('responsive');\n } else {\n // Service is still starting up\n res.writeHead(503, { 'Content-Type': 'text/plain' });\n res.end('Service Unavailable');\n }\n } else {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n }\n });\n\n return new Promise((resolve, reject) => {\n this.healthCheckServer!.listen(healthPort, '0.0.0.0', () => {\n this.logger.info({ port: healthPort }, 'Health check server started on port');\n resolve();\n });\n this.healthCheckServer!.on('error', (err) => {\n this.logger.error({ err, port: healthPort }, 'Failed to start health check server');\n reject(err);\n });\n });\n }\n\n private async stopHealthCheckServer(): Promise<void> {\n if (!this.healthCheckServer) {\n return;\n }\n\n return new Promise((resolve) => {\n this.healthCheckServer!.close(() => {\n this.logger.info('Health check server stopped');\n resolve();\n });\n });\n }\n\n private async registerService(): Promise<void> {\n const primary = this.services[0]?.definition;\n if (!primary) {\n throw new Error('Unexpected missing service definition during registration.');\n }\n const options = getServiceOptions(primary.ctor) ?? {};\n // Match C# exactly: use qualifiedName (preserves case) for name field.\n // The gateway lowercases service names when creating bindings, but uses the original case\n // from the registration request when constructing routing key lookups.\n // This ensures the routing key format matches what the gateway expects.\n // The gateway's binding lookup behavior:\n // - Gateway error shows: \"No binding found for service ...micro_examplenodeservice.basic\"\n // - This means the gateway lowercases the service name for binding storage/lookup\n // - Portal sends requests with mixed case in URL and routing key header\n // - The gateway lowercases the URL path for binding lookup, which should work\n // - But we need to register with the format the gateway expects for the binding key\n // - The gateway constructs binding key as: {cid}.{pid}.{lowercaseServiceName}.{type}\n // - So we register with lowercase to match what the gateway stores in the binding\n // - The portal will still send mixed case, and the gateway will lowercase it for lookup\n // Register with mixed-case qualifiedName to match C# behavior\n // The gateway will lowercase the service name when creating the binding key,\n // but the registration request should use the original case (as C# does)\n // This ensures the service name in the registration matches what the portal expects\n // Register with mixed-case qualifiedName to match C# behavior\n // The gateway's ServiceIdentity.fullNameNoType lowercases the service name when creating bindings,\n // but the registration request should use the original case (as C# does)\n // This ensures the service name in the registration matches what the portal expects\n const isDeployed = isRunningInContainer();\n \n // For deployed services, routingKey should be null/undefined (None in Scala)\n // For local dev, routingKey should be the actual routing key string\n // The backend expects Option[String] = None for deployed services\n // Note: microServiceId is not part of SocketSessionProviderRegisterRequest, so we don't include it\n // All fields except 'type' are Option[T] in Scala, so undefined fields will be omitted from JSON\n // This matches C# behavior where null/None fields are not serialized\n const request: Record<string, unknown> = {\n type: 'basic',\n name: primary.qualifiedName, // Use mixed-case as C# does - gateway handles lowercasing for binding storage\n beamoName: primary.name,\n };\n \n // Only include routingKey and startedById if they have values (for local dev)\n // For deployed services, these should be omitted (undefined) to match None in Scala\n if (!isDeployed && this.env.routingKey) {\n request.routingKey = this.env.routingKey;\n }\n if (!isDeployed && this.env.accountId) {\n request.startedById = this.env.accountId;\n }\n\n // Log registration request to match C# behavior exactly\n // Also log the actual JSON that will be sent (undefined fields will be omitted)\n const serializedRequest = JSON.stringify(request);\n this.logger.debug(\n {\n request: {\n type: request.type,\n name: request.name,\n beamoName: request.beamoName,\n routingKey: request.routingKey,\n startedById: request.startedById,\n },\n serializedJson: serializedRequest,\n isDeployed,\n },\n 'Registering service provider with gateway.',\n );\n\n try {\n await this.requester.request('post', 'gateway/provider', request);\n this.logger.info({ serviceName: primary.qualifiedName }, 'Service provider registered successfully.');\n \n // After registration, the gateway's BasicServiceProvider.start() is called asynchronously\n // This triggers afterRabbitInit() -> setupDirectServiceCommunication() -> scheduleServiceBindingCheck()\n // The first updateBindings() call happens immediately (0.millisecond delay)\n // We wait a bit to allow the gateway to set up the HTTP binding and call updateBindings()\n // This is especially important for deployed services where the gateway needs to establish\n // the external host binding before bindings can be created\n if (isDeployed) {\n this.logger.debug('Waiting for gateway to establish bindings after registration...');\n await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 second wait for deployed services\n this.logger.debug('Wait complete, gateway should have established bindings by now.');\n }\n } catch (error) {\n this.logger.error(\n {\n err: error,\n request,\n serviceName: primary.qualifiedName,\n errorMessage: error instanceof Error ? error.message : String(error),\n },\n 'Failed to register service provider with gateway. This will prevent the service from receiving requests.'\n );\n throw error; // Re-throw so startup fails and we can see the error\n }\n\n if (options.disableAllBeamableEvents) {\n this.logger.info('Beamable events disabled by configuration.');\n } else {\n const eventRequest = {\n type: 'event',\n evtWhitelist: ['content.manifest', 'realm.config', 'logging.context'],\n };\n try {\n await this.requester.request('post', 'gateway/provider', eventRequest);\n } catch (error) {\n this.logger.warn({ err: error }, 'Failed to register event provider. Continuing without events.');\n }\n }\n }\n\n private async handleEvent(envelope: WebsocketEventEnvelope): Promise<void> {\n try {\n if (!envelope.path) {\n this.logger.debug({ envelope }, 'Ignoring websocket event without path.');\n return;\n }\n\n if (envelope.path.startsWith('event/')) {\n await this.requester.acknowledge(envelope.id);\n return;\n }\n\n const context = this.toRequestContext(envelope);\n await this.dispatch(context);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.logger.error({ err, envelope }, 'Failed to handle websocket event.');\n const status = this.resolveErrorStatus(err);\n const response: GatewayResponse = {\n id: envelope.id,\n status,\n body: {\n error: err.name,\n message: err.message,\n },\n };\n await this.requester.sendResponse(response);\n }\n }\n\n private toRequestContext(envelope: WebsocketEventEnvelope): RequestContext {\n const path = envelope.path ?? '';\n const method = envelope.method ?? 'post';\n const userId = typeof envelope.from === 'number' ? envelope.from : 0;\n const headers = envelope.headers ?? {};\n \n // Extract scopes from envelope.scopes array\n // Note: X-DE-SCOPE header contains CID.PID, not scope values\n // The gateway sends scopes in envelope.scopes array\n // For admin endpoints, the gateway may not send scopes in the envelope,\n // so we infer admin scope from the path if it's an admin route\n const envelopeScopes = envelope.scopes ?? [];\n let scopes = normalizeScopes(envelopeScopes);\n \n // If this is an admin endpoint and no scopes are provided, infer admin scope\n // The gateway may not always send scopes for admin routes\n const pathLower = path.toLowerCase();\n if (pathLower.includes('/admin/') && scopes.size === 0) {\n scopes = normalizeScopes(['admin']);\n }\n\n let body: Record<string, unknown> | undefined;\n if (envelope.body && typeof envelope.body === 'string') {\n try {\n body = JSON.parse(envelope.body) as Record<string, unknown>;\n } catch (error) {\n this.logger.warn({ err: error, raw: envelope.body }, 'Failed to parse body string.');\n }\n } else if (envelope.body && typeof envelope.body === 'object') {\n body = envelope.body as Record<string, unknown>;\n }\n\n let payload: unknown;\n if (body && typeof body === 'object' && 'payload' in body) {\n const rawPayload = (body as Record<string, unknown>).payload;\n if (typeof rawPayload === 'string') {\n try {\n payload = JSON.parse(rawPayload) as unknown[];\n } catch (error) {\n this.logger.warn({ err: error }, 'Failed to parse payload JSON.');\n payload = rawPayload;\n }\n } else {\n payload = rawPayload;\n }\n }\n\n const targetService = this.findServiceForPath(path);\n const services = this.serviceManager.createFacade(userId, scopes, targetService?.definition.name);\n const provider = this.createRequestScope(path, targetService);\n\n const context: RequestContext = {\n id: envelope.id,\n path,\n method,\n status: envelope.status ?? 0,\n userId,\n payload,\n body,\n scopes,\n headers,\n cid: this.env.cid,\n pid: this.env.pid,\n services,\n throwIfCancelled: () => {},\n isCancelled: () => false,\n hasScopes: (...requiredScopes: string[]) => requiredScopes.every((scope) => scopeSetHas(scopes, scope)),\n requireScopes: (...requiredScopes: string[]) => {\n const missingScopes = requiredScopes.filter((scope) => !scopeSetHas(scopes, scope));\n if (missingScopes.length > 0) {\n throw new MissingScopesError(missingScopes);\n }\n },\n provider,\n };\n\n provider.setInstance(REQUEST_CONTEXT_TOKEN, context);\n provider.setInstance(BEAMABLE_SERVICES_TOKEN, services);\n\n return context;\n }\n\n private findServiceForPath(path: string): ServiceInstance | undefined {\n // Gateway sends paths with lowercase service names, so we need case-insensitive matching\n // Match by comparing lowercase versions to handle gateway's lowercase path format\n const pathLower = path.toLowerCase();\n return this.services.find((service) => {\n const qualifiedNameLower = service.definition.qualifiedName.toLowerCase();\n return pathLower.startsWith(`${qualifiedNameLower}/`);\n });\n }\n\n private async dispatch(ctx: RequestContext): Promise<void> {\n const service = this.findServiceForPath(ctx.path);\n if (!service) {\n throw new UnknownRouteError(ctx.path);\n }\n\n if (await this.tryHandleFederationRoute(ctx, service)) {\n return;\n }\n\n if (await this.tryHandleAdminRoute(ctx, service)) {\n return;\n }\n\n // Extract route from path - handle case-insensitive path matching\n const pathLower = ctx.path.toLowerCase();\n const qualifiedNameLower = service.definition.qualifiedName.toLowerCase();\n const route = pathLower.substring(qualifiedNameLower.length + 1);\n const metadata = service.definition.callables.get(route);\n if (!metadata) {\n throw new UnknownRouteError(ctx.path);\n }\n\n // For server and admin access, allow userId: 0 if the appropriate scope is present\n // For client access, always require userId > 0\n if (metadata.requireAuth && ctx.userId <= 0) {\n if (metadata.access === 'server' && scopeSetHas(ctx.scopes, 'server')) {\n // Server callables with server scope don't need a user ID\n } else if (metadata.access === 'admin' && scopeSetHas(ctx.scopes, 'admin')) {\n // Admin callables with admin scope don't need a user ID\n } else {\n throw new UnauthorizedUserError(route);\n }\n }\n\n enforceAccess(metadata.access, ctx);\n\n if (metadata.requiredScopes.length > 0) {\n const missing = metadata.requiredScopes.filter((scope) => !scopeSetHas(ctx.scopes, scope));\n if (missing.length > 0) {\n throw new MissingScopesError(missing);\n }\n }\n\n const handler = service.instance[metadata.displayName];\n if (typeof handler !== 'function') {\n throw new Error(`Callable ${metadata.displayName} is not a function on service ${service.definition.name}.`);\n }\n\n const args = this.buildInvocationArguments(handler as (...args: unknown[]) => unknown, ctx);\n const result = await Promise.resolve((handler as (...args: unknown[]) => unknown).apply(service.instance, args));\n await this.sendSuccessResponse(ctx, metadata, result);\n }\n\n private buildInvocationArguments(\n handler: (...args: unknown[]) => unknown,\n ctx: RequestContext,\n ): unknown[] {\n const payload = Array.isArray(ctx.payload)\n ? ctx.payload\n : typeof ctx.payload === 'string'\n ? [ctx.payload]\n : ctx.payload === undefined\n ? []\n : [ctx.payload];\n\n const expectedParams = handler.length;\n if (expectedParams === payload.length + 1) {\n return [ctx, ...payload];\n }\n return payload;\n }\n\n private async sendSuccessResponse(ctx: RequestContext, metadata: ServiceCallableMetadata, result: unknown): Promise<void> {\n let body: unknown;\n if (metadata.useLegacySerialization) {\n const serialized = typeof result === 'string' ? result : JSON.stringify(result ?? null);\n body = { payload: serialized };\n } else {\n body = result ?? null;\n }\n\n const response: GatewayResponse = {\n id: ctx.id,\n status: 200,\n body,\n };\n await this.requester.sendResponse(response);\n }\n\n private async sendFederationResponse(ctx: RequestContext, result: unknown): Promise<void> {\n const response: GatewayResponse = {\n id: ctx.id,\n status: 200,\n body: result ?? null,\n };\n await this.requester.sendResponse(response);\n }\n\n private async tryHandleFederationRoute(ctx: RequestContext, service: ServiceInstance): Promise<boolean> {\n // Gateway sends paths with lowercase service names, so we need case-insensitive matching\n const pathLower = ctx.path.toLowerCase();\n const qualifiedNameLower = service.definition.qualifiedName.toLowerCase();\n const prefixLower = `${qualifiedNameLower}/`;\n if (!pathLower.startsWith(prefixLower)) {\n return false;\n }\n // Extract relative path - use lowercase length since gateway sends lowercase paths\n const relativePath = ctx.path.substring(qualifiedNameLower.length + 1);\n const handler = service.federationRegistry.resolve(relativePath);\n if (!handler) {\n return false;\n }\n\n const result = await handler.invoke(ctx as FederatedRequestContext);\n await this.sendFederationResponse(ctx, result);\n return true;\n }\n\n private async tryHandleAdminRoute(ctx: RequestContext, service: ServiceInstance): Promise<boolean> {\n // Gateway sends paths with lowercase service names, so we need case-insensitive matching\n // Check if path starts with the admin prefix (case-insensitive)\n const pathLower = ctx.path.toLowerCase();\n const adminPrefixLower = `${service.definition.qualifiedName.toLowerCase()}/admin/`;\n if (!pathLower.startsWith(adminPrefixLower)) {\n return false;\n }\n\n const options = getServiceOptions(service.definition.ctor) ?? {};\n\n const action = pathLower.substring(adminPrefixLower.length);\n const requiresAdmin = action === 'metadata' || action === 'docs';\n if (requiresAdmin && !scopeSetHas(ctx.scopes, 'admin')) {\n // For portal requests to admin endpoints, the gateway may not send scopes\n // The X-DE-SCOPE header contains CID.PID, not scope values\n // If this is a portal request (has X-DE-SCOPE header), grant admin scope\n const hasPortalHeader = ctx.headers['X-DE-SCOPE'] || ctx.headers['x-de-scope'];\n if (hasPortalHeader) {\n // Grant admin scope for portal requests to admin endpoints\n ctx.scopes.add('admin');\n } else {\n throw new MissingScopesError(['admin']);\n }\n }\n\n switch (action) {\n case 'health':\n case 'healthcheck':\n await this.requester.sendResponse({ id: ctx.id, status: 200, body: 'responsive' });\n return true;\n case 'metadata':\n case 'docs':\n break;\n default:\n if (!scopeSetHas(ctx.scopes, 'admin')) {\n throw new MissingScopesError(['admin']);\n }\n throw new UnknownRouteError(ctx.path);\n }\n\n if (action === 'metadata') {\n const federatedComponents = service.federationRegistry\n .list()\n .map((component) => ({\n federationNamespace: component.federationNamespace,\n federationType: component.federationType,\n }));\n\n await this.requester.sendResponse({\n id: ctx.id,\n status: 200,\n body: {\n serviceName: service.definition.name,\n sdkVersion: this.env.sdkVersionExecution,\n sdkBaseBuildVersion: this.env.sdkVersionExecution,\n sdkExecutionVersion: this.env.sdkVersionExecution,\n useLegacySerialization: Boolean(options.useLegacySerialization),\n disableAllBeamableEvents: Boolean(options.disableAllBeamableEvents),\n enableEagerContentLoading: false,\n instanceId: this.microServiceId,\n routingKey: this.env.routingKey ?? '',\n federatedComponents,\n },\n });\n return true;\n }\n\n if (action === 'docs') {\n try {\n const document = generateOpenApiDocument(\n {\n qualifiedName: service.definition.qualifiedName,\n name: service.definition.name,\n callables: Array.from(service.definition.callables.values()).map((callable) => ({\n name: callable.displayName,\n route: callable.route,\n metadata: callable,\n handler: typeof service.instance[callable.displayName] === 'function'\n ? (service.instance[callable.displayName] as (...args: unknown[]) => unknown)\n : undefined,\n })),\n },\n this.env,\n VERSION,\n );\n\n // Ensure document is valid (not empty)\n if (!document || Object.keys(document).length === 0) {\n this.logger.warn({ serviceName: service.definition.name }, 'Generated OpenAPI document is empty');\n }\n\n await this.requester.sendResponse({\n id: ctx.id,\n status: 200,\n body: document,\n });\n return true;\n } catch (error) {\n this.logger.error({ err: error, serviceName: service.definition.name }, 'Failed to generate or send docs');\n throw error;\n }\n }\n\n return false;\n }\n\n private resolveErrorStatus(error: Error): number {\n if (error instanceof UnauthorizedUserError) {\n return 401;\n }\n if (error instanceof MissingScopesError) {\n return 403;\n }\n if (error instanceof UnknownRouteError) {\n return 404;\n }\n if (error instanceof BeamableRuntimeError) {\n return 500;\n }\n return 500;\n }\n\n private printHelpfulUrls(service?: ServiceInstance): void {\n if (!service) {\n return;\n }\n\n // Only print helpful URLs when IS_LOCAL=1 is set\n // In deployed containers, we want only JSON logs for proper log collection\n if (process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true') {\n return;\n }\n\n const docsUrl = buildDocsPortalUrl(this.env, service.definition);\n const endpointBase = buildPostmanBaseUrl(this.env, service.definition);\n\n const green = (text: string) => `\\x1b[32m${text}\\x1b[0m`;\n const yellow = (text: string) => `\\x1b[33m${text}\\x1b[0m`;\n\n const bannerLines = [\n '',\n yellow('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'),\n ` ${green('Beamable Node microservice ready:')} ${green(service.definition.name)}`,\n yellow(' Quick shortcuts'),\n ` ${yellow('Docs:')} ${docsUrl}`,\n ` ${yellow('Endpoint:')} ${endpointBase}`,\n yellow('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'),\n '',\n ];\n\n process.stdout.write(`${bannerLines.join('\\n')}`);\n }\n\n private async initializeDependencyProviders(): Promise<void> {\n for (const service of this.services) {\n const builder = new DependencyBuilder();\n builder.tryAddSingletonInstance(LOGGER_TOKEN, service.logger);\n builder.tryAddSingletonInstance(ENVIRONMENT_CONFIG_TOKEN, this.env);\n builder.tryAddSingletonInstance(BeamableServiceManager, this.serviceManager);\n builder.tryAddSingletonInstance(service.definition.ctor, service.instance);\n builder.tryAddSingletonInstance(FederationRegistry, service.federationRegistry);\n\n for (const handler of service.configureHandlers) {\n await handler(builder);\n }\n\n const provider = builder.build();\n service.provider = provider;\n\n for (const handler of service.initializeHandlers) {\n await handler(provider);\n }\n\n Object.defineProperty(service.instance, 'provider', {\n value: provider,\n enumerable: false,\n configurable: false,\n writable: false,\n });\n }\n }\n\n private createRequestScope(path: string, service?: ServiceInstance): MutableDependencyScope {\n const targetService = service ?? this.findServiceForPath(path);\n const provider = targetService?.provider ?? new DependencyBuilder().build();\n return provider.createScope();\n }\n}\n\nfunction enforceAccess(access: ServiceAccess, ctx: RequestContext): void {\n switch (access) {\n case 'client':\n if (ctx.userId <= 0) {\n throw new UnauthorizedUserError(ctx.path);\n }\n break;\n case 'server':\n if (!scopeSetHas(ctx.scopes, 'server')) {\n throw new MissingScopesError(['server']);\n }\n break;\n case 'admin':\n if (!scopeSetHas(ctx.scopes, 'admin')) {\n throw new MissingScopesError(['admin']);\n }\n break;\n default:\n break;\n }\n}\n\n/**\n * Conditionally output to console.error only when running locally (not in container).\n * In containers, we want only Pino JSON logs to stdout for proper log collection.\n */\nfunction debugLog(...args: unknown[]): void {\n // Only output debug logs when IS_LOCAL=1 is set\n if (process.env.IS_LOCAL === '1' || process.env.IS_LOCAL === 'true') {\n console.error(...args);\n }\n}\n\n/**\n * Determines if we're running in a deployed container.\n * Used for service registration logic (routing key handling, discovery broadcaster, etc.)\n * \n * Note: For log formatting, use IS_LOCAL env var instead.\n */\nfunction isRunningInContainer(): boolean {\n // Check for Docker container\n try {\n const fs = require('fs');\n if (fs.existsSync('/.dockerenv')) {\n return true;\n }\n } catch {\n // fs might not be available\n }\n \n // Check for Docker container hostname pattern (12 hex chars)\n const hostname = process.env.HOSTNAME || '';\n if (hostname && /^[a-f0-9]{12}$/i.test(hostname)) {\n return true;\n }\n \n // Explicit container indicators\n if (\n process.env.DOTNET_RUNNING_IN_CONTAINER === 'true' ||\n process.env.CONTAINER === 'beamable' ||\n !!process.env.ECS_CONTAINER_METADATA_URI ||\n !!process.env.KUBERNETES_SERVICE_HOST\n ) {\n return true;\n }\n \n // Default: assume local development\n return false;\n}\n\nfunction normalizeScopes(scopes: Array<unknown>): Set<string> {\n const normalized = new Set<string>();\n for (const scope of scopes) {\n if (typeof scope !== 'string' || scope.trim().length === 0) {\n continue;\n }\n normalized.add(scope.trim().toLowerCase());\n }\n return normalized;\n}\n\nfunction scopeSetHas(scopes: Set<string>, scope: string): boolean {\n const normalized = scope.trim().toLowerCase();\n if (normalized.length === 0) {\n return false;\n }\n return scopes.has('*') || scopes.has(normalized);\n}\n\nfunction buildPostmanBaseUrl(env: EnvironmentConfig, service: ServiceDefinition): string {\n const httpHost = hostToHttpUrl(env.host);\n const routingKeyPart = env.routingKey ? env.routingKey : '';\n return `${httpHost}/basic/${env.cid}.${env.pid}.${routingKeyPart}${service.qualifiedName}/`;\n}\n\nfunction buildDocsPortalUrl(env: EnvironmentConfig, service: ServiceDefinition): string {\n const portalHost = hostToPortalUrl(hostToHttpUrl(env.host));\n const queryParams: Record<string, string> = { srcTool: 'node-runtime' };\n if (env.routingKey) {\n queryParams.routingKey = env.routingKey;\n }\n const query = new URLSearchParams(queryParams);\n if (env.refreshToken) {\n query.set('refresh_token', env.refreshToken);\n }\n const beamoId = service.name;\n return `${portalHost}/${env.cid}/games/${env.pid}/realms/${env.pid}/microservices/micro_${beamoId}/docs?${query.toString()}`;\n}\n\nexport async function runMicroservice(): Promise<void> {\n // Immediate console output to verify process is starting (local dev only)\n // In containers, we rely on Pino logger for all output\n debugLog('[BEAMABLE-NODE] Starting microservice...');\n debugLog(`[BEAMABLE-NODE] Node version: ${process.version}`);\n debugLog(`[BEAMABLE-NODE] Working directory: ${process.cwd()}`);\n debugLog(`[BEAMABLE-NODE] Environment: ${JSON.stringify({\n NODE_ENV: process.env.NODE_ENV,\n CID: process.env.CID ? 'SET' : 'NOT SET',\n PID: process.env.PID ? 'SET' : 'NOT SET',\n HOST: process.env.HOST ? 'SET' : 'NOT SET',\n SECRET: process.env.SECRET ? 'SET' : 'NOT SET',\n })}`);\n if (process.env.BEAMABLE_SKIP_RUNTIME === 'true') {\n return;\n }\n const runtime = new MicroserviceRuntime();\n \n // Handle uncaught errors - log them but don't crash immediately\n // This allows the health check server to keep running so we can debug\n // In containers, errors will be logged by the logger in the runtime\n // Locally, use console.error for visibility\n process.on('uncaughtException', (error) => {\n // In containers, the logger will handle this; locally, show in console\n debugLog('Uncaught Exception:', error);\n // Don't exit - let the health check server keep running\n });\n \n process.on('unhandledRejection', (reason, promise) => {\n // In containers, the logger will handle this; locally, show in console\n debugLog('Unhandled Rejection at:', promise, 'reason:', reason);\n // Don't exit - let the health check server keep running\n });\n \n try {\n await runtime.start();\n } catch (error) {\n // Log the error but don't exit - health check server is running\n // This allows the container to stay alive so we can see what went wrong\n // In containers, the logger already logged it in start(); locally, also use console.error\n debugLog('Failed to start microservice runtime:', error);\n // Keep the process alive so health check can continue\n // The health check will return 503 until isReady is true\n }\n \n const shutdownSignals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT'];\n shutdownSignals.forEach((signal) => {\n process.once(signal, async () => {\n await runtime.shutdown();\n process.exit(0);\n });\n });\n}\n\ninterface GenerateOpenApiOptions {\n serviceName?: string;\n}\n\nexport function generateOpenApiDocumentForRegisteredServices(\n overrides: Partial<EnvironmentConfig> = {},\n options: GenerateOpenApiOptions = {},\n): unknown {\n const services = listRegisteredServices();\n if (services.length === 0) {\n throw new Error('No microservices registered. Import your service module before generating documentation.');\n }\n\n const baseEnv = buildEnvironmentConfig(overrides);\n const primary = options.serviceName\n ? services.find((svc) => svc.name === options.serviceName || svc.qualifiedName === options.serviceName)\n : services[0];\n\n if (!primary) {\n throw new Error(`No registered microservice matched '${options.serviceName}'.`);\n }\n\n return generateOpenApiDocument(\n {\n qualifiedName: primary.qualifiedName,\n name: primary.name,\n callables: Array.from(primary.callables.entries()).map(([displayName, metadata]) => ({\n name: displayName,\n route: metadata.route,\n metadata,\n handler: undefined,\n })),\n },\n baseEnv,\n VERSION,\n );\n}\n\nfunction buildEnvironmentConfig(overrides: Partial<EnvironmentConfig>): EnvironmentConfig {\n const merged: Partial<EnvironmentConfig> = { ...overrides };\n\n const ensure = (key: keyof EnvironmentConfig, fallbackEnv?: string) => {\n if (merged[key] !== undefined) {\n return;\n }\n if (fallbackEnv && process.env[fallbackEnv]) {\n merged[key] = process.env[fallbackEnv] as never;\n }\n };\n\n ensure('cid', 'CID');\n ensure('pid', 'PID');\n ensure('host', 'HOST');\n ensure('secret', 'SECRET');\n ensure('refreshToken', 'REFRESH_TOKEN');\n // Routing key is optional for deployed services (in containers)\n // It will be resolved to empty string if not provided and running in container\n if (!merged.routingKey && !isRunningInContainer()) {\n ensure('routingKey', 'NAME_PREFIX');\n }\n\n if (!merged.cid || !merged.pid || !merged.host) {\n throw new Error('CID, PID, and HOST are required to generate documentation.');\n }\n\n const base = loadEnvironmentConfig();\n\n return {\n ...base,\n ...merged,\n routingKey: merged.routingKey ?? base.routingKey,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { BeamableWebSocket } from './websocket.js';\nimport { GatewayRequester } from './requester.js';\nimport { AuthManager } from './auth.js';\nimport { createLogger } from './logger.js';\nimport { loadEnvironmentConfig } from './env.js';\nimport { loadAndInjectEnvironmentVariables, loadDeveloperEnvVarsSync } from './env-loader.js';\nimport { startCollectorAndWaitForReady } from './collector-manager.js';\nimport pino from 'pino';\n// Removed deasync - using non-blocking async pattern instead\nimport { listRegisteredServices, getServiceOptions, getConfigureServicesHandlers, getInitializeServicesHandlers } from './decorators.js';\nimport { generateOpenApiDocument } from './docs.js';\nimport { VERSION } from './index.js';\nimport { DiscoveryBroadcaster } from './discovery.js';\nimport { BeamableRuntimeError, MissingScopesError, UnauthorizedUserError, UnknownRouteError } from './errors.js';\nimport type {\n EnvironmentConfig,\n RequestContext,\n ServiceDefinition,\n ServiceCallableMetadata,\n GatewayResponse,\n WebsocketEventEnvelope,\n ServiceAccess,\n} from './types.js';\nimport type { Logger } from 'pino';\nimport { BeamableServiceManager } from './services.js';\nimport {\n DependencyBuilder,\n LOGGER_TOKEN,\n ENVIRONMENT_CONFIG_TOKEN,\n REQUEST_CONTEXT_TOKEN,\n BEAMABLE_SERVICES_TOKEN,\n ServiceProvider,\n MutableDependencyScope,\n} from './dependency.js';\nimport { hostToHttpUrl, hostToPortalUrl } from './utils/urls.js';\nimport { FederationRegistry, getFederationComponents, getFederatedInventoryMetadata } from './federation.js';\nimport type { FederatedRequestContext } from './federation.js';\nimport { createServer, type Server } from 'node:http';\n\ninterface ServiceInstance {\n definition: ServiceDefinition;\n instance: Record<string, unknown>;\n configureHandlers: ReturnType<typeof getConfigureServicesHandlers>;\n initializeHandlers: ReturnType<typeof getInitializeServicesHandlers>;\n provider?: ServiceProvider;\n logger: Logger;\n federationRegistry: FederationRegistry;\n}\n\nexport class MicroserviceRuntime {\n private readonly env: EnvironmentConfig;\n private logger: Logger; // Mutable to allow upgrading from console logger to structured logger when collector is ready\n private readonly services: ServiceInstance[];\n private readonly webSocket: BeamableWebSocket;\n private readonly requester: GatewayRequester;\n private readonly authManager: AuthManager;\n private readonly discovery?: DiscoveryBroadcaster;\n private readonly microServiceId = randomUUID();\n private readonly serviceManager: BeamableServiceManager;\n private healthCheckServer?: Server;\n private isReady: boolean = false;\n\n constructor(env?: EnvironmentConfig) {\n this.env = env ?? loadEnvironmentConfig();\n const envConfig = this.env; // Capture for async IIFE to satisfy TypeScript\n \n // STEP 1: Load developer-defined environment variables SYNCHRONOUSLY before logger creation\n // This ensures BetterStack and other env vars are available when the logger initializes\n loadDeveloperEnvVarsSync();\n \n // STEP 2: Create minimal console logger for startup messages (before collector setup)\n // This ensures we have logging available immediately, even before collector is ready\n const startupLogger = pino({\n name: 'beamable-runtime-startup',\n level: 'info',\n }, process.stdout);\n // Display runtime version at startup (VERSION is imported synchronously at top of file)\n startupLogger.info(`Starting Beamable Node microservice runtime (version: ${VERSION}).`);\n \n // STEP 2.5: Load Beamable Config asynchronously (in background, non-blocking)\n // Developer-defined vars are already loaded synchronously above\n // Beamable Config is fetched via API with a 2-second timeout\n (async () => {\n try {\n startupLogger.info('Loading Beamable Config environment variables...');\n await loadAndInjectEnvironmentVariables(envConfig, undefined, true, 2000);\n startupLogger.info('Beamable Config loading completed');\n } catch (error) {\n startupLogger.warn(`Beamable Config loading completed with warnings: ${error instanceof Error ? error.message : String(error)}`);\n }\n })();\n \n // STEP 2: Get registered services to extract service name\n const registered = listRegisteredServices();\n if (registered.length === 0) {\n throw new Error('No microservices registered. Use the @Microservice decorator to register at least one class.');\n }\n \n // Use the first service's name for the main logger (for CloudWatch filtering and ClickHouse compatibility)\n const primaryService = registered[0];\n const qualifiedServiceName = `micro_${primaryService.qualifiedName}`;\n \n // STEP 3: Create logger immediately (non-blocking pattern, matching C#)\n // Start with minimal console logger, upgrade to structured logger when collector is ready\n // This allows the service to start immediately without blocking\n startupLogger.info('Setting up OpenTelemetry collector in background (non-blocking)...');\n \n // Create logger immediately with console output (no OTLP yet)\n // This ensures we have logging available right away\n this.logger = createLogger(this.env, {\n name: 'beamable-node-microservice',\n serviceName: primaryService.name,\n qualifiedServiceName: qualifiedServiceName,\n // No otlpEndpoint - will use console logger initially\n });\n \n // STEP 4: Start collector setup in background (non-blocking)\n // When collector is ready, upgrade logger to structured logger with OTLP\n // This matches C# pattern: collector starts in background, service starts immediately\n startCollectorAndWaitForReady(this.env)\n .then((endpoint) => {\n if (endpoint) {\n // Collector is ready - upgrade to structured logger with OTLP support\n this.logger.info(`Collector ready at ${endpoint}, upgrading to structured logger for Portal logs...`);\n this.logger = createLogger(this.env, {\n name: 'beamable-node-microservice',\n serviceName: primaryService.name,\n qualifiedServiceName: qualifiedServiceName,\n otlpEndpoint: endpoint, // Collector is ready, Portal logs will now work\n });\n this.logger.info('Portal logs enabled - structured logs will now appear in Beamable Portal');\n } else {\n this.logger.warn('Collector setup completed but no endpoint was returned. Continuing with console logs. Portal logs will not be available.');\n }\n })\n .catch((error) => {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.logger.error(`Failed to setup collector: ${errorMsg}. Continuing with console logs. Portal logs will not be available.`);\n // Service continues to work with console logger - graceful degradation\n });\n \n // Continue immediately - don't wait for collector!\n // Service can start accepting requests right away\n // Collector setup happens in background, logger upgrades automatically when ready\n this.serviceManager = new BeamableServiceManager(this.env, this.logger);\n\n this.services = registered.map((definition) => {\n const instance = new definition.ctor() as Record<string, unknown>;\n const configureHandlers = getConfigureServicesHandlers(definition.ctor);\n const initializeHandlers = getInitializeServicesHandlers(definition.ctor);\n const logger = this.logger.child({ service: definition.name });\n const federationRegistry = new FederationRegistry(logger);\n const decoratedFederations = getFederationComponents(definition.ctor);\n for (const component of decoratedFederations) {\n federationRegistry.register(component);\n }\n const inventoryMetadata = getFederatedInventoryMetadata(definition.ctor);\n if (inventoryMetadata.length > 0) {\n federationRegistry.registerInventoryHandlers(instance, inventoryMetadata);\n }\n this.serviceManager.registerFederationRegistry(definition.name, federationRegistry);\n return { definition, instance, configureHandlers, initializeHandlers, logger, federationRegistry };\n });\n\n const socketUrl = this.env.host.endsWith('/socket') ? this.env.host : `${this.env.host}/socket`;\n this.webSocket = new BeamableWebSocket({ url: socketUrl, logger: this.logger });\n this.webSocket.on('message', (payload) => {\n this.logger.debug({ payload }, 'Runtime observed websocket frame.');\n });\n this.requester = new GatewayRequester(this.webSocket, this.logger);\n this.authManager = new AuthManager(this.env, this.requester);\n this.requester.on('event', (envelope) => this.handleEvent(envelope));\n\n // Discovery broadcaster only runs in local development (not in containers)\n // This allows the portal to detect that the service is running locally\n if (!isRunningInContainer() && this.services.length > 0) {\n this.discovery = new DiscoveryBroadcaster({\n env: this.env,\n serviceName: this.services[0].definition.name,\n routingKey: this.env.routingKey,\n logger: this.logger.child({ component: 'DiscoveryBroadcaster' }),\n });\n }\n }\n\n async start(): Promise<void> {\n // Immediate console output for container logs (before logger is ready)\n debugLog('[BEAMABLE-NODE] MicroserviceRuntime.start() called');\n debugLog(`[BEAMABLE-NODE] Service count: ${this.services.length}`);\n \n this.printHelpfulUrls(this.services[0]);\n this.logger.info('Starting Beamable Node microservice runtime.');\n \n // Start health check server FIRST - this is critical for container health checks\n // Even if startup fails, the health check server must be running so we can debug\n debugLog('[BEAMABLE-NODE] Starting health check server...');\n await this.startHealthCheckServer();\n debugLog('[BEAMABLE-NODE] Health check server started');\n \n try {\n this.logger.info('Connecting to Beamable gateway...');\n await this.webSocket.connect();\n await new Promise((resolve) => setTimeout(resolve, 250));\n \n this.logger.info('Authenticating with Beamable...');\n await this.authManager.authenticate();\n \n this.logger.info('Initializing Beamable SDK services...');\n await this.serviceManager.initialize();\n \n this.logger.info('Initializing dependency providers...');\n await this.initializeDependencyProviders();\n \n this.logger.info('Registering service with gateway...');\n await this.registerService();\n \n this.logger.info('Starting discovery broadcaster...');\n await this.discovery?.start();\n \n // Mark as ready only after service is fully registered and discovery is started\n this.isReady = true;\n this.logger.info('Beamable microservice runtime is ready to accept traffic.');\n } catch (error) {\n // Log the error with full context but don't crash - health check server is running\n // This allows the container to stay alive so we can debug the issue\n // Debug output for local development only (in containers, logger handles this)\n debugLog('[BEAMABLE-NODE] FATAL ERROR during startup:');\n debugLog(`[BEAMABLE-NODE] Error message: ${error instanceof Error ? error.message : String(error)}`);\n debugLog(`[BEAMABLE-NODE] Error stack: ${error instanceof Error ? error.stack : 'No stack trace'}`);\n debugLog(`[BEAMABLE-NODE] isReady: ${this.isReady}`);\n \n this.logger.error(\n { \n err: error,\n errorMessage: error instanceof Error ? error.message : String(error),\n errorStack: error instanceof Error ? error.stack : undefined,\n isReady: this.isReady,\n },\n 'Failed to fully initialize microservice runtime. Health check will continue to return 503 until initialization completes.'\n );\n // DON'T re-throw - keep process alive so health check can show 503\n // This allows us to see the error in logs\n this.isReady = false;\n }\n }\n\n async shutdown(): Promise<void> {\n this.logger.info('Shutting down microservice runtime.');\n this.isReady = false; // Mark as not ready during shutdown\n this.discovery?.stop();\n await this.stopHealthCheckServer();\n this.requester.dispose();\n await this.webSocket.close();\n }\n\n private async startHealthCheckServer(): Promise<void> {\n // For deployed services, always start health check server (required for container health checks)\n // For local development, only start if healthPort is explicitly set\n // IMPORTANT: Always default to 6565 if HEALTH_PORT env var is not set, as this is the standard port\n const healthPort = this.env.healthPort || 6565;\n \n // Always start health check server if we have a valid port\n // The container orchestrator expects this endpoint to be available\n if (!healthPort || healthPort === 0) {\n // Health check server not needed (local development without explicit port)\n this.logger.debug('Health check server skipped (no healthPort set)');\n return;\n }\n\n this.healthCheckServer = createServer((req, res) => {\n if (req.url === '/health' && req.method === 'GET') {\n // Only return success if service is fully ready (registered and accepting traffic)\n if (this.isReady) {\n res.writeHead(200, { 'Content-Type': 'text/plain' });\n res.end('responsive');\n } else {\n // Service is still starting up\n res.writeHead(503, { 'Content-Type': 'text/plain' });\n res.end('Service Unavailable');\n }\n } else {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n }\n });\n\n return new Promise((resolve, reject) => {\n this.healthCheckServer!.listen(healthPort, '0.0.0.0', () => {\n this.logger.info({ port: healthPort }, 'Health check server started on port');\n resolve();\n });\n this.healthCheckServer!.on('error', (err) => {\n this.logger.error({ err, port: healthPort }, 'Failed to start health check server');\n reject(err);\n });\n });\n }\n\n private async stopHealthCheckServer(): Promise<void> {\n if (!this.healthCheckServer) {\n return;\n }\n\n return new Promise((resolve) => {\n this.healthCheckServer!.close(() => {\n this.logger.info('Health check server stopped');\n resolve();\n });\n });\n }\n\n private async registerService(): Promise<void> {\n const primary = this.services[0]?.definition;\n if (!primary) {\n throw new Error('Unexpected missing service definition during registration.');\n }\n const options = getServiceOptions(primary.ctor) ?? {};\n // Match C# exactly: use qualifiedName (preserves case) for name field.\n // The gateway lowercases service names when creating bindings, but uses the original case\n // from the registration request when constructing routing key lookups.\n // This ensures the routing key format matches what the gateway expects.\n // The gateway's binding lookup behavior:\n // - Gateway error shows: \"No binding found for service ...micro_examplenodeservice.basic\"\n // - This means the gateway lowercases the service name for binding storage/lookup\n // - Portal sends requests with mixed case in URL and routing key header\n // - The gateway lowercases the URL path for binding lookup, which should work\n // - But we need to register with the format the gateway expects for the binding key\n // - The gateway constructs binding key as: {cid}.{pid}.{lowercaseServiceName}.{type}\n // - So we register with lowercase to match what the gateway stores in the binding\n // - The portal will still send mixed case, and the gateway will lowercase it for lookup\n // Register with mixed-case qualifiedName to match C# behavior\n // The gateway will lowercase the service name when creating the binding key,\n // but the registration request should use the original case (as C# does)\n // This ensures the service name in the registration matches what the portal expects\n // Register with mixed-case qualifiedName to match C# behavior\n // The gateway's ServiceIdentity.fullNameNoType lowercases the service name when creating bindings,\n // but the registration request should use the original case (as C# does)\n // This ensures the service name in the registration matches what the portal expects\n const isDeployed = isRunningInContainer();\n \n // For deployed services, routingKey should be null/undefined (None in Scala)\n // For local dev, routingKey should be the actual routing key string\n // The backend expects Option[String] = None for deployed services\n // Note: microServiceId is not part of SocketSessionProviderRegisterRequest, so we don't include it\n // All fields except 'type' are Option[T] in Scala, so undefined fields will be omitted from JSON\n // This matches C# behavior where null/None fields are not serialized\n const request: Record<string, unknown> = {\n type: 'basic',\n name: primary.qualifiedName, // Use mixed-case as C# does - gateway handles lowercasing for binding storage\n beamoName: primary.name,\n };\n \n // Only include routingKey and startedById if they have values (for local dev)\n // For deployed services, these should be omitted (undefined) to match None in Scala\n if (!isDeployed && this.env.routingKey) {\n request.routingKey = this.env.routingKey;\n }\n if (!isDeployed && this.env.accountId) {\n request.startedById = this.env.accountId;\n }\n\n // Log registration request to match C# behavior exactly\n // Also log the actual JSON that will be sent (undefined fields will be omitted)\n const serializedRequest = JSON.stringify(request);\n this.logger.debug(\n {\n request: {\n type: request.type,\n name: request.name,\n beamoName: request.beamoName,\n routingKey: request.routingKey,\n startedById: request.startedById,\n },\n serializedJson: serializedRequest,\n isDeployed,\n },\n 'Registering service provider with gateway.',\n );\n\n try {\n await this.requester.request('post', 'gateway/provider', request);\n this.logger.info({ serviceName: primary.qualifiedName }, 'Service provider registered successfully.');\n \n // After registration, the gateway's BasicServiceProvider.start() is called asynchronously\n // This triggers afterRabbitInit() -> setupDirectServiceCommunication() -> scheduleServiceBindingCheck()\n // The first updateBindings() call happens immediately (0.millisecond delay)\n // We wait a bit to allow the gateway to set up the HTTP binding and call updateBindings()\n // This is especially important for deployed services where the gateway needs to establish\n // the external host binding before bindings can be created\n if (isDeployed) {\n this.logger.debug('Waiting for gateway to establish bindings after registration...');\n await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 second wait for deployed services\n this.logger.debug('Wait complete, gateway should have established bindings by now.');\n }\n } catch (error) {\n this.logger.error(\n {\n err: error,\n request,\n serviceName: primary.qualifiedName,\n errorMessage: error instanceof Error ? error.message : String(error),\n },\n 'Failed to register service provider with gateway. This will prevent the service from receiving requests.'\n );\n throw error; // Re-throw so startup fails and we can see the error\n }\n\n if (options.disableAllBeamableEvents) {\n this.logger.info('Beamable events disabled by configuration.');\n } else {\n const eventRequest = {\n type: 'event',\n evtWhitelist: ['content.manifest', 'realm.config', 'logging.context'],\n };\n try {\n await this.requester.request('post', 'gateway/provider', eventRequest);\n } catch (error) {\n this.logger.warn({ err: error }, 'Failed to register event provider. Continuing without events.');\n }\n }\n }\n\n private async handleEvent(envelope: WebsocketEventEnvelope): Promise<void> {\n try {\n if (!envelope.path) {\n this.logger.debug({ envelope }, 'Ignoring websocket event without path.');\n return;\n }\n\n if (envelope.path.startsWith('event/')) {\n await this.requester.acknowledge(envelope.id);\n return;\n }\n\n const context = this.toRequestContext(envelope);\n await this.dispatch(context);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.logger.error({ err, envelope }, 'Failed to handle websocket event.');\n const status = this.resolveErrorStatus(err);\n const response: GatewayResponse = {\n id: envelope.id,\n status,\n body: {\n error: err.name,\n message: err.message,\n },\n };\n await this.requester.sendResponse(response);\n }\n }\n\n private toRequestContext(envelope: WebsocketEventEnvelope): RequestContext {\n const path = envelope.path ?? '';\n const method = envelope.method ?? 'post';\n const userId = typeof envelope.from === 'number' ? envelope.from : 0;\n const headers = envelope.headers ?? {};\n \n // Extract scopes from envelope.scopes array\n // Note: X-DE-SCOPE header contains CID.PID, not scope values\n // The gateway sends scopes in envelope.scopes array\n // For admin endpoints, the gateway may not send scopes in the envelope,\n // so we infer admin scope from the path if it's an admin route\n const envelopeScopes = envelope.scopes ?? [];\n let scopes = normalizeScopes(envelopeScopes);\n \n // If this is an admin endpoint and no scopes are provided, infer admin scope\n // The gateway may not always send scopes for admin routes\n const pathLower = path.toLowerCase();\n if (pathLower.includes('/admin/') && scopes.size === 0) {\n scopes = normalizeScopes(['admin']);\n }\n\n let body: Record<string, unknown> | undefined;\n if (envelope.body && typeof envelope.body === 'string') {\n try {\n body = JSON.parse(envelope.body) as Record<string, unknown>;\n } catch (error) {\n this.logger.warn({ err: error, raw: envelope.body }, 'Failed to parse body string.');\n }\n } else if (envelope.body && typeof envelope.body === 'object') {\n body = envelope.body as Record<string, unknown>;\n }\n\n let payload: unknown;\n if (body && typeof body === 'object' && 'payload' in body) {\n const rawPayload = (body as Record<string, unknown>).payload;\n if (typeof rawPayload === 'string') {\n try {\n payload = JSON.parse(rawPayload) as unknown[];\n } catch (error) {\n this.logger.warn({ err: error }, 'Failed to parse payload JSON.');\n payload = rawPayload;\n }\n } else {\n payload = rawPayload;\n }\n }\n\n const targetService = this.findServiceForPath(path);\n const services = this.serviceManager.createFacade(userId, scopes, targetService?.definition.name);\n const provider = this.createRequestScope(path, targetService);\n\n const context: RequestContext = {\n id: envelope.id,\n path,\n method,\n status: envelope.status ?? 0,\n userId,\n payload,\n body,\n scopes,\n headers,\n cid: this.env.cid,\n pid: this.env.pid,\n services,\n throwIfCancelled: () => {},\n isCancelled: () => false,\n hasScopes: (...requiredScopes: string[]) => requiredScopes.every((scope) => scopeSetHas(scopes, scope)),\n requireScopes: (...requiredScopes: string[]) => {\n const missingScopes = requiredScopes.filter((scope) => !scopeSetHas(scopes, scope));\n if (missingScopes.length > 0) {\n throw new MissingScopesError(missingScopes);\n }\n },\n provider,\n };\n\n provider.setInstance(REQUEST_CONTEXT_TOKEN, context);\n provider.setInstance(BEAMABLE_SERVICES_TOKEN, services);\n\n return context;\n }\n\n private findServiceForPath(path: string): ServiceInstance | undefined {\n // Gateway sends paths with lowercase service names, so we need case-insensitive matching\n // Match by comparing lowercase versions to handle gateway's lowercase path format\n const pathLower = path.toLowerCase();\n return this.services.find((service) => {\n const qualifiedNameLower = service.definition.qualifiedName.toLowerCase();\n return pathLower.startsWith(`${qualifiedNameLower}/`);\n });\n }\n\n private async dispatch(ctx: RequestContext): Promise<void> {\n const service = this.findServiceForPath(ctx.path);\n if (!service) {\n throw new UnknownRouteError(ctx.path);\n }\n\n if (await this.tryHandleFederationRoute(ctx, service)) {\n return;\n }\n\n if (await this.tryHandleAdminRoute(ctx, service)) {\n return;\n }\n\n // Extract route from path - handle case-insensitive path matching\n const pathLower = ctx.path.toLowerCase();\n const qualifiedNameLower = service.definition.qualifiedName.toLowerCase();\n const route = pathLower.substring(qualifiedNameLower.length + 1);\n const metadata = service.definition.callables.get(route);\n if (!metadata) {\n throw new UnknownRouteError(ctx.path);\n }\n\n // For server and admin access, allow userId: 0 if the appropriate scope is present\n // For client access, always require userId > 0\n if (metadata.requireAuth && ctx.userId <= 0) {\n if (metadata.access === 'server' && scopeSetHas(ctx.scopes, 'server')) {\n // Server callables with server scope don't need a user ID\n } else if (metadata.access === 'admin' && scopeSetHas(ctx.scopes, 'admin')) {\n // Admin callables with admin scope don't need a user ID\n } else {\n throw new UnauthorizedUserError(route);\n }\n }\n\n enforceAccess(metadata.access, ctx);\n\n if (metadata.requiredScopes.length > 0) {\n const missing = metadata.requiredScopes.filter((scope) => !scopeSetHas(ctx.scopes, scope));\n if (missing.length > 0) {\n throw new MissingScopesError(missing);\n }\n }\n\n const handler = service.instance[metadata.displayName];\n if (typeof handler !== 'function') {\n throw new Error(`Callable ${metadata.displayName} is not a function on service ${service.definition.name}.`);\n }\n\n const args = this.buildInvocationArguments(handler as (...args: unknown[]) => unknown, ctx);\n const result = await Promise.resolve((handler as (...args: unknown[]) => unknown).apply(service.instance, args));\n await this.sendSuccessResponse(ctx, metadata, result);\n }\n\n private buildInvocationArguments(\n handler: (...args: unknown[]) => unknown,\n ctx: RequestContext,\n ): unknown[] {\n const payload = Array.isArray(ctx.payload)\n ? ctx.payload\n : typeof ctx.payload === 'string'\n ? [ctx.payload]\n : ctx.payload === undefined\n ? []\n : [ctx.payload];\n\n const expectedParams = handler.length;\n if (expectedParams === payload.length + 1) {\n return [ctx, ...payload];\n }\n return payload;\n }\n\n private async sendSuccessResponse(ctx: RequestContext, metadata: ServiceCallableMetadata, result: unknown): Promise<void> {\n let body: unknown;\n if (metadata.useLegacySerialization) {\n const serialized = typeof result === 'string' ? result : JSON.stringify(result ?? null);\n body = { payload: serialized };\n } else {\n body = result ?? null;\n }\n\n const response: GatewayResponse = {\n id: ctx.id,\n status: 200,\n body,\n };\n await this.requester.sendResponse(response);\n }\n\n private async sendFederationResponse(ctx: RequestContext, result: unknown): Promise<void> {\n const response: GatewayResponse = {\n id: ctx.id,\n status: 200,\n body: result ?? null,\n };\n await this.requester.sendResponse(response);\n }\n\n private async tryHandleFederationRoute(ctx: RequestContext, service: ServiceInstance): Promise<boolean> {\n // Gateway sends paths with lowercase service names, so we need case-insensitive matching\n const pathLower = ctx.path.toLowerCase();\n const qualifiedNameLower = service.definition.qualifiedName.toLowerCase();\n const prefixLower = `${qualifiedNameLower}/`;\n if (!pathLower.startsWith(prefixLower)) {\n return false;\n }\n // Extract relative path - use lowercase length since gateway sends lowercase paths\n const relativePath = ctx.path.substring(qualifiedNameLower.length + 1);\n const handler = service.federationRegistry.resolve(relativePath);\n if (!handler) {\n return false;\n }\n\n const result = await handler.invoke(ctx as FederatedRequestContext);\n await this.sendFederationResponse(ctx, result);\n return true;\n }\n\n private async tryHandleAdminRoute(ctx: RequestContext, service: ServiceInstance): Promise<boolean> {\n // Gateway sends paths with lowercase service names, so we need case-insensitive matching\n // Check if path starts with the admin prefix (case-insensitive)\n const pathLower = ctx.path.toLowerCase();\n const adminPrefixLower = `${service.definition.qualifiedName.toLowerCase()}/admin/`;\n if (!pathLower.startsWith(adminPrefixLower)) {\n return false;\n }\n\n const options = getServiceOptions(service.definition.ctor) ?? {};\n\n const action = pathLower.substring(adminPrefixLower.length);\n const requiresAdmin = action === 'metadata' || action === 'docs';\n if (requiresAdmin && !scopeSetHas(ctx.scopes, 'admin')) {\n // For portal requests to admin endpoints, the gateway may not send scopes\n // The X-DE-SCOPE header contains CID.PID, not scope values\n // If this is a portal request (has X-DE-SCOPE header), grant admin scope\n const hasPortalHeader = ctx.headers['X-DE-SCOPE'] || ctx.headers['x-de-scope'];\n if (hasPortalHeader) {\n // Grant admin scope for portal requests to admin endpoints\n ctx.scopes.add('admin');\n } else {\n throw new MissingScopesError(['admin']);\n }\n }\n\n switch (action) {\n case 'health':\n case 'healthcheck':\n await this.requester.sendResponse({ id: ctx.id, status: 200, body: 'responsive' });\n return true;\n case 'metadata':\n case 'docs':\n break;\n default:\n if (!scopeSetHas(ctx.scopes, 'admin')) {\n throw new MissingScopesError(['admin']);\n }\n throw new UnknownRouteError(ctx.path);\n }\n\n if (action === 'metadata') {\n const federatedComponents = service.federationRegistry\n .list()\n .map((component) => ({\n federationNamespace: component.federationNamespace,\n federationType: component.federationType,\n }));\n\n await this.requester.sendResponse({\n id: ctx.id,\n status: 200,\n body: {\n serviceName: service.definition.name,\n sdkVersion: this.env.sdkVersionExecution,\n sdkBaseBuildVersion: this.env.sdkVersionExecution,\n sdkExecutionVersion: this.env.sdkVersionExecution,\n useLegacySerialization: Boolean(options.useLegacySerialization),\n disableAllBeamableEvents: Boolean(options.disableAllBeamableEvents),\n enableEagerContentLoading: false,\n instanceId: this.microServiceId,\n routingKey: this.env.routingKey ?? '',\n federatedComponents,\n },\n });\n return true;\n }\n\n if (action === 'docs') {\n try {\n const document = generateOpenApiDocument(\n {\n qualifiedName: service.definition.qualifiedName,\n name: service.definition.name,\n callables: Array.from(service.definition.callables.values()).map((callable) => ({\n name: callable.displayName,\n route: callable.route,\n metadata: callable,\n handler: typeof service.instance[callable.displayName] === 'function'\n ? (service.instance[callable.displayName] as (...args: unknown[]) => unknown)\n : undefined,\n })),\n },\n this.env,\n VERSION,\n );\n\n // Ensure document is valid (not empty)\n if (!document || Object.keys(document).length === 0) {\n this.logger.warn({ serviceName: service.definition.name }, 'Generated OpenAPI document is empty');\n }\n\n await this.requester.sendResponse({\n id: ctx.id,\n status: 200,\n body: document,\n });\n return true;\n } catch (error) {\n this.logger.error({ err: error, serviceName: service.definition.name }, 'Failed to generate or send docs');\n throw error;\n }\n }\n\n return false;\n }\n\n private resolveErrorStatus(error: Error): number {\n if (error instanceof UnauthorizedUserError) {\n return 401;\n }\n if (error instanceof MissingScopesError) {\n return 403;\n }\n if (error instanceof UnknownRouteError) {\n return 404;\n }\n if (error instanceof BeamableRuntimeError) {\n return 500;\n }\n return 500;\n }\n\n private printHelpfulUrls(service?: ServiceInstance): void {\n if (!service) {\n return;\n }\n\n // Only print helpful URLs when IS_LOCAL=1 is set\n // In deployed containers, we want only JSON logs for proper log collection\n if (process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true') {\n return;\n }\n\n const docsUrl = buildDocsPortalUrl(this.env, service.definition);\n const endpointBase = buildPostmanBaseUrl(this.env, service.definition);\n\n const green = (text: string) => `\\x1b[32m${text}\\x1b[0m`;\n const yellow = (text: string) => `\\x1b[33m${text}\\x1b[0m`;\n\n const bannerLines = [\n '',\n yellow('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'),\n ` ${green('Beamable Node microservice ready:')} ${green(service.definition.name)}`,\n yellow(' Quick shortcuts'),\n ` ${yellow('Docs:')} ${docsUrl}`,\n ` ${yellow('Endpoint:')} ${endpointBase}`,\n yellow('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'),\n '',\n ];\n\n process.stdout.write(`${bannerLines.join('\\n')}`);\n }\n\n private async initializeDependencyProviders(): Promise<void> {\n for (const service of this.services) {\n const builder = new DependencyBuilder();\n builder.tryAddSingletonInstance(LOGGER_TOKEN, service.logger);\n builder.tryAddSingletonInstance(ENVIRONMENT_CONFIG_TOKEN, this.env);\n builder.tryAddSingletonInstance(BeamableServiceManager, this.serviceManager);\n builder.tryAddSingletonInstance(service.definition.ctor, service.instance);\n builder.tryAddSingletonInstance(FederationRegistry, service.federationRegistry);\n\n for (const handler of service.configureHandlers) {\n await handler(builder);\n }\n\n const provider = builder.build();\n service.provider = provider;\n\n for (const handler of service.initializeHandlers) {\n await handler(provider);\n }\n\n Object.defineProperty(service.instance, 'provider', {\n value: provider,\n enumerable: false,\n configurable: false,\n writable: false,\n });\n }\n }\n\n private createRequestScope(path: string, service?: ServiceInstance): MutableDependencyScope {\n const targetService = service ?? this.findServiceForPath(path);\n const provider = targetService?.provider ?? new DependencyBuilder().build();\n return provider.createScope();\n }\n}\n\nfunction enforceAccess(access: ServiceAccess, ctx: RequestContext): void {\n switch (access) {\n case 'client':\n if (ctx.userId <= 0) {\n throw new UnauthorizedUserError(ctx.path);\n }\n break;\n case 'server':\n if (!scopeSetHas(ctx.scopes, 'server')) {\n throw new MissingScopesError(['server']);\n }\n break;\n case 'admin':\n if (!scopeSetHas(ctx.scopes, 'admin')) {\n throw new MissingScopesError(['admin']);\n }\n break;\n default:\n break;\n }\n}\n\n/**\n * Conditionally output to console.error only when running locally (not in container).\n * In containers, we want only Pino JSON logs to stdout for proper log collection.\n */\nfunction debugLog(...args: unknown[]): void {\n // Only output debug logs when IS_LOCAL=1 is set\n if (process.env.IS_LOCAL === '1' || process.env.IS_LOCAL === 'true') {\n console.error(...args);\n }\n}\n\n/**\n * Determines if we're running in a deployed container.\n * Used for service registration logic (routing key handling, discovery broadcaster, etc.)\n * \n * Note: For log formatting, use IS_LOCAL env var instead.\n */\nfunction isRunningInContainer(): boolean {\n // Check for Docker container\n try {\n const fs = require('fs');\n if (fs.existsSync('/.dockerenv')) {\n return true;\n }\n } catch {\n // fs might not be available\n }\n \n // Check for Docker container hostname pattern (12 hex chars)\n const hostname = process.env.HOSTNAME || '';\n if (hostname && /^[a-f0-9]{12}$/i.test(hostname)) {\n return true;\n }\n \n // Explicit container indicators\n if (\n process.env.DOTNET_RUNNING_IN_CONTAINER === 'true' ||\n process.env.CONTAINER === 'beamable' ||\n !!process.env.ECS_CONTAINER_METADATA_URI ||\n !!process.env.KUBERNETES_SERVICE_HOST\n ) {\n return true;\n }\n \n // Default: assume local development\n return false;\n}\n\nfunction normalizeScopes(scopes: Array<unknown>): Set<string> {\n const normalized = new Set<string>();\n for (const scope of scopes) {\n if (typeof scope !== 'string' || scope.trim().length === 0) {\n continue;\n }\n normalized.add(scope.trim().toLowerCase());\n }\n return normalized;\n}\n\nfunction scopeSetHas(scopes: Set<string>, scope: string): boolean {\n const normalized = scope.trim().toLowerCase();\n if (normalized.length === 0) {\n return false;\n }\n return scopes.has('*') || scopes.has(normalized);\n}\n\nfunction buildPostmanBaseUrl(env: EnvironmentConfig, service: ServiceDefinition): string {\n const httpHost = hostToHttpUrl(env.host);\n const routingKeyPart = env.routingKey ? env.routingKey : '';\n return `${httpHost}/basic/${env.cid}.${env.pid}.${routingKeyPart}${service.qualifiedName}/`;\n}\n\nfunction buildDocsPortalUrl(env: EnvironmentConfig, service: ServiceDefinition): string {\n const portalHost = hostToPortalUrl(hostToHttpUrl(env.host));\n const queryParams: Record<string, string> = { srcTool: 'node-runtime' };\n if (env.routingKey) {\n queryParams.routingKey = env.routingKey;\n }\n const query = new URLSearchParams(queryParams);\n if (env.refreshToken) {\n query.set('refresh_token', env.refreshToken);\n }\n const beamoId = service.name;\n return `${portalHost}/${env.cid}/games/${env.pid}/realms/${env.pid}/microservices/micro_${beamoId}/docs?${query.toString()}`;\n}\n\nexport async function runMicroservice(): Promise<void> {\n // Immediate console output to verify process is starting (local dev only)\n // In containers, we rely on Pino logger for all output\n debugLog('[BEAMABLE-NODE] Starting microservice...');\n debugLog(`[BEAMABLE-NODE] Node version: ${process.version}`);\n debugLog(`[BEAMABLE-NODE] Working directory: ${process.cwd()}`);\n debugLog(`[BEAMABLE-NODE] Environment: ${JSON.stringify({\n NODE_ENV: process.env.NODE_ENV,\n CID: process.env.CID ? 'SET' : 'NOT SET',\n PID: process.env.PID ? 'SET' : 'NOT SET',\n HOST: process.env.HOST ? 'SET' : 'NOT SET',\n SECRET: process.env.SECRET ? 'SET' : 'NOT SET',\n })}`);\n if (process.env.BEAMABLE_SKIP_RUNTIME === 'true') {\n return;\n }\n const runtime = new MicroserviceRuntime();\n \n // Handle uncaught errors - log them but don't crash immediately\n // This allows the health check server to keep running so we can debug\n // In containers, errors will be logged by the logger in the runtime\n // Locally, use console.error for visibility\n process.on('uncaughtException', (error) => {\n // In containers, the logger will handle this; locally, show in console\n debugLog('Uncaught Exception:', error);\n // Don't exit - let the health check server keep running\n });\n \n process.on('unhandledRejection', (reason, promise) => {\n // In containers, the logger will handle this; locally, show in console\n debugLog('Unhandled Rejection at:', promise, 'reason:', reason);\n // Don't exit - let the health check server keep running\n });\n \n try {\n await runtime.start();\n } catch (error) {\n // Log the error but don't exit - health check server is running\n // This allows the container to stay alive so we can see what went wrong\n // In containers, the logger already logged it in start(); locally, also use console.error\n debugLog('Failed to start microservice runtime:', error);\n // Keep the process alive so health check can continue\n // The health check will return 503 until isReady is true\n }\n \n const shutdownSignals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT'];\n shutdownSignals.forEach((signal) => {\n process.once(signal, async () => {\n await runtime.shutdown();\n process.exit(0);\n });\n });\n}\n\ninterface GenerateOpenApiOptions {\n serviceName?: string;\n}\n\nexport function generateOpenApiDocumentForRegisteredServices(\n overrides: Partial<EnvironmentConfig> = {},\n options: GenerateOpenApiOptions = {},\n): unknown {\n const services = listRegisteredServices();\n if (services.length === 0) {\n throw new Error('No microservices registered. Import your service module before generating documentation.');\n }\n\n const baseEnv = buildEnvironmentConfig(overrides);\n const primary = options.serviceName\n ? services.find((svc) => svc.name === options.serviceName || svc.qualifiedName === options.serviceName)\n : services[0];\n\n if (!primary) {\n throw new Error(`No registered microservice matched '${options.serviceName}'.`);\n }\n\n return generateOpenApiDocument(\n {\n qualifiedName: primary.qualifiedName,\n name: primary.name,\n callables: Array.from(primary.callables.entries()).map(([displayName, metadata]) => ({\n name: displayName,\n route: metadata.route,\n metadata,\n handler: undefined,\n })),\n },\n baseEnv,\n VERSION,\n );\n}\n\nfunction buildEnvironmentConfig(overrides: Partial<EnvironmentConfig>): EnvironmentConfig {\n const merged: Partial<EnvironmentConfig> = { ...overrides };\n\n const ensure = (key: keyof EnvironmentConfig, fallbackEnv?: string) => {\n if (merged[key] !== undefined) {\n return;\n }\n if (fallbackEnv && process.env[fallbackEnv]) {\n merged[key] = process.env[fallbackEnv] as never;\n }\n };\n\n ensure('cid', 'CID');\n ensure('pid', 'PID');\n ensure('host', 'HOST');\n ensure('secret', 'SECRET');\n ensure('refreshToken', 'REFRESH_TOKEN');\n // Routing key is optional for deployed services (in containers)\n // It will be resolved to empty string if not provided and running in container\n if (!merged.routingKey && !isRunningInContainer()) {\n ensure('routingKey', 'NAME_PREFIX');\n }\n\n if (!merged.cid || !merged.pid || !merged.host) {\n throw new Error('CID, PID, and HOST are required to generate documentation.');\n }\n\n const base = loadEnvironmentConfig();\n\n return {\n ...base,\n ...merged,\n routingKey: merged.routingKey ?? base.routingKey,\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -877,6 +877,24 @@ async function prepareDockerContext({ entry, distDir, openapiPath, packageJson,
|
|
|
877
877
|
} catch {
|
|
878
878
|
await fs.writeFile(path.join(appDir, 'beam_openApi.json'), '{}\n');
|
|
879
879
|
}
|
|
880
|
+
|
|
881
|
+
// Copy beam.env file if it exists (for developer-defined environment variables)
|
|
882
|
+
let beamEnvFile = null;
|
|
883
|
+
const beamEnvPath = path.join(path.dirname(packageJson), 'beam.env');
|
|
884
|
+
const beamEnvHiddenPath = path.join(path.dirname(packageJson), '.beam.env');
|
|
885
|
+
try {
|
|
886
|
+
if (await fs.access(beamEnvPath).then(() => true).catch(() => false)) {
|
|
887
|
+
await fs.copyFile(beamEnvPath, path.join(appDir, 'beam.env'));
|
|
888
|
+
beamEnvFile = 'beam.env';
|
|
889
|
+
console.log('Included beam.env file in Docker image');
|
|
890
|
+
} else if (await fs.access(beamEnvHiddenPath).then(() => true).catch(() => false)) {
|
|
891
|
+
await fs.copyFile(beamEnvHiddenPath, path.join(appDir, '.beam.env'));
|
|
892
|
+
beamEnvFile = '.beam.env';
|
|
893
|
+
console.log('Included .beam.env file in Docker image');
|
|
894
|
+
}
|
|
895
|
+
} catch {
|
|
896
|
+
// beam.env is optional, ignore if not found
|
|
897
|
+
}
|
|
880
898
|
|
|
881
899
|
const dockerfile = `# syntax=docker/dockerfile:1
|
|
882
900
|
ARG NODE_VERSION=${nodeVersion}
|
|
@@ -903,7 +921,7 @@ RUN mkdir -p /opt/beam/collectors/1.0.1 && \\
|
|
|
903
921
|
apk del wget gzip
|
|
904
922
|
|
|
905
923
|
COPY app/dist ./dist
|
|
906
|
-
COPY app/beam_openApi.json ./beam_openApi.json
|
|
924
|
+
COPY app/beam_openApi.json ./beam_openApi.json${beamEnvFile ? `\nCOPY app/${beamEnvFile} ./${beamEnvFile}` : ''}
|
|
907
925
|
|
|
908
926
|
# Expose health check port (matches C# microservice behavior)
|
|
909
927
|
EXPOSE 6565
|