@webority-technologies/mobile-core 0.0.9 → 0.0.11

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.
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PHONE_COUNTRY_NAMES = void 0;
7
+ /**
8
+ * English display names for every country libphonenumber-js knows, keyed by
9
+ * ISO 3166-1 alpha-2. GENERATED by scripts/gen-phone-countries.mjs from Node's
10
+ * Intl.DisplayNames('en', { type: 'region' }) over getCountries() on 2026-09-14;
11
+ * '&' is written as 'and'. Re-run the script rather than editing by hand.
12
+ *
13
+ * Lives on its own import path (mobile-core/phone/countries) so an app that
14
+ * never opens a full country list does not carry these 245 strings in its
15
+ * bundle. Pair with getPhoneCountries() from the package root for the calling
16
+ * codes; a country picker that needs another language supplies its own names.
17
+ */
18
+ const PHONE_COUNTRY_NAMES = exports.PHONE_COUNTRY_NAMES = {
19
+ AF: 'Afghanistan',
20
+ AX: 'Åland Islands',
21
+ AL: 'Albania',
22
+ DZ: 'Algeria',
23
+ AS: 'American Samoa',
24
+ AD: 'Andorra',
25
+ AO: 'Angola',
26
+ AI: 'Anguilla',
27
+ AG: 'Antigua and Barbuda',
28
+ AR: 'Argentina',
29
+ AM: 'Armenia',
30
+ AW: 'Aruba',
31
+ AC: 'Ascension Island',
32
+ AU: 'Australia',
33
+ AT: 'Austria',
34
+ AZ: 'Azerbaijan',
35
+ BS: 'Bahamas',
36
+ BH: 'Bahrain',
37
+ BD: 'Bangladesh',
38
+ BB: 'Barbados',
39
+ BY: 'Belarus',
40
+ BE: 'Belgium',
41
+ BZ: 'Belize',
42
+ BJ: 'Benin',
43
+ BM: 'Bermuda',
44
+ BT: 'Bhutan',
45
+ BO: 'Bolivia',
46
+ BA: 'Bosnia and Herzegovina',
47
+ BW: 'Botswana',
48
+ BR: 'Brazil',
49
+ IO: 'British Indian Ocean Territory',
50
+ VG: 'British Virgin Islands',
51
+ BN: 'Brunei',
52
+ BG: 'Bulgaria',
53
+ BF: 'Burkina Faso',
54
+ BI: 'Burundi',
55
+ KH: 'Cambodia',
56
+ CM: 'Cameroon',
57
+ CA: 'Canada',
58
+ CV: 'Cape Verde',
59
+ BQ: 'Caribbean Netherlands',
60
+ KY: 'Cayman Islands',
61
+ CF: 'Central African Republic',
62
+ TD: 'Chad',
63
+ CL: 'Chile',
64
+ CN: 'China',
65
+ CX: 'Christmas Island',
66
+ CC: 'Cocos (Keeling) Islands',
67
+ CO: 'Colombia',
68
+ KM: 'Comoros',
69
+ CG: 'Congo - Brazzaville',
70
+ CD: 'Congo - Kinshasa',
71
+ CK: 'Cook Islands',
72
+ CR: 'Costa Rica',
73
+ CI: 'Côte d’Ivoire',
74
+ HR: 'Croatia',
75
+ CU: 'Cuba',
76
+ CW: 'Curaçao',
77
+ CY: 'Cyprus',
78
+ CZ: 'Czechia',
79
+ DK: 'Denmark',
80
+ DJ: 'Djibouti',
81
+ DM: 'Dominica',
82
+ DO: 'Dominican Republic',
83
+ EC: 'Ecuador',
84
+ EG: 'Egypt',
85
+ SV: 'El Salvador',
86
+ GQ: 'Equatorial Guinea',
87
+ ER: 'Eritrea',
88
+ EE: 'Estonia',
89
+ SZ: 'Eswatini',
90
+ ET: 'Ethiopia',
91
+ FK: 'Falkland Islands',
92
+ FO: 'Faroe Islands',
93
+ FJ: 'Fiji',
94
+ FI: 'Finland',
95
+ FR: 'France',
96
+ GF: 'French Guiana',
97
+ PF: 'French Polynesia',
98
+ GA: 'Gabon',
99
+ GM: 'Gambia',
100
+ GE: 'Georgia',
101
+ DE: 'Germany',
102
+ GH: 'Ghana',
103
+ GI: 'Gibraltar',
104
+ GR: 'Greece',
105
+ GL: 'Greenland',
106
+ GD: 'Grenada',
107
+ GP: 'Guadeloupe',
108
+ GU: 'Guam',
109
+ GT: 'Guatemala',
110
+ GG: 'Guernsey',
111
+ GN: 'Guinea',
112
+ GW: 'Guinea-Bissau',
113
+ GY: 'Guyana',
114
+ HT: 'Haiti',
115
+ HN: 'Honduras',
116
+ HK: 'Hong Kong SAR China',
117
+ HU: 'Hungary',
118
+ IS: 'Iceland',
119
+ IN: 'India',
120
+ ID: 'Indonesia',
121
+ IR: 'Iran',
122
+ IQ: 'Iraq',
123
+ IE: 'Ireland',
124
+ IM: 'Isle of Man',
125
+ IL: 'Israel',
126
+ IT: 'Italy',
127
+ JM: 'Jamaica',
128
+ JP: 'Japan',
129
+ JE: 'Jersey',
130
+ JO: 'Jordan',
131
+ KZ: 'Kazakhstan',
132
+ KE: 'Kenya',
133
+ KI: 'Kiribati',
134
+ XK: 'Kosovo',
135
+ KW: 'Kuwait',
136
+ KG: 'Kyrgyzstan',
137
+ LA: 'Laos',
138
+ LV: 'Latvia',
139
+ LB: 'Lebanon',
140
+ LS: 'Lesotho',
141
+ LR: 'Liberia',
142
+ LY: 'Libya',
143
+ LI: 'Liechtenstein',
144
+ LT: 'Lithuania',
145
+ LU: 'Luxembourg',
146
+ MO: 'Macao SAR China',
147
+ MG: 'Madagascar',
148
+ MW: 'Malawi',
149
+ MY: 'Malaysia',
150
+ MV: 'Maldives',
151
+ ML: 'Mali',
152
+ MT: 'Malta',
153
+ MH: 'Marshall Islands',
154
+ MQ: 'Martinique',
155
+ MR: 'Mauritania',
156
+ MU: 'Mauritius',
157
+ YT: 'Mayotte',
158
+ MX: 'Mexico',
159
+ FM: 'Micronesia',
160
+ MD: 'Moldova',
161
+ MC: 'Monaco',
162
+ MN: 'Mongolia',
163
+ ME: 'Montenegro',
164
+ MS: 'Montserrat',
165
+ MA: 'Morocco',
166
+ MZ: 'Mozambique',
167
+ MM: 'Myanmar (Burma)',
168
+ NA: 'Namibia',
169
+ NR: 'Nauru',
170
+ NP: 'Nepal',
171
+ NL: 'Netherlands',
172
+ NC: 'New Caledonia',
173
+ NZ: 'New Zealand',
174
+ NI: 'Nicaragua',
175
+ NE: 'Niger',
176
+ NG: 'Nigeria',
177
+ NU: 'Niue',
178
+ NF: 'Norfolk Island',
179
+ KP: 'North Korea',
180
+ MK: 'North Macedonia',
181
+ MP: 'Northern Mariana Islands',
182
+ NO: 'Norway',
183
+ OM: 'Oman',
184
+ PK: 'Pakistan',
185
+ PW: 'Palau',
186
+ PS: 'Palestinian Territories',
187
+ PA: 'Panama',
188
+ PG: 'Papua New Guinea',
189
+ PY: 'Paraguay',
190
+ PE: 'Peru',
191
+ PH: 'Philippines',
192
+ PL: 'Poland',
193
+ PT: 'Portugal',
194
+ PR: 'Puerto Rico',
195
+ QA: 'Qatar',
196
+ RE: 'Réunion',
197
+ RO: 'Romania',
198
+ RU: 'Russia',
199
+ RW: 'Rwanda',
200
+ WS: 'Samoa',
201
+ SM: 'San Marino',
202
+ ST: 'São Tomé and Príncipe',
203
+ SA: 'Saudi Arabia',
204
+ SN: 'Senegal',
205
+ RS: 'Serbia',
206
+ SC: 'Seychelles',
207
+ SL: 'Sierra Leone',
208
+ SG: 'Singapore',
209
+ SX: 'Sint Maarten',
210
+ SK: 'Slovakia',
211
+ SI: 'Slovenia',
212
+ SB: 'Solomon Islands',
213
+ SO: 'Somalia',
214
+ ZA: 'South Africa',
215
+ KR: 'South Korea',
216
+ SS: 'South Sudan',
217
+ ES: 'Spain',
218
+ LK: 'Sri Lanka',
219
+ BL: 'St. Barthélemy',
220
+ SH: 'St. Helena',
221
+ KN: 'St. Kitts and Nevis',
222
+ LC: 'St. Lucia',
223
+ MF: 'St. Martin',
224
+ PM: 'St. Pierre and Miquelon',
225
+ VC: 'St. Vincent and Grenadines',
226
+ SD: 'Sudan',
227
+ SR: 'Suriname',
228
+ SJ: 'Svalbard and Jan Mayen',
229
+ SE: 'Sweden',
230
+ CH: 'Switzerland',
231
+ SY: 'Syria',
232
+ TW: 'Taiwan',
233
+ TJ: 'Tajikistan',
234
+ TZ: 'Tanzania',
235
+ TH: 'Thailand',
236
+ TL: 'Timor-Leste',
237
+ TG: 'Togo',
238
+ TK: 'Tokelau',
239
+ TO: 'Tonga',
240
+ TT: 'Trinidad and Tobago',
241
+ TA: 'Tristan da Cunha',
242
+ TN: 'Tunisia',
243
+ TR: 'Türkiye',
244
+ TM: 'Turkmenistan',
245
+ TC: 'Turks and Caicos Islands',
246
+ TV: 'Tuvalu',
247
+ VI: 'U.S. Virgin Islands',
248
+ UG: 'Uganda',
249
+ UA: 'Ukraine',
250
+ AE: 'United Arab Emirates',
251
+ GB: 'United Kingdom',
252
+ US: 'United States',
253
+ UY: 'Uruguay',
254
+ UZ: 'Uzbekistan',
255
+ VU: 'Vanuatu',
256
+ VA: 'Vatican City',
257
+ VE: 'Venezuela',
258
+ VN: 'Vietnam',
259
+ WF: 'Wallis and Futuna',
260
+ EH: 'Western Sahara',
261
+ YE: 'Yemen',
262
+ ZM: 'Zambia',
263
+ ZW: 'Zimbabwe'
264
+ };
265
+ //# sourceMappingURL=countries.js.map
@@ -5,5 +5,5 @@ export { formatDate, formatDateTime, formatRelativeTime, formatTime } from "./da
5
5
  export { addDays, diffMs, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatTime12h, formatTimeInWindowsZone, formatTimeInZone, isDateAfter, isDateBefore, isSameDay, startOfDay } from "./dateMath.js";
6
6
  export { getInitials } from "./initials.js";
7
7
  export { formatCompactNumber, formatNumber, formatPercent } from "./number.js";
8
- export { detectPhoneCountry, formatPhone, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString } from "./phone.js";
8
+ export { AsYouType, clampNationalNumber, countryFlagEmoji, detectPhoneCountry, formatPhone, formatPhoneAsTyped, getCountries, getCountryCallingCode, getPhoneCountries, isSupportedCountry, isValidNationalNumber, isValidPhoneNumber, maxNationalNumberLength, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString, splitPhoneNumber, validatePhoneNumberLength } from "./phone.js";
9
9
  //# sourceMappingURL=index.js.map
@@ -7,8 +7,13 @@
7
7
  * module exists is validation and formatting accuracy, the more accurate
8
8
  * variant wins throughout this file, not just for validation.
9
9
  */
10
- import { parsePhoneNumberFromString } from 'libphonenumber-js/max';
11
- export { isValidPhoneNumber, parsePhoneNumber, parsePhoneNumberFromString } from 'libphonenumber-js/max';
10
+ import { Metadata } from 'libphonenumber-js/core';
11
+ import { AsYouType, getCountries, getCountryCallingCode, parsePhoneNumberFromString, validatePhoneNumberLength } from 'libphonenumber-js/max';
12
+ // `Metadata` comes from the core entry with the max data passed in by hand:
13
+ // the max entry exports it in its ESM build only, and the CommonJS build jest
14
+ // and node resolve has no `Metadata` at all (libphonenumber-js 1.13.12).
15
+ import phoneMetadata from 'libphonenumber-js/metadata.max.json';
16
+ export { AsYouType, getCountries, getCountryCallingCode, isSupportedCountry, isValidPhoneNumber, parsePhoneNumber, parsePhoneNumberFromString, validatePhoneNumberLength } from 'libphonenumber-js/max';
12
17
 
13
18
  /**
14
19
  * Re-exported under our own name rather than importing CountryCode directly
@@ -122,4 +127,176 @@ export function formatPhone(input, arg) {
122
127
  }
123
128
  return fallbackRest.startsWith('+') ? bestEffortGroup(fallbackRest.slice(1)) : fallbackRest.replace(/(.{4})(?=.)/g, '$1 ').trim();
124
129
  }
130
+
131
+ // ---------------------------------------------------------------------------
132
+ // Structured-value helpers. These back PhoneNumberInput in mobile-ui, and are
133
+ // exported so an app's own form and API code validates with the same rules
134
+ // the field shows on screen, rather than a second regex table.
135
+ // ---------------------------------------------------------------------------
136
+
137
+ /** Country calling code + national digits, the way a phone field stores them. */
138
+
139
+ /**
140
+ * Which kinds of number count as valid. `'any'` is libphonenumber's own
141
+ * answer (a fixed line passes). `'mobile'` narrows to MOBILE and
142
+ * FIXED_LINE_OR_MOBILE, which is what an OTP or WhatsApp field wants: in India
143
+ * a 10-digit number starting with 1 to 5 is a real fixed line and passes
144
+ * `'any'`, but no SMS will ever reach it.
145
+ */
146
+
147
+ const onlyDigits = input => input.replace(/\D/g, '');
148
+
149
+ /**
150
+ * Split a typed or pasted number into calling code + national digits.
151
+ * `'+919876543210'` resolves to IN / 91 / 9876543210 from its own prefix; a
152
+ * bare `'9876543210'` needs `defaultCountry` to resolve at all. Returns null
153
+ * when the input has no digits or no country can be told. A shared calling
154
+ * code (`+1` for US and CA) resolves to the country whose area code matches,
155
+ * which is why the country comes back as part of the answer rather than being
156
+ * looked up again from the code.
157
+ */
158
+ export const splitPhoneNumber = (input, defaultCountry) => {
159
+ const normalized = normalizePhone(input);
160
+ if (!normalized || onlyDigits(normalized).length === 0) {
161
+ return null;
162
+ }
163
+ const parsed = normalized.startsWith('+') ? parsePhoneNumberFromString(normalized) : defaultCountry ? parsePhoneNumberFromString(normalized, defaultCountry) : undefined;
164
+ if (!parsed) {
165
+ return null;
166
+ }
167
+ return {
168
+ country: parsed.country ?? null,
169
+ callingCode: parsed.countryCallingCode,
170
+ nationalNumber: parsed.nationalNumber
171
+ };
172
+ };
173
+
174
+ /**
175
+ * Cut national digits that run past the longest number the country's plan
176
+ * allows, so a field stops accepting the impossible without a per-country
177
+ * length table. This is the PLAN's ceiling, not a mobile number's: India runs
178
+ * to 13 digits (toll-free 1800 numbers), the US to 10, Germany to 15. A field
179
+ * that should stop where a subscriber's number ends asks
180
+ * `maxNationalNumberLength` instead. Digits within range, including a number
181
+ * still too short, pass through untouched.
182
+ */
183
+ export const clampNationalNumber = (nationalDigits, country) => {
184
+ let digits = onlyDigits(nationalDigits);
185
+ while (digits.length > 0 && validatePhoneNumberLength(digits, country) === 'TOO_LONG') {
186
+ digits = digits.slice(0, -1);
187
+ }
188
+ return digits;
189
+ };
190
+
191
+ // The number types a person types into a phone field. Toll-free, premium,
192
+ // shared-cost and pager ranges are what push a plan's ceiling past them.
193
+ const SUBSCRIBER_TYPES = {
194
+ any: ['MOBILE', 'FIXED_LINE'],
195
+ mobile: ['MOBILE']
196
+ };
197
+
198
+ // libphonenumber-js types `numberingPlan` without its per-type accessor; the
199
+ // runtime object has it, and a type with no lengths of its own answers with the
200
+ // plan's.
201
+
202
+ /**
203
+ * The most national digits a subscriber's number can have in a country, so a
204
+ * field can refuse the next digit as it is typed rather than trimming after.
205
+ * `'any'` (default) covers mobile and fixed lines, `'mobile'` mobiles only: India
206
+ * is 10 either way (its plan's 13 belongs to toll-free numbers), Germany is 15
207
+ * for `'any'` and 11 for `'mobile'`, the UAE 9. A country whose metadata lists
208
+ * no lengths by type falls back to the plan's longest number.
209
+ */
210
+ export const maxNationalNumberLength = (country, kind = 'any') => {
211
+ const metadata = new Metadata(phoneMetadata);
212
+ metadata.selectNumberingPlan(country);
213
+ const plan = metadata.numberingPlan;
214
+ if (!plan) {
215
+ return E164_MAX_NATIONAL_DIGITS;
216
+ }
217
+ const byType = SUBSCRIBER_TYPES[kind].flatMap(type => plan.type(type)?.possibleLengths() ?? []);
218
+ return Math.max(...(byType.length > 0 ? byType : plan.possibleLengths()));
219
+ };
220
+
221
+ // E.164 allows 15 digits in total; a national number can never exceed it.
222
+ const E164_MAX_NATIONAL_DIGITS = 15;
223
+
224
+ /**
225
+ * National digits grouped the way the country writes them, updated on every
226
+ * keystroke: `'98765'` for IN is `'98765'`, `'9876543210'` is `'98765 43210'`,
227
+ * `'2025550123'` for US is `'(202) 555-0123'`. Output is for display only; the
228
+ * digits are what a value stores. Digits past the plan's longest possible
229
+ * number are dropped first, so an overflowing paste never formats as a longer
230
+ * number; digits that fit no pattern come back ungrouped rather than forced
231
+ * into a shape.
232
+ *
233
+ * Countries that write a leading 0 (the UAE, the UK, Australia, Saudi Arabia)
234
+ * only group in national mode when that 0 is typed, and a value never holds
235
+ * it. When national mode hands the digits back untouched, the grouping comes
236
+ * from the international form with the calling code removed: `'501234567'`
237
+ * for AE is `'50 123 4567'`. Countries that group nationally are unaffected.
238
+ */
239
+ export const formatPhoneAsTyped = (nationalDigits, country) => {
240
+ const digits = clampNationalNumber(nationalDigits, country);
241
+ if (!digits) {
242
+ return '';
243
+ }
244
+ const national = new AsYouType(country).input(digits);
245
+ if (national !== digits) {
246
+ return national;
247
+ }
248
+ const prefix = `+${getCountryCallingCode(country)}`;
249
+ const international = new AsYouType().input(`${prefix}${digits}`);
250
+ return international.startsWith(prefix) ? international.slice(prefix.length).trimStart() || digits : digits;
251
+ };
252
+
253
+ /**
254
+ * Whether national digits form a real number for the country, by the
255
+ * country's own numbering plan rather than a length check. `kind: 'mobile'`
256
+ * additionally rejects fixed lines; a number whose type the metadata cannot
257
+ * tell is accepted, since the metadata, not the number, is what is missing.
258
+ */
259
+ export const isValidNationalNumber = (nationalDigits, country, kind = 'any') => {
260
+ const digits = onlyDigits(nationalDigits);
261
+ if (!digits) {
262
+ return false;
263
+ }
264
+ const parsed = parsePhoneNumberFromString(digits, country);
265
+ if (!parsed?.isValid()) {
266
+ return false;
267
+ }
268
+ if (kind === 'any') {
269
+ return true;
270
+ }
271
+ const type = parsed.getType();
272
+ return type === undefined || type === 'MOBILE' || type === 'FIXED_LINE_OR_MOBILE';
273
+ };
274
+
275
+ /**
276
+ * The flag as an emoji built from the ISO code's two regional-indicator
277
+ * letters, so no font asset ships with the library: iOS and Android both draw
278
+ * these from the system font. An unknown or malformed code returns ''. (Windows
279
+ * browsers render the two letters instead of a flag; that is the platform, not
280
+ * the code.)
281
+ */
282
+ export const countryFlagEmoji = iso => {
283
+ const code = iso.trim().toUpperCase();
284
+ if (!/^[A-Z]{2}$/.test(code)) {
285
+ return '';
286
+ }
287
+ return String.fromCodePoint(0x1f1e6 + code.charCodeAt(0) - 65, 0x1f1e6 + code.charCodeAt(1) - 65);
288
+ };
289
+
290
+ /** Calling code + ISO for one country, the shape a country picker lists. */
291
+
292
+ /**
293
+ * Every country libphonenumber-js knows, with its calling code, in metadata
294
+ * order. Names are deliberately not here: they are display data, in one
295
+ * language, and live on their own import path (`mobile-core/phone/countries`)
296
+ * so an app that never opens a full country list does not carry them.
297
+ */
298
+ export const getPhoneCountries = () => getCountries().map(iso => ({
299
+ iso,
300
+ callingCode: getCountryCallingCode(iso)
301
+ }));
125
302
  //# sourceMappingURL=phone.js.map
@@ -14,6 +14,10 @@
14
14
  * @webority-technologies/mobile-core/download a filesystem module
15
15
  * @webority-technologies/mobile-core/smsRetriever Android only, own TurboModule
16
16
  *
17
+ * One more path is separate for size, not for a native package:
18
+ *
19
+ * @webority-technologies/mobile-core/phone/countries 245 English country names
20
+ *
17
21
  * react-native-keychain is the exception and is a REQUIRED peer: the HTTP client
18
22
  * reads the bearer token, so it is reachable from the main barrel by design.
19
23
  */
@@ -30,7 +34,7 @@ export { getConfig, getConfigValue, resetConfig, setConfig } from "./config/inde
30
34
  // Deep links
31
35
  export { DeepLink, parseDeepLink, useDeepLink } from "./deepLink/index.js";
32
36
  // Formatters
33
- export { addDays, detectPhoneCountry, diffMs, formatCompactNumber, formatCurrency, formatDate, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatDateTime, formatNumber, formatPercent, formatPhone, formatRelativeTime, formatTime, formatTime12h, formatTimeInWindowsZone, formatTimeInZone, getInitials, isDateAfter, isDateBefore, isSameDay, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString, startOfDay } from "./formatters/index.js";
37
+ export { AsYouType, addDays, clampNationalNumber, countryFlagEmoji, detectPhoneCountry, diffMs, formatCompactNumber, formatCurrency, formatDate, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatDateTime, formatNumber, formatPercent, formatPhone, formatPhoneAsTyped, formatRelativeTime, formatTime, formatTime12h, formatTimeInWindowsZone, formatTimeInZone, getCountries, getCountryCallingCode, getInitials, getPhoneCountries, isDateAfter, isDateBefore, isSameDay, isSupportedCountry, isValidNationalNumber, isValidPhoneNumber, maxNationalNumberLength, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString, splitPhoneNumber, startOfDay, validatePhoneNumberLength } from "./formatters/index.js";
34
38
  // Initialization
35
39
  export { initWebority } from "./initSDK.js";
36
40
  export { initUserAuth } from "./initUserAuth.js";