astro-tractstack 2.0.30 → 2.0.32

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.
@@ -1,172 +0,0 @@
1
- // Tenant form validation and state helpers following TractStack v2 patterns
2
- import type { TenantProvisioningData } from '@/types/multiTenant';
3
- import type {
4
- TenantRegistrationState,
5
- TenantValidationErrors,
6
- } from '@/types/multiTenant';
7
-
8
- /**
9
- * Convert tenant provisioning data to local form state
10
- */
11
- export function convertToLocalState(
12
- data?: TenantProvisioningData
13
- ): TenantRegistrationState {
14
- if (!data) {
15
- return {
16
- tenantId: '',
17
- adminPassword: '',
18
- confirmPassword: '',
19
- name: '',
20
- email: '',
21
- tursoEnabled: false,
22
- tursoDatabaseURL: '',
23
- tursoAuthToken: '',
24
- };
25
- }
26
-
27
- return {
28
- tenantId: data.tenantId,
29
- adminPassword: data.adminPassword,
30
- confirmPassword: '',
31
- name: data.name,
32
- email: data.adminEmail,
33
- tursoEnabled: data.tursoEnabled,
34
- tursoDatabaseURL: data.tursoDatabaseURL || '',
35
- tursoAuthToken: data.tursoAuthToken || '',
36
- };
37
- }
38
-
39
- /**
40
- * Convert local form state to backend format
41
- */
42
- export function convertToBackendFormat(
43
- state: TenantRegistrationState
44
- ): TenantProvisioningData {
45
- const data: TenantProvisioningData = {
46
- tenantId: state.tenantId.trim(),
47
- adminPassword: state.adminPassword.trim(),
48
- name: state.name.trim(),
49
- adminEmail: state.email.trim(),
50
- tursoEnabled: state.tursoEnabled,
51
- };
52
-
53
- // Only include Turso credentials if enabled
54
- if (state.tursoEnabled) {
55
- data.tursoDatabaseURL = state.tursoDatabaseURL.trim();
56
- data.tursoAuthToken = state.tursoAuthToken.trim();
57
- }
58
-
59
- return data;
60
- }
61
-
62
- /**
63
- * Validate tenant registration form
64
- */
65
- export function validateTenantRegistration(
66
- state: TenantRegistrationState,
67
- existingTenants?: string[],
68
- isInitMode?: boolean
69
- ): TenantValidationErrors {
70
- const errors: TenantValidationErrors = {};
71
-
72
- // Skip ALL tenant ID validation in init mode
73
- if (!isInitMode) {
74
- const tenantId = state.tenantId.trim();
75
- if (!tenantId) {
76
- errors.tenantId = 'Tenant ID is required';
77
- } else if (tenantId.length < 3 || tenantId.length > 12) {
78
- errors.tenantId = 'Tenant ID must be 3-12 characters long';
79
- } else if (tenantId !== tenantId.toLowerCase()) {
80
- errors.tenantId = 'Tenant ID must be lowercase';
81
- } else if (!/^[a-z0-9-]+$/.test(tenantId)) {
82
- errors.tenantId =
83
- 'Tenant ID can only contain lowercase letters, numbers, and dashes';
84
- } else if (tenantId === 'default') {
85
- errors.tenantId = "'default' is a reserved tenant ID";
86
- } else if (existingTenants && existingTenants.includes(tenantId)) {
87
- errors.tenantId = 'This tenant ID is already taken';
88
- }
89
- }
90
-
91
- // Admin password validation
92
- if (!state.adminPassword.trim()) {
93
- errors.adminPassword = 'Admin password is required';
94
- } else if (state.adminPassword.length < 8) {
95
- errors.adminPassword = 'Admin password must be at least 8 characters long';
96
- }
97
-
98
- // Password confirmation validation - only if main password is valid
99
- if (!errors.adminPassword && state.adminPassword !== state.confirmPassword) {
100
- errors.confirmPassword = 'Passwords do not match';
101
- }
102
-
103
- // Name validation
104
- if (!state.name.trim()) {
105
- errors.name = 'Name is required';
106
- }
107
-
108
- // Email validation
109
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
110
- if (!state.email.trim()) {
111
- errors.email = 'Email is required';
112
- } else if (!emailRegex.test(state.email.trim())) {
113
- errors.email = 'Please enter a valid email address';
114
- }
115
-
116
- // Turso validation (if enabled)
117
- if (state.tursoEnabled) {
118
- if (!state.tursoDatabaseURL.trim()) {
119
- errors.tursoDatabaseURL =
120
- 'Turso Database URL is required when Turso is enabled';
121
- } else if (!state.tursoDatabaseURL.startsWith('libsql://')) {
122
- errors.tursoDatabaseURL =
123
- 'Turso Database URL must start with "libsql://"';
124
- }
125
-
126
- if (!state.tursoAuthToken.trim()) {
127
- errors.tursoAuthToken =
128
- 'Turso Auth Token is required when Turso is enabled';
129
- }
130
- }
131
-
132
- return errors;
133
- }
134
-
135
- /**
136
- * State interceptor for cross-field logic
137
- */
138
- export function tenantStateIntercept(
139
- newState: TenantRegistrationState,
140
- field: keyof TenantRegistrationState,
141
- value: any
142
- ): TenantRegistrationState {
143
- // Clear Turso fields when disabled
144
- if (field === 'tursoEnabled' && !value) {
145
- return {
146
- ...newState,
147
- tursoEnabled: false,
148
- tursoDatabaseURL: '',
149
- tursoAuthToken: '',
150
- };
151
- }
152
-
153
- // Clear confirmation password when main password changes
154
- if (field === 'adminPassword') {
155
- return {
156
- ...newState,
157
- adminPassword: value,
158
- confirmPassword: '', // Clear confirmation to force re-entry
159
- };
160
- }
161
-
162
- // Normalize tenant ID
163
- if (field === 'tenantId' && typeof value === 'string') {
164
- return {
165
- ...newState,
166
- tenantId: value.toLowerCase().replace(/[^a-z0-9-]/g, ''),
167
- };
168
- }
169
-
170
- // Default behavior
171
- return newState;
172
- }