@volley/vwr-loader 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +7 -8
  2. package/dist/__mocks__/@datadog/browser-logs.d.ts +58 -0
  3. package/dist/__mocks__/@datadog/browser-logs.d.ts.map +1 -0
  4. package/dist/__mocks__/@datadog/browser-logs.js +34 -0
  5. package/dist/__mocks__/@datadog/browser-logs.js.map +1 -0
  6. package/dist/__mocks__/@datadog/browser-rum.d.ts +25 -0
  7. package/dist/__mocks__/@datadog/browser-rum.d.ts.map +1 -0
  8. package/dist/__mocks__/@datadog/browser-rum.js +25 -0
  9. package/dist/__mocks__/@datadog/browser-rum.js.map +1 -0
  10. package/dist/amplitudeFlagFetcher.d.ts +8 -3
  11. package/dist/amplitudeFlagFetcher.d.ts.map +1 -1
  12. package/dist/amplitudeFlagFetcher.js +14 -12
  13. package/dist/amplitudeFlagFetcher.js.map +1 -1
  14. package/dist/assets/profiler-BRmTNL9s.js +2 -0
  15. package/dist/assets/profiler-BRmTNL9s.js.map +1 -0
  16. package/dist/assets/startRecording-CuFdVhxx.js +3 -0
  17. package/dist/assets/startRecording-CuFdVhxx.js.map +1 -0
  18. package/dist/cli.js +42 -8
  19. package/dist/cli.js.map +1 -1
  20. package/dist/datadog.d.ts +19 -0
  21. package/dist/datadog.d.ts.map +1 -0
  22. package/dist/datadog.js +39 -0
  23. package/dist/datadog.js.map +1 -0
  24. package/dist/envDefaults.d.ts.map +1 -1
  25. package/dist/envDefaults.js +27 -2
  26. package/dist/envDefaults.js.map +1 -1
  27. package/dist/errors/InitializationError.d.ts +74 -0
  28. package/dist/errors/InitializationError.d.ts.map +1 -0
  29. package/dist/errors/InitializationError.js +77 -0
  30. package/dist/errors/InitializationError.js.map +1 -0
  31. package/dist/errors/ensureError.d.ts +2 -0
  32. package/dist/errors/ensureError.d.ts.map +1 -0
  33. package/dist/errors/ensureError.js +7 -0
  34. package/dist/errors/ensureError.js.map +1 -0
  35. package/dist/errors/index.d.ts +12 -0
  36. package/dist/errors/index.d.ts.map +1 -0
  37. package/dist/errors/index.js +10 -0
  38. package/dist/errors/index.js.map +1 -0
  39. package/dist/getDeviceId.d.ts +1 -2
  40. package/dist/getDeviceId.d.ts.map +1 -1
  41. package/dist/getDeviceId.js +17 -15
  42. package/dist/getDeviceId.js.map +1 -1
  43. package/dist/getEnvironment.d.ts +1 -2
  44. package/dist/getEnvironment.d.ts.map +1 -1
  45. package/dist/getEnvironment.js +4 -4
  46. package/dist/getEnvironment.js.map +1 -1
  47. package/dist/getShellVersion.d.ts +1 -2
  48. package/dist/getShellVersion.d.ts.map +1 -1
  49. package/dist/getShellVersion.js +4 -4
  50. package/dist/getShellVersion.js.map +1 -1
  51. package/dist/index.d.ts +0 -1
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/loadVwr.d.ts +4 -4
  55. package/dist/loadVwr.d.ts.map +1 -1
  56. package/dist/loadVwr.js +151 -37
  57. package/dist/loadVwr.js.map +1 -1
  58. package/dist/logger.d.ts +11 -6
  59. package/dist/logger.d.ts.map +1 -1
  60. package/dist/logger.js +107 -4
  61. package/dist/logger.js.map +1 -1
  62. package/dist/main.js +9 -1
  63. package/dist/main.js.map +1 -1
  64. package/dist/test-setup.d.ts +2 -0
  65. package/dist/test-setup.d.ts.map +1 -0
  66. package/dist/test-setup.js +5 -0
  67. package/dist/test-setup.js.map +1 -0
  68. package/dist/vwrConfig.d.ts +14 -2
  69. package/dist/vwrConfig.d.ts.map +1 -1
  70. package/dist/vwrConfig.js +74 -29
  71. package/dist/vwrConfig.js.map +1 -1
  72. package/package.json +59 -53
  73. package/src/__mocks__/@datadog/browser-logs.ts +35 -0
  74. package/src/__mocks__/@datadog/browser-rum.ts +27 -0
  75. package/src/amplitudeFlagFetcher.test.ts +28 -34
  76. package/src/amplitudeFlagFetcher.ts +22 -14
  77. package/src/datadog.ts +55 -0
  78. package/src/envDefaults.ts +32 -3
  79. package/src/errors/InitializationError.ts +105 -0
  80. package/src/errors/ensureError.ts +6 -0
  81. package/src/errors/index.ts +16 -0
  82. package/src/getDeviceId.test.ts +4 -5
  83. package/src/getDeviceId.ts +19 -18
  84. package/src/getEnvironment.test.ts +44 -106
  85. package/src/getEnvironment.ts +4 -5
  86. package/src/getShellVersion.test.ts +12 -6
  87. package/src/getShellVersion.ts +4 -7
  88. package/src/index.ts +0 -1
  89. package/src/loadVwr.test.ts +394 -0
  90. package/src/loadVwr.ts +243 -58
  91. package/src/logger.ts +118 -11
  92. package/src/main.test.ts +157 -0
  93. package/src/main.ts +79 -11
  94. package/src/test-setup.ts +5 -0
  95. package/src/vite-env.d.ts +2 -0
  96. package/src/vwrConfig.test.ts +104 -34
  97. package/src/vwrConfig.ts +115 -37
@@ -13,6 +13,14 @@ const CONFIG_URL_DEFAULT = "https://vwr.volley.tv/config/"
13
13
  const CONFIG_FILE_DEFAULT = "vwrConfig.json"
14
14
  const VWR_URL_PATH_DEFAULT = "v1/latest/vwr.js"
15
15
 
16
+ // Parse comma-separated env var, returning undefined if empty to allow fallback
17
+ const parseTrustedOrigins = (
18
+ envVar: string | undefined
19
+ ): string[] | undefined => {
20
+ const parsed = envVar?.split(",").filter(Boolean)
21
+ return parsed?.length ? parsed : undefined
22
+ }
23
+
16
24
  const prodConfig: EnvConfig = {
17
25
  hubUrl: "https://game-clients.volley.tv/hub",
18
26
  vwrUrl: `https://vwr.volley.tv/${VWR_URL_PATH_DEFAULT}`,
@@ -21,6 +29,7 @@ const prodConfig: EnvConfig = {
21
29
  platformApiUrl: "https://platform.volley-services.net",
22
30
  platformAuthApiUrl: "https://auth.volley.tv",
23
31
  amplitudeKey: "",
32
+ trustedOrigins: ["https://volley.tv", "https://vl.ly", "https://vly.gg"],
24
33
  }
25
34
 
26
35
  export const ENV_DEFAULTS: Record<string, EnvConfig> = {
@@ -37,9 +46,16 @@ export const ENV_DEFAULTS: Record<string, EnvConfig> = {
37
46
  import.meta.env.VITE_PLATFORM_AUTH_API_URL ||
38
47
  "https://auth-dev.volley.tv",
39
48
  amplitudeKey: "client-uJJVW3zKPC1G9kqPhUumLnZN6eaY42iQ",
40
- trustedOrigins: import.meta.env.VITE_TRUSTED_ORIGINS?.split(",").filter(
41
- Boolean
42
- ),
49
+ trustedOrigins: parseTrustedOrigins(
50
+ import.meta.env.VITE_TRUSTED_ORIGINS
51
+ ) || [
52
+ "http://localhost:5173",
53
+ "http://localhost:5174",
54
+ "https://vl.ly",
55
+ "https://dev.vl.ly",
56
+ "https://staging.vl.ly",
57
+ "https://vly.gg",
58
+ ],
43
59
  },
44
60
  dev: {
45
61
  hubUrl: "https://game-clients-dev.volley.tv/hub",
@@ -49,6 +65,13 @@ export const ENV_DEFAULTS: Record<string, EnvConfig> = {
49
65
  platformApiUrl: "https://platform-dev.volley-services.net",
50
66
  platformAuthApiUrl: "https://auth-dev.volley.tv",
51
67
  amplitudeKey: "client-uJJVW3zKPC1G9kqPhUumLnZN6eaY42iQ",
68
+ trustedOrigins: [
69
+ "https://volley.tv",
70
+ "https://vl.ly",
71
+ "https://dev.vl.ly",
72
+ "https://staging.vl.ly",
73
+ "https://vly.gg",
74
+ ],
52
75
  },
53
76
  staging: {
54
77
  hubUrl: "https://game-clients-staging.volley.tv/hub",
@@ -58,6 +81,12 @@ export const ENV_DEFAULTS: Record<string, EnvConfig> = {
58
81
  platformApiUrl: "https://platform-staging.volley-services.net",
59
82
  platformAuthApiUrl: "https://auth-staging.volley.tv",
60
83
  amplitudeKey: "",
84
+ trustedOrigins: [
85
+ "https://volley.tv",
86
+ "https://vl.ly",
87
+ "https://staging.vl.ly",
88
+ "https://vly.gg",
89
+ ],
61
90
  },
62
91
  prod: prodConfig,
63
92
  production: prodConfig, // Alias for prod
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Reason codes for VWR loader initialization failures.
3
+ * Each code maps to a specific failure point in the init flow.
4
+ */
5
+ export const InitializationErrorReason = {
6
+ // Environment variable errors
7
+ ENV_VARS_MISSING: "ENV_VARS_MISSING",
8
+ ENV_UNKNOWN: "ENV_UNKNOWN",
9
+
10
+ // Device/platform errors
11
+ DEVICE_ID_FAILED: "DEVICE_ID_FAILED",
12
+ SHELL_VERSION_FAILED: "SHELL_VERSION_FAILED",
13
+
14
+ // Feature flag errors
15
+ FLAG_DISABLED: "FLAG_DISABLED",
16
+ FLAG_FETCH_FAILED: "FLAG_FETCH_FAILED",
17
+
18
+ // Runtime config errors
19
+ CONFIG_FETCH_FAILED: "CONFIG_FETCH_FAILED",
20
+ CONFIG_INVALID: "CONFIG_INVALID",
21
+
22
+ // Module loading errors
23
+ MODULE_FETCH_FAILED: "MODULE_FETCH_FAILED",
24
+ MODULE_INVALID: "MODULE_INVALID",
25
+
26
+ // VWR init errors
27
+ INIT_FAILED: "INIT_FAILED",
28
+ } as const
29
+
30
+ export type InitializationErrorReason =
31
+ (typeof InitializationErrorReason)[keyof typeof InitializationErrorReason]
32
+
33
+ /**
34
+ * Context for initialization errors - used for structured logging
35
+ * and Datadog dashboard creation.
36
+ */
37
+ export interface InitializationErrorContext {
38
+ cause?: Error
39
+ [key: string]: unknown
40
+ }
41
+
42
+ /**
43
+ * Custom error for VWR loader initialization failures.
44
+ *
45
+ * Provides structured information for:
46
+ * - Error categorization (reason code)
47
+ * - RUM phase tracking
48
+ * - Datadog dashboard filtering
49
+ * - Original error chain preservation
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * throw new InitializationError(
54
+ * InitializationErrorReason.DEVICE_ID_FAILED,
55
+ * `Failed to retrieve device ID for platform: ${platform}`,
56
+ * {
57
+ * phase: "vwr-loader:device_id",
58
+ * platform,
59
+ * }
60
+ * );
61
+ * ```
62
+ */
63
+ export class InitializationError extends Error {
64
+ public readonly name = "InitializationError"
65
+
66
+ constructor(
67
+ /** Structured reason code for categorization */
68
+ public readonly reason: InitializationErrorReason,
69
+ /** Human-readable error message */
70
+ public readonly message: string,
71
+ /** Context for logging and RUM tracking */
72
+ public readonly context: InitializationErrorContext = {}
73
+ ) {
74
+ super(message)
75
+
76
+ // Ensure proper prototype chain for instanceof checks
77
+ Object.setPrototypeOf(this, InitializationError.prototype)
78
+ }
79
+
80
+ /**
81
+ * Convert to a plain object for structured logging.
82
+ * Useful for Datadog Logs and JSON serialization.
83
+ */
84
+ toJSON(): Record<string, unknown> {
85
+ return {
86
+ name: this.name,
87
+ reason: this.reason,
88
+ message: this.message,
89
+ ...this.context,
90
+ cause: this.context.cause?.message,
91
+ stack: this.stack,
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Get error context.
97
+ * Returns the context object.
98
+ */
99
+ getContext(): Record<string, unknown> {
100
+ return {
101
+ ...this.context,
102
+ reason: this.reason,
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,6 @@
1
+ export function ensureError(error: unknown): Error {
2
+ if (error instanceof Error) {
3
+ return error
4
+ }
5
+ return new Error(String(error ?? "Unknown error"))
6
+ }
@@ -0,0 +1,16 @@
1
+ export { ensureError } from "./ensureError"
2
+ export type { InitializationErrorContext } from "./InitializationError"
3
+ export {
4
+ InitializationError,
5
+ InitializationErrorReason,
6
+ } from "./InitializationError"
7
+
8
+ /**
9
+ * Type guard for VWR initialization errors.
10
+ * Checks error.name instead of instanceof to avoid runtime dependency on @volley/vwr.
11
+ */
12
+ export function isVWRInitializationError(
13
+ error: unknown
14
+ ): error is Error & { name: "VWRInitializationError"; reason: string } {
15
+ return error instanceof Error && error.name === "VWRInitializationError"
16
+ }
@@ -1,7 +1,10 @@
1
+ import * as uuid from "uuid"
1
2
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
2
3
 
3
4
  import { getDeviceId } from "./getDeviceId"
4
5
 
6
+ vi.mock("uuid")
7
+
5
8
  describe("getDeviceId", () => {
6
9
  beforeEach(() => {
7
10
  vi.clearAllMocks()
@@ -247,11 +250,7 @@ describe("getDeviceId", () => {
247
250
 
248
251
  it("generates and stores new device ID when none exists", async () => {
249
252
  const mockUUID = "web-uuid-123"
250
- Object.defineProperty(window.crypto, "randomUUID", {
251
- value: vi.fn().mockReturnValue(mockUUID),
252
- writable: true,
253
- configurable: true,
254
- })
253
+ vi.mocked(uuid.v4).mockReturnValue(mockUUID as any)
255
254
 
256
255
  const result = await getDeviceId("WEB")
257
256
 
@@ -1,4 +1,6 @@
1
- import { defaultLogger, type Logger } from "./logger"
1
+ import { v4 as uuidv4 } from "uuid"
2
+
3
+ import { logger } from "./logger"
2
4
  import type { LGDeviceIdResponse, MobileExtendedWindow } from "./types"
3
5
 
4
6
  /**
@@ -25,21 +27,18 @@ import type { LGDeviceIdResponse, MobileExtendedWindow } from "./types"
25
27
  * }
26
28
  * ```
27
29
  */
28
- export async function getDeviceId(
29
- platform: string,
30
- logger: Logger = defaultLogger
31
- ): Promise<string | null> {
30
+ export async function getDeviceId(platform: string): Promise<string | null> {
32
31
  const normalizedPlatform = platform.toUpperCase()
33
32
  switch (normalizedPlatform) {
34
33
  case "FIRE_TV":
35
- return await getFireTVDeviceId(logger)
34
+ return await getFireTVDeviceId()
36
35
  case "SAMSUNG_TV":
37
- return await getSamsungDeviceId(logger)
36
+ return await getSamsungDeviceId()
38
37
  case "LG_TV":
39
- return await getLGDeviceId(logger)
38
+ return await getLGDeviceId()
40
39
  case "ANDROID_MOBILE":
41
40
  case "IOS_MOBILE":
42
- return await getMobileDeviceId(logger)
41
+ return await getMobileDeviceId()
43
42
  case "WEB":
44
43
  return getLocalStorageDeviceId()
45
44
  default:
@@ -53,18 +52,20 @@ export async function getDeviceId(
53
52
  * Get or create device ID from localStorage (for Web platform)
54
53
  */
55
54
  function getLocalStorageDeviceId(): string {
56
- let deviceId = localStorage.getItem("volley_device_id")
57
- if (!deviceId) {
58
- deviceId = crypto.randomUUID()
59
- localStorage.setItem("volley_device_id", deviceId)
55
+ const existingDeviceId = localStorage.getItem("volley_device_id")
56
+ if (existingDeviceId) {
57
+ return existingDeviceId
60
58
  }
61
- return deviceId
59
+
60
+ const newDeviceId = uuidv4()
61
+ localStorage.setItem("volley_device_id", newDeviceId)
62
+ return newDeviceId
62
63
  }
63
64
 
64
65
  /**
65
66
  * Attempt to get device ID from Capacitor DeviceInfo plugin (FireTV)
66
67
  */
67
- async function getFireTVDeviceId(logger: Logger): Promise<string | null> {
68
+ async function getFireTVDeviceId(): Promise<string | null> {
68
69
  try {
69
70
  if (!window.Capacitor?.Plugins?.DeviceInfo?.getAndroidId) {
70
71
  return null
@@ -91,7 +92,7 @@ async function getFireTVDeviceId(logger: Logger): Promise<string | null> {
91
92
  * iOS exposes phoneDeviceId via window.iosAppContext
92
93
  * Android exposes phoneDeviceId via window.androidAppContext (also check window.top for iframes)
93
94
  */
94
- function getMobileDeviceId(logger: Logger): string | null {
95
+ function getMobileDeviceId(): string | null {
95
96
  // Try iOS first
96
97
  const iosId = (window as MobileExtendedWindow).iosAppContext?.phoneDeviceId
97
98
  if (iosId && iosId.trim()) {
@@ -126,7 +127,7 @@ function getMobileDeviceId(logger: Logger): string | null {
126
127
  /**
127
128
  * Attempt to get device ID from Samsung TV webapis
128
129
  */
129
- async function getSamsungDeviceId(logger: Logger): Promise<string | null> {
130
+ async function getSamsungDeviceId(): Promise<string | null> {
130
131
  try {
131
132
  if (!window.webapis?.productinfo?.getDuid) {
132
133
  return null
@@ -156,7 +157,7 @@ async function getSamsungDeviceId(logger: Logger): Promise<string | null> {
156
157
  */
157
158
  const LG_LUNA_SERVICE_TIMEOUT = 5000
158
159
 
159
- async function getLGDeviceId(logger: Logger): Promise<string | null> {
160
+ async function getLGDeviceId(): Promise<string | null> {
160
161
  if (!window.webOS?.service?.request) {
161
162
  const message = "LG webOS service request not available"
162
163
  logger.error(message)
@@ -1,19 +1,21 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
2
2
 
3
3
  import { type Environment, getEnvironment } from "./getEnvironment"
4
+ import { logger } from "./logger"
4
5
 
5
- describe("getEnvironment", () => {
6
- const mockLogger = {
6
+ vi.mock("./logger", () => ({
7
+ logger: {
7
8
  info: vi.fn(),
8
9
  warn: vi.fn(),
9
10
  error: vi.fn(),
10
- }
11
+ debug: vi.fn(),
12
+ child: vi.fn(),
13
+ },
14
+ }))
11
15
 
16
+ describe("getEnvironment", () => {
12
17
  beforeEach(() => {
13
18
  vi.clearAllMocks()
14
- mockLogger.info.mockClear()
15
- mockLogger.warn.mockClear()
16
- mockLogger.error.mockClear()
17
19
  // Clean up window properties
18
20
  delete (window as any).Capacitor
19
21
  })
@@ -42,15 +44,11 @@ describe("getEnvironment", () => {
42
44
  configurable: true,
43
45
  })
44
46
 
45
- const result = await getEnvironment(
46
- "FIRE_TV",
47
- undefined,
48
- mockLogger
49
- )
47
+ const result = await getEnvironment("FIRE_TV", undefined)
50
48
 
51
49
  expect(result.environment).toBe("dev")
52
50
  expect(result.source).toBe("native")
53
- expect(mockLogger.info).toHaveBeenCalledWith(
51
+ expect(logger.info).toHaveBeenCalledWith(
54
52
  expect.stringContaining(
55
53
  'Environment: "dev" (source: native BuildConfig.ENVIRONMENT="development")'
56
54
  )
@@ -74,11 +72,7 @@ describe("getEnvironment", () => {
74
72
  configurable: true,
75
73
  })
76
74
 
77
- const result = await getEnvironment(
78
- "FIRE_TV",
79
- undefined,
80
- mockLogger
81
- )
75
+ const result = await getEnvironment("FIRE_TV", undefined)
82
76
 
83
77
  expect(result.environment).toBe("prod")
84
78
  expect(result.source).toBe("native")
@@ -101,11 +95,7 @@ describe("getEnvironment", () => {
101
95
  configurable: true,
102
96
  })
103
97
 
104
- const result = await getEnvironment(
105
- "FIRE_TV",
106
- undefined,
107
- mockLogger
108
- )
98
+ const result = await getEnvironment("FIRE_TV", undefined)
109
99
 
110
100
  expect(result.environment).toBe("staging")
111
101
  expect(result.source).toBe("native")
@@ -128,11 +118,7 @@ describe("getEnvironment", () => {
128
118
  configurable: true,
129
119
  })
130
120
 
131
- const result = await getEnvironment(
132
- "FIRE_TV",
133
- undefined,
134
- mockLogger
135
- )
121
+ const result = await getEnvironment("FIRE_TV", undefined)
136
122
 
137
123
  expect(result.environment).toBe("staging")
138
124
  expect(result.source).toBe("native")
@@ -155,11 +141,7 @@ describe("getEnvironment", () => {
155
141
  configurable: true,
156
142
  })
157
143
 
158
- const result = await getEnvironment(
159
- "FIRE_TV",
160
- undefined,
161
- mockLogger
162
- )
144
+ const result = await getEnvironment("FIRE_TV", undefined)
163
145
 
164
146
  expect(result.environment).toBe("dev")
165
147
  expect(result.source).toBe("native")
@@ -182,11 +164,7 @@ describe("getEnvironment", () => {
182
164
  configurable: true,
183
165
  })
184
166
 
185
- const result = await getEnvironment(
186
- "FIRE_TV",
187
- undefined,
188
- mockLogger
189
- )
167
+ const result = await getEnvironment("FIRE_TV", undefined)
190
168
 
191
169
  expect(result.environment).toBe("dev")
192
170
  expect(result.source).toBe("native")
@@ -194,15 +172,11 @@ describe("getEnvironment", () => {
194
172
 
195
173
  it("should fallback to build-time when native plugin unavailable", async () => {
196
174
  // No Capacitor plugin available
197
- const result = await getEnvironment(
198
- "FIRE_TV",
199
- "staging",
200
- mockLogger
201
- )
175
+ const result = await getEnvironment("FIRE_TV", "staging")
202
176
 
203
177
  expect(result.environment).toBe("staging")
204
178
  expect(result.source).toBe("build-time")
205
- expect(mockLogger.warn).toHaveBeenCalledWith(
179
+ expect(logger.warn).toHaveBeenCalledWith(
206
180
  expect.stringContaining(
207
181
  "Failed to read environment from native, falling back to build-time"
208
182
  )
@@ -226,12 +200,12 @@ describe("getEnvironment", () => {
226
200
  configurable: true,
227
201
  })
228
202
 
229
- const result = await getEnvironment("FIRE_TV", "prod", mockLogger)
203
+ const result = await getEnvironment("FIRE_TV", "prod")
230
204
 
231
205
  expect(result.environment).toBe("prod")
232
206
  expect(result.source).toBe("build-time")
233
- expect(mockLogger.error).toHaveBeenCalled()
234
- expect(mockLogger.warn).toHaveBeenCalledWith(
207
+ expect(logger.error).toHaveBeenCalled()
208
+ expect(logger.warn).toHaveBeenCalledWith(
235
209
  expect.stringContaining("falling back to build-time")
236
210
  )
237
211
  })
@@ -253,11 +227,11 @@ describe("getEnvironment", () => {
253
227
  configurable: true,
254
228
  })
255
229
 
256
- const result = await getEnvironment("FIRE_TV", "dev", mockLogger)
230
+ const result = await getEnvironment("FIRE_TV", "dev")
257
231
 
258
232
  expect(result.environment).toBe("dev")
259
233
  expect(result.source).toBe("build-time")
260
- expect(mockLogger.error).toHaveBeenCalledWith(
234
+ expect(logger.error).toHaveBeenCalledWith(
261
235
  expect.stringContaining(
262
236
  "DeviceInfo.getNativeShellAppEnvironment returned empty"
263
237
  )
@@ -266,15 +240,11 @@ describe("getEnvironment", () => {
266
240
 
267
241
  it("should fallback to default when both native and build-time fail", async () => {
268
242
  // No Capacitor plugin, no build-time env
269
- const result = await getEnvironment(
270
- "FIRE_TV",
271
- undefined,
272
- mockLogger
273
- )
243
+ const result = await getEnvironment("FIRE_TV", undefined)
274
244
 
275
245
  expect(result.environment).toBe("dev")
276
246
  expect(result.source).toBe("default")
277
- expect(mockLogger.warn).toHaveBeenCalledWith(
247
+ expect(logger.warn).toHaveBeenCalledWith(
278
248
  expect.stringContaining(
279
249
  'Environment: "dev" (source: default fallback'
280
250
  )
@@ -298,16 +268,8 @@ describe("getEnvironment", () => {
298
268
  configurable: true,
299
269
  })
300
270
 
301
- const result1 = await getEnvironment(
302
- "fire_tv",
303
- undefined,
304
- mockLogger
305
- )
306
- const result2 = await getEnvironment(
307
- "FIRE_TV",
308
- undefined,
309
- mockLogger
310
- )
271
+ const result1 = await getEnvironment("fire_tv", undefined)
272
+ const result2 = await getEnvironment("FIRE_TV", undefined)
311
273
 
312
274
  expect(result1.environment).toBe("prod")
313
275
  expect(result2.environment).toBe("prod")
@@ -320,15 +282,11 @@ describe("getEnvironment", () => {
320
282
  platforms.forEach((platform) => {
321
283
  describe(`${platform}`, () => {
322
284
  it("should use build-time environment when provided", async () => {
323
- const result = await getEnvironment(
324
- platform,
325
- "staging",
326
- mockLogger
327
- )
285
+ const result = await getEnvironment(platform, "staging")
328
286
 
329
287
  expect(result.environment).toBe("staging")
330
288
  expect(result.source).toBe("build-time")
331
- expect(mockLogger.info).toHaveBeenCalledWith(
289
+ expect(logger.info).toHaveBeenCalledWith(
332
290
  expect.stringContaining(
333
291
  'Environment: "staging" (source: build-time CLI injection)'
334
292
  )
@@ -336,48 +294,32 @@ describe("getEnvironment", () => {
336
294
  })
337
295
 
338
296
  it("should use build-time 'prod' environment", async () => {
339
- const result = await getEnvironment(
340
- platform,
341
- "prod",
342
- mockLogger
343
- )
297
+ const result = await getEnvironment(platform, "prod")
344
298
 
345
299
  expect(result.environment).toBe("prod")
346
300
  expect(result.source).toBe("build-time")
347
301
  })
348
302
 
349
303
  it("should use build-time 'dev' environment", async () => {
350
- const result = await getEnvironment(
351
- platform,
352
- "dev",
353
- mockLogger
354
- )
304
+ const result = await getEnvironment(platform, "dev")
355
305
 
356
306
  expect(result.environment).toBe("dev")
357
307
  expect(result.source).toBe("build-time")
358
308
  })
359
309
 
360
310
  it("should use build-time 'local' environment", async () => {
361
- const result = await getEnvironment(
362
- platform,
363
- "local",
364
- mockLogger
365
- )
311
+ const result = await getEnvironment(platform, "local")
366
312
 
367
313
  expect(result.environment).toBe("local")
368
314
  expect(result.source).toBe("build-time")
369
315
  })
370
316
 
371
317
  it("should fallback to default when build-time not provided", async () => {
372
- const result = await getEnvironment(
373
- platform,
374
- undefined,
375
- mockLogger
376
- )
318
+ const result = await getEnvironment(platform, undefined)
377
319
 
378
320
  expect(result.environment).toBe("dev")
379
321
  expect(result.source).toBe("default")
380
- expect(mockLogger.warn).toHaveBeenCalledWith(
322
+ expect(logger.warn).toHaveBeenCalledWith(
381
323
  expect.stringContaining(
382
324
  'Environment: "dev" (source: default fallback'
383
325
  )
@@ -385,11 +327,7 @@ describe("getEnvironment", () => {
385
327
  })
386
328
 
387
329
  it("should fallback to default when build-time is invalid", async () => {
388
- const result = await getEnvironment(
389
- platform,
390
- "invalid-env",
391
- mockLogger
392
- )
330
+ const result = await getEnvironment(platform, "invalid-env")
393
331
 
394
332
  expect(result.environment).toBe("dev")
395
333
  expect(result.source).toBe("default")
@@ -403,7 +341,7 @@ describe("getEnvironment", () => {
403
341
  const validEnvs: Environment[] = ["local", "dev", "staging", "prod"]
404
342
 
405
343
  for (const env of validEnvs) {
406
- const result = await getEnvironment("WEB", env, mockLogger)
344
+ const result = await getEnvironment("WEB", env)
407
345
  expect(result.environment).toBe(env)
408
346
  expect(result.source).toBe("build-time")
409
347
  }
@@ -420,7 +358,7 @@ describe("getEnvironment", () => {
420
358
  ]
421
359
 
422
360
  for (const env of invalidEnvs) {
423
- const result = await getEnvironment("WEB", env, mockLogger)
361
+ const result = await getEnvironment("WEB", env)
424
362
  expect(result.environment).toBe("dev")
425
363
  expect(result.source).toBe("default")
426
364
  }
@@ -445,33 +383,33 @@ describe("getEnvironment", () => {
445
383
  configurable: true,
446
384
  })
447
385
 
448
- await getEnvironment("FIRE_TV", undefined, mockLogger)
386
+ await getEnvironment("FIRE_TV", undefined)
449
387
 
450
- expect(mockLogger.info).toHaveBeenCalledWith(
388
+ expect(logger.info).toHaveBeenCalledWith(
451
389
  '[Shell] Environment: "prod" (source: native BuildConfig.ENVIRONMENT="production")'
452
390
  )
453
391
  })
454
392
 
455
393
  it("should log build-time environment source", async () => {
456
- await getEnvironment("SAMSUNG_TV", "staging", mockLogger)
394
+ await getEnvironment("SAMSUNG_TV", "staging")
457
395
 
458
- expect(mockLogger.info).toHaveBeenCalledWith(
396
+ expect(logger.info).toHaveBeenCalledWith(
459
397
  '[Shell] Environment: "staging" (source: build-time CLI injection)'
460
398
  )
461
399
  })
462
400
 
463
401
  it("should warn when falling back to default", async () => {
464
- await getEnvironment("LG_TV", undefined, mockLogger)
402
+ await getEnvironment("LG_TV", undefined)
465
403
 
466
- expect(mockLogger.warn).toHaveBeenCalledWith(
404
+ expect(logger.warn).toHaveBeenCalledWith(
467
405
  '[Shell] Environment: "dev" (source: default fallback - no native or build-time env found)'
468
406
  )
469
407
  })
470
408
 
471
409
  it("should warn when native fails and falls back", async () => {
472
- await getEnvironment("FIRE_TV", "prod", mockLogger)
410
+ await getEnvironment("FIRE_TV", "prod")
473
411
 
474
- expect(mockLogger.warn).toHaveBeenCalledWith(
412
+ expect(logger.warn).toHaveBeenCalledWith(
475
413
  "[Shell] Failed to read environment from native, falling back to build-time"
476
414
  )
477
415
  })
@@ -1,4 +1,4 @@
1
- import { defaultLogger, type Logger } from "./logger"
1
+ import { logger } from "./logger"
2
2
 
3
3
  export type Environment = "local" | "dev" | "staging" | "prod"
4
4
  export type EnvironmentSource = "native" | "build-time" | "default"
@@ -26,14 +26,13 @@ export interface EnvironmentResult {
26
26
  */
27
27
  export async function getEnvironment(
28
28
  platform: string,
29
- buildTimeEnv: string | undefined,
30
- logger: Logger = defaultLogger
29
+ buildTimeEnv: string | undefined
31
30
  ): Promise<EnvironmentResult> {
32
31
  const normalizedPlatform = platform.toUpperCase()
33
32
 
34
33
  // For Fire TV, try to read from native first (safest - prevents env mismatch)
35
34
  if (normalizedPlatform === "FIRE_TV") {
36
- const nativeEnv = await getFireTVEnvironment(logger)
35
+ const nativeEnv = await getFireTVEnvironment()
37
36
  if (nativeEnv) {
38
37
  const mapped = mapNativeEnvironment(nativeEnv)
39
38
  logger.info(
@@ -72,7 +71,7 @@ export async function getEnvironment(
72
71
  /**
73
72
  * Read environment from Fire TV native shell via Capacitor plugin.
74
73
  */
75
- async function getFireTVEnvironment(logger: Logger): Promise<string | null> {
74
+ async function getFireTVEnvironment(): Promise<string | null> {
76
75
  try {
77
76
  if (
78
77
  !window.Capacitor?.Plugins?.DeviceInfo?.getNativeShellAppEnvironment