@orion-studios/payload-studio 0.6.0-beta.184 → 0.6.0-beta.186
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 +6 -1
- package/bin/init.js +329 -0
- package/dist/admin/index.d.mts +1 -1
- package/dist/admin/index.d.ts +1 -1
- package/dist/admin/index.js +61 -20
- package/dist/admin/index.mjs +1 -1
- package/dist/blocks/index.mjs +1 -2
- package/dist/builder-v2/client.js +21 -1
- package/dist/builder-v2/client.mjs +21 -1
- package/dist/builder-v2/index.js +33 -2
- package/dist/builder-v2/index.mjs +33 -2
- package/dist/{chunk-7HME6R2V.mjs → chunk-DTHBPJXU.mjs} +191 -21
- package/dist/{chunk-JQAHXYAM.mjs → chunk-KMYMSR7W.mjs} +163 -3
- package/dist/{chunk-KHK6RTGC.mjs → chunk-MMJNHBOF.mjs} +61 -20
- package/dist/{chunk-ZADL33R6.mjs → chunk-OF6BATTO.mjs} +56 -111
- package/dist/chunk-VA545CHJ.mjs +202 -0
- package/dist/forms/index.d.mts +25 -0
- package/dist/forms/index.d.ts +25 -0
- package/dist/forms/index.js +237 -0
- package/dist/forms/index.mjs +25 -0
- package/dist/forms/server.d.mts +35 -0
- package/dist/forms/server.d.ts +35 -0
- package/dist/forms/server.js +442 -0
- package/dist/forms/server.mjs +228 -0
- package/dist/{index-Dv-Alx4h.d.ts → index-0xXWuOuz.d.ts} +35 -5
- package/dist/{index-D5zrOdyv.d.mts → index-BU82akSL.d.mts} +35 -5
- package/dist/{index-DLfPOqYA.d.mts → index-BbTcimgH.d.mts} +1 -0
- package/dist/{index-D8BNfUJb.d.mts → index-Cen-9wcc.d.mts} +17 -5
- package/dist/{index-BV0vEGl6.d.ts → index-DV-nW43e.d.ts} +1 -0
- package/dist/{index-DD_E2UfJ.d.ts → index-gxcMPpm-.d.ts} +17 -5
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +302 -151
- package/dist/index.mjs +10 -11
- package/dist/nextjs/index.d.mts +1 -1
- package/dist/nextjs/index.d.ts +1 -1
- package/dist/nextjs/index.js +56 -111
- package/dist/nextjs/index.mjs +1 -1
- package/dist/studio-pages/index.d.mts +1 -1
- package/dist/studio-pages/index.d.ts +1 -1
- package/dist/studio-pages/index.js +1802 -20
- package/dist/studio-pages/index.mjs +10 -2
- package/package.json +18 -2
- package/dist/chunk-OQSEJXC4.mjs +0 -166
|
@@ -231,23 +231,33 @@ function configureAdmin(config) {
|
|
|
231
231
|
if (cssSources.length === 0) {
|
|
232
232
|
cssPath = sourceCssPath;
|
|
233
233
|
} else {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
234
|
+
try {
|
|
235
|
+
let css = cssSources.map((filePath) => fs.readFileSync(filePath, "utf-8")).join("\n\n");
|
|
236
|
+
css = css.replace(
|
|
237
|
+
"--orion-cms-brand-primary-fallback: #3b82f6;",
|
|
238
|
+
`--orion-cms-brand-primary-fallback: ${brandPrimary};`
|
|
239
|
+
);
|
|
240
|
+
css = css.replace(
|
|
241
|
+
"--orion-cms-brand-secondary-fallback: #8b5cf6;",
|
|
242
|
+
`--orion-cms-brand-secondary-fallback: ${brandSecondary};`
|
|
243
|
+
);
|
|
244
|
+
const outputBasePath = config.basePath || process.cwd();
|
|
245
|
+
const genDir = path.resolve(outputBasePath, ".generated");
|
|
246
|
+
const genPath = path.resolve(genDir, "admin.css");
|
|
247
|
+
let existing = null;
|
|
248
|
+
try {
|
|
249
|
+
existing = fs.readFileSync(genPath, "utf-8");
|
|
250
|
+
} catch {
|
|
251
|
+
existing = null;
|
|
252
|
+
}
|
|
253
|
+
if (existing !== css) {
|
|
254
|
+
fs.mkdirSync(genDir, { recursive: true });
|
|
255
|
+
fs.writeFileSync(genPath, css);
|
|
256
|
+
}
|
|
257
|
+
cssPath = genPath;
|
|
258
|
+
} catch {
|
|
259
|
+
cssPath = sourceCssPath;
|
|
247
260
|
}
|
|
248
|
-
const genPath = path.resolve(genDir, "admin.css");
|
|
249
|
-
fs.writeFileSync(genPath, css);
|
|
250
|
-
cssPath = genPath;
|
|
251
261
|
}
|
|
252
262
|
const clientPath = "@orion-studios/payload-studio/admin/client";
|
|
253
263
|
const studioNavClientProps = {
|
|
@@ -700,16 +710,47 @@ function configureAdmin(config) {
|
|
|
700
710
|
});
|
|
701
711
|
},
|
|
702
712
|
wrapGlobals(globals2) {
|
|
703
|
-
const
|
|
713
|
+
const defaultLabelMap = {
|
|
704
714
|
header: { group: "Site Design", label: "Header & Navigation" },
|
|
705
715
|
footer: { group: "Site Design", label: "Footer" },
|
|
706
716
|
"site-settings": { group: "Site Design", label: "Website Settings" },
|
|
707
717
|
"social-media": { group: "Site Design", label: "Social Media" },
|
|
708
718
|
"contact-form": { group: "Lead Forms", label: "Contact Form" }
|
|
709
719
|
};
|
|
720
|
+
const configuredBySlug = new Map(
|
|
721
|
+
(config.studio?.globals || []).map((link) => [link.slug, link])
|
|
722
|
+
);
|
|
723
|
+
const attachBreadcrumbToGlobal = (global) => {
|
|
724
|
+
if (!studioEnabled) {
|
|
725
|
+
return global;
|
|
726
|
+
}
|
|
727
|
+
const existingControls = global.admin?.components?.elements?.beforeDocumentControls;
|
|
728
|
+
return {
|
|
729
|
+
...global,
|
|
730
|
+
admin: {
|
|
731
|
+
...global.admin,
|
|
732
|
+
components: {
|
|
733
|
+
...global.admin?.components,
|
|
734
|
+
elements: {
|
|
735
|
+
...global.admin?.components?.elements,
|
|
736
|
+
beforeDocumentControls: appendComponent(
|
|
737
|
+
existingControls,
|
|
738
|
+
studioBackBreadcrumbComponent,
|
|
739
|
+
"StudioBackBreadcrumb"
|
|
740
|
+
)
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
};
|
|
710
746
|
return globals2.map((global) => {
|
|
711
|
-
const
|
|
712
|
-
|
|
747
|
+
const configured = configuredBySlug.get(global.slug);
|
|
748
|
+
const defaults = defaultLabelMap[global.slug];
|
|
749
|
+
const mapping = configured || defaults ? {
|
|
750
|
+
group: configured?.group || defaults?.group,
|
|
751
|
+
label: configured?.label || defaults?.label || global.slug
|
|
752
|
+
} : void 0;
|
|
753
|
+
if (!mapping) return attachBreadcrumbToGlobal(global);
|
|
713
754
|
const shouldAttachSiteSettingsEditView = studioEnabled && global.slug === "site-settings";
|
|
714
755
|
const shouldAttachSocialMediaEditView = studioEnabled && global.slug === "social-media";
|
|
715
756
|
const shouldAttachContactFormRedirect = studioEnabled && global.slug === "contact-form";
|
|
@@ -818,7 +859,7 @@ function configureAdmin(config) {
|
|
|
818
859
|
...global,
|
|
819
860
|
admin: {
|
|
820
861
|
...global.admin,
|
|
821
|
-
group: mapping.group,
|
|
862
|
+
...mapping.group ? { group: mapping.group } : {},
|
|
822
863
|
components: {
|
|
823
864
|
...global.admin?.components,
|
|
824
865
|
elements: {
|
|
@@ -26,12 +26,15 @@ __export(nextjs_exports, {
|
|
|
26
26
|
|
|
27
27
|
// src/nextjs/client/payload.ts
|
|
28
28
|
import { getPayload } from "payload";
|
|
29
|
-
var payloadPromise = null;
|
|
30
29
|
var WEBSITE_CONTENT_TAG = "website-content";
|
|
31
30
|
function createPayloadClient(config) {
|
|
31
|
+
let payloadPromise = null;
|
|
32
32
|
return function getPayloadClient() {
|
|
33
33
|
if (!payloadPromise) {
|
|
34
|
-
payloadPromise = getPayload({ config })
|
|
34
|
+
payloadPromise = Promise.resolve(config).then((resolvedConfig) => getPayload({ config: resolvedConfig })).catch((error) => {
|
|
35
|
+
payloadPromise = null;
|
|
36
|
+
throw error;
|
|
37
|
+
});
|
|
35
38
|
}
|
|
36
39
|
return payloadPromise;
|
|
37
40
|
};
|
|
@@ -64,7 +67,7 @@ function normalizePath(segments) {
|
|
|
64
67
|
const cleaned = segments.map((segment) => segment.trim()).filter(Boolean).join("/");
|
|
65
68
|
return cleaned.length > 0 ? `/${cleaned}` : "/";
|
|
66
69
|
}
|
|
67
|
-
async function queryPageByPath(payload, path, draft) {
|
|
70
|
+
async function queryPageByPath(payload, path, draft, collectionSlug, homeSlug) {
|
|
68
71
|
const pathWhere = {
|
|
69
72
|
path: {
|
|
70
73
|
equals: path
|
|
@@ -76,7 +79,7 @@ async function queryPageByPath(payload, path, draft) {
|
|
|
76
79
|
}
|
|
77
80
|
};
|
|
78
81
|
const result = await payload.find({
|
|
79
|
-
collection:
|
|
82
|
+
collection: collectionSlug,
|
|
80
83
|
depth: 2,
|
|
81
84
|
draft,
|
|
82
85
|
limit: 1,
|
|
@@ -89,11 +92,11 @@ async function queryPageByPath(payload, path, draft) {
|
|
|
89
92
|
if (path === "/") {
|
|
90
93
|
const homeWhere = {
|
|
91
94
|
slug: {
|
|
92
|
-
equals:
|
|
95
|
+
equals: homeSlug
|
|
93
96
|
}
|
|
94
97
|
};
|
|
95
98
|
const homeResult = await payload.find({
|
|
96
|
-
collection:
|
|
99
|
+
collection: collectionSlug,
|
|
97
100
|
depth: 2,
|
|
98
101
|
draft,
|
|
99
102
|
limit: 1,
|
|
@@ -104,27 +107,31 @@ async function queryPageByPath(payload, path, draft) {
|
|
|
104
107
|
}
|
|
105
108
|
return null;
|
|
106
109
|
}
|
|
107
|
-
function createPageQueries(getPayloadClient,
|
|
110
|
+
function createPageQueries(getPayloadClient, contentTagOrOptions = "website-content") {
|
|
111
|
+
const options = typeof contentTagOrOptions === "string" ? { contentTag: contentTagOrOptions } : contentTagOrOptions;
|
|
112
|
+
const contentTag = options.contentTag || "website-content";
|
|
113
|
+
const pagesCollectionSlug = options.pagesCollectionSlug || "pages";
|
|
114
|
+
const homeSlug = options.homeSlug || "home";
|
|
108
115
|
const getPublishedPageByPathCached = unstable_cache(
|
|
109
116
|
async (path) => {
|
|
110
117
|
const payload = await getPayloadClient();
|
|
111
|
-
return queryPageByPath(payload, path, false);
|
|
118
|
+
return queryPageByPath(payload, path, false, pagesCollectionSlug, homeSlug);
|
|
112
119
|
},
|
|
113
|
-
["page-by-path", PAGE_QUERY_CACHE_VERSION],
|
|
120
|
+
["page-by-path", PAGE_QUERY_CACHE_VERSION, pagesCollectionSlug, homeSlug, contentTag],
|
|
114
121
|
{ tags: [contentTag] }
|
|
115
122
|
);
|
|
116
123
|
async function getPageBySegments(segments, draft = false) {
|
|
117
124
|
const path = normalizePath(segments);
|
|
118
125
|
const payload = await getPayloadClient();
|
|
119
126
|
if (draft) {
|
|
120
|
-
return queryPageByPath(payload, path, true);
|
|
127
|
+
return queryPageByPath(payload, path, true, pagesCollectionSlug, homeSlug);
|
|
121
128
|
}
|
|
122
129
|
return getPublishedPageByPathCached(path);
|
|
123
130
|
}
|
|
124
131
|
async function listPublishedPagePaths() {
|
|
125
132
|
const payload = await getPayloadClient();
|
|
126
133
|
const pages = await payload.find({
|
|
127
|
-
collection:
|
|
134
|
+
collection: pagesCollectionSlug,
|
|
128
135
|
depth: 0,
|
|
129
136
|
draft: false,
|
|
130
137
|
limit: 1e3,
|
|
@@ -153,108 +160,46 @@ function createPageQueries(getPayloadClient, contentTag = "website-content") {
|
|
|
153
160
|
|
|
154
161
|
// src/nextjs/queries/site.ts
|
|
155
162
|
import { unstable_cache as unstable_cache2 } from "next/cache";
|
|
156
|
-
function createSiteQueries(getPayloadClient,
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
return
|
|
189
|
-
}
|
|
190
|
-
["footer-global"],
|
|
191
|
-
{ tags: [contentTag] }
|
|
192
|
-
);
|
|
193
|
-
const getSocialMediaCached = unstable_cache2(
|
|
194
|
-
async () => {
|
|
195
|
-
const payload = await getPayloadClient();
|
|
196
|
-
const socialMedia = await payload.findGlobal({
|
|
197
|
-
slug: "social-media",
|
|
198
|
-
depth: 1
|
|
199
|
-
});
|
|
200
|
-
return socialMedia;
|
|
201
|
-
},
|
|
202
|
-
["social-media-global"],
|
|
203
|
-
{ tags: [contentTag] }
|
|
204
|
-
);
|
|
205
|
-
async function getSiteSettings(draft = false) {
|
|
206
|
-
if (draft) {
|
|
207
|
-
const payload = await getPayloadClient();
|
|
208
|
-
const settings = await payload.findGlobal({
|
|
209
|
-
slug: "site-settings",
|
|
210
|
-
depth: 1,
|
|
211
|
-
draft: true
|
|
212
|
-
});
|
|
213
|
-
return settings;
|
|
214
|
-
}
|
|
215
|
-
return getSiteSettingsCached();
|
|
216
|
-
}
|
|
217
|
-
async function getHeader(draft = false) {
|
|
218
|
-
if (draft) {
|
|
219
|
-
const payload = await getPayloadClient();
|
|
220
|
-
const header = await payload.findGlobal({
|
|
221
|
-
slug: "header",
|
|
222
|
-
depth: 1,
|
|
223
|
-
draft: true
|
|
224
|
-
});
|
|
225
|
-
return header;
|
|
226
|
-
}
|
|
227
|
-
return getHeaderCached();
|
|
228
|
-
}
|
|
229
|
-
async function getFooter(draft = false) {
|
|
230
|
-
if (draft) {
|
|
231
|
-
const payload = await getPayloadClient();
|
|
232
|
-
const footer = await payload.findGlobal({
|
|
233
|
-
slug: "footer",
|
|
234
|
-
depth: 1,
|
|
235
|
-
draft: true
|
|
236
|
-
});
|
|
237
|
-
return footer;
|
|
238
|
-
}
|
|
239
|
-
return getFooterCached();
|
|
240
|
-
}
|
|
241
|
-
async function getSocialMedia(draft = false) {
|
|
242
|
-
if (draft) {
|
|
243
|
-
const payload = await getPayloadClient();
|
|
244
|
-
const socialMedia = await payload.findGlobal({
|
|
245
|
-
slug: "social-media",
|
|
246
|
-
depth: 1,
|
|
247
|
-
draft: true
|
|
248
|
-
});
|
|
249
|
-
return socialMedia;
|
|
250
|
-
}
|
|
251
|
-
return getSocialMediaCached();
|
|
163
|
+
function createSiteQueries(getPayloadClient, contentTagOrOptions = "website-content") {
|
|
164
|
+
const options = typeof contentTagOrOptions === "string" ? { contentTag: contentTagOrOptions } : contentTagOrOptions;
|
|
165
|
+
const contentTag = options.contentTag || "website-content";
|
|
166
|
+
const siteSettingsSlug = options.siteSettingsSlug || "site-settings";
|
|
167
|
+
const headerSlug = options.headerSlug || "header";
|
|
168
|
+
const footerSlug = options.footerSlug || "footer";
|
|
169
|
+
const socialMediaSlug = options.socialMediaSlug || "social-media";
|
|
170
|
+
function createGlobalQuery(slug, cacheKey) {
|
|
171
|
+
const getCached = unstable_cache2(
|
|
172
|
+
async () => {
|
|
173
|
+
const payload = await getPayloadClient();
|
|
174
|
+
const data = await payload.findGlobal({
|
|
175
|
+
slug,
|
|
176
|
+
depth: 1,
|
|
177
|
+
overrideAccess: false
|
|
178
|
+
});
|
|
179
|
+
return data;
|
|
180
|
+
},
|
|
181
|
+
[cacheKey, slug, contentTag],
|
|
182
|
+
{ tags: [contentTag] }
|
|
183
|
+
);
|
|
184
|
+
return async function getGlobal(draft = false) {
|
|
185
|
+
if (draft) {
|
|
186
|
+
const payload = await getPayloadClient();
|
|
187
|
+
const data = await payload.findGlobal({
|
|
188
|
+
slug,
|
|
189
|
+
depth: 1,
|
|
190
|
+
draft: true,
|
|
191
|
+
overrideAccess: false
|
|
192
|
+
});
|
|
193
|
+
return data;
|
|
194
|
+
}
|
|
195
|
+
return getCached();
|
|
196
|
+
};
|
|
252
197
|
}
|
|
253
198
|
return {
|
|
254
|
-
getSiteSettings,
|
|
255
|
-
getHeader,
|
|
256
|
-
getFooter,
|
|
257
|
-
getSocialMedia
|
|
199
|
+
getSiteSettings: createGlobalQuery(siteSettingsSlug, "site-settings-global"),
|
|
200
|
+
getHeader: createGlobalQuery(headerSlug, "header-global"),
|
|
201
|
+
getFooter: createGlobalQuery(footerSlug, "footer-global"),
|
|
202
|
+
getSocialMedia: createGlobalQuery(socialMediaSlug, "social-media-global")
|
|
258
203
|
};
|
|
259
204
|
}
|
|
260
205
|
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// src/forms/validation.ts
|
|
2
|
+
var MAJOR_EMAIL_PROVIDERS = [
|
|
3
|
+
"gmail.com",
|
|
4
|
+
"yahoo.com",
|
|
5
|
+
"outlook.com",
|
|
6
|
+
"hotmail.com",
|
|
7
|
+
"icloud.com",
|
|
8
|
+
"live.com",
|
|
9
|
+
"protonmail.com"
|
|
10
|
+
];
|
|
11
|
+
var KNOWN_GOOD_DOMAINS = /* @__PURE__ */ new Set([
|
|
12
|
+
...MAJOR_EMAIL_PROVIDERS,
|
|
13
|
+
"aol.com",
|
|
14
|
+
"gmx.com",
|
|
15
|
+
"googlemail.com",
|
|
16
|
+
"hey.com",
|
|
17
|
+
"mac.com",
|
|
18
|
+
"mail.com",
|
|
19
|
+
"me.com",
|
|
20
|
+
"msn.com",
|
|
21
|
+
"pm.me",
|
|
22
|
+
"proton.me",
|
|
23
|
+
"ymail.com",
|
|
24
|
+
"zoho.com"
|
|
25
|
+
]);
|
|
26
|
+
var EXPLICIT_TYPO_MAP = {
|
|
27
|
+
"gamil.com": "gmail.com",
|
|
28
|
+
"gmial.com": "gmail.com",
|
|
29
|
+
"gmai.com": "gmail.com",
|
|
30
|
+
"gmaill.com": "gmail.com",
|
|
31
|
+
"gmail.co": "gmail.com",
|
|
32
|
+
"gmail.con": "gmail.com",
|
|
33
|
+
"gmail.cmo": "gmail.com",
|
|
34
|
+
"hotmial.com": "hotmail.com",
|
|
35
|
+
"hotmall.com": "hotmail.com",
|
|
36
|
+
"hotmail.co": "hotmail.com",
|
|
37
|
+
"hotmail.con": "hotmail.com",
|
|
38
|
+
"iclod.com": "icloud.com",
|
|
39
|
+
"icloud.co": "icloud.com",
|
|
40
|
+
"icoud.com": "icloud.com",
|
|
41
|
+
"outlok.com": "outlook.com",
|
|
42
|
+
"outloook.com": "outlook.com",
|
|
43
|
+
"outlook.co": "outlook.com",
|
|
44
|
+
"outlook.con": "outlook.com",
|
|
45
|
+
"protonmail.co": "protonmail.com",
|
|
46
|
+
"yaho.com": "yahoo.com",
|
|
47
|
+
"yahooo.com": "yahoo.com",
|
|
48
|
+
"yahoo.co": "yahoo.com",
|
|
49
|
+
"yahoo.con": "yahoo.com"
|
|
50
|
+
};
|
|
51
|
+
var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
|
|
52
|
+
function levenshtein(a, b) {
|
|
53
|
+
if (a === b) return 0;
|
|
54
|
+
const rows = a.length + 1;
|
|
55
|
+
const cols = b.length + 1;
|
|
56
|
+
const dist = Array.from({ length: cols }, (_, j) => j);
|
|
57
|
+
for (let i = 1; i < rows; i += 1) {
|
|
58
|
+
let prevDiagonal = dist[0];
|
|
59
|
+
dist[0] = i;
|
|
60
|
+
for (let j = 1; j < cols; j += 1) {
|
|
61
|
+
const temp = dist[j];
|
|
62
|
+
dist[j] = Math.min(
|
|
63
|
+
dist[j] + 1,
|
|
64
|
+
dist[j - 1] + 1,
|
|
65
|
+
prevDiagonal + (a[i - 1] === b[j - 1] ? 0 : 1)
|
|
66
|
+
);
|
|
67
|
+
prevDiagonal = temp;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return dist[cols - 1];
|
|
71
|
+
}
|
|
72
|
+
function normalizeEmail(value) {
|
|
73
|
+
return value.trim().toLowerCase();
|
|
74
|
+
}
|
|
75
|
+
function validateEmail(value, options = {}) {
|
|
76
|
+
const normalized = normalizeEmail(value);
|
|
77
|
+
if (normalized.length === 0) {
|
|
78
|
+
return { valid: false, normalized, message: "Email is required." };
|
|
79
|
+
}
|
|
80
|
+
if (!EMAIL_PATTERN.test(normalized)) {
|
|
81
|
+
return { valid: false, normalized, message: "Enter a valid email address." };
|
|
82
|
+
}
|
|
83
|
+
const [localPart, domain] = normalized.split("@");
|
|
84
|
+
const knownGood = options.knownGoodDomains ? /* @__PURE__ */ new Set([...KNOWN_GOOD_DOMAINS, ...options.knownGoodDomains.map((entry) => entry.toLowerCase())]) : KNOWN_GOOD_DOMAINS;
|
|
85
|
+
if (knownGood.has(domain)) {
|
|
86
|
+
return { valid: true, normalized };
|
|
87
|
+
}
|
|
88
|
+
const explicitCorrection = EXPLICIT_TYPO_MAP[domain];
|
|
89
|
+
if (explicitCorrection) {
|
|
90
|
+
const suggestion = `${localPart}@${explicitCorrection}`;
|
|
91
|
+
return {
|
|
92
|
+
valid: false,
|
|
93
|
+
normalized,
|
|
94
|
+
message: `Did you mean ${suggestion}?`,
|
|
95
|
+
suggestion
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
for (const provider of MAJOR_EMAIL_PROVIDERS) {
|
|
99
|
+
if (levenshtein(domain, provider) === 1) {
|
|
100
|
+
const suggestion = `${localPart}@${provider}`;
|
|
101
|
+
return {
|
|
102
|
+
valid: false,
|
|
103
|
+
normalized,
|
|
104
|
+
message: `Did you mean ${suggestion}?`,
|
|
105
|
+
suggestion
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return { valid: true, normalized };
|
|
110
|
+
}
|
|
111
|
+
function normalizePhone(value) {
|
|
112
|
+
const digits = value.replace(/\D+/g, "");
|
|
113
|
+
if (digits.length === 11 && digits.startsWith("1")) {
|
|
114
|
+
return digits.slice(1);
|
|
115
|
+
}
|
|
116
|
+
return digits;
|
|
117
|
+
}
|
|
118
|
+
function formatPhoneUS(value) {
|
|
119
|
+
const digits = normalizePhone(value).slice(0, 10);
|
|
120
|
+
if (digits.length === 0) return "";
|
|
121
|
+
if (digits.length < 4) return `(${digits}`;
|
|
122
|
+
if (digits.length < 7) return `(${digits.slice(0, 3)}) ${digits.slice(3)}`;
|
|
123
|
+
return `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6)}`;
|
|
124
|
+
}
|
|
125
|
+
function validatePhoneUS(value) {
|
|
126
|
+
const digits = normalizePhone(value);
|
|
127
|
+
if (digits.length === 0) {
|
|
128
|
+
return { valid: false, normalized: "", message: "Phone number is required." };
|
|
129
|
+
}
|
|
130
|
+
if (digits.length !== 10) {
|
|
131
|
+
return { valid: false, normalized: digits, message: "Enter a 10-digit phone number." };
|
|
132
|
+
}
|
|
133
|
+
return { valid: true, normalized: digits };
|
|
134
|
+
}
|
|
135
|
+
function normalizeUrl(value) {
|
|
136
|
+
const trimmed = value.trim();
|
|
137
|
+
if (trimmed.length === 0) return "";
|
|
138
|
+
if (/^https?:\/\//i.test(trimmed)) return trimmed;
|
|
139
|
+
return `https://${trimmed}`;
|
|
140
|
+
}
|
|
141
|
+
function validateUrl(value) {
|
|
142
|
+
const normalized = normalizeUrl(value);
|
|
143
|
+
if (normalized.length === 0) {
|
|
144
|
+
return { valid: false, normalized, message: "URL is required." };
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
const parsed = new URL(normalized);
|
|
148
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
149
|
+
return { valid: false, normalized, message: "Enter a valid web address." };
|
|
150
|
+
}
|
|
151
|
+
if (!parsed.hostname.includes(".")) {
|
|
152
|
+
return { valid: false, normalized, message: "Enter a valid web address." };
|
|
153
|
+
}
|
|
154
|
+
return { valid: true, normalized };
|
|
155
|
+
} catch {
|
|
156
|
+
return { valid: false, normalized, message: "Enter a valid web address." };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function validateRequired(value, label = "This field") {
|
|
160
|
+
const normalized = typeof value === "string" ? value.trim() : "";
|
|
161
|
+
const present = typeof value === "string" ? normalized.length > 0 : Array.isArray(value) ? value.length > 0 : value !== null && value !== void 0 && value !== false;
|
|
162
|
+
if (!present) {
|
|
163
|
+
return { valid: false, normalized, message: `${label} is required.` };
|
|
164
|
+
}
|
|
165
|
+
return { valid: true, normalized: typeof value === "string" ? normalized : String(value) };
|
|
166
|
+
}
|
|
167
|
+
function normalizeFieldValue(value, fieldType) {
|
|
168
|
+
switch (fieldType) {
|
|
169
|
+
case "email":
|
|
170
|
+
return normalizeEmail(value);
|
|
171
|
+
case "phone":
|
|
172
|
+
return normalizePhone(value);
|
|
173
|
+
case "url":
|
|
174
|
+
return normalizeUrl(value);
|
|
175
|
+
default:
|
|
176
|
+
return value.trim();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function inferFieldType(field) {
|
|
180
|
+
const type = typeof field.type === "string" ? field.type.toLowerCase() : "";
|
|
181
|
+
if (type === "email" || type === "phone" || type === "tel" || type === "url") {
|
|
182
|
+
return type === "tel" ? "phone" : type;
|
|
183
|
+
}
|
|
184
|
+
const name = typeof field.name === "string" ? field.name.toLowerCase() : "";
|
|
185
|
+
if (name.includes("email")) return "email";
|
|
186
|
+
if (name.includes("phone") || name.includes("mobile")) return "phone";
|
|
187
|
+
if (name.includes("website") || name.endsWith("url")) return "url";
|
|
188
|
+
return "text";
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export {
|
|
192
|
+
normalizeEmail,
|
|
193
|
+
validateEmail,
|
|
194
|
+
normalizePhone,
|
|
195
|
+
formatPhoneUS,
|
|
196
|
+
validatePhoneUS,
|
|
197
|
+
normalizeUrl,
|
|
198
|
+
validateUrl,
|
|
199
|
+
validateRequired,
|
|
200
|
+
normalizeFieldValue,
|
|
201
|
+
inferFieldType
|
|
202
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type FieldValidationResult = {
|
|
2
|
+
valid: boolean;
|
|
3
|
+
normalized: string;
|
|
4
|
+
message?: string;
|
|
5
|
+
suggestion?: string;
|
|
6
|
+
};
|
|
7
|
+
declare function normalizeEmail(value: string): string;
|
|
8
|
+
type ValidateEmailOptions = {
|
|
9
|
+
knownGoodDomains?: string[];
|
|
10
|
+
};
|
|
11
|
+
declare function validateEmail(value: string, options?: ValidateEmailOptions): FieldValidationResult;
|
|
12
|
+
declare function normalizePhone(value: string): string;
|
|
13
|
+
declare function formatPhoneUS(value: string): string;
|
|
14
|
+
declare function validatePhoneUS(value: string): FieldValidationResult;
|
|
15
|
+
declare function normalizeUrl(value: string): string;
|
|
16
|
+
declare function validateUrl(value: string): FieldValidationResult;
|
|
17
|
+
declare function validateRequired(value: unknown, label?: string): FieldValidationResult;
|
|
18
|
+
type StudioFormFieldType = 'email' | 'phone' | 'url' | 'text';
|
|
19
|
+
declare function normalizeFieldValue(value: string, fieldType: StudioFormFieldType): string;
|
|
20
|
+
declare function inferFieldType(field: {
|
|
21
|
+
name?: unknown;
|
|
22
|
+
type?: unknown;
|
|
23
|
+
}): StudioFormFieldType;
|
|
24
|
+
|
|
25
|
+
export { type FieldValidationResult, type StudioFormFieldType, type ValidateEmailOptions, formatPhoneUS, inferFieldType, normalizeEmail, normalizeFieldValue, normalizePhone, normalizeUrl, validateEmail, validatePhoneUS, validateRequired, validateUrl };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type FieldValidationResult = {
|
|
2
|
+
valid: boolean;
|
|
3
|
+
normalized: string;
|
|
4
|
+
message?: string;
|
|
5
|
+
suggestion?: string;
|
|
6
|
+
};
|
|
7
|
+
declare function normalizeEmail(value: string): string;
|
|
8
|
+
type ValidateEmailOptions = {
|
|
9
|
+
knownGoodDomains?: string[];
|
|
10
|
+
};
|
|
11
|
+
declare function validateEmail(value: string, options?: ValidateEmailOptions): FieldValidationResult;
|
|
12
|
+
declare function normalizePhone(value: string): string;
|
|
13
|
+
declare function formatPhoneUS(value: string): string;
|
|
14
|
+
declare function validatePhoneUS(value: string): FieldValidationResult;
|
|
15
|
+
declare function normalizeUrl(value: string): string;
|
|
16
|
+
declare function validateUrl(value: string): FieldValidationResult;
|
|
17
|
+
declare function validateRequired(value: unknown, label?: string): FieldValidationResult;
|
|
18
|
+
type StudioFormFieldType = 'email' | 'phone' | 'url' | 'text';
|
|
19
|
+
declare function normalizeFieldValue(value: string, fieldType: StudioFormFieldType): string;
|
|
20
|
+
declare function inferFieldType(field: {
|
|
21
|
+
name?: unknown;
|
|
22
|
+
type?: unknown;
|
|
23
|
+
}): StudioFormFieldType;
|
|
24
|
+
|
|
25
|
+
export { type FieldValidationResult, type StudioFormFieldType, type ValidateEmailOptions, formatPhoneUS, inferFieldType, normalizeEmail, normalizeFieldValue, normalizePhone, normalizeUrl, validateEmail, validatePhoneUS, validateRequired, validateUrl };
|