@omen.foundation/node-microservice-runtime 0.1.6 → 0.1.7
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/env.d.ts.map +1 -1
- package/dist/env.js +27 -5
- package/dist/env.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +12 -7
- package/dist/logger.js.map +1 -1
- package/{dist/env.cjs → dist-cjs/env.js} +14 -2
- package/{dist/logger.cjs → dist-cjs/logger.js} +7 -4
- package/package.json +1 -1
- package/src/env.ts +31 -5
- package/src/logger.ts +13 -7
- /package/{dist/auth.cjs → dist-cjs/auth.js} +0 -0
- /package/{dist/decorators.cjs → dist-cjs/decorators.js} +0 -0
- /package/{dist/dependency.cjs → dist-cjs/dependency.js} +0 -0
- /package/{dist/dev.cjs → dist-cjs/dev.js} +0 -0
- /package/{dist/discovery.cjs → dist-cjs/discovery.js} +0 -0
- /package/{dist/docs.cjs → dist-cjs/docs.js} +0 -0
- /package/{dist/errors.cjs → dist-cjs/errors.js} +0 -0
- /package/{dist/federation.cjs → dist-cjs/federation.js} +0 -0
- /package/{dist/index.cjs → dist-cjs/index.js} +0 -0
- /package/{dist/inventory.cjs → dist-cjs/inventory.js} +0 -0
- /package/{dist/message.cjs → dist-cjs/message.js} +0 -0
- /package/{dist/requester.cjs → dist-cjs/requester.js} +0 -0
- /package/{dist/routing.cjs → dist-cjs/routing.js} +0 -0
- /package/{dist/runtime.cjs → dist-cjs/runtime.js} +0 -0
- /package/{dist/services.cjs → dist-cjs/services.js} +0 -0
- /package/{dist/storage.cjs → dist-cjs/storage.js} +0 -0
- /package/{dist/types.cjs → dist-cjs/types.js} +0 -0
- /package/{dist/utils/urls.cjs → dist-cjs/utils/urls.js} +0 -0
- /package/{dist/websocket.cjs → dist-cjs/websocket.js} +0 -0
package/dist/env.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA+GpD,wBAAgB,qBAAqB,IAAI,iBAAiB,CA4BzD;AAED,wBAAgB,2BAA2B,IAAI,MAAM,CAMpD"}
|
package/dist/env.js
CHANGED
|
@@ -36,15 +36,37 @@ function resolveRoutingKey() {
|
|
|
36
36
|
if (raw && raw.trim().length > 0) {
|
|
37
37
|
return raw.trim();
|
|
38
38
|
}
|
|
39
|
+
// Check for explicit container indicators first (highest priority)
|
|
40
|
+
const isExplicitlyInContainer = process.env.DOTNET_RUNNING_IN_CONTAINER === 'true' ||
|
|
41
|
+
process.env.CONTAINER === 'beamable' ||
|
|
42
|
+
!!process.env.ECS_CONTAINER_METADATA_URI ||
|
|
43
|
+
!!process.env.KUBERNETES_SERVICE_HOST;
|
|
44
|
+
if (isExplicitlyInContainer) {
|
|
45
|
+
// We're definitely in a container - return undefined (becomes None in Scala)
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
39
48
|
// For deployed services (in containers), routing key should be undefined (None in Scala)
|
|
40
49
|
// Beamable sets CID, PID, HOST, SECRET in containers but NOT routing key
|
|
41
|
-
//
|
|
42
|
-
|
|
50
|
+
// BUT: Local dev also has these env vars from .env file, so we need to be more careful
|
|
51
|
+
// If we have the required Beamable env vars but NO routing key AND no explicit container indicators,
|
|
52
|
+
// we might be in a deployed container OR local dev without routing key set
|
|
53
|
+
// For safety, if we're not explicitly in a container, try to generate a routing key for local dev
|
|
54
|
+
const hasBeamableEnvVars = !!(process.env.CID && process.env.PID && process.env.HOST && process.env.SECRET);
|
|
43
55
|
const hasNoRoutingKey = !raw || raw.trim().length === 0;
|
|
56
|
+
// If we have Beamable env vars but no routing key, and we're not explicitly in a container,
|
|
57
|
+
// we might be in local dev - try to generate a routing key
|
|
58
|
+
// Only return undefined if we're explicitly in a container
|
|
44
59
|
if (hasBeamableEnvVars && hasNoRoutingKey) {
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
|
|
60
|
+
// Try to generate a routing key for local dev
|
|
61
|
+
// If this fails, we'll throw an error (which is fine for local dev)
|
|
62
|
+
try {
|
|
63
|
+
return getDefaultRoutingKeyForMachine();
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// If we can't generate a routing key, we might be in a container
|
|
67
|
+
// But since we don't have explicit container indicators, assume local dev and throw
|
|
68
|
+
throw new Error(`Unable to determine routing key automatically. Set NAME_PREFIX environment variable. ${error.message}`);
|
|
69
|
+
}
|
|
48
70
|
}
|
|
49
71
|
// Local development - try to get a routing key
|
|
50
72
|
try {
|
package/dist/env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from 'node:fs';\r\nimport { tmpdir } from 'node:os';\r\nimport { join } from 'node:path';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { getDefaultRoutingKeyForMachine } from './routing.js';\r\n\r\nfunction getBoolean(name: string, defaultValue = false): boolean {\r\n const raw = process.env[name];\r\n if (!raw) {\r\n return defaultValue;\r\n }\r\n return ['1', 'true', 'yes', 'on'].includes(raw.toLowerCase());\r\n}\r\n\r\nfunction getNumber(name: string, defaultValue: number): number {\r\n const raw = process.env[name];\r\n if (!raw) {\r\n return defaultValue;\r\n }\r\n const parsed = Number(raw);\r\n return Number.isFinite(parsed) ? parsed : defaultValue;\r\n}\r\n\r\nfunction resolveHealthPort(): number {\r\n // Always default to 6565 if HEALTH_PORT is not explicitly set\r\n // This ensures the health check server starts in deployed environments\r\n // even if container detection fails or HEALTH_PORT env var is missing\r\n const preferred = getNumber('HEALTH_PORT', 6565);\r\n if (preferred > 0) {\r\n return preferred;\r\n }\r\n // Use PID-scoped pseudo random port to avoid collisions on dev machines.\r\n const base = 45000;\r\n const span = 2000;\r\n const candidate = base + (process.pid % span);\r\n return candidate;\r\n}\r\n\r\nfunction resolveRoutingKey(): string | undefined {\r\n const raw = process.env.NAME_PREFIX ?? process.env.ROUTING_KEY;\r\n if (raw && raw.trim().length > 0) {\r\n return raw.trim();\r\n }\r\n\r\n // For deployed services (in containers), routing key should be undefined (None in Scala)\r\n // Beamable sets CID, PID, HOST, SECRET in containers but NOT routing key\r\n // If we have the required Beamable env vars but no routing key, we're in a deployed container\r\n const hasBeamableEnvVars = process.env.CID && process.env.PID && process.env.HOST && process.env.SECRET;\r\n const hasNoRoutingKey = !raw || raw.trim().length === 0;\r\n \r\n if (hasBeamableEnvVars && hasNoRoutingKey) {\r\n // We're in a deployed container - return undefined (becomes None in Scala)\r\n // This allows the gateway to find bindings without routing key filter\r\n return undefined;\r\n }\r\n\r\n // Local development - try to get a routing key\r\n try {\r\n return getDefaultRoutingKeyForMachine();\r\n } catch (error) {\r\n throw new Error(\r\n `Unable to determine routing key automatically. Set NAME_PREFIX environment variable. ${(error as Error).message}`,\r\n );\r\n }\r\n}\r\n\r\nfunction resolveSdkVersionExecution(): string {\r\n return process.env.BEAMABLE_SDK_VERSION_EXECUTION ?? '';\r\n}\r\n\r\nfunction resolveLogLevel(): string {\r\n const candidate = process.env.LOG_LEVEL ?? 'info';\r\n const allowed = new Set(['fatal', 'error', 'warn', 'info', 'debug', 'trace']);\r\n return allowed.has(candidate.toLowerCase()) ? candidate.toLowerCase() : 'info';\r\n}\r\n\r\nfunction resolveWatchToken(): boolean {\r\n const value = process.env.WATCH_TOKEN;\r\n if (value === undefined) {\r\n return false;\r\n }\r\n return getBoolean('WATCH_TOKEN', false);\r\n}\r\n\r\nfunction resolveBeamInstanceCount(): number {\r\n return getNumber('BEAM_INSTANCE_COUNT', 1);\r\n}\r\n\r\nexport function loadEnvironmentConfig(): EnvironmentConfig {\r\n const cid = process.env.CID ?? '';\r\n const pid = process.env.PID ?? '';\r\n const host = process.env.HOST ?? '';\r\n\r\n if (!cid || !pid || !host) {\r\n throw new Error('Missing required Beamable environment variables (CID, PID, HOST).');\r\n }\r\n\r\n const config: EnvironmentConfig = {\r\n cid,\r\n pid,\r\n host,\r\n secret: process.env.SECRET ?? undefined,\r\n refreshToken: process.env.REFRESH_TOKEN ?? undefined,\r\n routingKey: resolveRoutingKey(),\r\n accountId: getNumber('USER_ACCOUNT_ID', 0) || undefined,\r\n accountEmail: process.env.USER_EMAIL ?? undefined,\r\n logLevel: resolveLogLevel(),\r\n healthPort: resolveHealthPort(),\r\n disableCustomInitializationHooks: getBoolean('DISABLE_CUSTOM_INITIALIZATION_HOOKS', false),\r\n watchToken: resolveWatchToken(),\r\n sdkVersionExecution: resolveSdkVersionExecution(),\r\n beamInstanceCount: resolveBeamInstanceCount(),\r\n logTruncateLimit: getNumber('LOG_TRUNCATE_LIMIT', 1000),\r\n };\r\n\r\n return config;\r\n}\r\n\r\nexport function ensureWritableTempDirectory(): string {\r\n const candidate = process.env.LOG_PATH ?? join(tmpdir(), 'beamable-node-runtime');\r\n if (!existsSync(candidate)) {\r\n return candidate;\r\n }\r\n return candidate;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from 'node:fs';\r\nimport { tmpdir } from 'node:os';\r\nimport { join } from 'node:path';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { getDefaultRoutingKeyForMachine } from './routing.js';\r\n\r\nfunction getBoolean(name: string, defaultValue = false): boolean {\r\n const raw = process.env[name];\r\n if (!raw) {\r\n return defaultValue;\r\n }\r\n return ['1', 'true', 'yes', 'on'].includes(raw.toLowerCase());\r\n}\r\n\r\nfunction getNumber(name: string, defaultValue: number): number {\r\n const raw = process.env[name];\r\n if (!raw) {\r\n return defaultValue;\r\n }\r\n const parsed = Number(raw);\r\n return Number.isFinite(parsed) ? parsed : defaultValue;\r\n}\r\n\r\nfunction resolveHealthPort(): number {\r\n // Always default to 6565 if HEALTH_PORT is not explicitly set\r\n // This ensures the health check server starts in deployed environments\r\n // even if container detection fails or HEALTH_PORT env var is missing\r\n const preferred = getNumber('HEALTH_PORT', 6565);\r\n if (preferred > 0) {\r\n return preferred;\r\n }\r\n // Use PID-scoped pseudo random port to avoid collisions on dev machines.\r\n const base = 45000;\r\n const span = 2000;\r\n const candidate = base + (process.pid % span);\r\n return candidate;\r\n}\r\n\r\nfunction resolveRoutingKey(): string | undefined {\r\n const raw = process.env.NAME_PREFIX ?? process.env.ROUTING_KEY;\r\n if (raw && raw.trim().length > 0) {\r\n return raw.trim();\r\n }\r\n\r\n // Check for explicit container indicators first (highest priority)\r\n const isExplicitlyInContainer = \r\n process.env.DOTNET_RUNNING_IN_CONTAINER === 'true' ||\r\n process.env.CONTAINER === 'beamable' ||\r\n !!process.env.ECS_CONTAINER_METADATA_URI ||\r\n !!process.env.KUBERNETES_SERVICE_HOST;\r\n \r\n if (isExplicitlyInContainer) {\r\n // We're definitely in a container - return undefined (becomes None in Scala)\r\n return undefined;\r\n }\r\n\r\n // For deployed services (in containers), routing key should be undefined (None in Scala)\r\n // Beamable sets CID, PID, HOST, SECRET in containers but NOT routing key\r\n // BUT: Local dev also has these env vars from .env file, so we need to be more careful\r\n // If we have the required Beamable env vars but NO routing key AND no explicit container indicators,\r\n // we might be in a deployed container OR local dev without routing key set\r\n // For safety, if we're not explicitly in a container, try to generate a routing key for local dev\r\n const hasBeamableEnvVars = !!(process.env.CID && process.env.PID && process.env.HOST && process.env.SECRET);\r\n const hasNoRoutingKey = !raw || raw.trim().length === 0;\r\n \r\n // If we have Beamable env vars but no routing key, and we're not explicitly in a container,\r\n // we might be in local dev - try to generate a routing key\r\n // Only return undefined if we're explicitly in a container\r\n if (hasBeamableEnvVars && hasNoRoutingKey) {\r\n // Try to generate a routing key for local dev\r\n // If this fails, we'll throw an error (which is fine for local dev)\r\n try {\r\n return getDefaultRoutingKeyForMachine();\r\n } catch (error) {\r\n // If we can't generate a routing key, we might be in a container\r\n // But since we don't have explicit container indicators, assume local dev and throw\r\n throw new Error(\r\n `Unable to determine routing key automatically. Set NAME_PREFIX environment variable. ${(error as Error).message}`,\r\n );\r\n }\r\n }\r\n\r\n // Local development - try to get a routing key\r\n try {\r\n return getDefaultRoutingKeyForMachine();\r\n } catch (error) {\r\n throw new Error(\r\n `Unable to determine routing key automatically. Set NAME_PREFIX environment variable. ${(error as Error).message}`,\r\n );\r\n }\r\n}\r\n\r\nfunction resolveSdkVersionExecution(): string {\r\n return process.env.BEAMABLE_SDK_VERSION_EXECUTION ?? '';\r\n}\r\n\r\nfunction resolveLogLevel(): string {\r\n const candidate = process.env.LOG_LEVEL ?? 'info';\r\n const allowed = new Set(['fatal', 'error', 'warn', 'info', 'debug', 'trace']);\r\n return allowed.has(candidate.toLowerCase()) ? candidate.toLowerCase() : 'info';\r\n}\r\n\r\nfunction resolveWatchToken(): boolean {\r\n const value = process.env.WATCH_TOKEN;\r\n if (value === undefined) {\r\n return false;\r\n }\r\n return getBoolean('WATCH_TOKEN', false);\r\n}\r\n\r\nfunction resolveBeamInstanceCount(): number {\r\n return getNumber('BEAM_INSTANCE_COUNT', 1);\r\n}\r\n\r\nexport function loadEnvironmentConfig(): EnvironmentConfig {\r\n const cid = process.env.CID ?? '';\r\n const pid = process.env.PID ?? '';\r\n const host = process.env.HOST ?? '';\r\n\r\n if (!cid || !pid || !host) {\r\n throw new Error('Missing required Beamable environment variables (CID, PID, HOST).');\r\n }\r\n\r\n const config: EnvironmentConfig = {\r\n cid,\r\n pid,\r\n host,\r\n secret: process.env.SECRET ?? undefined,\r\n refreshToken: process.env.REFRESH_TOKEN ?? undefined,\r\n routingKey: resolveRoutingKey(),\r\n accountId: getNumber('USER_ACCOUNT_ID', 0) || undefined,\r\n accountEmail: process.env.USER_EMAIL ?? undefined,\r\n logLevel: resolveLogLevel(),\r\n healthPort: resolveHealthPort(),\r\n disableCustomInitializationHooks: getBoolean('DISABLE_CUSTOM_INITIALIZATION_HOOKS', false),\r\n watchToken: resolveWatchToken(),\r\n sdkVersionExecution: resolveSdkVersionExecution(),\r\n beamInstanceCount: resolveBeamInstanceCount(),\r\n logTruncateLimit: getNumber('LOG_TRUNCATE_LIMIT', 1000),\r\n };\r\n\r\n return config;\r\n}\r\n\r\nexport function ensureWritableTempDirectory(): string {\r\n const candidate = process.env.LOG_PATH ?? join(tmpdir(), 'beamable-node-runtime');\r\n if (!existsSync(candidate)) {\r\n return candidate;\r\n }\r\n return candidate;\r\n}\r\n"]}
|
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAa,EAAe,KAAK,MAAM,EAAsB,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAa,EAAe,KAAK,MAAM,EAAsB,MAAM,MAAM,CAAC;AAI1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA8CpD,UAAU,oBAAoB;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAwHD,wBAAgB,YAAY,CAAC,GAAG,EAAE,iBAAiB,EAAE,OAAO,GAAE,oBAAyB,GAAG,MAAM,CAgE/F"}
|
package/dist/logger.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import pino, { destination } from 'pino';
|
|
2
2
|
import { Transform } from 'node:stream';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
3
4
|
import { ensureWritableTempDirectory } from './env.js';
|
|
5
|
+
// Create a require function for loading CommonJS modules in ESM
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
4
7
|
/**
|
|
5
8
|
* Detects if we're running in a container (deployed environment).
|
|
6
9
|
* This is used to determine log format: pretty for local dev, JSON for containers.
|
|
@@ -14,7 +17,7 @@ import { ensureWritableTempDirectory } from './env.js';
|
|
|
14
17
|
* - Has routing key (local dev always has a routing key)
|
|
15
18
|
* - Running via tsx/node directly (not in Docker)
|
|
16
19
|
*/
|
|
17
|
-
function isRunningInContainer() {
|
|
20
|
+
function isRunningInContainer(env) {
|
|
18
21
|
// Explicit container indicators (highest priority)
|
|
19
22
|
if (process.env.DOTNET_RUNNING_IN_CONTAINER === 'true' ||
|
|
20
23
|
process.env.CONTAINER === 'beamable' ||
|
|
@@ -22,9 +25,10 @@ function isRunningInContainer() {
|
|
|
22
25
|
!!process.env.KUBERNETES_SERVICE_HOST) {
|
|
23
26
|
return true;
|
|
24
27
|
}
|
|
25
|
-
// If we have a routing key, we're definitely running locally
|
|
26
|
-
// Local dev always
|
|
27
|
-
|
|
28
|
+
// If we have a routing key (from env object or process.env), we're definitely running locally
|
|
29
|
+
// Local dev always has a routing key (either set explicitly or auto-generated)
|
|
30
|
+
const hasRoutingKey = env?.routingKey || process.env.NAME_PREFIX || process.env.ROUTING_KEY;
|
|
31
|
+
if (hasRoutingKey) {
|
|
28
32
|
return false; // Local development
|
|
29
33
|
}
|
|
30
34
|
// If we have Beamable env vars but NO routing key, we're in a deployed container
|
|
@@ -151,7 +155,7 @@ function createBeamableLogFormatter() {
|
|
|
151
155
|
}
|
|
152
156
|
export function createLogger(env, options = {}) {
|
|
153
157
|
const configuredDestination = options.destinationPath ?? process.env.LOG_PATH;
|
|
154
|
-
const inContainer = isRunningInContainer();
|
|
158
|
+
const inContainer = isRunningInContainer(env);
|
|
155
159
|
const pinoOptions = {
|
|
156
160
|
name: options.name ?? 'beamable-node-runtime',
|
|
157
161
|
level: env.logLevel,
|
|
@@ -182,7 +186,7 @@ export function createLogger(env, options = {}) {
|
|
|
182
186
|
// Try to use pino-pretty if available (optional dependency)
|
|
183
187
|
// If not available, fall back to default Pino JSON output
|
|
184
188
|
try {
|
|
185
|
-
// Check if pino-pretty is available
|
|
189
|
+
// Check if pino-pretty is available (using createRequire for ESM compatibility)
|
|
186
190
|
const pinoPretty = require('pino-pretty');
|
|
187
191
|
// Create a pretty stream with formatting options
|
|
188
192
|
const prettyStream = pinoPretty({
|
|
@@ -194,8 +198,9 @@ export function createLogger(env, options = {}) {
|
|
|
194
198
|
// Use pino with the pretty stream
|
|
195
199
|
return pino(pinoOptions, prettyStream);
|
|
196
200
|
}
|
|
197
|
-
catch {
|
|
201
|
+
catch (error) {
|
|
198
202
|
// pino-pretty not available, use default Pino output (JSON but readable)
|
|
203
|
+
// This is expected if pino-pretty isn't installed, so we silently fall back
|
|
199
204
|
return pino(pinoOptions, process.stdout);
|
|
200
205
|
}
|
|
201
206
|
}
|
package/dist/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,EAAE,EAAE,WAAW,EAAmC,MAAM,MAAM,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AAGvD;;;;;;;;;;;;GAYG;AACH,SAAS,oBAAoB;IAC3B,mDAAmD;IACnD,IACE,OAAO,CAAC,GAAG,CAAC,2BAA2B,KAAK,MAAM;QAClD,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,UAAU;QACpC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B;QACxC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,EACrC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,2FAA2F;IAC3F,mDAAmD;IACnD,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QACvD,OAAO,KAAK,CAAC,CAAC,oBAAoB;IACpC,CAAC;IAED,iFAAiF;IACjF,MAAM,kBAAkB,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5G,IAAI,kBAAkB,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,CAAC,uDAAuD;IACtE,CAAC;IAED,oCAAoC;IACpC,OAAO,KAAK,CAAC;AACf,CAAC;AAOD;;;;GAIG;AACH,SAAS,2BAA2B,CAAC,KAAa;IAChD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,EAAE,EAAE,QAAQ;YACf,OAAO,OAAO,CAAC;QACjB,KAAK,EAAE,EAAE,QAAQ;YACf,OAAO,OAAO,CAAC;QACjB,KAAK,EAAE,EAAE,OAAO;YACd,OAAO,MAAM,CAAC;QAChB,KAAK,EAAE,EAAE,OAAO;YACd,OAAO,SAAS,CAAC;QACnB,KAAK,EAAE,EAAE,QAAQ;YACf,OAAO,OAAO,CAAC;QACjB,KAAK,EAAE,EAAE,QAAQ;YACf,OAAO,OAAO,CAAC;QACjB;YACE,OAAO,MAAM,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,0BAA0B;IACjC,OAAO,IAAI,SAAS,CAAC;QACnB,UAAU,EAAE,KAAK,EAAE,mCAAmC;QACtD,SAAS,CAAC,KAAa,EAAE,SAAS,EAAE,QAAQ;YAC1C,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAC9B,mBAAmB;gBACnB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;oBACjB,QAAQ,EAAE,CAAC;oBACX,OAAO;gBACT,CAAC;gBAED,6BAA6B;gBAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAEjC,+EAA+E;gBAC/E,0CAA0C;gBAC1C,IAAI,SAAiB,CAAC;gBACtB,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACrC,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;gBAC3B,CAAC;qBAAM,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC5C,SAAS,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;gBACnD,CAAC;qBAAM,CAAC;oBACN,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;gBACvC,CAAC;gBAED,mCAAmC;gBACnC,MAAM,KAAK,GAAG,2BAA2B,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAEzD,6DAA6D;gBAC7D,8CAA8C;gBAC9C,MAAM,YAAY,GAAa,EAAE,CAAC;gBAClC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;oBAChB,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACjC,CAAC;gBAED,uCAAuC;gBACvC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;oBAChB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;oBACxB,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC;oBACjD,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACnD,YAAY,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,QAAQ,EAAE,CAAC,CAAC;gBAC5C,CAAC;gBAED,gCAAgC;gBAChC,MAAM,WAAW,GAA4B;oBAC3C,GAAG,EAAE,SAAS;oBACd,GAAG,EAAE,KAAK;oBACV,GAAG,EAAE,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY;iBACrE,CAAC;gBAEF,yDAAyD;gBACzD,uEAAuE;gBACvE,MAAM,aAAa,GAA4B,EAAE,CAAC;gBAClD,IAAI,OAAO,CAAC,GAAG;oBAAE,aAAa,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;gBACjD,IAAI,OAAO,CAAC,GAAG;oBAAE,aAAa,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;gBACjD,IAAI,OAAO,CAAC,UAAU;oBAAE,aAAa,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;gBACtE,IAAI,OAAO,CAAC,OAAO;oBAAE,aAAa,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;gBAC7D,IAAI,OAAO,CAAC,SAAS;oBAAE,aAAa,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;gBAEnE,4DAA4D;gBAC5D,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;gBACtK,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;oBACnD,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;wBAC/E,aAAa,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;oBAC7B,CAAC;gBACH,CAAC;gBAED,uDAAuD;gBACvD,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1C,WAAW,CAAC,GAAG,GAAG,aAAa,CAAC;gBAClC,CAAC;gBAED,gEAAgE;gBAChE,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;gBAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;YAC9C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,gDAAgD;gBAChD,MAAM,WAAW,GAAG;oBAClB,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBAC7B,GAAG,EAAE,OAAO;oBACZ,GAAG,EAAE,8BAA8B,KAAK,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;iBACxE,CAAC;gBACF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAsB,EAAE,UAAgC,EAAE;IACrF,MAAM,qBAAqB,GAAG,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC9E,MAAM,WAAW,GAAG,oBAAoB,EAAE,CAAC;IAE3C,MAAM,WAAW,GAAkB;QACjC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,uBAAuB;QAC7C,KAAK,EAAE,GAAG,CAAC,QAAQ;QACnB,IAAI,EAAE;YACJ,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,IAAI;YAClC,mBAAmB,EAAE,GAAG,CAAC,mBAAmB;SAC7C;QACD,MAAM,EAAE;YACN,KAAK,EAAE,CAAC,QAAQ,EAAE,cAAc,CAAC;YACjC,MAAM,EAAE,KAAK;SACd;QACD,uEAAuE;QACvE,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,OAAO;KACzC,CAAC;IAEF,yFAAyF;IACzF,+EAA+E;IAC/E,IAAI,CAAC,qBAAqB,IAAI,qBAAqB,KAAK,GAAG,IAAI,qBAAqB,KAAK,QAAQ,IAAI,qBAAqB,KAAK,SAAS,EAAE,CAAC;QACzI,IAAI,WAAW,EAAE,CAAC;YAChB,oEAAoE;YACpE,MAAM,iBAAiB,GAAG,0BAA0B,EAAE,CAAC;YACvD,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACvC,OAAO,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,wEAAwE;YACxE,4DAA4D;YAC5D,0DAA0D;YAC1D,IAAI,CAAC;gBACH,oCAAoC;gBACpC,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;gBAC1C,iDAAiD;gBACjD,MAAM,YAAY,GAAG,UAAU,CAAC;oBAC9B,QAAQ,EAAE,IAAI;oBACd,aAAa,EAAE,YAAY;oBAC3B,MAAM,EAAE,cAAc;oBACtB,UAAU,EAAE,KAAK;iBAClB,CAAC,CAAC;gBACH,kCAAkC;gBAClC,OAAO,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;YACzC,CAAC;YAAC,MAAM,CAAC;gBACP,yEAAyE;gBACzE,OAAO,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;IACH,CAAC;IAED,mFAAmF;IACnF,MAAM,mBAAmB,GAAG,qBAAqB,KAAK,MAAM,CAAC,CAAC,CAAC,2BAA2B,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC;IACrH,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,iBAAiB,GAAG,0BAA0B,EAAE,CAAC;QACvD,MAAM,UAAU,GAAG,WAAW,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtG,iBAAiB,CAAC,IAAI,CAAC,UAA8C,CAAC,CAAC;QACvE,OAAO,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;IAC9C,CAAC;SAAM,CAAC;QACN,MAAM,UAAU,GAAG,WAAW,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtG,OAAO,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACvC,CAAC;AACH,CAAC","sourcesContent":["import pino, { destination, type Logger, type LoggerOptions } from 'pino';\r\nimport { Transform } from 'node:stream';\r\nimport { ensureWritableTempDirectory } from './env.js';\r\nimport type { EnvironmentConfig } from './types.js';\r\n\r\n/**\r\n * Detects if we're running in a container (deployed environment).\r\n * This is used to determine log format: pretty for local dev, JSON for containers.\r\n * \r\n * Key indicators we're in a container:\r\n * - Has CID, PID, HOST, SECRET (Beamable env vars)\r\n * - NO routing key (deployed services don't use routing keys)\r\n * - OR explicit container indicators (DOTNET_RUNNING_IN_CONTAINER, ECS, K8s)\r\n * \r\n * Key indicators we're running locally:\r\n * - Has routing key (local dev always has a routing key)\r\n * - Running via tsx/node directly (not in Docker)\r\n */\r\nfunction isRunningInContainer(): boolean {\r\n // Explicit container indicators (highest priority)\r\n if (\r\n process.env.DOTNET_RUNNING_IN_CONTAINER === 'true' ||\r\n process.env.CONTAINER === 'beamable' ||\r\n !!process.env.ECS_CONTAINER_METADATA_URI ||\r\n !!process.env.KUBERNETES_SERVICE_HOST\r\n ) {\r\n return true;\r\n }\r\n \r\n // If we have a routing key, we're definitely running locally (not in a deployed container)\r\n // Local dev always sets NAME_PREFIX or ROUTING_KEY\r\n if (process.env.NAME_PREFIX || process.env.ROUTING_KEY) {\r\n return false; // Local development\r\n }\r\n \r\n // If we have Beamable env vars but NO routing key, we're in a deployed container\r\n const hasBeamableEnvVars = !!(process.env.CID && process.env.PID && process.env.HOST && process.env.SECRET);\r\n if (hasBeamableEnvVars) {\r\n return true; // Deployed container (has env vars but no routing key)\r\n }\r\n \r\n // Default: assume local development\r\n return false;\r\n}\r\n\r\ninterface LoggerFactoryOptions {\r\n name?: string;\r\n destinationPath?: string;\r\n}\r\n\r\n/**\r\n * Maps Pino log levels to Beamable log levels\r\n * Pino levels: 10=trace, 20=debug, 30=info, 40=warn, 50=error, 60=fatal\r\n * Beamable levels: Debug, Info, Warning, Error, Fatal\r\n */\r\nfunction mapPinoLevelToBeamableLevel(level: number): string {\r\n switch (level) {\r\n case 10: // trace\r\n return 'Debug';\r\n case 20: // debug\r\n return 'Debug';\r\n case 30: // info\r\n return 'Info';\r\n case 40: // warn\r\n return 'Warning';\r\n case 50: // error\r\n return 'Error';\r\n case 60: // fatal\r\n return 'Fatal';\r\n default:\r\n return 'Info';\r\n }\r\n}\r\n\r\n/**\r\n * Creates a transform stream that converts Pino JSON logs to Beamable's expected format.\r\n * Beamable expects logs with __t (timestamp), __l (level), and __m (message) fields.\r\n * Pino writes JSON strings (one per line) to the stream.\r\n */\r\nfunction createBeamableLogFormatter(): Transform {\r\n return new Transform({\r\n objectMode: false, // Pino writes strings, not objects\r\n transform(chunk: Buffer, _encoding, callback) {\r\n try {\r\n const line = chunk.toString();\r\n // Skip empty lines\r\n if (!line.trim()) {\r\n callback();\r\n return;\r\n }\r\n \r\n // Parse Pino's JSON log line\r\n const pinoLog = JSON.parse(line);\r\n \r\n // Extract timestamp - Pino uses 'time' field (ISO 8601 string or milliseconds)\r\n // Convert to ISO 8601 string for Beamable\r\n let timestamp: string;\r\n if (typeof pinoLog.time === 'string') {\r\n timestamp = pinoLog.time;\r\n } else if (typeof pinoLog.time === 'number') {\r\n timestamp = new Date(pinoLog.time).toISOString();\r\n } else {\r\n timestamp = new Date().toISOString();\r\n }\r\n \r\n // Map Pino level to Beamable level\r\n const level = mapPinoLevelToBeamableLevel(pinoLog.level);\r\n \r\n // Build the message - combine msg with any additional fields\r\n // Pino's 'msg' field contains the log message\r\n const messageParts: string[] = [];\r\n if (pinoLog.msg) {\r\n messageParts.push(pinoLog.msg);\r\n }\r\n \r\n // Include error information if present\r\n if (pinoLog.err) {\r\n const err = pinoLog.err;\r\n const errMsg = err.message || err.msg || 'Error';\r\n const errStack = err.stack ? `\\n${err.stack}` : '';\r\n messageParts.push(`${errMsg}${errStack}`);\r\n }\r\n \r\n // Build the Beamable log format\r\n const beamableLog: Record<string, unknown> = {\r\n __t: timestamp,\r\n __l: level,\r\n __m: messageParts.length > 0 ? messageParts.join(' ') : 'No message',\r\n };\r\n \r\n // Include additional context fields that might be useful\r\n // These are included in the message object but not as top-level fields\r\n const contextFields: Record<string, unknown> = {};\r\n if (pinoLog.cid) contextFields.cid = pinoLog.cid;\r\n if (pinoLog.pid) contextFields.pid = pinoLog.pid;\r\n if (pinoLog.routingKey) contextFields.routingKey = pinoLog.routingKey;\r\n if (pinoLog.service) contextFields.service = pinoLog.service;\r\n if (pinoLog.component) contextFields.component = pinoLog.component;\r\n \r\n // Include any other fields that aren't standard Pino fields\r\n const standardPinoFields = ['level', 'time', 'pid', 'hostname', 'name', 'msg', 'err', 'v', 'cid', 'pid', 'routingKey', 'sdkVersionExecution', 'service', 'component'];\r\n for (const [key, value] of Object.entries(pinoLog)) {\r\n if (!standardPinoFields.includes(key) && value !== undefined && value !== null) {\r\n contextFields[key] = value;\r\n }\r\n }\r\n \r\n // If there are context fields, include them in the log\r\n if (Object.keys(contextFields).length > 0) {\r\n beamableLog.__c = contextFields;\r\n }\r\n \r\n // Output as a single-line JSON string (required for CloudWatch)\r\n const output = JSON.stringify(beamableLog) + '\\n';\r\n callback(null, Buffer.from(output, 'utf8'));\r\n } catch (error) {\r\n // If parsing fails, output a fallback log entry\r\n const fallbackLog = {\r\n __t: new Date().toISOString(),\r\n __l: 'Error',\r\n __m: `Failed to parse log entry: ${chunk.toString().substring(0, 200)}`,\r\n };\r\n callback(null, Buffer.from(JSON.stringify(fallbackLog) + '\\n', 'utf8'));\r\n }\r\n },\r\n });\r\n}\r\n\r\nexport function createLogger(env: EnvironmentConfig, options: LoggerFactoryOptions = {}): Logger {\r\n const configuredDestination = options.destinationPath ?? process.env.LOG_PATH;\r\n const inContainer = isRunningInContainer();\r\n\r\n const pinoOptions: LoggerOptions = {\r\n name: options.name ?? 'beamable-node-runtime',\r\n level: env.logLevel,\r\n base: {\r\n cid: env.cid,\r\n pid: env.pid,\r\n routingKey: env.routingKey ?? null,\r\n sdkVersionExecution: env.sdkVersionExecution,\r\n },\r\n redact: {\r\n paths: ['secret', 'refreshToken'],\r\n censor: '***',\r\n },\r\n // Use timestamp in milliseconds (Pino default) for accurate conversion\r\n timestamp: pino.stdTimeFunctions.isoTime,\r\n };\r\n\r\n // For deployed services, always log to stdout so container orchestrator can collect logs\r\n // For local development, log to stdout unless a specific file path is provided\r\n if (!configuredDestination || configuredDestination === '-' || configuredDestination === 'stdout' || configuredDestination === 'console') {\r\n if (inContainer) {\r\n // In containers: Use Beamable JSON format for CloudWatch collection\r\n const beamableFormatter = createBeamableLogFormatter();\r\n beamableFormatter.pipe(process.stdout);\r\n return pino(pinoOptions, beamableFormatter);\r\n } else {\r\n // Local development: Use Pino's pretty printing for human-readable logs\r\n // Try to use pino-pretty if available (optional dependency)\r\n // If not available, fall back to default Pino JSON output\r\n try {\r\n // Check if pino-pretty is available\r\n const pinoPretty = require('pino-pretty');\r\n // Create a pretty stream with formatting options\r\n const prettyStream = pinoPretty({\r\n colorize: true,\r\n translateTime: 'HH:MM:ss.l',\r\n ignore: 'pid,hostname',\r\n singleLine: false,\r\n });\r\n // Use pino with the pretty stream\r\n return pino(pinoOptions, prettyStream);\r\n } catch {\r\n // pino-pretty not available, use default Pino output (JSON but readable)\r\n return pino(pinoOptions, process.stdout);\r\n }\r\n }\r\n }\r\n\r\n // For file logging: Use Beamable format in containers, default Pino format locally\r\n const resolvedDestination = configuredDestination === 'temp' ? ensureWritableTempDirectory() : configuredDestination;\r\n if (inContainer) {\r\n const beamableFormatter = createBeamableLogFormatter();\r\n const fileStream = destination({ dest: resolvedDestination, mkdir: true, append: true, sync: false });\r\n beamableFormatter.pipe(fileStream as unknown as NodeJS.WritableStream);\r\n return pino(pinoOptions, beamableFormatter);\r\n } else {\r\n const fileStream = destination({ dest: resolvedDestination, mkdir: true, append: true, sync: false });\r\n return pino(pinoOptions, fileStream);\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,EAAE,EAAE,WAAW,EAAmC,MAAM,MAAM,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AAGvD,gEAAgE;AAChE,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C;;;;;;;;;;;;GAYG;AACH,SAAS,oBAAoB,CAAC,GAAuB;IACnD,mDAAmD;IACnD,IACE,OAAO,CAAC,GAAG,CAAC,2BAA2B,KAAK,MAAM;QAClD,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,UAAU;QACpC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B;QACxC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,EACrC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8FAA8F;IAC9F,+EAA+E;IAC/E,MAAM,aAAa,GAAG,GAAG,EAAE,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IAC5F,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,KAAK,CAAC,CAAC,oBAAoB;IACpC,CAAC;IAED,iFAAiF;IACjF,MAAM,kBAAkB,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5G,IAAI,kBAAkB,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,CAAC,uDAAuD;IACtE,CAAC;IAED,oCAAoC;IACpC,OAAO,KAAK,CAAC;AACf,CAAC;AAOD;;;;GAIG;AACH,SAAS,2BAA2B,CAAC,KAAa;IAChD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,EAAE,EAAE,QAAQ;YACf,OAAO,OAAO,CAAC;QACjB,KAAK,EAAE,EAAE,QAAQ;YACf,OAAO,OAAO,CAAC;QACjB,KAAK,EAAE,EAAE,OAAO;YACd,OAAO,MAAM,CAAC;QAChB,KAAK,EAAE,EAAE,OAAO;YACd,OAAO,SAAS,CAAC;QACnB,KAAK,EAAE,EAAE,QAAQ;YACf,OAAO,OAAO,CAAC;QACjB,KAAK,EAAE,EAAE,QAAQ;YACf,OAAO,OAAO,CAAC;QACjB;YACE,OAAO,MAAM,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,0BAA0B;IACjC,OAAO,IAAI,SAAS,CAAC;QACnB,UAAU,EAAE,KAAK,EAAE,mCAAmC;QACtD,SAAS,CAAC,KAAa,EAAE,SAAS,EAAE,QAAQ;YAC1C,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAC9B,mBAAmB;gBACnB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;oBACjB,QAAQ,EAAE,CAAC;oBACX,OAAO;gBACT,CAAC;gBAED,6BAA6B;gBAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAEjC,+EAA+E;gBAC/E,0CAA0C;gBAC1C,IAAI,SAAiB,CAAC;gBACtB,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACrC,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;gBAC3B,CAAC;qBAAM,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC5C,SAAS,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;gBACnD,CAAC;qBAAM,CAAC;oBACN,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;gBACvC,CAAC;gBAED,mCAAmC;gBACnC,MAAM,KAAK,GAAG,2BAA2B,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAEzD,6DAA6D;gBAC7D,8CAA8C;gBAC9C,MAAM,YAAY,GAAa,EAAE,CAAC;gBAClC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;oBAChB,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACjC,CAAC;gBAED,uCAAuC;gBACvC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;oBAChB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;oBACxB,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC;oBACjD,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACnD,YAAY,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,QAAQ,EAAE,CAAC,CAAC;gBAC5C,CAAC;gBAED,gCAAgC;gBAChC,MAAM,WAAW,GAA4B;oBAC3C,GAAG,EAAE,SAAS;oBACd,GAAG,EAAE,KAAK;oBACV,GAAG,EAAE,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY;iBACrE,CAAC;gBAEF,yDAAyD;gBACzD,uEAAuE;gBACvE,MAAM,aAAa,GAA4B,EAAE,CAAC;gBAClD,IAAI,OAAO,CAAC,GAAG;oBAAE,aAAa,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;gBACjD,IAAI,OAAO,CAAC,GAAG;oBAAE,aAAa,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;gBACjD,IAAI,OAAO,CAAC,UAAU;oBAAE,aAAa,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;gBACtE,IAAI,OAAO,CAAC,OAAO;oBAAE,aAAa,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;gBAC7D,IAAI,OAAO,CAAC,SAAS;oBAAE,aAAa,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;gBAEnE,4DAA4D;gBAC5D,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;gBACtK,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;oBACnD,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;wBAC/E,aAAa,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;oBAC7B,CAAC;gBACH,CAAC;gBAED,uDAAuD;gBACvD,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1C,WAAW,CAAC,GAAG,GAAG,aAAa,CAAC;gBAClC,CAAC;gBAED,gEAAgE;gBAChE,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;gBAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;YAC9C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,gDAAgD;gBAChD,MAAM,WAAW,GAAG;oBAClB,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBAC7B,GAAG,EAAE,OAAO;oBACZ,GAAG,EAAE,8BAA8B,KAAK,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;iBACxE,CAAC;gBACF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAsB,EAAE,UAAgC,EAAE;IACrF,MAAM,qBAAqB,GAAG,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC9E,MAAM,WAAW,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAE9C,MAAM,WAAW,GAAkB;QACjC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,uBAAuB;QAC7C,KAAK,EAAE,GAAG,CAAC,QAAQ;QACnB,IAAI,EAAE;YACJ,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,IAAI;YAClC,mBAAmB,EAAE,GAAG,CAAC,mBAAmB;SAC7C;QACD,MAAM,EAAE;YACN,KAAK,EAAE,CAAC,QAAQ,EAAE,cAAc,CAAC;YACjC,MAAM,EAAE,KAAK;SACd;QACD,uEAAuE;QACvE,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,OAAO;KACzC,CAAC;IAEF,yFAAyF;IACzF,+EAA+E;IAC/E,IAAI,CAAC,qBAAqB,IAAI,qBAAqB,KAAK,GAAG,IAAI,qBAAqB,KAAK,QAAQ,IAAI,qBAAqB,KAAK,SAAS,EAAE,CAAC;QACzI,IAAI,WAAW,EAAE,CAAC;YAChB,oEAAoE;YACpE,MAAM,iBAAiB,GAAG,0BAA0B,EAAE,CAAC;YACvD,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACvC,OAAO,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,wEAAwE;YACxE,4DAA4D;YAC5D,0DAA0D;YAC1D,IAAI,CAAC;gBACH,gFAAgF;gBAChF,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;gBAC1C,iDAAiD;gBACjD,MAAM,YAAY,GAAG,UAAU,CAAC;oBAC9B,QAAQ,EAAE,IAAI;oBACd,aAAa,EAAE,YAAY;oBAC3B,MAAM,EAAE,cAAc;oBACtB,UAAU,EAAE,KAAK;iBAClB,CAAC,CAAC;gBACH,kCAAkC;gBAClC,OAAO,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;YACzC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,yEAAyE;gBACzE,4EAA4E;gBAC5E,OAAO,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;IACH,CAAC;IAED,mFAAmF;IACnF,MAAM,mBAAmB,GAAG,qBAAqB,KAAK,MAAM,CAAC,CAAC,CAAC,2BAA2B,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC;IACrH,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,iBAAiB,GAAG,0BAA0B,EAAE,CAAC;QACvD,MAAM,UAAU,GAAG,WAAW,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtG,iBAAiB,CAAC,IAAI,CAAC,UAA8C,CAAC,CAAC;QACvE,OAAO,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;IAC9C,CAAC;SAAM,CAAC;QACN,MAAM,UAAU,GAAG,WAAW,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtG,OAAO,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACvC,CAAC;AACH,CAAC","sourcesContent":["import pino, { destination, type Logger, type LoggerOptions } from 'pino';\r\nimport { Transform } from 'node:stream';\r\nimport { createRequire } from 'node:module';\r\nimport { ensureWritableTempDirectory } from './env.js';\r\nimport type { EnvironmentConfig } from './types.js';\r\n\r\n// Create a require function for loading CommonJS modules in ESM\r\nconst require = createRequire(import.meta.url);\r\n\r\n/**\r\n * Detects if we're running in a container (deployed environment).\r\n * This is used to determine log format: pretty for local dev, JSON for containers.\r\n * \r\n * Key indicators we're in a container:\r\n * - Has CID, PID, HOST, SECRET (Beamable env vars)\r\n * - NO routing key (deployed services don't use routing keys)\r\n * - OR explicit container indicators (DOTNET_RUNNING_IN_CONTAINER, ECS, K8s)\r\n * \r\n * Key indicators we're running locally:\r\n * - Has routing key (local dev always has a routing key)\r\n * - Running via tsx/node directly (not in Docker)\r\n */\r\nfunction isRunningInContainer(env?: EnvironmentConfig): boolean {\r\n // Explicit container indicators (highest priority)\r\n if (\r\n process.env.DOTNET_RUNNING_IN_CONTAINER === 'true' ||\r\n process.env.CONTAINER === 'beamable' ||\r\n !!process.env.ECS_CONTAINER_METADATA_URI ||\r\n !!process.env.KUBERNETES_SERVICE_HOST\r\n ) {\r\n return true;\r\n }\r\n \r\n // If we have a routing key (from env object or process.env), we're definitely running locally\r\n // Local dev always has a routing key (either set explicitly or auto-generated)\r\n const hasRoutingKey = env?.routingKey || process.env.NAME_PREFIX || process.env.ROUTING_KEY;\r\n if (hasRoutingKey) {\r\n return false; // Local development\r\n }\r\n \r\n // If we have Beamable env vars but NO routing key, we're in a deployed container\r\n const hasBeamableEnvVars = !!(process.env.CID && process.env.PID && process.env.HOST && process.env.SECRET);\r\n if (hasBeamableEnvVars) {\r\n return true; // Deployed container (has env vars but no routing key)\r\n }\r\n \r\n // Default: assume local development\r\n return false;\r\n}\r\n\r\ninterface LoggerFactoryOptions {\r\n name?: string;\r\n destinationPath?: string;\r\n}\r\n\r\n/**\r\n * Maps Pino log levels to Beamable log levels\r\n * Pino levels: 10=trace, 20=debug, 30=info, 40=warn, 50=error, 60=fatal\r\n * Beamable levels: Debug, Info, Warning, Error, Fatal\r\n */\r\nfunction mapPinoLevelToBeamableLevel(level: number): string {\r\n switch (level) {\r\n case 10: // trace\r\n return 'Debug';\r\n case 20: // debug\r\n return 'Debug';\r\n case 30: // info\r\n return 'Info';\r\n case 40: // warn\r\n return 'Warning';\r\n case 50: // error\r\n return 'Error';\r\n case 60: // fatal\r\n return 'Fatal';\r\n default:\r\n return 'Info';\r\n }\r\n}\r\n\r\n/**\r\n * Creates a transform stream that converts Pino JSON logs to Beamable's expected format.\r\n * Beamable expects logs with __t (timestamp), __l (level), and __m (message) fields.\r\n * Pino writes JSON strings (one per line) to the stream.\r\n */\r\nfunction createBeamableLogFormatter(): Transform {\r\n return new Transform({\r\n objectMode: false, // Pino writes strings, not objects\r\n transform(chunk: Buffer, _encoding, callback) {\r\n try {\r\n const line = chunk.toString();\r\n // Skip empty lines\r\n if (!line.trim()) {\r\n callback();\r\n return;\r\n }\r\n \r\n // Parse Pino's JSON log line\r\n const pinoLog = JSON.parse(line);\r\n \r\n // Extract timestamp - Pino uses 'time' field (ISO 8601 string or milliseconds)\r\n // Convert to ISO 8601 string for Beamable\r\n let timestamp: string;\r\n if (typeof pinoLog.time === 'string') {\r\n timestamp = pinoLog.time;\r\n } else if (typeof pinoLog.time === 'number') {\r\n timestamp = new Date(pinoLog.time).toISOString();\r\n } else {\r\n timestamp = new Date().toISOString();\r\n }\r\n \r\n // Map Pino level to Beamable level\r\n const level = mapPinoLevelToBeamableLevel(pinoLog.level);\r\n \r\n // Build the message - combine msg with any additional fields\r\n // Pino's 'msg' field contains the log message\r\n const messageParts: string[] = [];\r\n if (pinoLog.msg) {\r\n messageParts.push(pinoLog.msg);\r\n }\r\n \r\n // Include error information if present\r\n if (pinoLog.err) {\r\n const err = pinoLog.err;\r\n const errMsg = err.message || err.msg || 'Error';\r\n const errStack = err.stack ? `\\n${err.stack}` : '';\r\n messageParts.push(`${errMsg}${errStack}`);\r\n }\r\n \r\n // Build the Beamable log format\r\n const beamableLog: Record<string, unknown> = {\r\n __t: timestamp,\r\n __l: level,\r\n __m: messageParts.length > 0 ? messageParts.join(' ') : 'No message',\r\n };\r\n \r\n // Include additional context fields that might be useful\r\n // These are included in the message object but not as top-level fields\r\n const contextFields: Record<string, unknown> = {};\r\n if (pinoLog.cid) contextFields.cid = pinoLog.cid;\r\n if (pinoLog.pid) contextFields.pid = pinoLog.pid;\r\n if (pinoLog.routingKey) contextFields.routingKey = pinoLog.routingKey;\r\n if (pinoLog.service) contextFields.service = pinoLog.service;\r\n if (pinoLog.component) contextFields.component = pinoLog.component;\r\n \r\n // Include any other fields that aren't standard Pino fields\r\n const standardPinoFields = ['level', 'time', 'pid', 'hostname', 'name', 'msg', 'err', 'v', 'cid', 'pid', 'routingKey', 'sdkVersionExecution', 'service', 'component'];\r\n for (const [key, value] of Object.entries(pinoLog)) {\r\n if (!standardPinoFields.includes(key) && value !== undefined && value !== null) {\r\n contextFields[key] = value;\r\n }\r\n }\r\n \r\n // If there are context fields, include them in the log\r\n if (Object.keys(contextFields).length > 0) {\r\n beamableLog.__c = contextFields;\r\n }\r\n \r\n // Output as a single-line JSON string (required for CloudWatch)\r\n const output = JSON.stringify(beamableLog) + '\\n';\r\n callback(null, Buffer.from(output, 'utf8'));\r\n } catch (error) {\r\n // If parsing fails, output a fallback log entry\r\n const fallbackLog = {\r\n __t: new Date().toISOString(),\r\n __l: 'Error',\r\n __m: `Failed to parse log entry: ${chunk.toString().substring(0, 200)}`,\r\n };\r\n callback(null, Buffer.from(JSON.stringify(fallbackLog) + '\\n', 'utf8'));\r\n }\r\n },\r\n });\r\n}\r\n\r\nexport function createLogger(env: EnvironmentConfig, options: LoggerFactoryOptions = {}): Logger {\r\n const configuredDestination = options.destinationPath ?? process.env.LOG_PATH;\r\n const inContainer = isRunningInContainer(env);\r\n\r\n const pinoOptions: LoggerOptions = {\r\n name: options.name ?? 'beamable-node-runtime',\r\n level: env.logLevel,\r\n base: {\r\n cid: env.cid,\r\n pid: env.pid,\r\n routingKey: env.routingKey ?? null,\r\n sdkVersionExecution: env.sdkVersionExecution,\r\n },\r\n redact: {\r\n paths: ['secret', 'refreshToken'],\r\n censor: '***',\r\n },\r\n // Use timestamp in milliseconds (Pino default) for accurate conversion\r\n timestamp: pino.stdTimeFunctions.isoTime,\r\n };\r\n\r\n // For deployed services, always log to stdout so container orchestrator can collect logs\r\n // For local development, log to stdout unless a specific file path is provided\r\n if (!configuredDestination || configuredDestination === '-' || configuredDestination === 'stdout' || configuredDestination === 'console') {\r\n if (inContainer) {\r\n // In containers: Use Beamable JSON format for CloudWatch collection\r\n const beamableFormatter = createBeamableLogFormatter();\r\n beamableFormatter.pipe(process.stdout);\r\n return pino(pinoOptions, beamableFormatter);\r\n } else {\r\n // Local development: Use Pino's pretty printing for human-readable logs\r\n // Try to use pino-pretty if available (optional dependency)\r\n // If not available, fall back to default Pino JSON output\r\n try {\r\n // Check if pino-pretty is available (using createRequire for ESM compatibility)\r\n const pinoPretty = require('pino-pretty');\r\n // Create a pretty stream with formatting options\r\n const prettyStream = pinoPretty({\r\n colorize: true,\r\n translateTime: 'HH:MM:ss.l',\r\n ignore: 'pid,hostname',\r\n singleLine: false,\r\n });\r\n // Use pino with the pretty stream\r\n return pino(pinoOptions, prettyStream);\r\n } catch (error) {\r\n // pino-pretty not available, use default Pino output (JSON but readable)\r\n // This is expected if pino-pretty isn't installed, so we silently fall back\r\n return pino(pinoOptions, process.stdout);\r\n }\r\n }\r\n }\r\n\r\n // For file logging: Use Beamable format in containers, default Pino format locally\r\n const resolvedDestination = configuredDestination === 'temp' ? ensureWritableTempDirectory() : configuredDestination;\r\n if (inContainer) {\r\n const beamableFormatter = createBeamableLogFormatter();\r\n const fileStream = destination({ dest: resolvedDestination, mkdir: true, append: true, sync: false });\r\n beamableFormatter.pipe(fileStream as unknown as NodeJS.WritableStream);\r\n return pino(pinoOptions, beamableFormatter);\r\n } else {\r\n const fileStream = destination({ dest: resolvedDestination, mkdir: true, append: true, sync: false });\r\n return pino(pinoOptions, fileStream);\r\n }\r\n}\r\n"]}
|
|
@@ -37,10 +37,22 @@ function resolveRoutingKey() {
|
|
|
37
37
|
if (raw && raw.trim().length > 0) {
|
|
38
38
|
return raw.trim();
|
|
39
39
|
}
|
|
40
|
-
const
|
|
40
|
+
const isExplicitlyInContainer = process.env.DOTNET_RUNNING_IN_CONTAINER === 'true' ||
|
|
41
|
+
process.env.CONTAINER === 'beamable' ||
|
|
42
|
+
!!process.env.ECS_CONTAINER_METADATA_URI ||
|
|
43
|
+
!!process.env.KUBERNETES_SERVICE_HOST;
|
|
44
|
+
if (isExplicitlyInContainer) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const hasBeamableEnvVars = !!(process.env.CID && process.env.PID && process.env.HOST && process.env.SECRET);
|
|
41
48
|
const hasNoRoutingKey = !raw || raw.trim().length === 0;
|
|
42
49
|
if (hasBeamableEnvVars && hasNoRoutingKey) {
|
|
43
|
-
|
|
50
|
+
try {
|
|
51
|
+
return (0, routing_js_1.getDefaultRoutingKeyForMachine)();
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error(`Unable to determine routing key automatically. Set NAME_PREFIX environment variable. ${error.message}`);
|
|
55
|
+
}
|
|
44
56
|
}
|
|
45
57
|
try {
|
|
46
58
|
return (0, routing_js_1.getDefaultRoutingKeyForMachine)();
|
|
@@ -36,15 +36,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.createLogger = createLogger;
|
|
37
37
|
const pino_1 = __importStar(require("pino"));
|
|
38
38
|
const node_stream_1 = require("node:stream");
|
|
39
|
+
const node_module_1 = require("node:module");
|
|
39
40
|
const env_js_1 = require("./env.js");
|
|
40
|
-
|
|
41
|
+
const require = (0, node_module_1.createRequire)(import.meta.url);
|
|
42
|
+
function isRunningInContainer(env) {
|
|
41
43
|
if (process.env.DOTNET_RUNNING_IN_CONTAINER === 'true' ||
|
|
42
44
|
process.env.CONTAINER === 'beamable' ||
|
|
43
45
|
!!process.env.ECS_CONTAINER_METADATA_URI ||
|
|
44
46
|
!!process.env.KUBERNETES_SERVICE_HOST) {
|
|
45
47
|
return true;
|
|
46
48
|
}
|
|
47
|
-
|
|
49
|
+
const hasRoutingKey = (env === null || env === void 0 ? void 0 : env.routingKey) || process.env.NAME_PREFIX || process.env.ROUTING_KEY;
|
|
50
|
+
if (hasRoutingKey) {
|
|
48
51
|
return false;
|
|
49
52
|
}
|
|
50
53
|
const hasBeamableEnvVars = !!(process.env.CID && process.env.PID && process.env.HOST && process.env.SECRET);
|
|
@@ -145,7 +148,7 @@ function createBeamableLogFormatter() {
|
|
|
145
148
|
function createLogger(env, options = {}) {
|
|
146
149
|
var _a, _b, _c;
|
|
147
150
|
const configuredDestination = (_a = options.destinationPath) !== null && _a !== void 0 ? _a : process.env.LOG_PATH;
|
|
148
|
-
const inContainer = isRunningInContainer();
|
|
151
|
+
const inContainer = isRunningInContainer(env);
|
|
149
152
|
const pinoOptions = {
|
|
150
153
|
name: (_b = options.name) !== null && _b !== void 0 ? _b : 'beamable-node-runtime',
|
|
151
154
|
level: env.logLevel,
|
|
@@ -178,7 +181,7 @@ function createLogger(env, options = {}) {
|
|
|
178
181
|
});
|
|
179
182
|
return (0, pino_1.default)(pinoOptions, prettyStream);
|
|
180
183
|
}
|
|
181
|
-
catch {
|
|
184
|
+
catch (error) {
|
|
182
185
|
return (0, pino_1.default)(pinoOptions, process.stdout);
|
|
183
186
|
}
|
|
184
187
|
}
|
package/package.json
CHANGED
package/src/env.ts
CHANGED
|
@@ -42,16 +42,42 @@ function resolveRoutingKey(): string | undefined {
|
|
|
42
42
|
return raw.trim();
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
// Check for explicit container indicators first (highest priority)
|
|
46
|
+
const isExplicitlyInContainer =
|
|
47
|
+
process.env.DOTNET_RUNNING_IN_CONTAINER === 'true' ||
|
|
48
|
+
process.env.CONTAINER === 'beamable' ||
|
|
49
|
+
!!process.env.ECS_CONTAINER_METADATA_URI ||
|
|
50
|
+
!!process.env.KUBERNETES_SERVICE_HOST;
|
|
51
|
+
|
|
52
|
+
if (isExplicitlyInContainer) {
|
|
53
|
+
// We're definitely in a container - return undefined (becomes None in Scala)
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
45
57
|
// For deployed services (in containers), routing key should be undefined (None in Scala)
|
|
46
58
|
// Beamable sets CID, PID, HOST, SECRET in containers but NOT routing key
|
|
47
|
-
//
|
|
48
|
-
|
|
59
|
+
// BUT: Local dev also has these env vars from .env file, so we need to be more careful
|
|
60
|
+
// If we have the required Beamable env vars but NO routing key AND no explicit container indicators,
|
|
61
|
+
// we might be in a deployed container OR local dev without routing key set
|
|
62
|
+
// For safety, if we're not explicitly in a container, try to generate a routing key for local dev
|
|
63
|
+
const hasBeamableEnvVars = !!(process.env.CID && process.env.PID && process.env.HOST && process.env.SECRET);
|
|
49
64
|
const hasNoRoutingKey = !raw || raw.trim().length === 0;
|
|
50
65
|
|
|
66
|
+
// If we have Beamable env vars but no routing key, and we're not explicitly in a container,
|
|
67
|
+
// we might be in local dev - try to generate a routing key
|
|
68
|
+
// Only return undefined if we're explicitly in a container
|
|
51
69
|
if (hasBeamableEnvVars && hasNoRoutingKey) {
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
|
|
70
|
+
// Try to generate a routing key for local dev
|
|
71
|
+
// If this fails, we'll throw an error (which is fine for local dev)
|
|
72
|
+
try {
|
|
73
|
+
return getDefaultRoutingKeyForMachine();
|
|
74
|
+
} catch (error) {
|
|
75
|
+
// If we can't generate a routing key, we might be in a container
|
|
76
|
+
// But since we don't have explicit container indicators, assume local dev and throw
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Unable to determine routing key automatically. Set NAME_PREFIX environment variable. ${(error as Error).message}`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
55
81
|
}
|
|
56
82
|
|
|
57
83
|
// Local development - try to get a routing key
|
package/src/logger.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import pino, { destination, type Logger, type LoggerOptions } from 'pino';
|
|
2
2
|
import { Transform } from 'node:stream';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
3
4
|
import { ensureWritableTempDirectory } from './env.js';
|
|
4
5
|
import type { EnvironmentConfig } from './types.js';
|
|
5
6
|
|
|
7
|
+
// Create a require function for loading CommonJS modules in ESM
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
|
|
6
10
|
/**
|
|
7
11
|
* Detects if we're running in a container (deployed environment).
|
|
8
12
|
* This is used to determine log format: pretty for local dev, JSON for containers.
|
|
@@ -16,7 +20,7 @@ import type { EnvironmentConfig } from './types.js';
|
|
|
16
20
|
* - Has routing key (local dev always has a routing key)
|
|
17
21
|
* - Running via tsx/node directly (not in Docker)
|
|
18
22
|
*/
|
|
19
|
-
function isRunningInContainer(): boolean {
|
|
23
|
+
function isRunningInContainer(env?: EnvironmentConfig): boolean {
|
|
20
24
|
// Explicit container indicators (highest priority)
|
|
21
25
|
if (
|
|
22
26
|
process.env.DOTNET_RUNNING_IN_CONTAINER === 'true' ||
|
|
@@ -27,9 +31,10 @@ function isRunningInContainer(): boolean {
|
|
|
27
31
|
return true;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
// If we have a routing key, we're definitely running locally
|
|
31
|
-
// Local dev always
|
|
32
|
-
|
|
34
|
+
// If we have a routing key (from env object or process.env), we're definitely running locally
|
|
35
|
+
// Local dev always has a routing key (either set explicitly or auto-generated)
|
|
36
|
+
const hasRoutingKey = env?.routingKey || process.env.NAME_PREFIX || process.env.ROUTING_KEY;
|
|
37
|
+
if (hasRoutingKey) {
|
|
33
38
|
return false; // Local development
|
|
34
39
|
}
|
|
35
40
|
|
|
@@ -168,7 +173,7 @@ function createBeamableLogFormatter(): Transform {
|
|
|
168
173
|
|
|
169
174
|
export function createLogger(env: EnvironmentConfig, options: LoggerFactoryOptions = {}): Logger {
|
|
170
175
|
const configuredDestination = options.destinationPath ?? process.env.LOG_PATH;
|
|
171
|
-
const inContainer = isRunningInContainer();
|
|
176
|
+
const inContainer = isRunningInContainer(env);
|
|
172
177
|
|
|
173
178
|
const pinoOptions: LoggerOptions = {
|
|
174
179
|
name: options.name ?? 'beamable-node-runtime',
|
|
@@ -200,7 +205,7 @@ export function createLogger(env: EnvironmentConfig, options: LoggerFactoryOptio
|
|
|
200
205
|
// Try to use pino-pretty if available (optional dependency)
|
|
201
206
|
// If not available, fall back to default Pino JSON output
|
|
202
207
|
try {
|
|
203
|
-
// Check if pino-pretty is available
|
|
208
|
+
// Check if pino-pretty is available (using createRequire for ESM compatibility)
|
|
204
209
|
const pinoPretty = require('pino-pretty');
|
|
205
210
|
// Create a pretty stream with formatting options
|
|
206
211
|
const prettyStream = pinoPretty({
|
|
@@ -211,8 +216,9 @@ export function createLogger(env: EnvironmentConfig, options: LoggerFactoryOptio
|
|
|
211
216
|
});
|
|
212
217
|
// Use pino with the pretty stream
|
|
213
218
|
return pino(pinoOptions, prettyStream);
|
|
214
|
-
} catch {
|
|
219
|
+
} catch (error) {
|
|
215
220
|
// pino-pretty not available, use default Pino output (JSON but readable)
|
|
221
|
+
// This is expected if pino-pretty isn't installed, so we silently fall back
|
|
216
222
|
return pino(pinoOptions, process.stdout);
|
|
217
223
|
}
|
|
218
224
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|