@thejob/schema 2.1.5 → 2.1.6

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
@@ -594,6 +594,26 @@ var PageSchema = (0, import_yup12.object)().shape({
594
594
  var import_yup13 = require("yup");
595
595
  var SkillSchema = (0, import_yup13.object)({
596
596
  name: (0, import_yup13.string)().trim().required().label("Skill Name"),
597
+ /**
598
+ * The taxonomy concept this skill resolved to, assigned by thejob-taxonomy-service
599
+ * via `POST /normalize/batch`. Stable slug, e.g. "power-bi".
600
+ *
601
+ * Normalization is ADDITIVE and never authoritative over `name`: the raw string a
602
+ * job was posted with is always preserved, and these two fields are written
603
+ * alongside it. That is what makes a wrong match, a taxonomy re-run, or a service
604
+ * outage recoverable rather than a data loss.
605
+ *
606
+ * Optional and nullable because they genuinely are absent in two normal cases,
607
+ * neither of which is an error:
608
+ * - the term did not resolve (~22% of mentions are a long tail the taxonomy has
609
+ * no concept for yet), and the raw `name` stands alone;
610
+ * - the document predates normalization and has not been re-processed.
611
+ *
612
+ * Consumers must therefore read `conceptName ?? name`, never `conceptName` alone.
613
+ */
614
+ conceptId: (0, import_yup13.string)().optional().nullable().label("Concept ID"),
615
+ /** Canonical display name for `conceptId`, e.g. "Power BI". See `conceptId`. */
616
+ conceptName: (0, import_yup13.string)().optional().nullable().label("Concept Name"),
597
617
  logo: (0, import_yup13.object)({
598
618
  light: (0, import_yup13.string)().required().label("Light Logo"),
599
619
  dark: (0, import_yup13.string)().optional().nullable().label("Dark Logo")
@@ -799,7 +819,15 @@ var JobSchema = (0, import_yup18.object)({
799
819
  designation: (0, import_yup18.string)().optional().nullable().label("Designation"),
800
820
  employmentType: (0, import_yup18.string)().required().label("Employment type"),
801
821
  workMode: (0, import_yup18.string)().required().label("Work mode"),
802
- skills: (0, import_yup18.array)().of(SkillSchema.pick(["name", "logo"]).required().label("Skill")).nullable().optional().label("Skills"),
822
+ /**
823
+ * `conceptId`/`conceptName` carry the taxonomy-service normalization. They are
824
+ * picked here (not just `name`/`logo`) because SkillSchema is `.noUnknown()`:
825
+ * an unpicked field that is actually PRESENT fails validation, so omitting them
826
+ * would reject every normalized job.
827
+ */
828
+ skills: (0, import_yup18.array)().of(
829
+ SkillSchema.pick(["name", "logo", "conceptId", "conceptName"]).required().label("Skill")
830
+ ).nullable().optional().label("Skills"),
803
831
  bookmarks: (0, import_yup18.array)().of(UserIdAndCreatedAtSchema).optional().label("Bookmarks"),
804
832
  embedding: (0, import_yup18.object)({
805
833
  vector: (0, import_yup18.array)((0, import_yup18.number)().required()).optional().label("Embedding vector"),
package/dist/index.d.cts CHANGED
@@ -437,6 +437,8 @@ declare const JobSchema: ObjectSchema<{
437
437
  employmentType: string;
438
438
  workMode: string;
439
439
  skills: {
440
+ conceptId?: string | null | undefined;
441
+ conceptName?: string | null | undefined;
440
442
  name: string;
441
443
  logo: {
442
444
  dark?: string | null | undefined;
@@ -1736,6 +1738,8 @@ declare const FeedbackSchema: yup.ObjectSchema<{
1736
1738
 
1737
1739
  declare const SkillSchema: yup.ObjectSchema<{
1738
1740
  name: string;
1741
+ conceptId: string | null | undefined;
1742
+ conceptName: string | null | undefined;
1739
1743
  logo: {
1740
1744
  dark?: string | null | undefined;
1741
1745
  light: string;
@@ -1749,6 +1753,8 @@ declare const SkillSchema: yup.ObjectSchema<{
1749
1753
  updatedAt: number | undefined;
1750
1754
  }, yup.AnyObject, {
1751
1755
  name: undefined;
1756
+ conceptId: undefined;
1757
+ conceptName: undefined;
1752
1758
  logo: null;
1753
1759
  tags: "";
1754
1760
  shortId: undefined;
package/dist/index.d.ts CHANGED
@@ -437,6 +437,8 @@ declare const JobSchema: ObjectSchema<{
437
437
  employmentType: string;
438
438
  workMode: string;
439
439
  skills: {
440
+ conceptId?: string | null | undefined;
441
+ conceptName?: string | null | undefined;
440
442
  name: string;
441
443
  logo: {
442
444
  dark?: string | null | undefined;
@@ -1736,6 +1738,8 @@ declare const FeedbackSchema: yup.ObjectSchema<{
1736
1738
 
1737
1739
  declare const SkillSchema: yup.ObjectSchema<{
1738
1740
  name: string;
1741
+ conceptId: string | null | undefined;
1742
+ conceptName: string | null | undefined;
1739
1743
  logo: {
1740
1744
  dark?: string | null | undefined;
1741
1745
  light: string;
@@ -1749,6 +1753,8 @@ declare const SkillSchema: yup.ObjectSchema<{
1749
1753
  updatedAt: number | undefined;
1750
1754
  }, yup.AnyObject, {
1751
1755
  name: undefined;
1756
+ conceptId: undefined;
1757
+ conceptName: undefined;
1752
1758
  logo: null;
1753
1759
  tags: "";
1754
1760
  shortId: undefined;
package/dist/index.js CHANGED
@@ -417,6 +417,26 @@ var PageSchema = object10().shape({
417
417
  import { array as array6, object as object11, string as string8 } from "yup";
418
418
  var SkillSchema = object11({
419
419
  name: string8().trim().required().label("Skill Name"),
420
+ /**
421
+ * The taxonomy concept this skill resolved to, assigned by thejob-taxonomy-service
422
+ * via `POST /normalize/batch`. Stable slug, e.g. "power-bi".
423
+ *
424
+ * Normalization is ADDITIVE and never authoritative over `name`: the raw string a
425
+ * job was posted with is always preserved, and these two fields are written
426
+ * alongside it. That is what makes a wrong match, a taxonomy re-run, or a service
427
+ * outage recoverable rather than a data loss.
428
+ *
429
+ * Optional and nullable because they genuinely are absent in two normal cases,
430
+ * neither of which is an error:
431
+ * - the term did not resolve (~22% of mentions are a long tail the taxonomy has
432
+ * no concept for yet), and the raw `name` stands alone;
433
+ * - the document predates normalization and has not been re-processed.
434
+ *
435
+ * Consumers must therefore read `conceptName ?? name`, never `conceptName` alone.
436
+ */
437
+ conceptId: string8().optional().nullable().label("Concept ID"),
438
+ /** Canonical display name for `conceptId`, e.g. "Power BI". See `conceptId`. */
439
+ conceptName: string8().optional().nullable().label("Concept Name"),
420
440
  logo: object11({
421
441
  light: string8().required().label("Light Logo"),
422
442
  dark: string8().optional().nullable().label("Dark Logo")
@@ -622,7 +642,15 @@ var JobSchema = object16({
622
642
  designation: string13().optional().nullable().label("Designation"),
623
643
  employmentType: string13().required().label("Employment type"),
624
644
  workMode: string13().required().label("Work mode"),
625
- skills: array8().of(SkillSchema.pick(["name", "logo"]).required().label("Skill")).nullable().optional().label("Skills"),
645
+ /**
646
+ * `conceptId`/`conceptName` carry the taxonomy-service normalization. They are
647
+ * picked here (not just `name`/`logo`) because SkillSchema is `.noUnknown()`:
648
+ * an unpicked field that is actually PRESENT fails validation, so omitting them
649
+ * would reject every normalized job.
650
+ */
651
+ skills: array8().of(
652
+ SkillSchema.pick(["name", "logo", "conceptId", "conceptName"]).required().label("Skill")
653
+ ).nullable().optional().label("Skills"),
626
654
  bookmarks: array8().of(UserIdAndCreatedAtSchema).optional().label("Bookmarks"),
627
655
  embedding: object16({
628
656
  vector: array8(number5().required()).optional().label("Embedding vector"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thejob/schema",
3
- "version": "2.1.5",
3
+ "version": "2.1.6",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -69,8 +69,18 @@ export const JobSchema = object({
69
69
 
70
70
  workMode: string().required().label("Work mode"),
71
71
 
72
+ /**
73
+ * `conceptId`/`conceptName` carry the taxonomy-service normalization. They are
74
+ * picked here (not just `name`/`logo`) because SkillSchema is `.noUnknown()`:
75
+ * an unpicked field that is actually PRESENT fails validation, so omitting them
76
+ * would reject every normalized job.
77
+ */
72
78
  skills: array()
73
- .of(SkillSchema.pick(["name", "logo"]).required().label("Skill"))
79
+ .of(
80
+ SkillSchema.pick(["name", "logo", "conceptId", "conceptName"])
81
+ .required()
82
+ .label("Skill"),
83
+ )
74
84
  .nullable()
75
85
  .optional()
76
86
  .label("Skills"),
@@ -3,6 +3,29 @@ import { DbDefaultSchema } from "../common/common.schema.js";
3
3
 
4
4
  export const SkillSchema = object({
5
5
  name: string().trim().required().label("Skill Name"),
6
+
7
+ /**
8
+ * The taxonomy concept this skill resolved to, assigned by thejob-taxonomy-service
9
+ * via `POST /normalize/batch`. Stable slug, e.g. "power-bi".
10
+ *
11
+ * Normalization is ADDITIVE and never authoritative over `name`: the raw string a
12
+ * job was posted with is always preserved, and these two fields are written
13
+ * alongside it. That is what makes a wrong match, a taxonomy re-run, or a service
14
+ * outage recoverable rather than a data loss.
15
+ *
16
+ * Optional and nullable because they genuinely are absent in two normal cases,
17
+ * neither of which is an error:
18
+ * - the term did not resolve (~22% of mentions are a long tail the taxonomy has
19
+ * no concept for yet), and the raw `name` stands alone;
20
+ * - the document predates normalization and has not been re-processed.
21
+ *
22
+ * Consumers must therefore read `conceptName ?? name`, never `conceptName` alone.
23
+ */
24
+ conceptId: string().optional().nullable().label("Concept ID"),
25
+
26
+ /** Canonical display name for `conceptId`, e.g. "Power BI". See `conceptId`. */
27
+ conceptName: string().optional().nullable().label("Concept Name"),
28
+
6
29
  logo: object({
7
30
  light: string().required().label("Light Logo"),
8
31
  dark: string().optional().nullable().label("Dark Logo"),