@volley/vwr-loader 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +21 -0
  2. package/dist/amplitudeFlagFetcher.d.ts +4 -2
  3. package/dist/amplitudeFlagFetcher.d.ts.map +1 -1
  4. package/dist/amplitudeFlagFetcher.js +26 -19
  5. package/dist/amplitudeFlagFetcher.js.map +1 -1
  6. package/dist/cli.js +213 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/envDefaults.d.ts +3 -0
  9. package/dist/envDefaults.d.ts.map +1 -1
  10. package/dist/envDefaults.js +16 -4
  11. package/dist/envDefaults.js.map +1 -1
  12. package/dist/getDeviceId.d.ts +2 -40
  13. package/dist/getDeviceId.d.ts.map +1 -1
  14. package/dist/getDeviceId.js +31 -18
  15. package/dist/getDeviceId.js.map +1 -1
  16. package/dist/getEnvironment.d.ts +1 -1
  17. package/dist/getEnvironment.d.ts.map +1 -1
  18. package/dist/getEnvironment.js +15 -7
  19. package/dist/getEnvironment.js.map +1 -1
  20. package/dist/getShellVersion.d.ts +2 -19
  21. package/dist/getShellVersion.d.ts.map +1 -1
  22. package/dist/getShellVersion.js +41 -6
  23. package/dist/getShellVersion.js.map +1 -1
  24. package/dist/index.html +1 -1
  25. package/dist/loadVwr.d.ts.map +1 -1
  26. package/dist/loadVwr.js +8 -6
  27. package/dist/loadVwr.js.map +1 -1
  28. package/dist/main.js +1 -1
  29. package/dist/main.js.map +1 -1
  30. package/dist/types.d.ts +87 -0
  31. package/dist/types.d.ts.map +1 -0
  32. package/dist/types.js +5 -0
  33. package/dist/types.js.map +1 -0
  34. package/dist/vwrConfig.d.ts +2 -0
  35. package/dist/vwrConfig.d.ts.map +1 -1
  36. package/dist/vwrConfig.js +148 -119
  37. package/dist/vwrConfig.js.map +1 -1
  38. package/package.json +16 -5
  39. package/src/amplitudeFlagFetcher.test.ts +36 -59
  40. package/src/amplitudeFlagFetcher.ts +31 -22
  41. package/src/envDefaults.ts +23 -4
  42. package/src/getDeviceId.test.ts +89 -27
  43. package/src/getDeviceId.ts +35 -58
  44. package/src/getEnvironment.test.ts +479 -0
  45. package/src/getEnvironment.ts +16 -8
  46. package/src/getShellVersion.test.ts +123 -4
  47. package/src/getShellVersion.ts +46 -21
  48. package/src/loadVwr.ts +13 -6
  49. package/src/main.ts +3 -1
  50. package/src/types.ts +88 -0
  51. package/src/vite-env.d.ts +3 -0
  52. package/src/vwrConfig.test.ts +2 -2
  53. package/src/vwrConfig.ts +202 -199
  54. package/eslint.config.mjs +0 -23
  55. package/scripts/build.js +0 -2
  56. package/scripts/build.ts +0 -207
  57. package/tsconfig.eslint.json +0 -16
  58. package/tsconfig.json +0 -17
  59. package/vite.config.ts +0 -24
  60. package/vitest.config.ts +0 -8
@@ -3,7 +3,10 @@ export interface EnvConfig {
3
3
  vwrUrl: string
4
4
  configUrl: string
5
5
  configFile: string
6
+ platformApiUrl: string
7
+ platformAuthApiUrl: string
6
8
  amplitudeKey: string // Used for amplitude flag fetch, not part of VWRConfig
9
+ trustedOrigins?: string[]
7
10
  }
8
11
 
9
12
  const CONFIG_URL_DEFAULT = "https://vwr.volley.tv/config/"
@@ -15,22 +18,36 @@ const prodConfig: EnvConfig = {
15
18
  vwrUrl: `https://vwr.volley.tv/${VWR_URL_PATH_DEFAULT}`,
16
19
  configUrl: CONFIG_URL_DEFAULT,
17
20
  configFile: CONFIG_FILE_DEFAULT,
21
+ platformApiUrl: "https://platform.volley-services.net",
22
+ platformAuthApiUrl: "https://auth.volley.tv",
18
23
  amplitudeKey: "",
19
24
  }
20
25
 
21
26
  export const ENV_DEFAULTS: Record<string, EnvConfig> = {
22
27
  local: {
23
- hubUrl: "http://localhost:5173",
24
- vwrUrl: "http://localhost:5174/vwr.js",
25
- configUrl: "http://localhost:5174/config/",
26
- configFile: CONFIG_FILE_DEFAULT,
28
+ hubUrl: import.meta.env.VITE_HUB_URL || "http://localhost:5173",
29
+ vwrUrl: import.meta.env.VITE_VWR_URL || "http://localhost:5174/vwr.js",
30
+ configUrl:
31
+ import.meta.env.VITE_CONFIG_URL || "http://localhost:5174/config/",
32
+ configFile: import.meta.env.VITE_CONFIG_FILE || CONFIG_FILE_DEFAULT,
33
+ platformApiUrl:
34
+ import.meta.env.VITE_PLATFORM_API_URL ||
35
+ "https://platform-dev.volley-services.net",
36
+ platformAuthApiUrl:
37
+ import.meta.env.VITE_PLATFORM_AUTH_API_URL ||
38
+ "https://auth-dev.volley.tv",
27
39
  amplitudeKey: "client-uJJVW3zKPC1G9kqPhUumLnZN6eaY42iQ",
40
+ trustedOrigins: import.meta.env.VITE_TRUSTED_ORIGINS?.split(",").filter(
41
+ Boolean
42
+ ),
28
43
  },
29
44
  dev: {
30
45
  hubUrl: "https://game-clients-dev.volley.tv/hub",
31
46
  vwrUrl: `https://vwr.volley.tv/dev/${VWR_URL_PATH_DEFAULT}`,
32
47
  configUrl: CONFIG_URL_DEFAULT,
33
48
  configFile: CONFIG_FILE_DEFAULT,
49
+ platformApiUrl: "https://platform-dev.volley-services.net",
50
+ platformAuthApiUrl: "https://auth-dev.volley.tv",
34
51
  amplitudeKey: "client-uJJVW3zKPC1G9kqPhUumLnZN6eaY42iQ",
35
52
  },
36
53
  staging: {
@@ -38,6 +55,8 @@ export const ENV_DEFAULTS: Record<string, EnvConfig> = {
38
55
  vwrUrl: `https://vwr.volley.tv/staging/${VWR_URL_PATH_DEFAULT}`,
39
56
  configUrl: CONFIG_URL_DEFAULT,
40
57
  configFile: CONFIG_FILE_DEFAULT,
58
+ platformApiUrl: "https://platform-staging.volley-services.net",
59
+ platformAuthApiUrl: "https://auth-staging.volley.tv",
41
60
  amplitudeKey: "",
42
61
  },
43
62
  prod: prodConfig,
@@ -6,8 +6,9 @@ describe("getDeviceId", () => {
6
6
  beforeEach(() => {
7
7
  vi.clearAllMocks()
8
8
  // Clean up window properties
9
- delete (window as any).DeviceInfo
10
- delete (window as any).NativeBridge
9
+ delete (window as any).Capacitor
10
+ delete (window as any).iosAppContext
11
+ delete (window as any).androidAppContext
11
12
  delete (window as any).webapis
12
13
  delete (window as any).webOSDev
13
14
  delete (window as any).webOS
@@ -15,21 +16,26 @@ describe("getDeviceId", () => {
15
16
 
16
17
  afterEach(() => {
17
18
  vi.restoreAllMocks()
18
- delete (window as any).DeviceInfo
19
- delete (window as any).NativeBridge
19
+ delete (window as any).Capacitor
20
+ delete (window as any).iosAppContext
21
+ delete (window as any).androidAppContext
20
22
  delete (window as any).webapis
21
23
  delete (window as any).webOSDev
22
24
  delete (window as any).webOS
23
25
  })
24
26
 
25
27
  describe("FIRE_TV platform", () => {
26
- it("returns device ID from DeviceInfo.getAndroidId when available", async () => {
28
+ it("returns device ID from Capacitor DeviceInfo.getAndroidId when available", async () => {
27
29
  const mockAndroidId = "firetv-android-id-123"
28
- Object.defineProperty(window, "DeviceInfo", {
30
+ Object.defineProperty(window, "Capacitor", {
29
31
  value: {
30
- getAndroidId: vi
31
- .fn()
32
- .mockResolvedValue({ androidId: mockAndroidId }),
32
+ Plugins: {
33
+ DeviceInfo: {
34
+ getAndroidId: vi.fn().mockResolvedValue({
35
+ androidId: mockAndroidId,
36
+ }),
37
+ },
38
+ },
33
39
  },
34
40
  writable: true,
35
41
  configurable: true,
@@ -40,11 +46,17 @@ describe("getDeviceId", () => {
40
46
  })
41
47
 
42
48
  it("returns null when DeviceInfo throws error", async () => {
43
- Object.defineProperty(window, "DeviceInfo", {
49
+ Object.defineProperty(window, "Capacitor", {
44
50
  value: {
45
- getAndroidId: vi
46
- .fn()
47
- .mockRejectedValue(new Error("DeviceInfo error")),
51
+ Plugins: {
52
+ DeviceInfo: {
53
+ getAndroidId: vi
54
+ .fn()
55
+ .mockRejectedValue(
56
+ new Error("DeviceInfo error")
57
+ ),
58
+ },
59
+ },
48
60
  },
49
61
  writable: true,
50
62
  configurable: true,
@@ -55,9 +67,15 @@ describe("getDeviceId", () => {
55
67
  })
56
68
 
57
69
  it("returns null when DeviceInfo returns empty", async () => {
58
- Object.defineProperty(window, "DeviceInfo", {
70
+ Object.defineProperty(window, "Capacitor", {
59
71
  value: {
60
- getAndroidId: vi.fn().mockResolvedValue({ androidId: "" }),
72
+ Plugins: {
73
+ DeviceInfo: {
74
+ getAndroidId: vi
75
+ .fn()
76
+ .mockResolvedValue({ androidId: "" }),
77
+ },
78
+ },
61
79
  },
62
80
  writable: true,
63
81
  configurable: true,
@@ -147,33 +165,77 @@ describe("getDeviceId", () => {
147
165
  })
148
166
  })
149
167
 
150
- describe("MOBILE platform", () => {
151
- it("returns device ID from NativeBridge when available", async () => {
152
- const mockDeviceId = "native-device-123"
153
- Object.defineProperty(window, "NativeBridge", {
168
+ describe("IOS_MOBILE platform", () => {
169
+ it("returns device ID from iosAppContext when available", async () => {
170
+ const mockDeviceId = "ios-device-123"
171
+ Object.defineProperty(window, "iosAppContext", {
172
+ value: {
173
+ phoneDeviceId: mockDeviceId,
174
+ },
175
+ writable: true,
176
+ configurable: true,
177
+ })
178
+
179
+ const result = await getDeviceId("IOS_MOBILE")
180
+ expect(result).toBe(mockDeviceId)
181
+ })
182
+
183
+ it("returns null when no app context is available", async () => {
184
+ const result = await getDeviceId("IOS_MOBILE")
185
+ expect(result).toBeNull()
186
+ })
187
+
188
+ it("returns null when phoneDeviceId is empty", async () => {
189
+ Object.defineProperty(window, "iosAppContext", {
190
+ value: {
191
+ phoneDeviceId: "",
192
+ },
193
+ writable: true,
194
+ configurable: true,
195
+ })
196
+
197
+ const result = await getDeviceId("IOS_MOBILE")
198
+ expect(result).toBeNull()
199
+ })
200
+ })
201
+
202
+ describe("ANDROID_MOBILE platform", () => {
203
+ it("returns device ID from androidAppContext when available", async () => {
204
+ const mockDeviceId = "android-device-123"
205
+ Object.defineProperty(window, "androidAppContext", {
154
206
  value: {
155
- getDeviceId: vi.fn().mockResolvedValue(mockDeviceId),
207
+ phoneDeviceId: mockDeviceId,
156
208
  },
157
209
  writable: true,
158
210
  configurable: true,
159
211
  })
160
212
 
161
- const result = await getDeviceId("MOBILE")
213
+ const result = await getDeviceId("ANDROID_MOBILE")
162
214
  expect(result).toBe(mockDeviceId)
163
215
  })
164
216
 
165
- it("returns null when NativeBridge throws error", async () => {
166
- Object.defineProperty(window, "NativeBridge", {
217
+ it("prefers iosAppContext over androidAppContext", async () => {
218
+ Object.defineProperty(window, "iosAppContext", {
219
+ value: {
220
+ phoneDeviceId: "ios-id",
221
+ },
222
+ writable: true,
223
+ configurable: true,
224
+ })
225
+ Object.defineProperty(window, "androidAppContext", {
167
226
  value: {
168
- getDeviceId: vi
169
- .fn()
170
- .mockRejectedValue(new Error("Native error")),
227
+ phoneDeviceId: "android-id",
171
228
  },
172
229
  writable: true,
173
230
  configurable: true,
174
231
  })
175
232
 
176
- const result = await getDeviceId("MOBILE")
233
+ const result = await getDeviceId("ANDROID_MOBILE")
234
+ expect(result).toBe("ios-id")
235
+ })
236
+
237
+ it("returns null when no app context is available", async () => {
238
+ const result = await getDeviceId("ANDROID_MOBILE")
177
239
  expect(result).toBeNull()
178
240
  })
179
241
  })
@@ -1,4 +1,5 @@
1
1
  import { defaultLogger, type Logger } from "./logger"
2
+ import type { LGDeviceIdResponse, MobileExtendedWindow } from "./types"
2
3
 
3
4
  /**
4
5
  * Get a unique device identifier for the current platform.
@@ -7,12 +8,12 @@ import { defaultLogger, type Logger } from "./logger"
7
8
  *
8
9
  * Platform handling:
9
10
  * - FireTV: DeviceInfo (Capacitor plugin)
10
- * - Android/iOS: NativeBridge
11
+ * - Android/iOS: window.iosAppContext / window.androidAppContext (phoneDeviceId)
11
12
  * - Samsung TV: webapis
12
13
  * - LG TV: webOS Luna service
13
14
  * - Web: localStorage (with generated UUID fallback)
14
15
  *
15
- * @param platform - Platform identifier ('FIRE_TV', 'SAMSUNG_TV', 'LG_TV', 'MOBILE', 'WEB')
16
+ * @param platform - Platform identifier ('FIRE_TV', 'SAMSUNG_TV', 'LG_TV', 'ANDROID_MOBILE', 'IOS_MOBILE', 'WEB')
16
17
  * @param logger - Optional logger for error reporting. Defaults to defaultLogger.
17
18
  * @returns A promise that resolves to a unique device identifier string, or null if retrieval fails
18
19
  *
@@ -36,7 +37,8 @@ export async function getDeviceId(
36
37
  return await getSamsungDeviceId(logger)
37
38
  case "LG_TV":
38
39
  return await getLGDeviceId(logger)
39
- case "MOBILE": // iOS and Android
40
+ case "ANDROID_MOBILE":
41
+ case "IOS_MOBILE":
40
42
  return await getMobileDeviceId(logger)
41
43
  case "WEB":
42
44
  return getLocalStorageDeviceId()
@@ -84,24 +86,40 @@ async function getFireTVDeviceId(logger: Logger): Promise<string | null> {
84
86
  }
85
87
 
86
88
  /**
87
- * Attempt to get device ID from Native Bridge (Android/iOS)
89
+ * Attempt to get device ID from mobile app context (Android/iOS)
90
+ *
91
+ * iOS exposes phoneDeviceId via window.iosAppContext
92
+ * Android exposes phoneDeviceId via window.androidAppContext (also check window.top for iframes)
88
93
  */
89
- async function getMobileDeviceId(logger: Logger): Promise<string | null> {
94
+ function getMobileDeviceId(logger: Logger): string | null {
95
+ // Try iOS first
96
+ const iosId = (window as MobileExtendedWindow).iosAppContext?.phoneDeviceId
97
+ if (iosId && iosId.trim()) {
98
+ return iosId
99
+ }
100
+
101
+ // Try Android (check both window and window.top for iframe scenarios)
102
+ const androidContext = (window as MobileExtendedWindow).androidAppContext
90
103
  try {
91
- if (!window.NativeBridge?.getDeviceId) {
92
- return null
104
+ const androidId =
105
+ androidContext?.phoneDeviceId ??
106
+ (window.top as MobileExtendedWindow | null)?.androidAppContext
107
+ ?.phoneDeviceId
108
+ if (androidId && androidId.trim()) {
109
+ return androidId
93
110
  }
94
-
95
- const id = await window.NativeBridge.getDeviceId()
96
- if (id && id.trim()) {
97
- return id
98
- } else {
99
- logger.error("NativeBridge.getDeviceId returned empty")
111
+ } catch {
112
+ // window.top access can throw if cross-origin
113
+ const androidId = androidContext?.phoneDeviceId
114
+ if (androidId && androidId.trim()) {
115
+ return androidId
100
116
  }
101
- } catch (error) {
102
- const message = "NativeBridge.getDeviceId failed:"
103
- logger.error(message, { error })
104
117
  }
118
+
119
+ logger.error("[VWR:MobileDeviceId] phoneDeviceId not found", {
120
+ iosAppContext: !!(window as MobileExtendedWindow).iosAppContext,
121
+ androidAppContext: !!androidContext,
122
+ })
105
123
  return null
106
124
  }
107
125
 
@@ -202,45 +220,4 @@ async function getLGDeviceId(logger: Logger): Promise<string | null> {
202
220
  })
203
221
  }
204
222
 
205
- // Type definitions for LG Luna service response
206
- interface LGDeviceIdResponse {
207
- idList?: Array<{
208
- idValue?: string
209
- }>
210
- }
211
-
212
- // Type augmentation for platform-specific APIs
213
- // Note: Capacitor types are declared in getShellVersion.ts with index signatures
214
- // to allow extensibility. Additional methods used here are accessed via
215
- // the index signatures [key: string]: any
216
- declare global {
217
- interface Window {
218
- DeviceInfo?: {
219
- getAndroidId: () => Promise<{ androidId: string }>
220
- }
221
- NativeBridge?: {
222
- getDeviceId: () => Promise<string>
223
- }
224
- webapis?: {
225
- productinfo?: {
226
- getDuid: () => string
227
- }
228
- }
229
- webOS?: {
230
- service?: {
231
- request: (
232
- uri: string,
233
- options: {
234
- method?: string
235
- parameters?: Record<string, unknown>
236
- onSuccess?: (response: LGDeviceIdResponse) => void
237
- onFailure?: (error: { errorText?: string }) => void
238
- subscribe?: boolean
239
- }
240
- ) => {
241
- cancel: () => void
242
- }
243
- }
244
- }
245
- }
246
- }
223
+ // Types imported from ./types.ts