@thejob/schema 2.5.0 → 2.7.0
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.md +6 -0
- package/dist/index.cjs +1063 -568
- package/dist/index.d.cts +602 -7
- package/dist/index.d.ts +602 -7
- package/dist/index.js +1002 -552
- package/package.json +1 -1
- package/src/index.ts +11 -0
- package/src/job/job.schema.ts +28 -5
- package/src/taxonomy/taxonomy-filter.schema.ts +84 -0
- package/src/taxonomy/taxonomy.constant.ts +127 -0
- package/src/taxonomy/taxonomy.schema.ts +404 -0
package/dist/index.js
CHANGED
|
@@ -370,7 +370,7 @@ var GroupFilterSchema = rejectUnknownKeys(
|
|
|
370
370
|
);
|
|
371
371
|
|
|
372
372
|
// src/job/job.schema.ts
|
|
373
|
-
import { array as
|
|
373
|
+
import { array as array10, boolean as boolean12, lazy, mixed as mixed3, number as number7, object as object19, string as string15 } from "yup";
|
|
374
374
|
|
|
375
375
|
// src/location/location.schema.ts
|
|
376
376
|
import { array as array3, number as number4, object as object6, string as string4 } from "yup";
|
|
@@ -589,6 +589,338 @@ var SkillSchema = object13({
|
|
|
589
589
|
tags: array7().of(string9().max(50)).max(20).optional().label("Tags")
|
|
590
590
|
}).concat(DbDefaultSchema).noUnknown().strict().label("Skill");
|
|
591
591
|
|
|
592
|
+
// src/taxonomy/taxonomy.schema.ts
|
|
593
|
+
import { array as array8, boolean as boolean10, number as number6, object as object14, string as string10 } from "yup";
|
|
594
|
+
|
|
595
|
+
// src/taxonomy/taxonomy.constant.ts
|
|
596
|
+
var SupportedConceptSources = ["seed", "manual", "import"];
|
|
597
|
+
var SupportedTaxonomySources = ["seed", "manual"];
|
|
598
|
+
var SupportedTaxonomyNodeKinds = ["category", "subcategory", "group"];
|
|
599
|
+
var SupportedPrefilterRules = [
|
|
600
|
+
"spoken_language",
|
|
601
|
+
"no_letters",
|
|
602
|
+
"url_or_email",
|
|
603
|
+
"fragment"
|
|
604
|
+
];
|
|
605
|
+
var SupportedUnmatchedResolutions = ["pending", "added", "rejected"];
|
|
606
|
+
var SupportedUnmatchedReasons = ["ambiguous"];
|
|
607
|
+
var SupportedProposalKinds = ["concept", "alias", "placement"];
|
|
608
|
+
var SupportedProposalFilters = [...SupportedProposalKinds, "uncategorized"];
|
|
609
|
+
var SupportedProposalStatuses = ["draft", "approved", "discarded"];
|
|
610
|
+
var SupportedProposalMessageRoles = ["operator", "model"];
|
|
611
|
+
var SupportedResolverVerdicts = [
|
|
612
|
+
"same",
|
|
613
|
+
"narrower",
|
|
614
|
+
"broader",
|
|
615
|
+
"related",
|
|
616
|
+
"new_concept",
|
|
617
|
+
"out_of_scope"
|
|
618
|
+
];
|
|
619
|
+
var SupportedAuditStatuses = ["pending", "correct", "wrong"];
|
|
620
|
+
var SupportedReleaseKinds = ["seed", "manual", "review", "auto"];
|
|
621
|
+
var SupportedReleaseStatuses = ["open", "rolled_back"];
|
|
622
|
+
var SupportedMatchTypes = ["exact", "canonical", "fuzzy", "none"];
|
|
623
|
+
var SupportedTaxonomyJobKinds = [
|
|
624
|
+
"describe-concepts",
|
|
625
|
+
"retype-concepts",
|
|
626
|
+
"generate-aliases",
|
|
627
|
+
"alias-backfill",
|
|
628
|
+
"close-gaps",
|
|
629
|
+
"propose-placements",
|
|
630
|
+
"place-unplaced",
|
|
631
|
+
"calibrate-placement",
|
|
632
|
+
"reseed",
|
|
633
|
+
"reindex",
|
|
634
|
+
"calibrate-resolver",
|
|
635
|
+
"golden",
|
|
636
|
+
"resolve-backlog"
|
|
637
|
+
];
|
|
638
|
+
var SupportedTaxonomyJobStates = ["running", "succeeded", "failed", "cancelled"];
|
|
639
|
+
var CONCEPT_ID_PATTERN = /^[a-z][a-z0-9-]*_[a-z0-9-]+$/;
|
|
640
|
+
var VOCABULARY_ID_PATTERN = /^[a-z][a-z0-9-]{0,31}$/;
|
|
641
|
+
var TAXONOMY_NODE_ID_PATTERN = /^[A-Za-z0-9_]{1,64}$/;
|
|
642
|
+
var CONCEPT_TYPE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
|
|
643
|
+
var SCHEDULE_MIN_HOURS = 1;
|
|
644
|
+
var SCHEDULE_MAX_HOURS = 24 * 30;
|
|
645
|
+
|
|
646
|
+
// src/taxonomy/taxonomy.schema.ts
|
|
647
|
+
var conceptId = () => string10().matches(CONCEPT_ID_PATTERN, "conceptId must look like <vocabulary>_<slug>");
|
|
648
|
+
var vocabularyId = () => string10().matches(VOCABULARY_ID_PATTERN, "vocabulary must match [a-z][a-z0-9-]{0,31}");
|
|
649
|
+
var nodeId = () => string10().matches(TAXONOMY_NODE_ID_PATTERN, "node ids look like CAT_01_TECH");
|
|
650
|
+
var strings = () => array8(string10().trim().min(1).required());
|
|
651
|
+
var VocabularyTypeSchema = object14({
|
|
652
|
+
id: string10().matches(CONCEPT_TYPE_PATTERN, "type ids match [a-z][a-z0-9_]*").required().label("Type ID"),
|
|
653
|
+
/** Shown to the model when it classifies a concept; include examples. */
|
|
654
|
+
description: string10().defined().label("Description")
|
|
655
|
+
}).label("Vocabulary Type");
|
|
656
|
+
var VocabularySchema = object14({
|
|
657
|
+
vocabularyId: vocabularyId().required().label("Vocabulary ID"),
|
|
658
|
+
name: string10().trim().min(1).required().label("Name"),
|
|
659
|
+
/** What one concept is called in prompts and messages: "skill", "role". */
|
|
660
|
+
noun: string10().trim().min(1).required().label("Noun"),
|
|
661
|
+
nounPlural: string10().trim().min(1).required().label("Noun (plural)"),
|
|
662
|
+
/** What belongs in this vocabulary, for prompts. */
|
|
663
|
+
description: string10().trim().min(1).required().label("Description"),
|
|
664
|
+
/** Where its terms are written, for the "swap it in" test: "a job posting". */
|
|
665
|
+
appearsIn: string10().trim().min(1).required().label("Appears In"),
|
|
666
|
+
/** Things that are NOT concepts of this vocabulary, for prompts. */
|
|
667
|
+
outOfScope: string10().trim().min(1).required().label("Out of Scope"),
|
|
668
|
+
types: array8(VocabularyTypeSchema.required()).min(1).required().test(
|
|
669
|
+
"unique-type-ids",
|
|
670
|
+
"type ids must be unique",
|
|
671
|
+
(types) => !types || new Set(types.map((t) => t.id)).size === types.length
|
|
672
|
+
).label("Types"),
|
|
673
|
+
/** The type a concept gets when nothing more specific is known. One of `types`. */
|
|
674
|
+
defaultType: string10().required().test("default-type-listed", "defaultType must be one of the type ids", function(value) {
|
|
675
|
+
const types = this.parent.types ?? [];
|
|
676
|
+
return types.some((t) => t.id === value);
|
|
677
|
+
}).label("Default Type"),
|
|
678
|
+
prefilter: array8(string10().oneOf(SupportedPrefilterRules).required()).default([]).label("Prefilter"),
|
|
679
|
+
/**
|
|
680
|
+
* Words that qualify a term without changing what it names ("fluent",
|
|
681
|
+
* "native"), dropped from its canonical lookup form in THIS vocabulary only.
|
|
682
|
+
*/
|
|
683
|
+
qualifiers: strings().optional().label("Qualifiers"),
|
|
684
|
+
/** Extra instructions per model task; each is optional. */
|
|
685
|
+
guidance: object14({
|
|
686
|
+
describe: string10().optional(),
|
|
687
|
+
classify: string10().optional(),
|
|
688
|
+
aliases: string10().optional(),
|
|
689
|
+
verify: string10().optional(),
|
|
690
|
+
place: string10().optional()
|
|
691
|
+
}).label("Guidance"),
|
|
692
|
+
source: string10().oneOf(SupportedTaxonomySources).required().label("Source"),
|
|
693
|
+
createdAt: number6().required().label("Created At"),
|
|
694
|
+
updatedAt: number6().required().label("Updated At")
|
|
695
|
+
}).label("Vocabulary");
|
|
696
|
+
var TaxonomyNodeSchema = object14({
|
|
697
|
+
nodeId: nodeId().required().label("Node ID"),
|
|
698
|
+
vocabulary: vocabularyId().required().label("Vocabulary"),
|
|
699
|
+
kind: string10().oneOf(SupportedTaxonomyNodeKinds).required().label("Kind"),
|
|
700
|
+
name: string10().trim().min(1).required().label("Name"),
|
|
701
|
+
/** Groups carry a description; categories and subcategories usually do not. */
|
|
702
|
+
description: string10().optional().label("Description"),
|
|
703
|
+
aliases: strings().default([]).label("Aliases"),
|
|
704
|
+
/** null for categories (the roots). */
|
|
705
|
+
parentId: string10().nullable().defined().label("Parent ID"),
|
|
706
|
+
/** Ancestor ids from the root down to and including this node. */
|
|
707
|
+
path: array8(string10().required()).default([]).label("Path"),
|
|
708
|
+
source: string10().oneOf(SupportedTaxonomySources).optional().label("Source"),
|
|
709
|
+
createdAt: number6().required().label("Created At"),
|
|
710
|
+
updatedAt: number6().required().label("Updated At")
|
|
711
|
+
}).label("Taxonomy Node");
|
|
712
|
+
var ConceptMembershipSchema = object14({
|
|
713
|
+
categoryId: string10().required().label("Category ID"),
|
|
714
|
+
categoryName: string10().required().label("Category Name"),
|
|
715
|
+
subcategoryId: string10().required().label("Subcategory ID"),
|
|
716
|
+
subcategoryName: string10().required().label("Subcategory Name"),
|
|
717
|
+
groupId: string10().required().label("Group ID"),
|
|
718
|
+
groupName: string10().required().label("Group Name"),
|
|
719
|
+
/** The source record this membership came from; '' when written by hand. */
|
|
720
|
+
sourceId: string10().default("").label("Source ID")
|
|
721
|
+
}).label("Concept Membership");
|
|
722
|
+
var ConceptSchema = object14({
|
|
723
|
+
/** `<vocabulary>_<slug>`, e.g. `skills_power-bi`. Primary key. */
|
|
724
|
+
conceptId: conceptId().required().label("Concept ID"),
|
|
725
|
+
vocabulary: vocabularyId().required().label("Vocabulary"),
|
|
726
|
+
name: string10().trim().min(1).max(200).required().label("Name"),
|
|
727
|
+
/** One of the vocabulary's type ids; checked against the vocabulary by the service. */
|
|
728
|
+
type: string10().trim().matches(CONCEPT_TYPE_PATTERN, "type must be a type id").required().label("Type"),
|
|
729
|
+
description: string10().trim().max(2e3).default("").label("Description"),
|
|
730
|
+
aliases: strings().default([]).label("Aliases"),
|
|
731
|
+
memberships: array8(ConceptMembershipSchema.required()).default([]).label("Memberships"),
|
|
732
|
+
/** Always concepts of the same vocabulary. */
|
|
733
|
+
relatedConceptIds: strings().default([]).label("Related Concepts"),
|
|
734
|
+
source: string10().oneOf(SupportedConceptSources).required().label("Source"),
|
|
735
|
+
createdAt: number6().required().label("Created At"),
|
|
736
|
+
updatedAt: number6().required().label("Updated At"),
|
|
737
|
+
/** Resume marker of `retype-concepts`: set once the type was examined. */
|
|
738
|
+
retypedAt: number6().optional().label("Retyped At"),
|
|
739
|
+
/** Resume marker of `generate-aliases`: set even when no alias was added. */
|
|
740
|
+
aliasedAt: number6().optional().label("Aliased At"),
|
|
741
|
+
/** Set while `description` is a stand-in; removed once a real one is written. */
|
|
742
|
+
descriptionPending: boolean10().isTrue().optional().label("Description Pending")
|
|
743
|
+
}).label("Concept");
|
|
744
|
+
var UnmatchedTermSchema = object14({
|
|
745
|
+
vocabulary: vocabularyId().required().label("Vocabulary"),
|
|
746
|
+
/** The raw input as first received. */
|
|
747
|
+
term: string10().required().label("Term"),
|
|
748
|
+
/** The dedupe key, so "React JS" and "react.js" share a row. */
|
|
749
|
+
normalizedTerm: string10().required().label("Normalized Term"),
|
|
750
|
+
count: number6().integer().min(0).required().label("Count"),
|
|
751
|
+
firstSeenAt: number6().required().label("First Seen At"),
|
|
752
|
+
lastSeenAt: number6().required().label("Last Seen At"),
|
|
753
|
+
/** Which callers sent it, capped. */
|
|
754
|
+
sources: array8(
|
|
755
|
+
object14({
|
|
756
|
+
service: string10().required(),
|
|
757
|
+
context: string10().optional()
|
|
758
|
+
}).required()
|
|
759
|
+
).default([]).label("Sources"),
|
|
760
|
+
resolution: string10().oneOf(SupportedUnmatchedResolutions).required().label("Resolution"),
|
|
761
|
+
resolvedConceptId: string10().optional().label("Resolved Concept"),
|
|
762
|
+
/** `ambiguous`: the concept exists; the caller gave no context that picked one. */
|
|
763
|
+
reason: string10().oneOf(SupportedUnmatchedReasons).optional().label("Reason"),
|
|
764
|
+
/** The concepts an ambiguous term could mean. */
|
|
765
|
+
candidates: array8(string10().required()).optional().label("Candidates"),
|
|
766
|
+
/** Who rejected it when it was not a human: `prefilter:<rule>` or `model`. */
|
|
767
|
+
rejectedBy: string10().optional().label("Rejected By")
|
|
768
|
+
}).label("Unmatched Term");
|
|
769
|
+
var ProposalCandidateSchema = object14({
|
|
770
|
+
groupId: string10().required(),
|
|
771
|
+
groupName: string10().required(),
|
|
772
|
+
subcategoryId: string10().required(),
|
|
773
|
+
subcategoryName: string10().required(),
|
|
774
|
+
categoryId: string10().required(),
|
|
775
|
+
categoryName: string10().required(),
|
|
776
|
+
score: number6().required(),
|
|
777
|
+
nearestMembers: array8(string10().required()).default([])
|
|
778
|
+
}).label("Proposal Candidate");
|
|
779
|
+
var ProposalMessageSchema = object14({
|
|
780
|
+
role: string10().oneOf(SupportedProposalMessageRoles).required(),
|
|
781
|
+
/** The operator's instruction, or the model's note on what it changed and why. */
|
|
782
|
+
content: string10().defined(),
|
|
783
|
+
/** Which model answered. Absent on operator turns. */
|
|
784
|
+
model: string10().optional(),
|
|
785
|
+
at: number6().required()
|
|
786
|
+
}).label("Proposal Message");
|
|
787
|
+
var SuggestedHomeSchema = object14({
|
|
788
|
+
categoryName: string10().defined(),
|
|
789
|
+
subcategoryName: string10().defined(),
|
|
790
|
+
groupName: string10().defined()
|
|
791
|
+
}).label("Suggested Home");
|
|
792
|
+
var ResolverVerificationSchema = object14({
|
|
793
|
+
verdict: string10().oneOf(SupportedResolverVerdicts).required(),
|
|
794
|
+
/** The shown concept the verdict is about; null for `new_concept` / `out_of_scope`. */
|
|
795
|
+
conceptId: string10().nullable().defined(),
|
|
796
|
+
evidence: string10().defined(),
|
|
797
|
+
/** What the judge took the term to mean, abbreviations expanded. */
|
|
798
|
+
means: string10().optional(),
|
|
799
|
+
/** For `same`: did the independent confirm step agree? */
|
|
800
|
+
consistent: boolean10().optional(),
|
|
801
|
+
confirm: object14({
|
|
802
|
+
answer: string10().oneOf(["yes", "no"]).required(),
|
|
803
|
+
evidence: string10().defined()
|
|
804
|
+
}).optional().default(void 0)
|
|
805
|
+
}).label("Resolver Verification");
|
|
806
|
+
var ConceptProposalSchema = object14({
|
|
807
|
+
proposalId: string10().required().label("Proposal ID"),
|
|
808
|
+
vocabulary: vocabularyId().required().label("Vocabulary"),
|
|
809
|
+
/** The miss this closes; `normalizedTerm` links back to its unmatched row. */
|
|
810
|
+
term: string10().required().label("Term"),
|
|
811
|
+
normalizedTerm: string10().required().label("Normalized Term"),
|
|
812
|
+
/** Demand at proposal time, so the queue ranks without a join. */
|
|
813
|
+
count: number6().integer().min(0).required().label("Count"),
|
|
814
|
+
/** Other misses folded into this draft because they name the same new concept. */
|
|
815
|
+
mergedTerms: array8(
|
|
816
|
+
object14({
|
|
817
|
+
term: string10().required(),
|
|
818
|
+
normalizedTerm: string10().required(),
|
|
819
|
+
count: number6().integer().min(0).required()
|
|
820
|
+
}).required()
|
|
821
|
+
).optional().label("Merged Terms"),
|
|
822
|
+
/** Absent on drafts that predate the field: read as `concept`. */
|
|
823
|
+
kind: string10().oneOf(SupportedProposalKinds).optional().label("Kind"),
|
|
824
|
+
/** For `alias`: the concept the term names. For `placement`: the concept to place. */
|
|
825
|
+
targetConceptId: string10().optional().label("Target Concept"),
|
|
826
|
+
targetName: string10().optional().label("Target Name"),
|
|
827
|
+
// The draft concept, editable until approved. Empty strings are valid here:
|
|
828
|
+
// an alias draft carries no draft concept of its own.
|
|
829
|
+
name: string10().defined().label("Name"),
|
|
830
|
+
type: string10().defined().label("Type"),
|
|
831
|
+
description: string10().defined().label("Description"),
|
|
832
|
+
aliases: array8(string10().required()).default([]).label("Aliases"),
|
|
833
|
+
/** Empty when no group fits: approved that way, the concept goes live uncategorized. */
|
|
834
|
+
memberships: array8(ConceptMembershipSchema.required()).default([]).label("Memberships"),
|
|
835
|
+
suggestedHome: SuggestedHomeSchema.nullable().optional().default(void 0).label("Suggested Home"),
|
|
836
|
+
/** Resolved to concepts that exist; names that matched nothing are dropped. */
|
|
837
|
+
relatedConceptIds: array8(string10().required()).default([]).label("Related Concepts"),
|
|
838
|
+
/** Every placement candidate considered, best first. */
|
|
839
|
+
candidates: array8(ProposalCandidateSchema.required()).default([]).label("Candidates"),
|
|
840
|
+
needsReview: boolean10().required().label("Needs Review"),
|
|
841
|
+
reason: string10().optional().label("Reason"),
|
|
842
|
+
verification: ResolverVerificationSchema.optional().default(void 0).label("Verification"),
|
|
843
|
+
/** What the auto-accept gate decided for an alias verdict. */
|
|
844
|
+
autoAccept: object14({
|
|
845
|
+
accepted: boolean10().required(),
|
|
846
|
+
reason: string10().optional(),
|
|
847
|
+
tier: string10().optional(),
|
|
848
|
+
calibrationId: string10().optional(),
|
|
849
|
+
releaseId: string10().optional()
|
|
850
|
+
}).optional().default(void 0).label("Auto Accept"),
|
|
851
|
+
/** Which model drafted it. */
|
|
852
|
+
model: string10().defined().label("Model"),
|
|
853
|
+
/** The refinement conversation, oldest first. */
|
|
854
|
+
messages: array8(ProposalMessageSchema.required()).default([]).label("Messages"),
|
|
855
|
+
status: string10().oneOf(SupportedProposalStatuses).required().label("Status"),
|
|
856
|
+
/** Set when approved: the concept this became. */
|
|
857
|
+
resolvedConceptId: string10().optional().label("Resolved Concept"),
|
|
858
|
+
createdAt: number6().required().label("Created At"),
|
|
859
|
+
updatedAt: number6().required().label("Updated At")
|
|
860
|
+
}).label("Concept Proposal");
|
|
861
|
+
var ReleaseSchema = object14({
|
|
862
|
+
releaseId: string10().required().label("Release ID"),
|
|
863
|
+
kind: string10().oneOf(SupportedReleaseKinds).required().label("Kind"),
|
|
864
|
+
status: string10().oneOf(SupportedReleaseStatuses).required().label("Status"),
|
|
865
|
+
createdBy: string10().required().label("Created By"),
|
|
866
|
+
createdAt: number6().required().label("Created At"),
|
|
867
|
+
note: string10().optional().label("Note"),
|
|
868
|
+
rolledBackAt: number6().optional().label("Rolled Back At"),
|
|
869
|
+
rolledBackBy: string10().optional().label("Rolled Back By")
|
|
870
|
+
}).label("Release");
|
|
871
|
+
var AuditSchema = object14({
|
|
872
|
+
auditId: string10().required().label("Audit ID"),
|
|
873
|
+
releaseId: string10().required().label("Release ID"),
|
|
874
|
+
key: string10().required().label("Key"),
|
|
875
|
+
term: string10().required().label("Term"),
|
|
876
|
+
conceptId: string10().required().label("Concept ID"),
|
|
877
|
+
tier: string10().optional().label("Tier"),
|
|
878
|
+
status: string10().oneOf(SupportedAuditStatuses).required().label("Status"),
|
|
879
|
+
createdAt: number6().required().label("Created At"),
|
|
880
|
+
resolvedAt: number6().optional().label("Resolved At"),
|
|
881
|
+
resolvedBy: string10().optional().label("Resolved By")
|
|
882
|
+
}).label("Audit");
|
|
883
|
+
var ResolverSettingsSchema = object14({
|
|
884
|
+
autoAccept: object14({
|
|
885
|
+
/** Stop switch for WRITING auto keys. Off until a calibration passes. */
|
|
886
|
+
enabled: boolean10().required(),
|
|
887
|
+
/** Minimum calibrated precision (Wilson 95% lower bound) for a tier to auto-accept. */
|
|
888
|
+
target: number6().min(0.5).lessThan(1).required(),
|
|
889
|
+
maxPerRun: number6().integer().min(0).required(),
|
|
890
|
+
maxPerDay: number6().integer().min(0).required(),
|
|
891
|
+
/** Share of each auto release sampled into the audit queue (0..1). */
|
|
892
|
+
auditRate: number6().min(0).max(1).required()
|
|
893
|
+
}).label("Auto Accept"),
|
|
894
|
+
/** Stop switch for SERVING auto keys: false hides them from lookups at once. */
|
|
895
|
+
serveAutoKeys: boolean10().required().label("Serve Auto Keys"),
|
|
896
|
+
/** Minimum Meilisearch ranking score (0..1) for a fuzzy hit to be considered. */
|
|
897
|
+
fuzzyMinScore: number6().min(0).max(1).required().label("Fuzzy Min Score"),
|
|
898
|
+
/** Per-client limit on public search, per minute per replica. 0 disables it. */
|
|
899
|
+
searchRateLimitPerMin: number6().integer().min(0).required().label("Search Rate Limit"),
|
|
900
|
+
/** Master switch for scheduled maintenance jobs. */
|
|
901
|
+
scheduledJobs: boolean10().required().label("Scheduled Jobs"),
|
|
902
|
+
updatedAt: number6().optional().label("Updated At"),
|
|
903
|
+
updatedBy: string10().optional().label("Updated By"),
|
|
904
|
+
/** Why auto-accept was last switched off automatically. */
|
|
905
|
+
trippedReason: string10().optional().label("Tripped Reason")
|
|
906
|
+
}).label("Resolver Settings");
|
|
907
|
+
var TaxonomyScheduleSchema = object14({
|
|
908
|
+
kind: string10().oneOf(SupportedTaxonomyJobKinds).required().label("Job"),
|
|
909
|
+
enabled: boolean10().required().label("Enabled"),
|
|
910
|
+
everyHours: number6().min(SCHEDULE_MIN_HOURS).max(SCHEDULE_MAX_HOURS).required().label("Every (hours)"),
|
|
911
|
+
/** Last time the scheduler fired this job. */
|
|
912
|
+
lastRunAt: number6().optional().label("Last Run At"),
|
|
913
|
+
updatedAt: number6().required().label("Updated At")
|
|
914
|
+
}).label("Taxonomy Schedule");
|
|
915
|
+
var NormalizeContextSchema = object14({
|
|
916
|
+
/** The title of the record the terms come from. */
|
|
917
|
+
title: string10().max(200).optional(),
|
|
918
|
+
/** Backbone node ids (category, subcategory or group). */
|
|
919
|
+
categoryIds: array8(nodeId().required()).max(10).optional(),
|
|
920
|
+
/** Other terms from the same record, in the same vocabulary. */
|
|
921
|
+
siblings: array8(string10().max(200).required()).max(50).optional()
|
|
922
|
+
}).label("Normalize Context");
|
|
923
|
+
|
|
592
924
|
// src/question/question.constant.ts
|
|
593
925
|
var QuestionType = /* @__PURE__ */ ((QuestionType2) => {
|
|
594
926
|
QuestionType2["Input"] = "input";
|
|
@@ -605,24 +937,24 @@ var AnswerChoiceType = /* @__PURE__ */ ((AnswerChoiceType2) => {
|
|
|
605
937
|
var SupportedAnswerChoiceTypes = Object.values(AnswerChoiceType);
|
|
606
938
|
|
|
607
939
|
// src/question/question.schema.ts
|
|
608
|
-
import { boolean as
|
|
609
|
-
var QuestionSchema =
|
|
610
|
-
label:
|
|
611
|
-
default:
|
|
612
|
-
title:
|
|
613
|
-
type:
|
|
614
|
-
isOptional:
|
|
615
|
-
readonly:
|
|
616
|
-
isNew:
|
|
940
|
+
import { boolean as boolean11, object as object15, string as string11 } from "yup";
|
|
941
|
+
var QuestionSchema = object15().shape({
|
|
942
|
+
label: string11().max(50).optional().label("Label"),
|
|
943
|
+
default: boolean11().optional().default(false).label("Default"),
|
|
944
|
+
title: string11().required().max(200).label("Title"),
|
|
945
|
+
type: string11().oneOf(SupportedQuestionTypes).required().label("Type"),
|
|
946
|
+
isOptional: boolean11().optional().label("Mark if the question is optional"),
|
|
947
|
+
readonly: boolean11().optional().label("Readonly"),
|
|
948
|
+
isNew: boolean11().optional().label("Is New")
|
|
617
949
|
});
|
|
618
950
|
|
|
619
951
|
// src/question/input-question.schema.ts
|
|
620
|
-
import { object as
|
|
952
|
+
import { object as object16, string as string12 } from "yup";
|
|
621
953
|
var InputQuestionSchema = QuestionSchema.concat(
|
|
622
|
-
|
|
623
|
-
type:
|
|
624
|
-
preferredAnswer:
|
|
625
|
-
answers:
|
|
954
|
+
object16().shape({
|
|
955
|
+
type: string12().oneOf(["input" /* Input */]).required().label("Question type"),
|
|
956
|
+
preferredAnswer: string12().max(100).optional().label("Preferred Answer"),
|
|
957
|
+
answers: string12().max(500).when("isOptional", {
|
|
626
958
|
is: (isOptional) => Boolean(isOptional),
|
|
627
959
|
then: (schema) => schema.optional(),
|
|
628
960
|
otherwise: (schema) => schema.required()
|
|
@@ -631,10 +963,10 @@ var InputQuestionSchema = QuestionSchema.concat(
|
|
|
631
963
|
);
|
|
632
964
|
|
|
633
965
|
// src/question/choice-question.schema.ts
|
|
634
|
-
import { array as
|
|
966
|
+
import { array as array9, mixed as mixed2, object as object17, string as string13 } from "yup";
|
|
635
967
|
var ChoicePreferredAnswerSchema = (label = "Preferred answer") => mixed2().when("answerChoiceType", {
|
|
636
968
|
is: (value) => value === "multiple" /* Multiple */,
|
|
637
|
-
then: () =>
|
|
969
|
+
then: () => array9(string13()).test(
|
|
638
970
|
"is-valid-option",
|
|
639
971
|
`${label} must be from the provided options`,
|
|
640
972
|
function(answer) {
|
|
@@ -645,7 +977,7 @@ var ChoicePreferredAnswerSchema = (label = "Preferred answer") => mixed2().when(
|
|
|
645
977
|
return true;
|
|
646
978
|
}
|
|
647
979
|
).optional().label(label),
|
|
648
|
-
otherwise: () =>
|
|
980
|
+
otherwise: () => string13().test(
|
|
649
981
|
"is-valid-option",
|
|
650
982
|
`${label} must be from the provided options`,
|
|
651
983
|
function(answer) {
|
|
@@ -656,18 +988,18 @@ var ChoicePreferredAnswerSchema = (label = "Preferred answer") => mixed2().when(
|
|
|
656
988
|
});
|
|
657
989
|
var getChoiceAnswerSchema = (answerChoiceType, isOptional) => {
|
|
658
990
|
if (answerChoiceType === "multiple" /* Multiple */) {
|
|
659
|
-
const multiAnswerSchema =
|
|
991
|
+
const multiAnswerSchema = array9(string13().max(500));
|
|
660
992
|
return isOptional ? multiAnswerSchema.optional().default([]) : multiAnswerSchema.min(1, "Select at least one option.").required("Select at least one option.").default([]);
|
|
661
993
|
}
|
|
662
|
-
const singleAnswerSchema =
|
|
994
|
+
const singleAnswerSchema = string13().max(500);
|
|
663
995
|
return isOptional ? singleAnswerSchema.optional() : singleAnswerSchema.required("Select an option.");
|
|
664
996
|
};
|
|
665
997
|
var ChoiceQuestionSchema = QuestionSchema.concat(
|
|
666
|
-
|
|
667
|
-
type:
|
|
668
|
-
optionsFrom:
|
|
669
|
-
options:
|
|
670
|
-
answerChoiceType:
|
|
998
|
+
object17().shape({
|
|
999
|
+
type: string13().oneOf(["choice" /* Choice */]).required().label("Question type"),
|
|
1000
|
+
optionsFrom: string13().oneOf(["skill" /* Skill */, "education_level" /* EducationLevel */, "experience_level" /* ExperienceLevel */]).optional().label("Option field"),
|
|
1001
|
+
options: array9(string13().required()).min(1).required().label("Options"),
|
|
1002
|
+
answerChoiceType: string13().oneOf(SupportedAnswerChoiceTypes).required().default("single" /* Single */).label("Type"),
|
|
671
1003
|
preferredAnswer: ChoicePreferredAnswerSchema("Preferred answer"),
|
|
672
1004
|
answers: mixed2().when(
|
|
673
1005
|
["answerChoiceType", "isOptional"],
|
|
@@ -677,12 +1009,12 @@ var ChoiceQuestionSchema = QuestionSchema.concat(
|
|
|
677
1009
|
);
|
|
678
1010
|
|
|
679
1011
|
// src/question/read-and-acknowledge.schema.ts
|
|
680
|
-
import { object as
|
|
681
|
-
var AcknowledgeAnswerSchema =
|
|
1012
|
+
import { object as object18, string as string14 } from "yup";
|
|
1013
|
+
var AcknowledgeAnswerSchema = string14().oneOf(["yes" /* Yes */, "no" /* No */]).required("This question must be acknowledged.");
|
|
682
1014
|
var ReadAndAcknowledgeQuestionSchema = QuestionSchema.concat(
|
|
683
|
-
|
|
684
|
-
type:
|
|
685
|
-
description:
|
|
1015
|
+
object18().shape({
|
|
1016
|
+
type: string14().oneOf(["readAndAcknowledge" /* ReadAndAcknowledge */]).required().label("Question type"),
|
|
1017
|
+
description: string14().max(1e4).required().label("Content"),
|
|
686
1018
|
preferredAnswer: AcknowledgeAnswerSchema.label("Preferred Answer"),
|
|
687
1019
|
answers: AcknowledgeAnswerSchema.label("Answer")
|
|
688
1020
|
})
|
|
@@ -763,20 +1095,20 @@ var SupportedApplicationReceivePreferences = Object.values(
|
|
|
763
1095
|
);
|
|
764
1096
|
|
|
765
1097
|
// src/job/job.schema.ts
|
|
766
|
-
var JobSchema =
|
|
1098
|
+
var JobSchema = object19({
|
|
767
1099
|
/** Unique id usable by external systems to reference the job. */
|
|
768
|
-
uniqueId:
|
|
1100
|
+
uniqueId: string15().optional().label("Unique ID"),
|
|
769
1101
|
/** Job title shown in listings and search. */
|
|
770
|
-
headline:
|
|
1102
|
+
headline: string15().required().min(5).max(150).label("Headline"),
|
|
771
1103
|
/** User-friendly, unique URL identifier. */
|
|
772
|
-
slug:
|
|
1104
|
+
slug: string15().required().max(250).label("Slug"),
|
|
773
1105
|
/** How applications are received (inbox vs external website). */
|
|
774
1106
|
applicationReceivePreference: mixed3().oneOf([
|
|
775
1107
|
"inbox" /* Inbox */,
|
|
776
1108
|
"external_website" /* ExternalWebsite */
|
|
777
1109
|
]).required().label("Preference"),
|
|
778
1110
|
/** Required when applicationReceivePreference is ExternalWebsite. */
|
|
779
|
-
externalApplyLink:
|
|
1111
|
+
externalApplyLink: string15().when("applicationReceivePreference", {
|
|
780
1112
|
is: (value) => value === "external_website" /* ExternalWebsite */,
|
|
781
1113
|
then: (schema) => schema.url().required().label("Apply for Job link"),
|
|
782
1114
|
otherwise: (schema) => schema.optional()
|
|
@@ -784,35 +1116,44 @@ var JobSchema = object18({
|
|
|
784
1116
|
/** Company the job belongs to (subset of PageSchema). */
|
|
785
1117
|
company: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Company"),
|
|
786
1118
|
/** @deprecated kept for backwards compatibility. */
|
|
787
|
-
designation:
|
|
788
|
-
employmentType:
|
|
789
|
-
workMode:
|
|
1119
|
+
designation: string15().optional().nullable().label("Designation"),
|
|
1120
|
+
employmentType: string15().required().label("Employment type"),
|
|
1121
|
+
workMode: string15().required().label("Work mode"),
|
|
790
1122
|
/**
|
|
791
|
-
* `
|
|
792
|
-
*
|
|
793
|
-
*
|
|
794
|
-
*
|
|
1123
|
+
* `name` is the skill exactly as posted. `concept` is what thejob-taxonomy-service
|
|
1124
|
+
* resolved it to (`vocabulary: skills`), written by jobs-service, never by the
|
|
1125
|
+
* poster: enough of the concept to filter by id and display the canonical name
|
|
1126
|
+
* without a lookup. A copy, so it can go stale after a taxonomy release; see
|
|
1127
|
+
* `taxonomyVersion`.
|
|
1128
|
+
*
|
|
1129
|
+
* Additive, never authoritative: the raw `name` is always kept, so a wrong
|
|
1130
|
+
* match, a taxonomy release or an outage is recoverable by re-normalizing.
|
|
1131
|
+
* `concept` is absent when the term did not resolve (a normal outcome, logged
|
|
1132
|
+
* as a miss on the taxonomy side) or the job predates normalization, so read
|
|
1133
|
+
* `concept?.name ?? name`.
|
|
795
1134
|
*/
|
|
796
|
-
skills:
|
|
797
|
-
SkillSchema.pick(["name", "logo"
|
|
1135
|
+
skills: array10().of(
|
|
1136
|
+
SkillSchema.pick(["name", "logo"]).shape({
|
|
1137
|
+
concept: ConceptSchema.pick(["conceptId", "vocabulary", "name", "type"]).nullable().optional().default(void 0)
|
|
1138
|
+
}).required().label("Skill")
|
|
798
1139
|
).nullable().optional().label("Skills"),
|
|
799
|
-
bookmarks:
|
|
800
|
-
embedding:
|
|
801
|
-
vector:
|
|
802
|
-
model:
|
|
1140
|
+
bookmarks: array10().of(UserIdAndCreatedAtSchema).optional().label("Bookmarks"),
|
|
1141
|
+
embedding: object19({
|
|
1142
|
+
vector: array10(number7().required()).optional().label("Embedding vector"),
|
|
1143
|
+
model: string15().optional().label("Embedding model")
|
|
803
1144
|
}).nullable().optional().label("Embedding"),
|
|
804
|
-
applicants:
|
|
805
|
-
applicantCount:
|
|
806
|
-
externalApplicationLinkClickCount:
|
|
807
|
-
description:
|
|
808
|
-
descriptionMarkdown:
|
|
809
|
-
descriptionHTML:
|
|
1145
|
+
applicants: array10().of(UserIdAndCreatedAtSchema).optional().label("Applicants"),
|
|
1146
|
+
applicantCount: number7().optional().label("Applicant count"),
|
|
1147
|
+
externalApplicationLinkClickCount: number7().optional().label("External application link click count"),
|
|
1148
|
+
description: string15().required().min(100).max(5e4).label("Description"),
|
|
1149
|
+
descriptionMarkdown: string15().required().label("Description Markdown"),
|
|
1150
|
+
descriptionHTML: string15().optional().label("Description HTML"),
|
|
810
1151
|
/**
|
|
811
1152
|
* Job locations. Required even for remote roles (compliance/legal). Defaults
|
|
812
1153
|
* to an empty array; min(1) is intentionally not enforced yet.
|
|
813
1154
|
*/
|
|
814
|
-
locations:
|
|
815
|
-
educationLevel:
|
|
1155
|
+
locations: array10().of(LocationSchema).default([]).label("Location"),
|
|
1156
|
+
educationLevel: array10(string15().oneOf(SupportedEducationLevels)).required().min(1).label("Educational level"),
|
|
816
1157
|
/** Posting validity window (start/expiry). */
|
|
817
1158
|
validity: DurationSchema({
|
|
818
1159
|
format: SYSTEM_DATE_FORMAT,
|
|
@@ -825,21 +1166,21 @@ var JobSchema = object18({
|
|
|
825
1166
|
* has no `validity.endDate` and must be verified by crawling its page. Guards
|
|
826
1167
|
* re-check cadence so the same job is not re-crawled on every sweep.
|
|
827
1168
|
*/
|
|
828
|
-
lastExpiryCheckAt:
|
|
1169
|
+
lastExpiryCheckAt: number7().optional().nullable().label("Last expiry check at"),
|
|
829
1170
|
/**
|
|
830
1171
|
* When this job transitioned to `status: closed` (epoch ms). Server-owned
|
|
831
1172
|
* operational field: stamped by every jobs-service close path (expiry
|
|
832
1173
|
* auto-close and the dated lapse sweep). Distinct from `updatedAt` so a later
|
|
833
1174
|
* edit to a closed job does not move it.
|
|
834
1175
|
*/
|
|
835
|
-
closedAt:
|
|
836
|
-
experienceLevel:
|
|
837
|
-
contactEmail:
|
|
838
|
-
workingHoursPerWeek:
|
|
839
|
-
tags:
|
|
1176
|
+
closedAt: number7().optional().nullable().label("Closed at"),
|
|
1177
|
+
experienceLevel: string15().oneOf(SupportedExperienceLevels).nullable().optional().label("Experience level"),
|
|
1178
|
+
contactEmail: string15().email().nullable().optional().label("Contact email"),
|
|
1179
|
+
workingHoursPerWeek: number7().nullable().optional().min(1).max(24 * 7).label("Working hours per week"),
|
|
1180
|
+
tags: array10().max(50).optional().label("Tags"),
|
|
840
1181
|
/** Direct/Quick-apply questionnaire. Each item is validated against the
|
|
841
1182
|
* concrete question schema for its `type`, with the stored `answers` omitted. */
|
|
842
|
-
questionnaire:
|
|
1183
|
+
questionnaire: array10().of(
|
|
843
1184
|
lazy((question) => {
|
|
844
1185
|
const schema = getSchemaByQuestion(question.type);
|
|
845
1186
|
if (question.type === "input" /* Input */) {
|
|
@@ -856,12 +1197,12 @@ var JobSchema = object18({
|
|
|
856
1197
|
return schema;
|
|
857
1198
|
})
|
|
858
1199
|
).label("Questionnaire"),
|
|
859
|
-
status:
|
|
860
|
-
seoTags:
|
|
861
|
-
description:
|
|
862
|
-
keywords:
|
|
1200
|
+
status: string15().oneOf(SupportedJobStatuses).default("draft" /* Draft */).required().label("Status"),
|
|
1201
|
+
seoTags: object19({
|
|
1202
|
+
description: string15().optional().label("Description"),
|
|
1203
|
+
keywords: array10().of(string15()).optional().label("Keywords")
|
|
863
1204
|
}).nullable().optional().label("SEO Tags"),
|
|
864
|
-
jdSummary:
|
|
1205
|
+
jdSummary: string15().optional().label("JD Summary"),
|
|
865
1206
|
/**
|
|
866
1207
|
* Structured, model-extracted sections of the posting, re-organized into clean
|
|
867
1208
|
* bullet points. This is our OWN unique presentation of the job (rendered as the
|
|
@@ -870,28 +1211,28 @@ var JobSchema = object18({
|
|
|
870
1211
|
* optional: absent on jobs not yet (re-)enriched, and any section is `[]`/omitted
|
|
871
1212
|
* when the posting genuinely has none.
|
|
872
1213
|
*/
|
|
873
|
-
jobHighlights:
|
|
874
|
-
responsibilities:
|
|
875
|
-
requirements:
|
|
876
|
-
benefits:
|
|
877
|
-
qualifications:
|
|
1214
|
+
jobHighlights: object19({
|
|
1215
|
+
responsibilities: array10().of(string15()).optional().label("Responsibilities"),
|
|
1216
|
+
requirements: array10().of(string15()).optional().label("Requirements"),
|
|
1217
|
+
benefits: array10().of(string15()).optional().label("Benefits"),
|
|
1218
|
+
qualifications: array10().of(string15()).optional().label("Qualifications")
|
|
878
1219
|
}).nullable().optional().label("Job Highlights"),
|
|
879
|
-
canCreateAlert:
|
|
880
|
-
canDirectApply:
|
|
881
|
-
hasApplied:
|
|
882
|
-
isOwner:
|
|
883
|
-
hasBookmarked:
|
|
884
|
-
hasReported:
|
|
885
|
-
ratePerHour:
|
|
886
|
-
isPromoted:
|
|
887
|
-
salaryRange:
|
|
888
|
-
currency:
|
|
889
|
-
min:
|
|
890
|
-
max:
|
|
891
|
-
compensationType:
|
|
892
|
-
isNegotiable:
|
|
1220
|
+
canCreateAlert: boolean12().optional().label("Can create alert"),
|
|
1221
|
+
canDirectApply: boolean12().optional().label("Can direct apply"),
|
|
1222
|
+
hasApplied: boolean12().optional().label("Has applied"),
|
|
1223
|
+
isOwner: boolean12().optional().label("Is owner"),
|
|
1224
|
+
hasBookmarked: boolean12().optional().label("Has bookmarked"),
|
|
1225
|
+
hasReported: boolean12().optional().label("Has reported"),
|
|
1226
|
+
ratePerHour: number7().optional().min(0).label("Rate per hour"),
|
|
1227
|
+
isPromoted: boolean12().optional().label("Is promoted"),
|
|
1228
|
+
salaryRange: object19({
|
|
1229
|
+
currency: string15().required().label("Currency").default("USD"),
|
|
1230
|
+
min: number7().nullable().optional().min(0).label("Minimum Salary"),
|
|
1231
|
+
max: number7().nullable().optional().min(0).label("Maximum Salary"),
|
|
1232
|
+
compensationType: string15().oneOf(SupportedCompensationTypes).nullable().optional().label("Compensation Type"),
|
|
1233
|
+
isNegotiable: boolean12().nullable().optional().default(true).label("Is Negotiable")
|
|
893
1234
|
}).nullable().optional().label("Salary Range"),
|
|
894
|
-
reports:
|
|
1235
|
+
reports: array10().of(UserIdAndCreatedAtSchema).optional().label("Reports"),
|
|
895
1236
|
// Taxonomy fields are constants (see job-taxonomy.constant.ts), stored as slugs and
|
|
896
1237
|
// translated for display. They are deliberately NOT `oneOf`-constrained here: a value
|
|
897
1238
|
// outside the taxonomy must be DROPPED, never a reason to reject the posting. Yup
|
|
@@ -904,17 +1245,25 @@ var JobSchema = object18({
|
|
|
904
1245
|
// time (values get renamed, retired, added), so stored jobs will always outlive the
|
|
905
1246
|
// enum — being lenient here is what lets the taxonomy evolve without a migration
|
|
906
1247
|
// gate on every write.
|
|
907
|
-
category:
|
|
908
|
-
industry:
|
|
909
|
-
subCategories:
|
|
910
|
-
|
|
911
|
-
|
|
1248
|
+
category: string15().nullable().optional().label("Category"),
|
|
1249
|
+
industry: string15().nullable().optional().label("Industry"),
|
|
1250
|
+
subCategories: array10().of(string15().trim().required()).nullable().optional().label("Sub Categories"),
|
|
1251
|
+
/**
|
|
1252
|
+
* The taxonomy state `skills[].concept` was resolved against (the service's
|
|
1253
|
+
* `taxonomyVersion`, bumped by every release and rollback); behind the current
|
|
1254
|
+
* version means the concepts may be stale. Written by jobs-service with every
|
|
1255
|
+
* skills write: `null` when that write could not be normalized (taxonomy down
|
|
1256
|
+
* or unconfigured), absent on jobs that predate normalization.
|
|
1257
|
+
*/
|
|
1258
|
+
taxonomyVersion: number7().integer().min(0).nullable().optional().label("Taxonomy Version"),
|
|
1259
|
+
termsAccepted: boolean12().oneOf([true], "Accept terms before proceeding").required("Accept terms before proceeding").label("Terms accepted"),
|
|
1260
|
+
isFeatured: boolean12().optional().default(false).label("Is featured"),
|
|
912
1261
|
/** Market country codes to feature this job in; empty = global. */
|
|
913
|
-
featuredMarkets:
|
|
1262
|
+
featuredMarkets: array10().of(string15().required()).optional().default([]).label("Featured markets")
|
|
914
1263
|
}).concat(DbDefaultSchema).noUnknown().label("Job");
|
|
915
1264
|
|
|
916
1265
|
// src/job/job-filter.schema.ts
|
|
917
|
-
import { boolean as
|
|
1266
|
+
import { boolean as boolean13, number as number8, object as object20, string as string16 } from "yup";
|
|
918
1267
|
|
|
919
1268
|
// src/user/user.constant.ts
|
|
920
1269
|
var UserRole = /* @__PURE__ */ ((UserRole2) => {
|
|
@@ -2102,7 +2451,7 @@ var TAXONOMY_LABELS = {
|
|
|
2102
2451
|
|
|
2103
2452
|
// src/job/job-filter.schema.ts
|
|
2104
2453
|
var GEO_GROUP = "Geo";
|
|
2105
|
-
var JobFilterShape =
|
|
2454
|
+
var JobFilterShape = object20({
|
|
2106
2455
|
// ── Classification ──────────────────────────────────────────────────────────
|
|
2107
2456
|
// Closed vocabularies, sent verbatim and matched exactly: a partial match
|
|
2108
2457
|
// would make "remote" also match a hypothetical "remote_first".
|
|
@@ -2245,8 +2594,8 @@ var JobFilterShape = object19({
|
|
|
2245
2594
|
// ── Flags ───────────────────────────────────────────────────────────────────
|
|
2246
2595
|
// No `.default(false)`: an unchecked box must mean "no constraint", not "only
|
|
2247
2596
|
// the non-featured ones", so absent simply omits the clause.
|
|
2248
|
-
isFeatured:
|
|
2249
|
-
isPromoted:
|
|
2597
|
+
isFeatured: boolean13().optional().label("Featured Only"),
|
|
2598
|
+
isPromoted: boolean13().optional().label("Promoted Only"),
|
|
2250
2599
|
featuredMarkets: tokens("Featured Markets"),
|
|
2251
2600
|
// ── Ranges ──────────────────────────────────────────────────────────────────
|
|
2252
2601
|
/**
|
|
@@ -2257,10 +2606,10 @@ var JobFilterShape = object19({
|
|
|
2257
2606
|
// can be selected and a bound is meaningless across them. Here the currency is
|
|
2258
2607
|
// a single sibling field, so the bound is plain and the currency simply
|
|
2259
2608
|
// narrows which jobs are compared.
|
|
2260
|
-
salary:
|
|
2261
|
-
min:
|
|
2262
|
-
max:
|
|
2263
|
-
currency:
|
|
2609
|
+
salary: object20({
|
|
2610
|
+
min: number8().integer().min(0).optional().default(void 0).label("Salary \u2265"),
|
|
2611
|
+
max: number8().integer().min(0).optional().default(void 0).label("Salary \u2264"),
|
|
2612
|
+
currency: string16().oneOf(SupportedSalaryCurrencies).optional().label("Currency")
|
|
2264
2613
|
}).optional().default(void 0).label("Salary"),
|
|
2265
2614
|
/** Posted within this many days. Relative, so a saved filter does not rot. */
|
|
2266
2615
|
postedWithinDays: days("Posted Within (days)"),
|
|
@@ -2269,7 +2618,7 @@ var JobFilterShape = object19({
|
|
|
2269
2618
|
* relative `postedWithinDays`. EPOCH MS, matching how the field is stored — a
|
|
2270
2619
|
* coerced date string would not compare.
|
|
2271
2620
|
*/
|
|
2272
|
-
createdAt:
|
|
2621
|
+
createdAt: object20({
|
|
2273
2622
|
min: epoch("Posted After"),
|
|
2274
2623
|
max: epoch("Posted Before")
|
|
2275
2624
|
}).optional().default(void 0).label("Posted Between")
|
|
@@ -2323,7 +2672,7 @@ function deriveIndustry(category, subCategories) {
|
|
|
2323
2672
|
}
|
|
2324
2673
|
|
|
2325
2674
|
// src/post/post.schema.ts
|
|
2326
|
-
import { array as
|
|
2675
|
+
import { array as array12, boolean as boolean14, number as number9, object as object21, string as string17 } from "yup";
|
|
2327
2676
|
|
|
2328
2677
|
// src/post/post.constant.ts
|
|
2329
2678
|
var PostStatus = /* @__PURE__ */ ((PostStatus2) => {
|
|
@@ -2335,41 +2684,41 @@ var PostStatus = /* @__PURE__ */ ((PostStatus2) => {
|
|
|
2335
2684
|
var SupportedPostStatuses = Object.values(PostStatus);
|
|
2336
2685
|
|
|
2337
2686
|
// src/post/post.schema.ts
|
|
2338
|
-
var PostSchema =
|
|
2687
|
+
var PostSchema = object21({
|
|
2339
2688
|
/** Headline shown in listings and at the top of the post. */
|
|
2340
|
-
title:
|
|
2689
|
+
title: string17().required().min(5).max(200).label("Title"),
|
|
2341
2690
|
/** User-friendly, unique URL identifier. */
|
|
2342
|
-
slug:
|
|
2691
|
+
slug: string17().required().max(250).label("Slug"),
|
|
2343
2692
|
/** Short summary used in listings and meta description fallback. */
|
|
2344
|
-
excerpt:
|
|
2693
|
+
excerpt: string17().max(500).optional().label("Excerpt"),
|
|
2345
2694
|
/** Rendered HTML source of truth for the post body (sanitized on write/render).
|
|
2346
2695
|
* Supports rich formatting markdown can't express (image size/alignment, etc). */
|
|
2347
|
-
bodyHTML:
|
|
2696
|
+
bodyHTML: string17().required().min(1).label("Body (HTML)"),
|
|
2348
2697
|
/** Optional Markdown mirror of the body (portable text / search fallback).
|
|
2349
2698
|
* Kept for back-compat and plain-text derivation; bodyHTML is authoritative. */
|
|
2350
|
-
bodyMarkdown:
|
|
2699
|
+
bodyMarkdown: string17().optional().label("Body (Markdown)"),
|
|
2351
2700
|
/** Cover/hero image URL. Not `.url()`-validated: the value is either an
|
|
2352
2701
|
* uploaded file URL served by this platform (which may be a bare host like
|
|
2353
2702
|
* `http://localhost:3082/...` in dev, that yup's `.url()` wrongly rejects) or
|
|
2354
2703
|
* an admin-pasted link. Kept as a plain string; empty ⇒ null. */
|
|
2355
|
-
coverImage:
|
|
2704
|
+
coverImage: string17().nullable().optional().label("Cover image"),
|
|
2356
2705
|
/** Author (user id). */
|
|
2357
|
-
authorId:
|
|
2706
|
+
authorId: string17().required().label("Author ID"),
|
|
2358
2707
|
/** Free-form tags for filtering and related-posts. */
|
|
2359
|
-
tags:
|
|
2708
|
+
tags: array12().of(string17().trim().required()).default([]).label("Tags"),
|
|
2360
2709
|
/** Estimated reading time in minutes (server-derived from body length). */
|
|
2361
|
-
readingTimeMinutes:
|
|
2710
|
+
readingTimeMinutes: number9().min(0).optional().label("Reading time (minutes)"),
|
|
2362
2711
|
/** SEO overrides. */
|
|
2363
|
-
seoTags:
|
|
2364
|
-
description:
|
|
2365
|
-
keywords:
|
|
2712
|
+
seoTags: object21({
|
|
2713
|
+
description: string17().optional().label("Description"),
|
|
2714
|
+
keywords: array12().of(string17().required()).optional().label("Keywords")
|
|
2366
2715
|
}).nullable().optional().label("SEO Tags"),
|
|
2367
2716
|
/** When the post was first published (epoch ms). Server-owned. */
|
|
2368
|
-
publishedAt:
|
|
2717
|
+
publishedAt: number9().nullable().optional().label("Published at"),
|
|
2369
2718
|
/** Whether the post is featured in the blog listing. */
|
|
2370
|
-
isFeatured:
|
|
2719
|
+
isFeatured: boolean14().default(false).optional().label("Is featured"),
|
|
2371
2720
|
/** Publication state. */
|
|
2372
|
-
status:
|
|
2721
|
+
status: string17().oneOf(SupportedPostStatuses).default("draft" /* Draft */).required().label("Status")
|
|
2373
2722
|
}).concat(DbDefaultSchema).noUnknown().label("Post");
|
|
2374
2723
|
|
|
2375
2724
|
// src/geo/geo.constant.ts
|
|
@@ -2419,11 +2768,11 @@ var GEO_COLLECTIONS = {
|
|
|
2419
2768
|
var GEO_SEARCH_MAX = 64;
|
|
2420
2769
|
|
|
2421
2770
|
// src/geo/country.schema.ts
|
|
2422
|
-
import { array as
|
|
2423
|
-
var CountrySchema =
|
|
2771
|
+
import { array as array13, number as number10, object as object22, string as string18 } from "yup";
|
|
2772
|
+
var CountrySchema = object22({
|
|
2424
2773
|
/** The upstream dr5hn id. Stable, and the key every upsert matches on. */
|
|
2425
|
-
id:
|
|
2426
|
-
name:
|
|
2774
|
+
id: number10().integer().required().label("ID"),
|
|
2775
|
+
name: string18().trim().required().label("Name"),
|
|
2427
2776
|
/**
|
|
2428
2777
|
* ISO 3166-1 alpha-2, UPPERCASE (`IN`, `SE`).
|
|
2429
2778
|
*
|
|
@@ -2432,34 +2781,34 @@ var CountrySchema = object21({
|
|
|
2432
2781
|
* already clean uppercase alpha-2. A lowercase value here would compare
|
|
2433
2782
|
* unequal to all of them and silently match nothing.
|
|
2434
2783
|
*/
|
|
2435
|
-
countryCode:
|
|
2436
|
-
iso3:
|
|
2437
|
-
numericCode:
|
|
2438
|
-
phonecode:
|
|
2439
|
-
capital:
|
|
2440
|
-
currency:
|
|
2441
|
-
currencyName:
|
|
2442
|
-
currencySymbol:
|
|
2443
|
-
tld:
|
|
2784
|
+
countryCode: string18().trim().uppercase().length(2).required().label("Country Code"),
|
|
2785
|
+
iso3: string18().trim().uppercase().length(3).optional().nullable().label("ISO3"),
|
|
2786
|
+
numericCode: string18().trim().optional().nullable().label("Numeric Code"),
|
|
2787
|
+
phonecode: string18().trim().optional().nullable().label("Phone Code"),
|
|
2788
|
+
capital: string18().trim().optional().nullable().label("Capital"),
|
|
2789
|
+
currency: string18().trim().optional().nullable().label("Currency"),
|
|
2790
|
+
currencyName: string18().trim().optional().nullable().label("Currency Name"),
|
|
2791
|
+
currencySymbol: string18().trim().optional().nullable().label("Currency Symbol"),
|
|
2792
|
+
tld: string18().trim().optional().nullable().label("TLD"),
|
|
2444
2793
|
/** The name in its own script, e.g. "भारत". Stored, but NOT searchable; see `searchByLocale`. */
|
|
2445
|
-
native:
|
|
2446
|
-
population:
|
|
2447
|
-
gdp:
|
|
2448
|
-
region:
|
|
2449
|
-
regionId:
|
|
2450
|
-
subregion:
|
|
2451
|
-
subregionId:
|
|
2452
|
-
nationality:
|
|
2453
|
-
areaSqKm:
|
|
2454
|
-
postalCodeFormat:
|
|
2455
|
-
postalCodeRegex:
|
|
2456
|
-
timezones:
|
|
2457
|
-
|
|
2458
|
-
zoneName:
|
|
2459
|
-
gmtOffset:
|
|
2460
|
-
gmtOffsetName:
|
|
2461
|
-
abbreviation:
|
|
2462
|
-
tzName:
|
|
2794
|
+
native: string18().trim().optional().nullable().label("Native Name"),
|
|
2795
|
+
population: number10().optional().nullable().label("Population"),
|
|
2796
|
+
gdp: number10().optional().nullable().label("GDP"),
|
|
2797
|
+
region: string18().trim().optional().nullable().label("Region"),
|
|
2798
|
+
regionId: number10().integer().optional().nullable().label("Region ID"),
|
|
2799
|
+
subregion: string18().trim().optional().nullable().label("Subregion"),
|
|
2800
|
+
subregionId: number10().integer().optional().nullable().label("Subregion ID"),
|
|
2801
|
+
nationality: string18().trim().optional().nullable().label("Nationality"),
|
|
2802
|
+
areaSqKm: number10().optional().nullable().label("Area (sq km)"),
|
|
2803
|
+
postalCodeFormat: string18().trim().optional().nullable().label("Postal Code Format"),
|
|
2804
|
+
postalCodeRegex: string18().optional().nullable().label("Postal Code Regex"),
|
|
2805
|
+
timezones: array13().of(
|
|
2806
|
+
object22({
|
|
2807
|
+
zoneName: string18().optional().nullable().label("Zone Name"),
|
|
2808
|
+
gmtOffset: number10().optional().nullable().label("GMT Offset"),
|
|
2809
|
+
gmtOffsetName: string18().optional().nullable().label("GMT Offset Name"),
|
|
2810
|
+
abbreviation: string18().optional().nullable().label("Abbreviation"),
|
|
2811
|
+
tzName: string18().optional().nullable().label("TZ Name")
|
|
2463
2812
|
})
|
|
2464
2813
|
).optional().nullable().label("Timezones"),
|
|
2465
2814
|
/**
|
|
@@ -2468,7 +2817,7 @@ var CountrySchema = object21({
|
|
|
2468
2817
|
* declaring it here would turn a new locale into a validation failure. The
|
|
2469
2818
|
* VALUES are split per-locale into `searchByLocale`.
|
|
2470
2819
|
*/
|
|
2471
|
-
translations:
|
|
2820
|
+
translations: object22().optional().nullable().label("Translations"),
|
|
2472
2821
|
/**
|
|
2473
2822
|
* Coordinates as NUMBERS.
|
|
2474
2823
|
*
|
|
@@ -2477,10 +2826,10 @@ var CountrySchema = object21({
|
|
|
2477
2826
|
* `"9" > "10"` is true, so a bounding-box filter would be quietly wrong rather
|
|
2478
2827
|
* than failing loudly.
|
|
2479
2828
|
*/
|
|
2480
|
-
latitude:
|
|
2481
|
-
longitude:
|
|
2482
|
-
emoji:
|
|
2483
|
-
emojiU:
|
|
2829
|
+
latitude: number10().optional().nullable().label("Latitude"),
|
|
2830
|
+
longitude: number10().optional().nullable().label("Longitude"),
|
|
2831
|
+
emoji: string18().optional().nullable().label("Emoji"),
|
|
2832
|
+
emojiU: string18().optional().nullable().label("Emoji Unicode"),
|
|
2484
2833
|
/**
|
|
2485
2834
|
* The name field searched for the DEFAULT (English) locale: the canonical
|
|
2486
2835
|
* `name`, and nothing else.
|
|
@@ -2490,7 +2839,7 @@ var CountrySchema = object21({
|
|
|
2490
2839
|
* field would make every locale's search implicitly a search of all 19
|
|
2491
2840
|
* languages: a French UI searching "Inde" would also match German "Indien".
|
|
2492
2841
|
*/
|
|
2493
|
-
searchDefault:
|
|
2842
|
+
searchDefault: array13().of(string18().required()).optional().default([]).label("Search Default"),
|
|
2494
2843
|
/**
|
|
2495
2844
|
* Per-locale name fields, keyed by lowercased BCP-47 tag (`de`, `pt-br`).
|
|
2496
2845
|
* Each carries ONLY that locale's translation, which is what makes
|
|
@@ -2508,21 +2857,21 @@ var CountrySchema = object21({
|
|
|
2508
2857
|
* it, zh-CN, tr, ru, uk, pl, hi, ar. **`sv` is absent**, so a Swedish search
|
|
2509
2858
|
* matches nothing. That is the accepted cost of strict scoping.
|
|
2510
2859
|
*/
|
|
2511
|
-
searchByLocale:
|
|
2860
|
+
searchByLocale: object22().optional().nullable().label("Search By Locale"),
|
|
2512
2861
|
/** Epoch ms of the run that last wrote this row. Drives the stale-row prune. */
|
|
2513
|
-
syncedAt:
|
|
2862
|
+
syncedAt: number10().optional().nullable().label("Synced At")
|
|
2514
2863
|
}).label("Country");
|
|
2515
2864
|
|
|
2516
2865
|
// src/geo/state.schema.ts
|
|
2517
|
-
import { array as
|
|
2518
|
-
var StateSchema =
|
|
2866
|
+
import { array as array14, number as number11, object as object23, string as string19 } from "yup";
|
|
2867
|
+
var StateSchema = object23({
|
|
2519
2868
|
/** The upstream dr5hn id. Stable, and the key every upsert matches on. */
|
|
2520
|
-
id:
|
|
2521
|
-
name:
|
|
2522
|
-
countryId:
|
|
2869
|
+
id: number11().integer().required().label("ID"),
|
|
2870
|
+
name: string19().trim().required().label("Name"),
|
|
2871
|
+
countryId: number11().integer().optional().nullable().label("Country ID"),
|
|
2523
2872
|
/** ISO 3166-1 alpha-2 of the parent, UPPERCASE. See `CountrySchema.countryCode`. */
|
|
2524
|
-
countryCode:
|
|
2525
|
-
countryName:
|
|
2873
|
+
countryCode: string19().trim().uppercase().length(2).required().label("Country Code"),
|
|
2874
|
+
countryName: string19().trim().optional().nullable().label("Country Name"),
|
|
2526
2875
|
/**
|
|
2527
2876
|
* The BARE subdivision code, e.g. `KA` (upstream `iso2`).
|
|
2528
2877
|
*
|
|
@@ -2534,22 +2883,22 @@ var StateSchema = object22({
|
|
|
2534
2883
|
* both are stored so the migration has its destination present before any
|
|
2535
2884
|
* consumer moves.
|
|
2536
2885
|
*/
|
|
2537
|
-
stateCode:
|
|
2886
|
+
stateCode: string19().trim().uppercase().optional().nullable().label("State Code"),
|
|
2538
2887
|
/** Fully-qualified ISO 3166-2, e.g. `IN-KA` (upstream `iso3166_2`). */
|
|
2539
|
-
stateCodeIso:
|
|
2540
|
-
fipsCode:
|
|
2888
|
+
stateCodeIso: string19().trim().uppercase().optional().nullable().label("ISO 3166-2 Code"),
|
|
2889
|
+
fipsCode: string19().trim().optional().nullable().label("FIPS Code"),
|
|
2541
2890
|
/** Upstream's own word for the subdivision: "province", "state", "district", … */
|
|
2542
|
-
type:
|
|
2543
|
-
level:
|
|
2544
|
-
parentId:
|
|
2891
|
+
type: string19().trim().optional().nullable().label("Type"),
|
|
2892
|
+
level: number11().integer().optional().nullable().label("Level"),
|
|
2893
|
+
parentId: number11().integer().optional().nullable().label("Parent ID"),
|
|
2545
2894
|
/** The name in its own script. Stored, but NOT searchable; see `searchByLocale`. */
|
|
2546
|
-
native:
|
|
2895
|
+
native: string19().trim().optional().nullable().label("Native Name"),
|
|
2547
2896
|
/** Numbers, not the strings upstream ships. See `CountrySchema.latitude`. */
|
|
2548
|
-
latitude:
|
|
2549
|
-
longitude:
|
|
2550
|
-
timezone:
|
|
2897
|
+
latitude: number11().optional().nullable().label("Latitude"),
|
|
2898
|
+
longitude: number11().optional().nullable().label("Longitude"),
|
|
2899
|
+
timezone: string19().trim().optional().nullable().label("Timezone"),
|
|
2551
2900
|
/** Localized names keyed by locale. Unshaped; see `CountrySchema.translations`. */
|
|
2552
|
-
translations:
|
|
2901
|
+
translations: object23().optional().nullable().label("Translations"),
|
|
2553
2902
|
/**
|
|
2554
2903
|
* The name field searched for the DEFAULT (English) locale: the canonical
|
|
2555
2904
|
* `name`, and nothing else.
|
|
@@ -2559,7 +2908,7 @@ var StateSchema = object22({
|
|
|
2559
2908
|
* field would make every locale's search implicitly a search of all 19
|
|
2560
2909
|
* languages: a French UI searching "Inde" would also match German "Indien".
|
|
2561
2910
|
*/
|
|
2562
|
-
searchDefault:
|
|
2911
|
+
searchDefault: array14().of(string19().required()).optional().default([]).label("Search Default"),
|
|
2563
2912
|
/**
|
|
2564
2913
|
* Per-locale name fields, keyed by lowercased BCP-47 tag (`de`, `pt-br`).
|
|
2565
2914
|
* Each carries ONLY that locale's translation, which is what makes
|
|
@@ -2577,20 +2926,20 @@ var StateSchema = object22({
|
|
|
2577
2926
|
* it, zh-CN, tr, ru, uk, pl, hi, ar. **`sv` is absent**, so a Swedish search
|
|
2578
2927
|
* matches nothing. That is the accepted cost of strict scoping.
|
|
2579
2928
|
*/
|
|
2580
|
-
searchByLocale:
|
|
2929
|
+
searchByLocale: object23().optional().nullable().label("Search By Locale"),
|
|
2581
2930
|
/** Epoch ms of the run that last wrote this row. Drives the stale-row prune. */
|
|
2582
|
-
syncedAt:
|
|
2931
|
+
syncedAt: number11().optional().nullable().label("Synced At")
|
|
2583
2932
|
}).label("State");
|
|
2584
2933
|
|
|
2585
2934
|
// src/geo/city.schema.ts
|
|
2586
|
-
import { array as
|
|
2587
|
-
var CitySchema =
|
|
2935
|
+
import { array as array15, number as number12, object as object24, string as string20 } from "yup";
|
|
2936
|
+
var CitySchema = object24({
|
|
2588
2937
|
/** The upstream dr5hn id. Stable, and the key every upsert matches on. */
|
|
2589
|
-
id:
|
|
2590
|
-
name:
|
|
2591
|
-
stateId:
|
|
2938
|
+
id: number12().integer().required().label("ID"),
|
|
2939
|
+
name: string20().trim().required().label("Name"),
|
|
2940
|
+
stateId: number12().integer().optional().nullable().label("State ID"),
|
|
2592
2941
|
/** The BARE subdivision code. Only meaningful paired with `countryCode`; see `StateSchema`. */
|
|
2593
|
-
stateCode:
|
|
2942
|
+
stateCode: string20().trim().uppercase().optional().nullable().label("State Code"),
|
|
2594
2943
|
/**
|
|
2595
2944
|
* Fully-qualified ISO 3166-2, e.g. `IN-KA`.
|
|
2596
2945
|
*
|
|
@@ -2600,29 +2949,29 @@ var CitySchema = object23({
|
|
|
2600
2949
|
* migration can re-point the cities route without a 153k-row re-ingest.
|
|
2601
2950
|
* Null when either half is missing.
|
|
2602
2951
|
*/
|
|
2603
|
-
stateCodeIso:
|
|
2604
|
-
stateName:
|
|
2605
|
-
countryId:
|
|
2952
|
+
stateCodeIso: string20().trim().uppercase().optional().nullable().label("ISO 3166-2 Code"),
|
|
2953
|
+
stateName: string20().trim().optional().nullable().label("State Name"),
|
|
2954
|
+
countryId: number12().integer().optional().nullable().label("Country ID"),
|
|
2606
2955
|
/** ISO 3166-1 alpha-2 of the parent, UPPERCASE. See `CountrySchema.countryCode`. */
|
|
2607
|
-
countryCode:
|
|
2608
|
-
countryName:
|
|
2956
|
+
countryCode: string20().trim().uppercase().length(2).required().label("Country Code"),
|
|
2957
|
+
countryName: string20().trim().optional().nullable().label("Country Name"),
|
|
2609
2958
|
/** Numbers, not the strings upstream ships. See `CountrySchema.latitude`. */
|
|
2610
|
-
latitude:
|
|
2611
|
-
longitude:
|
|
2959
|
+
latitude: number12().optional().nullable().label("Latitude"),
|
|
2960
|
+
longitude: number12().optional().nullable().label("Longitude"),
|
|
2612
2961
|
/** The name in its own script. Stored, but NOT searchable; see `searchByLocale`. */
|
|
2613
|
-
native:
|
|
2614
|
-
type:
|
|
2615
|
-
level:
|
|
2616
|
-
parentId:
|
|
2962
|
+
native: string20().trim().optional().nullable().label("Native Name"),
|
|
2963
|
+
type: string20().trim().optional().nullable().label("Type"),
|
|
2964
|
+
level: number12().integer().optional().nullable().label("Level"),
|
|
2965
|
+
parentId: number12().integer().optional().nullable().label("Parent ID"),
|
|
2617
2966
|
/**
|
|
2618
2967
|
* Null on most rows. Worth keeping (it is a good relevance signal when
|
|
2619
2968
|
* present) but never worth SORTING by alone, since a null-heavy sort buries
|
|
2620
2969
|
* every city upstream has no figure for.
|
|
2621
2970
|
*/
|
|
2622
|
-
population:
|
|
2623
|
-
timezone:
|
|
2971
|
+
population: number12().optional().nullable().label("Population"),
|
|
2972
|
+
timezone: string20().trim().optional().nullable().label("Timezone"),
|
|
2624
2973
|
/** Localized names keyed by locale. Unshaped; see `CountrySchema.translations`. */
|
|
2625
|
-
translations:
|
|
2974
|
+
translations: object24().optional().nullable().label("Translations"),
|
|
2626
2975
|
/**
|
|
2627
2976
|
* The name field searched for the DEFAULT (English) locale: the canonical
|
|
2628
2977
|
* `name`, and nothing else.
|
|
@@ -2632,7 +2981,7 @@ var CitySchema = object23({
|
|
|
2632
2981
|
* field would make every locale's search implicitly a search of all 19
|
|
2633
2982
|
* languages: a French UI searching "Inde" would also match German "Indien".
|
|
2634
2983
|
*/
|
|
2635
|
-
searchDefault:
|
|
2984
|
+
searchDefault: array15().of(string20().required()).optional().default([]).label("Search Default"),
|
|
2636
2985
|
/**
|
|
2637
2986
|
* Per-locale name fields, keyed by lowercased BCP-47 tag (`de`, `pt-br`).
|
|
2638
2987
|
* Each carries ONLY that locale's translation, which is what makes
|
|
@@ -2650,14 +2999,14 @@ var CitySchema = object23({
|
|
|
2650
2999
|
* it, zh-CN, tr, ru, uk, pl, hi, ar. **`sv` is absent**, so a Swedish search
|
|
2651
3000
|
* matches nothing. That is the accepted cost of strict scoping.
|
|
2652
3001
|
*/
|
|
2653
|
-
searchByLocale:
|
|
3002
|
+
searchByLocale: object24().optional().nullable().label("Search By Locale"),
|
|
2654
3003
|
/** Epoch ms of the run that last wrote this row. Drives the stale-row prune. */
|
|
2655
|
-
syncedAt:
|
|
3004
|
+
syncedAt: number12().optional().nullable().label("Synced At")
|
|
2656
3005
|
}).label("City");
|
|
2657
3006
|
|
|
2658
3007
|
// src/geo/country-filter.schema.ts
|
|
2659
|
-
import { object as
|
|
2660
|
-
var CountryFilterShape =
|
|
3008
|
+
import { object as object25 } from "yup";
|
|
3009
|
+
var CountryFilterShape = object25({
|
|
2661
3010
|
/** ISO 3166-1 alpha-2 codes, e.g. `IN`. Uppercased, matching how they are stored. */
|
|
2662
3011
|
countryCodes: codeTokens("Country Codes"),
|
|
2663
3012
|
/** ISO 3166-1 alpha-3 codes, e.g. `IND`. */
|
|
@@ -2677,8 +3026,8 @@ var CountryFilterSchema = rejectUnknownKeys(
|
|
|
2677
3026
|
);
|
|
2678
3027
|
|
|
2679
3028
|
// src/geo/state-filter.schema.ts
|
|
2680
|
-
import { object as
|
|
2681
|
-
var StateFilterShape =
|
|
3029
|
+
import { object as object26 } from "yup";
|
|
3030
|
+
var StateFilterShape = object26({
|
|
2682
3031
|
/** ISO 3166-1 alpha-2 of the parent country, e.g. `IN`. */
|
|
2683
3032
|
countryCodes: codeTokens("Country Codes"),
|
|
2684
3033
|
/**
|
|
@@ -2708,8 +3057,8 @@ var StateFilterSchema = rejectUnknownKeys(
|
|
|
2708
3057
|
);
|
|
2709
3058
|
|
|
2710
3059
|
// src/geo/city-filter.schema.ts
|
|
2711
|
-
import { object as
|
|
2712
|
-
var CityFilterShape =
|
|
3060
|
+
import { object as object27 } from "yup";
|
|
3061
|
+
var CityFilterShape = object27({
|
|
2713
3062
|
/** ISO 3166-1 alpha-2 of the parent country, e.g. `IN`. */
|
|
2714
3063
|
countryCodes: codeTokens("Country Codes"),
|
|
2715
3064
|
/**
|
|
@@ -2726,28 +3075,28 @@ var CityFilterSchema = rejectUnknownKeys(
|
|
|
2726
3075
|
);
|
|
2727
3076
|
|
|
2728
3077
|
// src/geo/geo-sync.schema.ts
|
|
2729
|
-
import { boolean as
|
|
2730
|
-
var GeoSyncCountsSchema =
|
|
2731
|
-
read:
|
|
2732
|
-
upserted:
|
|
2733
|
-
modified:
|
|
2734
|
-
matched:
|
|
3078
|
+
import { boolean as boolean15, mixed as mixed4, number as number13, object as object28, string as string21 } from "yup";
|
|
3079
|
+
var GeoSyncCountsSchema = object28({
|
|
3080
|
+
read: number13().integer().min(0).default(0).label("Read"),
|
|
3081
|
+
upserted: number13().integer().min(0).default(0).label("Upserted"),
|
|
3082
|
+
modified: number13().integer().min(0).default(0).label("Modified"),
|
|
3083
|
+
matched: number13().integer().min(0).default(0).label("Matched"),
|
|
2735
3084
|
/** Rows removed because upstream dropped them. See `prunedSkipped`. */
|
|
2736
|
-
pruned:
|
|
3085
|
+
pruned: number13().integer().min(0).default(0).label("Pruned"),
|
|
2737
3086
|
/**
|
|
2738
3087
|
* True when the stale-row prune was REFUSED because it would have removed more
|
|
2739
3088
|
* than its safety threshold of the collection. A partial fetch that looked
|
|
2740
3089
|
* like a success must not be able to empty the table, so the run reports the
|
|
2741
3090
|
* refusal rather than acting on it.
|
|
2742
3091
|
*/
|
|
2743
|
-
prunedSkipped:
|
|
3092
|
+
prunedSkipped: boolean15().default(false).label("Prune Skipped")
|
|
2744
3093
|
}).label("Sync Counts");
|
|
2745
|
-
var GeoSyncRunSchema =
|
|
2746
|
-
jobId:
|
|
3094
|
+
var GeoSyncRunSchema = object28({
|
|
3095
|
+
jobId: string21().required().label("Job ID"),
|
|
2747
3096
|
status: mixed4().oneOf(SupportedGeoSyncStatuses).required().label("Status"),
|
|
2748
3097
|
trigger: mixed4().oneOf(SupportedGeoSyncTriggers).optional().label("Trigger"),
|
|
2749
3098
|
/** Whether the caller asked to run even though the release tag was unchanged. */
|
|
2750
|
-
force:
|
|
3099
|
+
force: boolean15().default(false).label("Force"),
|
|
2751
3100
|
/**
|
|
2752
3101
|
* The upstream release tag this run fetched, e.g. `v3.2-export.7`.
|
|
2753
3102
|
*
|
|
@@ -2755,12 +3104,12 @@ var GeoSyncRunSchema = object27({
|
|
|
2755
3104
|
* cannot tell what version it is fetching is otherwise a failure, not a
|
|
2756
3105
|
* refresh, so it is not allowed to proceed unattended.
|
|
2757
3106
|
*/
|
|
2758
|
-
releaseTag:
|
|
3107
|
+
releaseTag: string21().optional().nullable().label("Release Tag"),
|
|
2759
3108
|
/** The tag of the last successful run, i.e. what this one is replacing. */
|
|
2760
|
-
previousReleaseTag:
|
|
2761
|
-
startedAt:
|
|
2762
|
-
finishedAt:
|
|
2763
|
-
durationMs:
|
|
3109
|
+
previousReleaseTag: string21().optional().nullable().label("Previous Release Tag"),
|
|
3110
|
+
startedAt: number13().required().label("Started At"),
|
|
3111
|
+
finishedAt: number13().optional().nullable().label("Finished At"),
|
|
3112
|
+
durationMs: number13().optional().nullable().label("Duration (ms)"),
|
|
2764
3113
|
phase: mixed4().oneOf(SupportedGeoSyncPhases).optional().nullable().label("Phase"),
|
|
2765
3114
|
/**
|
|
2766
3115
|
* Live progress for the dashboard bar.
|
|
@@ -2769,25 +3118,25 @@ var GeoSyncRunSchema = object27({
|
|
|
2769
3118
|
* collection, or a hardcoded fallback on the very first run, since the true
|
|
2770
3119
|
* total is not known until the stream ends. The UI should render it as one.
|
|
2771
3120
|
*/
|
|
2772
|
-
progress:
|
|
2773
|
-
collection:
|
|
2774
|
-
processed:
|
|
2775
|
-
total:
|
|
3121
|
+
progress: object28({
|
|
3122
|
+
collection: string21().optional().nullable().label("Collection"),
|
|
3123
|
+
processed: number13().integer().min(0).default(0).label("Processed"),
|
|
3124
|
+
total: number13().integer().min(0).optional().nullable().label("Total")
|
|
2776
3125
|
}).optional().nullable().label("Progress"),
|
|
2777
|
-
counts:
|
|
3126
|
+
counts: object28({
|
|
2778
3127
|
countries: GeoSyncCountsSchema.optional().nullable().label("Countries"),
|
|
2779
3128
|
states: GeoSyncCountsSchema.optional().nullable().label("States"),
|
|
2780
3129
|
cities: GeoSyncCountsSchema.optional().nullable().label("Cities")
|
|
2781
3130
|
}).optional().nullable().label("Counts"),
|
|
2782
3131
|
/** Why a `skipped` run was skipped, in words the dashboard can show verbatim. */
|
|
2783
|
-
reason:
|
|
3132
|
+
reason: string21().optional().nullable().label("Reason"),
|
|
2784
3133
|
/** The failure message on a `failed` run. Surfaced verbatim to the admin. */
|
|
2785
|
-
error:
|
|
3134
|
+
error: string21().optional().nullable().label("Error")
|
|
2786
3135
|
}).label("Geo Sync Run");
|
|
2787
3136
|
|
|
2788
3137
|
// src/language/language-filter.schema.ts
|
|
2789
|
-
import { object as
|
|
2790
|
-
var LanguageFilterShape =
|
|
3138
|
+
import { object as object29 } from "yup";
|
|
3139
|
+
var LanguageFilterShape = object29({
|
|
2791
3140
|
/** Language names, matched exactly. Free-text matching is `?search=`. */
|
|
2792
3141
|
names: tokens("Names")
|
|
2793
3142
|
}).label("Language Filter");
|
|
@@ -2797,8 +3146,8 @@ var LanguageFilterSchema = rejectUnknownKeys(
|
|
|
2797
3146
|
);
|
|
2798
3147
|
|
|
2799
3148
|
// src/page/page-filter.schema.ts
|
|
2800
|
-
import { boolean as
|
|
2801
|
-
var PageFilterShape =
|
|
3149
|
+
import { boolean as boolean16, object as object30 } from "yup";
|
|
3150
|
+
var PageFilterShape = object30({
|
|
2802
3151
|
/**
|
|
2803
3152
|
* `type`, NOT `pageType`.
|
|
2804
3153
|
*
|
|
@@ -2818,7 +3167,7 @@ var PageFilterShape = object29({
|
|
|
2818
3167
|
// No `.default(false)`: absent means no constraint. Note `isFeatured` is
|
|
2819
3168
|
// present on only 55 documents, so combining it with `status: ['published']`
|
|
2820
3169
|
// leaves 11 pages — a legitimate filter that returns almost nothing.
|
|
2821
|
-
isFeatured:
|
|
3170
|
+
isFeatured: boolean16().optional().label("Featured Only"),
|
|
2822
3171
|
/** Lowercase (`in`, `se`, `ww`), like groups. See `GroupFilterSchema`. */
|
|
2823
3172
|
featuredMarkets: tokens("Featured Markets"),
|
|
2824
3173
|
/** Page SLUGS. A company is matched by slug: a display name breaks on rename. */
|
|
@@ -2831,7 +3180,7 @@ var PageFilterSchema = rejectUnknownKeys(
|
|
|
2831
3180
|
);
|
|
2832
3181
|
|
|
2833
3182
|
// src/marketing/marketing.schema.ts
|
|
2834
|
-
import { array as
|
|
3183
|
+
import { array as array17, boolean as boolean18, lazy as lazy2, mixed as mixed5, number as number15, object as object32, string as string23 } from "yup";
|
|
2835
3184
|
|
|
2836
3185
|
// src/marketing/marketing.constant.ts
|
|
2837
3186
|
var CampaignStatus = /* @__PURE__ */ ((CampaignStatus2) => {
|
|
@@ -2908,8 +3257,8 @@ var SupportedOccurrenceStatuses = Object.values(OccurrenceStatus);
|
|
|
2908
3257
|
var CAMPAIGN_MAX_RECIPIENTS_CEILING = 5e3;
|
|
2909
3258
|
|
|
2910
3259
|
// src/user/user-filter.schema.ts
|
|
2911
|
-
import { array as
|
|
2912
|
-
var UserFilterBranchShape =
|
|
3260
|
+
import { array as array16, boolean as boolean17, number as number14, object as object31, string as string22 } from "yup";
|
|
3261
|
+
var UserFilterBranchShape = object31({
|
|
2913
3262
|
/**
|
|
2914
3263
|
* Exact email addresses. An IDENTITY lookup, not a search.
|
|
2915
3264
|
*
|
|
@@ -2929,7 +3278,7 @@ var UserFilterBranchShape = object30({
|
|
|
2929
3278
|
* the input keeps the match an indexed equality instead of a regex that would
|
|
2930
3279
|
* put the scan straight back.
|
|
2931
3280
|
*/
|
|
2932
|
-
emails:
|
|
3281
|
+
emails: array16().of(string22().required()).optional().default([]).label("Email Addresses"),
|
|
2933
3282
|
/**
|
|
2934
3283
|
* Better Auth account ids. An IDENTITY lookup like `emails`, and for the same
|
|
2935
3284
|
* reason: the caller already knows the exact value.
|
|
@@ -2948,9 +3297,9 @@ var UserFilterBranchShape = object30({
|
|
|
2948
3297
|
* The admin filter panel builds its controls explicitly rather than from this
|
|
2949
3298
|
* shape, so declaring it here does not put an account-id box in the UI.
|
|
2950
3299
|
*/
|
|
2951
|
-
authAccountIds:
|
|
3300
|
+
authAccountIds: array16().of(string22().required()).optional().default([]).label("Auth Account IDs"),
|
|
2952
3301
|
// ── Enum facets (closed vocabularies, chip pickers) ─────────────────────────
|
|
2953
|
-
countries:
|
|
3302
|
+
countries: array16().of(string22().required()).optional().default([]).label("Countries"),
|
|
2954
3303
|
roles: enumFacet(SupportedUserRoles, "Roles"),
|
|
2955
3304
|
// The user's own current seniority (UserSchema.experienceLevel).
|
|
2956
3305
|
experienceLevels: enumFacet(SupportedExperienceLevels, "Experience Levels"),
|
|
@@ -3083,12 +3432,12 @@ var UserFilterBranchShape = object30({
|
|
|
3083
3432
|
// it, so the dependency is stated rather than assumed.
|
|
3084
3433
|
minSalaryFloor: currencyBound("Min Salary \u2265", "salaryCurrencies"),
|
|
3085
3434
|
minSalaryCeil: currencyBound("Min Salary \u2264", "salaryCurrencies"),
|
|
3086
|
-
openToWorkOnly:
|
|
3087
|
-
remoteExperienceOnly:
|
|
3088
|
-
hasResumeOnly:
|
|
3089
|
-
onboardingCompletedOnly:
|
|
3090
|
-
emailVerifiedOnly:
|
|
3091
|
-
mobileVerifiedOnly:
|
|
3435
|
+
openToWorkOnly: boolean17().optional().default(false).label("Open to Work Only"),
|
|
3436
|
+
remoteExperienceOnly: boolean17().optional().default(false).label("Has Remote Experience"),
|
|
3437
|
+
hasResumeOnly: boolean17().optional().default(false).label("Has Resume"),
|
|
3438
|
+
onboardingCompletedOnly: boolean17().optional().default(false).label("Onboarding Completed"),
|
|
3439
|
+
emailVerifiedOnly: boolean17().optional().default(false).label("Email Verified Only"),
|
|
3440
|
+
mobileVerifiedOnly: boolean17().optional().default(false).label("Mobile Verified Only"),
|
|
3092
3441
|
// ── Lifecycle windows ───────────────────────────────────────────────────────
|
|
3093
3442
|
// Relative, because a saved list is resolved fresh on every send: a stored
|
|
3094
3443
|
// absolute epoch would freeze at authoring time and the audience would decay
|
|
@@ -3116,10 +3465,10 @@ var UserFilterBranchShape = object30({
|
|
|
3116
3465
|
// Radius search around a point, against location.geo. All three required
|
|
3117
3466
|
// together; validated as a group rather than field-by-field so a half-filled
|
|
3118
3467
|
// radius cannot silently match everyone.
|
|
3119
|
-
withinRadius:
|
|
3120
|
-
lat:
|
|
3121
|
-
lng:
|
|
3122
|
-
km:
|
|
3468
|
+
withinRadius: object31({
|
|
3469
|
+
lat: number14().min(-90).max(90).required().label("Latitude"),
|
|
3470
|
+
lng: number14().min(-180).max(180).required().label("Longitude"),
|
|
3471
|
+
km: number14().moreThan(0).max(2e4).required().label("Radius (km)")
|
|
3123
3472
|
}).optional().default(void 0).label("Within Radius"),
|
|
3124
3473
|
// ── Signup context (immutable market / locale) ──────────────────────────────
|
|
3125
3474
|
signupCountries: tokens("Signup Countries"),
|
|
@@ -3142,7 +3491,7 @@ var UserFilterBranchShape = object30({
|
|
|
3142
3491
|
// materialise the second case on every list that never chose it.
|
|
3143
3492
|
//
|
|
3144
3493
|
// @todo CONSENT-FILTER-ENFORCEMENT — nothing enforces consent anywhere now.
|
|
3145
|
-
marketingSubscribed:
|
|
3494
|
+
marketingSubscribed: boolean17().optional().label("Marketing Subscribed"),
|
|
3146
3495
|
jobAlertFrequencies: enumFacet(
|
|
3147
3496
|
SupportedJobAlertFrequencies,
|
|
3148
3497
|
"Job Alert Frequency"
|
|
@@ -3163,7 +3512,7 @@ var UserFilterBranchShape = object30({
|
|
|
3163
3512
|
),
|
|
3164
3513
|
// ── Tenure / recency ────────────────────────────────────────────────────────
|
|
3165
3514
|
// Against workExperiences[].duration and educations[].duration ("YYYY-MM").
|
|
3166
|
-
currentlyEmployed:
|
|
3515
|
+
currentlyEmployed: boolean17().optional().default(false).label("Currently Employed"),
|
|
3167
3516
|
graduatedWithinMonths: months("Graduated Within (months)"),
|
|
3168
3517
|
skillUsedWithinMonths: months("Skill Used Within (months)"),
|
|
3169
3518
|
// The ABSOLUTE bounds the three relative windows above resolve into
|
|
@@ -3176,13 +3525,13 @@ var UserFilterBranchShape = object30({
|
|
|
3176
3525
|
// meaning that forever, while "within 18 months" keeps meaning what the admin
|
|
3177
3526
|
// intended. They are declared because the vocabulary must be complete, not
|
|
3178
3527
|
// because a list should store one.
|
|
3179
|
-
graduatedAfter:
|
|
3180
|
-
skillUsedAfter:
|
|
3528
|
+
graduatedAfter: string22().trim().optional().label("Graduated After"),
|
|
3529
|
+
skillUsedAfter: string22().trim().optional().label("Skill Used After"),
|
|
3181
3530
|
// ── Profile richness ────────────────────────────────────────────────────────
|
|
3182
|
-
hasImage:
|
|
3183
|
-
hasHeadline:
|
|
3184
|
-
hasAboutMe:
|
|
3185
|
-
hasMobile:
|
|
3531
|
+
hasImage: boolean17().optional().default(false).label("Has Photo"),
|
|
3532
|
+
hasHeadline: boolean17().optional().default(false).label("Has Headline"),
|
|
3533
|
+
hasAboutMe: boolean17().optional().default(false).label("Has About Me"),
|
|
3534
|
+
hasMobile: boolean17().optional().default(false).label("Has Mobile Number"),
|
|
3186
3535
|
// Segment by WHICH profile section is missing (profileCompleteness.missing[]),
|
|
3187
3536
|
// rather than only by the overall percentage.
|
|
3188
3537
|
missingSections: tokens("Missing Profile Sections"),
|
|
@@ -3194,8 +3543,8 @@ var UserFilterBranchShape = object30({
|
|
|
3194
3543
|
// data lives in other services' collections. Tri-state: `false` is a real
|
|
3195
3544
|
// filter ("has NO job alert"), which is the audience an alert nudge wants, so
|
|
3196
3545
|
// these are `undefined` when unset rather than defaulting to false.
|
|
3197
|
-
hasJobAlert:
|
|
3198
|
-
hasApplied:
|
|
3546
|
+
hasJobAlert: boolean17().optional().default(void 0).label("Has a Job Alert"),
|
|
3547
|
+
hasApplied: boolean17().optional().default(void 0).label("Has Applied"),
|
|
3199
3548
|
appliedWithinDays: days("Applied Within (days)")
|
|
3200
3549
|
// `search` is NOT here. It is free text over name/email, not a facet: it names
|
|
3201
3550
|
// no field on a user document, user-service treats it as a RESERVED PARAM
|
|
@@ -3208,25 +3557,25 @@ var BRANCH_KEYS = Object.keys(UserFilterBranchShape.fields);
|
|
|
3208
3557
|
var UserFilterBranch = rejectUnknownKeys(UserFilterBranchShape, () => BRANCH_KEYS);
|
|
3209
3558
|
var UserFilterSchema = rejectUnknownKeys(
|
|
3210
3559
|
UserFilterBranchShape.shape({
|
|
3211
|
-
or:
|
|
3560
|
+
or: array16().of(UserFilterBranch).optional().default([]).label("Or Any Of")
|
|
3212
3561
|
}).label("User Filter"),
|
|
3213
3562
|
() => [...BRANCH_KEYS, "or"]
|
|
3214
3563
|
);
|
|
3215
3564
|
|
|
3216
3565
|
// src/marketing/marketing.schema.ts
|
|
3217
3566
|
var MailingListFilterSchema = UserFilterSchema;
|
|
3218
|
-
var MailingListSchema =
|
|
3219
|
-
name:
|
|
3220
|
-
description:
|
|
3567
|
+
var MailingListSchema = object32({
|
|
3568
|
+
name: string23().required().min(1).max(120).label("Name"),
|
|
3569
|
+
description: string23().optional().max(500).label("Description"),
|
|
3221
3570
|
filter: MailingListFilterSchema.default(
|
|
3222
3571
|
() => MailingListFilterSchema.getDefault()
|
|
3223
3572
|
)
|
|
3224
3573
|
}).label("Mailing List");
|
|
3225
|
-
var CampaignTriggerSchema =
|
|
3226
|
-
kind:
|
|
3574
|
+
var CampaignTriggerSchema = object32({
|
|
3575
|
+
kind: string23().oneOf(SupportedCampaignTriggerKinds).required().default("manual" /* Manual */).label("Trigger"),
|
|
3227
3576
|
// IANA zone, e.g. "Asia/Kolkata". Local wall-clock times are interpreted in it,
|
|
3228
3577
|
// so occurrences land at the intended hour across DST rather than drifting.
|
|
3229
|
-
timezone:
|
|
3578
|
+
timezone: string23().optional().default("UTC").label("Timezone").when("kind", {
|
|
3230
3579
|
is: (k) => k !== "manual" /* Manual */,
|
|
3231
3580
|
then: (s) => s.required()
|
|
3232
3581
|
}),
|
|
@@ -3240,26 +3589,26 @@ var CampaignTriggerSchema = object31({
|
|
|
3240
3589
|
is: "schedule" /* Schedule */,
|
|
3241
3590
|
then: (s) => s.required()
|
|
3242
3591
|
}),
|
|
3243
|
-
interval:
|
|
3244
|
-
every:
|
|
3245
|
-
unit:
|
|
3592
|
+
interval: object32({
|
|
3593
|
+
every: number15().integer().min(1).max(365).required().label("Every"),
|
|
3594
|
+
unit: string23().oneOf(SupportedCampaignIntervalUnits).required().label("Unit")
|
|
3246
3595
|
}).optional().default(void 0).label("Repeats").when("kind", {
|
|
3247
3596
|
is: "schedule" /* Schedule */,
|
|
3248
3597
|
then: (s) => s.required()
|
|
3249
3598
|
}),
|
|
3250
3599
|
/** Local wall-clock send time, "HH:mm" in `timezone`. */
|
|
3251
|
-
timeOfDay:
|
|
3600
|
+
timeOfDay: string23().matches(/^([01]\d|2[0-3]):[0-5]\d$/, "Use HH:mm").optional().default("09:00").label("Time of Day"),
|
|
3252
3601
|
/** For weekly intervals: ISO weekdays, 1 = Monday .. 7 = Sunday. */
|
|
3253
|
-
byWeekday:
|
|
3602
|
+
byWeekday: array17().of(number15().integer().min(1).max(7).required()).optional().default([]).label("On Days"),
|
|
3254
3603
|
/**
|
|
3255
3604
|
* For monthly intervals: 1-31, or -1 meaning "last day of the month". A month
|
|
3256
3605
|
* shorter than the chosen day is clamped to its last day, so 31 in February
|
|
3257
3606
|
* fires on the 28th/29th rather than being skipped.
|
|
3258
3607
|
*/
|
|
3259
|
-
byMonthday:
|
|
3260
|
-
end:
|
|
3261
|
-
kind:
|
|
3262
|
-
occurrences:
|
|
3608
|
+
byMonthday: number15().integer().min(-1).max(31).notOneOf([0]).optional().default(void 0).label("Day of Month"),
|
|
3609
|
+
end: object32({
|
|
3610
|
+
kind: string23().oneOf(SupportedCampaignEndKinds).required().label("Ends"),
|
|
3611
|
+
occurrences: number15().integer().min(1).max(1e4).optional().default(void 0).label("After N Sends").when("kind", {
|
|
3263
3612
|
is: "afterOccurrences" /* AfterOccurrences */,
|
|
3264
3613
|
then: (s) => s.required()
|
|
3265
3614
|
}),
|
|
@@ -3269,8 +3618,8 @@ var CampaignTriggerSchema = object31({
|
|
|
3269
3618
|
})
|
|
3270
3619
|
}).optional().default(() => ({ kind: "never" /* Never */ })).label("End Condition")
|
|
3271
3620
|
}).label("Trigger");
|
|
3272
|
-
var CampaignDataSourceSchema =
|
|
3273
|
-
id:
|
|
3621
|
+
var CampaignDataSourceSchema = object32({
|
|
3622
|
+
id: string23().required().label("Data Source"),
|
|
3274
3623
|
/**
|
|
3275
3624
|
* Derive this source's filter per recipient from their profile, instead of
|
|
3276
3625
|
* using the admin-entered `params` for everyone.
|
|
@@ -3285,7 +3634,7 @@ var CampaignDataSourceSchema = object31({
|
|
|
3285
3634
|
* un-personalised. Whether a source can honour it at all is declared by the
|
|
3286
3635
|
* source itself (`supportsPersonalisation`), which this package cannot see.
|
|
3287
3636
|
*/
|
|
3288
|
-
personalised:
|
|
3637
|
+
personalised: boolean18().optional().label("Personalised"),
|
|
3289
3638
|
/**
|
|
3290
3639
|
* A free-form bag whose keys are defined by the chosen source's OWN
|
|
3291
3640
|
* `paramsSchema`, which this package cannot see. Same `lazy` treatment as
|
|
@@ -3300,20 +3649,20 @@ var CampaignDataSourceSchema = object31({
|
|
|
3300
3649
|
*/
|
|
3301
3650
|
params: lazy2((value) => {
|
|
3302
3651
|
const keys = value && typeof value === "object" ? Object.keys(value) : [];
|
|
3303
|
-
return
|
|
3652
|
+
return object32(
|
|
3304
3653
|
Object.fromEntries(keys.map((k) => [k, mixed5().optional()]))
|
|
3305
3654
|
).optional().default(() => ({})).label("Parameters");
|
|
3306
3655
|
})
|
|
3307
3656
|
}).label("Data Source");
|
|
3308
|
-
var TemplateVariableBindingSchema =
|
|
3309
|
-
kind:
|
|
3310
|
-
value:
|
|
3657
|
+
var TemplateVariableBindingSchema = object32({
|
|
3658
|
+
kind: string23().oneOf(SupportedTemplateVariableBindingKinds).required().label("Source"),
|
|
3659
|
+
value: string23().required().min(1).max(2e3).label("Value")
|
|
3311
3660
|
}).label("Template Variable Binding");
|
|
3312
|
-
var CampaignSchema =
|
|
3313
|
-
name:
|
|
3661
|
+
var CampaignSchema = object32({
|
|
3662
|
+
name: string23().required().min(1).max(200).label("Campaign Name"),
|
|
3314
3663
|
// The template renders its own subject; an override is only needed for the
|
|
3315
3664
|
// inline-HTML path, hence not required when a template is chosen.
|
|
3316
|
-
subject:
|
|
3665
|
+
subject: string23().optional().max(255).label("Subject").when("templateKey", {
|
|
3317
3666
|
is: (v) => !v,
|
|
3318
3667
|
then: (s) => s.required().min(1)
|
|
3319
3668
|
}),
|
|
@@ -3324,12 +3673,12 @@ var CampaignSchema = object31({
|
|
|
3324
3673
|
* one with a compliance-checked footer and a render test,
|
|
3325
3674
|
* and hand-pasted HTML that repeats forever is a mistake that repeats forever.
|
|
3326
3675
|
*/
|
|
3327
|
-
html:
|
|
3676
|
+
html: string23().optional().label("HTML Body").when("templateKey", {
|
|
3328
3677
|
is: (v) => !v,
|
|
3329
3678
|
then: (s) => s.required().min(1)
|
|
3330
3679
|
}),
|
|
3331
|
-
text:
|
|
3332
|
-
listId:
|
|
3680
|
+
text: string23().optional().label("Plain-text Body"),
|
|
3681
|
+
listId: string23().required().label("Mailing List"),
|
|
3333
3682
|
/**
|
|
3334
3683
|
* Where the campaign is in its life. See `CampaignStatus` for the transitions.
|
|
3335
3684
|
*
|
|
@@ -3338,9 +3687,9 @@ var CampaignSchema = object31({
|
|
|
3338
3687
|
* value the enum never contained (`scheduled`) reached production rows and
|
|
3339
3688
|
* rendered in the admin list as though it were real.
|
|
3340
3689
|
*/
|
|
3341
|
-
status:
|
|
3690
|
+
status: string23().oneOf(SupportedCampaignStatuses).optional().default("draft" /* Draft */).label("Status"),
|
|
3342
3691
|
/** Key from email-service's template registry. Mutually exclusive with `html`. */
|
|
3343
|
-
templateKey:
|
|
3692
|
+
templateKey: string23().optional().label("Email Template"),
|
|
3344
3693
|
/**
|
|
3345
3694
|
* One entry per variable the chosen template declares. Validated at save time
|
|
3346
3695
|
* against the template's own `variables`, so a missing required binding is a
|
|
@@ -3357,7 +3706,7 @@ var CampaignSchema = object31({
|
|
|
3357
3706
|
*/
|
|
3358
3707
|
bindings: lazy2((value) => {
|
|
3359
3708
|
const keys = value && typeof value === "object" ? Object.keys(value) : [];
|
|
3360
|
-
return
|
|
3709
|
+
return object32(
|
|
3361
3710
|
Object.fromEntries(keys.map((k) => [k, TemplateVariableBindingSchema.required()]))
|
|
3362
3711
|
).optional().default(() => ({})).label("Template Data");
|
|
3363
3712
|
}),
|
|
@@ -3369,7 +3718,7 @@ var CampaignSchema = object31({
|
|
|
3369
3718
|
* `groups.groupCount`), so two sources providing the same name cannot
|
|
3370
3719
|
* overwrite each other and a template says which one it means.
|
|
3371
3720
|
*/
|
|
3372
|
-
dataSources:
|
|
3721
|
+
dataSources: array17().of(CampaignDataSourceSchema).optional().default(void 0).label("Data Sources"),
|
|
3373
3722
|
trigger: CampaignTriggerSchema.default(
|
|
3374
3723
|
() => CampaignTriggerSchema.getDefault()
|
|
3375
3724
|
),
|
|
@@ -3384,7 +3733,7 @@ var CampaignSchema = object31({
|
|
|
3384
3733
|
* representable, and the admin list showed exactly that. Activation is a
|
|
3385
3734
|
* state transition, so it belongs in the state.
|
|
3386
3735
|
*/
|
|
3387
|
-
dryRun:
|
|
3736
|
+
dryRun: boolean18().optional().default(true).label("Dry Run"),
|
|
3388
3737
|
/**
|
|
3389
3738
|
* Re-eligibility: when someone this campaign already mailed may get it again.
|
|
3390
3739
|
*
|
|
@@ -3392,23 +3741,23 @@ var CampaignSchema = object31({
|
|
|
3392
3741
|
* person. `N`: again only after N days. Opt-in, because most recurring
|
|
3393
3742
|
* campaigns exist to mail the same people repeatedly.
|
|
3394
3743
|
*/
|
|
3395
|
-
resendAfterDays:
|
|
3396
|
-
maxRecipients:
|
|
3397
|
-
utm:
|
|
3398
|
-
campaign:
|
|
3399
|
-
content:
|
|
3744
|
+
resendAfterDays: number15().integer().min(0).max(365).nullable().optional().default(void 0).label("Resend After (days)"),
|
|
3745
|
+
maxRecipients: number15().integer().min(1).max(CAMPAIGN_MAX_RECIPIENTS_CEILING).optional().default(void 0).label("Max Recipients"),
|
|
3746
|
+
utm: object32({
|
|
3747
|
+
campaign: string23().optional().max(120).label("utm_campaign"),
|
|
3748
|
+
content: string23().optional().max(120).label("utm_content")
|
|
3400
3749
|
}).optional().default(void 0).label("Link Tagging")
|
|
3401
3750
|
}).label("Campaign");
|
|
3402
3751
|
|
|
3403
3752
|
// src/pagination/pagination.schema.ts
|
|
3404
|
-
import { number as
|
|
3405
|
-
var PaginationSchema =
|
|
3406
|
-
page:
|
|
3407
|
-
limit:
|
|
3408
|
-
sortBy:
|
|
3409
|
-
nextPage:
|
|
3410
|
-
prevPage:
|
|
3411
|
-
sortDirection:
|
|
3753
|
+
import { number as number16, object as object33, string as string24 } from "yup";
|
|
3754
|
+
var PaginationSchema = object33().shape({
|
|
3755
|
+
page: number16().required().min(1).label("Page").default(1),
|
|
3756
|
+
limit: number16().required().min(1).max(100).label("Limit").default(10),
|
|
3757
|
+
sortBy: string24().notOneOf([""]).optional().label("SortBy"),
|
|
3758
|
+
nextPage: string24().optional().label("Next Page Token"),
|
|
3759
|
+
prevPage: string24().optional().label("Previous Page Token"),
|
|
3760
|
+
sortDirection: string24().oneOf(["asc", "desc"]).optional().label("Sort Direction")
|
|
3412
3761
|
});
|
|
3413
3762
|
|
|
3414
3763
|
// src/pagination/pagination.constant.ts
|
|
@@ -3424,7 +3773,7 @@ var DefaultPaginationOptions = {
|
|
|
3424
3773
|
};
|
|
3425
3774
|
|
|
3426
3775
|
// src/saved-search/saved-search.schema.ts
|
|
3427
|
-
import { number as
|
|
3776
|
+
import { number as number17, object as object34, string as string25 } from "yup";
|
|
3428
3777
|
|
|
3429
3778
|
// src/saved-search/saved-search.constant.ts
|
|
3430
3779
|
var SavedSearchStatus = /* @__PURE__ */ ((SavedSearchStatus2) => {
|
|
@@ -3435,21 +3784,21 @@ var SavedSearchStatus = /* @__PURE__ */ ((SavedSearchStatus2) => {
|
|
|
3435
3784
|
var SupportedSavedSearchStatuses = Object.values(SavedSearchStatus);
|
|
3436
3785
|
|
|
3437
3786
|
// src/saved-search/saved-search.schema.ts
|
|
3438
|
-
var SavedSearchSchema =
|
|
3787
|
+
var SavedSearchSchema = object34({
|
|
3439
3788
|
/** Public identifier. Server-assigned. */
|
|
3440
|
-
shortId:
|
|
3789
|
+
shortId: string25().trim().label("Short Id"),
|
|
3441
3790
|
/**
|
|
3442
3791
|
* Owner's Better Auth account id. Server-assigned from the verified token,
|
|
3443
3792
|
* never accepted from a request body.
|
|
3444
3793
|
*/
|
|
3445
|
-
ownerUserId:
|
|
3794
|
+
ownerUserId: string25().trim().label("Owner"),
|
|
3446
3795
|
/** What the user calls this search, e.g. "Remote React roles". */
|
|
3447
|
-
label:
|
|
3796
|
+
label: string25().trim().max(120).required().label("Label"),
|
|
3448
3797
|
/**
|
|
3449
3798
|
* The free-text query. Optional because a search can be filters-only ("all
|
|
3450
3799
|
* remote jobs in Sweden"), which is a legitimate alert to want.
|
|
3451
3800
|
*/
|
|
3452
|
-
search:
|
|
3801
|
+
search: string25().trim().max(500).optional().label("Search Text"),
|
|
3453
3802
|
/**
|
|
3454
3803
|
* Field filters, in the same `{ field: values }` shape the search endpoint
|
|
3455
3804
|
* parses from `filter[field]=a,b`. Held as a free-form object rather than a
|
|
@@ -3457,7 +3806,7 @@ var SavedSearchSchema = object33({
|
|
|
3457
3806
|
* change independently; validating them here would put this package in the
|
|
3458
3807
|
* business of tracking that vocabulary.
|
|
3459
3808
|
*/
|
|
3460
|
-
filter:
|
|
3809
|
+
filter: object34().optional().default({}).label("Filters"),
|
|
3461
3810
|
/**
|
|
3462
3811
|
* How often to mail matches. `off` keeps the search saved but silent, which is
|
|
3463
3812
|
* the difference between "I don't want mail" and "delete my search".
|
|
@@ -3466,26 +3815,26 @@ var SavedSearchSchema = object33({
|
|
|
3466
3815
|
* than defining a second one: two vocabularies for the same concept is how
|
|
3467
3816
|
* they drift.
|
|
3468
3817
|
*/
|
|
3469
|
-
frequency:
|
|
3470
|
-
status:
|
|
3818
|
+
frequency: string25().oneOf(SupportedJobAlertFrequencies).default("off" /* Off */).label("Alert Frequency"),
|
|
3819
|
+
status: string25().oneOf(SupportedSavedSearchStatuses).default("active" /* Active */).label("Status"),
|
|
3471
3820
|
/**
|
|
3472
3821
|
* Epoch ms of the last alert sent for this search. The matching sweep reads it
|
|
3473
3822
|
* to decide whether the cadence is due, and writes it only AFTER a successful
|
|
3474
3823
|
* publish, so a failed run retries next tick rather than silently skipping a
|
|
3475
3824
|
* period.
|
|
3476
3825
|
*/
|
|
3477
|
-
lastNotifiedAt:
|
|
3826
|
+
lastNotifiedAt: number17().optional().label("Last Notified At"),
|
|
3478
3827
|
/**
|
|
3479
3828
|
* Epoch ms high-water mark: only jobs created after this are "new" for the
|
|
3480
3829
|
* next alert. Kept separate from `lastNotifiedAt` because a run that finds no
|
|
3481
3830
|
* matches should still advance what counts as new, without implying mail was
|
|
3482
3831
|
* sent.
|
|
3483
3832
|
*/
|
|
3484
|
-
lastMatchedAt:
|
|
3833
|
+
lastMatchedAt: number17().optional().label("Last Matched At")
|
|
3485
3834
|
}).noUnknown().strict();
|
|
3486
3835
|
|
|
3487
3836
|
// src/report/report.schema.ts
|
|
3488
|
-
import { mixed as mixed6, object as
|
|
3837
|
+
import { mixed as mixed6, object as object35, string as string26 } from "yup";
|
|
3489
3838
|
|
|
3490
3839
|
// src/report/report.constant.ts
|
|
3491
3840
|
var ResourceType = /* @__PURE__ */ ((ResourceType3) => {
|
|
@@ -3509,15 +3858,15 @@ var ReportReason = /* @__PURE__ */ ((ReportReason3) => {
|
|
|
3509
3858
|
var SupportedReportReasons = Object.values(ReportReason);
|
|
3510
3859
|
|
|
3511
3860
|
// src/report/report.schema.ts
|
|
3512
|
-
var ReportSchema =
|
|
3861
|
+
var ReportSchema = object35({
|
|
3513
3862
|
type: mixed6().oneOf(SupportedResourceTypes).required().label("Type"),
|
|
3514
|
-
resourceId:
|
|
3863
|
+
resourceId: string26().required().label("Resource ID"),
|
|
3515
3864
|
reason: mixed6().oneOf(SupportedReportReasons).required("Please choose a reason").label("Reason"),
|
|
3516
|
-
comment:
|
|
3865
|
+
comment: string26().max(1e3).optional().label("Comment")
|
|
3517
3866
|
}).label("Report Schema");
|
|
3518
3867
|
|
|
3519
3868
|
// src/feedback/feedback-filter.schema.ts
|
|
3520
|
-
import { object as
|
|
3869
|
+
import { object as object36 } from "yup";
|
|
3521
3870
|
|
|
3522
3871
|
// src/feedback/feedback.constant.ts
|
|
3523
3872
|
var FeedbackType = /* @__PURE__ */ ((FeedbackType3) => {
|
|
@@ -3540,7 +3889,7 @@ var SupportedFeedbackStatuses = Object.values(FeedbackStatus);
|
|
|
3540
3889
|
var FEEDBACK_MESSAGE_MAX = 4e3;
|
|
3541
3890
|
|
|
3542
3891
|
// src/feedback/feedback-filter.schema.ts
|
|
3543
|
-
var FeedbackFilterShape =
|
|
3892
|
+
var FeedbackFilterShape = object36({
|
|
3544
3893
|
type: enumFacet(SupportedFeedbackTypes, "Type"),
|
|
3545
3894
|
status: enumFacet(SupportedFeedbackStatuses, "Status")
|
|
3546
3895
|
}).label("Feedback Filter");
|
|
@@ -3550,18 +3899,18 @@ var FeedbackFilterSchema = rejectUnknownKeys(
|
|
|
3550
3899
|
);
|
|
3551
3900
|
|
|
3552
3901
|
// src/feedback/feedback.schema.ts
|
|
3553
|
-
import { mixed as mixed7, object as
|
|
3554
|
-
var FeedbackSchema =
|
|
3902
|
+
import { mixed as mixed7, object as object37, string as string27 } from "yup";
|
|
3903
|
+
var FeedbackSchema = object37({
|
|
3555
3904
|
type: mixed7().oneOf(SupportedFeedbackTypes).required().label("Type"),
|
|
3556
|
-
message:
|
|
3557
|
-
email:
|
|
3558
|
-
pageUrl:
|
|
3905
|
+
message: string27().trim().required("Please enter a message").max(FEEDBACK_MESSAGE_MAX).label("Message"),
|
|
3906
|
+
email: string27().email().optional().label("Email"),
|
|
3907
|
+
pageUrl: string27().optional().label("Page URL"),
|
|
3559
3908
|
status: mixed7().oneOf(SupportedFeedbackStatuses).optional().label("Status")
|
|
3560
3909
|
}).label("Feedback Schema");
|
|
3561
3910
|
|
|
3562
3911
|
// src/skill/skill-filter.schema.ts
|
|
3563
|
-
import { object as
|
|
3564
|
-
var SkillFilterShape =
|
|
3912
|
+
import { object as object38 } from "yup";
|
|
3913
|
+
var SkillFilterShape = object38({
|
|
3565
3914
|
/** Display names, matched exactly. Free-text matching is `?search=`. */
|
|
3566
3915
|
names: tokens("Names"),
|
|
3567
3916
|
/**
|
|
@@ -3579,7 +3928,7 @@ var SkillFilterSchema = rejectUnknownKeys(
|
|
|
3579
3928
|
);
|
|
3580
3929
|
|
|
3581
3930
|
// src/billing/billing.schema.ts
|
|
3582
|
-
import { array as
|
|
3931
|
+
import { array as array18, boolean as boolean19, number as number18, object as object39, string as string28 } from "yup";
|
|
3583
3932
|
|
|
3584
3933
|
// src/billing/billing.constant.ts
|
|
3585
3934
|
var PlanKind = /* @__PURE__ */ ((PlanKind2) => {
|
|
@@ -3682,60 +4031,60 @@ var GRANT_MAX_LIMIT = 1e5;
|
|
|
3682
4031
|
var CONSUME_MAX_UNITS = 1e3;
|
|
3683
4032
|
|
|
3684
4033
|
// src/billing/billing.schema.ts
|
|
3685
|
-
var MoneySchema =
|
|
3686
|
-
amountMinor:
|
|
4034
|
+
var MoneySchema = object39({
|
|
4035
|
+
amountMinor: number18().integer().min(0).required().label("Amount (minor units)"),
|
|
3687
4036
|
/**
|
|
3688
4037
|
* ISO-4217, as returned by Paddle. Deliberately NOT constrained to
|
|
3689
4038
|
* `SupportedSalaryCurrencies`: that list is the job-salary vocabulary, and
|
|
3690
4039
|
* Paddle bills in currencies it does not contain. Constraining it here would
|
|
3691
4040
|
* reject real payments.
|
|
3692
4041
|
*/
|
|
3693
|
-
currencyCode:
|
|
4042
|
+
currencyCode: string28().trim().uppercase().required().label("Currency")
|
|
3694
4043
|
}).label("Money");
|
|
3695
|
-
var PlanGrantSchema =
|
|
4044
|
+
var PlanGrantSchema = object39({
|
|
3696
4045
|
/**
|
|
3697
4046
|
* The gated capability, e.g. `job.post`. A free string on purpose: see the
|
|
3698
4047
|
* note on `FeatureKey` in `billing.constant.ts`. Adding a feature to the
|
|
3699
4048
|
* paywall must not require releasing this package.
|
|
3700
4049
|
*/
|
|
3701
|
-
feature:
|
|
3702
|
-
type:
|
|
4050
|
+
feature: string28().trim().required().min(1).max(64).label("Feature"),
|
|
4051
|
+
type: string28().oneOf(SupportedGrantTypes).required().default("boolean" /* Boolean */).label("Grant Type"),
|
|
3703
4052
|
/** Uses per period. Required for `quota`, meaningless otherwise. */
|
|
3704
|
-
limit:
|
|
4053
|
+
limit: number18().integer().min(1).max(GRANT_MAX_LIMIT).optional().label("Limit").when("type", {
|
|
3705
4054
|
is: "quota" /* Quota */,
|
|
3706
4055
|
then: (s) => s.required("A quota grant needs a limit")
|
|
3707
4056
|
}),
|
|
3708
|
-
period:
|
|
4057
|
+
period: string28().oneOf(SupportedQuotaPeriods).optional().default("month" /* Month */).label("Period").when("type", {
|
|
3709
4058
|
is: "quota" /* Quota */,
|
|
3710
4059
|
then: (s) => s.required("A quota grant needs a period")
|
|
3711
4060
|
}),
|
|
3712
4061
|
/** Non-expiring uses granted per purchase. Required for `credit`. */
|
|
3713
|
-
amount:
|
|
4062
|
+
amount: number18().integer().min(1).max(GRANT_MAX_LIMIT).optional().label("Amount").when("type", {
|
|
3714
4063
|
is: "credit" /* Credit */,
|
|
3715
4064
|
then: (s) => s.required("A credit grant needs an amount")
|
|
3716
4065
|
})
|
|
3717
4066
|
}).label("Plan Grant");
|
|
3718
|
-
var PaddlePriceIdsSchema =
|
|
3719
|
-
sandbox:
|
|
3720
|
-
live:
|
|
4067
|
+
var PaddlePriceIdsSchema = object39({
|
|
4068
|
+
sandbox: array18().of(string28().required()).optional().default([]).label("Sandbox Price IDs"),
|
|
4069
|
+
live: array18().of(string28().required()).optional().default([]).label("Live Price IDs")
|
|
3721
4070
|
}).label("Paddle Price IDs");
|
|
3722
|
-
var PlanSchema =
|
|
4071
|
+
var PlanSchema = object39({
|
|
3723
4072
|
/** Stable slug, e.g. `employer-pro`. The identifier everything else references. */
|
|
3724
|
-
key:
|
|
3725
|
-
name:
|
|
3726
|
-
description:
|
|
3727
|
-
kind:
|
|
4073
|
+
key: string28().trim().lowercase().required().min(2).max(64).label("Key"),
|
|
4074
|
+
name: string28().required().min(1).max(120).label("Name"),
|
|
4075
|
+
description: string28().optional().max(500).label("Description"),
|
|
4076
|
+
kind: string28().oneOf(SupportedPlanKinds).required().default("subscription" /* Subscription */).label("Kind"),
|
|
3728
4077
|
/**
|
|
3729
4078
|
* The line this plan belongs to; a user holds one live subscription per line.
|
|
3730
4079
|
* Optional on purpose: absent is the default line, so existing plans need no
|
|
3731
4080
|
* migration and together still read as "one plan at a time".
|
|
3732
4081
|
*/
|
|
3733
|
-
audience:
|
|
3734
|
-
status:
|
|
4082
|
+
audience: string28().oneOf(SupportedPlanAudiences).optional().label("Audience"),
|
|
4083
|
+
status: string28().oneOf(SupportedPlanStatuses).required().default("draft" /* Draft */).label("Status"),
|
|
3735
4084
|
paddlePriceIds: PaddlePriceIdsSchema.default(
|
|
3736
4085
|
() => PaddlePriceIdsSchema.getDefault()
|
|
3737
4086
|
),
|
|
3738
|
-
grants:
|
|
4087
|
+
grants: array18().of(PlanGrantSchema.required()).required().min(1, "A plan must grant at least one feature").label("Grants"),
|
|
3739
4088
|
/** Display price for the pricing page. Billing is always Paddle's own figure. */
|
|
3740
4089
|
price: MoneySchema.optional().default(void 0).label("Price"),
|
|
3741
4090
|
/**
|
|
@@ -3748,133 +4097,189 @@ var PlanSchema = object38({
|
|
|
3748
4097
|
* a subscription as "monthly" at the use site rather than defaulting it here,
|
|
3749
4098
|
* so an unset value stays visible as unset.
|
|
3750
4099
|
*/
|
|
3751
|
-
billingPeriod:
|
|
4100
|
+
billingPeriod: string28().oneOf(SupportedBillingPeriods).optional().label("Billing Period"),
|
|
3752
4101
|
/** Ordering on the pricing page, ascending. */
|
|
3753
|
-
sortOrder:
|
|
3754
|
-
createdAt:
|
|
3755
|
-
updatedAt:
|
|
4102
|
+
sortOrder: number18().integer().optional().default(0).label("Sort Order"),
|
|
4103
|
+
createdAt: number18().optional().label("Created At"),
|
|
4104
|
+
updatedAt: number18().optional().label("Updated At")
|
|
3756
4105
|
}).label("Plan");
|
|
3757
|
-
var BillingSubscriptionSchema =
|
|
3758
|
-
userId:
|
|
3759
|
-
paddleSubscriptionId:
|
|
3760
|
-
paddleCustomerId:
|
|
3761
|
-
planKey:
|
|
3762
|
-
priceIds:
|
|
3763
|
-
status:
|
|
4106
|
+
var BillingSubscriptionSchema = object39({
|
|
4107
|
+
userId: string28().required().label("User ID"),
|
|
4108
|
+
paddleSubscriptionId: string28().required().label("Paddle Subscription ID"),
|
|
4109
|
+
paddleCustomerId: string28().required().label("Paddle Customer ID"),
|
|
4110
|
+
planKey: string28().required().label("Plan Key"),
|
|
4111
|
+
priceIds: array18().of(string28().required()).required().label("Price IDs"),
|
|
4112
|
+
status: string28().oneOf(SupportedSubscriptionStatuses).required().label("Status"),
|
|
3764
4113
|
/** Start of the period the quota is anchored to. */
|
|
3765
|
-
currentPeriodStart:
|
|
3766
|
-
currentPeriodEnd:
|
|
4114
|
+
currentPeriodStart: number18().optional().label("Current Period Start"),
|
|
4115
|
+
currentPeriodEnd: number18().optional().label("Current Period End"),
|
|
3767
4116
|
/** Set when a cancellation is scheduled; access continues until the period ends. */
|
|
3768
|
-
canceledAt:
|
|
4117
|
+
canceledAt: number18().optional().label("Canceled At"),
|
|
3769
4118
|
/**
|
|
3770
4119
|
* A downgrade booked for the end of the current period: the plan key it moves
|
|
3771
4120
|
* to at renewal. Upgrades never set this; they apply immediately. Mirrored
|
|
3772
4121
|
* from the Paddle subscription's own `customData`, so Paddle stays the source
|
|
3773
4122
|
* of truth.
|
|
3774
4123
|
*/
|
|
3775
|
-
pendingPlanKey:
|
|
4124
|
+
pendingPlanKey: string28().optional().label("Pending Plan Key"),
|
|
3776
4125
|
/** `occurred_at` of the newest Paddle event applied. Guards out-of-order writes. */
|
|
3777
|
-
lastEventAt:
|
|
3778
|
-
createdAt:
|
|
3779
|
-
updatedAt:
|
|
4126
|
+
lastEventAt: number18().required().default(0).label("Last Event At"),
|
|
4127
|
+
createdAt: number18().optional().label("Created At"),
|
|
4128
|
+
updatedAt: number18().optional().label("Updated At")
|
|
3780
4129
|
}).label("Billing Subscription");
|
|
3781
|
-
var BillingTransactionSchema =
|
|
3782
|
-
userId:
|
|
3783
|
-
paddleTransactionId:
|
|
3784
|
-
paddleCustomerId:
|
|
3785
|
-
paddleSubscriptionId:
|
|
3786
|
-
planKey:
|
|
3787
|
-
priceIds:
|
|
3788
|
-
status:
|
|
4130
|
+
var BillingTransactionSchema = object39({
|
|
4131
|
+
userId: string28().required().label("User ID"),
|
|
4132
|
+
paddleTransactionId: string28().required().label("Paddle Transaction ID"),
|
|
4133
|
+
paddleCustomerId: string28().optional().label("Paddle Customer ID"),
|
|
4134
|
+
paddleSubscriptionId: string28().optional().label("Paddle Subscription ID"),
|
|
4135
|
+
planKey: string28().optional().label("Plan Key"),
|
|
4136
|
+
priceIds: array18().of(string28().required()).required().label("Price IDs"),
|
|
4137
|
+
status: string28().oneOf(SupportedTransactionStatuses).required().label("Status"),
|
|
3789
4138
|
total: MoneySchema.optional().default(void 0).label("Total"),
|
|
3790
|
-
billedAt:
|
|
3791
|
-
lastEventAt:
|
|
3792
|
-
createdAt:
|
|
3793
|
-
updatedAt:
|
|
4139
|
+
billedAt: number18().optional().label("Billed At"),
|
|
4140
|
+
lastEventAt: number18().required().default(0).label("Last Event At"),
|
|
4141
|
+
createdAt: number18().optional().label("Created At"),
|
|
4142
|
+
updatedAt: number18().optional().label("Updated At")
|
|
3794
4143
|
}).label("Billing Transaction");
|
|
3795
|
-
var FeatureEntitlementSchema =
|
|
3796
|
-
feature:
|
|
3797
|
-
type:
|
|
4144
|
+
var FeatureEntitlementSchema = object39({
|
|
4145
|
+
feature: string28().required().label("Feature"),
|
|
4146
|
+
type: string28().oneOf(SupportedGrantTypes).required().label("Grant Type"),
|
|
3798
4147
|
/** Whether the feature may be used AT ALL right now. */
|
|
3799
|
-
allowed:
|
|
4148
|
+
allowed: boolean19().required().default(false).label("Allowed"),
|
|
3800
4149
|
/** Quota ceiling for the period. Absent for boolean grants. */
|
|
3801
|
-
limit:
|
|
3802
|
-
used:
|
|
4150
|
+
limit: number18().integer().optional().label("Limit"),
|
|
4151
|
+
used: number18().integer().optional().label("Used"),
|
|
3803
4152
|
/** Quota remaining plus any credit balance. Absent for boolean grants. */
|
|
3804
|
-
remaining:
|
|
4153
|
+
remaining: number18().integer().optional().label("Remaining"),
|
|
3805
4154
|
/** Non-expiring balance from one-off purchases. */
|
|
3806
|
-
credits:
|
|
4155
|
+
credits: number18().integer().optional().label("Credits"),
|
|
3807
4156
|
/** When the quota next refreshes. */
|
|
3808
|
-
resetsAt:
|
|
4157
|
+
resetsAt: number18().optional().label("Resets At")
|
|
3809
4158
|
}).label("Feature Entitlement");
|
|
3810
|
-
var EntitlementDenialSchema =
|
|
3811
|
-
feature:
|
|
3812
|
-
reason:
|
|
3813
|
-
limit:
|
|
3814
|
-
used:
|
|
3815
|
-
resetsAt:
|
|
3816
|
-
upgradeUrl:
|
|
4159
|
+
var EntitlementDenialSchema = object39({
|
|
4160
|
+
feature: string28().required().label("Feature"),
|
|
4161
|
+
reason: string28().oneOf(SupportedEntitlementDenialReasons).required().label("Reason"),
|
|
4162
|
+
limit: number18().integer().optional().label("Limit"),
|
|
4163
|
+
used: number18().integer().optional().label("Used"),
|
|
4164
|
+
resetsAt: number18().optional().label("Resets At"),
|
|
4165
|
+
upgradeUrl: string28().optional().label("Upgrade URL")
|
|
3817
4166
|
}).label("Entitlement Denial");
|
|
3818
|
-
var EntitlementConsumeSchema =
|
|
3819
|
-
userId:
|
|
3820
|
-
feature:
|
|
3821
|
-
units:
|
|
4167
|
+
var EntitlementConsumeSchema = object39({
|
|
4168
|
+
userId: string28().required().label("User ID"),
|
|
4169
|
+
feature: string28().trim().required().min(1).max(64).label("Feature"),
|
|
4170
|
+
units: number18().integer().min(1).max(CONSUME_MAX_UNITS).required().default(1).label("Units"),
|
|
3822
4171
|
/**
|
|
3823
4172
|
* Caller-supplied de-duplication key. Makes a spend exactly-once across the
|
|
3824
4173
|
* retries that at-least-once delivery and ordinary network failures produce.
|
|
3825
4174
|
*/
|
|
3826
|
-
idempotencyKey:
|
|
4175
|
+
idempotencyKey: string28().trim().required().min(8).max(128).label("Idempotency Key")
|
|
3827
4176
|
}).label("Entitlement Consume");
|
|
3828
4177
|
|
|
4178
|
+
// src/taxonomy/taxonomy-filter.schema.ts
|
|
4179
|
+
import { boolean as boolean20, object as object40 } from "yup";
|
|
4180
|
+
var ConceptFilterShape = object40({
|
|
4181
|
+
/** Type ids. Open: which types exist is the vocabulary's data. */
|
|
4182
|
+
type: tokens("Type"),
|
|
4183
|
+
/** Category node ids the concept is placed under (`memberships.categoryId`). */
|
|
4184
|
+
categoryId: tokens("Category"),
|
|
4185
|
+
/** True: only live concepts with no backbone home (the uncategorized backlog). */
|
|
4186
|
+
unplaced: boolean20().optional().label("Unplaced")
|
|
4187
|
+
}).label("Concept Filter");
|
|
4188
|
+
var ConceptFilterSchema = rejectUnknownKeys(
|
|
4189
|
+
ConceptFilterShape,
|
|
4190
|
+
() => Object.keys(ConceptFilterShape.fields)
|
|
4191
|
+
);
|
|
4192
|
+
var TaxonomyNodeFilterShape = object40({
|
|
4193
|
+
kind: enumFacet(SupportedTaxonomyNodeKinds, "Kind"),
|
|
4194
|
+
/** Parent node ids: a node's children. */
|
|
4195
|
+
parentId: tokens("Parent")
|
|
4196
|
+
}).label("Taxonomy Node Filter");
|
|
4197
|
+
var TaxonomyNodeFilterSchema = rejectUnknownKeys(
|
|
4198
|
+
TaxonomyNodeFilterShape,
|
|
4199
|
+
() => Object.keys(TaxonomyNodeFilterShape.fields)
|
|
4200
|
+
);
|
|
4201
|
+
var UnmatchedFilterShape = object40({
|
|
4202
|
+
resolution: enumFacet(SupportedUnmatchedResolutions, "Resolution"),
|
|
4203
|
+
reason: enumFacet(SupportedUnmatchedReasons, "Reason")
|
|
4204
|
+
}).label("Unmatched Filter");
|
|
4205
|
+
var UnmatchedFilterSchema = rejectUnknownKeys(
|
|
4206
|
+
UnmatchedFilterShape,
|
|
4207
|
+
() => Object.keys(UnmatchedFilterShape.fields)
|
|
4208
|
+
);
|
|
4209
|
+
var ConceptProposalFilterShape = object40({
|
|
4210
|
+
status: enumFacet(SupportedProposalStatuses, "Status"),
|
|
4211
|
+
/** A kind, or `uncategorized`: concept and placement drafts with no home yet. */
|
|
4212
|
+
kind: enumFacet(SupportedProposalFilters, "Kind")
|
|
4213
|
+
}).label("Concept Proposal Filter");
|
|
4214
|
+
var ConceptProposalFilterSchema = rejectUnknownKeys(
|
|
4215
|
+
ConceptProposalFilterShape,
|
|
4216
|
+
() => Object.keys(ConceptProposalFilterShape.fields)
|
|
4217
|
+
);
|
|
4218
|
+
var ReleaseFilterShape = object40({
|
|
4219
|
+
kind: enumFacet(SupportedReleaseKinds, "Kind"),
|
|
4220
|
+
status: enumFacet(SupportedReleaseStatuses, "Status")
|
|
4221
|
+
}).label("Release Filter");
|
|
4222
|
+
var ReleaseFilterSchema = rejectUnknownKeys(
|
|
4223
|
+
ReleaseFilterShape,
|
|
4224
|
+
() => Object.keys(ReleaseFilterShape.fields)
|
|
4225
|
+
);
|
|
4226
|
+
var AuditFilterShape = object40({
|
|
4227
|
+
status: enumFacet(SupportedAuditStatuses, "Status")
|
|
4228
|
+
}).label("Audit Filter");
|
|
4229
|
+
var AuditFilterSchema = rejectUnknownKeys(
|
|
4230
|
+
AuditFilterShape,
|
|
4231
|
+
() => Object.keys(AuditFilterShape.fields)
|
|
4232
|
+
);
|
|
4233
|
+
|
|
3829
4234
|
// src/user/user.schema.ts
|
|
3830
|
-
import { array as
|
|
4235
|
+
import { array as array22, boolean as boolean24, number as number21, object as object53, string as string41 } from "yup";
|
|
3831
4236
|
|
|
3832
4237
|
// src/user/work-experience.schema.ts
|
|
3833
|
-
import { boolean as
|
|
3834
|
-
var WorkExperienceSchema =
|
|
4238
|
+
import { boolean as boolean21, object as object41, string as string29 } from "yup";
|
|
4239
|
+
var WorkExperienceSchema = object41().shape({
|
|
3835
4240
|
company: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Company"),
|
|
3836
|
-
designation:
|
|
4241
|
+
designation: string29().trim().required().label("Designation"),
|
|
3837
4242
|
duration: DurationSchema({
|
|
3838
4243
|
format: "YYYY-MM",
|
|
3839
4244
|
startLabel: "Start Date",
|
|
3840
4245
|
endLabel: "End Date"
|
|
3841
4246
|
}).required().label("Duration"),
|
|
3842
|
-
description:
|
|
4247
|
+
description: string29().trim().max(3e3).optional().label("Description"),
|
|
3843
4248
|
location: LocationSchema.required().label("Location"),
|
|
3844
|
-
isRemote:
|
|
4249
|
+
isRemote: boolean21().oneOf([true, false]).default(false).label("Is Remote")
|
|
3845
4250
|
}).noUnknown().strict().label("Work Experience");
|
|
3846
4251
|
|
|
3847
4252
|
// src/user/education.schema.ts
|
|
3848
|
-
import { boolean as
|
|
3849
|
-
var EducationSchema =
|
|
4253
|
+
import { boolean as boolean22, object as object42, string as string30 } from "yup";
|
|
4254
|
+
var EducationSchema = object42({
|
|
3850
4255
|
institute: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Institute"),
|
|
3851
|
-
course:
|
|
3852
|
-
fieldOfStudy:
|
|
4256
|
+
course: string30().trim().required().label("Course"),
|
|
4257
|
+
fieldOfStudy: string30().trim().required().label("Field of Study"),
|
|
3853
4258
|
duration: DurationSchema({
|
|
3854
4259
|
format: "YYYY-MM",
|
|
3855
4260
|
startLabel: "Start Date",
|
|
3856
4261
|
endLabel: "End Date"
|
|
3857
4262
|
}).required().label("Duration"),
|
|
3858
|
-
description:
|
|
3859
|
-
isDistanceLearning:
|
|
4263
|
+
description: string30().trim().max(3e3).optional().label("Description"),
|
|
4264
|
+
isDistanceLearning: boolean22().default(false).label("Is Distance Learning"),
|
|
3860
4265
|
location: LocationSchema.required().label("Location"),
|
|
3861
|
-
studyType:
|
|
4266
|
+
studyType: string30().oneOf(SupportedStudyTypes).trim().max(50).required().label("Study Type")
|
|
3862
4267
|
}).noUnknown().strict().label("Education");
|
|
3863
4268
|
|
|
3864
4269
|
// src/user/user-skill.schema.ts
|
|
3865
|
-
import { object as
|
|
3866
|
-
var UserSkillSchema =
|
|
3867
|
-
name:
|
|
3868
|
-
proficiencyLevel:
|
|
4270
|
+
import { object as object43, string as string31 } from "yup";
|
|
4271
|
+
var UserSkillSchema = object43({
|
|
4272
|
+
name: string31().required().label("Name"),
|
|
4273
|
+
proficiencyLevel: string31().oneOf(SupportedProficiencyLevels).required().label("Proficiency Level"),
|
|
3869
4274
|
lastUsed: dateString().format("YYYY-MM").nullable().optional().label("Last Used")
|
|
3870
4275
|
}).noUnknown().strict().label("Skill");
|
|
3871
4276
|
|
|
3872
4277
|
// src/user/project.schema.ts
|
|
3873
|
-
import { object as
|
|
3874
|
-
var UserProjectSchema =
|
|
3875
|
-
name:
|
|
3876
|
-
url:
|
|
3877
|
-
description:
|
|
4278
|
+
import { object as object44, string as string32 } from "yup";
|
|
4279
|
+
var UserProjectSchema = object44({
|
|
4280
|
+
name: string32().trim().max(50).required().label("Name"),
|
|
4281
|
+
url: string32().optional().label("URL"),
|
|
4282
|
+
description: string32().trim().min(100).max(3e3).required().label("Description"),
|
|
3878
4283
|
duration: DurationSchema({
|
|
3879
4284
|
format: "YYYY-MM",
|
|
3880
4285
|
startLabel: "Start Date",
|
|
@@ -3883,68 +4288,68 @@ var UserProjectSchema = object42({
|
|
|
3883
4288
|
}).noUnknown().strict().label("Project");
|
|
3884
4289
|
|
|
3885
4290
|
// src/user/user-certification.schema.ts
|
|
3886
|
-
import { object as
|
|
3887
|
-
var UserCertificationSchema =
|
|
3888
|
-
name:
|
|
4291
|
+
import { object as object45, string as string33 } from "yup";
|
|
4292
|
+
var UserCertificationSchema = object45({
|
|
4293
|
+
name: string33().trim().max(100).required().label("Name"),
|
|
3889
4294
|
// TODO: Add validation for authority
|
|
3890
|
-
authority:
|
|
3891
|
-
licenseNumber:
|
|
4295
|
+
authority: string33().trim().max(100).required().label("Authority"),
|
|
4296
|
+
licenseNumber: string33().trim().max(50).optional().label("License Number"),
|
|
3892
4297
|
duration: DurationSchema({
|
|
3893
4298
|
format: "YYYY-MM",
|
|
3894
4299
|
startLabel: "Start Date",
|
|
3895
4300
|
endLabel: "End Date"
|
|
3896
4301
|
}).optional().nullable().label("Duration"),
|
|
3897
|
-
url:
|
|
4302
|
+
url: string33().optional().label("URL")
|
|
3898
4303
|
}).noUnknown().strict().label("Certification");
|
|
3899
4304
|
|
|
3900
4305
|
// src/user/user-interest.schema.ts
|
|
3901
|
-
import { object as
|
|
3902
|
-
var UserInterestSchema =
|
|
4306
|
+
import { object as object46, string as string34 } from "yup";
|
|
4307
|
+
var UserInterestSchema = object46({
|
|
3903
4308
|
/** The taxonomy entry's id. */
|
|
3904
|
-
id:
|
|
4309
|
+
id: string34().trim().required().label("Interest Id"),
|
|
3905
4310
|
/** Display name, e.g. "Cloud Computing". */
|
|
3906
|
-
name:
|
|
4311
|
+
name: string34().trim().required().label("Interest"),
|
|
3907
4312
|
/** Material-symbols icon name, e.g. "cloud". */
|
|
3908
|
-
logo:
|
|
4313
|
+
logo: string34().trim().required().label("Interest Logo")
|
|
3909
4314
|
}).required().label("Interest");
|
|
3910
4315
|
|
|
3911
4316
|
// src/user/user-language.schema.ts
|
|
3912
|
-
import { object as
|
|
3913
|
-
var UserLanguageSchema =
|
|
3914
|
-
name:
|
|
3915
|
-
proficiencyLevel:
|
|
4317
|
+
import { object as object47, string as string35 } from "yup";
|
|
4318
|
+
var UserLanguageSchema = object47({
|
|
4319
|
+
name: string35().trim().required().label("Name"),
|
|
4320
|
+
proficiencyLevel: string35().oneOf(SupportedProficiencyLevels).trim().max(50).required().label("Proficiency Level")
|
|
3916
4321
|
}).noUnknown().strict().label("Language");
|
|
3917
4322
|
|
|
3918
4323
|
// src/user/user-additional-info.schema.ts
|
|
3919
|
-
import { object as
|
|
3920
|
-
var UserAdditionalInfoSchema =
|
|
3921
|
-
title:
|
|
3922
|
-
description:
|
|
4324
|
+
import { object as object48, string as string36 } from "yup";
|
|
4325
|
+
var UserAdditionalInfoSchema = object48({
|
|
4326
|
+
title: string36().trim().max(60).required().label("Title"),
|
|
4327
|
+
description: string36().trim().max(1e3).required().label("Description")
|
|
3923
4328
|
}).noUnknown().strict().label("User Additional Info");
|
|
3924
4329
|
|
|
3925
4330
|
// src/user/general-detail.schema.ts
|
|
3926
|
-
import { number as
|
|
3927
|
-
var UserGeneralDetailSchema =
|
|
3928
|
-
id:
|
|
3929
|
-
name:
|
|
3930
|
-
first:
|
|
3931
|
-
last:
|
|
4331
|
+
import { number as number19, object as object49, string as string37 } from "yup";
|
|
4332
|
+
var UserGeneralDetailSchema = object49({
|
|
4333
|
+
id: string37().optional().label("ID"),
|
|
4334
|
+
name: object49().shape({
|
|
4335
|
+
first: string37().trim().max(50).required().label("First Name"),
|
|
4336
|
+
last: string37().trim().max(50).optional().label("Last Name")
|
|
3932
4337
|
}).required().label("Name"),
|
|
3933
|
-
headline:
|
|
3934
|
-
image:
|
|
4338
|
+
headline: string37().trim().max(200).optional().label("Headline"),
|
|
4339
|
+
image: string37().optional().label("Image"),
|
|
3935
4340
|
// The DISPLAYED avatar (`image`) is a flattened export with any status frame
|
|
3936
4341
|
// ("#OpenToWork", …) already burned into the pixels. `imageOriginal` keeps the
|
|
3937
4342
|
// un-framed source the user uploaded, so the image builder can reopen it and
|
|
3938
4343
|
// apply a DIFFERENT frame instead of stacking a second one on top of the first.
|
|
3939
4344
|
// Optional and absent on every pre-existing user: treat a missing value as
|
|
3940
4345
|
// "only the flattened image is available".
|
|
3941
|
-
imageOriginal:
|
|
3942
|
-
aboutMe:
|
|
3943
|
-
email:
|
|
3944
|
-
mobile:
|
|
3945
|
-
emailVerified:
|
|
3946
|
-
mobileVerified:
|
|
3947
|
-
experienceLevel:
|
|
4346
|
+
imageOriginal: string37().optional().label("Original Image"),
|
|
4347
|
+
aboutMe: string37().trim().max(3e3).optional().label("About Me"),
|
|
4348
|
+
email: string37().required().label("Email"),
|
|
4349
|
+
mobile: string37().nullable().optional().label("Mobile"),
|
|
4350
|
+
emailVerified: string37().nullable().optional().label("Email Verified"),
|
|
4351
|
+
mobileVerified: string37().nullable().optional().label("Mobile Verified"),
|
|
4352
|
+
experienceLevel: string37().oneOf(SupportedExperienceLevels).required().label("Experience level"),
|
|
3948
4353
|
/**
|
|
3949
4354
|
* The user's HIGHEST qualification, e.g. `bachelor`.
|
|
3950
4355
|
*
|
|
@@ -3963,7 +4368,7 @@ var UserGeneralDetailSchema = object47({
|
|
|
3963
4368
|
* UNCONSTRAINED on education rather than filtering the user out — the same
|
|
3964
4369
|
* opt-out reasoning `notificationPrefs` uses.
|
|
3965
4370
|
*/
|
|
3966
|
-
educationLevel:
|
|
4371
|
+
educationLevel: string37().oneOf(SupportedEducationLevels).optional().label("Education level"),
|
|
3967
4372
|
location: LocationSchema.required().label("Location"),
|
|
3968
4373
|
/**
|
|
3969
4374
|
* Where the account was created, captured once and never rewritten.
|
|
@@ -3979,38 +4384,38 @@ var UserGeneralDetailSchema = object47({
|
|
|
3979
4384
|
* - `location` derived from the user's self-entered profile location
|
|
3980
4385
|
* - `default` assumed (no signal available); presumption, not evidence
|
|
3981
4386
|
*/
|
|
3982
|
-
signupContext:
|
|
4387
|
+
signupContext: object49().shape({
|
|
3983
4388
|
// ISO 3166-1 alpha-2, uppercase — the shape `cf-ipcountry` returns, so
|
|
3984
4389
|
// measured and inferred values are directly comparable.
|
|
3985
|
-
country:
|
|
3986
|
-
locale:
|
|
3987
|
-
source:
|
|
3988
|
-
at:
|
|
4390
|
+
country: string37().trim().uppercase().length(2).required().label("Signup Country"),
|
|
4391
|
+
locale: string37().trim().required().label("Signup Locale"),
|
|
4392
|
+
source: string37().oneOf(SupportedSignupContextSources).required().label("Signup Context Source"),
|
|
4393
|
+
at: number19().required().label("Signup Context At")
|
|
3989
4394
|
}).optional().default(void 0).label("Signup Context"),
|
|
3990
|
-
profileVisibility:
|
|
4395
|
+
profileVisibility: string37().oneOf(SupportedUserProfileVisibilities).default("public" /* Public */).label("Profile Visibility")
|
|
3991
4396
|
}).noUnknown().strict().label("General Detail");
|
|
3992
4397
|
|
|
3993
4398
|
// src/user/user-job-preferences.schema.ts
|
|
3994
|
-
import { array as
|
|
3995
|
-
var UserJobPreferencesSchema =
|
|
4399
|
+
import { array as array19, boolean as boolean23, date as date2, number as number20, object as object50, string as string38 } from "yup";
|
|
4400
|
+
var UserJobPreferencesSchema = object50({
|
|
3996
4401
|
/**
|
|
3997
4402
|
* Whether the job seeker is openly signalling availability. Surfaces the
|
|
3998
4403
|
* "Open to work" badge on the public profile and boosts visibility in
|
|
3999
4404
|
* recruiter search. Defaults to `false` - users must opt in.
|
|
4000
4405
|
*/
|
|
4001
|
-
openToWork:
|
|
4406
|
+
openToWork: boolean23().default(false).label("Open to Work"),
|
|
4002
4407
|
/**
|
|
4003
4408
|
* How urgently the user is looking for their next job. Drives match scoring
|
|
4004
4409
|
* and can downgrade the visibility of expired or low-relevance postings for
|
|
4005
4410
|
* users in `passively_browsing` mode.
|
|
4006
4411
|
*/
|
|
4007
|
-
jobSearchUrgency:
|
|
4412
|
+
jobSearchUrgency: string38().oneOf(SupportedJobSearchUrgencies).required().label("Job Search Urgency"),
|
|
4008
4413
|
/**
|
|
4009
4414
|
* Locations the user wants to work in. Stores the full `LocationSchema`
|
|
4010
4415
|
* shape (country, city, state, geo, etc.) as returned by the locations
|
|
4011
4416
|
* autocomplete API.
|
|
4012
4417
|
*/
|
|
4013
|
-
jobLocations:
|
|
4418
|
+
jobLocations: array19().of(LocationSchema.required().label("Job Location")).min(1, "Pick at least one preferred location.").required().label("Job Locations"),
|
|
4014
4419
|
/**
|
|
4015
4420
|
* Seniority levels the user wants jobs to be matched against. Multi-select
|
|
4016
4421
|
* (up to 2) for borderline candidates.
|
|
@@ -4021,7 +4426,7 @@ var UserJobPreferencesSchema = object48({
|
|
|
4021
4426
|
* Both reuse the same `ExperienceLevel` taxonomy from `common.constant.ts`
|
|
4022
4427
|
* so search/match logic doesn't have to translate between two vocabularies.
|
|
4023
4428
|
*/
|
|
4024
|
-
targetExperienceLevels:
|
|
4429
|
+
targetExperienceLevels: array19().of(string38().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"),
|
|
4025
4430
|
/**
|
|
4026
4431
|
* Specializations the user is searching for - free-form titles.
|
|
4027
4432
|
*
|
|
@@ -4030,19 +4435,19 @@ var UserJobPreferencesSchema = object48({
|
|
|
4030
4435
|
* surfaces a curated "Popular Roles" picker for discovery, but the user
|
|
4031
4436
|
* can ultimately add any title; matching/normalization happens downstream.
|
|
4032
4437
|
*/
|
|
4033
|
-
jobRoles:
|
|
4438
|
+
jobRoles: array19().of(string38().trim().max(120).required()).min(1, "Pick at least one role.").required().label("Job Roles"),
|
|
4034
4439
|
/**
|
|
4035
4440
|
* Minimum acceptable annual base salary, in `minSalaryCurrency`.
|
|
4036
4441
|
* Stored as an integer in the currency's major unit (e.g. dollars, not cents).
|
|
4037
4442
|
* Defaults to 0 ("any salary") rather than being optional - every job-seeker
|
|
4038
4443
|
* has a floor, even if it's zero.
|
|
4039
4444
|
*/
|
|
4040
|
-
minSalary:
|
|
4041
|
-
minSalaryCurrency:
|
|
4445
|
+
minSalary: number20().integer().min(MIN_SALARY_LOWER_BOUND).max(MIN_SALARY_UPPER_BOUND).default(0).required().label("Minimum Salary"),
|
|
4446
|
+
minSalaryCurrency: string38().oneOf(SupportedSalaryCurrencies).default("USD").required().label("Minimum Salary Currency"),
|
|
4042
4447
|
/**
|
|
4043
4448
|
* Marketing-attribution capture from the final onboarding step.
|
|
4044
4449
|
*/
|
|
4045
|
-
referralSource:
|
|
4450
|
+
referralSource: string38().oneOf(SupportedReferralSources).required().label("Referral Source"),
|
|
4046
4451
|
/**
|
|
4047
4452
|
* Resumes the user has uploaded. Embedded directly on the user document
|
|
4048
4453
|
* (capped at 5) - they're cheap to denormalize, every wizard step that
|
|
@@ -4056,18 +4461,18 @@ var UserJobPreferencesSchema = object48({
|
|
|
4056
4461
|
* AI resume-builder flow - onboarding uploads land here, AI-built resumes
|
|
4057
4462
|
* live in their own collection.
|
|
4058
4463
|
*/
|
|
4059
|
-
resumes:
|
|
4060
|
-
|
|
4464
|
+
resumes: array19().of(
|
|
4465
|
+
object50({
|
|
4061
4466
|
// Stable id assigned on upload - used to address a specific entry
|
|
4062
4467
|
// for delete / set-primary operations without exposing the GCS URL
|
|
4063
4468
|
// as a route key.
|
|
4064
|
-
id:
|
|
4065
|
-
url:
|
|
4066
|
-
filename:
|
|
4067
|
-
sizeBytes:
|
|
4068
|
-
mimeType:
|
|
4469
|
+
id: string38().required().label("ID"),
|
|
4470
|
+
url: string38().required().label("Resume URL"),
|
|
4471
|
+
filename: string38().trim().max(255).optional().label("Filename"),
|
|
4472
|
+
sizeBytes: number20().integer().min(0).optional().label("Size (bytes)"),
|
|
4473
|
+
mimeType: string38().trim().max(120).optional().label("MIME Type"),
|
|
4069
4474
|
uploadedAt: date2().required().label("Uploaded At"),
|
|
4070
|
-
isPrimary:
|
|
4475
|
+
isPrimary: boolean23().default(false).label("Is Primary")
|
|
4071
4476
|
}).noUnknown().strict().label("Resume")
|
|
4072
4477
|
).max(5, "You can keep at most 5 resumes on file.").default([]).label("Resumes"),
|
|
4073
4478
|
/**
|
|
@@ -4094,92 +4499,92 @@ var UserJobPreferencesSchema = object48({
|
|
|
4094
4499
|
* APIs. If `user.<field>` is empty there, the correct behavior is empty,
|
|
4095
4500
|
* because the user has not confirmed it yet.
|
|
4096
4501
|
*/
|
|
4097
|
-
pendingPrefill:
|
|
4098
|
-
headline:
|
|
4099
|
-
aboutMe:
|
|
4100
|
-
mobile:
|
|
4502
|
+
pendingPrefill: object50({
|
|
4503
|
+
headline: string38().trim().optional().label("Pending Headline"),
|
|
4504
|
+
aboutMe: string38().trim().optional().label("Pending About Me"),
|
|
4505
|
+
mobile: string38().trim().optional().label("Pending Mobile"),
|
|
4101
4506
|
location: LocationSchema.optional().default(void 0).label("Pending Location"),
|
|
4102
|
-
experienceLevel:
|
|
4103
|
-
socialAccounts:
|
|
4104
|
-
workExperiences:
|
|
4105
|
-
educations:
|
|
4507
|
+
experienceLevel: string38().oneOf(SupportedExperienceLevels).optional().label("Pending Experience Level"),
|
|
4508
|
+
socialAccounts: array19().of(SocialAccountSchema.required()).optional().label("Pending Social Accounts"),
|
|
4509
|
+
workExperiences: array19().of(WorkExperienceSchema.required()).optional().label("Pending Work Experiences"),
|
|
4510
|
+
educations: array19().of(EducationSchema.required()).optional().label("Pending Educations")
|
|
4106
4511
|
}).nullable().optional().default(void 0).label("Pending Prefill")
|
|
4107
4512
|
}).noUnknown().strict().label("User Job Preferences Schema");
|
|
4108
4513
|
|
|
4109
4514
|
// src/user/user-recruiter-profile.schema.ts
|
|
4110
|
-
import { array as
|
|
4111
|
-
var RecruiterPageLinkSchema =
|
|
4515
|
+
import { array as array20, object as object51, string as string39 } from "yup";
|
|
4516
|
+
var RecruiterPageLinkSchema = object51({
|
|
4112
4517
|
page: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Company Page"),
|
|
4113
|
-
jobTitle:
|
|
4518
|
+
jobTitle: string39().trim().max(100).optional().label("Job Title")
|
|
4114
4519
|
}).noUnknown().strict().label("Recruiter Page Link");
|
|
4115
|
-
var UserRecruiterProfileSchema =
|
|
4116
|
-
recruiterProfile:
|
|
4117
|
-
hiringFor:
|
|
4520
|
+
var UserRecruiterProfileSchema = object51({
|
|
4521
|
+
recruiterProfile: object51({
|
|
4522
|
+
hiringFor: array20().of(RecruiterPageLinkSchema).default([]).label("Hiring For")
|
|
4118
4523
|
}).optional().default(void 0).label("Recruiter Profile")
|
|
4119
4524
|
}).noUnknown().strict().label("User Recruiter Profile");
|
|
4120
4525
|
|
|
4121
4526
|
// src/user/user-coordinator-profile.schema.ts
|
|
4122
|
-
import { array as
|
|
4123
|
-
var CoordinatorPageLinkSchema =
|
|
4527
|
+
import { array as array21, object as object52, string as string40 } from "yup";
|
|
4528
|
+
var CoordinatorPageLinkSchema = object52({
|
|
4124
4529
|
page: PageSchema.pick(["name", "slug", "type", "logo"]).deepPartial().concat(PageSchema.pick(["name", "type"])).required().label("Institute Page"),
|
|
4125
|
-
jobTitle:
|
|
4530
|
+
jobTitle: string40().trim().max(100).optional().label("Job Title")
|
|
4126
4531
|
}).noUnknown().strict().label("Coordinator Page Link");
|
|
4127
|
-
var UserCoordinatorProfileSchema =
|
|
4128
|
-
coordinatorProfile:
|
|
4129
|
-
coordinatesAt:
|
|
4532
|
+
var UserCoordinatorProfileSchema = object52({
|
|
4533
|
+
coordinatorProfile: object52({
|
|
4534
|
+
coordinatesAt: array21().of(CoordinatorPageLinkSchema).default([]).label("Coordinates At")
|
|
4130
4535
|
}).optional().default(void 0).label("Coordinator Profile")
|
|
4131
4536
|
}).noUnknown().strict().label("User Coordinator Profile");
|
|
4132
4537
|
|
|
4133
4538
|
// src/user/user.schema.ts
|
|
4134
|
-
var UserSchema =
|
|
4539
|
+
var UserSchema = object53({
|
|
4135
4540
|
/**
|
|
4136
4541
|
* Related auth account id from auth Server (e.g. Better auth https://auth.thejob.dev)
|
|
4137
4542
|
*/
|
|
4138
|
-
authAccountId:
|
|
4543
|
+
authAccountId: string41().required().label("Auth Account ID"),
|
|
4139
4544
|
/**
|
|
4140
4545
|
* Social media information about the user (e.g. LinkedIn, GitHub, etc.)
|
|
4141
4546
|
*/
|
|
4142
|
-
socialAccounts:
|
|
4547
|
+
socialAccounts: array22().of(SocialAccountSchema).default([]).label("Social Accounts"),
|
|
4143
4548
|
/**
|
|
4144
4549
|
* Work experience information about the user
|
|
4145
4550
|
*/
|
|
4146
|
-
workExperiences:
|
|
4551
|
+
workExperiences: array22().of(WorkExperienceSchema).required().default([]).label("Work Experiences"),
|
|
4147
4552
|
/**
|
|
4148
4553
|
* Education information about the user
|
|
4149
4554
|
*/
|
|
4150
|
-
educations:
|
|
4555
|
+
educations: array22().of(EducationSchema).required().default([]).label("Educations"),
|
|
4151
4556
|
/**
|
|
4152
4557
|
* Skills information about the user
|
|
4153
4558
|
*/
|
|
4154
|
-
skills:
|
|
4559
|
+
skills: array22().of(UserSkillSchema).required().default([]).label("Skills"),
|
|
4155
4560
|
/**
|
|
4156
4561
|
* Projects information about the user
|
|
4157
4562
|
*/
|
|
4158
|
-
projects:
|
|
4563
|
+
projects: array22().of(UserProjectSchema).default([]).label("Projects"),
|
|
4159
4564
|
/**
|
|
4160
4565
|
* Certifications information about the user
|
|
4161
4566
|
*/
|
|
4162
|
-
certifications:
|
|
4567
|
+
certifications: array22().of(UserCertificationSchema).default([]).label("Certifications"),
|
|
4163
4568
|
/**
|
|
4164
4569
|
* Interests information about the user.
|
|
4165
4570
|
*/
|
|
4166
|
-
interests:
|
|
4571
|
+
interests: array22().of(UserInterestSchema).optional().default([]).label("Interests"),
|
|
4167
4572
|
/**
|
|
4168
4573
|
* Languages information about the user
|
|
4169
4574
|
*/
|
|
4170
|
-
languages:
|
|
4575
|
+
languages: array22().of(UserLanguageSchema).required().default([]).label("Languages"),
|
|
4171
4576
|
/**
|
|
4172
4577
|
* Additional information about the user
|
|
4173
4578
|
*/
|
|
4174
|
-
additionalInfo:
|
|
4579
|
+
additionalInfo: array22().of(UserAdditionalInfoSchema).default([]).label("Additional Information"),
|
|
4175
4580
|
/**
|
|
4176
4581
|
* Status of the user account
|
|
4177
4582
|
*/
|
|
4178
|
-
status:
|
|
4583
|
+
status: string41().oneOf(SupportedUserStatuses).required().label("Status"),
|
|
4179
4584
|
/**
|
|
4180
4585
|
* Roles assigned to the user
|
|
4181
4586
|
*/
|
|
4182
|
-
roles:
|
|
4587
|
+
roles: array22().of(string41().oneOf(SupportedUserRoles)).required().default(DefaultUserRoles).label("Roles"),
|
|
4183
4588
|
/**
|
|
4184
4589
|
* Explicit consent to receive marketing email (newsletters, job alerts by
|
|
4185
4590
|
* broadcast, product updates). Marketing sends are HARD-GATED on
|
|
@@ -4191,18 +4596,18 @@ var UserSchema = object51({
|
|
|
4191
4596
|
* unsubscribe sets `subscribed=false` so consent and the email-service
|
|
4192
4597
|
* suppression list stay consistent. Defaults to NOT subscribed (opt-in).
|
|
4193
4598
|
*/
|
|
4194
|
-
marketingConsent:
|
|
4195
|
-
subscribed:
|
|
4599
|
+
marketingConsent: object53({
|
|
4600
|
+
subscribed: boolean24().default(false).label("Subscribed to marketing email"),
|
|
4196
4601
|
/** Epoch ms of the last consent change (opt-in or opt-out). */
|
|
4197
|
-
updatedAt:
|
|
4602
|
+
updatedAt: number21().optional().label("Consent updated at"),
|
|
4198
4603
|
/** Where the consent change originated, e.g. `onboarding`, `unsubscribe`, `settings`. */
|
|
4199
|
-
source:
|
|
4604
|
+
source: string41().optional().label("Consent source"),
|
|
4200
4605
|
/**
|
|
4201
4606
|
* How often the user receives job-alert emails. `off` disables job alerts
|
|
4202
4607
|
* only; other marketing stays governed by `subscribed`. Unset means the
|
|
4203
4608
|
* user has not chosen a cadence yet.
|
|
4204
4609
|
*/
|
|
4205
|
-
jobAlertFrequency:
|
|
4610
|
+
jobAlertFrequency: string41().oneOf(SupportedJobAlertFrequencies).optional().label("Job alert frequency")
|
|
4206
4611
|
}).default({ subscribed: false }).label("Marketing Consent"),
|
|
4207
4612
|
/**
|
|
4208
4613
|
* Per-channel toggles for NOTIFICATION email — mail about activity on the
|
|
@@ -4217,11 +4622,11 @@ var UserSchema = object51({
|
|
|
4217
4622
|
*
|
|
4218
4623
|
* Transactional mail (magic-link, verification) ignores this object entirely.
|
|
4219
4624
|
*/
|
|
4220
|
-
notificationPrefs:
|
|
4221
|
-
groupActivity:
|
|
4222
|
-
jobActivity:
|
|
4223
|
-
applicationUpdates:
|
|
4224
|
-
productUpdates:
|
|
4625
|
+
notificationPrefs: object53({
|
|
4626
|
+
groupActivity: boolean24().default(true).label("Group activity email"),
|
|
4627
|
+
jobActivity: boolean24().default(true).label("Job activity email"),
|
|
4628
|
+
applicationUpdates: boolean24().default(true).label("Application update email"),
|
|
4629
|
+
productUpdates: boolean24().default(false).label("Product update email")
|
|
4225
4630
|
}).default({
|
|
4226
4631
|
groupActivity: true,
|
|
4227
4632
|
jobActivity: true,
|
|
@@ -4248,21 +4653,21 @@ var UserSchema = object51({
|
|
|
4248
4653
|
* subscription (see `PushSubscriptionSchema`). This flag is the user's
|
|
4249
4654
|
* intent, the subscription is the browser grant, and both are required.
|
|
4250
4655
|
*/
|
|
4251
|
-
pushConsent:
|
|
4252
|
-
subscribed:
|
|
4656
|
+
pushConsent: object53({
|
|
4657
|
+
subscribed: boolean24().default(false).label("Subscribed to push notifications"),
|
|
4253
4658
|
/** Epoch ms of the last consent change (opt-in or opt-out). */
|
|
4254
|
-
updatedAt:
|
|
4659
|
+
updatedAt: number21().optional().label("Push consent updated at"),
|
|
4255
4660
|
/** Where the change originated, e.g. `onboarding`, `settings`, `prompt`. */
|
|
4256
|
-
source:
|
|
4661
|
+
source: string41().optional().label("Push consent source")
|
|
4257
4662
|
}).default({ subscribed: false }).label("Push Consent"),
|
|
4258
4663
|
/**
|
|
4259
4664
|
* Vector embedding of the user's profile for semantic/hybrid search.
|
|
4260
4665
|
* Generated from a structured summary of skills, experience, education, etc.
|
|
4261
4666
|
* Only generated for public profiles with sufficient completeness (≥60%).
|
|
4262
4667
|
*/
|
|
4263
|
-
embedding:
|
|
4264
|
-
vector:
|
|
4265
|
-
model:
|
|
4668
|
+
embedding: object53({
|
|
4669
|
+
vector: array22(number21().required()).optional().label("Embedding vector"),
|
|
4670
|
+
model: string41().optional().label("Embedding model")
|
|
4266
4671
|
}).nullable().optional().label("Embedding"),
|
|
4267
4672
|
/**
|
|
4268
4673
|
* Epoch ms the account was created, assigned by the storing service.
|
|
@@ -4277,12 +4682,12 @@ var UserSchema = object51({
|
|
|
4277
4682
|
* `updatedAt` is deliberately NOT added alongside it: nothing derives from it
|
|
4278
4683
|
* yet, and an optional field is only safe to add when something needs it.
|
|
4279
4684
|
*/
|
|
4280
|
-
createdAt:
|
|
4685
|
+
createdAt: number21().optional().label("Created At")
|
|
4281
4686
|
}).concat(UserGeneralDetailSchema).concat(UserJobPreferencesSchema).concat(UserRecruiterProfileSchema).concat(UserCoordinatorProfileSchema).noUnknown().strict().label("User Schema");
|
|
4282
4687
|
|
|
4283
4688
|
// src/user/push-subscription.schema.ts
|
|
4284
|
-
import { number as
|
|
4285
|
-
var PushSubscriptionSchema =
|
|
4689
|
+
import { number as number22, object as object54, string as string42 } from "yup";
|
|
4690
|
+
var PushSubscriptionSchema = object54({
|
|
4286
4691
|
/**
|
|
4287
4692
|
* The user this subscription belongs to, by the `shortId` every service
|
|
4288
4693
|
* keys a user on, matching `UserSchema.shortId`.
|
|
@@ -4296,7 +4701,7 @@ var PushSubscriptionSchema = object52({
|
|
|
4296
4701
|
* `shortId` of its OWN (see `PushSubscriptionRecord`); one field cannot be
|
|
4297
4702
|
* both the row's id and its owner's.
|
|
4298
4703
|
*/
|
|
4299
|
-
userShortId:
|
|
4704
|
+
userShortId: string42().required().label("User Short ID"),
|
|
4300
4705
|
/**
|
|
4301
4706
|
* The push service URL the browser issued. Vendor-specific (FCM, Mozilla,
|
|
4302
4707
|
* Apple) and effectively unbounded in length, so it carries no length cap.
|
|
@@ -4305,16 +4710,16 @@ var PushSubscriptionSchema = object52({
|
|
|
4305
4710
|
* browser sends back unchanged, and what a 404/410 response identifies as
|
|
4306
4711
|
* dead. Upserts and deletes both key on it.
|
|
4307
4712
|
*/
|
|
4308
|
-
endpoint:
|
|
4713
|
+
endpoint: string42().required().label("Push Endpoint"),
|
|
4309
4714
|
/**
|
|
4310
4715
|
* Encryption material from the browser. Web Push payloads are encrypted to
|
|
4311
4716
|
* these keys, so a row missing either one cannot be delivered to at all.
|
|
4312
4717
|
*/
|
|
4313
|
-
keys:
|
|
4718
|
+
keys: object54({
|
|
4314
4719
|
/** Client public key, base64url. */
|
|
4315
|
-
p256dh:
|
|
4720
|
+
p256dh: string42().required().label("P256DH Key"),
|
|
4316
4721
|
/** Client auth secret, base64url. */
|
|
4317
|
-
auth:
|
|
4722
|
+
auth: string42().required().label("Auth Secret")
|
|
4318
4723
|
}).required().label("Push Keys"),
|
|
4319
4724
|
/**
|
|
4320
4725
|
* Epoch ms the push service says the subscription expires, when it says
|
|
@@ -4322,22 +4727,22 @@ var PushSubscriptionSchema = object52({
|
|
|
4322
4727
|
* informational and never the basis for pruning. A 404/410 on send is the
|
|
4323
4728
|
* only reliable death signal.
|
|
4324
4729
|
*/
|
|
4325
|
-
expirationTime:
|
|
4730
|
+
expirationTime: number22().nullable().optional().label("Expiration Time"),
|
|
4326
4731
|
/**
|
|
4327
4732
|
* The subscribing browser's user agent, kept so a user can recognise their
|
|
4328
4733
|
* own devices in a "where you receive notifications" list. Display only:
|
|
4329
4734
|
* never parsed, and never used to decide delivery.
|
|
4330
4735
|
*/
|
|
4331
|
-
userAgent:
|
|
4736
|
+
userAgent: string42().optional().label("User Agent"),
|
|
4332
4737
|
/** Epoch ms the subscription was first registered. */
|
|
4333
|
-
createdAt:
|
|
4738
|
+
createdAt: number22().optional().label("Created At"),
|
|
4334
4739
|
/**
|
|
4335
4740
|
* Epoch ms this subscription was last confirmed live, refreshed when the
|
|
4336
4741
|
* browser re-registers it. A subscription that stops being refreshed is a
|
|
4337
4742
|
* device that stopped visiting, which is useful for pruning rows that never
|
|
4338
4743
|
* fail loudly enough to be caught by a 410.
|
|
4339
4744
|
*/
|
|
4340
|
-
lastSeenAt:
|
|
4745
|
+
lastSeenAt: number22().optional().label("Last Seen At"),
|
|
4341
4746
|
/**
|
|
4342
4747
|
* Epoch ms the owner explicitly signed out on this device, or absent.
|
|
4343
4748
|
*
|
|
@@ -4347,12 +4752,12 @@ var PushSubscriptionSchema = object52({
|
|
|
4347
4752
|
* so that a MISSING row keeps one meaning to the browser ("stop, this device
|
|
4348
4753
|
* was removed"), which it acts on by dropping its own subscription.
|
|
4349
4754
|
*/
|
|
4350
|
-
signedOutAt:
|
|
4755
|
+
signedOutAt: number22().nullable().optional().label("Signed Out At")
|
|
4351
4756
|
}).noUnknown().strict().label("Push Subscription Schema");
|
|
4352
4757
|
|
|
4353
4758
|
// src/user/user-completeness.schema.ts
|
|
4354
|
-
import { object as
|
|
4355
|
-
var UserCompletenessSchema =
|
|
4759
|
+
import { object as object55 } from "yup";
|
|
4760
|
+
var UserCompletenessSchema = object55({
|
|
4356
4761
|
additionalInfo: CompletenessScoreSchema(0).label("Additional Info"),
|
|
4357
4762
|
// Optional
|
|
4358
4763
|
certifications: CompletenessScoreSchema(0).label("Certifications"),
|
|
@@ -4376,10 +4781,14 @@ var StudentCompletenessSchema = UserCompletenessSchema.omit([
|
|
|
4376
4781
|
export {
|
|
4377
4782
|
AnswerChoiceType,
|
|
4378
4783
|
ApplicationReceivePreference,
|
|
4784
|
+
AuditFilterSchema,
|
|
4785
|
+
AuditSchema,
|
|
4379
4786
|
BillingPeriod,
|
|
4380
4787
|
BillingSubscriptionSchema,
|
|
4381
4788
|
BillingTransactionSchema,
|
|
4382
4789
|
CAMPAIGN_MAX_RECIPIENTS_CEILING,
|
|
4790
|
+
CONCEPT_ID_PATTERN,
|
|
4791
|
+
CONCEPT_TYPE_PATTERN,
|
|
4383
4792
|
CONSUME_MAX_UNITS,
|
|
4384
4793
|
CampaignDataSourceSchema,
|
|
4385
4794
|
CampaignEndKind,
|
|
@@ -4395,6 +4804,11 @@ export {
|
|
|
4395
4804
|
Common,
|
|
4396
4805
|
CompensationType,
|
|
4397
4806
|
CompletenessScoreSchema,
|
|
4807
|
+
ConceptFilterSchema,
|
|
4808
|
+
ConceptMembershipSchema,
|
|
4809
|
+
ConceptProposalFilterSchema,
|
|
4810
|
+
ConceptProposalSchema,
|
|
4811
|
+
ConceptSchema,
|
|
4398
4812
|
ContactTypes,
|
|
4399
4813
|
CoordinatorPageLinkSchema,
|
|
4400
4814
|
CountryFilterSchema,
|
|
@@ -4460,6 +4874,7 @@ export {
|
|
|
4460
4874
|
MailingListFilterSchema,
|
|
4461
4875
|
MailingListSchema,
|
|
4462
4876
|
MoneySchema,
|
|
4877
|
+
NormalizeContextSchema,
|
|
4463
4878
|
NotificationType,
|
|
4464
4879
|
OccurrenceStatus,
|
|
4465
4880
|
PREFILL_MIRRORED_KEYS,
|
|
@@ -4479,6 +4894,8 @@ export {
|
|
|
4479
4894
|
PostSchema,
|
|
4480
4895
|
PostStatus,
|
|
4481
4896
|
ProficiencyLevel,
|
|
4897
|
+
ProposalCandidateSchema,
|
|
4898
|
+
ProposalMessageSchema,
|
|
4482
4899
|
PushSubscriptionSchema,
|
|
4483
4900
|
QuestionSchema,
|
|
4484
4901
|
QuestionType,
|
|
@@ -4486,9 +4903,15 @@ export {
|
|
|
4486
4903
|
ReadAndAcknowledgeQuestionSchema,
|
|
4487
4904
|
RecruiterPageLinkSchema,
|
|
4488
4905
|
ReferralSource,
|
|
4906
|
+
ReleaseFilterSchema,
|
|
4907
|
+
ReleaseSchema,
|
|
4489
4908
|
ReportReason,
|
|
4490
4909
|
ReportSchema,
|
|
4910
|
+
ResolverSettingsSchema,
|
|
4911
|
+
ResolverVerificationSchema,
|
|
4491
4912
|
ResourceType,
|
|
4913
|
+
SCHEDULE_MAX_HOURS,
|
|
4914
|
+
SCHEDULE_MIN_HOURS,
|
|
4492
4915
|
SITEMAP_FORMAT,
|
|
4493
4916
|
SYSTEM_DATE_FORMAT,
|
|
4494
4917
|
SavedSearchSchema,
|
|
@@ -4503,14 +4926,17 @@ export {
|
|
|
4503
4926
|
StudentCompletenessSchema,
|
|
4504
4927
|
StudyType,
|
|
4505
4928
|
SubscriptionStatus,
|
|
4929
|
+
SuggestedHomeSchema,
|
|
4506
4930
|
SupportedAnswerChoiceTypes,
|
|
4507
4931
|
SupportedApplicationReceivePreferences,
|
|
4932
|
+
SupportedAuditStatuses,
|
|
4508
4933
|
SupportedBillingPeriods,
|
|
4509
4934
|
SupportedCampaignEndKinds,
|
|
4510
4935
|
SupportedCampaignIntervalUnits,
|
|
4511
4936
|
SupportedCampaignStatuses,
|
|
4512
4937
|
SupportedCampaignTriggerKinds,
|
|
4513
4938
|
SupportedCompensationTypes,
|
|
4939
|
+
SupportedConceptSources,
|
|
4514
4940
|
SupportedContactTypes,
|
|
4515
4941
|
SupportedEducationLevels,
|
|
4516
4942
|
SupportedEmployeeCounts,
|
|
@@ -4535,6 +4961,7 @@ export {
|
|
|
4535
4961
|
SupportedJobSearchUrgencies,
|
|
4536
4962
|
SupportedJobStatuses,
|
|
4537
4963
|
SupportedJobSubCategories,
|
|
4964
|
+
SupportedMatchTypes,
|
|
4538
4965
|
SupportedNotificationTypes,
|
|
4539
4966
|
SupportedOccurrenceStatuses,
|
|
4540
4967
|
SupportedPaddleEnvironments,
|
|
@@ -4544,11 +4971,19 @@ export {
|
|
|
4544
4971
|
SupportedPlanKinds,
|
|
4545
4972
|
SupportedPlanStatuses,
|
|
4546
4973
|
SupportedPostStatuses,
|
|
4974
|
+
SupportedPrefilterRules,
|
|
4547
4975
|
SupportedProficiencyLevels,
|
|
4976
|
+
SupportedProposalFilters,
|
|
4977
|
+
SupportedProposalKinds,
|
|
4978
|
+
SupportedProposalMessageRoles,
|
|
4979
|
+
SupportedProposalStatuses,
|
|
4548
4980
|
SupportedQuestionTypes,
|
|
4549
4981
|
SupportedQuotaPeriods,
|
|
4550
4982
|
SupportedReferralSources,
|
|
4983
|
+
SupportedReleaseKinds,
|
|
4984
|
+
SupportedReleaseStatuses,
|
|
4551
4985
|
SupportedReportReasons,
|
|
4986
|
+
SupportedResolverVerdicts,
|
|
4552
4987
|
SupportedResourceTypes,
|
|
4553
4988
|
SupportedSalaryCurrencies,
|
|
4554
4989
|
SupportedSavedSearchStatuses,
|
|
@@ -4556,19 +4991,31 @@ export {
|
|
|
4556
4991
|
SupportedSocialAccounts,
|
|
4557
4992
|
SupportedStudyTypes,
|
|
4558
4993
|
SupportedSubscriptionStatuses,
|
|
4994
|
+
SupportedTaxonomyJobKinds,
|
|
4995
|
+
SupportedTaxonomyJobStates,
|
|
4996
|
+
SupportedTaxonomyNodeKinds,
|
|
4997
|
+
SupportedTaxonomySources,
|
|
4559
4998
|
SupportedTemplateVariableBindingKinds,
|
|
4560
4999
|
SupportedTransactionStatuses,
|
|
5000
|
+
SupportedUnmatchedReasons,
|
|
5001
|
+
SupportedUnmatchedResolutions,
|
|
4561
5002
|
SupportedUserProfileVisibilities,
|
|
4562
5003
|
SupportedUserRoles,
|
|
4563
5004
|
SupportedUserStatuses,
|
|
4564
5005
|
SupportedWorkModes,
|
|
4565
5006
|
TAXONOMY_LABELS,
|
|
5007
|
+
TAXONOMY_NODE_ID_PATTERN,
|
|
5008
|
+
TaxonomyNodeFilterSchema,
|
|
5009
|
+
TaxonomyNodeSchema,
|
|
5010
|
+
TaxonomyScheduleSchema,
|
|
4566
5011
|
TemplateVariableBindingKind,
|
|
4567
5012
|
TemplateVariableBindingSchema,
|
|
4568
5013
|
TerminalCampaignStatuses,
|
|
4569
5014
|
TerminalGeoSyncStatuses,
|
|
4570
5015
|
TermsAcceptedSchema,
|
|
4571
5016
|
TransactionStatus,
|
|
5017
|
+
UnmatchedFilterSchema,
|
|
5018
|
+
UnmatchedTermSchema,
|
|
4572
5019
|
UserAdditionalInfoSchema,
|
|
4573
5020
|
UserCertificationSchema,
|
|
4574
5021
|
UserCompletenessSchema,
|
|
@@ -4587,6 +5034,9 @@ export {
|
|
|
4587
5034
|
UserSchema,
|
|
4588
5035
|
UserSkillSchema,
|
|
4589
5036
|
UserStatus,
|
|
5037
|
+
VOCABULARY_ID_PATTERN,
|
|
5038
|
+
VocabularySchema,
|
|
5039
|
+
VocabularyTypeSchema,
|
|
4590
5040
|
WorkExperienceSchema,
|
|
4591
5041
|
WorkMode,
|
|
4592
5042
|
canTransitionCampaign,
|