@thejob/schema 2.1.3 → 2.1.5
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/.claude/settings.local.json +5 -5
- package/CLAUDE.md +85 -0
- package/dist/index.cjs +234 -138
- package/dist/index.d.cts +203 -129
- package/dist/index.d.ts +203 -129
- package/dist/index.js +198 -107
- package/package.json +1 -1
- package/src/index.ts +6 -0
- package/src/saved-search/saved-search.constant.ts +17 -0
- package/src/saved-search/saved-search.schema.ts +84 -0
- package/src/user/general-detail.schema.ts +27 -5
- package/src/user/user.constant.ts +20 -0
package/dist/index.js
CHANGED
|
@@ -1935,6 +1935,13 @@ var UserProfileVisibility = /* @__PURE__ */ ((UserProfileVisibility2) => {
|
|
|
1935
1935
|
var SupportedUserProfileVisibilities = Object.values(
|
|
1936
1936
|
UserProfileVisibility
|
|
1937
1937
|
);
|
|
1938
|
+
var SignupContextSource = /* @__PURE__ */ ((SignupContextSource2) => {
|
|
1939
|
+
SignupContextSource2["CfHeader"] = "cf-header";
|
|
1940
|
+
SignupContextSource2["Location"] = "location";
|
|
1941
|
+
SignupContextSource2["Default"] = "default";
|
|
1942
|
+
return SignupContextSource2;
|
|
1943
|
+
})(SignupContextSource || {});
|
|
1944
|
+
var SupportedSignupContextSources = Object.values(SignupContextSource);
|
|
1938
1945
|
var UserDetailType = /* @__PURE__ */ ((UserDetailType2) => {
|
|
1939
1946
|
UserDetailType2["Overview"] = "overview";
|
|
1940
1947
|
UserDetailType2["AdditionalInfo"] = "additionalInfo";
|
|
@@ -2127,8 +2134,69 @@ var DefaultPaginationOptions = {
|
|
|
2127
2134
|
limit: 10
|
|
2128
2135
|
};
|
|
2129
2136
|
|
|
2137
|
+
// src/saved-search/saved-search.schema.ts
|
|
2138
|
+
import { number as number9, object as object20, string as string17 } from "yup";
|
|
2139
|
+
|
|
2140
|
+
// src/saved-search/saved-search.constant.ts
|
|
2141
|
+
var SavedSearchStatus = /* @__PURE__ */ ((SavedSearchStatus2) => {
|
|
2142
|
+
SavedSearchStatus2["Active"] = "active";
|
|
2143
|
+
SavedSearchStatus2["Paused"] = "paused";
|
|
2144
|
+
return SavedSearchStatus2;
|
|
2145
|
+
})(SavedSearchStatus || {});
|
|
2146
|
+
var SupportedSavedSearchStatuses = Object.values(SavedSearchStatus);
|
|
2147
|
+
|
|
2148
|
+
// src/saved-search/saved-search.schema.ts
|
|
2149
|
+
var SavedSearchSchema = object20({
|
|
2150
|
+
/** Public identifier. Server-assigned. */
|
|
2151
|
+
shortId: string17().trim().label("Short Id"),
|
|
2152
|
+
/**
|
|
2153
|
+
* Owner's Better Auth account id. Server-assigned from the verified token,
|
|
2154
|
+
* never accepted from a request body.
|
|
2155
|
+
*/
|
|
2156
|
+
ownerUserId: string17().trim().label("Owner"),
|
|
2157
|
+
/** What the user calls this search, e.g. "Remote React roles". */
|
|
2158
|
+
label: string17().trim().max(120).required().label("Label"),
|
|
2159
|
+
/**
|
|
2160
|
+
* The free-text query. Optional because a search can be filters-only ("all
|
|
2161
|
+
* remote jobs in Sweden"), which is a legitimate alert to want.
|
|
2162
|
+
*/
|
|
2163
|
+
search: string17().trim().max(500).optional().label("Search Text"),
|
|
2164
|
+
/**
|
|
2165
|
+
* Field filters, in the same `{ field: values }` shape the search endpoint
|
|
2166
|
+
* parses from `filter[field]=a,b`. Held as a free-form object rather than a
|
|
2167
|
+
* closed schema because the job facets it addresses live in jobs-service and
|
|
2168
|
+
* change independently; validating them here would put this package in the
|
|
2169
|
+
* business of tracking that vocabulary.
|
|
2170
|
+
*/
|
|
2171
|
+
filter: object20().optional().default({}).label("Filters"),
|
|
2172
|
+
/**
|
|
2173
|
+
* How often to mail matches. `off` keeps the search saved but silent, which is
|
|
2174
|
+
* the difference between "I don't want mail" and "delete my search".
|
|
2175
|
+
*
|
|
2176
|
+
* Reuses the cadence enum from `marketingConsent.jobAlertFrequency` rather
|
|
2177
|
+
* than defining a second one: two vocabularies for the same concept is how
|
|
2178
|
+
* they drift.
|
|
2179
|
+
*/
|
|
2180
|
+
frequency: string17().oneOf(SupportedJobAlertFrequencies).default("off" /* Off */).label("Alert Frequency"),
|
|
2181
|
+
status: string17().oneOf(SupportedSavedSearchStatuses).default("active" /* Active */).label("Status"),
|
|
2182
|
+
/**
|
|
2183
|
+
* Epoch ms of the last alert sent for this search. The matching sweep reads it
|
|
2184
|
+
* to decide whether the cadence is due, and writes it only AFTER a successful
|
|
2185
|
+
* publish, so a failed run retries next tick rather than silently skipping a
|
|
2186
|
+
* period.
|
|
2187
|
+
*/
|
|
2188
|
+
lastNotifiedAt: number9().optional().label("Last Notified At"),
|
|
2189
|
+
/**
|
|
2190
|
+
* Epoch ms high-water mark: only jobs created after this are "new" for the
|
|
2191
|
+
* next alert. Kept separate from `lastNotifiedAt` because a run that finds no
|
|
2192
|
+
* matches should still advance what counts as new, without implying mail was
|
|
2193
|
+
* sent.
|
|
2194
|
+
*/
|
|
2195
|
+
lastMatchedAt: number9().optional().label("Last Matched At")
|
|
2196
|
+
}).noUnknown().strict();
|
|
2197
|
+
|
|
2130
2198
|
// src/report/report.schema.ts
|
|
2131
|
-
import { mixed as mixed4, object as
|
|
2199
|
+
import { mixed as mixed4, object as object21, string as string18 } from "yup";
|
|
2132
2200
|
|
|
2133
2201
|
// src/report/report.constant.ts
|
|
2134
2202
|
var ResourceType = /* @__PURE__ */ ((ResourceType3) => {
|
|
@@ -2152,15 +2220,15 @@ var ReportReason = /* @__PURE__ */ ((ReportReason3) => {
|
|
|
2152
2220
|
var SupportedReportReasons = Object.values(ReportReason);
|
|
2153
2221
|
|
|
2154
2222
|
// src/report/report.schema.ts
|
|
2155
|
-
var ReportSchema =
|
|
2223
|
+
var ReportSchema = object21({
|
|
2156
2224
|
type: mixed4().oneOf(SupportedResourceTypes).required().label("Type"),
|
|
2157
|
-
resourceId:
|
|
2225
|
+
resourceId: string18().required().label("Resource ID"),
|
|
2158
2226
|
reason: mixed4().oneOf(SupportedReportReasons).required("Please choose a reason").label("Reason"),
|
|
2159
|
-
comment:
|
|
2227
|
+
comment: string18().max(1e3).optional().label("Comment")
|
|
2160
2228
|
}).label("Report Schema");
|
|
2161
2229
|
|
|
2162
2230
|
// src/feedback/feedback.schema.ts
|
|
2163
|
-
import { mixed as mixed5, object as
|
|
2231
|
+
import { mixed as mixed5, object as object22, string as string19 } from "yup";
|
|
2164
2232
|
|
|
2165
2233
|
// src/feedback/feedback.constant.ts
|
|
2166
2234
|
var FeedbackType = /* @__PURE__ */ ((FeedbackType3) => {
|
|
@@ -2183,63 +2251,63 @@ var SupportedFeedbackStatuses = Object.values(FeedbackStatus);
|
|
|
2183
2251
|
var FEEDBACK_MESSAGE_MAX = 4e3;
|
|
2184
2252
|
|
|
2185
2253
|
// src/feedback/feedback.schema.ts
|
|
2186
|
-
var FeedbackSchema =
|
|
2254
|
+
var FeedbackSchema = object22({
|
|
2187
2255
|
type: mixed5().oneOf(SupportedFeedbackTypes).required().label("Type"),
|
|
2188
|
-
message:
|
|
2189
|
-
email:
|
|
2190
|
-
pageUrl:
|
|
2256
|
+
message: string19().trim().required("Please enter a message").max(FEEDBACK_MESSAGE_MAX).label("Message"),
|
|
2257
|
+
email: string19().email().optional().label("Email"),
|
|
2258
|
+
pageUrl: string19().optional().label("Page URL"),
|
|
2191
2259
|
status: mixed5().oneOf(SupportedFeedbackStatuses).optional().label("Status")
|
|
2192
2260
|
}).label("Feedback Schema");
|
|
2193
2261
|
|
|
2194
2262
|
// src/user/user.schema.ts
|
|
2195
|
-
import { array as array14, boolean as boolean15, number as
|
|
2263
|
+
import { array as array14, boolean as boolean15, number as number12, object as object34, string as string32 } from "yup";
|
|
2196
2264
|
|
|
2197
2265
|
// src/user/work-experience.schema.ts
|
|
2198
|
-
import { boolean as boolean12, object as
|
|
2199
|
-
var WorkExperienceSchema =
|
|
2266
|
+
import { boolean as boolean12, object as object23, string as string20 } from "yup";
|
|
2267
|
+
var WorkExperienceSchema = object23().shape({
|
|
2200
2268
|
company: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Company"),
|
|
2201
|
-
designation:
|
|
2269
|
+
designation: string20().trim().required().label("Designation"),
|
|
2202
2270
|
duration: DurationSchema({
|
|
2203
2271
|
format: "YYYY-MM",
|
|
2204
2272
|
startLabel: "Start Date",
|
|
2205
2273
|
endLabel: "End Date"
|
|
2206
2274
|
}).required().label("Duration"),
|
|
2207
|
-
description:
|
|
2275
|
+
description: string20().trim().max(3e3).optional().label("Description"),
|
|
2208
2276
|
location: LocationSchema.required().label("Location"),
|
|
2209
2277
|
isRemote: boolean12().oneOf([true, false]).default(false).label("Is Remote")
|
|
2210
2278
|
}).noUnknown().strict().label("Work Experience");
|
|
2211
2279
|
|
|
2212
2280
|
// src/user/education.schema.ts
|
|
2213
|
-
import { boolean as boolean13, object as
|
|
2214
|
-
var EducationSchema =
|
|
2281
|
+
import { boolean as boolean13, object as object24, string as string21 } from "yup";
|
|
2282
|
+
var EducationSchema = object24({
|
|
2215
2283
|
institute: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Institute"),
|
|
2216
|
-
course:
|
|
2217
|
-
fieldOfStudy:
|
|
2284
|
+
course: string21().trim().required().label("Course"),
|
|
2285
|
+
fieldOfStudy: string21().trim().required().label("Field of Study"),
|
|
2218
2286
|
duration: DurationSchema({
|
|
2219
2287
|
format: "YYYY-MM",
|
|
2220
2288
|
startLabel: "Start Date",
|
|
2221
2289
|
endLabel: "End Date"
|
|
2222
2290
|
}).required().label("Duration"),
|
|
2223
|
-
description:
|
|
2291
|
+
description: string21().trim().max(3e3).optional().label("Description"),
|
|
2224
2292
|
isDistanceLearning: boolean13().default(false).label("Is Distance Learning"),
|
|
2225
2293
|
location: LocationSchema.required().label("Location"),
|
|
2226
|
-
studyType:
|
|
2294
|
+
studyType: string21().oneOf(SupportedStudyTypes).trim().max(50).required().label("Study Type")
|
|
2227
2295
|
}).noUnknown().strict().label("Education");
|
|
2228
2296
|
|
|
2229
2297
|
// src/user/user-skill.schema.ts
|
|
2230
|
-
import { object as
|
|
2231
|
-
var UserSkillSchema =
|
|
2232
|
-
name:
|
|
2233
|
-
proficiencyLevel:
|
|
2298
|
+
import { object as object25, string as string22 } from "yup";
|
|
2299
|
+
var UserSkillSchema = object25({
|
|
2300
|
+
name: string22().required().label("Name"),
|
|
2301
|
+
proficiencyLevel: string22().oneOf(SupportedProficiencyLevels).required().label("Proficiency Level"),
|
|
2234
2302
|
lastUsed: dateString().format("YYYY-MM").nullable().optional().label("Last Used")
|
|
2235
2303
|
}).noUnknown().strict().label("Skill");
|
|
2236
2304
|
|
|
2237
2305
|
// src/user/project.schema.ts
|
|
2238
|
-
import { object as
|
|
2239
|
-
var UserProjectSchema =
|
|
2240
|
-
name:
|
|
2241
|
-
url:
|
|
2242
|
-
description:
|
|
2306
|
+
import { object as object26, string as string23 } from "yup";
|
|
2307
|
+
var UserProjectSchema = object26({
|
|
2308
|
+
name: string23().trim().max(50).required().label("Name"),
|
|
2309
|
+
url: string23().optional().label("URL"),
|
|
2310
|
+
description: string23().trim().min(100).max(3e3).required().label("Description"),
|
|
2243
2311
|
duration: DurationSchema({
|
|
2244
2312
|
format: "YYYY-MM",
|
|
2245
2313
|
startLabel: "Start Date",
|
|
@@ -2248,65 +2316,83 @@ var UserProjectSchema = object25({
|
|
|
2248
2316
|
}).noUnknown().strict().label("Project");
|
|
2249
2317
|
|
|
2250
2318
|
// src/user/user-certification.schema.ts
|
|
2251
|
-
import { object as
|
|
2252
|
-
var UserCertificationSchema =
|
|
2253
|
-
name:
|
|
2319
|
+
import { object as object27, string as string24 } from "yup";
|
|
2320
|
+
var UserCertificationSchema = object27({
|
|
2321
|
+
name: string24().trim().max(100).required().label("Name"),
|
|
2254
2322
|
// TODO: Add validation for authority
|
|
2255
|
-
authority:
|
|
2256
|
-
licenseNumber:
|
|
2323
|
+
authority: string24().trim().max(100).required().label("Authority"),
|
|
2324
|
+
licenseNumber: string24().trim().max(50).optional().label("License Number"),
|
|
2257
2325
|
duration: DurationSchema({
|
|
2258
2326
|
format: "YYYY-MM",
|
|
2259
2327
|
startLabel: "Start Date",
|
|
2260
2328
|
endLabel: "End Date"
|
|
2261
2329
|
}).optional().nullable().label("Duration"),
|
|
2262
|
-
url:
|
|
2330
|
+
url: string24().optional().label("URL")
|
|
2263
2331
|
}).noUnknown().strict().label("Certification");
|
|
2264
2332
|
|
|
2265
2333
|
// src/user/user-interest.schema.ts
|
|
2266
|
-
import { string as
|
|
2267
|
-
var UserInterestSchema =
|
|
2334
|
+
import { string as string25 } from "yup";
|
|
2335
|
+
var UserInterestSchema = string25().trim().required().label("Interest");
|
|
2268
2336
|
|
|
2269
2337
|
// src/user/user-language.schema.ts
|
|
2270
|
-
import { object as
|
|
2271
|
-
var UserLanguageSchema =
|
|
2272
|
-
name:
|
|
2273
|
-
proficiencyLevel:
|
|
2338
|
+
import { object as object28, string as string26 } from "yup";
|
|
2339
|
+
var UserLanguageSchema = object28({
|
|
2340
|
+
name: string26().trim().required().label("Name"),
|
|
2341
|
+
proficiencyLevel: string26().oneOf(SupportedProficiencyLevels).trim().max(50).required().label("Proficiency Level")
|
|
2274
2342
|
}).noUnknown().strict().label("Language");
|
|
2275
2343
|
|
|
2276
2344
|
// src/user/user-additional-info.schema.ts
|
|
2277
|
-
import { object as
|
|
2278
|
-
var UserAdditionalInfoSchema =
|
|
2279
|
-
title:
|
|
2280
|
-
description:
|
|
2345
|
+
import { object as object29, string as string27 } from "yup";
|
|
2346
|
+
var UserAdditionalInfoSchema = object29({
|
|
2347
|
+
title: string27().trim().max(60).required().label("Title"),
|
|
2348
|
+
description: string27().trim().max(1e3).required().label("Description")
|
|
2281
2349
|
}).noUnknown().strict().label("User Additional Info");
|
|
2282
2350
|
|
|
2283
2351
|
// src/user/general-detail.schema.ts
|
|
2284
|
-
import { object as
|
|
2285
|
-
var UserGeneralDetailSchema =
|
|
2286
|
-
id:
|
|
2287
|
-
name:
|
|
2288
|
-
first:
|
|
2289
|
-
last:
|
|
2352
|
+
import { number as number10, object as object30, string as string28 } from "yup";
|
|
2353
|
+
var UserGeneralDetailSchema = object30({
|
|
2354
|
+
id: string28().optional().label("ID"),
|
|
2355
|
+
name: object30().shape({
|
|
2356
|
+
first: string28().trim().max(50).required().label("First Name"),
|
|
2357
|
+
last: string28().trim().max(50).optional().label("Last Name")
|
|
2290
2358
|
}).required().label("Name"),
|
|
2291
|
-
headline:
|
|
2292
|
-
image:
|
|
2293
|
-
aboutMe:
|
|
2294
|
-
email:
|
|
2295
|
-
mobile:
|
|
2296
|
-
emailVerified:
|
|
2297
|
-
mobileVerified:
|
|
2298
|
-
experienceLevel:
|
|
2359
|
+
headline: string28().trim().max(200).optional().label("Headline"),
|
|
2360
|
+
image: string28().optional().label("Image"),
|
|
2361
|
+
aboutMe: string28().trim().max(3e3).optional().label("About Me"),
|
|
2362
|
+
email: string28().required().label("Email"),
|
|
2363
|
+
mobile: string28().nullable().optional().label("Mobile"),
|
|
2364
|
+
emailVerified: string28().nullable().optional().label("Email Verified"),
|
|
2365
|
+
mobileVerified: string28().nullable().optional().label("Mobile Verified"),
|
|
2366
|
+
experienceLevel: string28().oneOf(SupportedExperienceLevels).required().label("Experience level"),
|
|
2299
2367
|
location: LocationSchema.required().label("Location"),
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2368
|
+
/**
|
|
2369
|
+
* Where the account was created, captured once and never rewritten.
|
|
2370
|
+
*
|
|
2371
|
+
* Server-owned: listed in user-service's SERVER_CONTROLLED_FIELDS and absent
|
|
2372
|
+
* from every user-writable schema, so a client cannot set or amend it. That
|
|
2373
|
+
* immutability is the point — this answers "which market/jurisdiction governed
|
|
2374
|
+
* this user at sign-up?", which a field the user can PATCH could never do.
|
|
2375
|
+
*
|
|
2376
|
+
* `source` records HOW the value was obtained, because most of it is inferred
|
|
2377
|
+
* rather than measured, and an audit has to be able to tell those apart:
|
|
2378
|
+
* - `cf-header` measured from Cloudflare's `cf-ipcountry` at sign-up
|
|
2379
|
+
* - `location` derived from the user's self-entered profile location
|
|
2380
|
+
* - `default` assumed (no signal available); presumption, not evidence
|
|
2381
|
+
*/
|
|
2382
|
+
signupContext: object30().shape({
|
|
2383
|
+
// ISO 3166-1 alpha-2, uppercase — the shape `cf-ipcountry` returns, so
|
|
2384
|
+
// measured and inferred values are directly comparable.
|
|
2385
|
+
country: string28().trim().uppercase().length(2).required().label("Signup Country"),
|
|
2386
|
+
locale: string28().trim().required().label("Signup Locale"),
|
|
2387
|
+
source: string28().oneOf(SupportedSignupContextSources).required().label("Signup Context Source"),
|
|
2388
|
+
at: number10().required().label("Signup Context At")
|
|
2389
|
+
}).optional().default(void 0).label("Signup Context"),
|
|
2390
|
+
profileVisibility: string28().oneOf(SupportedUserProfileVisibilities).default("public" /* Public */).label("Profile Visibility")
|
|
2305
2391
|
}).noUnknown().strict().label("General Detail");
|
|
2306
2392
|
|
|
2307
2393
|
// src/user/user-job-preferences.schema.ts
|
|
2308
|
-
import { array as array11, boolean as boolean14, date as date2, number as
|
|
2309
|
-
var UserJobPreferencesSchema =
|
|
2394
|
+
import { array as array11, boolean as boolean14, date as date2, number as number11, object as object31, string as string29 } from "yup";
|
|
2395
|
+
var UserJobPreferencesSchema = object31({
|
|
2310
2396
|
/**
|
|
2311
2397
|
* Whether the job seeker is openly signalling availability. Surfaces the
|
|
2312
2398
|
* "Open to work" badge on the public profile and boosts visibility in
|
|
@@ -2318,7 +2404,7 @@ var UserJobPreferencesSchema = object30({
|
|
|
2318
2404
|
* and can downgrade the visibility of expired or low-relevance postings for
|
|
2319
2405
|
* users in `passively_browsing` mode.
|
|
2320
2406
|
*/
|
|
2321
|
-
jobSearchUrgency:
|
|
2407
|
+
jobSearchUrgency: string29().oneOf(SupportedJobSearchUrgencies).required().label("Job Search Urgency"),
|
|
2322
2408
|
/**
|
|
2323
2409
|
* Locations the user wants to work in. Stores the full `LocationSchema`
|
|
2324
2410
|
* shape (country, city, state, geo, etc.) as returned by the locations
|
|
@@ -2335,7 +2421,7 @@ var UserJobPreferencesSchema = object30({
|
|
|
2335
2421
|
* Both reuse the same `ExperienceLevel` taxonomy from `common.constant.ts`
|
|
2336
2422
|
* so search/match logic doesn't have to translate between two vocabularies.
|
|
2337
2423
|
*/
|
|
2338
|
-
targetExperienceLevels: array11().of(
|
|
2424
|
+
targetExperienceLevels: array11().of(string29().oneOf(SupportedExperienceLevels).required()).min(1, "Pick at least one experience level.").max(2, "You can select at most 2 experience levels.").required().label("Target Experience Levels"),
|
|
2339
2425
|
/**
|
|
2340
2426
|
* Specializations the user is searching for - free-form titles.
|
|
2341
2427
|
*
|
|
@@ -2344,19 +2430,19 @@ var UserJobPreferencesSchema = object30({
|
|
|
2344
2430
|
* surfaces a curated "Popular Roles" picker for discovery, but the user
|
|
2345
2431
|
* can ultimately add any title; matching/normalization happens downstream.
|
|
2346
2432
|
*/
|
|
2347
|
-
jobRoles: array11().of(
|
|
2433
|
+
jobRoles: array11().of(string29().trim().max(120).required()).min(1, "Pick at least one role.").required().label("Job Roles"),
|
|
2348
2434
|
/**
|
|
2349
2435
|
* Minimum acceptable annual base salary, in `minSalaryCurrency`.
|
|
2350
2436
|
* Stored as an integer in the currency's major unit (e.g. dollars, not cents).
|
|
2351
2437
|
* Defaults to 0 ("any salary") rather than being optional - every job-seeker
|
|
2352
2438
|
* has a floor, even if it's zero.
|
|
2353
2439
|
*/
|
|
2354
|
-
minSalary:
|
|
2355
|
-
minSalaryCurrency:
|
|
2440
|
+
minSalary: number11().integer().min(MIN_SALARY_LOWER_BOUND).max(MIN_SALARY_UPPER_BOUND).default(0).required().label("Minimum Salary"),
|
|
2441
|
+
minSalaryCurrency: string29().oneOf(SupportedSalaryCurrencies).default("USD").required().label("Minimum Salary Currency"),
|
|
2356
2442
|
/**
|
|
2357
2443
|
* Marketing-attribution capture from the final onboarding step.
|
|
2358
2444
|
*/
|
|
2359
|
-
referralSource:
|
|
2445
|
+
referralSource: string29().oneOf(SupportedReferralSources).required().label("Referral Source"),
|
|
2360
2446
|
/**
|
|
2361
2447
|
* Resumes the user has uploaded. Embedded directly on the user document
|
|
2362
2448
|
* (capped at 5) - they're cheap to denormalize, every wizard step that
|
|
@@ -2371,15 +2457,15 @@ var UserJobPreferencesSchema = object30({
|
|
|
2371
2457
|
* live in their own collection.
|
|
2372
2458
|
*/
|
|
2373
2459
|
resumes: array11().of(
|
|
2374
|
-
|
|
2460
|
+
object31({
|
|
2375
2461
|
// Stable id assigned on upload - used to address a specific entry
|
|
2376
2462
|
// for delete / set-primary operations without exposing the GCS URL
|
|
2377
2463
|
// as a route key.
|
|
2378
|
-
id:
|
|
2379
|
-
url:
|
|
2380
|
-
filename:
|
|
2381
|
-
sizeBytes:
|
|
2382
|
-
mimeType:
|
|
2464
|
+
id: string29().required().label("ID"),
|
|
2465
|
+
url: string29().required().label("Resume URL"),
|
|
2466
|
+
filename: string29().trim().max(255).optional().label("Filename"),
|
|
2467
|
+
sizeBytes: number11().integer().min(0).optional().label("Size (bytes)"),
|
|
2468
|
+
mimeType: string29().trim().max(120).optional().label("MIME Type"),
|
|
2383
2469
|
uploadedAt: date2().required().label("Uploaded At"),
|
|
2384
2470
|
isPrimary: boolean14().default(false).label("Is Primary")
|
|
2385
2471
|
}).noUnknown().strict().label("Resume")
|
|
@@ -2408,12 +2494,12 @@ var UserJobPreferencesSchema = object30({
|
|
|
2408
2494
|
* APIs. If `user.<field>` is empty there, the correct behavior is empty,
|
|
2409
2495
|
* because the user has not confirmed it yet.
|
|
2410
2496
|
*/
|
|
2411
|
-
pendingPrefill:
|
|
2412
|
-
headline:
|
|
2413
|
-
aboutMe:
|
|
2414
|
-
mobile:
|
|
2497
|
+
pendingPrefill: object31({
|
|
2498
|
+
headline: string29().trim().optional().label("Pending Headline"),
|
|
2499
|
+
aboutMe: string29().trim().optional().label("Pending About Me"),
|
|
2500
|
+
mobile: string29().trim().optional().label("Pending Mobile"),
|
|
2415
2501
|
location: LocationSchema.optional().default(void 0).label("Pending Location"),
|
|
2416
|
-
experienceLevel:
|
|
2502
|
+
experienceLevel: string29().oneOf(SupportedExperienceLevels).optional().label("Pending Experience Level"),
|
|
2417
2503
|
socialAccounts: array11().of(SocialAccountSchema.required()).optional().label("Pending Social Accounts"),
|
|
2418
2504
|
workExperiences: array11().of(WorkExperienceSchema.required()).optional().label("Pending Work Experiences"),
|
|
2419
2505
|
educations: array11().of(EducationSchema.required()).optional().label("Pending Educations")
|
|
@@ -2421,35 +2507,35 @@ var UserJobPreferencesSchema = object30({
|
|
|
2421
2507
|
}).noUnknown().strict().label("User Job Preferences Schema");
|
|
2422
2508
|
|
|
2423
2509
|
// src/user/user-recruiter-profile.schema.ts
|
|
2424
|
-
import { array as array12, object as
|
|
2425
|
-
var RecruiterPageLinkSchema =
|
|
2510
|
+
import { array as array12, object as object32, string as string30 } from "yup";
|
|
2511
|
+
var RecruiterPageLinkSchema = object32({
|
|
2426
2512
|
page: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Company Page"),
|
|
2427
|
-
jobTitle:
|
|
2513
|
+
jobTitle: string30().trim().max(100).optional().label("Job Title")
|
|
2428
2514
|
}).noUnknown().strict().label("Recruiter Page Link");
|
|
2429
|
-
var UserRecruiterProfileSchema =
|
|
2430
|
-
recruiterProfile:
|
|
2515
|
+
var UserRecruiterProfileSchema = object32({
|
|
2516
|
+
recruiterProfile: object32({
|
|
2431
2517
|
hiringFor: array12().of(RecruiterPageLinkSchema).default([]).label("Hiring For")
|
|
2432
2518
|
}).optional().default(void 0).label("Recruiter Profile")
|
|
2433
2519
|
}).noUnknown().strict().label("User Recruiter Profile");
|
|
2434
2520
|
|
|
2435
2521
|
// src/user/user-coordinator-profile.schema.ts
|
|
2436
|
-
import { array as array13, object as
|
|
2437
|
-
var CoordinatorPageLinkSchema =
|
|
2522
|
+
import { array as array13, object as object33, string as string31 } from "yup";
|
|
2523
|
+
var CoordinatorPageLinkSchema = object33({
|
|
2438
2524
|
page: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Institute Page"),
|
|
2439
|
-
jobTitle:
|
|
2525
|
+
jobTitle: string31().trim().max(100).optional().label("Job Title")
|
|
2440
2526
|
}).noUnknown().strict().label("Coordinator Page Link");
|
|
2441
|
-
var UserCoordinatorProfileSchema =
|
|
2442
|
-
coordinatorProfile:
|
|
2527
|
+
var UserCoordinatorProfileSchema = object33({
|
|
2528
|
+
coordinatorProfile: object33({
|
|
2443
2529
|
coordinatesAt: array13().of(CoordinatorPageLinkSchema).default([]).label("Coordinates At")
|
|
2444
2530
|
}).optional().default(void 0).label("Coordinator Profile")
|
|
2445
2531
|
}).noUnknown().strict().label("User Coordinator Profile");
|
|
2446
2532
|
|
|
2447
2533
|
// src/user/user.schema.ts
|
|
2448
|
-
var UserSchema =
|
|
2534
|
+
var UserSchema = object34({
|
|
2449
2535
|
/**
|
|
2450
2536
|
* Related auth account id from auth Server (e.g. Better auth https://auth.thejob.dev)
|
|
2451
2537
|
*/
|
|
2452
|
-
authAccountId:
|
|
2538
|
+
authAccountId: string32().required().label("Auth Account ID"),
|
|
2453
2539
|
/**
|
|
2454
2540
|
* Social media information about the user (e.g. LinkedIn, GitHub, etc.)
|
|
2455
2541
|
*/
|
|
@@ -2489,11 +2575,11 @@ var UserSchema = object33({
|
|
|
2489
2575
|
/**
|
|
2490
2576
|
* Status of the user account
|
|
2491
2577
|
*/
|
|
2492
|
-
status:
|
|
2578
|
+
status: string32().oneOf(SupportedUserStatuses).required().label("Status"),
|
|
2493
2579
|
/**
|
|
2494
2580
|
* Roles assigned to the user
|
|
2495
2581
|
*/
|
|
2496
|
-
roles: array14().of(
|
|
2582
|
+
roles: array14().of(string32().oneOf(SupportedUserRoles)).required().default(DefaultUserRoles).label("Roles"),
|
|
2497
2583
|
/**
|
|
2498
2584
|
* Explicit consent to receive marketing email (newsletters, job alerts by
|
|
2499
2585
|
* broadcast, product updates). Marketing sends are HARD-GATED on
|
|
@@ -2505,18 +2591,18 @@ var UserSchema = object33({
|
|
|
2505
2591
|
* unsubscribe sets `subscribed=false` so consent and the email-service
|
|
2506
2592
|
* suppression list stay consistent. Defaults to NOT subscribed (opt-in).
|
|
2507
2593
|
*/
|
|
2508
|
-
marketingConsent:
|
|
2594
|
+
marketingConsent: object34({
|
|
2509
2595
|
subscribed: boolean15().default(false).label("Subscribed to marketing email"),
|
|
2510
2596
|
/** Epoch ms of the last consent change (opt-in or opt-out). */
|
|
2511
|
-
updatedAt:
|
|
2597
|
+
updatedAt: number12().optional().label("Consent updated at"),
|
|
2512
2598
|
/** Where the consent change originated, e.g. `onboarding`, `unsubscribe`, `settings`. */
|
|
2513
|
-
source:
|
|
2599
|
+
source: string32().optional().label("Consent source"),
|
|
2514
2600
|
/**
|
|
2515
2601
|
* How often the user receives job-alert emails. `off` disables job alerts
|
|
2516
2602
|
* only; other marketing stays governed by `subscribed`. Unset means the
|
|
2517
2603
|
* user has not chosen a cadence yet.
|
|
2518
2604
|
*/
|
|
2519
|
-
jobAlertFrequency:
|
|
2605
|
+
jobAlertFrequency: string32().oneOf(SupportedJobAlertFrequencies).optional().label("Job alert frequency")
|
|
2520
2606
|
}).default({ subscribed: false }).label("Marketing Consent"),
|
|
2521
2607
|
/**
|
|
2522
2608
|
* Per-channel toggles for NOTIFICATION email — mail about activity on the
|
|
@@ -2531,7 +2617,7 @@ var UserSchema = object33({
|
|
|
2531
2617
|
*
|
|
2532
2618
|
* Transactional mail (magic-link, verification) ignores this object entirely.
|
|
2533
2619
|
*/
|
|
2534
|
-
notificationPrefs:
|
|
2620
|
+
notificationPrefs: object34({
|
|
2535
2621
|
groupActivity: boolean15().default(true).label("Group activity email"),
|
|
2536
2622
|
jobActivity: boolean15().default(true).label("Job activity email"),
|
|
2537
2623
|
applicationUpdates: boolean15().default(true).label("Application update email"),
|
|
@@ -2547,15 +2633,15 @@ var UserSchema = object33({
|
|
|
2547
2633
|
* Generated from a structured summary of skills, experience, education, etc.
|
|
2548
2634
|
* Only generated for public profiles with sufficient completeness (≥60%).
|
|
2549
2635
|
*/
|
|
2550
|
-
embedding:
|
|
2551
|
-
vector: array14(
|
|
2552
|
-
model:
|
|
2636
|
+
embedding: object34({
|
|
2637
|
+
vector: array14(number12().required()).optional().label("Embedding vector"),
|
|
2638
|
+
model: string32().optional().label("Embedding model")
|
|
2553
2639
|
}).nullable().optional().label("Embedding")
|
|
2554
2640
|
}).concat(UserGeneralDetailSchema).concat(UserJobPreferencesSchema).concat(UserRecruiterProfileSchema).concat(UserCoordinatorProfileSchema).noUnknown().strict().label("User Schema");
|
|
2555
2641
|
|
|
2556
2642
|
// src/user/user-completeness.schema.ts
|
|
2557
|
-
import { object as
|
|
2558
|
-
var UserCompletenessSchema =
|
|
2643
|
+
import { object as object35 } from "yup";
|
|
2644
|
+
var UserCompletenessSchema = object35({
|
|
2559
2645
|
additionalInfo: CompletenessScoreSchema(0).label("Additional Info"),
|
|
2560
2646
|
// Optional
|
|
2561
2647
|
certifications: CompletenessScoreSchema(0).label("Certifications"),
|
|
@@ -2647,6 +2733,9 @@ export {
|
|
|
2647
2733
|
ResourceType,
|
|
2648
2734
|
SITEMAP_FORMAT,
|
|
2649
2735
|
SYSTEM_DATE_FORMAT,
|
|
2736
|
+
SavedSearchSchema,
|
|
2737
|
+
SavedSearchStatus,
|
|
2738
|
+
SignupContextSource,
|
|
2650
2739
|
SkillSchema,
|
|
2651
2740
|
SocialAccount,
|
|
2652
2741
|
SocialAccountSchema,
|
|
@@ -2679,6 +2768,8 @@ export {
|
|
|
2679
2768
|
SupportedReportReasons,
|
|
2680
2769
|
SupportedResourceTypes,
|
|
2681
2770
|
SupportedSalaryCurrencies,
|
|
2771
|
+
SupportedSavedSearchStatuses,
|
|
2772
|
+
SupportedSignupContextSources,
|
|
2682
2773
|
SupportedSocialAccounts,
|
|
2683
2774
|
SupportedStudyTypes,
|
|
2684
2775
|
SupportedUserProfileVisibilities,
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -62,6 +62,12 @@ export * from "./marketing/marketing.constant.js";
|
|
|
62
62
|
export * from "./pagination/pagination.schema.js";
|
|
63
63
|
export * from "./pagination/pagination.constant.js";
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Saved-search schemas and constants (job alerts).
|
|
67
|
+
*/
|
|
68
|
+
export * from "./saved-search/saved-search.schema.js";
|
|
69
|
+
export * from "./saved-search/saved-search.constant.js";
|
|
70
|
+
|
|
65
71
|
/**
|
|
66
72
|
* Report schemas and constants.
|
|
67
73
|
*/
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle of a saved search. Lowercase values, like every other enum in this
|
|
3
|
+
* package: the string is stored in Mongo and compared as a literal across
|
|
4
|
+
* services, so its casing is data rather than style.
|
|
5
|
+
*/
|
|
6
|
+
export enum SavedSearchStatus {
|
|
7
|
+
/** Matching runs and alerts may be sent. */
|
|
8
|
+
Active = "active",
|
|
9
|
+
/**
|
|
10
|
+
* Kept for the user to see and re-enable, but skipped by the matching sweep.
|
|
11
|
+
* Distinct from deleting: a user pausing alerts should not lose the query they
|
|
12
|
+
* spent time building.
|
|
13
|
+
*/
|
|
14
|
+
Paused = "paused",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const SupportedSavedSearchStatuses = Object.values(SavedSearchStatus);
|