@ankhorage/studio 0.0.20 → 0.1.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 (211) hide show
  1. package/README.md +1 -2
  2. package/dist/cli/index.d.ts +4 -4
  3. package/dist/cli/index.d.ts.map +1 -1
  4. package/dist/cli/index.js +81 -56
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/core/constants.d.ts.map +1 -1
  7. package/dist/core/constants.js +17 -6
  8. package/dist/core/constants.js.map +1 -1
  9. package/dist/hooks/useProjects.js +1 -1
  10. package/dist/hooks/useProjects.js.map +1 -1
  11. package/dist/host/createStudioHost.d.ts +13 -0
  12. package/dist/host/createStudioHost.d.ts.map +1 -0
  13. package/dist/host/createStudioHost.js +16 -0
  14. package/dist/host/createStudioHost.js.map +1 -0
  15. package/dist/host/http/security.d.ts +2 -0
  16. package/dist/host/http/security.d.ts.map +1 -0
  17. package/dist/host/http/security.js +55 -0
  18. package/dist/host/http/security.js.map +1 -0
  19. package/dist/host/http/server.d.ts +16 -0
  20. package/dist/host/http/server.d.ts.map +1 -0
  21. package/dist/host/http/server.js +549 -0
  22. package/dist/host/http/server.js.map +1 -0
  23. package/dist/host/layout/auth/resolveAuthLayoutPlan.d.ts +38 -0
  24. package/dist/host/layout/auth/resolveAuthLayoutPlan.d.ts.map +1 -0
  25. package/dist/host/layout/auth/resolveAuthLayoutPlan.js +262 -0
  26. package/dist/host/layout/auth/resolveAuthLayoutPlan.js.map +1 -0
  27. package/dist/host/layout/layoutGenerator.d.ts +19 -0
  28. package/dist/host/layout/layoutGenerator.d.ts.map +1 -0
  29. package/dist/host/layout/layoutGenerator.js +418 -0
  30. package/dist/host/layout/layoutGenerator.js.map +1 -0
  31. package/dist/host/layout/templates/auth/adapter.d.ts +6 -0
  32. package/dist/host/layout/templates/auth/adapter.d.ts.map +1 -0
  33. package/dist/host/layout/templates/auth/adapter.js +94 -0
  34. package/dist/host/layout/templates/auth/adapter.js.map +1 -0
  35. package/dist/host/layout/templates/auth/screen.d.ts +12 -0
  36. package/dist/host/layout/templates/auth/screen.d.ts.map +1 -0
  37. package/dist/host/layout/templates/auth/screen.js +648 -0
  38. package/dist/host/layout/templates/auth/screen.js.map +1 -0
  39. package/dist/host/layout/templates/auth/session.d.ts +2 -0
  40. package/dist/host/layout/templates/auth/session.d.ts.map +1 -0
  41. package/dist/host/layout/templates/auth/session.js +326 -0
  42. package/dist/host/layout/templates/auth/session.js.map +1 -0
  43. package/dist/host/layout/templates/auth/signOut.d.ts +2 -0
  44. package/dist/host/layout/templates/auth/signOut.d.ts.map +1 -0
  45. package/dist/host/layout/templates/auth/signOut.js +43 -0
  46. package/dist/host/layout/templates/auth/signOut.js.map +1 -0
  47. package/dist/host/layout/templates/index.d.ts +11 -0
  48. package/dist/host/layout/templates/index.d.ts.map +1 -0
  49. package/dist/host/layout/templates/index.js +10 -0
  50. package/dist/host/layout/templates/index.js.map +1 -0
  51. package/dist/host/layout/templates/navigation.d.ts +16 -0
  52. package/dist/host/layout/templates/navigation.d.ts.map +1 -0
  53. package/dist/host/layout/templates/navigation.js +332 -0
  54. package/dist/host/layout/templates/navigation.js.map +1 -0
  55. package/dist/host/layout/templates/nestedLayout.d.ts +7 -0
  56. package/dist/host/layout/templates/nestedLayout.d.ts.map +1 -0
  57. package/dist/host/layout/templates/nestedLayout.js +56 -0
  58. package/dist/host/layout/templates/nestedLayout.js.map +1 -0
  59. package/dist/host/layout/templates/redirect.d.ts +2 -0
  60. package/dist/host/layout/templates/redirect.d.ts.map +1 -0
  61. package/dist/host/layout/templates/redirect.js +10 -0
  62. package/dist/host/layout/templates/redirect.js.map +1 -0
  63. package/dist/host/layout/templates/rootLayout.d.ts +28 -0
  64. package/dist/host/layout/templates/rootLayout.d.ts.map +1 -0
  65. package/dist/host/layout/templates/rootLayout.js +507 -0
  66. package/dist/host/layout/templates/rootLayout.js.map +1 -0
  67. package/dist/host/layout/templates/screen.d.ts +6 -0
  68. package/dist/host/layout/templates/screen.d.ts.map +1 -0
  69. package/dist/host/layout/templates/screen.js +94 -0
  70. package/dist/host/layout/templates/screen.js.map +1 -0
  71. package/dist/host/layout/templates/utils/routes.d.ts +3 -0
  72. package/dist/host/layout/templates/utils/routes.d.ts.map +1 -0
  73. package/dist/host/layout/templates/utils/routes.js +15 -0
  74. package/dist/host/layout/templates/utils/routes.js.map +1 -0
  75. package/dist/host/layout/templates/utils/strings.d.ts +3 -0
  76. package/dist/host/layout/templates/utils/strings.d.ts.map +1 -0
  77. package/dist/host/layout/templates/utils/strings.js +7 -0
  78. package/dist/host/layout/templates/utils/strings.js.map +1 -0
  79. package/dist/host/layout/utils/escapeStringLiteral.d.ts +2 -0
  80. package/dist/host/layout/utils/escapeStringLiteral.d.ts.map +1 -0
  81. package/dist/host/layout/utils/escapeStringLiteral.js +8 -0
  82. package/dist/host/layout/utils/escapeStringLiteral.js.map +1 -0
  83. package/dist/host/manifestSystem/auth/index.d.ts +2 -0
  84. package/dist/host/manifestSystem/auth/index.d.ts.map +1 -0
  85. package/dist/host/manifestSystem/auth/index.js +2 -0
  86. package/dist/host/manifestSystem/auth/index.js.map +1 -0
  87. package/dist/host/manifestSystem/auth/shared/global.auth.system.tpl.d.ts +4 -0
  88. package/dist/host/manifestSystem/auth/shared/global.auth.system.tpl.d.ts.map +1 -0
  89. package/dist/host/manifestSystem/auth/shared/global.auth.system.tpl.js +7 -0
  90. package/dist/host/manifestSystem/auth/shared/global.auth.system.tpl.js.map +1 -0
  91. package/dist/host/manifestSystem/auth/shared/index.d.ts +3 -0
  92. package/dist/host/manifestSystem/auth/shared/index.d.ts.map +1 -0
  93. package/dist/host/manifestSystem/auth/shared/index.js +8 -0
  94. package/dist/host/manifestSystem/auth/shared/index.js.map +1 -0
  95. package/dist/host/manifestSystem/index.d.ts +5 -0
  96. package/dist/host/manifestSystem/index.d.ts.map +1 -0
  97. package/dist/host/manifestSystem/index.js +23 -0
  98. package/dist/host/manifestSystem/index.js.map +1 -0
  99. package/dist/host/manifestSystem/types.d.ts +8 -0
  100. package/dist/host/manifestSystem/types.d.ts.map +1 -0
  101. package/dist/host/manifestSystem/types.js +2 -0
  102. package/dist/host/manifestSystem/types.js.map +1 -0
  103. package/dist/host/modules/catalog.d.ts +40 -0
  104. package/dist/host/modules/catalog.d.ts.map +1 -0
  105. package/dist/host/modules/catalog.js +112 -0
  106. package/dist/host/modules/catalog.js.map +1 -0
  107. package/dist/host/modules/layout.d.ts +7 -0
  108. package/dist/host/modules/layout.d.ts.map +1 -0
  109. package/dist/host/modules/layout.js +2 -0
  110. package/dist/host/modules/layout.js.map +1 -0
  111. package/dist/host/modules/runtime/LocalFsTargetAdapter.d.ts +34 -0
  112. package/dist/host/modules/runtime/LocalFsTargetAdapter.d.ts.map +1 -0
  113. package/dist/host/modules/runtime/LocalFsTargetAdapter.js +85 -0
  114. package/dist/host/modules/runtime/LocalFsTargetAdapter.js.map +1 -0
  115. package/dist/host/orchestrator/generatedAppFiles.d.ts +8 -0
  116. package/dist/host/orchestrator/generatedAppFiles.d.ts.map +1 -0
  117. package/dist/host/orchestrator/generatedAppFiles.js +125 -0
  118. package/dist/host/orchestrator/generatedAppFiles.js.map +1 -0
  119. package/dist/host/orchestrator/generatedRouteCleanup.d.ts +5 -0
  120. package/dist/host/orchestrator/generatedRouteCleanup.d.ts.map +1 -0
  121. package/dist/host/orchestrator/generatedRouteCleanup.js +117 -0
  122. package/dist/host/orchestrator/generatedRouteCleanup.js.map +1 -0
  123. package/dist/host/orchestrator/infraGenerator.d.ts +35 -0
  124. package/dist/host/orchestrator/infraGenerator.d.ts.map +1 -0
  125. package/dist/host/orchestrator/infraGenerator.js +135 -0
  126. package/dist/host/orchestrator/infraGenerator.js.map +1 -0
  127. package/dist/host/orchestrator/infraRuntime.d.ts +38 -0
  128. package/dist/host/orchestrator/infraRuntime.d.ts.map +1 -0
  129. package/dist/host/orchestrator/infraRuntime.js +227 -0
  130. package/dist/host/orchestrator/infraRuntime.js.map +1 -0
  131. package/dist/host/orchestrator/infraValidation.d.ts +3 -0
  132. package/dist/host/orchestrator/infraValidation.d.ts.map +1 -0
  133. package/dist/host/orchestrator/infraValidation.js +59 -0
  134. package/dist/host/orchestrator/infraValidation.js.map +1 -0
  135. package/dist/host/orchestrator/moduleManager.d.ts +86 -0
  136. package/dist/host/orchestrator/moduleManager.d.ts.map +1 -0
  137. package/dist/host/orchestrator/moduleManager.js +312 -0
  138. package/dist/host/orchestrator/moduleManager.js.map +1 -0
  139. package/dist/host/orchestrator/projectDeletion.d.ts +27 -0
  140. package/dist/host/orchestrator/projectDeletion.d.ts.map +1 -0
  141. package/dist/host/orchestrator/projectDeletion.js +242 -0
  142. package/dist/host/orchestrator/projectDeletion.js.map +1 -0
  143. package/dist/host/orchestrator/projectManager.d.ts +87 -0
  144. package/dist/host/orchestrator/projectManager.d.ts.map +1 -0
  145. package/dist/host/orchestrator/projectManager.js +371 -0
  146. package/dist/host/orchestrator/projectManager.js.map +1 -0
  147. package/dist/host/orchestrator/projectPaths.d.ts +4 -0
  148. package/dist/host/orchestrator/projectPaths.d.ts.map +1 -0
  149. package/dist/host/orchestrator/projectPaths.js +25 -0
  150. package/dist/host/orchestrator/projectPaths.js.map +1 -0
  151. package/dist/host/orchestrator/projectStore.d.ts +24 -0
  152. package/dist/host/orchestrator/projectStore.d.ts.map +1 -0
  153. package/dist/host/orchestrator/projectStore.js +155 -0
  154. package/dist/host/orchestrator/projectStore.js.map +1 -0
  155. package/dist/host/orchestrator/resolveMutations.d.ts +3 -0
  156. package/dist/host/orchestrator/resolveMutations.d.ts.map +1 -0
  157. package/dist/host/orchestrator/resolveMutations.js +12 -0
  158. package/dist/host/orchestrator/resolveMutations.js.map +1 -0
  159. package/dist/host/orchestrator/scaffolder.d.ts +33 -0
  160. package/dist/host/orchestrator/scaffolder.d.ts.map +1 -0
  161. package/dist/host/orchestrator/scaffolder.js +246 -0
  162. package/dist/host/orchestrator/scaffolder.js.map +1 -0
  163. package/dist/host/orchestrator/templates.d.ts +83 -0
  164. package/dist/host/orchestrator/templates.d.ts.map +1 -0
  165. package/dist/host/orchestrator/templates.js +355 -0
  166. package/dist/host/orchestrator/templates.js.map +1 -0
  167. package/dist/host/orchestrator/workspaceRuntime.d.ts +2 -0
  168. package/dist/host/orchestrator/workspaceRuntime.d.ts.map +1 -0
  169. package/dist/host/orchestrator/workspaceRuntime.js +82 -0
  170. package/dist/host/orchestrator/workspaceRuntime.js.map +1 -0
  171. package/dist/host/templateRegistry/index.d.ts +16 -0
  172. package/dist/host/templateRegistry/index.d.ts.map +1 -0
  173. package/dist/host/templateRegistry/index.js +74 -0
  174. package/dist/host/templateRegistry/index.js.map +1 -0
  175. package/dist/host/utils/requirementsInference.d.ts +4 -0
  176. package/dist/host/utils/requirementsInference.d.ts.map +1 -0
  177. package/dist/host/utils/requirementsInference.js +49 -0
  178. package/dist/host/utils/requirementsInference.js.map +1 -0
  179. package/dist/host/utils/trimOutput.d.ts +7 -0
  180. package/dist/host/utils/trimOutput.d.ts.map +1 -0
  181. package/dist/host/utils/trimOutput.js +32 -0
  182. package/dist/host/utils/trimOutput.js.map +1 -0
  183. package/dist/host/utils/workspaceRoot.d.ts +2 -0
  184. package/dist/host/utils/workspaceRoot.d.ts.map +1 -0
  185. package/dist/host/utils/workspaceRoot.js +33 -0
  186. package/dist/host/utils/workspaceRoot.js.map +1 -0
  187. package/dist/host/zoraExtensions/index.d.ts +11 -0
  188. package/dist/host/zoraExtensions/index.d.ts.map +1 -0
  189. package/dist/host/zoraExtensions/index.js +54 -0
  190. package/dist/host/zoraExtensions/index.js.map +1 -0
  191. package/dist/runtime/appExtensionRegistry.d.ts +3 -0
  192. package/dist/runtime/appExtensionRegistry.d.ts.map +1 -0
  193. package/dist/runtime/appExtensionRegistry.js +8 -0
  194. package/dist/runtime/appExtensionRegistry.js.map +1 -0
  195. package/dist/runtime/index.d.ts +8 -4
  196. package/dist/runtime/index.d.ts.map +1 -1
  197. package/dist/runtime/index.js +8 -4
  198. package/dist/runtime/index.js.map +1 -1
  199. package/dist/runtime/registry.d.ts +7 -0
  200. package/dist/runtime/registry.d.ts.map +1 -0
  201. package/dist/runtime/registry.js +7 -0
  202. package/dist/runtime/registry.js.map +1 -0
  203. package/dist/runtime/runtimeActions.d.ts +19 -0
  204. package/dist/runtime/runtimeActions.d.ts.map +1 -0
  205. package/dist/runtime/runtimeActions.js +5 -0
  206. package/dist/runtime/runtimeActions.js.map +1 -0
  207. package/dist/runtime/useRuntimeAction.d.ts +10 -0
  208. package/dist/runtime/useRuntimeAction.d.ts.map +1 -0
  209. package/dist/runtime/useRuntimeAction.js +30 -0
  210. package/dist/runtime/useRuntimeAction.js.map +1 -0
  211. package/package.json +35 -3
@@ -0,0 +1,648 @@
1
+ import { escapeStringLiteral } from '../../utils/escapeStringLiteral';
2
+ import { routeNameToGroupedHref } from '../utils/routes';
3
+ import { toSafeComponentName } from '../utils/strings';
4
+ const AUTH_SCREEN_CONTAINER_PADDING = 24;
5
+ const AUTH_SCREEN_CARD_MAX_WIDTH = 560;
6
+ function serializeStringArrayLiteral(values) {
7
+ return `[${values.map((value) => `'${escapeStringLiteral(value)}'`).join(', ')}]`;
8
+ }
9
+ export function getAuthScreenTsx(args) {
10
+ const { initialMode, screenName, title, signInRoute, signUpRoute, signInIdentifiers, signUpRequiredFields, signUpOptionalFields, signUpPolicy, } = args;
11
+ const safeName = toSafeComponentName(screenName);
12
+ const signUpSessionMessage = signUpPolicy === 'autoSignIn'
13
+ ? ` setStoredAuthSession(result.data);`
14
+ : ` clearStoredAuthSession();
15
+ router.replace(SIGN_IN_ROUTE);`;
16
+ return `import type { AppManifest } from '@ankhorage/contracts';
17
+ import type { AuthIdentifier, AuthSession } from '@ankhorage/contracts/auth';
18
+ import {
19
+ type AuthIdentifierKind,
20
+ SignInForm,
21
+ type SignInFormValues,
22
+ SignUpForm,
23
+ type SignUpFormField,
24
+ type SignUpFormValues,
25
+ Text,
26
+ useZoraTheme,
27
+ } from '@ankhorage/zora';
28
+ import ankhConfig from '@root/ankh.config.json';
29
+ import { Stack, useRouter } from 'expo-router';
30
+ import React, { useMemo, useState } from 'react';
31
+ import { StyleSheet, View } from 'react-native';
32
+
33
+ import { authAdapter } from '@/auth/adapter';
34
+ import { clearStoredAuthSession, setStoredAuthSession } from '@/auth/session';
35
+ import { ManifestProvider } from '@ankhorage/runtime';
36
+
37
+ const SIGN_IN_IDENTIFIERS: string[] = ${serializeStringArrayLiteral(signInIdentifiers)};
38
+ const SIGN_UP_REQUIRED_FIELDS: string[] = ${serializeStringArrayLiteral(signUpRequiredFields)};
39
+ const SIGN_UP_OPTIONAL_FIELDS: string[] = ${serializeStringArrayLiteral(signUpOptionalFields)};
40
+ const SIGN_IN_ROUTE = '${escapeStringLiteral(routeNameToGroupedHref(signInRoute, 'auth'))}';
41
+ const SIGN_UP_ROUTE = '${escapeStringLiteral(routeNameToGroupedHref(signUpRoute, 'auth'))}';
42
+ const fallbackManifest = ankhConfig as unknown as AppManifest;
43
+ const authScreenOptions = {
44
+ title: '${escapeStringLiteral(title ?? screenName)}',
45
+ };
46
+
47
+ type AuthMode = 'signIn' | 'signUp';
48
+
49
+ interface AuthSubmitValues {
50
+ mode: AuthMode;
51
+ identifier: string;
52
+ password: string;
53
+ firstName: string;
54
+ lastName: string;
55
+ displayName: string;
56
+ }
57
+
58
+ function getErrorMessage(caught: unknown): string {
59
+ if (caught instanceof Error) {
60
+ return caught.message;
61
+ }
62
+
63
+ if (typeof caught === 'string') {
64
+ return caught;
65
+ }
66
+
67
+ return 'Unknown auth error';
68
+ }
69
+
70
+ export default function ${safeName}Screen() {
71
+ const router = useRouter();
72
+ const { theme } = useZoraTheme();
73
+
74
+ const [mode, setMode] = useState<AuthMode>('${initialMode}');
75
+ const [loading, setLoading] = useState(false);
76
+ const [error, setError] = useState<string | null>(null);
77
+ const [info, setInfo] = useState<string | null>(null);
78
+
79
+ const identifierField = useMemo(() => resolveIdentifierFieldDefinition(SIGN_IN_IDENTIFIERS), []);
80
+ const authIdentifiers = useMemo(() => resolveAuthIdentifiers(SIGN_IN_IDENTIFIERS), []);
81
+ const signUpFields = useMemo(
82
+ () =>
83
+ buildSignUpFields({
84
+ identifierField,
85
+ configuredFields: unique([...SIGN_UP_REQUIRED_FIELDS, ...SIGN_UP_OPTIONAL_FIELDS]),
86
+ requiredFields: SIGN_UP_REQUIRED_FIELDS,
87
+ }),
88
+ [identifierField],
89
+ );
90
+
91
+ function showSignIn() {
92
+ setMode('signIn');
93
+ setError(null);
94
+ setInfo(null);
95
+ router.replace(SIGN_IN_ROUTE);
96
+ }
97
+
98
+ function showSignUp() {
99
+ setMode('signUp');
100
+ setError(null);
101
+ setInfo(null);
102
+ router.replace(SIGN_UP_ROUTE);
103
+ }
104
+
105
+ async function handleSignInSubmit(values: SignInFormValues) {
106
+ await submitAuthForm({
107
+ mode: 'signIn',
108
+ identifier: values.identifier,
109
+ password: values.secret,
110
+ firstName: '',
111
+ lastName: '',
112
+ displayName: '',
113
+ });
114
+ }
115
+
116
+ async function handleSignUpSubmit(values: SignUpFormValues) {
117
+ await submitAuthForm({
118
+ mode: 'signUp',
119
+ identifier: getFormValue(values, 'identifier'),
120
+ password: getFormValue(values, 'password'),
121
+ firstName: getFormValue(values, 'firstName'),
122
+ lastName: getFormValue(values, 'lastName'),
123
+ displayName: getFormValue(values, 'displayName'),
124
+ });
125
+ }
126
+
127
+ async function submitAuthForm(values: AuthSubmitValues) {
128
+ const { mode, identifier, password, firstName, lastName, displayName } = values;
129
+
130
+ setError(null);
131
+ setInfo(null);
132
+
133
+ const trimmedIdentifier = identifier.trim();
134
+ const normalizedPassword = password;
135
+ if (!trimmedIdentifier || normalizedPassword.length === 0) {
136
+ setError('Enter both credentials before continuing.');
137
+ return;
138
+ }
139
+
140
+ const identifierValidationError = validateIdentifier(trimmedIdentifier, SIGN_IN_IDENTIFIERS);
141
+ if (identifierValidationError) {
142
+ setError(identifierValidationError);
143
+ return;
144
+ }
145
+
146
+ if (normalizedPassword.length < 6) {
147
+ setError('Password must be at least 6 characters.');
148
+ return;
149
+ }
150
+
151
+ if (mode === 'signUp') {
152
+ const signUpValidationError = validateSignUpInput({
153
+ identifier: trimmedIdentifier,
154
+ password: normalizedPassword,
155
+ requiredFields: SIGN_UP_REQUIRED_FIELDS,
156
+ firstName,
157
+ lastName,
158
+ displayName,
159
+ });
160
+ if (signUpValidationError) {
161
+ setError(signUpValidationError);
162
+ return;
163
+ }
164
+ }
165
+
166
+ const authIdentifier = buildAuthIdentifierInput(trimmedIdentifier, SIGN_IN_IDENTIFIERS);
167
+ if (!authIdentifier) {
168
+ setError('Unable to resolve the configured sign-in identifier.');
169
+ return;
170
+ }
171
+
172
+ setLoading(true);
173
+ try {
174
+ if (mode === 'signIn') {
175
+ const result = await authAdapter.signIn({
176
+ identifier: authIdentifier,
177
+ password: normalizedPassword,
178
+ });
179
+
180
+ if (!result.ok) {
181
+ setError(result.error.message);
182
+ return;
183
+ }
184
+
185
+ if (!result.data) {
186
+ setError('Sign in succeeded without a session.');
187
+ return;
188
+ }
189
+
190
+ setStoredAuthSession(result.data);
191
+ return;
192
+ }
193
+
194
+ const result = await authAdapter.signUp({
195
+ identifier: authIdentifier,
196
+ password: normalizedPassword,
197
+ profile: buildSignUpProfile({
198
+ firstName,
199
+ lastName,
200
+ displayName,
201
+ }),
202
+ });
203
+
204
+ if (!result.ok) {
205
+ setError(result.error.message);
206
+ return;
207
+ }
208
+
209
+ if (isAuthSession(result.data)) {
210
+ ${signUpSessionMessage}
211
+ return;
212
+ }
213
+
214
+ router.replace(SIGN_IN_ROUTE);
215
+ } catch (caught) {
216
+ setError(getErrorMessage(caught));
217
+ } finally {
218
+ setLoading(false);
219
+ }
220
+ }
221
+
222
+ return (
223
+ <ManifestProvider manifest={fallbackManifest}>
224
+ <View
225
+ style={{
226
+ flex: 1,
227
+ backgroundColor: theme.colors.background,
228
+ justifyContent: 'center',
229
+ alignItems: 'center',
230
+ padding: ${AUTH_SCREEN_CONTAINER_PADDING},
231
+ }}
232
+ >
233
+ <Stack.Screen options={authScreenOptions} />
234
+ <View
235
+ style={[
236
+ styles.card,
237
+ {
238
+ backgroundColor: theme.colors.surface,
239
+ borderColor: theme.colors.border,
240
+ },
241
+ ]}
242
+ >
243
+ <Text variant="lead" weight="semiBold">
244
+ {mode === 'signIn' ? 'Sign in' : 'Create account'}
245
+ </Text>
246
+ <Text emphasis="muted" variant="bodySmall">
247
+ {identifierField.helper}
248
+ </Text>
249
+
250
+ {mode === 'signIn' ? (
251
+ <SignInForm
252
+ error={error}
253
+ identifierLabel={identifierField.label}
254
+ identifiers={authIdentifiers}
255
+ loading={loading}
256
+ onSignUp={showSignUp}
257
+ onSubmit={handleSignInSubmit}
258
+ signUpLabel="Need an account? Sign up"
259
+ submitLabel="Sign in"
260
+ />
261
+ ) : (
262
+ <SignUpForm
263
+ error={error}
264
+ fields={signUpFields}
265
+ loading={loading}
266
+ onSignIn={showSignIn}
267
+ onSubmit={handleSignUpSubmit}
268
+ signInLabel="Already have an account? Sign in"
269
+ submitLabel="Create account"
270
+ />
271
+ )}
272
+
273
+ {info ? (
274
+ <Text color="success" variant="bodySmall">
275
+ {info}
276
+ </Text>
277
+ ) : null}
278
+ </View>
279
+ </View>
280
+ </ManifestProvider>
281
+ );
282
+ }
283
+
284
+ const styles = StyleSheet.create({
285
+ card: {
286
+ borderRadius: 24,
287
+ borderWidth: 1,
288
+ gap: 16,
289
+ maxWidth: ${AUTH_SCREEN_CARD_MAX_WIDTH},
290
+ padding: 24,
291
+ width: '100%',
292
+ },
293
+ });
294
+
295
+ function buildAuthIdentifierInput(
296
+ identifier: string,
297
+ identifiers: string[],
298
+ ): AuthIdentifier | null {
299
+ const normalizedIdentifier = identifier.trim();
300
+ const resolvedIdentifiers = resolveAuthIdentifiers(identifiers);
301
+
302
+ if (resolvedIdentifiers.includes('email') && isEmail(normalizedIdentifier)) {
303
+ return { kind: 'email' as const, value: normalizedIdentifier };
304
+ }
305
+
306
+ if (resolvedIdentifiers.includes('phone') && isPhone(normalizedIdentifier)) {
307
+ return { kind: 'phone' as const, value: normalizedIdentifier };
308
+ }
309
+
310
+ if (resolvedIdentifiers.includes('username') && isUsername(normalizedIdentifier)) {
311
+ return { kind: 'username' as const, value: normalizedIdentifier };
312
+ }
313
+
314
+ const [fallbackKind] = resolvedIdentifiers;
315
+ return fallbackKind ? { kind: fallbackKind, value: normalizedIdentifier } : null;
316
+ }
317
+
318
+ function buildSignUpProfile(args: { firstName: string; lastName: string; displayName: string }) {
319
+ const { firstName, lastName, displayName } = args;
320
+ const profile: Record<string, string> = {};
321
+
322
+ if (firstName.trim()) profile.firstName = firstName.trim();
323
+ if (lastName.trim()) profile.lastName = lastName.trim();
324
+ if (displayName.trim()) profile.displayName = displayName.trim();
325
+
326
+ return Object.keys(profile).length > 0 ? profile : undefined;
327
+ }
328
+
329
+ function isAuthSession(value: unknown): value is AuthSession {
330
+ if (!isRecord(value)) {
331
+ return false;
332
+ }
333
+
334
+ const { accessToken, user } = value;
335
+ if (typeof accessToken !== 'string' || accessToken.length === 0) {
336
+ return false;
337
+ }
338
+
339
+ if (!isRecord(user)) {
340
+ return false;
341
+ }
342
+
343
+ const { id: userId } = user;
344
+ return typeof userId === 'string' && userId.length > 0;
345
+ }
346
+
347
+ function isRecord(value: unknown): value is Record<string, unknown> {
348
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
349
+ }
350
+
351
+ function getFormValue(values: SignUpFormValues, name: string): string {
352
+ return values[name] ?? '';
353
+ }
354
+
355
+ function buildSignUpFields(args: {
356
+ identifierField: ReturnType<typeof resolveIdentifierFieldDefinition>;
357
+ configuredFields: string[];
358
+ requiredFields: string[];
359
+ }): SignUpFormField[] {
360
+ const { identifierField, configuredFields, requiredFields } = args;
361
+ const fields: SignUpFormField[] = [
362
+ {
363
+ name: 'identifier',
364
+ label: identifierField.label,
365
+ helperText: identifierField.helper,
366
+ placeholder: identifierField.placeholder,
367
+ type: identifierField.type,
368
+ autoCapitalize: 'none',
369
+ keyboardType: identifierField.keyboardType,
370
+ required:
371
+ hasConfiguredSignUpField(requiredFields, 'email') ||
372
+ hasConfiguredSignUpField(requiredFields, 'phone') ||
373
+ hasConfiguredSignUpField(requiredFields, 'username'),
374
+ },
375
+ {
376
+ name: 'password',
377
+ label: 'Password',
378
+ type: 'password',
379
+ required: hasConfiguredSignUpField(requiredFields, 'password'),
380
+ },
381
+ ];
382
+
383
+ if (hasConfiguredSignUpField(configuredFields, 'firstname')) {
384
+ fields.push({
385
+ name: 'firstName',
386
+ label: 'First name',
387
+ type: 'text',
388
+ required: hasConfiguredSignUpField(requiredFields, 'firstname'),
389
+ });
390
+ }
391
+
392
+ if (hasConfiguredSignUpField(configuredFields, 'lastname')) {
393
+ fields.push({
394
+ name: 'lastName',
395
+ label: 'Last name',
396
+ type: 'text',
397
+ required: hasConfiguredSignUpField(requiredFields, 'lastname'),
398
+ });
399
+ }
400
+
401
+ if (hasConfiguredSignUpField(configuredFields, 'displayname')) {
402
+ fields.push({
403
+ name: 'displayName',
404
+ label: 'Display name',
405
+ type: 'text',
406
+ required: hasConfiguredSignUpField(requiredFields, 'displayname'),
407
+ });
408
+ }
409
+
410
+ return fields;
411
+ }
412
+
413
+ function hasConfiguredSignUpField(fields: string[], field: string): boolean {
414
+ return fields.some((value) => value.trim().toLowerCase() === field);
415
+ }
416
+
417
+ function resolveAuthIdentifiers(identifiers: string[]): AuthIdentifierKind[] {
418
+ const resolved: AuthIdentifierKind[] = [];
419
+
420
+ for (const identifier of identifiers) {
421
+ const normalized = identifier.trim().toLowerCase();
422
+ if (isAuthIdentifierKind(normalized) && !resolved.includes(normalized)) {
423
+ resolved.push(normalized);
424
+ }
425
+ }
426
+
427
+ return resolved.length > 0 ? resolved : ['email'];
428
+ }
429
+
430
+ function isAuthIdentifierKind(value: string): value is AuthIdentifierKind {
431
+ return value === 'email' || value === 'phone' || value === 'username';
432
+ }
433
+
434
+ function resolveIdentifierFieldDefinition(identifiers: string[]) {
435
+ const set = new Set(identifiers.map((identifier) => identifier.trim().toLowerCase()));
436
+ const supportsEmail = set.has('email');
437
+ const supportsPhone = set.has('phone');
438
+ const supportsUsername = set.has('username');
439
+
440
+ if (supportsEmail && !supportsPhone && !supportsUsername) {
441
+ return {
442
+ label: 'Email',
443
+ placeholder: 'hello@example.com',
444
+ helper: 'Use your email to continue.',
445
+ type: 'email' as const,
446
+ keyboardType: 'email-address' as const,
447
+ };
448
+ }
449
+
450
+ if (supportsPhone && !supportsEmail && !supportsUsername) {
451
+ return {
452
+ label: 'Phone',
453
+ placeholder: '+1 555 123 4567',
454
+ helper: 'Use your phone to continue.',
455
+ type: 'tel' as const,
456
+ keyboardType: 'phone-pad' as const,
457
+ };
458
+ }
459
+
460
+ if (supportsUsername && !supportsEmail && !supportsPhone) {
461
+ return {
462
+ label: 'Username',
463
+ placeholder: 'your-username',
464
+ helper: 'Use your username to continue.',
465
+ type: 'text' as const,
466
+ keyboardType: 'default' as const,
467
+ };
468
+ }
469
+
470
+ return {
471
+ label: supportsUsername ? 'Identifier' : 'Email or phone',
472
+ placeholder: 'Email or phone',
473
+ helper: 'Use your configured identifier to continue.',
474
+ type: 'text' as const,
475
+ keyboardType: 'default' as const,
476
+ };
477
+ }
478
+
479
+ function validateIdentifier(identifier: string, identifiers: string[]): string | null {
480
+ const normalizedIdentifier = identifier.trim();
481
+ 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
+ const allowed: { label: string; matches: boolean }[] = [];
491
+ if (supportsEmail) allowed.push({ label: 'email address', matches: matchesEmail });
492
+ if (supportsPhone) allowed.push({ label: 'phone number', matches: matchesPhone });
493
+ if (supportsUsername) allowed.push({ label: 'username', matches: matchesUsername });
494
+
495
+ if (allowed.length === 0 || allowed.some((entry) => entry.matches)) {
496
+ return null;
497
+ }
498
+
499
+ if (allowed.length === 1 && allowed[0]?.label === 'username') {
500
+ return 'Username must be at least 3 characters and use letters, numbers, dot, underscore, or dash.';
501
+ }
502
+
503
+ if (allowed.length === 1) {
504
+ return 'Use a valid ' + (allowed[0]?.label ?? 'identifier') + '.';
505
+ }
506
+
507
+ if (allowed.length === 2) {
508
+ return (
509
+ 'Use a valid ' +
510
+ (allowed[0]?.label ?? 'identifier') +
511
+ ' or ' +
512
+ (allowed[1]?.label ?? 'identifier') +
513
+ '.'
514
+ );
515
+ }
516
+
517
+ return (
518
+ 'Use a valid ' +
519
+ (allowed[0]?.label ?? 'identifier') +
520
+ ', ' +
521
+ (allowed[1]?.label ?? 'identifier') +
522
+ ', or ' +
523
+ (allowed[2]?.label ?? 'identifier') +
524
+ '.'
525
+ );
526
+ }
527
+
528
+ function validateSignUpInput(args: {
529
+ identifier: string;
530
+ password: string;
531
+ requiredFields: string[];
532
+ firstName: string;
533
+ lastName: string;
534
+ displayName: string;
535
+ }): string | null {
536
+ const { identifier, password, requiredFields, firstName, lastName, displayName } = args;
537
+ const missing: string[] = [];
538
+
539
+ for (const field of requiredFields) {
540
+ const normalized = field.trim().toLowerCase();
541
+ switch (normalized) {
542
+ case 'email':
543
+ case 'username':
544
+ case 'phone':
545
+ if (!identifier.trim()) missing.push(fieldLabel(normalized));
546
+ break;
547
+ case 'password':
548
+ if (password.length === 0) missing.push('password');
549
+ break;
550
+ case 'firstname':
551
+ if (!firstName.trim()) missing.push('first name');
552
+ break;
553
+ case 'lastname':
554
+ if (!lastName.trim()) missing.push('last name');
555
+ break;
556
+ case 'displayname':
557
+ if (!displayName.trim()) missing.push('display name');
558
+ break;
559
+ default:
560
+ break;
561
+ }
562
+ }
563
+
564
+ if (missing.length > 0) {
565
+ return 'Complete required fields: ' + missing.join(', ') + '.';
566
+ }
567
+
568
+ return null;
569
+ }
570
+
571
+ function fieldLabel(normalized: string): string {
572
+ switch (normalized) {
573
+ case 'email':
574
+ return 'email';
575
+ case 'phone':
576
+ return 'phone';
577
+ case 'username':
578
+ return 'username';
579
+ default:
580
+ return normalized;
581
+ }
582
+ }
583
+
584
+ function isEmail(value: string): boolean {
585
+ const normalized = value.trim();
586
+ if (normalized.length === 0 || normalized.length > 254) return false;
587
+
588
+ const atIndex = normalized.indexOf('@');
589
+ if (atIndex <= 0 || atIndex !== normalized.lastIndexOf('@')) return false;
590
+
591
+ const localPart = normalized.slice(0, atIndex);
592
+ const domainPart = normalized.slice(atIndex + 1);
593
+ if (localPart.length > 64 || domainPart.length === 0) return false;
594
+
595
+ if (!/^[A-Za-z0-9.!#$%&'*+/=?^_\`{|}~-]+$/.test(localPart)) return false;
596
+ if (!/^[A-Za-z0-9.-]+$/.test(domainPart)) return false;
597
+ if (domainPart.startsWith('.') || domainPart.endsWith('.') || domainPart.includes('..')) {
598
+ return false;
599
+ }
600
+
601
+ const labels = domainPart.split('.');
602
+ const [topLevelDomain] = labels.slice(-1);
603
+ if (labels.length < 2) return false;
604
+ if (
605
+ labels.some(
606
+ (label) =>
607
+ label.length === 0 ||
608
+ label.length > 63 ||
609
+ label.startsWith('-') ||
610
+ label.endsWith('-') ||
611
+ !/^[A-Za-z0-9-]+$/.test(label),
612
+ )
613
+ ) {
614
+ return false;
615
+ }
616
+
617
+ return (topLevelDomain ?? '').length >= 2;
618
+ }
619
+
620
+ function isPhone(value: string): boolean {
621
+ const normalized = value.trim();
622
+ if (normalized.length === 0) return false;
623
+ if (!/^[+()\\d\\s.-]+$/.test(normalized)) return false;
624
+
625
+ const digitCount = (normalized.match(/\\d/g) ?? []).length;
626
+ if (digitCount < 7 || digitCount > 15) return false;
627
+
628
+ const plusCount = (normalized.match(/\\+/g) ?? []).length;
629
+ if (plusCount > 1) return false;
630
+ if (plusCount === 1 && !normalized.startsWith('+')) return false;
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;
637
+ }
638
+
639
+ function isUsername(value: string): boolean {
640
+ return /^[a-zA-Z0-9._-]{3,}$/.test(value);
641
+ }
642
+
643
+ function unique(values: string[]): string[] {
644
+ return [...new Set(values)];
645
+ }
646
+ `;
647
+ }
648
+ //# sourceMappingURL=screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen.js","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/screen.ts"],"names":[],"mappings":"AAAA,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,IAUhC;IACC,MAAM,EACJ,WAAW,EACX,UAAU,EACV,KAAK,EACL,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,YAAY,GACb,GAAG,IAAI,CAAC;IACT,MAAM,QAAQ,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IACjD,MAAM,oBAAoB,GACxB,YAAY,KAAK,YAAY;QAC3B,CAAC,CAAC,4CAA4C;QAC9C,CAAC,CAAC;uCAC+B,CAAC;IAEtC,OAAO;;;;;;;;;;;;;;;;;;;;;wCAqB+B,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;;;YAG7E,mBAAmB,CAAC,KAAK,IAAI,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;0BA0B1B,QAAQ;;;;gDAIc,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwIzD,oBAAoB;;;;;;;;;;;;;;;;;;;;qBAoBD,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBA2DlC,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqWzC,CAAC;AACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function getAuthSessionTs(): string;
2
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/session.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,WAoU/B"}