@volley/vwr-loader 1.0.0-alpha.1
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/README.md +205 -0
- package/dist/amplitudeFlagFetcher.d.ts +23 -0
- package/dist/amplitudeFlagFetcher.d.ts.map +1 -0
- package/dist/amplitudeFlagFetcher.js +60 -0
- package/dist/amplitudeFlagFetcher.js.map +1 -0
- package/dist/cli.js +177 -0
- package/dist/cli.js.map +1 -0
- package/dist/envDefaults.d.ts +9 -0
- package/dist/envDefaults.d.ts.map +1 -0
- package/dist/envDefaults.js +36 -0
- package/dist/envDefaults.js.map +1 -0
- package/dist/getDeviceId.d.ts +65 -0
- package/dist/getDeviceId.d.ts.map +1 -0
- package/dist/getDeviceId.js +196 -0
- package/dist/getDeviceId.js.map +1 -0
- package/dist/getShellVersion.d.ts +34 -0
- package/dist/getShellVersion.d.ts.map +1 -0
- package/dist/getShellVersion.js +84 -0
- package/dist/getShellVersion.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.html +25 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/loadVwr.d.ts +19 -0
- package/dist/loadVwr.d.ts.map +1 -0
- package/dist/loadVwr.js +104 -0
- package/dist/loadVwr.js.map +1 -0
- package/dist/logger.d.ts +7 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +6 -0
- package/dist/logger.js.map +1 -0
- package/dist/main.js +2 -0
- package/dist/main.js.map +1 -0
- package/dist/vwrConfig.d.ts +19 -0
- package/dist/vwrConfig.d.ts.map +1 -0
- package/dist/vwrConfig.js +172 -0
- package/dist/vwrConfig.js.map +1 -0
- package/package.json +54 -0
- package/src/amplitudeFlagFetcher.test.ts +209 -0
- package/src/amplitudeFlagFetcher.ts +88 -0
- package/src/envDefaults.ts +45 -0
- package/src/getDeviceId.test.ts +237 -0
- package/src/getDeviceId.ts +243 -0
- package/src/getShellVersion.test.ts +278 -0
- package/src/getShellVersion.ts +114 -0
- package/src/index.html +25 -0
- package/src/index.ts +8 -0
- package/src/loadVwr.ts +126 -0
- package/src/logger.ts +14 -0
- package/src/main.ts +26 -0
- package/src/vite-env.d.ts +15 -0
- package/src/vwrConfig.test.ts +316 -0
- package/src/vwrConfig.ts +293 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { defaultLogger } from "./logger";
|
|
2
|
+
/**
|
|
3
|
+
* Get a unique device identifier for the current platform.
|
|
4
|
+
*
|
|
5
|
+
* This function attempts to retrieve a device ID from platform-specific APIs.
|
|
6
|
+
*
|
|
7
|
+
* Platform handling:
|
|
8
|
+
* - FireTV: DeviceInfo (Capacitor plugin)
|
|
9
|
+
* - Android/iOS: NativeBridge
|
|
10
|
+
* - Samsung TV: webapis
|
|
11
|
+
* - LG TV: webOS Luna service
|
|
12
|
+
* - Web: localStorage (with generated UUID fallback)
|
|
13
|
+
*
|
|
14
|
+
* @param platform - Platform identifier ('FIRE_TV', 'SAMSUNG_TV', 'LG_TV', 'ANDROID_MOBILE', 'IOS_MOBILE', 'WEB')
|
|
15
|
+
* @param logger - Optional logger for error reporting. Defaults to defaultLogger.
|
|
16
|
+
* @returns A promise that resolves to a unique device identifier string, or null if retrieval fails
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const deviceId = await getDeviceId('SAMSUNG_TV', logger)
|
|
21
|
+
* if (!deviceId) {
|
|
22
|
+
* // Handle error
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export async function getDeviceId(platform, logger = defaultLogger) {
|
|
27
|
+
const normalizedPlatform = platform.toUpperCase();
|
|
28
|
+
switch (normalizedPlatform) {
|
|
29
|
+
case "FIRE_TV":
|
|
30
|
+
return await getFireTVDeviceId(logger);
|
|
31
|
+
case "SAMSUNG_TV":
|
|
32
|
+
return await getSamsungDeviceId(logger);
|
|
33
|
+
case "LG_TV":
|
|
34
|
+
return await getLGDeviceId(logger);
|
|
35
|
+
case "ANDROID_MOBILE":
|
|
36
|
+
case "IOS_MOBILE":
|
|
37
|
+
case "MOBILE": // Legacy/Generic
|
|
38
|
+
return await getMobileDeviceId(logger);
|
|
39
|
+
case "WEB":
|
|
40
|
+
return getLocalStorageDeviceId();
|
|
41
|
+
default:
|
|
42
|
+
const message = `[getDeviceId] Unknown platform: ${platform}`;
|
|
43
|
+
logger.error(message);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get or create device ID from localStorage (for Web platform)
|
|
49
|
+
*/
|
|
50
|
+
function getLocalStorageDeviceId() {
|
|
51
|
+
let deviceId = localStorage.getItem("volley_device_id");
|
|
52
|
+
if (!deviceId) {
|
|
53
|
+
deviceId = crypto.randomUUID();
|
|
54
|
+
localStorage.setItem("volley_device_id", deviceId);
|
|
55
|
+
}
|
|
56
|
+
return deviceId;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Attempt to get device ID from Capacitor DeviceInfo plugin (FireTV)
|
|
60
|
+
*/
|
|
61
|
+
async function getFireTVDeviceId(logger) {
|
|
62
|
+
var _a;
|
|
63
|
+
try {
|
|
64
|
+
if (!((_a = window.DeviceInfo) === null || _a === void 0 ? void 0 : _a.getAndroidId)) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const result = await window.DeviceInfo.getAndroidId();
|
|
68
|
+
if ((result === null || result === void 0 ? void 0 : result.androidId) && result.androidId.trim()) {
|
|
69
|
+
return result.androidId;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
logger.error("DeviceInfo.getAndroidId returned empty");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
const message = "DeviceInfo.getAndroidId failed:";
|
|
77
|
+
logger.error(message, { error });
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Attempt to get device ID from Native Bridge (Android/iOS)
|
|
83
|
+
*/
|
|
84
|
+
async function getMobileDeviceId(logger) {
|
|
85
|
+
var _a;
|
|
86
|
+
try {
|
|
87
|
+
if (!((_a = window.NativeBridge) === null || _a === void 0 ? void 0 : _a.getDeviceId)) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const id = await window.NativeBridge.getDeviceId();
|
|
91
|
+
if (id && id.trim()) {
|
|
92
|
+
return id;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
logger.error("NativeBridge.getDeviceId returned empty");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
const message = "NativeBridge.getDeviceId failed:";
|
|
100
|
+
logger.error(message, { error });
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Attempt to get device ID from Samsung TV webapis
|
|
106
|
+
*/
|
|
107
|
+
async function getSamsungDeviceId(logger) {
|
|
108
|
+
var _a, _b;
|
|
109
|
+
try {
|
|
110
|
+
if (!((_b = (_a = window.webapis) === null || _a === void 0 ? void 0 : _a.productinfo) === null || _b === void 0 ? void 0 : _b.getDuid)) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const id = window.webapis.productinfo.getDuid();
|
|
114
|
+
if (id && id.trim()) {
|
|
115
|
+
return id;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
logger.error("Samsung webapis.getDuid returned empty");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
const message = "Samsung webapis.getDuid failed:";
|
|
123
|
+
logger.error(message, { error });
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Attempt to get device ID from LG TV using Luna Service.
|
|
129
|
+
*
|
|
130
|
+
* This implementation is copied from PSDK's LGTVDeviceInfo to ensure
|
|
131
|
+
* the shell and SDK return the exact same device ID.
|
|
132
|
+
*
|
|
133
|
+
* TODO: In the future, PSDK should import this function from vwr-loader
|
|
134
|
+
* to maintain a single source of truth for LG device ID retrieval.
|
|
135
|
+
*/
|
|
136
|
+
const LG_LUNA_SERVICE_TIMEOUT = 5000;
|
|
137
|
+
async function getLGDeviceId(logger) {
|
|
138
|
+
var _a, _b;
|
|
139
|
+
if (!((_b = (_a = window.webOS) === null || _a === void 0 ? void 0 : _a.service) === null || _b === void 0 ? void 0 : _b.request)) {
|
|
140
|
+
const message = "LG webOS service request not available";
|
|
141
|
+
logger.error(message);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
return new Promise((resolve) => {
|
|
145
|
+
var _a, _b;
|
|
146
|
+
let timeoutId;
|
|
147
|
+
let request;
|
|
148
|
+
let resolved = false;
|
|
149
|
+
const cleanup = () => {
|
|
150
|
+
if (timeoutId) {
|
|
151
|
+
clearTimeout(timeoutId);
|
|
152
|
+
timeoutId = undefined;
|
|
153
|
+
}
|
|
154
|
+
request === null || request === void 0 ? void 0 : request.cancel();
|
|
155
|
+
};
|
|
156
|
+
const finish = (value) => {
|
|
157
|
+
if (resolved)
|
|
158
|
+
return;
|
|
159
|
+
resolved = true;
|
|
160
|
+
cleanup();
|
|
161
|
+
resolve(value);
|
|
162
|
+
};
|
|
163
|
+
timeoutId = setTimeout(() => {
|
|
164
|
+
const message = "LG Luna service timed out";
|
|
165
|
+
logger.error(message);
|
|
166
|
+
finish(null);
|
|
167
|
+
}, LG_LUNA_SERVICE_TIMEOUT);
|
|
168
|
+
try {
|
|
169
|
+
request = (_b = (_a = window.webOS) === null || _a === void 0 ? void 0 : _a.service) === null || _b === void 0 ? void 0 : _b.request("luna://com.webos.service.sm", {
|
|
170
|
+
method: "deviceid/getIDs",
|
|
171
|
+
parameters: { idType: ["LGUDID"] },
|
|
172
|
+
onSuccess: (response) => {
|
|
173
|
+
var _a, _b;
|
|
174
|
+
const deviceId = (_b = (_a = response.idList) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.idValue;
|
|
175
|
+
if (!deviceId) {
|
|
176
|
+
const message = "LG Luna service returned no device ID";
|
|
177
|
+
logger.error(message);
|
|
178
|
+
}
|
|
179
|
+
finish(deviceId || null);
|
|
180
|
+
},
|
|
181
|
+
onFailure: (error) => {
|
|
182
|
+
const message = "LG Luna service failed:";
|
|
183
|
+
logger.error(message, { error });
|
|
184
|
+
finish(null);
|
|
185
|
+
},
|
|
186
|
+
subscribe: false,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
const message = "LG Luna service request threw error:";
|
|
191
|
+
logger.error(message, { error });
|
|
192
|
+
finish(null);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=getDeviceId.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getDeviceId.js","sourceRoot":"","sources":["../src/getDeviceId.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Logger } from "./logger";
|
|
2
|
+
/**
|
|
3
|
+
* Retrieve shell app version for different platforms.
|
|
4
|
+
*
|
|
5
|
+
* Platform-specific methods:
|
|
6
|
+
* - SAMSUNG_TV: Tizen Application API `tizen.application.getAppInfo().version`
|
|
7
|
+
* - LG_TV: webOS Application API `webOS.fetchAppInfo()`
|
|
8
|
+
* - FIRE_TV: Native bridge via Capacitor DeviceInfo plugin
|
|
9
|
+
* - ANDROID_MOBILE/IOS_MOBILE: Native bridge (future implementation)
|
|
10
|
+
* - WEB/Unknown: Returns 'unknown'
|
|
11
|
+
*
|
|
12
|
+
* @param platform - Platform identifier (SAMSUNG_TV, LG_TV, FIRE_TV, ANDROID_MOBILE, IOS_MOBILE, WEB)
|
|
13
|
+
* @param logger - Optional logger for warning reporting. Defaults to defaultLogger.
|
|
14
|
+
* @returns Shell version string or 'unknown' if not available
|
|
15
|
+
*/
|
|
16
|
+
export declare function getShellVersion(platform: string, logger?: Logger): Promise<string>;
|
|
17
|
+
declare global {
|
|
18
|
+
interface Window {
|
|
19
|
+
Capacitor?: {
|
|
20
|
+
Plugins?: {
|
|
21
|
+
DeviceInfo?: {
|
|
22
|
+
getDeviceInfo(): Promise<{
|
|
23
|
+
versionName?: string;
|
|
24
|
+
[key: string]: any;
|
|
25
|
+
}>;
|
|
26
|
+
[key: string]: any;
|
|
27
|
+
};
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
};
|
|
30
|
+
[key: string]: any;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=getShellVersion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getShellVersion.d.ts","sourceRoot":"","sources":["../src/getShellVersion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAErD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACjC,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAsB,GAC/B,OAAO,CAAC,MAAM,CAAC,CA2EjB;AAGD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM;QACZ,SAAS,CAAC,EAAE;YACR,OAAO,CAAC,EAAE;gBACN,UAAU,CAAC,EAAE;oBACT,aAAa,IAAI,OAAO,CAAC;wBACrB,WAAW,CAAC,EAAE,MAAM,CAAA;wBACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;qBACrB,CAAC,CAAA;oBACF,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;iBACrB,CAAA;gBACD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;aACrB,CAAA;YACD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SACrB,CAAA;KACJ;CACJ"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { defaultLogger } from "./logger";
|
|
2
|
+
/**
|
|
3
|
+
* Retrieve shell app version for different platforms.
|
|
4
|
+
*
|
|
5
|
+
* Platform-specific methods:
|
|
6
|
+
* - SAMSUNG_TV: Tizen Application API `tizen.application.getAppInfo().version`
|
|
7
|
+
* - LG_TV: webOS Application API `webOS.fetchAppInfo()`
|
|
8
|
+
* - FIRE_TV: Native bridge via Capacitor DeviceInfo plugin
|
|
9
|
+
* - ANDROID_MOBILE/IOS_MOBILE: Native bridge (future implementation)
|
|
10
|
+
* - WEB/Unknown: Returns 'unknown'
|
|
11
|
+
*
|
|
12
|
+
* @param platform - Platform identifier (SAMSUNG_TV, LG_TV, FIRE_TV, ANDROID_MOBILE, IOS_MOBILE, WEB)
|
|
13
|
+
* @param logger - Optional logger for warning reporting. Defaults to defaultLogger.
|
|
14
|
+
* @returns Shell version string or 'unknown' if not available
|
|
15
|
+
*/
|
|
16
|
+
export async function getShellVersion(platform, logger = defaultLogger) {
|
|
17
|
+
var _a, _b, _c, _d;
|
|
18
|
+
try {
|
|
19
|
+
const normalizedPlatform = platform.toUpperCase();
|
|
20
|
+
// Samsung TV: Get version from Tizen Application API
|
|
21
|
+
if (normalizedPlatform === "SAMSUNG_TV") {
|
|
22
|
+
if (typeof window !== "undefined" && window.tizen) {
|
|
23
|
+
const tizen = window.tizen;
|
|
24
|
+
if ((_a = tizen.application) === null || _a === void 0 ? void 0 : _a.getAppInfo) {
|
|
25
|
+
const appInfo = tizen.application.getAppInfo();
|
|
26
|
+
return (_b = appInfo === null || appInfo === void 0 ? void 0 : appInfo.version) !== null && _b !== void 0 ? _b : "unknown";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return "unknown";
|
|
30
|
+
}
|
|
31
|
+
// LG TV: Get version from webOS API
|
|
32
|
+
// Note: webOS.fetchAppInfo(callback, path) takes a single callback and optional path.
|
|
33
|
+
// The callback receives the parsed appinfo.json or undefined on failure.
|
|
34
|
+
if (normalizedPlatform === "LG_TV") {
|
|
35
|
+
if (typeof window !== "undefined" && window.webOS) {
|
|
36
|
+
const webOS = window.webOS;
|
|
37
|
+
if (webOS.fetchAppInfo) {
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
webOS.fetchAppInfo((appInfo) => {
|
|
40
|
+
var _a;
|
|
41
|
+
resolve((_a = appInfo === null || appInfo === void 0 ? void 0 : appInfo.version) !== null && _a !== void 0 ? _a : "unknown");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return "unknown";
|
|
47
|
+
}
|
|
48
|
+
// FireTV: Get version from Capacitor DeviceInfo plugin
|
|
49
|
+
if (normalizedPlatform === "FIRE_TV") {
|
|
50
|
+
// Check if Capacitor is available
|
|
51
|
+
if (typeof window !== "undefined" && window.Capacitor) {
|
|
52
|
+
const Capacitor = window.Capacitor;
|
|
53
|
+
const DeviceInfo = (_c = Capacitor.Plugins) === null || _c === void 0 ? void 0 : _c.DeviceInfo;
|
|
54
|
+
if (DeviceInfo === null || DeviceInfo === void 0 ? void 0 : DeviceInfo.getDeviceInfo) {
|
|
55
|
+
const deviceInfo = await DeviceInfo.getDeviceInfo();
|
|
56
|
+
return (_d = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.versionName) !== null && _d !== void 0 ? _d : "unknown";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return "unknown";
|
|
60
|
+
}
|
|
61
|
+
// Mobile: Future implementation via native bridge
|
|
62
|
+
if (normalizedPlatform === "ANDROID_MOBILE" ||
|
|
63
|
+
normalizedPlatform === "IOS_MOBILE" ||
|
|
64
|
+
normalizedPlatform === "MOBILE") {
|
|
65
|
+
// TODO: Implement native bridge version retrieval when available
|
|
66
|
+
return "unknown";
|
|
67
|
+
}
|
|
68
|
+
// Web platform: Check for injected version at build time
|
|
69
|
+
if (normalizedPlatform === "WEB") {
|
|
70
|
+
if (typeof import.meta.env !== "undefined" &&
|
|
71
|
+
import.meta.env.VITE_SHELL_VERSION) {
|
|
72
|
+
return import.meta.env.VITE_SHELL_VERSION;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Other unknown platforms
|
|
76
|
+
return "unknown";
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
const message = "[Shell] Failed to get shell version:";
|
|
80
|
+
logger.warn(message, { error });
|
|
81
|
+
return "unknown";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=getShellVersion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getShellVersion.js","sourceRoot":"","sources":["../src/getShellVersion.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type { AmplitudeConfig, FlagResult } from "./amplitudeFlagFetcher";
|
|
2
|
+
export { fetchAmplitudeFlags } from "./amplitudeFlagFetcher";
|
|
3
|
+
export { getDeviceId } from "./getDeviceId";
|
|
4
|
+
export { getShellVersion } from "./getShellVersion";
|
|
5
|
+
export type { Logger } from "./loadVwr";
|
|
6
|
+
export { loadVwr } from "./loadVwr";
|
|
7
|
+
export type { VWRConfig, VWRConfigRequest } from "./vwrConfig";
|
|
8
|
+
export { getVWRConfig } from "./vwrConfig";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,YAAY,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA"}
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Volley</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
background: #010020;
|
|
12
|
+
}
|
|
13
|
+
#loading {
|
|
14
|
+
color: #ffec37;
|
|
15
|
+
text-align: center;
|
|
16
|
+
padding-top: 40vh;
|
|
17
|
+
font-family: sans-serif;
|
|
18
|
+
}
|
|
19
|
+
</style>
|
|
20
|
+
<script type="module" crossorigin src="/main.js"></script>
|
|
21
|
+
</head>
|
|
22
|
+
<body>
|
|
23
|
+
<div id="loading">Loading...</div>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { fetchAmplitudeFlags } from "./amplitudeFlagFetcher";
|
|
2
|
+
export { getDeviceId } from "./getDeviceId";
|
|
3
|
+
export { getShellVersion } from "./getShellVersion";
|
|
4
|
+
export { loadVwr } from "./loadVwr";
|
|
5
|
+
export { getVWRConfig } from "./vwrConfig";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Logger } from "./logger";
|
|
2
|
+
export type { Logger };
|
|
3
|
+
/**
|
|
4
|
+
* Load VWR runtime.
|
|
5
|
+
*
|
|
6
|
+
* Optimized flow: checks vwr-enabled flag FIRST using baked-in Amplitude key,
|
|
7
|
+
* before doing any config fetches. For flag-OFF users (100% at initial launch),
|
|
8
|
+
* this reduces startup latency from ~2-4s to ~500ms by skipping config fetches.
|
|
9
|
+
*
|
|
10
|
+
* Flow:
|
|
11
|
+
* 1. Get deviceId, shellVersion (fast, local)
|
|
12
|
+
* 2. Check vwr-enabled flag (single request, ~500ms)
|
|
13
|
+
* 3. If OFF → throw immediately (no config fetches)
|
|
14
|
+
* 4. If ON → fetch config, load VWR module, initialize
|
|
15
|
+
*
|
|
16
|
+
* @param logger - Optional logger, defaults to console
|
|
17
|
+
*/
|
|
18
|
+
export declare const loadVwr: (logger?: Logger) => Promise<void>;
|
|
19
|
+
//# sourceMappingURL=loadVwr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadVwr.d.ts","sourceRoot":"","sources":["../src/loadVwr.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAcrD,YAAY,EAAE,MAAM,EAAE,CAAA;AAEtB;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,OAAO,GAAU,SAAQ,MAAsB,kBA0F3D,CAAA"}
|
package/dist/loadVwr.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { fetchAmplitudeFlags } from "./amplitudeFlagFetcher";
|
|
2
|
+
import { ENV_DEFAULTS } from "./envDefaults";
|
|
3
|
+
import { getDeviceId } from "./getDeviceId";
|
|
4
|
+
import { getShellVersion } from "./getShellVersion";
|
|
5
|
+
import { defaultLogger } from "./logger";
|
|
6
|
+
import { getVWRConfig, validateConfig } from "./vwrConfig";
|
|
7
|
+
// Vite injects these at build time
|
|
8
|
+
const ENVIRONMENT = import.meta.env.VITE_ENVIRONMENT;
|
|
9
|
+
const PLATFORM = import.meta.env.VITE_PLATFORM;
|
|
10
|
+
const CONFIG_URL = import.meta.env.VITE_CONFIG_URL;
|
|
11
|
+
const CONFIG_FILE = import.meta.env.VITE_CONFIG_FILE;
|
|
12
|
+
// AMPLITUDE_KEY can be optionally injected at build time (via build.ts script)
|
|
13
|
+
// Falls back to envDefaults if not injected (e.g., vite.config.dev.ts)
|
|
14
|
+
const AMPLITUDE_KEY = import.meta.env.VITE_AMPLITUDE_DEPLOYMENT_KEY;
|
|
15
|
+
/**
|
|
16
|
+
* Load VWR runtime.
|
|
17
|
+
*
|
|
18
|
+
* Optimized flow: checks vwr-enabled flag FIRST using baked-in Amplitude key,
|
|
19
|
+
* before doing any config fetches. For flag-OFF users (100% at initial launch),
|
|
20
|
+
* this reduces startup latency from ~2-4s to ~500ms by skipping config fetches.
|
|
21
|
+
*
|
|
22
|
+
* Flow:
|
|
23
|
+
* 1. Get deviceId, shellVersion (fast, local)
|
|
24
|
+
* 2. Check vwr-enabled flag (single request, ~500ms)
|
|
25
|
+
* 3. If OFF → throw immediately (no config fetches)
|
|
26
|
+
* 4. If ON → fetch config, load VWR module, initialize
|
|
27
|
+
*
|
|
28
|
+
* @param logger - Optional logger, defaults to console
|
|
29
|
+
*/
|
|
30
|
+
export const loadVwr = async (logger = defaultLogger) => {
|
|
31
|
+
if (!ENVIRONMENT || !PLATFORM || !CONFIG_URL || !CONFIG_FILE) {
|
|
32
|
+
throw new Error("[Shell] Build config not injected properly");
|
|
33
|
+
}
|
|
34
|
+
const deviceId = await getDeviceId(PLATFORM, logger);
|
|
35
|
+
if (!deviceId) {
|
|
36
|
+
const message = `[Shell] Failed to retrieve device ID for platform: ${PLATFORM}`;
|
|
37
|
+
logger.error(message);
|
|
38
|
+
throw new Error(message);
|
|
39
|
+
}
|
|
40
|
+
const shellVersion = await getShellVersion(PLATFORM, logger);
|
|
41
|
+
// Get amplitude key: injected at build time OR from envDefaults
|
|
42
|
+
// Precedence: build-time injection > envDefaults
|
|
43
|
+
let amplitudeKey = AMPLITUDE_KEY;
|
|
44
|
+
if (!amplitudeKey) {
|
|
45
|
+
const envDefaults = ENV_DEFAULTS[ENVIRONMENT];
|
|
46
|
+
if (!envDefaults) {
|
|
47
|
+
throw new Error(`[Shell] Unknown environment: ${ENVIRONMENT}`);
|
|
48
|
+
}
|
|
49
|
+
amplitudeKey = envDefaults.amplitudeKey;
|
|
50
|
+
}
|
|
51
|
+
// FAST PATH: Check flag first using amplitude key
|
|
52
|
+
// This avoids config fetches for flag-OFF users (majority at launch)
|
|
53
|
+
const flags = await fetchAmplitudeFlags(deviceId, PLATFORM, {
|
|
54
|
+
apiKey: amplitudeKey,
|
|
55
|
+
timeout: 2000,
|
|
56
|
+
}, shellVersion);
|
|
57
|
+
logger.info("[Shell] Flags fetched", { flags });
|
|
58
|
+
if (!flags["vwr-enabled"]) {
|
|
59
|
+
// Flag OFF: skip all config fetches, fail fast
|
|
60
|
+
throw new Error("[Shell] VWR not enabled via Amplitude flags");
|
|
61
|
+
}
|
|
62
|
+
// Flag ON: proceed with full config loading
|
|
63
|
+
logger.info("[Shell] VWR flag enabled, fetching config...");
|
|
64
|
+
const vwrConfigRequest = {
|
|
65
|
+
configUrl: CONFIG_URL,
|
|
66
|
+
configFile: CONFIG_FILE,
|
|
67
|
+
platform: PLATFORM,
|
|
68
|
+
deviceId: deviceId,
|
|
69
|
+
environment: ENVIRONMENT,
|
|
70
|
+
shellVersion: shellVersion,
|
|
71
|
+
};
|
|
72
|
+
const vwrConfig = await getVWRConfig(vwrConfigRequest, logger);
|
|
73
|
+
if (!validateConfig(vwrConfig)) {
|
|
74
|
+
throw new Error("Invalid config, falling back to default hub");
|
|
75
|
+
}
|
|
76
|
+
logger.info("[Shell] VWR enabled, loading module", {
|
|
77
|
+
vwrUrl: vwrConfig.vwrUrl,
|
|
78
|
+
});
|
|
79
|
+
try {
|
|
80
|
+
const vwr = await import(/* @vite-ignore */ vwrConfig.vwrUrl);
|
|
81
|
+
logger.info("[Shell] VWR module loaded successfully");
|
|
82
|
+
if (typeof vwr.init !== "function") {
|
|
83
|
+
throw new Error("[Shell] VWR module missing init() function");
|
|
84
|
+
}
|
|
85
|
+
await vwr.init({
|
|
86
|
+
hubUrl: vwrConfig.hubUrl,
|
|
87
|
+
launchUrl: vwrConfig.launchUrl,
|
|
88
|
+
platform: PLATFORM,
|
|
89
|
+
deviceId,
|
|
90
|
+
environment: ENVIRONMENT,
|
|
91
|
+
trustedDomains: vwrConfig.trustedDomains,
|
|
92
|
+
nativeShellVersion: shellVersion,
|
|
93
|
+
});
|
|
94
|
+
logger.info("[Shell] VWR initialized successfully");
|
|
95
|
+
}
|
|
96
|
+
catch (vwrError) {
|
|
97
|
+
logger.error("[Shell] VWR load failed", {
|
|
98
|
+
error: vwrError instanceof Error ? vwrError.message : String(vwrError),
|
|
99
|
+
vwrUrl: vwrConfig.vwrUrl,
|
|
100
|
+
});
|
|
101
|
+
throw vwrError; // Re-throw to outer catch for fallback
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=loadVwr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadVwr.js","sourceRoot":"","sources":["../src/loadVwr.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface Logger {
|
|
2
|
+
info: (message: string, context?: Record<string, unknown>) => void;
|
|
3
|
+
warn: (message: string, context?: Record<string, unknown>) => void;
|
|
4
|
+
error: (message: string, context?: Record<string, unknown>) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare const defaultLogger: Logger;
|
|
7
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACnB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IAClE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IAClE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;CACtE;AAED,eAAO,MAAM,aAAa,EAAE,MAO3B,CAAA"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const defaultLogger = {
|
|
2
|
+
info: (message, context) => context ? console.log(message, context) : console.log(message),
|
|
3
|
+
warn: (message, context) => context ? console.warn(message, context) : console.warn(message),
|
|
4
|
+
error: (message, context) => context ? console.error(message, context) : console.error(message),
|
|
5
|
+
};
|
|
6
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,aAAa,GAAW;IACjC,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CACvB,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;IAClE,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CACvB,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;IACpE,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CACxB,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;CACzE,CAAA"}
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(){const o=document.createElement("link").relList;if(o&&o.supports&&o.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))i(e);new MutationObserver(e=>{for(const t of e)if(t.type==="childList")for(const n of t.addedNodes)n.tagName==="LINK"&&n.rel==="modulepreload"&&i(n)}).observe(document,{childList:!0,subtree:!0});function l(e){const t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin==="use-credentials"?t.credentials="include":e.crossOrigin==="anonymous"?t.credentials="omit":t.credentials="same-origin",t}function i(e){if(e.ep)return;e.ep=!0;const t=l(e);fetch(e.href,t)}})();const c={info:(r,o)=>o?console.log(r,o):console.log(r),warn:(r,o)=>o?console.warn(r,o):console.warn(r),error:(r,o)=>o?console.error(r,o):console.error(r)},s=async(r=c)=>{throw new Error("[Shell] Build config not injected properly")},f=void 0,d=void 0;async function u(){try{await s()}catch(r){try{console.error("[Shell] ⚠️ FALLBACK TO HUB - Init failed:",r),window.DD_LOGS&&window.DD_LOGS.logger.error("shell_init_failed",{error:r.message,platform:f})}finally{window.location.href=d}}}u();
|
|
2
|
+
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sources":["../src/logger.ts","../src/loadVwr.ts","../src/main.ts"],"sourcesContent":["export interface Logger {\n info: (message: string, context?: Record<string, unknown>) => void\n warn: (message: string, context?: Record<string, unknown>) => void\n error: (message: string, context?: Record<string, unknown>) => void\n}\n\nexport const defaultLogger: Logger = {\n info: (message, context) =>\n context ? console.log(message, context) : console.log(message),\n warn: (message, context) =>\n context ? console.warn(message, context) : console.warn(message),\n error: (message, context) =>\n context ? console.error(message, context) : console.error(message),\n}\n","import { fetchAmplitudeFlags } from \"./amplitudeFlagFetcher\"\nimport { ENV_DEFAULTS } from \"./envDefaults\"\nimport { getDeviceId } from \"./getDeviceId\"\nimport { getShellVersion } from \"./getShellVersion\"\nimport { defaultLogger, type Logger } from \"./logger\"\nimport type { VWRConfig, VWRConfigRequest } from \"./vwrConfig\"\nimport { getVWRConfig, validateConfig } from \"./vwrConfig\"\n\n// Vite injects these at build time\nconst ENVIRONMENT = import.meta.env.VITE_ENVIRONMENT\nconst PLATFORM = import.meta.env.VITE_PLATFORM\nconst CONFIG_URL = import.meta.env.VITE_CONFIG_URL\nconst CONFIG_FILE = import.meta.env.VITE_CONFIG_FILE\n\n// AMPLITUDE_KEY can be optionally injected at build time (via build.ts script)\n// Falls back to envDefaults if not injected (e.g., vite.config.dev.ts)\nconst AMPLITUDE_KEY = import.meta.env.VITE_AMPLITUDE_DEPLOYMENT_KEY\n\nexport type { Logger }\n\n/**\n * Load VWR runtime.\n *\n * Optimized flow: checks vwr-enabled flag FIRST using baked-in Amplitude key,\n * before doing any config fetches. For flag-OFF users (100% at initial launch),\n * this reduces startup latency from ~2-4s to ~500ms by skipping config fetches.\n *\n * Flow:\n * 1. Get deviceId, shellVersion (fast, local)\n * 2. Check vwr-enabled flag (single request, ~500ms)\n * 3. If OFF → throw immediately (no config fetches)\n * 4. If ON → fetch config, load VWR module, initialize\n *\n * @param logger - Optional logger, defaults to console\n */\nexport const loadVwr = async (logger: Logger = defaultLogger) => {\n if (!ENVIRONMENT || !PLATFORM || !CONFIG_URL || !CONFIG_FILE) {\n throw new Error(\"[Shell] Build config not injected properly\")\n }\n\n const deviceId = await getDeviceId(PLATFORM, logger)\n if (!deviceId) {\n const message = `[Shell] Failed to retrieve device ID for platform: ${PLATFORM}`\n logger.error(message)\n throw new Error(message)\n }\n const shellVersion = await getShellVersion(PLATFORM, logger)\n\n // Get amplitude key: injected at build time OR from envDefaults\n // Precedence: build-time injection > envDefaults\n let amplitudeKey = AMPLITUDE_KEY\n if (!amplitudeKey) {\n const envDefaults = ENV_DEFAULTS[ENVIRONMENT]\n if (!envDefaults) {\n throw new Error(`[Shell] Unknown environment: ${ENVIRONMENT}`)\n }\n amplitudeKey = envDefaults.amplitudeKey\n }\n\n // FAST PATH: Check flag first using amplitude key\n // This avoids config fetches for flag-OFF users (majority at launch)\n const flags = await fetchAmplitudeFlags(\n deviceId,\n PLATFORM,\n {\n apiKey: amplitudeKey,\n timeout: 2000,\n },\n shellVersion\n )\n\n logger.info(\"[Shell] Flags fetched\", { flags })\n\n if (!flags[\"vwr-enabled\"]) {\n // Flag OFF: skip all config fetches, fail fast\n throw new Error(\"[Shell] VWR not enabled via Amplitude flags\")\n }\n\n // Flag ON: proceed with full config loading\n logger.info(\"[Shell] VWR flag enabled, fetching config...\")\n\n const vwrConfigRequest: VWRConfigRequest = {\n configUrl: CONFIG_URL,\n configFile: CONFIG_FILE,\n platform: PLATFORM,\n deviceId: deviceId,\n environment: ENVIRONMENT,\n shellVersion: shellVersion,\n }\n\n const vwrConfig: VWRConfig = await getVWRConfig(vwrConfigRequest, logger)\n\n if (!validateConfig(vwrConfig)) {\n throw new Error(\"Invalid config, falling back to default hub\")\n }\n\n logger.info(\"[Shell] VWR enabled, loading module\", {\n vwrUrl: vwrConfig.vwrUrl,\n })\n try {\n const vwr = await import(/* @vite-ignore */ vwrConfig.vwrUrl)\n logger.info(\"[Shell] VWR module loaded successfully\")\n\n if (typeof vwr.init !== \"function\") {\n throw new Error(\"[Shell] VWR module missing init() function\")\n }\n\n await vwr.init({\n hubUrl: vwrConfig.hubUrl,\n launchUrl: vwrConfig.launchUrl,\n platform: PLATFORM,\n deviceId,\n environment: ENVIRONMENT,\n trustedDomains: vwrConfig.trustedDomains,\n nativeShellVersion: shellVersion,\n })\n logger.info(\"[Shell] VWR initialized successfully\")\n } catch (vwrError) {\n logger.error(\"[Shell] VWR load failed\", {\n error:\n vwrError instanceof Error ? vwrError.message : String(vwrError),\n vwrUrl: vwrConfig.vwrUrl,\n })\n throw vwrError // Re-throw to outer catch for fallback\n }\n}\n","import { loadVwr } from \"./loadVwr\"\n\nconst PLATFORM = import.meta.env.VITE_PLATFORM\nconst HUB_URL = import.meta.env.VITE_HUB_URL\n\nasync function init() {\n try {\n await loadVwr()\n } catch (error) {\n try {\n console.error(\"[Shell] ⚠️ FALLBACK TO HUB - Init failed:\", error)\n\n if ((window as any).DD_LOGS) {\n ;(window as any).DD_LOGS.logger.error(\"shell_init_failed\", {\n error: (error as Error).message,\n platform: PLATFORM,\n })\n }\n } finally {\n //Fallback, can't trust config exists\n window.location.href = HUB_URL\n }\n }\n}\n\ninit()\n"],"names":["defaultLogger","message","context","loadVwr","logger","PLATFORM","HUB_URL","init","error"],"mappings":"ssBAMO,MAAMA,EAAwB,CACjC,KAAM,CAACC,EAASC,IACZA,EAAU,QAAQ,IAAID,EAASC,CAAO,EAAI,QAAQ,IAAID,CAAO,EACjE,KAAM,CAACA,EAASC,IACZA,EAAU,QAAQ,KAAKD,EAASC,CAAO,EAAI,QAAQ,KAAKD,CAAO,EACnE,MAAO,CAACA,EAASC,IACbA,EAAU,QAAQ,MAAMD,EAASC,CAAO,EAAI,QAAQ,MAAMD,CAAO,CACzE,ECsBaE,EAAU,MAAOC,EAAiBJ,IAAkB,CAEzD,MAAM,IAAI,MAAM,4CAA4C,CAwFpE,EC3HMK,EAAW,OACXC,EAAU,OAEhB,eAAeC,GAAO,CAClB,GAAI,CACA,MAAMJ,EAAA,CACV,OAASK,EAAO,CACZ,GAAI,CACA,QAAQ,MAAM,6CAA8CA,CAAK,EAE5D,OAAe,SACd,OAAe,QAAQ,OAAO,MAAM,oBAAqB,CACvD,MAAQA,EAAgB,QACxB,SAAUH,CAAA,CACb,CAET,QAAA,CAEI,OAAO,SAAS,KAAOC,CAC3B,CACJ,CACJ,CAEAC,EAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Logger } from "./logger";
|
|
2
|
+
export type VWRConfig = {
|
|
3
|
+
hubUrl: string;
|
|
4
|
+
vwrUrl: string;
|
|
5
|
+
launchUrl: string | undefined;
|
|
6
|
+
trustedDomains: Array<string>;
|
|
7
|
+
};
|
|
8
|
+
export type VWRConfigRequest = {
|
|
9
|
+
configUrl: string;
|
|
10
|
+
configFile: string;
|
|
11
|
+
platform: string;
|
|
12
|
+
deviceId: string;
|
|
13
|
+
environment: string;
|
|
14
|
+
shellVersion: string;
|
|
15
|
+
timeout?: number;
|
|
16
|
+
};
|
|
17
|
+
export declare const getVWRConfig: (request: VWRConfigRequest, logger?: Logger) => Promise<VWRConfig>;
|
|
18
|
+
export declare const validateConfig: (config: VWRConfig) => boolean;
|
|
19
|
+
//# sourceMappingURL=vwrConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vwrConfig.d.ts","sourceRoot":"","sources":["../src/vwrConfig.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAErD,MAAM,MAAM,SAAS,GAAG;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAsBD,eAAO,MAAM,YAAY,GACrB,SAAS,gBAAgB,EACzB,SAAQ,MAAsB,KAC/B,OAAO,CAAC,SAAS,CAmEnB,CAAA;AAyJD,eAAO,MAAM,cAAc,GAAI,QAAQ,SAAS,KAAG,OAWlD,CAAA"}
|