@ankhorage/studio 0.5.0 → 0.6.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.
- package/README.md +1 -1
- package/dist/host/layout/auth/resolveAuthLayoutPlan.d.ts +16 -2
- package/dist/host/layout/auth/resolveAuthLayoutPlan.d.ts.map +1 -1
- package/dist/host/layout/auth/resolveAuthLayoutPlan.js +78 -4
- package/dist/host/layout/auth/resolveAuthLayoutPlan.js.map +1 -1
- package/dist/host/layout/layoutGenerator.d.ts.map +1 -1
- package/dist/host/layout/layoutGenerator.js +16 -2
- package/dist/host/layout/layoutGenerator.js.map +1 -1
- package/dist/host/layout/templates/auth/adapter.d.ts +1 -0
- package/dist/host/layout/templates/auth/adapter.d.ts.map +1 -1
- package/dist/host/layout/templates/auth/adapter.js +5 -0
- package/dist/host/layout/templates/auth/adapter.js.map +1 -1
- package/dist/host/layout/templates/auth/callback.d.ts +5 -0
- package/dist/host/layout/templates/auth/callback.d.ts.map +1 -0
- package/dist/host/layout/templates/auth/callback.js +114 -0
- package/dist/host/layout/templates/auth/callback.js.map +1 -0
- package/dist/host/layout/templates/auth/oauth.d.ts +3 -0
- package/dist/host/layout/templates/auth/oauth.d.ts.map +1 -0
- package/dist/host/layout/templates/auth/oauth.js +268 -0
- package/dist/host/layout/templates/auth/oauth.js.map +1 -0
- package/dist/host/layout/templates/auth/screen.d.ts +3 -0
- package/dist/host/layout/templates/auth/screen.d.ts.map +1 -1
- package/dist/host/layout/templates/auth/screen.js +99 -94
- package/dist/host/layout/templates/auth/screen.js.map +1 -1
- package/dist/host/layout/templates/auth/session.d.ts.map +1 -1
- package/dist/host/layout/templates/auth/session.js +125 -127
- package/dist/host/layout/templates/auth/session.js.map +1 -1
- package/dist/host/layout/templates/auth/signOut.js +1 -1
- package/dist/host/layout/templates/index.d.ts +2 -0
- package/dist/host/layout/templates/index.d.ts.map +1 -1
- package/dist/host/layout/templates/index.js +2 -0
- package/dist/host/layout/templates/index.js.map +1 -1
- package/dist/host/layout/templates/rootLayout.d.ts.map +1 -1
- package/dist/host/layout/templates/rootLayout.js +12 -1
- package/dist/host/layout/templates/rootLayout.js.map +1 -1
- package/dist/host/orchestrator/templates.d.ts +2 -0
- package/dist/host/orchestrator/templates.d.ts.map +1 -1
- package/dist/host/orchestrator/templates.js +12 -2
- package/dist/host/orchestrator/templates.js.map +1 -1
- package/package.json +2 -2
|
@@ -7,17 +7,78 @@ function serializeStringArrayLiteral(values) {
|
|
|
7
7
|
return `[${values.map((value) => `'${escapeStringLiteral(value)}'`).join(', ')}]`;
|
|
8
8
|
}
|
|
9
9
|
export function getAuthScreenTsx(args) {
|
|
10
|
-
const { initialMode, screenName, title, signInRoute, signUpRoute, signInIdentifiers, signUpRequiredFields, signUpOptionalFields, signUpPolicy, } = args;
|
|
10
|
+
const { initialMode, screenName, title, signInRoute, signUpRoute, postSignInRoute, signInIdentifiers, signUpRequiredFields, signUpOptionalFields, signUpPolicy, oauthProviders = [], } = args;
|
|
11
11
|
const safeName = toSafeComponentName(screenName);
|
|
12
|
+
const oauthEnabled = oauthProviders.length > 0;
|
|
13
|
+
const postSignInTarget = routeNameToGroupedHref(postSignInRoute, 'app');
|
|
12
14
|
const signUpSessionMessage = signUpPolicy === 'autoSignIn'
|
|
13
|
-
? ` setStoredAuthSession(result.data)
|
|
14
|
-
|
|
15
|
+
? ` await setStoredAuthSession(result.data);
|
|
16
|
+
router.replace(POST_SIGN_IN_ROUTE);`
|
|
17
|
+
: ` await clearStoredAuthSession();
|
|
15
18
|
router.replace(SIGN_IN_ROUTE);`;
|
|
19
|
+
const oauthImport = oauthEnabled
|
|
20
|
+
? `import {
|
|
21
|
+
generatedOAuthProviderItems,
|
|
22
|
+
startOAuthAuthorization,
|
|
23
|
+
} from '@/auth/oauth';\n`
|
|
24
|
+
: '';
|
|
25
|
+
const oauthState = oauthEnabled
|
|
26
|
+
? ` const [oauthLoadingProvider, setOAuthLoadingProvider] = useState<string | null>(null);\n`
|
|
27
|
+
: '';
|
|
28
|
+
const oauthHandler = oauthEnabled
|
|
29
|
+
? `
|
|
30
|
+
async function handleOAuthProviderPress(providerId: string) {
|
|
31
|
+
if (loading || oauthLoadingProvider !== null) return;
|
|
32
|
+
setError(null);
|
|
33
|
+
setInfo(null);
|
|
34
|
+
setOAuthLoadingProvider(providerId);
|
|
35
|
+
try {
|
|
36
|
+
const outcome = await startOAuthAuthorization(providerId);
|
|
37
|
+
if (outcome.status === 'authenticated') {
|
|
38
|
+
router.replace(POST_SIGN_IN_ROUTE);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (outcome.status === 'cancelled') {
|
|
42
|
+
setInfo(outcome.message);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
setError(outcome.message);
|
|
46
|
+
} catch (caught) {
|
|
47
|
+
setError(getErrorMessage(caught));
|
|
48
|
+
} finally {
|
|
49
|
+
setOAuthLoadingProvider(null);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
`
|
|
53
|
+
: '';
|
|
54
|
+
const oauthJsx = oauthEnabled
|
|
55
|
+
? `
|
|
56
|
+
<OAuthProviderList
|
|
57
|
+
disabled={loading}
|
|
58
|
+
onProviderPress={handleOAuthProviderPress}
|
|
59
|
+
providers={generatedOAuthProviderItems.map((provider) => ({
|
|
60
|
+
...provider,
|
|
61
|
+
disabled:
|
|
62
|
+
oauthLoadingProvider !== null && oauthLoadingProvider !== provider.id,
|
|
63
|
+
loading: oauthLoadingProvider === provider.id,
|
|
64
|
+
}))}
|
|
65
|
+
/>
|
|
66
|
+
<View style={styles.separatorRow}>
|
|
67
|
+
<View style={[styles.separatorLine, { backgroundColor: theme.colors.border }]} />
|
|
68
|
+
<Text emphasis="muted" variant="bodySmall">
|
|
69
|
+
or continue with password
|
|
70
|
+
</Text>
|
|
71
|
+
<View style={[styles.separatorLine, { backgroundColor: theme.colors.border }]} />
|
|
72
|
+
</View>
|
|
73
|
+
`
|
|
74
|
+
: '';
|
|
75
|
+
const zoraOAuthImport = oauthEnabled ? ' OAuthProviderList,\n' : '';
|
|
76
|
+
const formLoading = oauthEnabled ? 'loading || oauthLoadingProvider !== null' : 'loading';
|
|
16
77
|
return `import type { AppManifest } from '@ankhorage/contracts';
|
|
17
78
|
import type { AuthIdentifier, AuthSession } from '@ankhorage/contracts/auth';
|
|
18
79
|
import {
|
|
19
80
|
type AuthIdentifierKind,
|
|
20
|
-
SignInForm,
|
|
81
|
+
${zoraOAuthImport} SignInForm,
|
|
21
82
|
type SignInFormValues,
|
|
22
83
|
SignUpForm,
|
|
23
84
|
type SignUpFormField,
|
|
@@ -25,20 +86,21 @@ import {
|
|
|
25
86
|
Text,
|
|
26
87
|
useZoraTheme,
|
|
27
88
|
} from '@ankhorage/zora';
|
|
89
|
+
import { ManifestProvider } from '@ankhorage/runtime';
|
|
28
90
|
import ankhConfig from '@root/ankh.config.json';
|
|
29
91
|
import { Stack, useRouter } from 'expo-router';
|
|
30
92
|
import React, { useMemo, useState } from 'react';
|
|
31
93
|
import { StyleSheet, View } from 'react-native';
|
|
32
94
|
|
|
33
95
|
import { authAdapter } from '@/auth/adapter';
|
|
34
|
-
import { clearStoredAuthSession, setStoredAuthSession } from '@/auth/session';
|
|
35
|
-
import { ManifestProvider } from '@ankhorage/runtime';
|
|
96
|
+
${oauthImport}import { clearStoredAuthSession, setStoredAuthSession } from '@/auth/session';
|
|
36
97
|
|
|
37
98
|
const SIGN_IN_IDENTIFIERS: string[] = ${serializeStringArrayLiteral(signInIdentifiers)};
|
|
38
99
|
const SIGN_UP_REQUIRED_FIELDS: string[] = ${serializeStringArrayLiteral(signUpRequiredFields)};
|
|
39
100
|
const SIGN_UP_OPTIONAL_FIELDS: string[] = ${serializeStringArrayLiteral(signUpOptionalFields)};
|
|
40
101
|
const SIGN_IN_ROUTE = '${escapeStringLiteral(routeNameToGroupedHref(signInRoute, 'auth'))}';
|
|
41
102
|
const SIGN_UP_ROUTE = '${escapeStringLiteral(routeNameToGroupedHref(signUpRoute, 'auth'))}';
|
|
103
|
+
const POST_SIGN_IN_ROUTE = '${escapeStringLiteral(postSignInTarget)}';
|
|
42
104
|
const fallbackManifest = ankhConfig as unknown as AppManifest;
|
|
43
105
|
const authScreenOptions = {
|
|
44
106
|
title: '${escapeStringLiteral(title ?? screenName)}',
|
|
@@ -56,14 +118,8 @@ interface AuthSubmitValues {
|
|
|
56
118
|
}
|
|
57
119
|
|
|
58
120
|
function getErrorMessage(caught: unknown): string {
|
|
59
|
-
if (caught instanceof Error)
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (typeof caught === 'string') {
|
|
64
|
-
return caught;
|
|
65
|
-
}
|
|
66
|
-
|
|
121
|
+
if (caught instanceof Error) return caught.message;
|
|
122
|
+
if (typeof caught === 'string') return caught;
|
|
67
123
|
return 'Unknown auth error';
|
|
68
124
|
}
|
|
69
125
|
|
|
@@ -73,7 +129,7 @@ export default function ${safeName}Screen() {
|
|
|
73
129
|
|
|
74
130
|
const [mode, setMode] = useState<AuthMode>('${initialMode}');
|
|
75
131
|
const [loading, setLoading] = useState(false);
|
|
76
|
-
const [error, setError] = useState<string | null>(null);
|
|
132
|
+
${oauthState} const [error, setError] = useState<string | null>(null);
|
|
77
133
|
const [info, setInfo] = useState<string | null>(null);
|
|
78
134
|
|
|
79
135
|
const identifierField = useMemo(() => resolveIdentifierFieldDefinition(SIGN_IN_IDENTIFIERS), []);
|
|
@@ -123,7 +179,7 @@ export default function ${safeName}Screen() {
|
|
|
123
179
|
displayName: getFormValue(values, 'displayName'),
|
|
124
180
|
});
|
|
125
181
|
}
|
|
126
|
-
|
|
182
|
+
${oauthHandler}
|
|
127
183
|
async function submitAuthForm(values: AuthSubmitValues) {
|
|
128
184
|
const { mode, identifier, password, firstName, lastName, displayName } = values;
|
|
129
185
|
|
|
@@ -187,7 +243,8 @@ export default function ${safeName}Screen() {
|
|
|
187
243
|
return;
|
|
188
244
|
}
|
|
189
245
|
|
|
190
|
-
setStoredAuthSession(result.data);
|
|
246
|
+
await setStoredAuthSession(result.data);
|
|
247
|
+
router.replace(POST_SIGN_IN_ROUTE);
|
|
191
248
|
return;
|
|
192
249
|
}
|
|
193
250
|
|
|
@@ -246,13 +303,13 @@ ${signUpSessionMessage}
|
|
|
246
303
|
<Text emphasis="muted" variant="bodySmall">
|
|
247
304
|
{identifierField.helper}
|
|
248
305
|
</Text>
|
|
249
|
-
|
|
306
|
+
${oauthJsx}
|
|
250
307
|
{mode === 'signIn' ? (
|
|
251
308
|
<SignInForm
|
|
252
309
|
error={error}
|
|
253
310
|
identifierLabel={identifierField.label}
|
|
254
311
|
identifiers={authIdentifiers}
|
|
255
|
-
loading={
|
|
312
|
+
loading={${formLoading}}
|
|
256
313
|
onSignUp={showSignUp}
|
|
257
314
|
onSubmit={handleSignInSubmit}
|
|
258
315
|
signUpLabel="Need an account? Sign up"
|
|
@@ -262,7 +319,7 @@ ${signUpSessionMessage}
|
|
|
262
319
|
<SignUpForm
|
|
263
320
|
error={error}
|
|
264
321
|
fields={signUpFields}
|
|
265
|
-
loading={
|
|
322
|
+
loading={${formLoading}}
|
|
266
323
|
onSignIn={showSignIn}
|
|
267
324
|
onSubmit={handleSignUpSubmit}
|
|
268
325
|
signInLabel="Already have an account? Sign in"
|
|
@@ -290,6 +347,15 @@ const styles = StyleSheet.create({
|
|
|
290
347
|
padding: 24,
|
|
291
348
|
width: '100%',
|
|
292
349
|
},
|
|
350
|
+
separatorLine: {
|
|
351
|
+
flex: 1,
|
|
352
|
+
height: StyleSheet.hairlineWidth,
|
|
353
|
+
},
|
|
354
|
+
separatorRow: {
|
|
355
|
+
alignItems: 'center',
|
|
356
|
+
flexDirection: 'row',
|
|
357
|
+
gap: 12,
|
|
358
|
+
},
|
|
293
359
|
});
|
|
294
360
|
|
|
295
361
|
function buildAuthIdentifierInput(
|
|
@@ -302,11 +368,9 @@ function buildAuthIdentifierInput(
|
|
|
302
368
|
if (resolvedIdentifiers.includes('email') && isEmail(normalizedIdentifier)) {
|
|
303
369
|
return { kind: 'email' as const, value: normalizedIdentifier };
|
|
304
370
|
}
|
|
305
|
-
|
|
306
371
|
if (resolvedIdentifiers.includes('phone') && isPhone(normalizedIdentifier)) {
|
|
307
372
|
return { kind: 'phone' as const, value: normalizedIdentifier };
|
|
308
373
|
}
|
|
309
|
-
|
|
310
374
|
if (resolvedIdentifiers.includes('username') && isUsername(normalizedIdentifier)) {
|
|
311
375
|
return { kind: 'username' as const, value: normalizedIdentifier };
|
|
312
376
|
}
|
|
@@ -318,28 +382,17 @@ function buildAuthIdentifierInput(
|
|
|
318
382
|
function buildSignUpProfile(args: { firstName: string; lastName: string; displayName: string }) {
|
|
319
383
|
const { firstName, lastName, displayName } = args;
|
|
320
384
|
const profile: Record<string, string> = {};
|
|
321
|
-
|
|
322
385
|
if (firstName.trim()) profile.firstName = firstName.trim();
|
|
323
386
|
if (lastName.trim()) profile.lastName = lastName.trim();
|
|
324
387
|
if (displayName.trim()) profile.displayName = displayName.trim();
|
|
325
|
-
|
|
326
388
|
return Object.keys(profile).length > 0 ? profile : undefined;
|
|
327
389
|
}
|
|
328
390
|
|
|
329
391
|
function isAuthSession(value: unknown): value is AuthSession {
|
|
330
|
-
if (!isRecord(value))
|
|
331
|
-
return false;
|
|
332
|
-
}
|
|
333
|
-
|
|
392
|
+
if (!isRecord(value)) return false;
|
|
334
393
|
const { accessToken, user } = value;
|
|
335
|
-
if (typeof accessToken !== 'string' || accessToken.length === 0)
|
|
336
|
-
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (!isRecord(user)) {
|
|
340
|
-
return false;
|
|
341
|
-
}
|
|
342
|
-
|
|
394
|
+
if (typeof accessToken !== 'string' || accessToken.length === 0) return false;
|
|
395
|
+
if (!isRecord(user)) return false;
|
|
343
396
|
const { id: userId } = user;
|
|
344
397
|
return typeof userId === 'string' && userId.length > 0;
|
|
345
398
|
}
|
|
@@ -388,7 +441,6 @@ function buildSignUpFields(args: {
|
|
|
388
441
|
required: hasConfiguredSignUpField(requiredFields, 'firstname'),
|
|
389
442
|
});
|
|
390
443
|
}
|
|
391
|
-
|
|
392
444
|
if (hasConfiguredSignUpField(configuredFields, 'lastname')) {
|
|
393
445
|
fields.push({
|
|
394
446
|
name: 'lastName',
|
|
@@ -397,7 +449,6 @@ function buildSignUpFields(args: {
|
|
|
397
449
|
required: hasConfiguredSignUpField(requiredFields, 'lastname'),
|
|
398
450
|
});
|
|
399
451
|
}
|
|
400
|
-
|
|
401
452
|
if (hasConfiguredSignUpField(configuredFields, 'displayname')) {
|
|
402
453
|
fields.push({
|
|
403
454
|
name: 'displayName',
|
|
@@ -406,7 +457,6 @@ function buildSignUpFields(args: {
|
|
|
406
457
|
required: hasConfiguredSignUpField(requiredFields, 'displayname'),
|
|
407
458
|
});
|
|
408
459
|
}
|
|
409
|
-
|
|
410
460
|
return fields;
|
|
411
461
|
}
|
|
412
462
|
|
|
@@ -416,14 +466,12 @@ function hasConfiguredSignUpField(fields: string[], field: string): boolean {
|
|
|
416
466
|
|
|
417
467
|
function resolveAuthIdentifiers(identifiers: string[]): AuthIdentifierKind[] {
|
|
418
468
|
const resolved: AuthIdentifierKind[] = [];
|
|
419
|
-
|
|
420
469
|
for (const identifier of identifiers) {
|
|
421
470
|
const normalized = identifier.trim().toLowerCase();
|
|
422
471
|
if (isAuthIdentifierKind(normalized) && !resolved.includes(normalized)) {
|
|
423
472
|
resolved.push(normalized);
|
|
424
473
|
}
|
|
425
474
|
}
|
|
426
|
-
|
|
427
475
|
return resolved.length > 0 ? resolved : ['email'];
|
|
428
476
|
}
|
|
429
477
|
|
|
@@ -446,7 +494,6 @@ function resolveIdentifierFieldDefinition(identifiers: string[]) {
|
|
|
446
494
|
keyboardType: 'email-address' as const,
|
|
447
495
|
};
|
|
448
496
|
}
|
|
449
|
-
|
|
450
497
|
if (supportsPhone && !supportsEmail && !supportsUsername) {
|
|
451
498
|
return {
|
|
452
499
|
label: 'Phone',
|
|
@@ -456,7 +503,6 @@ function resolveIdentifierFieldDefinition(identifiers: string[]) {
|
|
|
456
503
|
keyboardType: 'phone-pad' as const,
|
|
457
504
|
};
|
|
458
505
|
}
|
|
459
|
-
|
|
460
506
|
if (supportsUsername && !supportsEmail && !supportsPhone) {
|
|
461
507
|
return {
|
|
462
508
|
label: 'Username',
|
|
@@ -466,7 +512,6 @@ function resolveIdentifierFieldDefinition(identifiers: string[]) {
|
|
|
466
512
|
keyboardType: 'default' as const,
|
|
467
513
|
};
|
|
468
514
|
}
|
|
469
|
-
|
|
470
515
|
return {
|
|
471
516
|
label: supportsUsername ? 'Identifier' : 'Email or phone',
|
|
472
517
|
placeholder: 'Email or phone',
|
|
@@ -479,31 +524,15 @@ function resolveIdentifierFieldDefinition(identifiers: string[]) {
|
|
|
479
524
|
function validateIdentifier(identifier: string, identifiers: string[]): string | null {
|
|
480
525
|
const normalizedIdentifier = identifier.trim();
|
|
481
526
|
const set = new Set(identifiers.map((entry) => entry.trim().toLowerCase()));
|
|
482
|
-
const supportsEmail = set.has('email');
|
|
483
|
-
const supportsPhone = set.has('phone');
|
|
484
|
-
const supportsUsername = set.has('username');
|
|
485
|
-
|
|
486
|
-
const matchesEmail = isEmail(normalizedIdentifier);
|
|
487
|
-
const matchesPhone = isPhone(normalizedIdentifier);
|
|
488
|
-
const matchesUsername = isUsername(normalizedIdentifier);
|
|
489
|
-
|
|
490
527
|
const allowed: { label: string; matches: boolean }[] = [];
|
|
491
|
-
if (
|
|
492
|
-
if (
|
|
493
|
-
if (
|
|
494
|
-
|
|
495
|
-
if (allowed.length === 0 || allowed.some((entry) => entry.matches)) {
|
|
496
|
-
return null;
|
|
497
|
-
}
|
|
498
|
-
|
|
528
|
+
if (set.has('email')) allowed.push({ label: 'email address', matches: isEmail(normalizedIdentifier) });
|
|
529
|
+
if (set.has('phone')) allowed.push({ label: 'phone number', matches: isPhone(normalizedIdentifier) });
|
|
530
|
+
if (set.has('username')) allowed.push({ label: 'username', matches: isUsername(normalizedIdentifier) });
|
|
531
|
+
if (allowed.length === 0 || allowed.some((entry) => entry.matches)) return null;
|
|
499
532
|
if (allowed.length === 1 && allowed[0]?.label === 'username') {
|
|
500
533
|
return 'Username must be at least 3 characters and use letters, numbers, dot, underscore, or dash.';
|
|
501
534
|
}
|
|
502
|
-
|
|
503
|
-
if (allowed.length === 1) {
|
|
504
|
-
return 'Use a valid ' + (allowed[0]?.label ?? 'identifier') + '.';
|
|
505
|
-
}
|
|
506
|
-
|
|
535
|
+
if (allowed.length === 1) return 'Use a valid ' + (allowed[0]?.label ?? 'identifier') + '.';
|
|
507
536
|
if (allowed.length === 2) {
|
|
508
537
|
return (
|
|
509
538
|
'Use a valid ' +
|
|
@@ -513,7 +542,6 @@ function validateIdentifier(identifier: string, identifiers: string[]): string |
|
|
|
513
542
|
'.'
|
|
514
543
|
);
|
|
515
544
|
}
|
|
516
|
-
|
|
517
545
|
return (
|
|
518
546
|
'Use a valid ' +
|
|
519
547
|
(allowed[0]?.label ?? 'identifier') +
|
|
@@ -535,7 +563,6 @@ function validateSignUpInput(args: {
|
|
|
535
563
|
}): string | null {
|
|
536
564
|
const { identifier, password, requiredFields, firstName, lastName, displayName } = args;
|
|
537
565
|
const missing: string[] = [];
|
|
538
|
-
|
|
539
566
|
for (const field of requiredFields) {
|
|
540
567
|
const normalized = field.trim().toLowerCase();
|
|
541
568
|
switch (normalized) {
|
|
@@ -560,12 +587,7 @@ function validateSignUpInput(args: {
|
|
|
560
587
|
break;
|
|
561
588
|
}
|
|
562
589
|
}
|
|
563
|
-
|
|
564
|
-
if (missing.length > 0) {
|
|
565
|
-
return 'Complete required fields: ' + missing.join(', ') + '.';
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
return null;
|
|
590
|
+
return missing.length > 0 ? 'Complete required fields: ' + missing.join(', ') + '.' : null;
|
|
569
591
|
}
|
|
570
592
|
|
|
571
593
|
function fieldLabel(normalized: string): string {
|
|
@@ -584,20 +606,14 @@ function fieldLabel(normalized: string): string {
|
|
|
584
606
|
function isEmail(value: string): boolean {
|
|
585
607
|
const normalized = value.trim();
|
|
586
608
|
if (normalized.length === 0 || normalized.length > 254) return false;
|
|
587
|
-
|
|
588
609
|
const atIndex = normalized.indexOf('@');
|
|
589
610
|
if (atIndex <= 0 || atIndex !== normalized.lastIndexOf('@')) return false;
|
|
590
|
-
|
|
591
611
|
const localPart = normalized.slice(0, atIndex);
|
|
592
612
|
const domainPart = normalized.slice(atIndex + 1);
|
|
593
613
|
if (localPart.length > 64 || domainPart.length === 0) return false;
|
|
594
|
-
|
|
595
614
|
if (!/^[A-Za-z0-9.!#$%&'*+/=?^_\`{|}~-]+$/.test(localPart)) return false;
|
|
596
615
|
if (!/^[A-Za-z0-9.-]+$/.test(domainPart)) return false;
|
|
597
|
-
if (domainPart.startsWith('.') || domainPart.endsWith('.') || domainPart.includes('..'))
|
|
598
|
-
return false;
|
|
599
|
-
}
|
|
600
|
-
|
|
616
|
+
if (domainPart.startsWith('.') || domainPart.endsWith('.') || domainPart.includes('..')) return false;
|
|
601
617
|
const labels = domainPart.split('.');
|
|
602
618
|
const [topLevelDomain] = labels.slice(-1);
|
|
603
619
|
if (labels.length < 2) return false;
|
|
@@ -610,10 +626,7 @@ function isEmail(value: string): boolean {
|
|
|
610
626
|
label.endsWith('-') ||
|
|
611
627
|
!/^[A-Za-z0-9-]+$/.test(label),
|
|
612
628
|
)
|
|
613
|
-
)
|
|
614
|
-
return false;
|
|
615
|
-
}
|
|
616
|
-
|
|
629
|
+
) return false;
|
|
617
630
|
return (topLevelDomain ?? '').length >= 2;
|
|
618
631
|
}
|
|
619
632
|
|
|
@@ -621,19 +634,11 @@ function isPhone(value: string): boolean {
|
|
|
621
634
|
const normalized = value.trim();
|
|
622
635
|
if (normalized.length === 0) return false;
|
|
623
636
|
if (!/^[+()\\d\\s.-]+$/.test(normalized)) return false;
|
|
624
|
-
|
|
625
637
|
const digitCount = (normalized.match(/\\d/g) ?? []).length;
|
|
626
638
|
if (digitCount < 7 || digitCount > 15) return false;
|
|
627
|
-
|
|
628
639
|
const plusCount = (normalized.match(/\\+/g) ?? []).length;
|
|
629
|
-
if (plusCount > 1) return false;
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
const openParenCount = (normalized.match(/\\(/g) ?? []).length;
|
|
633
|
-
const closeParenCount = (normalized.match(/\\)/g) ?? []).length;
|
|
634
|
-
if (openParenCount !== closeParenCount) return false;
|
|
635
|
-
|
|
636
|
-
return true;
|
|
640
|
+
if (plusCount > 1 || (plusCount === 1 && !normalized.startsWith('+'))) return false;
|
|
641
|
+
return (normalized.match(/\\(/g) ?? []).length === (normalized.match(/\\)/g) ?? []).length;
|
|
637
642
|
}
|
|
638
643
|
|
|
639
644
|
function isUsername(value: string): boolean {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screen.js","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/screen.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"screen.js","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/screen.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,6BAA6B,GAAG,EAAE,CAAC;AACzC,MAAM,0BAA0B,GAAG,GAAG,CAAC;AAEvC,SAAS,2BAA2B,CAAC,MAAyB;IAC5D,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAYhC;IACC,MAAM,EACJ,WAAW,EACX,UAAU,EACV,KAAK,EACL,WAAW,EACX,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,YAAY,EACZ,cAAc,GAAG,EAAE,GACpB,GAAG,IAAI,CAAC;IACT,MAAM,QAAQ,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IACjD,MAAM,YAAY,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/C,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACxE,MAAM,oBAAoB,GACxB,YAAY,KAAK,YAAY;QAC3B,CAAC,CAAC;4CACoC;QACtC,CAAC,CAAC;uCAC+B,CAAC;IACtC,MAAM,WAAW,GAAG,YAAY;QAC9B,CAAC,CAAC;;;yBAGmB;QACrB,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,UAAU,GAAG,YAAY;QAC7B,CAAC,CAAC,4FAA4F;QAC9F,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,YAAY,GAAG,YAAY;QAC/B,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;CAuBL;QACG,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,QAAQ,GAAG,YAAY;QAC3B,CAAC,CAAC;;;;;;;;;;;;;;;;;;CAkBL;QACG,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,eAAe,GAAG,YAAY,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,0CAA0C,CAAC,CAAC,CAAC,SAAS,CAAC;IAE1F,OAAO;;;;EAIP,eAAe;;;;;;;;;;;;;;;EAef,WAAW;;wCAE2B,2BAA2B,CAAC,iBAAiB,CAAC;4CAC1C,2BAA2B,CAAC,oBAAoB,CAAC;4CACjD,2BAA2B,CAAC,oBAAoB,CAAC;yBACpE,mBAAmB,CAAC,sBAAsB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;yBAChE,mBAAmB,CAAC,sBAAsB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;8BAC3D,mBAAmB,CAAC,gBAAgB,CAAC;;;YAGvD,mBAAmB,CAAC,KAAK,IAAI,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;0BAoB1B,QAAQ;;;;gDAIc,WAAW;;EAEzD,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkDV,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqFZ,oBAAoB;;;;;;;;;;;;;;;;;;;;qBAoBD,6BAA6B;;;;;;;;;;;;;;;;;;;EAmBhD,QAAQ;;;;;;yBAMe,WAAW;;;;;;;;;;yBAUX,WAAW;;;;;;;;;;;;;;;;;;;;;;;;gBAwBpB,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiTzC,CAAC;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/session.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/session.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,WAkU/B"}
|