@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/dist/index.cjs CHANGED
@@ -80,6 +80,7 @@ __export(index_exports, {
80
80
  MIN_SALARY_LOWER_BOUND: () => MIN_SALARY_LOWER_BOUND,
81
81
  MIN_SALARY_UPPER_BOUND: () => MIN_SALARY_UPPER_BOUND,
82
82
  MailingListSchema: () => MailingListSchema,
83
+ NotificationChannel: () => NotificationChannel,
83
84
  PREFILL_MIRRORED_KEYS: () => PREFILL_MIRRORED_KEYS,
84
85
  PRIVATE_PROFILE_FIELDS: () => PRIVATE_PROFILE_FIELDS,
85
86
  PageSchema: () => PageSchema,
@@ -99,6 +100,8 @@ __export(index_exports, {
99
100
  ResourceType: () => ResourceType,
100
101
  SITEMAP_FORMAT: () => SITEMAP_FORMAT,
101
102
  SYSTEM_DATE_FORMAT: () => SYSTEM_DATE_FORMAT,
103
+ SavedSearchSchema: () => SavedSearchSchema,
104
+ SavedSearchStatus: () => SavedSearchStatus,
102
105
  SkillSchema: () => SkillSchema,
103
106
  SocialAccount: () => SocialAccount,
104
107
  SocialAccountSchema: () => SocialAccountSchema,
@@ -121,6 +124,7 @@ __export(index_exports, {
121
124
  SupportedJobSearchUrgencies: () => SupportedJobSearchUrgencies,
122
125
  SupportedJobStatuses: () => SupportedJobStatuses,
123
126
  SupportedJobSubCategories: () => SupportedJobSubCategories,
127
+ SupportedNotificationChannels: () => SupportedNotificationChannels,
124
128
  SupportedPageStatuses: () => SupportedPageStatuses,
125
129
  SupportedPageTypes: () => SupportedPageTypes,
126
130
  SupportedPostStatuses: () => SupportedPostStatuses,
@@ -130,6 +134,7 @@ __export(index_exports, {
130
134
  SupportedReportReasons: () => SupportedReportReasons,
131
135
  SupportedResourceTypes: () => SupportedResourceTypes,
132
136
  SupportedSalaryCurrencies: () => SupportedSalaryCurrencies,
137
+ SupportedSavedSearchStatuses: () => SupportedSavedSearchStatuses,
133
138
  SupportedSocialAccounts: () => SupportedSocialAccounts,
134
139
  SupportedStudyTypes: () => SupportedStudyTypes,
135
140
  SupportedUserProfileVisibilities: () => SupportedUserProfileVisibilities,
@@ -2155,6 +2160,14 @@ var JobAlertFrequency = /* @__PURE__ */ ((JobAlertFrequency2) => {
2155
2160
  return JobAlertFrequency2;
2156
2161
  })(JobAlertFrequency || {});
2157
2162
  var SupportedJobAlertFrequencies = Object.values(JobAlertFrequency);
2163
+ var NotificationChannel = /* @__PURE__ */ ((NotificationChannel2) => {
2164
+ NotificationChannel2["GroupActivity"] = "groupActivity";
2165
+ NotificationChannel2["JobActivity"] = "jobActivity";
2166
+ NotificationChannel2["ApplicationUpdates"] = "applicationUpdates";
2167
+ NotificationChannel2["ProductUpdates"] = "productUpdates";
2168
+ return NotificationChannel2;
2169
+ })(NotificationChannel || {});
2170
+ var SupportedNotificationChannels = Object.values(NotificationChannel);
2158
2171
  var SupportedSalaryCurrencies = ["USD", "EUR", "GBP", "SEK", "INR"];
2159
2172
  var MIN_SALARY_LOWER_BOUND = 0;
2160
2173
  var MIN_SALARY_UPPER_BOUND = 1e6;
@@ -2289,9 +2302,70 @@ var DefaultPaginationOptions = {
2289
2302
  limit: 10
2290
2303
  };
2291
2304
 
2292
- // src/report/report.schema.ts
2305
+ // src/saved-search/saved-search.schema.ts
2293
2306
  var import_yup22 = require("yup");
2294
2307
 
2308
+ // src/saved-search/saved-search.constant.ts
2309
+ var SavedSearchStatus = /* @__PURE__ */ ((SavedSearchStatus2) => {
2310
+ SavedSearchStatus2["Active"] = "active";
2311
+ SavedSearchStatus2["Paused"] = "paused";
2312
+ return SavedSearchStatus2;
2313
+ })(SavedSearchStatus || {});
2314
+ var SupportedSavedSearchStatuses = Object.values(SavedSearchStatus);
2315
+
2316
+ // src/saved-search/saved-search.schema.ts
2317
+ var SavedSearchSchema = (0, import_yup22.object)({
2318
+ /** Public identifier. Server-assigned. */
2319
+ shortId: (0, import_yup22.string)().trim().label("Short Id"),
2320
+ /**
2321
+ * Owner's Better Auth account id. Server-assigned from the verified token,
2322
+ * never accepted from a request body.
2323
+ */
2324
+ ownerUserId: (0, import_yup22.string)().trim().label("Owner"),
2325
+ /** What the user calls this search, e.g. "Remote React roles". */
2326
+ label: (0, import_yup22.string)().trim().max(120).required().label("Label"),
2327
+ /**
2328
+ * The free-text query. Optional because a search can be filters-only ("all
2329
+ * remote jobs in Sweden"), which is a legitimate alert to want.
2330
+ */
2331
+ search: (0, import_yup22.string)().trim().max(500).optional().label("Search Text"),
2332
+ /**
2333
+ * Field filters, in the same `{ field: values }` shape the search endpoint
2334
+ * parses from `filter[field]=a,b`. Held as a free-form object rather than a
2335
+ * closed schema because the job facets it addresses live in jobs-service and
2336
+ * change independently; validating them here would put this package in the
2337
+ * business of tracking that vocabulary.
2338
+ */
2339
+ filter: (0, import_yup22.object)().optional().default({}).label("Filters"),
2340
+ /**
2341
+ * How often to mail matches. `off` keeps the search saved but silent, which is
2342
+ * the difference between "I don't want mail" and "delete my search".
2343
+ *
2344
+ * Reuses the cadence enum from `marketingConsent.jobAlertFrequency` rather
2345
+ * than defining a second one: two vocabularies for the same concept is how
2346
+ * they drift.
2347
+ */
2348
+ frequency: (0, import_yup22.string)().oneOf(SupportedJobAlertFrequencies).default("off" /* Off */).label("Alert Frequency"),
2349
+ status: (0, import_yup22.string)().oneOf(SupportedSavedSearchStatuses).default("active" /* Active */).label("Status"),
2350
+ /**
2351
+ * Epoch ms of the last alert sent for this search. The matching sweep reads it
2352
+ * to decide whether the cadence is due, and writes it only AFTER a successful
2353
+ * publish, so a failed run retries next tick rather than silently skipping a
2354
+ * period.
2355
+ */
2356
+ lastNotifiedAt: (0, import_yup22.number)().optional().label("Last Notified At"),
2357
+ /**
2358
+ * Epoch ms high-water mark: only jobs created after this are "new" for the
2359
+ * next alert. Kept separate from `lastNotifiedAt` because a run that finds no
2360
+ * matches should still advance what counts as new, without implying mail was
2361
+ * sent.
2362
+ */
2363
+ lastMatchedAt: (0, import_yup22.number)().optional().label("Last Matched At")
2364
+ }).noUnknown().strict();
2365
+
2366
+ // src/report/report.schema.ts
2367
+ var import_yup23 = require("yup");
2368
+
2295
2369
  // src/report/report.constant.ts
2296
2370
  var ResourceType = /* @__PURE__ */ ((ResourceType3) => {
2297
2371
  ResourceType3["Job"] = "job";
@@ -2314,15 +2388,15 @@ var ReportReason = /* @__PURE__ */ ((ReportReason3) => {
2314
2388
  var SupportedReportReasons = Object.values(ReportReason);
2315
2389
 
2316
2390
  // src/report/report.schema.ts
2317
- var ReportSchema = (0, import_yup22.object)({
2318
- type: (0, import_yup22.mixed)().oneOf(SupportedResourceTypes).required().label("Type"),
2319
- resourceId: (0, import_yup22.string)().required().label("Resource ID"),
2320
- reason: (0, import_yup22.mixed)().oneOf(SupportedReportReasons).required("Please choose a reason").label("Reason"),
2321
- comment: (0, import_yup22.string)().max(1e3).optional().label("Comment")
2391
+ var ReportSchema = (0, import_yup23.object)({
2392
+ type: (0, import_yup23.mixed)().oneOf(SupportedResourceTypes).required().label("Type"),
2393
+ resourceId: (0, import_yup23.string)().required().label("Resource ID"),
2394
+ reason: (0, import_yup23.mixed)().oneOf(SupportedReportReasons).required("Please choose a reason").label("Reason"),
2395
+ comment: (0, import_yup23.string)().max(1e3).optional().label("Comment")
2322
2396
  }).label("Report Schema");
2323
2397
 
2324
2398
  // src/feedback/feedback.schema.ts
2325
- var import_yup23 = require("yup");
2399
+ var import_yup24 = require("yup");
2326
2400
 
2327
2401
  // src/feedback/feedback.constant.ts
2328
2402
  var FeedbackType = /* @__PURE__ */ ((FeedbackType3) => {
@@ -2345,63 +2419,63 @@ var SupportedFeedbackStatuses = Object.values(FeedbackStatus);
2345
2419
  var FEEDBACK_MESSAGE_MAX = 4e3;
2346
2420
 
2347
2421
  // src/feedback/feedback.schema.ts
2348
- var FeedbackSchema = (0, import_yup23.object)({
2349
- type: (0, import_yup23.mixed)().oneOf(SupportedFeedbackTypes).required().label("Type"),
2350
- message: (0, import_yup23.string)().trim().required("Please enter a message").max(FEEDBACK_MESSAGE_MAX).label("Message"),
2351
- email: (0, import_yup23.string)().email().optional().label("Email"),
2352
- pageUrl: (0, import_yup23.string)().optional().label("Page URL"),
2353
- status: (0, import_yup23.mixed)().oneOf(SupportedFeedbackStatuses).optional().label("Status")
2422
+ var FeedbackSchema = (0, import_yup24.object)({
2423
+ type: (0, import_yup24.mixed)().oneOf(SupportedFeedbackTypes).required().label("Type"),
2424
+ message: (0, import_yup24.string)().trim().required("Please enter a message").max(FEEDBACK_MESSAGE_MAX).label("Message"),
2425
+ email: (0, import_yup24.string)().email().optional().label("Email"),
2426
+ pageUrl: (0, import_yup24.string)().optional().label("Page URL"),
2427
+ status: (0, import_yup24.mixed)().oneOf(SupportedFeedbackStatuses).optional().label("Status")
2354
2428
  }).label("Feedback Schema");
2355
2429
 
2356
2430
  // src/user/user.schema.ts
2357
- var import_yup36 = require("yup");
2431
+ var import_yup37 = require("yup");
2358
2432
 
2359
2433
  // src/user/work-experience.schema.ts
2360
- var import_yup24 = require("yup");
2361
- var WorkExperienceSchema = (0, import_yup24.object)().shape({
2434
+ var import_yup25 = require("yup");
2435
+ var WorkExperienceSchema = (0, import_yup25.object)().shape({
2362
2436
  company: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Company"),
2363
- designation: (0, import_yup24.string)().trim().required().label("Designation"),
2437
+ designation: (0, import_yup25.string)().trim().required().label("Designation"),
2364
2438
  duration: DurationSchema({
2365
2439
  format: "YYYY-MM",
2366
2440
  startLabel: "Start Date",
2367
2441
  endLabel: "End Date"
2368
2442
  }).required().label("Duration"),
2369
- description: (0, import_yup24.string)().trim().max(3e3).optional().label("Description"),
2443
+ description: (0, import_yup25.string)().trim().max(3e3).optional().label("Description"),
2370
2444
  location: LocationSchema.required().label("Location"),
2371
- isRemote: (0, import_yup24.boolean)().oneOf([true, false]).default(false).label("Is Remote")
2445
+ isRemote: (0, import_yup25.boolean)().oneOf([true, false]).default(false).label("Is Remote")
2372
2446
  }).noUnknown().strict().label("Work Experience");
2373
2447
 
2374
2448
  // src/user/education.schema.ts
2375
- var import_yup25 = require("yup");
2376
- var EducationSchema = (0, import_yup25.object)({
2449
+ var import_yup26 = require("yup");
2450
+ var EducationSchema = (0, import_yup26.object)({
2377
2451
  institute: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Institute"),
2378
- course: (0, import_yup25.string)().trim().required().label("Course"),
2379
- fieldOfStudy: (0, import_yup25.string)().trim().required().label("Field of Study"),
2452
+ course: (0, import_yup26.string)().trim().required().label("Course"),
2453
+ fieldOfStudy: (0, import_yup26.string)().trim().required().label("Field of Study"),
2380
2454
  duration: DurationSchema({
2381
2455
  format: "YYYY-MM",
2382
2456
  startLabel: "Start Date",
2383
2457
  endLabel: "End Date"
2384
2458
  }).required().label("Duration"),
2385
- description: (0, import_yup25.string)().trim().max(3e3).optional().label("Description"),
2386
- isDistanceLearning: (0, import_yup25.boolean)().default(false).label("Is Distance Learning"),
2459
+ description: (0, import_yup26.string)().trim().max(3e3).optional().label("Description"),
2460
+ isDistanceLearning: (0, import_yup26.boolean)().default(false).label("Is Distance Learning"),
2387
2461
  location: LocationSchema.required().label("Location"),
2388
- studyType: (0, import_yup25.string)().oneOf(SupportedStudyTypes).trim().max(50).required().label("Study Type")
2462
+ studyType: (0, import_yup26.string)().oneOf(SupportedStudyTypes).trim().max(50).required().label("Study Type")
2389
2463
  }).noUnknown().strict().label("Education");
2390
2464
 
2391
2465
  // src/user/user-skill.schema.ts
2392
- var import_yup26 = require("yup");
2393
- var UserSkillSchema = (0, import_yup26.object)({
2394
- name: (0, import_yup26.string)().required().label("Name"),
2395
- proficiencyLevel: (0, import_yup26.string)().oneOf(SupportedProficiencyLevels).required().label("Proficiency Level"),
2466
+ var import_yup27 = require("yup");
2467
+ var UserSkillSchema = (0, import_yup27.object)({
2468
+ name: (0, import_yup27.string)().required().label("Name"),
2469
+ proficiencyLevel: (0, import_yup27.string)().oneOf(SupportedProficiencyLevels).required().label("Proficiency Level"),
2396
2470
  lastUsed: dateString().format("YYYY-MM").nullable().optional().label("Last Used")
2397
2471
  }).noUnknown().strict().label("Skill");
2398
2472
 
2399
2473
  // src/user/project.schema.ts
2400
- var import_yup27 = require("yup");
2401
- var UserProjectSchema = (0, import_yup27.object)({
2402
- name: (0, import_yup27.string)().trim().max(50).required().label("Name"),
2403
- url: (0, import_yup27.string)().optional().label("URL"),
2404
- description: (0, import_yup27.string)().trim().min(100).max(3e3).required().label("Description"),
2474
+ var import_yup28 = require("yup");
2475
+ var UserProjectSchema = (0, import_yup28.object)({
2476
+ name: (0, import_yup28.string)().trim().max(50).required().label("Name"),
2477
+ url: (0, import_yup28.string)().optional().label("URL"),
2478
+ description: (0, import_yup28.string)().trim().min(100).max(3e3).required().label("Description"),
2405
2479
  duration: DurationSchema({
2406
2480
  format: "YYYY-MM",
2407
2481
  startLabel: "Start Date",
@@ -2410,83 +2484,83 @@ var UserProjectSchema = (0, import_yup27.object)({
2410
2484
  }).noUnknown().strict().label("Project");
2411
2485
 
2412
2486
  // src/user/user-certification.schema.ts
2413
- var import_yup28 = require("yup");
2414
- var UserCertificationSchema = (0, import_yup28.object)({
2415
- name: (0, import_yup28.string)().trim().max(100).required().label("Name"),
2487
+ var import_yup29 = require("yup");
2488
+ var UserCertificationSchema = (0, import_yup29.object)({
2489
+ name: (0, import_yup29.string)().trim().max(100).required().label("Name"),
2416
2490
  // TODO: Add validation for authority
2417
- authority: (0, import_yup28.string)().trim().max(100).required().label("Authority"),
2418
- licenseNumber: (0, import_yup28.string)().trim().max(50).optional().label("License Number"),
2491
+ authority: (0, import_yup29.string)().trim().max(100).required().label("Authority"),
2492
+ licenseNumber: (0, import_yup29.string)().trim().max(50).optional().label("License Number"),
2419
2493
  duration: DurationSchema({
2420
2494
  format: "YYYY-MM",
2421
2495
  startLabel: "Start Date",
2422
2496
  endLabel: "End Date"
2423
2497
  }).optional().nullable().label("Duration"),
2424
- url: (0, import_yup28.string)().optional().label("URL")
2498
+ url: (0, import_yup29.string)().optional().label("URL")
2425
2499
  }).noUnknown().strict().label("Certification");
2426
2500
 
2427
2501
  // src/user/user-interest.schema.ts
2428
- var import_yup29 = require("yup");
2429
- var UserInterestSchema = (0, import_yup29.string)().trim().required().label("Interest");
2502
+ var import_yup30 = require("yup");
2503
+ var UserInterestSchema = (0, import_yup30.string)().trim().required().label("Interest");
2430
2504
 
2431
2505
  // src/user/user-language.schema.ts
2432
- var import_yup30 = require("yup");
2433
- var UserLanguageSchema = (0, import_yup30.object)({
2434
- name: (0, import_yup30.string)().trim().required().label("Name"),
2435
- proficiencyLevel: (0, import_yup30.string)().oneOf(SupportedProficiencyLevels).trim().max(50).required().label("Proficiency Level")
2506
+ var import_yup31 = require("yup");
2507
+ var UserLanguageSchema = (0, import_yup31.object)({
2508
+ name: (0, import_yup31.string)().trim().required().label("Name"),
2509
+ proficiencyLevel: (0, import_yup31.string)().oneOf(SupportedProficiencyLevels).trim().max(50).required().label("Proficiency Level")
2436
2510
  }).noUnknown().strict().label("Language");
2437
2511
 
2438
2512
  // src/user/user-additional-info.schema.ts
2439
- var import_yup31 = require("yup");
2440
- var UserAdditionalInfoSchema = (0, import_yup31.object)({
2441
- title: (0, import_yup31.string)().trim().max(60).required().label("Title"),
2442
- description: (0, import_yup31.string)().trim().max(1e3).required().label("Description")
2513
+ var import_yup32 = require("yup");
2514
+ var UserAdditionalInfoSchema = (0, import_yup32.object)({
2515
+ title: (0, import_yup32.string)().trim().max(60).required().label("Title"),
2516
+ description: (0, import_yup32.string)().trim().max(1e3).required().label("Description")
2443
2517
  }).noUnknown().strict().label("User Additional Info");
2444
2518
 
2445
2519
  // src/user/general-detail.schema.ts
2446
- var import_yup32 = require("yup");
2447
- var UserGeneralDetailSchema = (0, import_yup32.object)({
2448
- id: (0, import_yup32.string)().optional().label("ID"),
2449
- name: (0, import_yup32.object)().shape({
2450
- first: (0, import_yup32.string)().trim().max(50).required().label("First Name"),
2451
- last: (0, import_yup32.string)().trim().max(50).optional().label("Last Name")
2520
+ var import_yup33 = require("yup");
2521
+ var UserGeneralDetailSchema = (0, import_yup33.object)({
2522
+ id: (0, import_yup33.string)().optional().label("ID"),
2523
+ name: (0, import_yup33.object)().shape({
2524
+ first: (0, import_yup33.string)().trim().max(50).required().label("First Name"),
2525
+ last: (0, import_yup33.string)().trim().max(50).optional().label("Last Name")
2452
2526
  }).required().label("Name"),
2453
- headline: (0, import_yup32.string)().trim().max(200).optional().label("Headline"),
2454
- image: (0, import_yup32.string)().optional().label("Image"),
2455
- aboutMe: (0, import_yup32.string)().trim().max(3e3).optional().label("About Me"),
2456
- email: (0, import_yup32.string)().required().label("Email"),
2457
- mobile: (0, import_yup32.string)().nullable().optional().label("Mobile"),
2458
- emailVerified: (0, import_yup32.string)().nullable().optional().label("Email Verified"),
2459
- mobileVerified: (0, import_yup32.string)().nullable().optional().label("Mobile Verified"),
2460
- experienceLevel: (0, import_yup32.string)().oneOf(SupportedExperienceLevels).required().label("Experience level"),
2527
+ headline: (0, import_yup33.string)().trim().max(200).optional().label("Headline"),
2528
+ image: (0, import_yup33.string)().optional().label("Image"),
2529
+ aboutMe: (0, import_yup33.string)().trim().max(3e3).optional().label("About Me"),
2530
+ email: (0, import_yup33.string)().required().label("Email"),
2531
+ mobile: (0, import_yup33.string)().nullable().optional().label("Mobile"),
2532
+ emailVerified: (0, import_yup33.string)().nullable().optional().label("Email Verified"),
2533
+ mobileVerified: (0, import_yup33.string)().nullable().optional().label("Mobile Verified"),
2534
+ experienceLevel: (0, import_yup33.string)().oneOf(SupportedExperienceLevels).required().label("Experience level"),
2461
2535
  location: LocationSchema.required().label("Location"),
2462
- region: (0, import_yup32.object)().shape({
2463
- country: (0, import_yup32.string)().trim().required().label("Region Country"),
2464
- lang: (0, import_yup32.string)().trim().required().label("Region Language")
2536
+ region: (0, import_yup33.object)().shape({
2537
+ country: (0, import_yup33.string)().trim().required().label("Region Country"),
2538
+ lang: (0, import_yup33.string)().trim().required().label("Region Language")
2465
2539
  }).optional().default(void 0).label("Region"),
2466
- profileVisibility: (0, import_yup32.string)().oneOf(SupportedUserProfileVisibilities).default("public" /* Public */).label("Profile Visibility")
2540
+ profileVisibility: (0, import_yup33.string)().oneOf(SupportedUserProfileVisibilities).default("public" /* Public */).label("Profile Visibility")
2467
2541
  }).noUnknown().strict().label("General Detail");
2468
2542
 
2469
2543
  // src/user/user-job-preferences.schema.ts
2470
- var import_yup33 = require("yup");
2471
- var UserJobPreferencesSchema = (0, import_yup33.object)({
2544
+ var import_yup34 = require("yup");
2545
+ var UserJobPreferencesSchema = (0, import_yup34.object)({
2472
2546
  /**
2473
2547
  * Whether the job seeker is openly signalling availability. Surfaces the
2474
2548
  * "Open to work" badge on the public profile and boosts visibility in
2475
2549
  * recruiter search. Defaults to `false` - users must opt in.
2476
2550
  */
2477
- openToWork: (0, import_yup33.boolean)().default(false).label("Open to Work"),
2551
+ openToWork: (0, import_yup34.boolean)().default(false).label("Open to Work"),
2478
2552
  /**
2479
2553
  * How urgently the user is looking for their next job. Drives match scoring
2480
2554
  * and can downgrade the visibility of expired or low-relevance postings for
2481
2555
  * users in `passively_browsing` mode.
2482
2556
  */
2483
- jobSearchUrgency: (0, import_yup33.string)().oneOf(SupportedJobSearchUrgencies).required().label("Job Search Urgency"),
2557
+ jobSearchUrgency: (0, import_yup34.string)().oneOf(SupportedJobSearchUrgencies).required().label("Job Search Urgency"),
2484
2558
  /**
2485
2559
  * Locations the user wants to work in. Stores the full `LocationSchema`
2486
2560
  * shape (country, city, state, geo, etc.) as returned by the locations
2487
2561
  * autocomplete API.
2488
2562
  */
2489
- jobLocations: (0, import_yup33.array)().of(LocationSchema.required().label("Job Location")).min(1, "Pick at least one preferred location.").required().label("Job Locations"),
2563
+ jobLocations: (0, import_yup34.array)().of(LocationSchema.required().label("Job Location")).min(1, "Pick at least one preferred location.").required().label("Job Locations"),
2490
2564
  /**
2491
2565
  * Seniority levels the user wants jobs to be matched against. Multi-select
2492
2566
  * (up to 2) for borderline candidates.
@@ -2497,7 +2571,7 @@ var UserJobPreferencesSchema = (0, import_yup33.object)({
2497
2571
  * Both reuse the same `ExperienceLevel` taxonomy from `common.constant.ts`
2498
2572
  * so search/match logic doesn't have to translate between two vocabularies.
2499
2573
  */
2500
- targetExperienceLevels: (0, import_yup33.array)().of((0, import_yup33.string)().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"),
2574
+ targetExperienceLevels: (0, import_yup34.array)().of((0, import_yup34.string)().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"),
2501
2575
  /**
2502
2576
  * Specializations the user is searching for - free-form titles.
2503
2577
  *
@@ -2506,19 +2580,19 @@ var UserJobPreferencesSchema = (0, import_yup33.object)({
2506
2580
  * surfaces a curated "Popular Roles" picker for discovery, but the user
2507
2581
  * can ultimately add any title; matching/normalization happens downstream.
2508
2582
  */
2509
- jobRoles: (0, import_yup33.array)().of((0, import_yup33.string)().trim().max(120).required()).min(1, "Pick at least one role.").required().label("Job Roles"),
2583
+ jobRoles: (0, import_yup34.array)().of((0, import_yup34.string)().trim().max(120).required()).min(1, "Pick at least one role.").required().label("Job Roles"),
2510
2584
  /**
2511
2585
  * Minimum acceptable annual base salary, in `minSalaryCurrency`.
2512
2586
  * Stored as an integer in the currency's major unit (e.g. dollars, not cents).
2513
2587
  * Defaults to 0 ("any salary") rather than being optional - every job-seeker
2514
2588
  * has a floor, even if it's zero.
2515
2589
  */
2516
- minSalary: (0, import_yup33.number)().integer().min(MIN_SALARY_LOWER_BOUND).max(MIN_SALARY_UPPER_BOUND).default(0).required().label("Minimum Salary"),
2517
- minSalaryCurrency: (0, import_yup33.string)().oneOf(SupportedSalaryCurrencies).default("USD").required().label("Minimum Salary Currency"),
2590
+ minSalary: (0, import_yup34.number)().integer().min(MIN_SALARY_LOWER_BOUND).max(MIN_SALARY_UPPER_BOUND).default(0).required().label("Minimum Salary"),
2591
+ minSalaryCurrency: (0, import_yup34.string)().oneOf(SupportedSalaryCurrencies).default("USD").required().label("Minimum Salary Currency"),
2518
2592
  /**
2519
2593
  * Marketing-attribution capture from the final onboarding step.
2520
2594
  */
2521
- referralSource: (0, import_yup33.string)().oneOf(SupportedReferralSources).required().label("Referral Source"),
2595
+ referralSource: (0, import_yup34.string)().oneOf(SupportedReferralSources).required().label("Referral Source"),
2522
2596
  /**
2523
2597
  * Resumes the user has uploaded. Embedded directly on the user document
2524
2598
  * (capped at 5) - they're cheap to denormalize, every wizard step that
@@ -2532,25 +2606,25 @@ var UserJobPreferencesSchema = (0, import_yup33.object)({
2532
2606
  * AI resume-builder flow - onboarding uploads land here, AI-built resumes
2533
2607
  * live in their own collection.
2534
2608
  */
2535
- resumes: (0, import_yup33.array)().of(
2536
- (0, import_yup33.object)({
2609
+ resumes: (0, import_yup34.array)().of(
2610
+ (0, import_yup34.object)({
2537
2611
  // Stable id assigned on upload - used to address a specific entry
2538
2612
  // for delete / set-primary operations without exposing the GCS URL
2539
2613
  // as a route key.
2540
- id: (0, import_yup33.string)().required().label("ID"),
2541
- url: (0, import_yup33.string)().required().label("Resume URL"),
2542
- filename: (0, import_yup33.string)().trim().max(255).optional().label("Filename"),
2543
- sizeBytes: (0, import_yup33.number)().integer().min(0).optional().label("Size (bytes)"),
2544
- mimeType: (0, import_yup33.string)().trim().max(120).optional().label("MIME Type"),
2545
- uploadedAt: (0, import_yup33.date)().required().label("Uploaded At"),
2546
- isPrimary: (0, import_yup33.boolean)().default(false).label("Is Primary")
2614
+ id: (0, import_yup34.string)().required().label("ID"),
2615
+ url: (0, import_yup34.string)().required().label("Resume URL"),
2616
+ filename: (0, import_yup34.string)().trim().max(255).optional().label("Filename"),
2617
+ sizeBytes: (0, import_yup34.number)().integer().min(0).optional().label("Size (bytes)"),
2618
+ mimeType: (0, import_yup34.string)().trim().max(120).optional().label("MIME Type"),
2619
+ uploadedAt: (0, import_yup34.date)().required().label("Uploaded At"),
2620
+ isPrimary: (0, import_yup34.boolean)().default(false).label("Is Primary")
2547
2621
  }).noUnknown().strict().label("Resume")
2548
2622
  ).max(5, "You can keep at most 5 resumes on file.").default([]).label("Resumes"),
2549
2623
  /**
2550
2624
  * Set when the user finishes the wizard's last step. Acts as the gate the
2551
2625
  * onboarding hook checks to redirect users who haven't completed setup.
2552
2626
  */
2553
- onboardingCompletedAt: (0, import_yup33.date)().nullable().optional().label("Onboarding Completed At"),
2627
+ onboardingCompletedAt: (0, import_yup34.date)().nullable().optional().label("Onboarding Completed At"),
2554
2628
  /**
2555
2629
  * Parser-suggested values for wizard fields, written by the resume-upload
2556
2630
  * flow. Every parser-derived field lands here - including profile-shaped
@@ -2570,92 +2644,92 @@ var UserJobPreferencesSchema = (0, import_yup33.object)({
2570
2644
  * APIs. If `user.<field>` is empty there, the correct behavior is empty,
2571
2645
  * because the user has not confirmed it yet.
2572
2646
  */
2573
- pendingPrefill: (0, import_yup33.object)({
2574
- headline: (0, import_yup33.string)().trim().optional().label("Pending Headline"),
2575
- aboutMe: (0, import_yup33.string)().trim().optional().label("Pending About Me"),
2576
- mobile: (0, import_yup33.string)().trim().optional().label("Pending Mobile"),
2647
+ pendingPrefill: (0, import_yup34.object)({
2648
+ headline: (0, import_yup34.string)().trim().optional().label("Pending Headline"),
2649
+ aboutMe: (0, import_yup34.string)().trim().optional().label("Pending About Me"),
2650
+ mobile: (0, import_yup34.string)().trim().optional().label("Pending Mobile"),
2577
2651
  location: LocationSchema.optional().default(void 0).label("Pending Location"),
2578
- experienceLevel: (0, import_yup33.string)().oneOf(SupportedExperienceLevels).optional().label("Pending Experience Level"),
2579
- socialAccounts: (0, import_yup33.array)().of(SocialAccountSchema.required()).optional().label("Pending Social Accounts"),
2580
- workExperiences: (0, import_yup33.array)().of(WorkExperienceSchema.required()).optional().label("Pending Work Experiences"),
2581
- educations: (0, import_yup33.array)().of(EducationSchema.required()).optional().label("Pending Educations")
2652
+ experienceLevel: (0, import_yup34.string)().oneOf(SupportedExperienceLevels).optional().label("Pending Experience Level"),
2653
+ socialAccounts: (0, import_yup34.array)().of(SocialAccountSchema.required()).optional().label("Pending Social Accounts"),
2654
+ workExperiences: (0, import_yup34.array)().of(WorkExperienceSchema.required()).optional().label("Pending Work Experiences"),
2655
+ educations: (0, import_yup34.array)().of(EducationSchema.required()).optional().label("Pending Educations")
2582
2656
  }).nullable().optional().default(void 0).label("Pending Prefill")
2583
2657
  }).noUnknown().strict().label("User Job Preferences Schema");
2584
2658
 
2585
2659
  // src/user/user-recruiter-profile.schema.ts
2586
- var import_yup34 = require("yup");
2587
- var RecruiterPageLinkSchema = (0, import_yup34.object)({
2660
+ var import_yup35 = require("yup");
2661
+ var RecruiterPageLinkSchema = (0, import_yup35.object)({
2588
2662
  page: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Company Page"),
2589
- jobTitle: (0, import_yup34.string)().trim().max(100).optional().label("Job Title")
2663
+ jobTitle: (0, import_yup35.string)().trim().max(100).optional().label("Job Title")
2590
2664
  }).noUnknown().strict().label("Recruiter Page Link");
2591
- var UserRecruiterProfileSchema = (0, import_yup34.object)({
2592
- recruiterProfile: (0, import_yup34.object)({
2593
- hiringFor: (0, import_yup34.array)().of(RecruiterPageLinkSchema).default([]).label("Hiring For")
2665
+ var UserRecruiterProfileSchema = (0, import_yup35.object)({
2666
+ recruiterProfile: (0, import_yup35.object)({
2667
+ hiringFor: (0, import_yup35.array)().of(RecruiterPageLinkSchema).default([]).label("Hiring For")
2594
2668
  }).optional().default(void 0).label("Recruiter Profile")
2595
2669
  }).noUnknown().strict().label("User Recruiter Profile");
2596
2670
 
2597
2671
  // src/user/user-coordinator-profile.schema.ts
2598
- var import_yup35 = require("yup");
2599
- var CoordinatorPageLinkSchema = (0, import_yup35.object)({
2672
+ var import_yup36 = require("yup");
2673
+ var CoordinatorPageLinkSchema = (0, import_yup36.object)({
2600
2674
  page: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Institute Page"),
2601
- jobTitle: (0, import_yup35.string)().trim().max(100).optional().label("Job Title")
2675
+ jobTitle: (0, import_yup36.string)().trim().max(100).optional().label("Job Title")
2602
2676
  }).noUnknown().strict().label("Coordinator Page Link");
2603
- var UserCoordinatorProfileSchema = (0, import_yup35.object)({
2604
- coordinatorProfile: (0, import_yup35.object)({
2605
- coordinatesAt: (0, import_yup35.array)().of(CoordinatorPageLinkSchema).default([]).label("Coordinates At")
2677
+ var UserCoordinatorProfileSchema = (0, import_yup36.object)({
2678
+ coordinatorProfile: (0, import_yup36.object)({
2679
+ coordinatesAt: (0, import_yup36.array)().of(CoordinatorPageLinkSchema).default([]).label("Coordinates At")
2606
2680
  }).optional().default(void 0).label("Coordinator Profile")
2607
2681
  }).noUnknown().strict().label("User Coordinator Profile");
2608
2682
 
2609
2683
  // src/user/user.schema.ts
2610
- var UserSchema = (0, import_yup36.object)({
2684
+ var UserSchema = (0, import_yup37.object)({
2611
2685
  /**
2612
2686
  * Related auth account id from auth Server (e.g. Better auth https://auth.thejob.dev)
2613
2687
  */
2614
- authAccountId: (0, import_yup36.string)().required().label("Auth Account ID"),
2688
+ authAccountId: (0, import_yup37.string)().required().label("Auth Account ID"),
2615
2689
  /**
2616
2690
  * Social media information about the user (e.g. LinkedIn, GitHub, etc.)
2617
2691
  */
2618
- socialAccounts: (0, import_yup36.array)().of(SocialAccountSchema).default([]).label("Social Accounts"),
2692
+ socialAccounts: (0, import_yup37.array)().of(SocialAccountSchema).default([]).label("Social Accounts"),
2619
2693
  /**
2620
2694
  * Work experience information about the user
2621
2695
  */
2622
- workExperiences: (0, import_yup36.array)().of(WorkExperienceSchema).required().default([]).label("Work Experiences"),
2696
+ workExperiences: (0, import_yup37.array)().of(WorkExperienceSchema).required().default([]).label("Work Experiences"),
2623
2697
  /**
2624
2698
  * Education information about the user
2625
2699
  */
2626
- educations: (0, import_yup36.array)().of(EducationSchema).required().default([]).label("Educations"),
2700
+ educations: (0, import_yup37.array)().of(EducationSchema).required().default([]).label("Educations"),
2627
2701
  /**
2628
2702
  * Skills information about the user
2629
2703
  */
2630
- skills: (0, import_yup36.array)().of(UserSkillSchema).required().default([]).label("Skills"),
2704
+ skills: (0, import_yup37.array)().of(UserSkillSchema).required().default([]).label("Skills"),
2631
2705
  /**
2632
2706
  * Projects information about the user
2633
2707
  */
2634
- projects: (0, import_yup36.array)().of(UserProjectSchema).default([]).label("Projects"),
2708
+ projects: (0, import_yup37.array)().of(UserProjectSchema).default([]).label("Projects"),
2635
2709
  /**
2636
2710
  * Certifications information about the user
2637
2711
  */
2638
- certifications: (0, import_yup36.array)().of(UserCertificationSchema).default([]).label("Certifications"),
2712
+ certifications: (0, import_yup37.array)().of(UserCertificationSchema).default([]).label("Certifications"),
2639
2713
  /**
2640
2714
  * Interests information about the user.
2641
2715
  */
2642
- interests: (0, import_yup36.array)().of(UserInterestSchema).optional().default([]).label("Interests"),
2716
+ interests: (0, import_yup37.array)().of(UserInterestSchema).optional().default([]).label("Interests"),
2643
2717
  /**
2644
2718
  * Languages information about the user
2645
2719
  */
2646
- languages: (0, import_yup36.array)().of(UserLanguageSchema).required().default([]).label("Languages"),
2720
+ languages: (0, import_yup37.array)().of(UserLanguageSchema).required().default([]).label("Languages"),
2647
2721
  /**
2648
2722
  * Additional information about the user
2649
2723
  */
2650
- additionalInfo: (0, import_yup36.array)().of(UserAdditionalInfoSchema).default([]).label("Additional Information"),
2724
+ additionalInfo: (0, import_yup37.array)().of(UserAdditionalInfoSchema).default([]).label("Additional Information"),
2651
2725
  /**
2652
2726
  * Status of the user account
2653
2727
  */
2654
- status: (0, import_yup36.string)().oneOf(SupportedUserStatuses).required().label("Status"),
2728
+ status: (0, import_yup37.string)().oneOf(SupportedUserStatuses).required().label("Status"),
2655
2729
  /**
2656
2730
  * Roles assigned to the user
2657
2731
  */
2658
- roles: (0, import_yup36.array)().of((0, import_yup36.string)().oneOf(SupportedUserRoles)).required().default(DefaultUserRoles).label("Roles"),
2732
+ roles: (0, import_yup37.array)().of((0, import_yup37.string)().oneOf(SupportedUserRoles)).required().default(DefaultUserRoles).label("Roles"),
2659
2733
  /**
2660
2734
  * Explicit consent to receive marketing email (newsletters, job alerts by
2661
2735
  * broadcast, product updates). Marketing sends are HARD-GATED on
@@ -2667,33 +2741,57 @@ var UserSchema = (0, import_yup36.object)({
2667
2741
  * unsubscribe sets `subscribed=false` so consent and the email-service
2668
2742
  * suppression list stay consistent. Defaults to NOT subscribed (opt-in).
2669
2743
  */
2670
- marketingConsent: (0, import_yup36.object)({
2671
- subscribed: (0, import_yup36.boolean)().default(false).label("Subscribed to marketing email"),
2744
+ marketingConsent: (0, import_yup37.object)({
2745
+ subscribed: (0, import_yup37.boolean)().default(false).label("Subscribed to marketing email"),
2672
2746
  /** Epoch ms of the last consent change (opt-in or opt-out). */
2673
- updatedAt: (0, import_yup36.number)().optional().label("Consent updated at"),
2747
+ updatedAt: (0, import_yup37.number)().optional().label("Consent updated at"),
2674
2748
  /** Where the consent change originated, e.g. `onboarding`, `unsubscribe`, `settings`. */
2675
- source: (0, import_yup36.string)().optional().label("Consent source"),
2749
+ source: (0, import_yup37.string)().optional().label("Consent source"),
2676
2750
  /**
2677
2751
  * How often the user receives job-alert emails. `off` disables job alerts
2678
2752
  * only; other marketing stays governed by `subscribed`. Unset means the
2679
2753
  * user has not chosen a cadence yet.
2680
2754
  */
2681
- jobAlertFrequency: (0, import_yup36.string)().oneOf(SupportedJobAlertFrequencies).optional().label("Job alert frequency")
2755
+ jobAlertFrequency: (0, import_yup37.string)().oneOf(SupportedJobAlertFrequencies).optional().label("Job alert frequency")
2682
2756
  }).default({ subscribed: false }).label("Marketing Consent"),
2757
+ /**
2758
+ * Per-channel toggles for NOTIFICATION email — mail about activity on the
2759
+ * user's own account (a group invite, a job of theirs expiring).
2760
+ *
2761
+ * Deliberately separate from `marketingConsent`, which they must NOT be
2762
+ * collapsed into: the two have different legal footing, which the
2763
+ * email-service footer rules already encode. Notifications are opt-OUT
2764
+ * (default `true`) because a user who declined marketing still needs to hear
2765
+ * that their group invite arrived; marketing stays opt-IN. `productUpdates`
2766
+ * is the exception — it is promotional in character, so it defaults off.
2767
+ *
2768
+ * Transactional mail (magic-link, verification) ignores this object entirely.
2769
+ */
2770
+ notificationPrefs: (0, import_yup37.object)({
2771
+ groupActivity: (0, import_yup37.boolean)().default(true).label("Group activity email"),
2772
+ jobActivity: (0, import_yup37.boolean)().default(true).label("Job activity email"),
2773
+ applicationUpdates: (0, import_yup37.boolean)().default(true).label("Application update email"),
2774
+ productUpdates: (0, import_yup37.boolean)().default(false).label("Product update email")
2775
+ }).default({
2776
+ groupActivity: true,
2777
+ jobActivity: true,
2778
+ applicationUpdates: true,
2779
+ productUpdates: false
2780
+ }).label("Notification Preferences"),
2683
2781
  /**
2684
2782
  * Vector embedding of the user's profile for semantic/hybrid search.
2685
2783
  * Generated from a structured summary of skills, experience, education, etc.
2686
2784
  * Only generated for public profiles with sufficient completeness (≥60%).
2687
2785
  */
2688
- embedding: (0, import_yup36.object)({
2689
- vector: (0, import_yup36.array)((0, import_yup36.number)().required()).optional().label("Embedding vector"),
2690
- model: (0, import_yup36.string)().optional().label("Embedding model")
2786
+ embedding: (0, import_yup37.object)({
2787
+ vector: (0, import_yup37.array)((0, import_yup37.number)().required()).optional().label("Embedding vector"),
2788
+ model: (0, import_yup37.string)().optional().label("Embedding model")
2691
2789
  }).nullable().optional().label("Embedding")
2692
2790
  }).concat(UserGeneralDetailSchema).concat(UserJobPreferencesSchema).concat(UserRecruiterProfileSchema).concat(UserCoordinatorProfileSchema).noUnknown().strict().label("User Schema");
2693
2791
 
2694
2792
  // src/user/user-completeness.schema.ts
2695
- var import_yup37 = require("yup");
2696
- var UserCompletenessSchema = (0, import_yup37.object)({
2793
+ var import_yup38 = require("yup");
2794
+ var UserCompletenessSchema = (0, import_yup38.object)({
2697
2795
  additionalInfo: CompletenessScoreSchema(0).label("Additional Info"),
2698
2796
  // Optional
2699
2797
  certifications: CompletenessScoreSchema(0).label("Certifications"),
@@ -2766,6 +2864,7 @@ var StudentCompletenessSchema = UserCompletenessSchema.omit([
2766
2864
  MIN_SALARY_LOWER_BOUND,
2767
2865
  MIN_SALARY_UPPER_BOUND,
2768
2866
  MailingListSchema,
2867
+ NotificationChannel,
2769
2868
  PREFILL_MIRRORED_KEYS,
2770
2869
  PRIVATE_PROFILE_FIELDS,
2771
2870
  PageSchema,
@@ -2785,6 +2884,8 @@ var StudentCompletenessSchema = UserCompletenessSchema.omit([
2785
2884
  ResourceType,
2786
2885
  SITEMAP_FORMAT,
2787
2886
  SYSTEM_DATE_FORMAT,
2887
+ SavedSearchSchema,
2888
+ SavedSearchStatus,
2788
2889
  SkillSchema,
2789
2890
  SocialAccount,
2790
2891
  SocialAccountSchema,
@@ -2807,6 +2908,7 @@ var StudentCompletenessSchema = UserCompletenessSchema.omit([
2807
2908
  SupportedJobSearchUrgencies,
2808
2909
  SupportedJobStatuses,
2809
2910
  SupportedJobSubCategories,
2911
+ SupportedNotificationChannels,
2810
2912
  SupportedPageStatuses,
2811
2913
  SupportedPageTypes,
2812
2914
  SupportedPostStatuses,
@@ -2816,6 +2918,7 @@ var StudentCompletenessSchema = UserCompletenessSchema.omit([
2816
2918
  SupportedReportReasons,
2817
2919
  SupportedResourceTypes,
2818
2920
  SupportedSalaryCurrencies,
2921
+ SupportedSavedSearchStatuses,
2819
2922
  SupportedSocialAccounts,
2820
2923
  SupportedStudyTypes,
2821
2924
  SupportedUserProfileVisibilities,