devframe 0.9.0-beta.3 → 0.9.0-beta.5

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 (65) hide show
  1. package/dist/{_shared-CGPVmXUM.mjs → _shared-CKZPvSrN.mjs} +2 -1
  2. package/dist/{_shared-Bm8p4-fD.d.mts → _shared-QkI6ljJS.d.mts} +2 -2
  3. package/dist/adapters/build.d.mts +10 -12
  4. package/dist/adapters/build.mjs +23 -27
  5. package/dist/adapters/cac.d.mts +1 -1
  6. package/dist/adapters/cac.mjs +3 -4
  7. package/dist/adapters/dev.d.mts +19 -5
  8. package/dist/adapters/dev.mjs +2 -2
  9. package/dist/adapters/embedded.d.mts +1 -1
  10. package/dist/adapters/initiate.d.mts +4 -3
  11. package/dist/adapters/initiate.mjs +1 -1
  12. package/dist/adapters/mcp.d.mts +1 -1
  13. package/dist/adapters/mcp.mjs +1 -1
  14. package/dist/cli/main.mjs +2 -2
  15. package/dist/client/index.d.mts +1 -1
  16. package/dist/client/index.mjs +2 -1175
  17. package/dist/constants.d.mts +1 -2
  18. package/dist/constants.mjs +1 -2
  19. package/dist/{context-DV4uWieM.d.mts → context-CQkRTbAc.d.mts} +1 -1
  20. package/dist/{context-b6iSomtv.mjs → context-D0HD0F7C.mjs} +19 -7
  21. package/dist/{context-CMSryXs-.mjs → context-D0jErmlx.mjs} +1 -1
  22. package/dist/{dev-4xjiynUD.mjs → dev-QEuT8SOF.mjs} +15 -9
  23. package/dist/{devframe-5oblos7I.d.mts → devframe-Cfx6doi4.d.mts} +41 -64
  24. package/dist/{diagnostics-C7IGWppM.mjs → diagnostics-DEuH3P5O.mjs} +32 -0
  25. package/dist/{host-agent-BBkKT27Q.mjs → host-agent-C5HjzfBz.mjs} +41 -3
  26. package/dist/{host-h3-CzCZwtuV.mjs → host-h3-Crkzm42q.mjs} +2 -2
  27. package/dist/{http-Z0w9baEe.mjs → http-CVwj7b4g.mjs} +2 -2
  28. package/dist/{index-BzDl02lt.d.mts → index-MYi1SZVL.d.mts} +2 -2
  29. package/dist/index.d.mts +3 -2
  30. package/dist/{instance-registry-Du_hbx-j.mjs → instance-registry-M2p-z6xE.mjs} +1 -1
  31. package/dist/{instance-shell-B0TwOxCl.mjs → instance-shell-DJ8s-MFw.mjs} +5 -5
  32. package/dist/{instance-shell-B-BSVp37.d.mts → instance-shell-D_UA0Idz.d.mts} +2 -2
  33. package/dist/internal/index.d.mts +72 -10
  34. package/dist/internal/index.mjs +7 -7
  35. package/dist/node/auth.d.mts +2 -2
  36. package/dist/node/auth.mjs +1 -1
  37. package/dist/node/hub-internals.d.mts +2 -2
  38. package/dist/node/hub-internals.mjs +2 -2
  39. package/dist/node/index.d.mts +1 -1
  40. package/dist/node/index.mjs +2 -2
  41. package/dist/recipes/common-rpc-functions.d.mts +1 -1
  42. package/dist/recipes/interactive-auth.d.mts +2 -2
  43. package/dist/recipes/interactive-auth.mjs +2 -2
  44. package/dist/remote-assets-DclsYyoL.d.mts +106 -0
  45. package/dist/rpc/transports/ws-bun.d.mts +1 -1
  46. package/dist/{rpc-core-B4Qm66Qt.d.mts → rpc-core-C8JQ3p7A.d.mts} +2 -2
  47. package/dist/{rpc-core-Cva-0pw0.mjs → rpc-core-IhcWl_xn.mjs} +1 -1
  48. package/dist/state-Cc1IeSmQ.mjs +1291 -0
  49. package/dist/storage-BVuipbGS.mjs +137 -0
  50. package/dist/types/index.d.mts +3 -2
  51. package/dist/utils/events.d.mts +1 -1
  52. package/dist/utils/open.d.mts +2 -10
  53. package/dist/utils/open.mjs +56 -1
  54. package/dist/utils/remote-assets.d.mts +15 -0
  55. package/dist/utils/remote-assets.mjs +309 -0
  56. package/dist/utils/serve-static.d.mts +13 -5
  57. package/dist/utils/serve-static.mjs +103 -9
  58. package/dist/utils/shared-state.d.mts +1 -1
  59. package/dist/utils/streaming-channel.d.mts +1 -1
  60. package/package.json +2 -3
  61. package/skills/devframe/SKILL.md +4 -5
  62. package/dist/open-Dz4V4irZ.mjs +0 -547
  63. package/dist/state-BeUHDDjk.mjs +0 -108
  64. package/dist/storage-CaUVrBrG.mjs +0 -1122
  65. package/skills/devframe/templates/spa-devframe.ts +0 -38
@@ -0,0 +1,1291 @@
1
+ import { DEVFRAME_OTP_URL_PARAM } from "./constants.mjs";
2
+ import { n as randomToken, r as timingSafeEqual, t as randomDigits } from "./crypto-token-XCqTSMg9.mjs";
3
+ //#region ../../node_modules/.pnpm/ua-parser-modern@0.1.1/node_modules/ua-parser-modern/dist/index.mjs
4
+ const EMPTY = "";
5
+ const UNKNOWN = "?";
6
+ const MAJOR = "major";
7
+ const MODEL = "model";
8
+ const NAME = "name";
9
+ const TYPE = "type";
10
+ const VENDOR = "vendor";
11
+ const VERSION = "version";
12
+ const ARCHITECTURE = "architecture";
13
+ const CONSOLE = "console";
14
+ const MOBILE = "mobile";
15
+ const TABLET = "tablet";
16
+ const SMARTTV = "smarttv";
17
+ const WEARABLE = "wearable";
18
+ const EMBEDDED = "embedded";
19
+ const UA_MAX_LENGTH = 500;
20
+ const AMAZON = "Amazon";
21
+ const APPLE = "Apple";
22
+ const ASUS = "ASUS";
23
+ const BLACKBERRY = "BlackBerry";
24
+ const BROWSER_LABEL = "Browser";
25
+ const CHROME = "Chrome";
26
+ const EDGE = "Edge";
27
+ const FIREFOX = "Firefox";
28
+ const GOOGLE = "Google";
29
+ const HUAWEI = "Huawei";
30
+ const LG = "LG";
31
+ const MICROSOFT = "Microsoft";
32
+ const MOTOROLA = "Motorola";
33
+ const OPERA = "Opera";
34
+ const SAMSUNG = "Samsung";
35
+ const SHARP = "Sharp";
36
+ const SONY = "Sony";
37
+ const XIAOMI = "Xiaomi";
38
+ const ZEBRA = "Zebra";
39
+ const FACEBOOK = "Facebook";
40
+ const CHROMIUM_OS = "Chromium OS";
41
+ const MAC_OS = "Mac OS";
42
+ function extend(regexes, extensions = {}) {
43
+ const mergedRegexes = {};
44
+ for (const key of Object.keys(regexes)) {
45
+ const extension = extensions[key];
46
+ if (extension && extension.length % 2 === 0) mergedRegexes[key] = [...extension, ...regexes[key]];
47
+ else mergedRegexes[key] = regexes[key];
48
+ }
49
+ return mergedRegexes;
50
+ }
51
+ function enumerize(arr) {
52
+ const enums = {};
53
+ for (let i = 0; i < arr.length; i++) enums[arr[i].toUpperCase()] = arr[i];
54
+ return enums;
55
+ }
56
+ function lowerize(str) {
57
+ return str.toLowerCase();
58
+ }
59
+ function has(str1, str2) {
60
+ return typeof str1 === "string" ? lowerize(str2).includes(lowerize(str1)) : false;
61
+ }
62
+ function majorize(version) {
63
+ return typeof version === "string" ? version.replace(/[^\d.]/g, EMPTY).split(".")[0] : void 0;
64
+ }
65
+ function trim(str, len) {
66
+ const result = str.replace(/^\s+/, EMPTY);
67
+ return typeof len === "undefined" ? result : result.substring(0, len);
68
+ }
69
+ function rgxMapper(ua, arrays, augment) {
70
+ const result = augment ?? {};
71
+ for (let i = 0; i < arrays.length; i += 2) {
72
+ const regex = arrays[i];
73
+ const props = arrays[i + 1];
74
+ for (let j = 0; j < regex.length; j++) {
75
+ const matcher = regex[j];
76
+ if (!matcher) break;
77
+ const matches = matcher.exec(ua);
78
+ if (!matches) continue;
79
+ for (let p = 0; p < props.length; p++) {
80
+ const match = matches[p + 1];
81
+ const q = props[p];
82
+ if (Array.isArray(q)) {
83
+ const key = q[0];
84
+ const length = q.length;
85
+ if (length === 2) {
86
+ const value = q[1];
87
+ if (typeof value === "function") result[key] = value(match, void 0, result);
88
+ else result[key] = value;
89
+ } else if (length === 3) {
90
+ const arg1 = q[1];
91
+ const arg2 = q[2];
92
+ if (typeof arg1 === "function" && !("exec" in arg1) && !("test" in arg1)) result[key] = match ? arg1(match, arg2, result) : void 0;
93
+ else result[key] = match ? match.replace(arg1, arg2) : void 0;
94
+ } else if (length === 4) result[key] = match ? q[3](match.replace(q[1], q[2]), void 0, result) : void 0;
95
+ } else result[q] = match || void 0;
96
+ }
97
+ return result;
98
+ }
99
+ }
100
+ return result;
101
+ }
102
+ function strMapper(str, map) {
103
+ for (const i in map) {
104
+ const value = map[i];
105
+ if (Array.isArray(value) && value.length > 0) {
106
+ for (let j = 0; j < value.length; j++) if (has(value[j], str)) return i === UNKNOWN ? void 0 : i;
107
+ } else if (has(value, str)) return i === UNKNOWN ? void 0 : i;
108
+ }
109
+ return str;
110
+ }
111
+ const oldSafariMap = {
112
+ "1.0": "/8",
113
+ "1.2": "/1",
114
+ "1.3": "/3",
115
+ "2.0": "/412",
116
+ "2.0.2": "/416",
117
+ "2.0.3": "/417",
118
+ "2.0.4": "/419",
119
+ "?": "/"
120
+ };
121
+ const windowsVersionMap = {
122
+ "ME": "4.90",
123
+ "NT 3.11": "NT3.51",
124
+ "NT 4.0": "NT4.0",
125
+ "2000": "NT 5.0",
126
+ "XP": ["NT 5.1", "NT 5.2"],
127
+ "Vista": "NT 6.0",
128
+ "7": "NT 6.1",
129
+ "8": "NT 6.2",
130
+ "8.1": "NT 6.3",
131
+ "10": ["NT 6.4", "NT 10.0"],
132
+ "RT": "ARM"
133
+ };
134
+ const regexes = {
135
+ browser: [
136
+ [/\b(?:crmo|crios)\/([\w.]+)/i],
137
+ [VERSION, [NAME, "Chrome"]],
138
+ [/edg(?:e|ios|a)?\/([\w.]+)/i],
139
+ [VERSION, [NAME, "Edge"]],
140
+ [
141
+ /(opera mini)\/([-\w.]+)/i,
142
+ /(opera [mobileta]{3,6})\b.+version\/([-\w.]+)/i,
143
+ /(opera)(?:.+version\/|[/ ]+)([\w.]+)/i
144
+ ],
145
+ [NAME, VERSION],
146
+ [/opios[/ ]+([\w.]+)/i],
147
+ [VERSION, [NAME, `${OPERA} Mini`]],
148
+ [/\bop(?:rg)?x\/([\w.]+)/i],
149
+ [VERSION, [NAME, `${OPERA} GX`]],
150
+ [/\bopr\/([\w.]+)/i],
151
+ [VERSION, [NAME, OPERA]],
152
+ [/\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[/ ]?([\w.]+)/i],
153
+ [VERSION, [NAME, "Baidu"]],
154
+ [
155
+ /(kindle)\/([\w.]+)/i,
156
+ /(lunascape|maxthon|netfront|jasmine|blazer)[/ ]?([\w.]*)/i,
157
+ /(avant|iemobile|slim)\s?(?:browser)?[/ ]?([\w.]*)/i,
158
+ /(?:ms|\()(ie) ([\w.]+)/i,
159
+ /(flock|rockmelt|midori|epiphany|silk|skyfire|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|qq|duckduckgo)\/([-\w.]+)/i,
160
+ /(heytap|ovi)browser\/([\d.]+)/i,
161
+ /(weibo)__([\d.]+)/i
162
+ ],
163
+ [NAME, VERSION],
164
+ [/\bddg\/([\w.]+)/i],
165
+ [VERSION, [NAME, "DuckDuckGo"]],
166
+ [/(?:\buc? ?browser|juc.+ucweb)[/ ]?([\w.]+)/i],
167
+ [VERSION, [NAME, `UC${BROWSER_LABEL}`]],
168
+ [
169
+ /microm.+\bqbcore\/([\w.]+)/i,
170
+ /\bqbcore\/([\w.]+).+microm/i,
171
+ /micromessenger\/([\w.]+)/i
172
+ ],
173
+ [VERSION, [NAME, "WeChat"]],
174
+ [/konqueror\/([\w.]+)/i],
175
+ [VERSION, [NAME, "Konqueror"]],
176
+ [/trident.+rv[: ]([\w.]{1,9})\b.+like gecko/i],
177
+ [VERSION, [NAME, "IE"]],
178
+ [/ya(?:search)?browser\/([\w.]+)/i],
179
+ [VERSION, [NAME, "Yandex"]],
180
+ [/slbrowser\/([\w.]+)/i],
181
+ [VERSION, [NAME, `Smart Lenovo ${BROWSER_LABEL}`]],
182
+ [/(avast|avg)\/([\w.]+)/i],
183
+ [[
184
+ NAME,
185
+ /(.+)/,
186
+ `$1 Secure ${BROWSER_LABEL}`
187
+ ], VERSION],
188
+ [/\bfocus\/([\w.]+)/i],
189
+ [VERSION, [NAME, `${FIREFOX} Focus`]],
190
+ [/\bopt\/([\w.]+)/i],
191
+ [VERSION, [NAME, `${OPERA} Touch`]],
192
+ [/coc_coc\w+\/([\w.]+)/i],
193
+ [VERSION, [NAME, "Coc Coc"]],
194
+ [/dolfin\/([\w.]+)/i],
195
+ [VERSION, [NAME, "Dolphin"]],
196
+ [/coast\/([\w.]+)/i],
197
+ [VERSION, [NAME, `${OPERA} Coast`]],
198
+ [/miuibrowser\/([\w.]+)/i],
199
+ [VERSION, [NAME, `MIUI ${BROWSER_LABEL}`]],
200
+ [/fxios\/([-\w.]+)/i],
201
+ [VERSION, [NAME, FIREFOX]],
202
+ [/\bqihu|(qi?ho{0,2}|360)browser/i],
203
+ [[NAME, `360 ${BROWSER_LABEL}`]],
204
+ [/(oculus|sailfish|huawei|vivo)browser\/([\w.]+)/i],
205
+ [[
206
+ NAME,
207
+ /(.+)/,
208
+ `$1 ${BROWSER_LABEL}`
209
+ ], VERSION],
210
+ [/samsungbrowser\/([\w.]+)/i],
211
+ [VERSION, [NAME, `${SAMSUNG} Internet`]],
212
+ [/(comodo_dragon)\/([\w.]+)/i],
213
+ [[
214
+ NAME,
215
+ /_/g,
216
+ " "
217
+ ], VERSION],
218
+ [/metasr[/ ]?([\d.]+)/i],
219
+ [VERSION, [NAME, "Sogou Explorer"]],
220
+ [/(sogou)mo\w+\/([\d.]+)/i],
221
+ [[NAME, "Sogou Mobile"], VERSION],
222
+ [
223
+ /(electron)\/([\w.]+) safari/i,
224
+ /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w.]+))/i,
225
+ /m?(qqbrowser|2345Explorer)[/ ]?([\w.]+)/i
226
+ ],
227
+ [NAME, VERSION],
228
+ [/(lbbrowser)/i, /\[(linkedin)app\]/i],
229
+ [NAME],
230
+ [/((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w.]+);)/i],
231
+ [[NAME, FACEBOOK], VERSION],
232
+ [
233
+ /(Klarna)\/([\w.]+)/i,
234
+ /(kakao(?:talk|story))[/ ]([\w.]+)/i,
235
+ /(naver)\(.*?(\d+\.[\w.]+).*\)/i,
236
+ /safari (line)\/([\w.]+)/i,
237
+ /\b(line)\/([\w.]+)\/iab/i,
238
+ /(alipay)client\/([\w.]+)/i,
239
+ /(twitter)(?:and| f.+e\/([\w.]+))/i,
240
+ /(chromium|instagram|snapchat)[/ ]([-\w.]+)/i
241
+ ],
242
+ [NAME, VERSION],
243
+ [/\bgsa\/([\w.]+) .*safari\//i],
244
+ [VERSION, [NAME, "GSA"]],
245
+ [/musical_ly(?:.+app_?version\/|_)([\w.]+)/i],
246
+ [VERSION, [NAME, "TikTok"]],
247
+ [/headlesschrome(?:\/([\w.]+)| )/i],
248
+ [VERSION, [NAME, `${CHROME} Headless`]],
249
+ [/ wv\).+(chrome)\/([\w.]+)/i],
250
+ [[NAME, `${CHROME} WebView`], VERSION],
251
+ [/droid.+ version\/([\w.]+)\b.+(?:mobile safari|safari)/i],
252
+ [VERSION, [NAME, `Android ${BROWSER_LABEL}`]],
253
+ [/(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w.]+)/i],
254
+ [NAME, VERSION],
255
+ [/version\/([\w.,]+) .*mobile\/\w+ (safari)/i],
256
+ [VERSION, [NAME, "Mobile Safari"]],
257
+ [/version\/([\w(.|,)]+) .*(mobile ?safari|safari)/i],
258
+ [VERSION, NAME],
259
+ [/webkit.+?(mobile ?safari|safari)(\/[\w.]+)/i],
260
+ [NAME, [
261
+ VERSION,
262
+ strMapper,
263
+ oldSafariMap
264
+ ]],
265
+ [/(webkit|khtml)\/([\w.]+)/i],
266
+ [NAME, VERSION],
267
+ [/(navigator|netscape\d?)\/([-\w.]+)/i],
268
+ [[NAME, "Netscape"], VERSION],
269
+ [/mobile vr; rv:([\w.]+)\).+firefox/i],
270
+ [VERSION, [NAME, `${FIREFOX} Reality`]],
271
+ [
272
+ /ekiohf.+(flow)\/([\w.]+)/i,
273
+ /(swiftfox)/i,
274
+ /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[/ ]?([\w.+]+)/i,
275
+ /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w.]+)$/i,
276
+ /(firefox)\/([\w.]+)/i,
277
+ /(mozilla)\/([\w.]+) .+rv:.+gecko\/\d+/i,
278
+ /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[. ]?browser)[-/ ]?v?([\w.]+)/i,
279
+ /(links) \(([\w.]+)/i,
280
+ /panasonic;(viera)/i
281
+ ],
282
+ [NAME, VERSION],
283
+ [/(cobalt)\/([\w.]+)/i],
284
+ [NAME, [
285
+ VERSION,
286
+ /master.|lts./,
287
+ ""
288
+ ]]
289
+ ],
290
+ cpu: [
291
+ [/(amd|x(?:(?:86|64)[-_])?|wow|win)64[;)]/i],
292
+ [[ARCHITECTURE, "amd64"]],
293
+ [/(ia32(?=;))/i],
294
+ [[ARCHITECTURE, lowerize]],
295
+ [/((?:i[346]|x)86)[;)]/i],
296
+ [[ARCHITECTURE, "ia32"]],
297
+ [/\b(aarch64|arm(v?8e?l?|_?64))\b/i],
298
+ [[ARCHITECTURE, "arm64"]],
299
+ [/\b(arm(?:v[67])?ht?n?[fl]p?)\b/i],
300
+ [[ARCHITECTURE, "armhf"]],
301
+ [/windows (ce|mobile); ppc;/i],
302
+ [[ARCHITECTURE, "arm"]],
303
+ [/((?:ppc|powerpc)(?:64)?)(?: mac|;|\))/i],
304
+ [[
305
+ ARCHITECTURE,
306
+ /ower/,
307
+ EMPTY,
308
+ lowerize
309
+ ]],
310
+ [/(sun4\w)[;)]/i],
311
+ [[ARCHITECTURE, "sparc"]],
312
+ [/(avr32|ia64(?=;)|68k(?=\))|\barm(?=v(?:[1-7]|[5-7]1)l?|;|eabi)|(?=atmel )avr|(?:irix|mips|sparc)(?:64)?\b|pa-risc)/i],
313
+ [[ARCHITECTURE, lowerize]]
314
+ ],
315
+ device: [
316
+ [/\b(sch-i[89]0\d|shw-m380s|sm-[ptx]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus 10)/i],
317
+ [
318
+ MODEL,
319
+ [VENDOR, SAMSUNG],
320
+ [TYPE, TABLET]
321
+ ],
322
+ [
323
+ /\b((?:s[cgp]h|gt|sm)-\w+|sc[g-]?\d+a?|galaxy nexus)/i,
324
+ /samsung[- ]([-\w]+)/i,
325
+ /sec-(sgh\w+)/i
326
+ ],
327
+ [
328
+ MODEL,
329
+ [VENDOR, SAMSUNG],
330
+ [TYPE, MOBILE]
331
+ ],
332
+ [/(?:\/|\()(ip(?:hone|od)[\w, ]*)(?:\/|;)/i],
333
+ [
334
+ MODEL,
335
+ [VENDOR, APPLE],
336
+ [TYPE, MOBILE]
337
+ ],
338
+ [
339
+ /\((ipad);[-\w),; ]+apple/i,
340
+ /applecoremedia\/[\w.]+ \((ipad)/i,
341
+ /\b(ipad)\d\d?,\d\d?[;\]].+ios/i
342
+ ],
343
+ [
344
+ MODEL,
345
+ [VENDOR, APPLE],
346
+ [TYPE, TABLET]
347
+ ],
348
+ [/(macintosh);/i],
349
+ [MODEL, [VENDOR, APPLE]],
350
+ [/\b(sh-?[altvz]?\d\d[a-ekm]?)/i],
351
+ [
352
+ MODEL,
353
+ [VENDOR, SHARP],
354
+ [TYPE, MOBILE]
355
+ ],
356
+ [/\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\d{2})\b(?!.+d\/s)/i],
357
+ [
358
+ MODEL,
359
+ [VENDOR, HUAWEI],
360
+ [TYPE, TABLET]
361
+ ],
362
+ [/(?:huawei|honor)([-\w ]+)[;)]/i, /\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][0-359c][adn]?)\b(?!.+d\/s)/i],
363
+ [
364
+ MODEL,
365
+ [VENDOR, HUAWEI],
366
+ [TYPE, MOBILE]
367
+ ],
368
+ [
369
+ /\b(poco[\w ]+|m2\d{3}j\d\d[a-z]{2})(?: bui|\))/i,
370
+ /\b; (\w+) build\/hm\1/i,
371
+ /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i,
372
+ /\b(redmi[\-_ ]?[\w ]+)(?: bui|\))/i,
373
+ /oid[^)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|; wv|\))/i,
374
+ /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?\d?\w?[_ ]?(?:plus|se|lite)?)(?: bui|\))/i
375
+ ],
376
+ [
377
+ [
378
+ MODEL,
379
+ /_/g,
380
+ " "
381
+ ],
382
+ [VENDOR, XIAOMI],
383
+ [TYPE, MOBILE]
384
+ ],
385
+ [/oid[^)]+; (2\d{4}(283|rpbf)[cgl])( bui|\))/i, /\b(mi[-_ ]?pad[\w ]+)(?: bui|\))/i],
386
+ [
387
+ [
388
+ MODEL,
389
+ /_/g,
390
+ " "
391
+ ],
392
+ [VENDOR, XIAOMI],
393
+ [TYPE, TABLET]
394
+ ],
395
+ [/; (\w+) bui.+ oppo/i, /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i],
396
+ [
397
+ MODEL,
398
+ [VENDOR, "OPPO"],
399
+ [TYPE, MOBILE]
400
+ ],
401
+ [/\b(opd2\d{3}a?) bui/i],
402
+ [
403
+ MODEL,
404
+ [VENDOR, "OPPO"],
405
+ [TYPE, TABLET]
406
+ ],
407
+ [/vivo (\w+)(?: bui|\))/i, /\b(v[12]\d{3}\w?[at])(?: bui|;)/i],
408
+ [
409
+ MODEL,
410
+ [VENDOR, "Vivo"],
411
+ [TYPE, MOBILE]
412
+ ],
413
+ [/\b(rmx[1-3]\d{3})(?: bui|;|\))/i],
414
+ [
415
+ MODEL,
416
+ [VENDOR, "Realme"],
417
+ [TYPE, MOBILE]
418
+ ],
419
+ [
420
+ /\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i,
421
+ /\bmot(?:orola)?[- ](\w*)/i,
422
+ /((?:moto[\w() ]+|xt\d{3,4}|nexus 6)(?= bui|\)))/i
423
+ ],
424
+ [
425
+ MODEL,
426
+ [VENDOR, MOTOROLA],
427
+ [TYPE, MOBILE]
428
+ ],
429
+ [/\b(mz60\d|xoom[2 ]{0,2}) build\//i],
430
+ [
431
+ MODEL,
432
+ [VENDOR, MOTOROLA],
433
+ [TYPE, TABLET]
434
+ ],
435
+ [/((?=lg)?[vl]k-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i],
436
+ [
437
+ MODEL,
438
+ [VENDOR, LG],
439
+ [TYPE, TABLET]
440
+ ],
441
+ [
442
+ /(lm(?:-?f100[nv]?|-[\w.]+)(?= bui|\))|nexus [45])/i,
443
+ /\blg[-e;/ ]+((?!browser|netcast|android tv)\w+)/i,
444
+ /\blg-?(\w+) bui/i
445
+ ],
446
+ [
447
+ MODEL,
448
+ [VENDOR, LG],
449
+ [TYPE, MOBILE]
450
+ ],
451
+ [/(ideatab[-\w ]+)/i, /lenovo ?(s[56]000[-\w]+|tab[\w ]+|yt[-\w]{6}|tb[-\w]{6})/i],
452
+ [
453
+ MODEL,
454
+ [VENDOR, "Lenovo"],
455
+ [TYPE, TABLET]
456
+ ],
457
+ [/(?:maemo|nokia).*(n900|lumia \d+)/i, /nokia[-_ ]?([-\w.]*)/i],
458
+ [
459
+ [
460
+ MODEL,
461
+ /_/g,
462
+ " "
463
+ ],
464
+ [VENDOR, "Nokia"],
465
+ [TYPE, MOBILE]
466
+ ],
467
+ [/(pixel c)\b/i],
468
+ [
469
+ MODEL,
470
+ [VENDOR, GOOGLE],
471
+ [TYPE, TABLET]
472
+ ],
473
+ [/droid.+; (pixel[\daxl ]{0,6})(?: bui|\))/i],
474
+ [
475
+ MODEL,
476
+ [VENDOR, GOOGLE],
477
+ [TYPE, MOBILE]
478
+ ],
479
+ [/droid.+ (a?\d[0-2]{2}so|[c-g]\d{4}|so[-gl]\w+|xq-a\w[4-7][12])(?= bui|\).+chrome\/(?![1-6]?\d\.))/i],
480
+ [
481
+ MODEL,
482
+ [VENDOR, SONY],
483
+ [TYPE, MOBILE]
484
+ ],
485
+ [/sony tablet [ps]/i, /\b(?:sony)?sgp\w+(?: bui|\))/i],
486
+ [
487
+ [MODEL, "Xperia Tablet"],
488
+ [VENDOR, SONY],
489
+ [TYPE, TABLET]
490
+ ],
491
+ [/ (kb2005|in20[12]5|be20[12][59])\b/i, /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i],
492
+ [
493
+ MODEL,
494
+ [VENDOR, "OnePlus"],
495
+ [TYPE, MOBILE]
496
+ ],
497
+ [
498
+ /(alexa)webm/i,
499
+ /(kf[a-z]{2}wi|aeo[c-r]{2})( bui|\))/i,
500
+ /(kf[a-z]+)( bui|\)).+silk\//i
501
+ ],
502
+ [
503
+ MODEL,
504
+ [VENDOR, AMAZON],
505
+ [TYPE, TABLET]
506
+ ],
507
+ [/((?:sd|kf)[0349hijor-uw]+)( bui|\)).+silk\//i],
508
+ [
509
+ [
510
+ MODEL,
511
+ /(.+)/g,
512
+ "Fire Phone $1"
513
+ ],
514
+ [VENDOR, AMAZON],
515
+ [TYPE, MOBILE]
516
+ ],
517
+ [/(playbook);[-\w),; ]+(rim)/i],
518
+ [
519
+ MODEL,
520
+ VENDOR,
521
+ [TYPE, TABLET]
522
+ ],
523
+ [/\b((?:bb[a-f]|st[hv])100-\d)/i, /\(bb10; (\w+)/i],
524
+ [
525
+ MODEL,
526
+ [VENDOR, BLACKBERRY],
527
+ [TYPE, MOBILE]
528
+ ],
529
+ [/(?:\b|asus_)(transfo[prime ]{4,10} \w+|eeepc|slider \w+|nexus 7|padfone|p00[cj])/i],
530
+ [
531
+ MODEL,
532
+ [VENDOR, ASUS],
533
+ [TYPE, TABLET]
534
+ ],
535
+ [/ (z[bes]6[027][012][km][ls]|zenfone \d\w?)\b/i],
536
+ [
537
+ MODEL,
538
+ [VENDOR, ASUS],
539
+ [TYPE, MOBILE]
540
+ ],
541
+ [/(nexus 9)/i],
542
+ [
543
+ MODEL,
544
+ [VENDOR, "HTC"],
545
+ [TYPE, TABLET]
546
+ ],
547
+ [
548
+ /(htc)[-;_ ]{1,2}([\w ]+(?=\)| bui)|\w+)/i,
549
+ /(zte)[- ]([\w ]+?)(?: bui|\/|\))/i,
550
+ /(alcatel|geeksphone|nexian|panasonic(?!;|\.)|sony(?!-bra))[-_ ]?([-\w]*)/i
551
+ ],
552
+ [
553
+ VENDOR,
554
+ [
555
+ MODEL,
556
+ /_/g,
557
+ " "
558
+ ],
559
+ [TYPE, MOBILE]
560
+ ],
561
+ [/droid.+; ([ab][1-7]-?[0178a]\d\d?)/i],
562
+ [
563
+ MODEL,
564
+ [VENDOR, "Acer"],
565
+ [TYPE, TABLET]
566
+ ],
567
+ [/droid.+; (m[1-5] note) bui/i, /\bmz-([-\w]{2,})/i],
568
+ [
569
+ MODEL,
570
+ [VENDOR, "Meizu"],
571
+ [TYPE, MOBILE]
572
+ ],
573
+ [/; ((?:power )?armor[\w ]{0,8})(?: bui|\))/i],
574
+ [
575
+ MODEL,
576
+ [VENDOR, "Ulefone"],
577
+ [TYPE, MOBILE]
578
+ ],
579
+ [
580
+ /(blackberry|benq|palm(?=-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron|infinix|tecno)[-_ ]?([-\w]*)/i,
581
+ /(hp) ([\w ]+\w)/i,
582
+ /(asus)-?(\w+)/i,
583
+ /(microsoft); (lumia[\w ]+)/i,
584
+ /(lenovo)[-_ ]?([-\w]+)/i,
585
+ /(jolla)/i,
586
+ /(oppo) ?([\w ]+) bui/i
587
+ ],
588
+ [
589
+ VENDOR,
590
+ MODEL,
591
+ [TYPE, MOBILE]
592
+ ],
593
+ [
594
+ /(kobo)\s(ereader|touch)/i,
595
+ /(archos) (gamepad2?)/i,
596
+ /(hp).+(touchpad(?!.+tablet)|tablet)/i,
597
+ /(kindle)\/([\w.]+)/i,
598
+ /(nook)[\w ]+build\/(\w+)/i,
599
+ /(dell) (strea[kpr\d ]*[\dko])/i,
600
+ /(le[- ]+pan)[- ]+(\w{1,9}) bui/i,
601
+ /(trinity)[- ]*(t\d{3}) bui/i,
602
+ /(gigaset)[- ]+(q\w{1,9}) bui/i,
603
+ /(vodafone) ([\w ]+)(?:\)| bui)/i
604
+ ],
605
+ [
606
+ VENDOR,
607
+ MODEL,
608
+ [TYPE, TABLET]
609
+ ],
610
+ [/(surface duo)/i],
611
+ [
612
+ MODEL,
613
+ [VENDOR, MICROSOFT],
614
+ [TYPE, TABLET]
615
+ ],
616
+ [/droid [\d.]+; (fp\du?)(?: b|\))/i],
617
+ [
618
+ MODEL,
619
+ [VENDOR, "Fairphone"],
620
+ [TYPE, MOBILE]
621
+ ],
622
+ [/(u304aa)/i],
623
+ [
624
+ MODEL,
625
+ [VENDOR, "AT&T"],
626
+ [TYPE, MOBILE]
627
+ ],
628
+ [/\bsie-(\w*)/i],
629
+ [
630
+ MODEL,
631
+ [VENDOR, "Siemens"],
632
+ [TYPE, MOBILE]
633
+ ],
634
+ [/\b(rct\w+) b/i],
635
+ [
636
+ MODEL,
637
+ [VENDOR, "RCA"],
638
+ [TYPE, TABLET]
639
+ ],
640
+ [/\b(venue[\d ]{2,7}) b/i],
641
+ [
642
+ MODEL,
643
+ [VENDOR, "Dell"],
644
+ [TYPE, TABLET]
645
+ ],
646
+ [/\b(q(?:mv|ta)\w+) b/i],
647
+ [
648
+ MODEL,
649
+ [VENDOR, "Verizon"],
650
+ [TYPE, TABLET]
651
+ ],
652
+ [/\b(?:barnes[& ]+noble |bn[rt])([\w+ ]*) b/i],
653
+ [
654
+ MODEL,
655
+ [VENDOR, "Barnes & Noble"],
656
+ [TYPE, TABLET]
657
+ ],
658
+ [/\b(tm\d{3}\w+) b/i],
659
+ [
660
+ MODEL,
661
+ [VENDOR, "NuVision"],
662
+ [TYPE, TABLET]
663
+ ],
664
+ [/\b(k88) b/i],
665
+ [
666
+ MODEL,
667
+ [VENDOR, "ZTE"],
668
+ [TYPE, TABLET]
669
+ ],
670
+ [/\b(nx\d{3}j) b/i],
671
+ [
672
+ MODEL,
673
+ [VENDOR, "ZTE"],
674
+ [TYPE, MOBILE]
675
+ ],
676
+ [/\b(gen\d{3}) b.+49h/i],
677
+ [
678
+ MODEL,
679
+ [VENDOR, "Swiss"],
680
+ [TYPE, MOBILE]
681
+ ],
682
+ [/\b(zur\d{3}) b/i],
683
+ [
684
+ MODEL,
685
+ [VENDOR, "Swiss"],
686
+ [TYPE, TABLET]
687
+ ],
688
+ [/\b((zeki)?tb.*\b) b/i],
689
+ [
690
+ MODEL,
691
+ [VENDOR, "Zeki"],
692
+ [TYPE, TABLET]
693
+ ],
694
+ [/\b([yr]\d{2}) b/i, /\b(dragon[- ]+touch |dt)(\w{5}) b/i],
695
+ [
696
+ [VENDOR, "Dragon Touch"],
697
+ MODEL,
698
+ [TYPE, TABLET]
699
+ ],
700
+ [/\b(ns-?\w{0,9}) b/i],
701
+ [
702
+ MODEL,
703
+ [VENDOR, "Insignia"],
704
+ [TYPE, TABLET]
705
+ ],
706
+ [/\b((nxa|next)-?\w{0,9}) b/i],
707
+ [
708
+ MODEL,
709
+ [VENDOR, "NextBook"],
710
+ [TYPE, TABLET]
711
+ ],
712
+ [/\b(xtreme_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i],
713
+ [
714
+ [VENDOR, "Voice"],
715
+ MODEL,
716
+ [TYPE, MOBILE]
717
+ ],
718
+ [/\b(lvtel-)?(v1[12]) b/i],
719
+ [
720
+ [VENDOR, "LvTel"],
721
+ MODEL,
722
+ [TYPE, MOBILE]
723
+ ],
724
+ [/\b(ph-1) /i],
725
+ [
726
+ MODEL,
727
+ [VENDOR, "Essential"],
728
+ [TYPE, MOBILE]
729
+ ],
730
+ [/\b(v(100md|700na|7011|917g).*\b) b/i],
731
+ [
732
+ MODEL,
733
+ [VENDOR, "Envizen"],
734
+ [TYPE, TABLET]
735
+ ],
736
+ [/\b(trio[-\w. ]+) b/i],
737
+ [
738
+ MODEL,
739
+ [VENDOR, "MachSpeed"],
740
+ [TYPE, TABLET]
741
+ ],
742
+ [/\btu_(1491) b/i],
743
+ [
744
+ MODEL,
745
+ [VENDOR, "Rotor"],
746
+ [TYPE, TABLET]
747
+ ],
748
+ [/(shield[\w ]+) b/i],
749
+ [
750
+ MODEL,
751
+ [VENDOR, "Nvidia"],
752
+ [TYPE, TABLET]
753
+ ],
754
+ [/(sprint) (\w+)/i],
755
+ [
756
+ VENDOR,
757
+ MODEL,
758
+ [TYPE, MOBILE]
759
+ ],
760
+ [/(kin\.[onetw]{3})/i],
761
+ [
762
+ [
763
+ MODEL,
764
+ /\./g,
765
+ " "
766
+ ],
767
+ [VENDOR, MICROSOFT],
768
+ [TYPE, MOBILE]
769
+ ],
770
+ [/droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i],
771
+ [
772
+ MODEL,
773
+ [VENDOR, ZEBRA],
774
+ [TYPE, TABLET]
775
+ ],
776
+ [/droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i],
777
+ [
778
+ MODEL,
779
+ [VENDOR, ZEBRA],
780
+ [TYPE, MOBILE]
781
+ ],
782
+ [/smart-tv.+(samsung)/i],
783
+ [VENDOR, [TYPE, SMARTTV]],
784
+ [/hbbtv.+maple;(\d+)/i],
785
+ [
786
+ [
787
+ MODEL,
788
+ /^/,
789
+ "SmartTV"
790
+ ],
791
+ [VENDOR, SAMSUNG],
792
+ [TYPE, SMARTTV]
793
+ ],
794
+ [/(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i],
795
+ [[VENDOR, LG], [TYPE, SMARTTV]],
796
+ [/(apple) ?tv/i],
797
+ [
798
+ VENDOR,
799
+ [MODEL, `${APPLE} TV`],
800
+ [TYPE, SMARTTV]
801
+ ],
802
+ [/crkey/i],
803
+ [
804
+ [MODEL, `${CHROME}cast`],
805
+ [VENDOR, GOOGLE],
806
+ [TYPE, SMARTTV]
807
+ ],
808
+ [/droid.+aft(\w+)( bui|\))/i],
809
+ [
810
+ MODEL,
811
+ [VENDOR, AMAZON],
812
+ [TYPE, SMARTTV]
813
+ ],
814
+ [/\(dtv[);].+(aquos)/i, /(aquos-tv[\w ]+)\)/i],
815
+ [
816
+ MODEL,
817
+ [VENDOR, SHARP],
818
+ [TYPE, SMARTTV]
819
+ ],
820
+ [/(bravia[\w ]+)( bui|\))/i],
821
+ [
822
+ MODEL,
823
+ [VENDOR, SONY],
824
+ [TYPE, SMARTTV]
825
+ ],
826
+ [/(mitv-\w{5}) bui/i],
827
+ [
828
+ MODEL,
829
+ [VENDOR, XIAOMI],
830
+ [TYPE, SMARTTV]
831
+ ],
832
+ [/Hbbtv.*(technisat) (.*);/i],
833
+ [
834
+ VENDOR,
835
+ MODEL,
836
+ [TYPE, SMARTTV]
837
+ ],
838
+ [/\b(roku)[\dx]*[)/]((?:dvp-)?[\d.]*)/i, /hbbtv\/\d+\.\d+\.\d+ +\([\w+ ]*; *(\w[^;]*);([^;]*)/i],
839
+ [
840
+ [VENDOR, trim],
841
+ [MODEL, trim],
842
+ [TYPE, SMARTTV]
843
+ ],
844
+ [/\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\b/i],
845
+ [[TYPE, SMARTTV]],
846
+ [/(ouya)/i, /(nintendo) ([wids3utch]+)/i],
847
+ [
848
+ VENDOR,
849
+ MODEL,
850
+ [TYPE, CONSOLE]
851
+ ],
852
+ [/droid.+; (shield) bui/i],
853
+ [
854
+ MODEL,
855
+ [VENDOR, "Nvidia"],
856
+ [TYPE, CONSOLE]
857
+ ],
858
+ [/(playstation [345portablevi]+)/i],
859
+ [
860
+ MODEL,
861
+ [VENDOR, SONY],
862
+ [TYPE, CONSOLE]
863
+ ],
864
+ [/\b(xbox(?: one)?(?!; xbox))[); ]/i],
865
+ [
866
+ MODEL,
867
+ [VENDOR, MICROSOFT],
868
+ [TYPE, CONSOLE]
869
+ ],
870
+ [/((pebble))app/i],
871
+ [
872
+ VENDOR,
873
+ MODEL,
874
+ [TYPE, WEARABLE]
875
+ ],
876
+ [/(watch)(?: ?os[,/]|\d,\d\/)[\d.]+/i],
877
+ [
878
+ MODEL,
879
+ [VENDOR, APPLE],
880
+ [TYPE, WEARABLE]
881
+ ],
882
+ [/droid.+; (glass) \d/i],
883
+ [
884
+ MODEL,
885
+ [VENDOR, GOOGLE],
886
+ [TYPE, WEARABLE]
887
+ ],
888
+ [/droid.+; (wt63?0{2,3})\)/i],
889
+ [
890
+ MODEL,
891
+ [VENDOR, ZEBRA],
892
+ [TYPE, WEARABLE]
893
+ ],
894
+ [/(quest( \d| pro)?)/i],
895
+ [
896
+ MODEL,
897
+ [VENDOR, FACEBOOK],
898
+ [TYPE, WEARABLE]
899
+ ],
900
+ [/(tesla)(?: qtcarbrowser|\/[-\w.]+)/i],
901
+ [VENDOR, [TYPE, EMBEDDED]],
902
+ [/(aeobc)\b/i],
903
+ [
904
+ MODEL,
905
+ [VENDOR, AMAZON],
906
+ [TYPE, EMBEDDED]
907
+ ],
908
+ [/droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+? mobile safari/i],
909
+ [MODEL, [TYPE, MOBILE]],
910
+ [/droid .+?; ([^;]+?)(?: bui|\) applew).+?(?! mobile) safari/i],
911
+ [MODEL, [TYPE, TABLET]],
912
+ [/\b((tablet|tab)[;/]|focus\/\d(?!.+mobile))/i],
913
+ [[TYPE, TABLET]],
914
+ [/(phone|mobile(?:[;/]| [ \w/.]*safari)|pda(?=.+windows ce))/i],
915
+ [[TYPE, MOBILE]],
916
+ [/(android[-\w. ]{0,9});.+buil/i],
917
+ [MODEL, [VENDOR, "Generic"]]
918
+ ],
919
+ engine: [
920
+ [/windows.+ edge\/([\w.]+)/i],
921
+ [VERSION, [NAME, `${EDGE}HTML`]],
922
+ [/webkit\/537\.36.+chrome\/(?!27)([\w.]+)/i],
923
+ [VERSION, [NAME, "Blink"]],
924
+ [
925
+ /(presto)\/([\w.]+)/i,
926
+ /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w.]+)/i,
927
+ /ekioh(flow)\/([\w.]+)/i,
928
+ /(khtml|tasman|links)[/ ]\(?([\w.]+)/i,
929
+ /(icab)[/ ]([23]\.[\d.]+)/i,
930
+ /\b(libweb)/i
931
+ ],
932
+ [NAME, VERSION],
933
+ [/rv:([\w.]{1,9})\b.+(gecko)/i],
934
+ [VERSION, NAME]
935
+ ],
936
+ os: [
937
+ [/microsoft (windows) (vista|xp)/i],
938
+ [NAME, VERSION],
939
+ [/(windows (?:phone(?: os)?|mobile))[/ ]?([.\w ]*)/i],
940
+ [NAME, [
941
+ VERSION,
942
+ strMapper,
943
+ windowsVersionMap
944
+ ]],
945
+ [
946
+ /windows nt 6\.2; (arm)/i,
947
+ /windows[/ ]?([ntce\d. ]+\w)(?!.+xbox)/i,
948
+ /(?:win(?=[39n])|win 9x )([nt\d.]+)/i
949
+ ],
950
+ [[
951
+ VERSION,
952
+ strMapper,
953
+ windowsVersionMap
954
+ ], [NAME, "Windows"]],
955
+ [
956
+ /ip[honead]{2,4}\b(?:.*os (\w+) like mac|; opera)/i,
957
+ /(?:ios;fbsv\/|iphone.+ios[/ ])([\d.]+)/i,
958
+ /cfnetwork\/.+darwin/i
959
+ ],
960
+ [[
961
+ VERSION,
962
+ /_/g,
963
+ "."
964
+ ], [NAME, "iOS"]],
965
+ [/(mac os x) ?([\w. ]*)/i, /(macintosh|mac_powerpc\b)(?!.+haiku)/i],
966
+ [[NAME, MAC_OS], [
967
+ VERSION,
968
+ /_/g,
969
+ "."
970
+ ]],
971
+ [/droid ([\w.]+)\b.+(android[- ]x86|harmonyos)/i],
972
+ [VERSION, NAME],
973
+ [
974
+ /(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-/ ]?([\w.]*)/i,
975
+ /(blackberry)\w*\/([\w.]*)/i,
976
+ /(tizen|kaios)[/ ]([\w.]+)/i,
977
+ /\((series40);/i
978
+ ],
979
+ [NAME, VERSION],
980
+ [/\(bb(10);/i],
981
+ [VERSION, [NAME, BLACKBERRY]],
982
+ [/(?:symbian ?os|symbos|s60(?=;)|series60)[-/ ]?([\w.]*)/i],
983
+ [VERSION, [NAME, "Symbian"]],
984
+ [/mozilla\/[\d.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w.]+)/i],
985
+ [VERSION, [NAME, `${FIREFOX} OS`]],
986
+ [/web0s;.+rt(tv)/i, /\b(?:hp)?wos(?:browser)?\/([\w.]+)/i],
987
+ [VERSION, [NAME, "webOS"]],
988
+ [/watch(?: ?os[,/]|\d,\d\/)([\d.]+)/i],
989
+ [VERSION, [NAME, "watchOS"]],
990
+ [/crkey\/([\d.]+)/i],
991
+ [VERSION, [NAME, `${CHROME}cast`]],
992
+ [/(cros) \w+(?:\)| ([\w.]+)\b)/i],
993
+ [[NAME, CHROMIUM_OS], VERSION],
994
+ [
995
+ /panasonic;(viera)/i,
996
+ /(netrange)mmh/i,
997
+ /(nettv)\/(\d+\.[\w.]+)/i,
998
+ /(nintendo|playstation) ([wids345portablevuch]+)/i,
999
+ /(xbox); +xbox ([^);]+)/i,
1000
+ /\b(joli|palm)\b ?(?:os)?\/?([\w.]*)/i,
1001
+ /(mint)[/() ]?(\w*)/i,
1002
+ /(mageia|vectorlinux)[; ]/i,
1003
+ /([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-/ ]?(?!chrom|package)([-\w.]*)/i,
1004
+ /(hurd|linux) ?([\w.]*)/i,
1005
+ /(gnu) ?([\w.]*)/i,
1006
+ /\b([-e-hrntopcs]{0,5}bsd|dragonfly)[/ ]?(?!amd|[ix346]{1,2}86)([\w.]*)/i,
1007
+ /(haiku) (\w+)/i
1008
+ ],
1009
+ [NAME, VERSION],
1010
+ [/(sunos) ?([\w.]*)/i],
1011
+ [[NAME, "Solaris"], VERSION],
1012
+ [
1013
+ /((?:open)?solaris)[-/ ]?([\w.]*)/i,
1014
+ /(aix) ((\d)(?=[.) ])[\w.])*/i,
1015
+ /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux|serenityos)/i,
1016
+ /(unix) ?([\w.]*)/i
1017
+ ],
1018
+ [NAME, VERSION]
1019
+ ]
1020
+ };
1021
+ function isExtensionsInput(input) {
1022
+ return typeof input === "object" && input !== null;
1023
+ }
1024
+ Object.freeze(enumerize([
1025
+ NAME,
1026
+ VERSION,
1027
+ MAJOR
1028
+ ]));
1029
+ Object.freeze(enumerize([ARCHITECTURE]));
1030
+ Object.freeze(enumerize([
1031
+ MODEL,
1032
+ VENDOR,
1033
+ TYPE,
1034
+ CONSOLE,
1035
+ MOBILE,
1036
+ SMARTTV,
1037
+ TABLET,
1038
+ WEARABLE,
1039
+ EMBEDDED
1040
+ ]));
1041
+ Object.freeze(enumerize([NAME, VERSION]));
1042
+ Object.freeze(enumerize([NAME, VERSION]));
1043
+ function getRuntimeNavigator() {
1044
+ if (typeof window === "undefined" || !window.navigator) return void 0;
1045
+ return window.navigator;
1046
+ }
1047
+ function normalizeUA(ua) {
1048
+ return ua.length > UA_MAX_LENGTH ? trim(ua, UA_MAX_LENGTH) : ua;
1049
+ }
1050
+ function createDefaultParserContext(uastring) {
1051
+ if (typeof uastring === "string") return {
1052
+ ua: normalizeUA(uastring),
1053
+ isSelfNavigator: false,
1054
+ navigator: void 0,
1055
+ userAgentData: void 0,
1056
+ regexMap: regexes
1057
+ };
1058
+ const navigator = getRuntimeNavigator();
1059
+ const ua = normalizeUA(navigator && navigator.userAgent ? navigator.userAgent : EMPTY);
1060
+ return {
1061
+ ua,
1062
+ isSelfNavigator: Boolean(navigator && navigator.userAgent === ua),
1063
+ navigator,
1064
+ userAgentData: navigator?.userAgentData,
1065
+ regexMap: regexes
1066
+ };
1067
+ }
1068
+ function createParserContext(uastringOrExtensions, extensions) {
1069
+ if (!extensions && !isExtensionsInput(uastringOrExtensions)) return createDefaultParserContext(uastringOrExtensions);
1070
+ const navigator = getRuntimeNavigator();
1071
+ const uastring = isExtensionsInput(uastringOrExtensions) ? void 0 : uastringOrExtensions;
1072
+ const resolvedExtensions = isExtensionsInput(uastringOrExtensions) ? uastringOrExtensions : extensions;
1073
+ const ua = normalizeUA(uastring || (navigator && navigator.userAgent ? navigator.userAgent : EMPTY));
1074
+ const userAgentData = navigator?.userAgentData;
1075
+ return {
1076
+ ua,
1077
+ isSelfNavigator: Boolean(navigator && navigator.userAgent === ua),
1078
+ navigator,
1079
+ userAgentData,
1080
+ regexMap: resolvedExtensions ? extend(regexes, resolvedExtensions) : regexes
1081
+ };
1082
+ }
1083
+ function parseBrowserFromContext(context) {
1084
+ const browser = {
1085
+ name: void 0,
1086
+ version: void 0,
1087
+ major: void 0
1088
+ };
1089
+ rgxMapper(context.ua, context.regexMap.browser, browser);
1090
+ browser.major = majorize(browser.version);
1091
+ if (context.isSelfNavigator && context.navigator?.brave && typeof context.navigator.brave.isBrave === "function") browser.name = "Brave";
1092
+ return browser;
1093
+ }
1094
+ function parseCPUFromContext(context) {
1095
+ const cpu = { architecture: void 0 };
1096
+ rgxMapper(context.ua, context.regexMap.cpu, cpu);
1097
+ return cpu;
1098
+ }
1099
+ function parseDeviceFromContext(context) {
1100
+ const device = {
1101
+ vendor: void 0,
1102
+ model: void 0,
1103
+ type: void 0
1104
+ };
1105
+ rgxMapper(context.ua, context.regexMap.device, device);
1106
+ if (context.isSelfNavigator && !device.type && context.userAgentData?.mobile) device.type = MOBILE;
1107
+ if (context.isSelfNavigator && device.model === "Macintosh" && context.navigator && typeof context.navigator.standalone !== "undefined" && context.navigator.maxTouchPoints && context.navigator.maxTouchPoints > 2) {
1108
+ device.model = "iPad";
1109
+ device.type = TABLET;
1110
+ }
1111
+ return device;
1112
+ }
1113
+ function parseEngineFromContext(context) {
1114
+ const engine = {
1115
+ name: void 0,
1116
+ version: void 0
1117
+ };
1118
+ rgxMapper(context.ua, context.regexMap.engine, engine);
1119
+ return engine;
1120
+ }
1121
+ function parseOSFromContext(context) {
1122
+ const os = {
1123
+ name: void 0,
1124
+ version: void 0
1125
+ };
1126
+ rgxMapper(context.ua, context.regexMap.os, os);
1127
+ if (context.isSelfNavigator && !os.name && context.userAgentData?.platform && context.userAgentData.platform !== "Unknown") os.name = context.userAgentData.platform.replace(/chrome os/i, CHROMIUM_OS).replace(/macos/i, MAC_OS);
1128
+ return os;
1129
+ }
1130
+ function parseUA(uastringOrExtensions, extensions) {
1131
+ let context;
1132
+ let browserCache;
1133
+ let engineCache;
1134
+ let osCache;
1135
+ let deviceCache;
1136
+ let cpuCache;
1137
+ const getContext = () => context ||= createParserContext(uastringOrExtensions, extensions);
1138
+ return {
1139
+ get ua() {
1140
+ return getContext().ua;
1141
+ },
1142
+ get browser() {
1143
+ browserCache ||= parseBrowserFromContext(getContext());
1144
+ return browserCache;
1145
+ },
1146
+ get engine() {
1147
+ engineCache ||= parseEngineFromContext(getContext());
1148
+ return engineCache;
1149
+ },
1150
+ get os() {
1151
+ osCache ||= parseOSFromContext(getContext());
1152
+ return osCache;
1153
+ },
1154
+ get device() {
1155
+ deviceCache ||= parseDeviceFromContext(getContext());
1156
+ return deviceCache;
1157
+ },
1158
+ get cpu() {
1159
+ cpuCache ||= parseCPUFromContext(getContext());
1160
+ return cpuCache;
1161
+ }
1162
+ };
1163
+ }
1164
+ //#endregion
1165
+ //#region src/node/auth/state.ts
1166
+ /**
1167
+ * Format a raw `navigator.userAgent` string into the short display label
1168
+ * shown for a trusted device (e.g. "Chrome 120 | macOS 14 desktop").
1169
+ *
1170
+ * The client used to parse+format this itself, but that pulled
1171
+ * `ua-parser-modern` into the browser bundle for a label nothing else on
1172
+ * the client needs — the client now sends the raw string and parsing
1173
+ * happens here, at the server ingress, keeping the persisted label format
1174
+ * identical.
1175
+ */
1176
+ function describeUA(userAgent) {
1177
+ const info = parseUA(userAgent);
1178
+ return [
1179
+ info.browser.name,
1180
+ info.browser.version,
1181
+ "|",
1182
+ info.os.name,
1183
+ info.os.version,
1184
+ info.device.type
1185
+ ].filter((i) => i).join(" ");
1186
+ }
1187
+ /** Number of decimal digits in a human-typed one-time authentication code. */
1188
+ const TEMP_AUTH_CODE_LENGTH = 6;
1189
+ /**
1190
+ * How long an authentication code stays valid after it is (re)generated. A
1191
+ * 6-digit code only has ~20 bits of entropy, so a short lifetime plus the
1192
+ * attempt cap below are what keep it brute-force resistant.
1193
+ */
1194
+ const TEMP_AUTH_CODE_TTL = 5 * 6e4;
1195
+ /** Failed attempts allowed against a single code before it is rotated. */
1196
+ const TEMP_AUTH_MAX_ATTEMPTS = 5;
1197
+ let tempAuthCode = generateTempCode();
1198
+ let tempAuthCodeExpiresAt = Date.now() + TEMP_AUTH_CODE_TTL;
1199
+ let tempAuthFailedAttempts = 0;
1200
+ function generateTempCode() {
1201
+ return randomDigits(TEMP_AUTH_CODE_LENGTH);
1202
+ }
1203
+ /**
1204
+ * The current one-time authentication code. Display this to the user (e.g. in
1205
+ * the dev-server terminal) so they can type it into the browser to authenticate.
1206
+ */
1207
+ function getTempAuthCode() {
1208
+ return tempAuthCode;
1209
+ }
1210
+ /**
1211
+ * Rotate the authentication code, resetting its expiry window and failed-attempt
1212
+ * counter. Call this when a new authentication flow begins (e.g. when an
1213
+ * untrusted client starts authenticating) so the displayed code is freshly
1214
+ * valid for its full TTL.
1215
+ */
1216
+ function refreshTempAuthCode() {
1217
+ tempAuthCode = generateTempCode();
1218
+ tempAuthCodeExpiresAt = Date.now() + TEMP_AUTH_CODE_TTL;
1219
+ tempAuthFailedAttempts = 0;
1220
+ return tempAuthCode;
1221
+ }
1222
+ /**
1223
+ * Build a "magic link" authentication URL that embeds a one-time code (OTP) in
1224
+ * the URL **fragment**. Opening it authenticates the client without typing —
1225
+ * print it on startup (devframe stays headless, so the host prints its own
1226
+ * banner). Defaults to the current code; the link is subject to the same TTL.
1227
+ *
1228
+ * The code rides the fragment (`#devframe_otp=…`), not the query string, so it
1229
+ * is never sent to the server, written to an access log, or leaked in a
1230
+ * `Referer` header — the browser client reads it locally (see
1231
+ * `consumeOtpFromUrl`). Any existing fragment parameters are preserved.
1232
+ */
1233
+ function buildOtpAuthUrl(baseUrl, code = tempAuthCode) {
1234
+ const url = new URL(baseUrl);
1235
+ const fragment = new URLSearchParams(url.hash.replace(/^#/, ""));
1236
+ fragment.set(DEVFRAME_OTP_URL_PARAM, code);
1237
+ url.hash = fragment.toString();
1238
+ return url.href;
1239
+ }
1240
+ /**
1241
+ * Re-authenticate a connection that presents a previously-issued bearer token.
1242
+ * Returns `true` and marks the session trusted when the token is known.
1243
+ *
1244
+ * Used by the `anonymous:devframe:auth` handler so a client that already
1245
+ * authenticated (token persisted in the browser) is trusted on reconnect
1246
+ * without entering the code again.
1247
+ */
1248
+ function verifyAuthToken(token, session, storage) {
1249
+ if (!token || !storage.value().trusted[token]) return false;
1250
+ session.meta.clientAuthToken = token;
1251
+ session.meta.isTrusted = true;
1252
+ return true;
1253
+ }
1254
+ /**
1255
+ * Exchange a one-time authentication code for a fresh, node-issued bearer token.
1256
+ *
1257
+ * On success this mints a high-entropy token, records it in the trusted store,
1258
+ * marks the calling session trusted, rotates the code, and returns the token
1259
+ * for the client to persist. Returns `null` on any failure.
1260
+ *
1261
+ * Because the code is short and human-typed, verification is hardened against
1262
+ * brute force: it enforces a time-to-live, compares in constant time, and
1263
+ * rotates the code after {@link TEMP_AUTH_MAX_ATTEMPTS} failed attempts so an
1264
+ * attacker cannot keep guessing against the same code.
1265
+ */
1266
+ function exchangeTempAuthCode(code, session, info, storage) {
1267
+ if (Date.now() > tempAuthCodeExpiresAt) {
1268
+ refreshTempAuthCode();
1269
+ return null;
1270
+ }
1271
+ if (!timingSafeEqual(code, tempAuthCode)) {
1272
+ tempAuthFailedAttempts += 1;
1273
+ if (tempAuthFailedAttempts >= TEMP_AUTH_MAX_ATTEMPTS) refreshTempAuthCode();
1274
+ return null;
1275
+ }
1276
+ const authToken = randomToken();
1277
+ storage.mutate((state) => {
1278
+ state.trusted[authToken] = {
1279
+ authToken,
1280
+ ua: describeUA(info.ua),
1281
+ origin: info.origin,
1282
+ timestamp: Date.now()
1283
+ };
1284
+ });
1285
+ session.meta.clientAuthToken = authToken;
1286
+ session.meta.isTrusted = true;
1287
+ refreshTempAuthCode();
1288
+ return authToken;
1289
+ }
1290
+ //#endregion
1291
+ export { verifyAuthToken as a, refreshTempAuthCode as i, exchangeTempAuthCode as n, getTempAuthCode as r, buildOtpAuthUrl as t };