@thejob/schema 2.1.2 → 2.1.4
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 +62 -0
- package/dist/index.cjs +235 -132
- package/dist/index.d.cts +187 -102
- package/dist/index.d.ts +187 -102
- package/dist/index.js +203 -105
- 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/user.constant.ts +23 -0
- package/src/user/user.schema.ts +27 -0
package/dist/index.js
CHANGED
|
@@ -1985,6 +1985,14 @@ var JobAlertFrequency = /* @__PURE__ */ ((JobAlertFrequency2) => {
|
|
|
1985
1985
|
return JobAlertFrequency2;
|
|
1986
1986
|
})(JobAlertFrequency || {});
|
|
1987
1987
|
var SupportedJobAlertFrequencies = Object.values(JobAlertFrequency);
|
|
1988
|
+
var NotificationChannel = /* @__PURE__ */ ((NotificationChannel2) => {
|
|
1989
|
+
NotificationChannel2["GroupActivity"] = "groupActivity";
|
|
1990
|
+
NotificationChannel2["JobActivity"] = "jobActivity";
|
|
1991
|
+
NotificationChannel2["ApplicationUpdates"] = "applicationUpdates";
|
|
1992
|
+
NotificationChannel2["ProductUpdates"] = "productUpdates";
|
|
1993
|
+
return NotificationChannel2;
|
|
1994
|
+
})(NotificationChannel || {});
|
|
1995
|
+
var SupportedNotificationChannels = Object.values(NotificationChannel);
|
|
1988
1996
|
var SupportedSalaryCurrencies = ["USD", "EUR", "GBP", "SEK", "INR"];
|
|
1989
1997
|
var MIN_SALARY_LOWER_BOUND = 0;
|
|
1990
1998
|
var MIN_SALARY_UPPER_BOUND = 1e6;
|
|
@@ -2119,8 +2127,69 @@ var DefaultPaginationOptions = {
|
|
|
2119
2127
|
limit: 10
|
|
2120
2128
|
};
|
|
2121
2129
|
|
|
2130
|
+
// src/saved-search/saved-search.schema.ts
|
|
2131
|
+
import { number as number9, object as object20, string as string17 } from "yup";
|
|
2132
|
+
|
|
2133
|
+
// src/saved-search/saved-search.constant.ts
|
|
2134
|
+
var SavedSearchStatus = /* @__PURE__ */ ((SavedSearchStatus2) => {
|
|
2135
|
+
SavedSearchStatus2["Active"] = "active";
|
|
2136
|
+
SavedSearchStatus2["Paused"] = "paused";
|
|
2137
|
+
return SavedSearchStatus2;
|
|
2138
|
+
})(SavedSearchStatus || {});
|
|
2139
|
+
var SupportedSavedSearchStatuses = Object.values(SavedSearchStatus);
|
|
2140
|
+
|
|
2141
|
+
// src/saved-search/saved-search.schema.ts
|
|
2142
|
+
var SavedSearchSchema = object20({
|
|
2143
|
+
/** Public identifier. Server-assigned. */
|
|
2144
|
+
shortId: string17().trim().label("Short Id"),
|
|
2145
|
+
/**
|
|
2146
|
+
* Owner's Better Auth account id. Server-assigned from the verified token,
|
|
2147
|
+
* never accepted from a request body.
|
|
2148
|
+
*/
|
|
2149
|
+
ownerUserId: string17().trim().label("Owner"),
|
|
2150
|
+
/** What the user calls this search, e.g. "Remote React roles". */
|
|
2151
|
+
label: string17().trim().max(120).required().label("Label"),
|
|
2152
|
+
/**
|
|
2153
|
+
* The free-text query. Optional because a search can be filters-only ("all
|
|
2154
|
+
* remote jobs in Sweden"), which is a legitimate alert to want.
|
|
2155
|
+
*/
|
|
2156
|
+
search: string17().trim().max(500).optional().label("Search Text"),
|
|
2157
|
+
/**
|
|
2158
|
+
* Field filters, in the same `{ field: values }` shape the search endpoint
|
|
2159
|
+
* parses from `filter[field]=a,b`. Held as a free-form object rather than a
|
|
2160
|
+
* closed schema because the job facets it addresses live in jobs-service and
|
|
2161
|
+
* change independently; validating them here would put this package in the
|
|
2162
|
+
* business of tracking that vocabulary.
|
|
2163
|
+
*/
|
|
2164
|
+
filter: object20().optional().default({}).label("Filters"),
|
|
2165
|
+
/**
|
|
2166
|
+
* How often to mail matches. `off` keeps the search saved but silent, which is
|
|
2167
|
+
* the difference between "I don't want mail" and "delete my search".
|
|
2168
|
+
*
|
|
2169
|
+
* Reuses the cadence enum from `marketingConsent.jobAlertFrequency` rather
|
|
2170
|
+
* than defining a second one: two vocabularies for the same concept is how
|
|
2171
|
+
* they drift.
|
|
2172
|
+
*/
|
|
2173
|
+
frequency: string17().oneOf(SupportedJobAlertFrequencies).default("off" /* Off */).label("Alert Frequency"),
|
|
2174
|
+
status: string17().oneOf(SupportedSavedSearchStatuses).default("active" /* Active */).label("Status"),
|
|
2175
|
+
/**
|
|
2176
|
+
* Epoch ms of the last alert sent for this search. The matching sweep reads it
|
|
2177
|
+
* to decide whether the cadence is due, and writes it only AFTER a successful
|
|
2178
|
+
* publish, so a failed run retries next tick rather than silently skipping a
|
|
2179
|
+
* period.
|
|
2180
|
+
*/
|
|
2181
|
+
lastNotifiedAt: number9().optional().label("Last Notified At"),
|
|
2182
|
+
/**
|
|
2183
|
+
* Epoch ms high-water mark: only jobs created after this are "new" for the
|
|
2184
|
+
* next alert. Kept separate from `lastNotifiedAt` because a run that finds no
|
|
2185
|
+
* matches should still advance what counts as new, without implying mail was
|
|
2186
|
+
* sent.
|
|
2187
|
+
*/
|
|
2188
|
+
lastMatchedAt: number9().optional().label("Last Matched At")
|
|
2189
|
+
}).noUnknown().strict();
|
|
2190
|
+
|
|
2122
2191
|
// src/report/report.schema.ts
|
|
2123
|
-
import { mixed as mixed4, object as
|
|
2192
|
+
import { mixed as mixed4, object as object21, string as string18 } from "yup";
|
|
2124
2193
|
|
|
2125
2194
|
// src/report/report.constant.ts
|
|
2126
2195
|
var ResourceType = /* @__PURE__ */ ((ResourceType3) => {
|
|
@@ -2144,15 +2213,15 @@ var ReportReason = /* @__PURE__ */ ((ReportReason3) => {
|
|
|
2144
2213
|
var SupportedReportReasons = Object.values(ReportReason);
|
|
2145
2214
|
|
|
2146
2215
|
// src/report/report.schema.ts
|
|
2147
|
-
var ReportSchema =
|
|
2216
|
+
var ReportSchema = object21({
|
|
2148
2217
|
type: mixed4().oneOf(SupportedResourceTypes).required().label("Type"),
|
|
2149
|
-
resourceId:
|
|
2218
|
+
resourceId: string18().required().label("Resource ID"),
|
|
2150
2219
|
reason: mixed4().oneOf(SupportedReportReasons).required("Please choose a reason").label("Reason"),
|
|
2151
|
-
comment:
|
|
2220
|
+
comment: string18().max(1e3).optional().label("Comment")
|
|
2152
2221
|
}).label("Report Schema");
|
|
2153
2222
|
|
|
2154
2223
|
// src/feedback/feedback.schema.ts
|
|
2155
|
-
import { mixed as mixed5, object as
|
|
2224
|
+
import { mixed as mixed5, object as object22, string as string19 } from "yup";
|
|
2156
2225
|
|
|
2157
2226
|
// src/feedback/feedback.constant.ts
|
|
2158
2227
|
var FeedbackType = /* @__PURE__ */ ((FeedbackType3) => {
|
|
@@ -2175,63 +2244,63 @@ var SupportedFeedbackStatuses = Object.values(FeedbackStatus);
|
|
|
2175
2244
|
var FEEDBACK_MESSAGE_MAX = 4e3;
|
|
2176
2245
|
|
|
2177
2246
|
// src/feedback/feedback.schema.ts
|
|
2178
|
-
var FeedbackSchema =
|
|
2247
|
+
var FeedbackSchema = object22({
|
|
2179
2248
|
type: mixed5().oneOf(SupportedFeedbackTypes).required().label("Type"),
|
|
2180
|
-
message:
|
|
2181
|
-
email:
|
|
2182
|
-
pageUrl:
|
|
2249
|
+
message: string19().trim().required("Please enter a message").max(FEEDBACK_MESSAGE_MAX).label("Message"),
|
|
2250
|
+
email: string19().email().optional().label("Email"),
|
|
2251
|
+
pageUrl: string19().optional().label("Page URL"),
|
|
2183
2252
|
status: mixed5().oneOf(SupportedFeedbackStatuses).optional().label("Status")
|
|
2184
2253
|
}).label("Feedback Schema");
|
|
2185
2254
|
|
|
2186
2255
|
// src/user/user.schema.ts
|
|
2187
|
-
import { array as array14, boolean as boolean15, number as
|
|
2256
|
+
import { array as array14, boolean as boolean15, number as number11, object as object34, string as string32 } from "yup";
|
|
2188
2257
|
|
|
2189
2258
|
// src/user/work-experience.schema.ts
|
|
2190
|
-
import { boolean as boolean12, object as
|
|
2191
|
-
var WorkExperienceSchema =
|
|
2259
|
+
import { boolean as boolean12, object as object23, string as string20 } from "yup";
|
|
2260
|
+
var WorkExperienceSchema = object23().shape({
|
|
2192
2261
|
company: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Company"),
|
|
2193
|
-
designation:
|
|
2262
|
+
designation: string20().trim().required().label("Designation"),
|
|
2194
2263
|
duration: DurationSchema({
|
|
2195
2264
|
format: "YYYY-MM",
|
|
2196
2265
|
startLabel: "Start Date",
|
|
2197
2266
|
endLabel: "End Date"
|
|
2198
2267
|
}).required().label("Duration"),
|
|
2199
|
-
description:
|
|
2268
|
+
description: string20().trim().max(3e3).optional().label("Description"),
|
|
2200
2269
|
location: LocationSchema.required().label("Location"),
|
|
2201
2270
|
isRemote: boolean12().oneOf([true, false]).default(false).label("Is Remote")
|
|
2202
2271
|
}).noUnknown().strict().label("Work Experience");
|
|
2203
2272
|
|
|
2204
2273
|
// src/user/education.schema.ts
|
|
2205
|
-
import { boolean as boolean13, object as
|
|
2206
|
-
var EducationSchema =
|
|
2274
|
+
import { boolean as boolean13, object as object24, string as string21 } from "yup";
|
|
2275
|
+
var EducationSchema = object24({
|
|
2207
2276
|
institute: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Institute"),
|
|
2208
|
-
course:
|
|
2209
|
-
fieldOfStudy:
|
|
2277
|
+
course: string21().trim().required().label("Course"),
|
|
2278
|
+
fieldOfStudy: string21().trim().required().label("Field of Study"),
|
|
2210
2279
|
duration: DurationSchema({
|
|
2211
2280
|
format: "YYYY-MM",
|
|
2212
2281
|
startLabel: "Start Date",
|
|
2213
2282
|
endLabel: "End Date"
|
|
2214
2283
|
}).required().label("Duration"),
|
|
2215
|
-
description:
|
|
2284
|
+
description: string21().trim().max(3e3).optional().label("Description"),
|
|
2216
2285
|
isDistanceLearning: boolean13().default(false).label("Is Distance Learning"),
|
|
2217
2286
|
location: LocationSchema.required().label("Location"),
|
|
2218
|
-
studyType:
|
|
2287
|
+
studyType: string21().oneOf(SupportedStudyTypes).trim().max(50).required().label("Study Type")
|
|
2219
2288
|
}).noUnknown().strict().label("Education");
|
|
2220
2289
|
|
|
2221
2290
|
// src/user/user-skill.schema.ts
|
|
2222
|
-
import { object as
|
|
2223
|
-
var UserSkillSchema =
|
|
2224
|
-
name:
|
|
2225
|
-
proficiencyLevel:
|
|
2291
|
+
import { object as object25, string as string22 } from "yup";
|
|
2292
|
+
var UserSkillSchema = object25({
|
|
2293
|
+
name: string22().required().label("Name"),
|
|
2294
|
+
proficiencyLevel: string22().oneOf(SupportedProficiencyLevels).required().label("Proficiency Level"),
|
|
2226
2295
|
lastUsed: dateString().format("YYYY-MM").nullable().optional().label("Last Used")
|
|
2227
2296
|
}).noUnknown().strict().label("Skill");
|
|
2228
2297
|
|
|
2229
2298
|
// src/user/project.schema.ts
|
|
2230
|
-
import { object as
|
|
2231
|
-
var UserProjectSchema =
|
|
2232
|
-
name:
|
|
2233
|
-
url:
|
|
2234
|
-
description:
|
|
2299
|
+
import { object as object26, string as string23 } from "yup";
|
|
2300
|
+
var UserProjectSchema = object26({
|
|
2301
|
+
name: string23().trim().max(50).required().label("Name"),
|
|
2302
|
+
url: string23().optional().label("URL"),
|
|
2303
|
+
description: string23().trim().min(100).max(3e3).required().label("Description"),
|
|
2235
2304
|
duration: DurationSchema({
|
|
2236
2305
|
format: "YYYY-MM",
|
|
2237
2306
|
startLabel: "Start Date",
|
|
@@ -2240,65 +2309,65 @@ var UserProjectSchema = object25({
|
|
|
2240
2309
|
}).noUnknown().strict().label("Project");
|
|
2241
2310
|
|
|
2242
2311
|
// src/user/user-certification.schema.ts
|
|
2243
|
-
import { object as
|
|
2244
|
-
var UserCertificationSchema =
|
|
2245
|
-
name:
|
|
2312
|
+
import { object as object27, string as string24 } from "yup";
|
|
2313
|
+
var UserCertificationSchema = object27({
|
|
2314
|
+
name: string24().trim().max(100).required().label("Name"),
|
|
2246
2315
|
// TODO: Add validation for authority
|
|
2247
|
-
authority:
|
|
2248
|
-
licenseNumber:
|
|
2316
|
+
authority: string24().trim().max(100).required().label("Authority"),
|
|
2317
|
+
licenseNumber: string24().trim().max(50).optional().label("License Number"),
|
|
2249
2318
|
duration: DurationSchema({
|
|
2250
2319
|
format: "YYYY-MM",
|
|
2251
2320
|
startLabel: "Start Date",
|
|
2252
2321
|
endLabel: "End Date"
|
|
2253
2322
|
}).optional().nullable().label("Duration"),
|
|
2254
|
-
url:
|
|
2323
|
+
url: string24().optional().label("URL")
|
|
2255
2324
|
}).noUnknown().strict().label("Certification");
|
|
2256
2325
|
|
|
2257
2326
|
// src/user/user-interest.schema.ts
|
|
2258
|
-
import { string as
|
|
2259
|
-
var UserInterestSchema =
|
|
2327
|
+
import { string as string25 } from "yup";
|
|
2328
|
+
var UserInterestSchema = string25().trim().required().label("Interest");
|
|
2260
2329
|
|
|
2261
2330
|
// src/user/user-language.schema.ts
|
|
2262
|
-
import { object as
|
|
2263
|
-
var UserLanguageSchema =
|
|
2264
|
-
name:
|
|
2265
|
-
proficiencyLevel:
|
|
2331
|
+
import { object as object28, string as string26 } from "yup";
|
|
2332
|
+
var UserLanguageSchema = object28({
|
|
2333
|
+
name: string26().trim().required().label("Name"),
|
|
2334
|
+
proficiencyLevel: string26().oneOf(SupportedProficiencyLevels).trim().max(50).required().label("Proficiency Level")
|
|
2266
2335
|
}).noUnknown().strict().label("Language");
|
|
2267
2336
|
|
|
2268
2337
|
// src/user/user-additional-info.schema.ts
|
|
2269
|
-
import { object as
|
|
2270
|
-
var UserAdditionalInfoSchema =
|
|
2271
|
-
title:
|
|
2272
|
-
description:
|
|
2338
|
+
import { object as object29, string as string27 } from "yup";
|
|
2339
|
+
var UserAdditionalInfoSchema = object29({
|
|
2340
|
+
title: string27().trim().max(60).required().label("Title"),
|
|
2341
|
+
description: string27().trim().max(1e3).required().label("Description")
|
|
2273
2342
|
}).noUnknown().strict().label("User Additional Info");
|
|
2274
2343
|
|
|
2275
2344
|
// src/user/general-detail.schema.ts
|
|
2276
|
-
import { object as
|
|
2277
|
-
var UserGeneralDetailSchema =
|
|
2278
|
-
id:
|
|
2279
|
-
name:
|
|
2280
|
-
first:
|
|
2281
|
-
last:
|
|
2345
|
+
import { object as object30, string as string28 } from "yup";
|
|
2346
|
+
var UserGeneralDetailSchema = object30({
|
|
2347
|
+
id: string28().optional().label("ID"),
|
|
2348
|
+
name: object30().shape({
|
|
2349
|
+
first: string28().trim().max(50).required().label("First Name"),
|
|
2350
|
+
last: string28().trim().max(50).optional().label("Last Name")
|
|
2282
2351
|
}).required().label("Name"),
|
|
2283
|
-
headline:
|
|
2284
|
-
image:
|
|
2285
|
-
aboutMe:
|
|
2286
|
-
email:
|
|
2287
|
-
mobile:
|
|
2288
|
-
emailVerified:
|
|
2289
|
-
mobileVerified:
|
|
2290
|
-
experienceLevel:
|
|
2352
|
+
headline: string28().trim().max(200).optional().label("Headline"),
|
|
2353
|
+
image: string28().optional().label("Image"),
|
|
2354
|
+
aboutMe: string28().trim().max(3e3).optional().label("About Me"),
|
|
2355
|
+
email: string28().required().label("Email"),
|
|
2356
|
+
mobile: string28().nullable().optional().label("Mobile"),
|
|
2357
|
+
emailVerified: string28().nullable().optional().label("Email Verified"),
|
|
2358
|
+
mobileVerified: string28().nullable().optional().label("Mobile Verified"),
|
|
2359
|
+
experienceLevel: string28().oneOf(SupportedExperienceLevels).required().label("Experience level"),
|
|
2291
2360
|
location: LocationSchema.required().label("Location"),
|
|
2292
|
-
region:
|
|
2293
|
-
country:
|
|
2294
|
-
lang:
|
|
2361
|
+
region: object30().shape({
|
|
2362
|
+
country: string28().trim().required().label("Region Country"),
|
|
2363
|
+
lang: string28().trim().required().label("Region Language")
|
|
2295
2364
|
}).optional().default(void 0).label("Region"),
|
|
2296
|
-
profileVisibility:
|
|
2365
|
+
profileVisibility: string28().oneOf(SupportedUserProfileVisibilities).default("public" /* Public */).label("Profile Visibility")
|
|
2297
2366
|
}).noUnknown().strict().label("General Detail");
|
|
2298
2367
|
|
|
2299
2368
|
// src/user/user-job-preferences.schema.ts
|
|
2300
|
-
import { array as array11, boolean as boolean14, date as date2, number as
|
|
2301
|
-
var UserJobPreferencesSchema =
|
|
2369
|
+
import { array as array11, boolean as boolean14, date as date2, number as number10, object as object31, string as string29 } from "yup";
|
|
2370
|
+
var UserJobPreferencesSchema = object31({
|
|
2302
2371
|
/**
|
|
2303
2372
|
* Whether the job seeker is openly signalling availability. Surfaces the
|
|
2304
2373
|
* "Open to work" badge on the public profile and boosts visibility in
|
|
@@ -2310,7 +2379,7 @@ var UserJobPreferencesSchema = object30({
|
|
|
2310
2379
|
* and can downgrade the visibility of expired or low-relevance postings for
|
|
2311
2380
|
* users in `passively_browsing` mode.
|
|
2312
2381
|
*/
|
|
2313
|
-
jobSearchUrgency:
|
|
2382
|
+
jobSearchUrgency: string29().oneOf(SupportedJobSearchUrgencies).required().label("Job Search Urgency"),
|
|
2314
2383
|
/**
|
|
2315
2384
|
* Locations the user wants to work in. Stores the full `LocationSchema`
|
|
2316
2385
|
* shape (country, city, state, geo, etc.) as returned by the locations
|
|
@@ -2327,7 +2396,7 @@ var UserJobPreferencesSchema = object30({
|
|
|
2327
2396
|
* Both reuse the same `ExperienceLevel` taxonomy from `common.constant.ts`
|
|
2328
2397
|
* so search/match logic doesn't have to translate between two vocabularies.
|
|
2329
2398
|
*/
|
|
2330
|
-
targetExperienceLevels: array11().of(
|
|
2399
|
+
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"),
|
|
2331
2400
|
/**
|
|
2332
2401
|
* Specializations the user is searching for - free-form titles.
|
|
2333
2402
|
*
|
|
@@ -2336,19 +2405,19 @@ var UserJobPreferencesSchema = object30({
|
|
|
2336
2405
|
* surfaces a curated "Popular Roles" picker for discovery, but the user
|
|
2337
2406
|
* can ultimately add any title; matching/normalization happens downstream.
|
|
2338
2407
|
*/
|
|
2339
|
-
jobRoles: array11().of(
|
|
2408
|
+
jobRoles: array11().of(string29().trim().max(120).required()).min(1, "Pick at least one role.").required().label("Job Roles"),
|
|
2340
2409
|
/**
|
|
2341
2410
|
* Minimum acceptable annual base salary, in `minSalaryCurrency`.
|
|
2342
2411
|
* Stored as an integer in the currency's major unit (e.g. dollars, not cents).
|
|
2343
2412
|
* Defaults to 0 ("any salary") rather than being optional - every job-seeker
|
|
2344
2413
|
* has a floor, even if it's zero.
|
|
2345
2414
|
*/
|
|
2346
|
-
minSalary:
|
|
2347
|
-
minSalaryCurrency:
|
|
2415
|
+
minSalary: number10().integer().min(MIN_SALARY_LOWER_BOUND).max(MIN_SALARY_UPPER_BOUND).default(0).required().label("Minimum Salary"),
|
|
2416
|
+
minSalaryCurrency: string29().oneOf(SupportedSalaryCurrencies).default("USD").required().label("Minimum Salary Currency"),
|
|
2348
2417
|
/**
|
|
2349
2418
|
* Marketing-attribution capture from the final onboarding step.
|
|
2350
2419
|
*/
|
|
2351
|
-
referralSource:
|
|
2420
|
+
referralSource: string29().oneOf(SupportedReferralSources).required().label("Referral Source"),
|
|
2352
2421
|
/**
|
|
2353
2422
|
* Resumes the user has uploaded. Embedded directly on the user document
|
|
2354
2423
|
* (capped at 5) - they're cheap to denormalize, every wizard step that
|
|
@@ -2363,15 +2432,15 @@ var UserJobPreferencesSchema = object30({
|
|
|
2363
2432
|
* live in their own collection.
|
|
2364
2433
|
*/
|
|
2365
2434
|
resumes: array11().of(
|
|
2366
|
-
|
|
2435
|
+
object31({
|
|
2367
2436
|
// Stable id assigned on upload - used to address a specific entry
|
|
2368
2437
|
// for delete / set-primary operations without exposing the GCS URL
|
|
2369
2438
|
// as a route key.
|
|
2370
|
-
id:
|
|
2371
|
-
url:
|
|
2372
|
-
filename:
|
|
2373
|
-
sizeBytes:
|
|
2374
|
-
mimeType:
|
|
2439
|
+
id: string29().required().label("ID"),
|
|
2440
|
+
url: string29().required().label("Resume URL"),
|
|
2441
|
+
filename: string29().trim().max(255).optional().label("Filename"),
|
|
2442
|
+
sizeBytes: number10().integer().min(0).optional().label("Size (bytes)"),
|
|
2443
|
+
mimeType: string29().trim().max(120).optional().label("MIME Type"),
|
|
2375
2444
|
uploadedAt: date2().required().label("Uploaded At"),
|
|
2376
2445
|
isPrimary: boolean14().default(false).label("Is Primary")
|
|
2377
2446
|
}).noUnknown().strict().label("Resume")
|
|
@@ -2400,12 +2469,12 @@ var UserJobPreferencesSchema = object30({
|
|
|
2400
2469
|
* APIs. If `user.<field>` is empty there, the correct behavior is empty,
|
|
2401
2470
|
* because the user has not confirmed it yet.
|
|
2402
2471
|
*/
|
|
2403
|
-
pendingPrefill:
|
|
2404
|
-
headline:
|
|
2405
|
-
aboutMe:
|
|
2406
|
-
mobile:
|
|
2472
|
+
pendingPrefill: object31({
|
|
2473
|
+
headline: string29().trim().optional().label("Pending Headline"),
|
|
2474
|
+
aboutMe: string29().trim().optional().label("Pending About Me"),
|
|
2475
|
+
mobile: string29().trim().optional().label("Pending Mobile"),
|
|
2407
2476
|
location: LocationSchema.optional().default(void 0).label("Pending Location"),
|
|
2408
|
-
experienceLevel:
|
|
2477
|
+
experienceLevel: string29().oneOf(SupportedExperienceLevels).optional().label("Pending Experience Level"),
|
|
2409
2478
|
socialAccounts: array11().of(SocialAccountSchema.required()).optional().label("Pending Social Accounts"),
|
|
2410
2479
|
workExperiences: array11().of(WorkExperienceSchema.required()).optional().label("Pending Work Experiences"),
|
|
2411
2480
|
educations: array11().of(EducationSchema.required()).optional().label("Pending Educations")
|
|
@@ -2413,35 +2482,35 @@ var UserJobPreferencesSchema = object30({
|
|
|
2413
2482
|
}).noUnknown().strict().label("User Job Preferences Schema");
|
|
2414
2483
|
|
|
2415
2484
|
// src/user/user-recruiter-profile.schema.ts
|
|
2416
|
-
import { array as array12, object as
|
|
2417
|
-
var RecruiterPageLinkSchema =
|
|
2485
|
+
import { array as array12, object as object32, string as string30 } from "yup";
|
|
2486
|
+
var RecruiterPageLinkSchema = object32({
|
|
2418
2487
|
page: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Company Page"),
|
|
2419
|
-
jobTitle:
|
|
2488
|
+
jobTitle: string30().trim().max(100).optional().label("Job Title")
|
|
2420
2489
|
}).noUnknown().strict().label("Recruiter Page Link");
|
|
2421
|
-
var UserRecruiterProfileSchema =
|
|
2422
|
-
recruiterProfile:
|
|
2490
|
+
var UserRecruiterProfileSchema = object32({
|
|
2491
|
+
recruiterProfile: object32({
|
|
2423
2492
|
hiringFor: array12().of(RecruiterPageLinkSchema).default([]).label("Hiring For")
|
|
2424
2493
|
}).optional().default(void 0).label("Recruiter Profile")
|
|
2425
2494
|
}).noUnknown().strict().label("User Recruiter Profile");
|
|
2426
2495
|
|
|
2427
2496
|
// src/user/user-coordinator-profile.schema.ts
|
|
2428
|
-
import { array as array13, object as
|
|
2429
|
-
var CoordinatorPageLinkSchema =
|
|
2497
|
+
import { array as array13, object as object33, string as string31 } from "yup";
|
|
2498
|
+
var CoordinatorPageLinkSchema = object33({
|
|
2430
2499
|
page: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Institute Page"),
|
|
2431
|
-
jobTitle:
|
|
2500
|
+
jobTitle: string31().trim().max(100).optional().label("Job Title")
|
|
2432
2501
|
}).noUnknown().strict().label("Coordinator Page Link");
|
|
2433
|
-
var UserCoordinatorProfileSchema =
|
|
2434
|
-
coordinatorProfile:
|
|
2502
|
+
var UserCoordinatorProfileSchema = object33({
|
|
2503
|
+
coordinatorProfile: object33({
|
|
2435
2504
|
coordinatesAt: array13().of(CoordinatorPageLinkSchema).default([]).label("Coordinates At")
|
|
2436
2505
|
}).optional().default(void 0).label("Coordinator Profile")
|
|
2437
2506
|
}).noUnknown().strict().label("User Coordinator Profile");
|
|
2438
2507
|
|
|
2439
2508
|
// src/user/user.schema.ts
|
|
2440
|
-
var UserSchema =
|
|
2509
|
+
var UserSchema = object34({
|
|
2441
2510
|
/**
|
|
2442
2511
|
* Related auth account id from auth Server (e.g. Better auth https://auth.thejob.dev)
|
|
2443
2512
|
*/
|
|
2444
|
-
authAccountId:
|
|
2513
|
+
authAccountId: string32().required().label("Auth Account ID"),
|
|
2445
2514
|
/**
|
|
2446
2515
|
* Social media information about the user (e.g. LinkedIn, GitHub, etc.)
|
|
2447
2516
|
*/
|
|
@@ -2481,11 +2550,11 @@ var UserSchema = object33({
|
|
|
2481
2550
|
/**
|
|
2482
2551
|
* Status of the user account
|
|
2483
2552
|
*/
|
|
2484
|
-
status:
|
|
2553
|
+
status: string32().oneOf(SupportedUserStatuses).required().label("Status"),
|
|
2485
2554
|
/**
|
|
2486
2555
|
* Roles assigned to the user
|
|
2487
2556
|
*/
|
|
2488
|
-
roles: array14().of(
|
|
2557
|
+
roles: array14().of(string32().oneOf(SupportedUserRoles)).required().default(DefaultUserRoles).label("Roles"),
|
|
2489
2558
|
/**
|
|
2490
2559
|
* Explicit consent to receive marketing email (newsletters, job alerts by
|
|
2491
2560
|
* broadcast, product updates). Marketing sends are HARD-GATED on
|
|
@@ -2497,33 +2566,57 @@ var UserSchema = object33({
|
|
|
2497
2566
|
* unsubscribe sets `subscribed=false` so consent and the email-service
|
|
2498
2567
|
* suppression list stay consistent. Defaults to NOT subscribed (opt-in).
|
|
2499
2568
|
*/
|
|
2500
|
-
marketingConsent:
|
|
2569
|
+
marketingConsent: object34({
|
|
2501
2570
|
subscribed: boolean15().default(false).label("Subscribed to marketing email"),
|
|
2502
2571
|
/** Epoch ms of the last consent change (opt-in or opt-out). */
|
|
2503
|
-
updatedAt:
|
|
2572
|
+
updatedAt: number11().optional().label("Consent updated at"),
|
|
2504
2573
|
/** Where the consent change originated, e.g. `onboarding`, `unsubscribe`, `settings`. */
|
|
2505
|
-
source:
|
|
2574
|
+
source: string32().optional().label("Consent source"),
|
|
2506
2575
|
/**
|
|
2507
2576
|
* How often the user receives job-alert emails. `off` disables job alerts
|
|
2508
2577
|
* only; other marketing stays governed by `subscribed`. Unset means the
|
|
2509
2578
|
* user has not chosen a cadence yet.
|
|
2510
2579
|
*/
|
|
2511
|
-
jobAlertFrequency:
|
|
2580
|
+
jobAlertFrequency: string32().oneOf(SupportedJobAlertFrequencies).optional().label("Job alert frequency")
|
|
2512
2581
|
}).default({ subscribed: false }).label("Marketing Consent"),
|
|
2582
|
+
/**
|
|
2583
|
+
* Per-channel toggles for NOTIFICATION email — mail about activity on the
|
|
2584
|
+
* user's own account (a group invite, a job of theirs expiring).
|
|
2585
|
+
*
|
|
2586
|
+
* Deliberately separate from `marketingConsent`, which they must NOT be
|
|
2587
|
+
* collapsed into: the two have different legal footing, which the
|
|
2588
|
+
* email-service footer rules already encode. Notifications are opt-OUT
|
|
2589
|
+
* (default `true`) because a user who declined marketing still needs to hear
|
|
2590
|
+
* that their group invite arrived; marketing stays opt-IN. `productUpdates`
|
|
2591
|
+
* is the exception — it is promotional in character, so it defaults off.
|
|
2592
|
+
*
|
|
2593
|
+
* Transactional mail (magic-link, verification) ignores this object entirely.
|
|
2594
|
+
*/
|
|
2595
|
+
notificationPrefs: object34({
|
|
2596
|
+
groupActivity: boolean15().default(true).label("Group activity email"),
|
|
2597
|
+
jobActivity: boolean15().default(true).label("Job activity email"),
|
|
2598
|
+
applicationUpdates: boolean15().default(true).label("Application update email"),
|
|
2599
|
+
productUpdates: boolean15().default(false).label("Product update email")
|
|
2600
|
+
}).default({
|
|
2601
|
+
groupActivity: true,
|
|
2602
|
+
jobActivity: true,
|
|
2603
|
+
applicationUpdates: true,
|
|
2604
|
+
productUpdates: false
|
|
2605
|
+
}).label("Notification Preferences"),
|
|
2513
2606
|
/**
|
|
2514
2607
|
* Vector embedding of the user's profile for semantic/hybrid search.
|
|
2515
2608
|
* Generated from a structured summary of skills, experience, education, etc.
|
|
2516
2609
|
* Only generated for public profiles with sufficient completeness (≥60%).
|
|
2517
2610
|
*/
|
|
2518
|
-
embedding:
|
|
2519
|
-
vector: array14(
|
|
2520
|
-
model:
|
|
2611
|
+
embedding: object34({
|
|
2612
|
+
vector: array14(number11().required()).optional().label("Embedding vector"),
|
|
2613
|
+
model: string32().optional().label("Embedding model")
|
|
2521
2614
|
}).nullable().optional().label("Embedding")
|
|
2522
2615
|
}).concat(UserGeneralDetailSchema).concat(UserJobPreferencesSchema).concat(UserRecruiterProfileSchema).concat(UserCoordinatorProfileSchema).noUnknown().strict().label("User Schema");
|
|
2523
2616
|
|
|
2524
2617
|
// src/user/user-completeness.schema.ts
|
|
2525
|
-
import { object as
|
|
2526
|
-
var UserCompletenessSchema =
|
|
2618
|
+
import { object as object35 } from "yup";
|
|
2619
|
+
var UserCompletenessSchema = object35({
|
|
2527
2620
|
additionalInfo: CompletenessScoreSchema(0).label("Additional Info"),
|
|
2528
2621
|
// Optional
|
|
2529
2622
|
certifications: CompletenessScoreSchema(0).label("Certifications"),
|
|
@@ -2595,6 +2688,7 @@ export {
|
|
|
2595
2688
|
MIN_SALARY_LOWER_BOUND,
|
|
2596
2689
|
MIN_SALARY_UPPER_BOUND,
|
|
2597
2690
|
MailingListSchema,
|
|
2691
|
+
NotificationChannel,
|
|
2598
2692
|
PREFILL_MIRRORED_KEYS,
|
|
2599
2693
|
PRIVATE_PROFILE_FIELDS,
|
|
2600
2694
|
PageSchema,
|
|
@@ -2614,6 +2708,8 @@ export {
|
|
|
2614
2708
|
ResourceType,
|
|
2615
2709
|
SITEMAP_FORMAT,
|
|
2616
2710
|
SYSTEM_DATE_FORMAT,
|
|
2711
|
+
SavedSearchSchema,
|
|
2712
|
+
SavedSearchStatus,
|
|
2617
2713
|
SkillSchema,
|
|
2618
2714
|
SocialAccount,
|
|
2619
2715
|
SocialAccountSchema,
|
|
@@ -2636,6 +2732,7 @@ export {
|
|
|
2636
2732
|
SupportedJobSearchUrgencies,
|
|
2637
2733
|
SupportedJobStatuses,
|
|
2638
2734
|
SupportedJobSubCategories,
|
|
2735
|
+
SupportedNotificationChannels,
|
|
2639
2736
|
SupportedPageStatuses,
|
|
2640
2737
|
SupportedPageTypes,
|
|
2641
2738
|
SupportedPostStatuses,
|
|
@@ -2645,6 +2742,7 @@ export {
|
|
|
2645
2742
|
SupportedReportReasons,
|
|
2646
2743
|
SupportedResourceTypes,
|
|
2647
2744
|
SupportedSalaryCurrencies,
|
|
2745
|
+
SupportedSavedSearchStatuses,
|
|
2648
2746
|
SupportedSocialAccounts,
|
|
2649
2747
|
SupportedStudyTypes,
|
|
2650
2748
|
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);
|