@arkyc/widget 1.0.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 (59) hide show
  1. package/README.md +85 -0
  2. package/dist/ArkycWidget.d.mts +50 -0
  3. package/dist/ArkycWidget.d.mts.map +1 -0
  4. package/dist/ArkycWidget.mjs +80 -0
  5. package/dist/ArkycWidget.mjs.map +1 -0
  6. package/dist/WidgetHandler.d.mts +24 -0
  7. package/dist/WidgetHandler.d.mts.map +1 -0
  8. package/dist/WidgetHandler.mjs +28 -0
  9. package/dist/WidgetHandler.mjs.map +1 -0
  10. package/dist/_virtual/_virtual_arkyc-theme-css.mjs +4 -0
  11. package/dist/arkyc-widget.iife.global.js +670 -0
  12. package/dist/arkyc-widget.iife.global.js.map +1 -0
  13. package/dist/capture.d.mts +73 -0
  14. package/dist/capture.d.mts.map +1 -0
  15. package/dist/capture.mjs +126 -0
  16. package/dist/capture.mjs.map +1 -0
  17. package/dist/client.d.mts +152 -0
  18. package/dist/client.d.mts.map +1 -0
  19. package/dist/client.mjs +120 -0
  20. package/dist/client.mjs.map +1 -0
  21. package/dist/controller.d.mts +126 -0
  22. package/dist/controller.d.mts.map +1 -0
  23. package/dist/controller.mjs +582 -0
  24. package/dist/controller.mjs.map +1 -0
  25. package/dist/countries.mjs +967 -0
  26. package/dist/countries.mjs.map +1 -0
  27. package/dist/device.mjs +17 -0
  28. package/dist/device.mjs.map +1 -0
  29. package/dist/document.d.mts +108 -0
  30. package/dist/document.d.mts.map +1 -0
  31. package/dist/document.mjs +227 -0
  32. package/dist/document.mjs.map +1 -0
  33. package/dist/face.d.mts +82 -0
  34. package/dist/face.d.mts.map +1 -0
  35. package/dist/face.mjs +230 -0
  36. package/dist/face.mjs.map +1 -0
  37. package/dist/flow.d.mts +74 -0
  38. package/dist/flow.d.mts.map +1 -0
  39. package/dist/flow.mjs +132 -0
  40. package/dist/flow.mjs.map +1 -0
  41. package/dist/index.d.mts +19 -0
  42. package/dist/index.d.mts.map +1 -0
  43. package/dist/index.mjs +16 -0
  44. package/dist/index.mjs.map +1 -0
  45. package/dist/qr.mjs +22 -0
  46. package/dist/qr.mjs.map +1 -0
  47. package/dist/realtime.d.mts +29 -0
  48. package/dist/realtime.d.mts.map +1 -0
  49. package/dist/realtime.mjs +107 -0
  50. package/dist/realtime.mjs.map +1 -0
  51. package/dist/theme.d.mts +42 -0
  52. package/dist/theme.d.mts.map +1 -0
  53. package/dist/theme.mjs +77 -0
  54. package/dist/theme.mjs.map +1 -0
  55. package/dist/types.d.mts +153 -0
  56. package/dist/types.d.mts.map +1 -0
  57. package/dist/ui.mjs +931 -0
  58. package/dist/ui.mjs.map +1 -0
  59. package/package.json +43 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"countries.mjs","names":[],"sources":["../src/countries.ts"],"sourcesContent":["export const countries = [\n {\n name: 'United States',\n iso2: 'US',\n flag: '๐Ÿ‡บ๐Ÿ‡ธ',\n },\n {\n name: 'Canada',\n iso2: 'CA',\n flag: '๐Ÿ‡จ๐Ÿ‡ฆ',\n },\n {\n name: 'Brazil',\n iso2: 'BR',\n flag: '๐Ÿ‡ง๐Ÿ‡ท',\n },\n {\n name: 'United Kingdom',\n iso2: 'GB',\n flag: '๐Ÿ‡ฌ๐Ÿ‡ง',\n },\n {\n name: 'Germany',\n iso2: 'DE',\n flag: '๐Ÿ‡ฉ๐Ÿ‡ช',\n },\n {\n name: 'France',\n iso2: 'FR',\n flag: '๐Ÿ‡ซ๐Ÿ‡ท',\n },\n {\n name: 'China',\n iso2: 'CN',\n flag: '๐Ÿ‡จ๐Ÿ‡ณ',\n },\n {\n name: 'Japan',\n iso2: 'JP',\n flag: '๐Ÿ‡ฏ๐Ÿ‡ต',\n },\n {\n name: 'India',\n iso2: 'IN',\n flag: '๐Ÿ‡ฎ๐Ÿ‡ณ',\n },\n {\n name: 'Australia',\n iso2: 'AU',\n flag: '๐Ÿ‡ฆ๐Ÿ‡บ',\n },\n {\n name: 'South Africa',\n iso2: 'ZA',\n flag: '๐Ÿ‡ฟ๐Ÿ‡ฆ',\n },\n {\n name: 'Russia',\n iso2: 'RU',\n flag: '๐Ÿ‡ท๐Ÿ‡บ',\n },\n {\n name: 'Saudi Arabia',\n iso2: 'SA',\n flag: '๐Ÿ‡ธ๐Ÿ‡ฆ',\n },\n {\n name: 'Afghanistan',\n iso2: 'AF',\n flag: '๐Ÿ‡ฆ๐Ÿ‡ซ',\n },\n {\n name: 'Albania',\n iso2: 'AL',\n flag: '๐Ÿ‡ฆ๐Ÿ‡ฑ',\n },\n {\n name: 'Algeria',\n iso2: 'DZ',\n flag: '๐Ÿ‡ฉ๐Ÿ‡ฟ',\n },\n {\n name: 'Andorra',\n iso2: 'AD',\n flag: '๐Ÿ‡ฆ๐Ÿ‡ฉ',\n },\n {\n name: 'Angola',\n iso2: 'AO',\n flag: '๐Ÿ‡ฆ๐Ÿ‡ด',\n },\n {\n name: 'Antigua and Barbuda',\n iso2: 'AG',\n flag: '๐Ÿ‡ฆ๐Ÿ‡ฌ',\n },\n {\n name: 'Argentina',\n iso2: 'AR',\n flag: '๐Ÿ‡ฆ๐Ÿ‡ท',\n },\n {\n name: 'Armenia',\n iso2: 'AM',\n flag: '๐Ÿ‡ฆ๐Ÿ‡ฒ',\n },\n {\n name: 'Austria',\n iso2: 'AT',\n flag: '๐Ÿ‡ฆ๐Ÿ‡น',\n },\n {\n name: 'Azerbaijan',\n iso2: 'AZ',\n flag: '๐Ÿ‡ฆ๐Ÿ‡ฟ',\n },\n {\n name: 'Bahamas',\n iso2: 'BS',\n flag: '๐Ÿ‡ง๐Ÿ‡ธ',\n },\n {\n name: 'Bahrain',\n iso2: 'BH',\n flag: '๐Ÿ‡ง๐Ÿ‡ญ',\n },\n {\n name: 'Bangladesh',\n iso2: 'BD',\n flag: '๐Ÿ‡ง๐Ÿ‡ฉ',\n },\n {\n name: 'Barbados',\n iso2: 'BB',\n flag: '๐Ÿ‡ง๐Ÿ‡ง',\n },\n {\n name: 'Belarus',\n iso2: 'BY',\n flag: '๐Ÿ‡ง๐Ÿ‡พ',\n },\n {\n name: 'Belgium',\n iso2: 'BE',\n flag: '๐Ÿ‡ง๐Ÿ‡ช',\n },\n {\n name: 'Belize',\n iso2: 'BZ',\n flag: '๐Ÿ‡ง๐Ÿ‡ฟ',\n },\n {\n name: 'Benin',\n iso2: 'BJ',\n flag: '๐Ÿ‡ง๐Ÿ‡ฏ',\n },\n {\n name: 'Bhutan',\n iso2: 'BT',\n flag: '๐Ÿ‡ง๐Ÿ‡น',\n },\n {\n name: 'Bolivia',\n iso2: 'BO',\n flag: '๐Ÿ‡ง๐Ÿ‡ด',\n },\n {\n name: 'Bosnia and Herzegovina',\n iso2: 'BA',\n flag: '๐Ÿ‡ง๐Ÿ‡ฆ',\n },\n {\n name: 'Botswana',\n iso2: 'BW',\n flag: '๐Ÿ‡ง๐Ÿ‡ผ',\n },\n {\n name: 'Brunei',\n iso2: 'BN',\n flag: '๐Ÿ‡ง๐Ÿ‡ณ',\n },\n {\n name: 'Bulgaria',\n iso2: 'BG',\n flag: '๐Ÿ‡ง๐Ÿ‡ฌ',\n },\n {\n name: 'Burkina Faso',\n iso2: 'BF',\n flag: '๐Ÿ‡ง๐Ÿ‡ซ',\n },\n {\n name: 'Burundi',\n iso2: 'BI',\n flag: '๐Ÿ‡ง๐Ÿ‡ฎ',\n },\n {\n name: 'Cabo Verde',\n iso2: 'CV',\n flag: '๐Ÿ‡จ๐Ÿ‡ป',\n },\n {\n name: 'Cambodia',\n iso2: 'KH',\n flag: '๐Ÿ‡ฐ๐Ÿ‡ญ',\n },\n {\n name: 'Cameroon',\n iso2: 'CM',\n flag: '๐Ÿ‡จ๐Ÿ‡ฒ',\n },\n {\n name: 'Central African Republic',\n iso2: 'CF',\n flag: '๐Ÿ‡จ๐Ÿ‡ซ',\n },\n {\n name: 'Chad',\n iso2: 'TD',\n flag: '๐Ÿ‡น๐Ÿ‡ฉ',\n },\n {\n name: 'Chile',\n iso2: 'CL',\n flag: '๐Ÿ‡จ๐Ÿ‡ฑ',\n },\n {\n name: 'Colombia',\n iso2: 'CO',\n flag: '๐Ÿ‡จ๐Ÿ‡ด',\n },\n {\n name: 'Comoros',\n iso2: 'KM',\n flag: '๐Ÿ‡ฐ๐Ÿ‡ฒ',\n },\n {\n name: 'Congo (Congo-Brazzaville)',\n iso2: 'CG',\n flag: '๐Ÿ‡จ๐Ÿ‡ฌ',\n },\n {\n name: 'Congo (Congo-Kinshasa)',\n iso2: 'CD',\n flag: '๐Ÿ‡จ๐Ÿ‡ฉ',\n },\n {\n name: 'Costa Rica',\n iso2: 'CR',\n flag: '๐Ÿ‡จ๐Ÿ‡ท',\n },\n {\n name: 'Croatia',\n iso2: 'HR',\n flag: '๐Ÿ‡ญ๐Ÿ‡ท',\n },\n {\n name: 'Cuba',\n iso2: 'CU',\n flag: '๐Ÿ‡จ๐Ÿ‡บ',\n },\n {\n name: 'Cyprus',\n iso2: 'CY',\n flag: '๐Ÿ‡จ๐Ÿ‡พ',\n },\n {\n name: 'Czech Republic',\n iso2: 'CZ',\n flag: '๐Ÿ‡จ๐Ÿ‡ฟ',\n },\n {\n name: 'Denmark',\n iso2: 'DK',\n flag: '๐Ÿ‡ฉ๐Ÿ‡ฐ',\n },\n {\n name: 'Djibouti',\n iso2: 'DJ',\n flag: '๐Ÿ‡ฉ๐Ÿ‡ฏ',\n },\n {\n name: 'Dominica',\n iso2: 'DM',\n flag: '๐Ÿ‡ฉ๐Ÿ‡ฒ',\n },\n {\n name: 'Dominican Republic',\n iso2: 'DO',\n flag: '๐Ÿ‡ฉ๐Ÿ‡ด',\n },\n {\n name: 'Ecuador',\n iso2: 'EC',\n flag: '๐Ÿ‡ช๐Ÿ‡จ',\n },\n {\n name: 'Egypt',\n iso2: 'EG',\n flag: '๐Ÿ‡ช๐Ÿ‡ฌ',\n },\n {\n name: 'El Salvador',\n iso2: 'SV',\n flag: '๐Ÿ‡ธ๐Ÿ‡ป',\n },\n {\n name: 'Equatorial Guinea',\n iso2: 'GQ',\n flag: '๐Ÿ‡ฌ๐Ÿ‡ถ',\n },\n {\n name: 'Eritrea',\n iso2: 'ER',\n flag: '๐Ÿ‡ช๐Ÿ‡ท',\n },\n {\n name: 'Estonia',\n iso2: 'EE',\n flag: '๐Ÿ‡ช๐Ÿ‡ช',\n },\n {\n name: 'Eswatini',\n iso2: 'SZ',\n flag: '๐Ÿ‡ธ๐Ÿ‡ฟ',\n },\n {\n name: 'Ethiopia',\n iso2: 'ET',\n flag: '๐Ÿ‡ช๐Ÿ‡น',\n },\n {\n name: 'Fiji',\n iso2: 'FJ',\n flag: '๐Ÿ‡ซ๐Ÿ‡ฏ',\n },\n {\n name: 'Finland',\n iso2: 'FI',\n flag: '๐Ÿ‡ซ๐Ÿ‡ฎ',\n },\n {\n name: 'Gabon',\n iso2: 'GA',\n flag: '๐Ÿ‡ฌ๐Ÿ‡ฆ',\n },\n {\n name: 'Gambia',\n iso2: 'GM',\n flag: '๐Ÿ‡ฌ๐Ÿ‡ฒ',\n },\n {\n name: 'Georgia',\n iso2: 'GE',\n flag: '๐Ÿ‡ฌ๐Ÿ‡ช',\n },\n {\n name: 'Ghana',\n iso2: 'GH',\n flag: '๐Ÿ‡ฌ๐Ÿ‡ญ',\n },\n {\n name: 'Greece',\n iso2: 'GR',\n flag: '๐Ÿ‡ฌ๐Ÿ‡ท',\n },\n {\n name: 'Grenada',\n iso2: 'GD',\n flag: '๐Ÿ‡ฌ๐Ÿ‡ฉ',\n },\n {\n name: 'Guatemala',\n iso2: 'GT',\n flag: '๐Ÿ‡ฌ๐Ÿ‡น',\n },\n {\n name: 'Guinea',\n iso2: 'GN',\n flag: '๐Ÿ‡ฌ๐Ÿ‡ณ',\n },\n {\n name: 'Guinea-Bissau',\n iso2: 'GW',\n flag: '๐Ÿ‡ฌ๐Ÿ‡ผ',\n },\n {\n name: 'Guyana',\n iso2: 'GY',\n flag: '๐Ÿ‡ฌ๐Ÿ‡พ',\n },\n {\n name: 'Haiti',\n iso2: 'HT',\n flag: '๐Ÿ‡ญ๐Ÿ‡น',\n },\n {\n name: 'Honduras',\n iso2: 'HN',\n flag: '๐Ÿ‡ญ๐Ÿ‡ณ',\n },\n {\n name: 'Hungary',\n iso2: 'HU',\n flag: '๐Ÿ‡ญ๐Ÿ‡บ',\n },\n {\n name: 'Iceland',\n iso2: 'IS',\n flag: '๐Ÿ‡ฎ๐Ÿ‡ธ',\n },\n {\n name: 'Indonesia',\n iso2: 'ID',\n flag: '๐Ÿ‡ฎ๐Ÿ‡ฉ',\n },\n {\n name: 'Iran',\n iso2: 'IR',\n flag: '๐Ÿ‡ฎ๐Ÿ‡ท',\n },\n {\n name: 'Iraq',\n iso2: 'IQ',\n flag: '๐Ÿ‡ฎ๐Ÿ‡ถ',\n },\n {\n name: 'Ireland',\n iso2: 'IE',\n flag: '๐Ÿ‡ฎ๐Ÿ‡ช',\n },\n {\n name: 'Israel',\n iso2: 'IL',\n flag: '๐Ÿ‡ฎ๐Ÿ‡ฑ',\n },\n {\n name: 'Italy',\n iso2: 'IT',\n flag: '๐Ÿ‡ฎ๐Ÿ‡น',\n },\n {\n name: 'Jamaica',\n iso2: 'JM',\n flag: '๐Ÿ‡ฏ๐Ÿ‡ฒ',\n },\n {\n name: 'Jordan',\n iso2: 'JO',\n flag: '๐Ÿ‡ฏ๐Ÿ‡ด',\n },\n {\n name: 'Kazakhstan',\n iso2: 'KZ',\n flag: '๐Ÿ‡ฐ๐Ÿ‡ฟ',\n },\n {\n name: 'Kenya',\n iso2: 'KE',\n flag: '๐Ÿ‡ฐ๐Ÿ‡ช',\n },\n {\n name: 'Kiribati',\n iso2: 'KI',\n flag: '๐Ÿ‡ฐ๐Ÿ‡ฎ',\n },\n {\n name: 'Kuwait',\n iso2: 'KW',\n flag: '๐Ÿ‡ฐ๐Ÿ‡ผ',\n },\n {\n name: 'Kyrgyzstan',\n iso2: 'KG',\n flag: '๐Ÿ‡ฐ๐Ÿ‡ฌ',\n },\n {\n name: 'Laos',\n iso2: 'LA',\n flag: '๐Ÿ‡ฑ๐Ÿ‡ฆ',\n },\n {\n name: 'Latvia',\n iso2: 'LV',\n flag: '๐Ÿ‡ฑ๐Ÿ‡ป',\n },\n {\n name: 'Lebanon',\n iso2: 'LB',\n flag: '๐Ÿ‡ฑ๐Ÿ‡ง',\n },\n {\n name: 'Lesotho',\n iso2: 'LS',\n flag: '๐Ÿ‡ฑ๐Ÿ‡ธ',\n },\n {\n name: 'Liberia',\n iso2: 'LR',\n flag: '๐Ÿ‡ฑ๐Ÿ‡ท',\n },\n {\n name: 'Libya',\n iso2: 'LY',\n flag: '๐Ÿ‡ฑ๐Ÿ‡พ',\n },\n {\n name: 'Liechtenstein',\n iso2: 'LI',\n flag: '๐Ÿ‡ฑ๐Ÿ‡ฎ',\n },\n {\n name: 'Lithuania',\n iso2: 'LT',\n flag: '๐Ÿ‡ฑ๐Ÿ‡น',\n },\n {\n name: 'Luxembourg',\n iso2: 'LU',\n flag: '๐Ÿ‡ฑ๐Ÿ‡บ',\n },\n {\n name: 'Madagascar',\n iso2: 'MG',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ฌ',\n },\n {\n name: 'Malawi',\n iso2: 'MW',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ผ',\n },\n {\n name: 'Malaysia',\n iso2: 'MY',\n flag: '๐Ÿ‡ฒ๐Ÿ‡พ',\n },\n {\n name: 'Maldives',\n iso2: 'MV',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ป',\n },\n {\n name: 'Mali',\n iso2: 'ML',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ฑ',\n },\n {\n name: 'Malta',\n iso2: 'MT',\n flag: '๐Ÿ‡ฒ๐Ÿ‡น',\n },\n {\n name: 'Marshall Islands',\n iso2: 'MH',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ญ',\n },\n {\n name: 'Mauritania',\n iso2: 'MR',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ท',\n },\n {\n name: 'Mauritius',\n iso2: 'MU',\n flag: '๐Ÿ‡ฒ๐Ÿ‡บ',\n },\n {\n name: 'Mexico',\n iso2: 'MX',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ฝ',\n },\n {\n name: 'Micronesia',\n iso2: 'FM',\n flag: '๐Ÿ‡ซ๐Ÿ‡ฒ',\n },\n {\n name: 'Moldova',\n iso2: 'MD',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ฉ',\n },\n {\n name: 'Monaco',\n iso2: 'MC',\n flag: '๐Ÿ‡ฒ๐Ÿ‡จ',\n },\n {\n name: 'Mongolia',\n iso2: 'MN',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ณ',\n },\n {\n name: 'Montenegro',\n iso2: 'ME',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ช',\n },\n {\n name: 'Morocco',\n iso2: 'MA',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ฆ',\n },\n {\n name: 'Mozambique',\n iso2: 'MZ',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ฟ',\n },\n {\n name: 'Myanmar',\n iso2: 'MM',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ฒ',\n },\n {\n name: 'Namibia',\n iso2: 'NA',\n flag: '๐Ÿ‡ณ๐Ÿ‡ฆ',\n },\n {\n name: 'Nauru',\n iso2: 'NR',\n flag: '๐Ÿ‡ณ๐Ÿ‡ท',\n },\n {\n name: 'Nepal',\n iso2: 'NP',\n flag: '๐Ÿ‡ณ๐Ÿ‡ต',\n },\n {\n name: 'Netherlands',\n iso2: 'NL',\n flag: '๐Ÿ‡ณ๐Ÿ‡ฑ',\n },\n {\n name: 'New Zealand',\n iso2: 'NZ',\n flag: '๐Ÿ‡ณ๐Ÿ‡ฟ',\n },\n {\n name: 'Nicaragua',\n iso2: 'NI',\n flag: '๐Ÿ‡ณ๐Ÿ‡ฎ',\n },\n {\n name: 'Niger',\n iso2: 'NE',\n flag: '๐Ÿ‡ณ๐Ÿ‡ช',\n },\n {\n name: 'Nigeria',\n iso2: 'NG',\n flag: '๐Ÿ‡ณ๐Ÿ‡ฌ',\n },\n {\n name: 'North Korea',\n iso2: 'KP',\n flag: '๐Ÿ‡ฐ๐Ÿ‡ต',\n },\n {\n name: 'North Macedonia',\n iso2: 'MK',\n flag: '๐Ÿ‡ฒ๐Ÿ‡ฐ',\n },\n {\n name: 'Norway',\n iso2: 'NO',\n flag: '๐Ÿ‡ณ๐Ÿ‡ด',\n },\n {\n name: 'Oman',\n iso2: 'OM',\n flag: '๐Ÿ‡ด๐Ÿ‡ฒ',\n },\n {\n name: 'Pakistan',\n iso2: 'PK',\n flag: '๐Ÿ‡ต๐Ÿ‡ฐ',\n },\n {\n name: 'Palau',\n iso2: 'PW',\n flag: '๐Ÿ‡ต๐Ÿ‡ผ',\n },\n {\n name: 'Panama',\n iso2: 'PA',\n flag: '๐Ÿ‡ต๐Ÿ‡ฆ',\n },\n {\n name: 'Papua New Guinea',\n iso2: 'PG',\n flag: '๐Ÿ‡ต๐Ÿ‡ฌ',\n },\n {\n name: 'Paraguay',\n iso2: 'PY',\n flag: '๐Ÿ‡ต๐Ÿ‡พ',\n },\n {\n name: 'Peru',\n iso2: 'PE',\n flag: '๐Ÿ‡ต๐Ÿ‡ช',\n },\n {\n name: 'Philippines',\n iso2: 'PH',\n flag: '๐Ÿ‡ต๐Ÿ‡ญ',\n },\n {\n name: 'Poland',\n iso2: 'PL',\n flag: '๐Ÿ‡ต๐Ÿ‡ฑ',\n },\n {\n name: 'Portugal',\n iso2: 'PT',\n flag: '๐Ÿ‡ต๐Ÿ‡น',\n },\n {\n name: 'Qatar',\n iso2: 'QA',\n flag: '๐Ÿ‡ถ๐Ÿ‡ฆ',\n },\n {\n name: 'Romania',\n iso2: 'RO',\n flag: '๐Ÿ‡ท๐Ÿ‡ด',\n },\n {\n name: 'Rwanda',\n iso2: 'RW',\n flag: '๐Ÿ‡ท๐Ÿ‡ผ',\n },\n {\n name: 'Saint Kitts and Nevis',\n iso2: 'KN',\n flag: '๐Ÿ‡ฐ๐Ÿ‡ณ',\n },\n {\n name: 'Saint Lucia',\n iso2: 'LC',\n flag: '๐Ÿ‡ฑ๐Ÿ‡จ',\n },\n {\n name: 'Saint Vincent and the Grenadines',\n iso2: 'VC',\n flag: '๐Ÿ‡ป๐Ÿ‡จ',\n },\n {\n name: 'Samoa',\n iso2: 'WS',\n flag: '๐Ÿ‡ผ๐Ÿ‡ธ',\n },\n {\n name: 'San Marino',\n iso2: 'SM',\n flag: '๐Ÿ‡ธ๐Ÿ‡ฒ',\n },\n {\n name: 'Sao Tome and Principe',\n iso2: 'ST',\n flag: '๐Ÿ‡ธ๐Ÿ‡น',\n },\n {\n name: 'Senegal',\n iso2: 'SN',\n flag: '๐Ÿ‡ธ๐Ÿ‡ณ',\n },\n {\n name: 'Serbia',\n iso2: 'RS',\n flag: '๐Ÿ‡ท๐Ÿ‡ธ',\n },\n {\n name: 'Seychelles',\n iso2: 'SC',\n flag: '๐Ÿ‡ธ๐Ÿ‡จ',\n },\n {\n name: 'Sierra Leone',\n iso2: 'SL',\n flag: '๐Ÿ‡ธ๐Ÿ‡ฑ',\n },\n {\n name: 'Singapore',\n iso2: 'SG',\n flag: '๐Ÿ‡ธ๐Ÿ‡ฌ',\n },\n {\n name: 'Slovakia',\n iso2: 'SK',\n flag: '๐Ÿ‡ธ๐Ÿ‡ฐ',\n },\n {\n name: 'Slovenia',\n iso2: 'SI',\n flag: '๐Ÿ‡ธ๐Ÿ‡ฎ',\n },\n {\n name: 'Solomon Islands',\n iso2: 'SB',\n flag: '๐Ÿ‡ธ๐Ÿ‡ง',\n },\n {\n name: 'Somalia',\n iso2: 'SO',\n flag: '๐Ÿ‡ธ๐Ÿ‡ด',\n },\n {\n name: 'South Korea',\n iso2: 'KR',\n flag: '๐Ÿ‡ฐ๐Ÿ‡ท',\n },\n {\n name: 'South Sudan',\n iso2: 'SS',\n flag: '๐Ÿ‡ธ๐Ÿ‡ธ',\n },\n {\n name: 'Spain',\n iso2: 'ES',\n flag: '๐Ÿ‡ช๐Ÿ‡ธ',\n },\n {\n name: 'Sri Lanka',\n iso2: 'LK',\n flag: '๐Ÿ‡ฑ๐Ÿ‡ฐ',\n },\n {\n name: 'Sudan',\n iso2: 'SD',\n flag: '๐Ÿ‡ธ๐Ÿ‡ฉ',\n },\n {\n name: 'Suriname',\n iso2: 'SR',\n flag: '๐Ÿ‡ธ๐Ÿ‡ท',\n },\n {\n name: 'Sweden',\n iso2: 'SE',\n flag: '๐Ÿ‡ธ๐Ÿ‡ช',\n },\n {\n name: 'Switzerland',\n iso2: 'CH',\n flag: '๐Ÿ‡จ๐Ÿ‡ญ',\n },\n {\n name: 'Syria',\n iso2: 'SY',\n flag: '๐Ÿ‡ธ๐Ÿ‡พ',\n },\n {\n name: 'Tajikistan',\n iso2: 'TJ',\n flag: '๐Ÿ‡น๐Ÿ‡ฏ',\n },\n {\n name: 'Tanzania',\n iso2: 'TZ',\n flag: '๐Ÿ‡น๐Ÿ‡ฟ',\n },\n {\n name: 'Thailand',\n iso2: 'TH',\n flag: '๐Ÿ‡น๐Ÿ‡ญ',\n },\n {\n name: 'Togo',\n iso2: 'TG',\n flag: '๐Ÿ‡น๐Ÿ‡ฌ',\n },\n {\n name: 'Tonga',\n iso2: 'TO',\n flag: '๐Ÿ‡น๐Ÿ‡ด',\n },\n {\n name: 'Trinidad and Tobago',\n iso2: 'TT',\n flag: '๐Ÿ‡น๐Ÿ‡น',\n },\n {\n name: 'Tunisia',\n iso2: 'TN',\n flag: '๐Ÿ‡น๐Ÿ‡ณ',\n },\n {\n name: 'Turkey',\n iso2: 'TR',\n flag: '๐Ÿ‡น๐Ÿ‡ท',\n },\n {\n name: 'Turkmenistan',\n iso2: 'TM',\n flag: '๐Ÿ‡น๐Ÿ‡ฒ',\n },\n {\n name: 'Tuvalu',\n iso2: 'TV',\n flag: '๐Ÿ‡น๐Ÿ‡ป',\n },\n {\n name: 'Uganda',\n iso2: 'UG',\n flag: '๐Ÿ‡บ๐Ÿ‡ฌ',\n },\n {\n name: 'Ukraine',\n iso2: 'UA',\n flag: '๐Ÿ‡บ๐Ÿ‡ฆ',\n },\n {\n name: 'United Arab Emirates',\n iso2: 'AE',\n flag: '๐Ÿ‡ฆ๐Ÿ‡ช',\n },\n {\n name: 'Uruguay',\n iso2: 'UY',\n flag: '๐Ÿ‡บ๐Ÿ‡พ',\n },\n {\n name: 'Uzbekistan',\n iso2: 'UZ',\n flag: '๐Ÿ‡บ๐Ÿ‡ฟ',\n },\n {\n name: 'Vanuatu',\n iso2: 'VU',\n flag: '๐Ÿ‡ป๐Ÿ‡บ',\n },\n {\n name: 'Venezuela',\n iso2: 'VE',\n flag: '๐Ÿ‡ป๐Ÿ‡ช',\n },\n {\n name: 'Vietnam',\n iso2: 'VN',\n flag: '๐Ÿ‡ป๐Ÿ‡ณ',\n },\n {\n name: 'Yemen',\n iso2: 'YE',\n flag: '๐Ÿ‡พ๐Ÿ‡ช',\n },\n {\n name: 'Zambia',\n iso2: 'ZM',\n flag: '๐Ÿ‡ฟ๐Ÿ‡ฒ',\n },\n {\n name: 'Zimbabwe',\n iso2: 'ZW',\n flag: '๐Ÿ‡ฟ๐Ÿ‡ผ',\n },\n {\n name: 'Timor-Leste',\n iso2: 'TL',\n flag: '๐Ÿ‡น๐Ÿ‡ฑ',\n },\n] as const\n"],"mappings":";AAAA,MAAa,YAAY;CACvB;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;CACR;AACF"}
@@ -0,0 +1,17 @@
1
+ //#region src/device.ts
2
+ /**
3
+ * Coarse desktop/mobile detection used to decide whether to offer cross-device
4
+ * handoff. Handoff is most useful when the user starts on a desktop (no good
5
+ * camera) and continues on a phone, so projects can restrict it to desktops.
6
+ */
7
+ function isDesktopDevice(nav) {
8
+ const ua = nav.userAgent || "";
9
+ if (!ua) return false;
10
+ const mobile = /Android|iPhone|iPad|iPod|Opera Mini|IEMobile|Mobile|BlackBerry|Windows Phone/i.test(ua);
11
+ const iPadOS = nav.platform === "MacIntel" && (nav.maxTouchPoints ?? 0) > 1;
12
+ return !mobile && !iPadOS;
13
+ }
14
+ //#endregion
15
+ export { isDesktopDevice };
16
+
17
+ //# sourceMappingURL=device.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.mjs","names":[],"sources":["../src/device.ts"],"sourcesContent":["/**\n * Coarse desktop/mobile detection used to decide whether to offer cross-device\n * handoff. Handoff is most useful when the user starts on a desktop (no good\n * camera) and continues on a phone, so projects can restrict it to desktops.\n */\nexport function isDesktopDevice(nav: Navigator): boolean {\n const ua = nav.userAgent || ''\n // Require a positive desktop signal: an unknown/empty UA is treated as\n // non-desktop so the QR-first handoff flow never triggers on uncertainty.\n if (!ua) return false\n const mobile = /Android|iPhone|iPad|iPod|Opera Mini|IEMobile|Mobile|BlackBerry|Windows Phone/i.test(ua)\n // iPadOS 13+ masquerades as desktop Safari but reports touch points.\n const iPadOS = nav.platform === 'MacIntel' && (nav.maxTouchPoints ?? 0) > 1\n return !mobile && !iPadOS\n}\n"],"mappings":";;;;;;AAKA,SAAgB,gBAAgB,KAAyB;CACvD,MAAM,KAAK,IAAI,aAAa;CAG5B,IAAI,CAAC,IAAI,OAAO;CAChB,MAAM,SAAS,gFAAgF,KAAK,EAAE;CAEtG,MAAM,SAAS,IAAI,aAAa,eAAe,IAAI,kBAAkB,KAAK;CAC1E,OAAO,CAAC,UAAU,CAAC;AACrB"}
@@ -0,0 +1,108 @@
1
+ //#region src/document.d.ts
2
+ /**
3
+ * In-browser document detection for the capture screens. Pure JavaScript, no
4
+ * dependency: it draws the current frame to a small canvas and runs Sobel edge
5
+ * projection to locate the document's four borders, then judges whether a real,
6
+ * well-framed, in-focus document is present before auto-capturing.
7
+ *
8
+ * Like the face analyzer it is feature-detected and wrapped so that on any
9
+ * failure (no 2D canvas, a non-browser/test host) `ready()` resolves `false` and
10
+ * the caller falls back to the simpler brightness heuristic. The detection core
11
+ * (`analyzeDocumentGray` / `documentGuidance`) is a set of pure functions over a
12
+ * grayscale buffer, so it is unit-testable without a real canvas or camera.
13
+ */
14
+ /** Detected document rectangle, normalized 0โ€“1 within the frame. */
15
+ interface DocRect {
16
+ x: number;
17
+ y: number;
18
+ w: number;
19
+ h: number;
20
+ }
21
+ /**
22
+ * A normalized read of the current frame's document candidate.
23
+ */
24
+ interface DocumentSample {
25
+ /** A plausible rectangular document border was found. */
26
+ present: boolean;
27
+ /** The detected border rectangle (normalized 0โ€“1). */
28
+ rect: DocRect;
29
+ /** Rectangle area as a fraction of the frame (proxy for distance). */
30
+ fill: number;
31
+ centerX: number;
32
+ centerY: number;
33
+ /** Weakest of the four border edges, 0โ€“1 (how convincingly bordered it is). */
34
+ edgeStrength: number;
35
+ /** Variance of the Laplacian over the frame โ€” a focus/blur proxy (higher = sharper). */
36
+ sharpness: number;
37
+ /** Mean luminance, 0โ€“1. */
38
+ brightness: number;
39
+ }
40
+ interface DocumentAnalyzer {
41
+ /** Prepare the canvas. Resolves `false` if unavailable โ€” callers go manual. */
42
+ ready(): Promise<boolean>;
43
+ /** Analyze the current video frame, or `null` if it can't be read. */
44
+ analyze(video: HTMLVideoElement): DocumentSample | null;
45
+ /** Release resources. */
46
+ close(): void;
47
+ }
48
+ /**
49
+ * Detection thresholds. Tunable per-widget via `documentTuning`. Like the face
50
+ * tuning, the geometric/strength knobs benefit from calibration against real
51
+ * devices and lighting.
52
+ */
53
+ interface DocumentTuning {
54
+ /** Width (px) the frame is downscaled to before analysis. */
55
+ sampleWidth: number;
56
+ /** Min / max rectangle area (fraction of frame) โ€” too small = far, too big = cropped. */
57
+ minFill: number;
58
+ maxFill: number;
59
+ /** Max distance of the document centre from the frame centre (0โ€“1). */
60
+ centerTol: number;
61
+ /** Min weakest-border strength to count as a real document edge (0โ€“1). */
62
+ minEdgeStrength: number;
63
+ /** Min Laplacian variance to count as in-focus. */
64
+ minSharpness: number;
65
+ /** Each border must sit at least this far (0โ€“1) inside the frame (not cropped). */
66
+ borderMargin: number;
67
+ /** Below this mean luminance the frame is treated as too dark. */
68
+ minBrightness: number;
69
+ /** Consecutive "ready" frames before auto-capture fires. */
70
+ hold: number;
71
+ }
72
+ declare const DEFAULT_DOCUMENT_TUNING: DocumentTuning;
73
+ /**
74
+ * Locate the dominant rectangle in a grayscale frame via Sobel edge projection,
75
+ * and measure focus and brightness. Pure โ€” operates on a grayscale buffer.
76
+ *
77
+ * @param tuning
78
+ * @returns
79
+ */
80
+ declare function analyzeDocumentGray(gray: ArrayLike<number>, w: number, h: number): DocumentSample;
81
+ /**
82
+ * Whether a document is present, well-framed and in focus, with a guidance hint.
83
+ *
84
+ * @param tuning
85
+ * @returns
86
+ */
87
+ declare function documentGuidance(s: DocumentSample, t?: DocumentTuning): {
88
+ ready: boolean;
89
+ hint: string;
90
+ };
91
+ /**
92
+ * Whether the sample is a well-framed, in-focus document ready to capture.
93
+ *
94
+ * @param s
95
+ * @param t
96
+ * @returns
97
+ */
98
+ declare function isDocumentReady(s: DocumentSample, t?: DocumentTuning): boolean;
99
+ /**
100
+ * The default (canvas edge-projection) document analyzer.
101
+ *
102
+ * @param tuning
103
+ * @returns
104
+ */
105
+ declare function createDefaultDocumentAnalyzer(tuning?: DocumentTuning): DocumentAnalyzer;
106
+ //#endregion
107
+ export { DEFAULT_DOCUMENT_TUNING, DocRect, DocumentAnalyzer, DocumentSample, DocumentTuning, analyzeDocumentGray, createDefaultDocumentAnalyzer, documentGuidance, isDocumentReady };
108
+ //# sourceMappingURL=document.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.d.mts","names":[],"sources":["../src/document.ts"],"mappings":";;AAcA;;;;;;;;;AAIG;AAMH;;UAViB,OAAA;EACf,CAAA;EACA,CAAA;EACA,CAAA;EACA,CAAA;AAAA;;;;UAMe,cAAA;EAcf;EAZA,OAAA;EAYU;EAVV,IAAA,EAAM,OAAO;EAakB;EAX/B,IAAA;EACA,OAAA;EACA,OAAA;EAakC;EAXlC,YAAA;EAWgD;EAThD,SAAA;EAOS;EALT,UAAA;AAAA;AAAA,UAGe,gBAAA;EAImB;EAFlC,KAAA,IAAS,OAAA;EAIJ;EAFL,OAAA,CAAQ,KAAA,EAAO,gBAAA,GAAmB,cAAA;EAUnB;EARf,KAAA;AAAA;;;;;;UAQe,cAAA;EAWf;EATA,WAAA;EAaA;EAXA,OAAA;EACA,OAAA;EAYI;EAVJ,SAAA;EA0BD;EAxBC,eAAA;EAwBD;EAtBC,YAAA;EAsDc;EApDd,YAAA;;EAEA,aAAA;EAkDwC;EAhDxC,IAAA;AAAA;AAAA,cAGW,uBAAA,EAAyB,cAarC;;;AAgCiG;AAgGlG;;;;iBAhGgB,mBAAA,CAAoB,IAAA,EAAM,SAAA,UAAmB,CAAA,UAAW,CAAA,WAAY,cAAc;;;;;;;iBAgGlF,gBAAA,CACd,CAAA,EAAG,cAAA,EACH,CAAA,GAAG,cAAwC;EACxC,KAAA;EAAgB,IAAA;AAAA;;;;;;;AAuByE;iBAA9E,eAAA,CAAgB,CAAA,EAAG,cAAA,EAAgB,CAAA,GAAG,cAAwC;;;;;;;iBAwD9E,6BAAA,CAA8B,MAAA,GAAQ,cAAA,GAA2C,gBAAgB"}
@@ -0,0 +1,227 @@
1
+ //#region src/document.ts
2
+ const DEFAULT_DOCUMENT_TUNING = {
3
+ sampleWidth: 320,
4
+ minFill: .18,
5
+ maxFill: .97,
6
+ centerTol: .22,
7
+ minEdgeStrength: .1,
8
+ minSharpness: 8,
9
+ borderMargin: .012,
10
+ minBrightness: .18,
11
+ hold: 5
12
+ };
13
+ /**
14
+ * The four border insets of a rect from the frame edges (top, right, bottom, left).
15
+ *
16
+ * @param rect
17
+ * @returns
18
+ */
19
+ function margins(rect) {
20
+ return [
21
+ rect.y,
22
+ 1 - (rect.x + rect.w),
23
+ 1 - (rect.y + rect.h),
24
+ rect.x
25
+ ];
26
+ }
27
+ function peak(arr, lo, hi) {
28
+ let bi = lo;
29
+ let bv = -1;
30
+ for (let i = lo; i < hi; i += 1) {
31
+ const v = arr[i];
32
+ if (v > bv) {
33
+ bv = v;
34
+ bi = i;
35
+ }
36
+ }
37
+ return {
38
+ i: bi,
39
+ v: bv
40
+ };
41
+ }
42
+ /**
43
+ * Locate the dominant rectangle in a grayscale frame via Sobel edge projection,
44
+ * and measure focus and brightness. Pure โ€” operates on a grayscale buffer.
45
+ *
46
+ * @param tuning
47
+ * @returns
48
+ */
49
+ function analyzeDocumentGray(gray, w, h) {
50
+ const empty = {
51
+ present: false,
52
+ rect: {
53
+ x: 0,
54
+ y: 0,
55
+ w: 0,
56
+ h: 0
57
+ },
58
+ fill: 0,
59
+ centerX: .5,
60
+ centerY: .5,
61
+ edgeStrength: 0,
62
+ sharpness: 0,
63
+ brightness: 0
64
+ };
65
+ if (w < 8 || h < 8 || gray.length < w * h) return empty;
66
+ const rowH = new Float64Array(h);
67
+ const colV = new Float64Array(w);
68
+ let lapSum = 0;
69
+ let lapSumSq = 0;
70
+ let lapN = 0;
71
+ let lumSum = 0;
72
+ for (let i = 0; i < w * h; i += 1) lumSum += gray[i];
73
+ const brightness = lumSum / (w * h * 255);
74
+ for (let y = 1; y < h - 1; y += 1) for (let x = 1; x < w - 1; x += 1) {
75
+ const i = y * w + x;
76
+ const tl = gray[i - w - 1];
77
+ const tc = gray[i - w];
78
+ const tr = gray[i - w + 1];
79
+ const ml = gray[i - 1];
80
+ const c = gray[i];
81
+ const mr = gray[i + 1];
82
+ const bl = gray[i + w - 1];
83
+ const bc = gray[i + w];
84
+ const br = gray[i + w + 1];
85
+ const gx = tr + 2 * mr + br - (tl + 2 * ml + bl);
86
+ const gy = bl + 2 * bc + br - (tl + 2 * tc + tr);
87
+ rowH[y] += Math.abs(gy);
88
+ colV[x] += Math.abs(gx);
89
+ const lap = 4 * c - ml - mr - tc - bc;
90
+ lapSum += lap;
91
+ lapSumSq += lap * lap;
92
+ lapN += 1;
93
+ }
94
+ const sharpness = lapN ? lapSumSq / lapN - (lapSum / lapN) ** 2 : 0;
95
+ const bandH = Math.max(1, Math.floor(h * .05));
96
+ const bandW = Math.max(1, Math.floor(w * .05));
97
+ const midY = Math.floor(h / 2);
98
+ const midX = Math.floor(w / 2);
99
+ const top = peak(rowH, bandH, midY);
100
+ const bottom = peak(rowH, midY, h - bandH);
101
+ const left = peak(colV, bandW, midX);
102
+ const right = peak(colV, midX, w - bandW);
103
+ const x0 = left.i / w;
104
+ const x1 = right.i / w;
105
+ const y0 = top.i / h;
106
+ const y1 = bottom.i / h;
107
+ const rect = {
108
+ x: x0,
109
+ y: y0,
110
+ w: Math.max(0, x1 - x0),
111
+ h: Math.max(0, y1 - y0)
112
+ };
113
+ const topLenPx = Math.max(1, rect.w * w);
114
+ const sideLenPx = Math.max(1, rect.h * h);
115
+ const edgeStrength = Math.min(top.v / (topLenPx * 1020), bottom.v / (topLenPx * 1020), left.v / (sideLenPx * 1020), right.v / (sideLenPx * 1020));
116
+ return {
117
+ present: rect.w > .12 && rect.h > .12 && edgeStrength > .04,
118
+ rect,
119
+ fill: rect.w * rect.h,
120
+ centerX: (x0 + x1) / 2,
121
+ centerY: (y0 + y1) / 2,
122
+ edgeStrength,
123
+ sharpness,
124
+ brightness
125
+ };
126
+ }
127
+ /**
128
+ * Whether a document is present, well-framed and in focus, with a guidance hint.
129
+ *
130
+ * @param tuning
131
+ * @returns
132
+ */
133
+ function documentGuidance(s, t = DEFAULT_DOCUMENT_TUNING) {
134
+ if (s.brightness < t.minBrightness) return {
135
+ ready: false,
136
+ hint: "Too dark โ€” find better lighting"
137
+ };
138
+ if (!s.present || s.edgeStrength < t.minEdgeStrength) return {
139
+ ready: false,
140
+ hint: "Fit your document inside the frame"
141
+ };
142
+ if (s.fill > t.maxFill || Math.min(...margins(s.rect)) < t.borderMargin) return {
143
+ ready: false,
144
+ hint: "Move back a little โ€” fit the whole document"
145
+ };
146
+ if (s.fill < t.minFill) return {
147
+ ready: false,
148
+ hint: "Move closer"
149
+ };
150
+ if (Math.abs(s.centerX - .5) > t.centerTol || Math.abs(s.centerY - .5) > t.centerTol) return {
151
+ ready: false,
152
+ hint: "Center the document"
153
+ };
154
+ if (s.sharpness < t.minSharpness) return {
155
+ ready: false,
156
+ hint: "Hold steady to focus"
157
+ };
158
+ return {
159
+ ready: true,
160
+ hint: "Looks good โ€” hold steady"
161
+ };
162
+ }
163
+ /**
164
+ * Whether the sample is a well-framed, in-focus document ready to capture.
165
+ *
166
+ * @param s
167
+ * @param t
168
+ * @returns
169
+ */
170
+ function isDocumentReady(s, t = DEFAULT_DOCUMENT_TUNING) {
171
+ return documentGuidance(s, t).ready;
172
+ }
173
+ var CanvasDocumentAnalyzer = class {
174
+ tuning;
175
+ canvas = null;
176
+ ctx = null;
177
+ constructor(tuning) {
178
+ this.tuning = tuning;
179
+ }
180
+ ready() {
181
+ try {
182
+ if (typeof document === "undefined") return Promise.resolve(false);
183
+ const canvas = document.createElement("canvas");
184
+ const ctx = canvas.getContext("2d", { willReadFrequently: true });
185
+ if (!ctx) return Promise.resolve(false);
186
+ this.canvas = canvas;
187
+ this.ctx = ctx;
188
+ return Promise.resolve(true);
189
+ } catch {
190
+ return Promise.resolve(false);
191
+ }
192
+ }
193
+ analyze(video) {
194
+ if (!this.ctx || !this.canvas || !video.videoWidth) return null;
195
+ const tw = this.tuning.sampleWidth;
196
+ const th = Math.max(1, Math.round(tw * video.videoHeight / video.videoWidth));
197
+ this.canvas.width = tw;
198
+ this.canvas.height = th;
199
+ let data;
200
+ try {
201
+ this.ctx.drawImage(video, 0, 0, tw, th);
202
+ data = this.ctx.getImageData(0, 0, tw, th).data;
203
+ } catch {
204
+ return null;
205
+ }
206
+ const gray = new Float32Array(tw * th);
207
+ for (let i = 0, p = 0; i < gray.length; i += 1, p += 4) gray[i] = .299 * data[p] + .587 * data[p + 1] + .114 * data[p + 2];
208
+ return analyzeDocumentGray(gray, tw, th);
209
+ }
210
+ close() {
211
+ this.canvas = null;
212
+ this.ctx = null;
213
+ }
214
+ };
215
+ /**
216
+ * The default (canvas edge-projection) document analyzer.
217
+ *
218
+ * @param tuning
219
+ * @returns
220
+ */
221
+ function createDefaultDocumentAnalyzer(tuning = DEFAULT_DOCUMENT_TUNING) {
222
+ return new CanvasDocumentAnalyzer(tuning);
223
+ }
224
+ //#endregion
225
+ export { DEFAULT_DOCUMENT_TUNING, analyzeDocumentGray, createDefaultDocumentAnalyzer, documentGuidance, isDocumentReady };
226
+
227
+ //# sourceMappingURL=document.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.mjs","names":[],"sources":["../src/document.ts"],"sourcesContent":["/**\n * In-browser document detection for the capture screens. Pure JavaScript, no\n * dependency: it draws the current frame to a small canvas and runs Sobel edge\n * projection to locate the document's four borders, then judges whether a real,\n * well-framed, in-focus document is present before auto-capturing.\n *\n * Like the face analyzer it is feature-detected and wrapped so that on any\n * failure (no 2D canvas, a non-browser/test host) `ready()` resolves `false` and\n * the caller falls back to the simpler brightness heuristic. The detection core\n * (`analyzeDocumentGray` / `documentGuidance`) is a set of pure functions over a\n * grayscale buffer, so it is unit-testable without a real canvas or camera.\n */\n\n/** Detected document rectangle, normalized 0โ€“1 within the frame. */\nexport interface DocRect {\n x: number\n y: number\n w: number\n h: number\n}\n\n/**\n * A normalized read of the current frame's document candidate.\n */\nexport interface DocumentSample {\n /** A plausible rectangular document border was found. */\n present: boolean\n /** The detected border rectangle (normalized 0โ€“1). */\n rect: DocRect\n /** Rectangle area as a fraction of the frame (proxy for distance). */\n fill: number\n centerX: number\n centerY: number\n /** Weakest of the four border edges, 0โ€“1 (how convincingly bordered it is). */\n edgeStrength: number\n /** Variance of the Laplacian over the frame โ€” a focus/blur proxy (higher = sharper). */\n sharpness: number\n /** Mean luminance, 0โ€“1. */\n brightness: number\n}\n\nexport interface DocumentAnalyzer {\n /** Prepare the canvas. Resolves `false` if unavailable โ€” callers go manual. */\n ready(): Promise<boolean>\n /** Analyze the current video frame, or `null` if it can't be read. */\n analyze(video: HTMLVideoElement): DocumentSample | null\n /** Release resources. */\n close(): void\n}\n\n/**\n * Detection thresholds. Tunable per-widget via `documentTuning`. Like the face\n * tuning, the geometric/strength knobs benefit from calibration against real\n * devices and lighting.\n */\nexport interface DocumentTuning {\n /** Width (px) the frame is downscaled to before analysis. */\n sampleWidth: number\n /** Min / max rectangle area (fraction of frame) โ€” too small = far, too big = cropped. */\n minFill: number\n maxFill: number\n /** Max distance of the document centre from the frame centre (0โ€“1). */\n centerTol: number\n /** Min weakest-border strength to count as a real document edge (0โ€“1). */\n minEdgeStrength: number\n /** Min Laplacian variance to count as in-focus. */\n minSharpness: number\n /** Each border must sit at least this far (0โ€“1) inside the frame (not cropped). */\n borderMargin: number\n /** Below this mean luminance the frame is treated as too dark. */\n minBrightness: number\n /** Consecutive \"ready\" frames before auto-capture fires. */\n hold: number\n}\n\nexport const DEFAULT_DOCUMENT_TUNING: DocumentTuning = {\n sampleWidth: 320,\n // Edge-projection underestimates the document rectangle when the strongest\n // borders sit inside the card, so a demanding minFill reads as a constant\n // \"move closer\". Keep it modest; framing is still gated by maxFill + margins.\n minFill: 0.18,\n maxFill: 0.97,\n centerTol: 0.22,\n minEdgeStrength: 0.1,\n minSharpness: 8,\n borderMargin: 0.012,\n minBrightness: 0.18,\n hold: 5,\n}\n\n/**\n * The four border insets of a rect from the frame edges (top, right, bottom, left).\n *\n * @param rect\n * @returns\n */\nfunction margins(rect: DocRect): [number, number, number, number] {\n return [rect.y, 1 - (rect.x + rect.w), 1 - (rect.y + rect.h), rect.x]\n}\n\nfunction peak(arr: Float64Array, lo: number, hi: number): { i: number; v: number } {\n let bi = lo\n let bv = -1\n for (let i = lo; i < hi; i += 1) {\n const v = arr[i]!\n if (v > bv) {\n bv = v\n bi = i\n }\n }\n return { i: bi, v: bv }\n}\n\n/**\n * Locate the dominant rectangle in a grayscale frame via Sobel edge projection,\n * and measure focus and brightness. Pure โ€” operates on a grayscale buffer.\n *\n * @param tuning\n * @returns\n */\nexport function analyzeDocumentGray(gray: ArrayLike<number>, w: number, h: number): DocumentSample {\n const empty: DocumentSample = {\n present: false,\n rect: { x: 0, y: 0, w: 0, h: 0 },\n fill: 0,\n centerX: 0.5,\n centerY: 0.5,\n edgeStrength: 0,\n sharpness: 0,\n brightness: 0,\n }\n if (w < 8 || h < 8 || gray.length < w * h) return empty\n\n // Per-row horizontal-edge energy (|gy|) and per-column vertical-edge energy (|gx|).\n const rowH = new Float64Array(h)\n const colV = new Float64Array(w)\n let lapSum = 0\n let lapSumSq = 0\n let lapN = 0\n let lumSum = 0\n for (let i = 0; i < w * h; i += 1) lumSum += gray[i]!\n const brightness = lumSum / (w * h * 255)\n\n for (let y = 1; y < h - 1; y += 1) {\n for (let x = 1; x < w - 1; x += 1) {\n const i = y * w + x\n const tl = gray[i - w - 1]!\n const tc = gray[i - w]!\n const tr = gray[i - w + 1]!\n const ml = gray[i - 1]!\n const c = gray[i]!\n const mr = gray[i + 1]!\n const bl = gray[i + w - 1]!\n const bc = gray[i + w]!\n const br = gray[i + w + 1]!\n const gx = tr + 2 * mr + br - (tl + 2 * ml + bl)\n const gy = bl + 2 * bc + br - (tl + 2 * tc + tr)\n rowH[y]! += Math.abs(gy)\n colV[x]! += Math.abs(gx)\n const lap = 4 * c - ml - mr - tc - bc\n lapSum += lap\n lapSumSq += lap * lap\n lapN += 1\n }\n }\n const sharpness = lapN ? lapSumSq / lapN - (lapSum / lapN) ** 2 : 0\n\n const bandH = Math.max(1, Math.floor(h * 0.05))\n const bandW = Math.max(1, Math.floor(w * 0.05))\n const midY = Math.floor(h / 2)\n const midX = Math.floor(w / 2)\n\n // Top/bottom borders are the strongest horizontal edges in the upper/lower half;\n // left/right borders the strongest vertical edges in the left/right half.\n const top = peak(rowH, bandH, midY)\n const bottom = peak(rowH, midY, h - bandH)\n const left = peak(colV, bandW, midX)\n const right = peak(colV, midX, w - bandW)\n\n const x0 = left.i / w\n const x1 = right.i / w\n const y0 = top.i / h\n const y1 = bottom.i / h\n const rect: DocRect = { x: x0, y: y0, w: Math.max(0, x1 - x0), h: Math.max(0, y1 - y0) }\n\n // Normalize each border by its own length (max |sobel| โ‰ˆ 4ยท255), so strength\n // measures how cleanly bordered the edge is, independent of document size โ€”\n // size is judged separately by `fill`.\n const topLenPx = Math.max(1, rect.w * w)\n const sideLenPx = Math.max(1, rect.h * h)\n const edgeStrength = Math.min(\n top.v / (topLenPx * 1020),\n bottom.v / (topLenPx * 1020),\n left.v / (sideLenPx * 1020),\n right.v / (sideLenPx * 1020),\n )\n const present = rect.w > 0.12 && rect.h > 0.12 && edgeStrength > 0.04\n\n return {\n present,\n rect,\n fill: rect.w * rect.h,\n centerX: (x0 + x1) / 2,\n centerY: (y0 + y1) / 2,\n edgeStrength,\n sharpness,\n brightness,\n }\n}\n\n/**\n * Whether a document is present, well-framed and in focus, with a guidance hint.\n *\n * @param tuning\n * @returns\n */\nexport function documentGuidance(\n s: DocumentSample,\n t: DocumentTuning = DEFAULT_DOCUMENT_TUNING,\n): { ready: boolean; hint: string } {\n if (s.brightness < t.minBrightness) return { ready: false, hint: 'Too dark โ€” find better lighting' }\n if (!s.present || s.edgeStrength < t.minEdgeStrength) {\n return { ready: false, hint: 'Fit your document inside the frame' }\n }\n if (s.fill > t.maxFill || Math.min(...margins(s.rect)) < t.borderMargin) {\n return { ready: false, hint: 'Move back a little โ€” fit the whole document' }\n }\n if (s.fill < t.minFill) return { ready: false, hint: 'Move closer' }\n if (Math.abs(s.centerX - 0.5) > t.centerTol || Math.abs(s.centerY - 0.5) > t.centerTol) {\n return { ready: false, hint: 'Center the document' }\n }\n if (s.sharpness < t.minSharpness) return { ready: false, hint: 'Hold steady to focus' }\n return { ready: true, hint: 'Looks good โ€” hold steady' }\n}\n\n/**\n * Whether the sample is a well-framed, in-focus document ready to capture.\n *\n * @param s\n * @param t\n * @returns\n */\nexport function isDocumentReady(s: DocumentSample, t: DocumentTuning = DEFAULT_DOCUMENT_TUNING): boolean {\n return documentGuidance(s, t).ready\n}\n\nclass CanvasDocumentAnalyzer implements DocumentAnalyzer {\n private canvas: HTMLCanvasElement | null = null\n private ctx: CanvasRenderingContext2D | null = null\n\n constructor(private readonly tuning: DocumentTuning) {}\n\n ready(): Promise<boolean> {\n try {\n if (typeof document === 'undefined') return Promise.resolve(false)\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d', { willReadFrequently: true })\n if (!ctx) return Promise.resolve(false)\n this.canvas = canvas\n this.ctx = ctx\n return Promise.resolve(true)\n } catch {\n return Promise.resolve(false)\n }\n }\n\n analyze(video: HTMLVideoElement): DocumentSample | null {\n if (!this.ctx || !this.canvas || !video.videoWidth) return null\n const tw = this.tuning.sampleWidth\n const th = Math.max(1, Math.round((tw * video.videoHeight) / video.videoWidth))\n this.canvas.width = tw\n this.canvas.height = th\n let data: Uint8ClampedArray\n try {\n this.ctx.drawImage(video, 0, 0, tw, th)\n data = this.ctx.getImageData(0, 0, tw, th).data\n } catch {\n return null\n }\n const gray = new Float32Array(tw * th)\n for (let i = 0, p = 0; i < gray.length; i += 1, p += 4) {\n gray[i] = 0.299 * data[p]! + 0.587 * data[p + 1]! + 0.114 * data[p + 2]!\n }\n return analyzeDocumentGray(gray, tw, th)\n }\n\n close(): void {\n this.canvas = null\n this.ctx = null\n }\n}\n\n/**\n * The default (canvas edge-projection) document analyzer.\n *\n * @param tuning\n * @returns\n */\nexport function createDefaultDocumentAnalyzer(tuning: DocumentTuning = DEFAULT_DOCUMENT_TUNING): DocumentAnalyzer {\n return new CanvasDocumentAnalyzer(tuning)\n}\n"],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import { LivenessChallenge } from "@arkyc/types";
2
+
3
+ //#region src/face.d.ts
4
+ /** A normalized read of the current frame's face. */
5
+ interface FaceSample {
6
+ present: boolean;
7
+ /** Face bounding-box centre, normalized 0โ€“1. */
8
+ centerX: number;
9
+ centerY: number;
10
+ /** Face bounding-box height, normalized 0โ€“1 (proxy for distance). */
11
+ scale: number;
12
+ /** Head turn: <0 toward one side, >0 the other (approx, from landmark asymmetry). */
13
+ turn: number;
14
+ /** Head pitch proxy: nose-to-eye offset over face height (relative changes matter). */
15
+ pitch: number;
16
+ /** Eyes-closed score 0โ€“1 (blendshape). */
17
+ blink: number;
18
+ /** Smile score 0โ€“1 (blendshape). */
19
+ smile: number;
20
+ }
21
+ interface FaceAnalyzer {
22
+ /** Load models. Resolves `false` if unavailable โ€” callers then go manual. */
23
+ ready(): Promise<boolean>;
24
+ /** Analyze the current video frame, or `null` if it can't be read. */
25
+ analyze(video: HTMLVideoElement): FaceSample | null;
26
+ /** Release resources. */
27
+ close(): void;
28
+ }
29
+ /** The default (real, MediaPipe-backed) analyzer. */
30
+ declare function createDefaultFaceAnalyzer(): FaceAnalyzer;
31
+ /** A challenge detector: fed frame samples, returns `true` once satisfied. */
32
+ interface ChallengeDetector {
33
+ feed(sample: FaceSample): boolean;
34
+ /**
35
+ * 0โ€“1 progress toward satisfying the challenge, updated on each `feed` โ€” drives
36
+ * the UI's hold-progress ring. Multi-stage gestures (blink/nod) step through
37
+ * intermediate values; sustained gestures ramp with the hold streak.
38
+ */
39
+ readonly progress: number;
40
+ }
41
+ /**
42
+ * Detection thresholds. These are the knobs to tune against a real camera โ€”
43
+ * use the calibration harness (`playground/calibration.html`) to read live
44
+ * signal values and adjust. All are overridable per-widget via `faceTuning`.
45
+ */
46
+ interface FaceTuning {
47
+ /** |turn| asymmetry needed to count as a head turn. */
48
+ turn: number;
49
+ /** Mouth-smile blendshape score needed to count as a smile. */
50
+ smile: number;
51
+ /** Eye-blink score above which the eyes count as closed. */
52
+ blinkClosed: number;
53
+ /** Eye-blink score below which they count as re-opened. */
54
+ blinkOpen: number;
55
+ /** Consecutive frames a condition must hold before it fires. */
56
+ hold: number;
57
+ /** Pitch increase (looking down) needed to arm a nod. */
58
+ nodDown: number;
59
+ /** Pitch return delta (back up) that completes a nod. */
60
+ nodReturn: number;
61
+ /** Face must grow past `baseline * closerFactor` for move-closer. */
62
+ closerFactor: number;
63
+ /** Selfie framing tolerances (distance from frame centre / size window). */
64
+ selfieCenterTol: number;
65
+ selfieCenterYTol: number;
66
+ selfieMinScale: number;
67
+ selfieMaxScale: number;
68
+ }
69
+ declare const DEFAULT_TUNING: FaceTuning;
70
+ /**
71
+ * Build a stateful detector for a single active-liveness challenge.
72
+ *
73
+ * @param challenge
74
+ * @param t
75
+ * @returns
76
+ */
77
+ declare function makeChallengeDetector(challenge: LivenessChallenge, t?: FaceTuning): ChallengeDetector;
78
+ /** Whether a face is well-framed for a selfie (present, centred, right distance). */
79
+ declare function isSelfieReady(s: FaceSample, t?: FaceTuning): boolean;
80
+ //#endregion
81
+ export { ChallengeDetector, DEFAULT_TUNING, FaceAnalyzer, FaceSample, FaceTuning, createDefaultFaceAnalyzer, isSelfieReady, makeChallengeDetector };
82
+ //# sourceMappingURL=face.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"face.d.mts","names":[],"sources":["../src/face.ts"],"mappings":";;;;UAaiB,UAAA;EACf,OAAA;EAaA;EAXA,OAAA;EACA,OAAA;EAae;EAXf,KAAA;;EAEA,IAAA;EAae;EAXf,KAAA;EAW4C;EAT5C,KAAA;EAOA;EALA,KAAA;AAAA;AAAA,UAGe,YAAA;EAIP;EAFR,KAAA,IAAS,OAAA;EAIT;EAFA,OAAA,CAAQ,KAAA,EAAO,gBAAA,GAAmB,UAAA;EAE7B;EAAL,KAAA;AAAA;;iBAqJc,yBAAA,IAA6B,YAAY;AAAA;AAAA,UAKxC,iBAAA;EACf,IAAA,CAAK,MAAA,EAAQ,UAAU;;;;;;WAMd,QAAA;AAAA;AAAQ;AAQnB;;;;AARmB,UAQF,UAAA;EAIf;EAFA,IAAA;EAMA;EAJA,KAAA;EAQA;EANA,WAAA;EAUA;EARA,SAAA;EAWA;EATA,IAAA;EAWA;EATA,OAAA;EASc;EAPd,SAAA;EAuBD;EArBC,YAAA;EAqBD;EAnBC,eAAA;EACA,gBAAA;EACA,cAAA;EACA,cAAA;AAAA;AAAA,cAGW,cAAA,EAAgB,UAa5B;;;;;;;;iBASe,qBAAA,CAAsB,SAAA,EAAW,iBAAA,EAAmB,CAAA,GAAG,UAAA,GAA8B,iBAAA;;iBAsGrF,aAAA,CAAc,CAAA,EAAG,UAAA,EAAY,CAAA,GAAG,UAA2B"}