@bash-app/bash-common 30.433.0 → 30.435.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.
Files changed (111) hide show
  1. package/dist/__tests__/appleIapProducts.test.js +1 -0
  2. package/dist/__tests__/appleIapProducts.test.js.map +1 -1
  3. package/dist/__tests__/promoCodeScope.test.js +9 -2
  4. package/dist/__tests__/promoCodeScope.test.js.map +1 -1
  5. package/dist/__tests__/statusEnums.test.js +1 -0
  6. package/dist/__tests__/statusEnums.test.js.map +1 -1
  7. package/dist/appleIapProducts.d.ts +12 -2
  8. package/dist/appleIapProducts.d.ts.map +1 -1
  9. package/dist/appleIapProducts.js +13 -0
  10. package/dist/appleIapProducts.js.map +1 -1
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/intros/__tests__/introsReleaseGates.test.d.ts +2 -0
  16. package/dist/intros/__tests__/introsReleaseGates.test.d.ts.map +1 -0
  17. package/dist/intros/__tests__/introsReleaseGates.test.js +140 -0
  18. package/dist/intros/__tests__/introsReleaseGates.test.js.map +1 -0
  19. package/dist/intros/__tests__/psychExperiment.test.d.ts +2 -0
  20. package/dist/intros/__tests__/psychExperiment.test.d.ts.map +1 -0
  21. package/dist/intros/__tests__/psychExperiment.test.js +63 -0
  22. package/dist/intros/__tests__/psychExperiment.test.js.map +1 -0
  23. package/dist/intros/__tests__/reasons.test.d.ts +2 -0
  24. package/dist/intros/__tests__/reasons.test.d.ts.map +1 -0
  25. package/dist/intros/__tests__/reasons.test.js +72 -0
  26. package/dist/intros/__tests__/reasons.test.js.map +1 -0
  27. package/dist/intros/__tests__/sharedNotes.test.d.ts +2 -0
  28. package/dist/intros/__tests__/sharedNotes.test.d.ts.map +1 -0
  29. package/dist/intros/__tests__/sharedNotes.test.js +19 -0
  30. package/dist/intros/__tests__/sharedNotes.test.js.map +1 -0
  31. package/dist/intros/__tests__/transitions.test.d.ts +2 -0
  32. package/dist/intros/__tests__/transitions.test.d.ts.map +1 -0
  33. package/dist/intros/__tests__/transitions.test.js +43 -0
  34. package/dist/intros/__tests__/transitions.test.js.map +1 -0
  35. package/dist/intros/__tests__/warmDisclosure.test.d.ts +2 -0
  36. package/dist/intros/__tests__/warmDisclosure.test.d.ts.map +1 -0
  37. package/dist/intros/__tests__/warmDisclosure.test.js +10 -0
  38. package/dist/intros/__tests__/warmDisclosure.test.js.map +1 -0
  39. package/dist/intros/age.d.ts +4 -0
  40. package/dist/intros/age.d.ts.map +1 -0
  41. package/dist/intros/age.js +14 -0
  42. package/dist/intros/age.js.map +1 -0
  43. package/dist/intros/attendance.d.ts +11 -0
  44. package/dist/intros/attendance.d.ts.map +1 -0
  45. package/dist/intros/attendance.js +27 -0
  46. package/dist/intros/attendance.js.map +1 -0
  47. package/dist/intros/attributeCatalog.d.ts +17 -0
  48. package/dist/intros/attributeCatalog.d.ts.map +1 -0
  49. package/dist/intros/attributeCatalog.js +96 -0
  50. package/dist/intros/attributeCatalog.js.map +1 -0
  51. package/dist/intros/index.d.ts +10 -0
  52. package/dist/intros/index.d.ts.map +1 -0
  53. package/dist/intros/index.js +10 -0
  54. package/dist/intros/index.js.map +1 -0
  55. package/dist/intros/intents.d.ts +8 -0
  56. package/dist/intros/intents.d.ts.map +1 -0
  57. package/dist/intros/intents.js +44 -0
  58. package/dist/intros/intents.js.map +1 -0
  59. package/dist/intros/psychExperiment.d.ts +29 -0
  60. package/dist/intros/psychExperiment.d.ts.map +1 -0
  61. package/dist/intros/psychExperiment.js +82 -0
  62. package/dist/intros/psychExperiment.js.map +1 -0
  63. package/dist/intros/reasons.d.ts +38 -0
  64. package/dist/intros/reasons.d.ts.map +1 -0
  65. package/dist/intros/reasons.js +162 -0
  66. package/dist/intros/reasons.js.map +1 -0
  67. package/dist/intros/sharedNotes.d.ts +10 -0
  68. package/dist/intros/sharedNotes.d.ts.map +1 -0
  69. package/dist/intros/sharedNotes.js +56 -0
  70. package/dist/intros/sharedNotes.js.map +1 -0
  71. package/dist/intros/transitions.d.ts +29 -0
  72. package/dist/intros/transitions.d.ts.map +1 -0
  73. package/dist/intros/transitions.js +128 -0
  74. package/dist/intros/transitions.js.map +1 -0
  75. package/dist/intros/validation.d.ts +50 -0
  76. package/dist/intros/validation.d.ts.map +1 -0
  77. package/dist/intros/validation.js +212 -0
  78. package/dist/intros/validation.js.map +1 -0
  79. package/dist/mirroredPrismaEnums.d.ts +1 -0
  80. package/dist/mirroredPrismaEnums.d.ts.map +1 -1
  81. package/dist/mirroredPrismaEnums.js +1 -0
  82. package/dist/mirroredPrismaEnums.js.map +1 -1
  83. package/dist/promoCodeScope.d.ts +7 -1
  84. package/dist/promoCodeScope.d.ts.map +1 -1
  85. package/dist/promoCodeScope.js +13 -4
  86. package/dist/promoCodeScope.js.map +1 -1
  87. package/package.json +1 -1
  88. package/prisma/schema.prisma +321 -2
  89. package/src/__tests__/appleIapProducts.test.ts +3 -0
  90. package/src/__tests__/promoCodeScope.test.ts +16 -3
  91. package/src/__tests__/statusEnums.test.ts +1 -0
  92. package/src/appleIapProducts.ts +29 -2
  93. package/src/index.ts +1 -0
  94. package/src/intros/__tests__/introsReleaseGates.test.ts +181 -0
  95. package/src/intros/__tests__/psychExperiment.test.ts +99 -0
  96. package/src/intros/__tests__/reasons.test.ts +122 -0
  97. package/src/intros/__tests__/sharedNotes.test.ts +20 -0
  98. package/src/intros/__tests__/transitions.test.ts +61 -0
  99. package/src/intros/__tests__/warmDisclosure.test.ts +10 -0
  100. package/src/intros/age.ts +13 -0
  101. package/src/intros/attendance.ts +33 -0
  102. package/src/intros/attributeCatalog.ts +113 -0
  103. package/src/intros/index.ts +9 -0
  104. package/src/intros/intents.ts +49 -0
  105. package/src/intros/psychExperiment.ts +130 -0
  106. package/src/intros/reasons.ts +187 -0
  107. package/src/intros/sharedNotes.ts +59 -0
  108. package/src/intros/transitions.ts +172 -0
  109. package/src/intros/validation.ts +248 -0
  110. package/src/mirroredPrismaEnums.ts +1 -0
  111. package/src/promoCodeScope.ts +20 -4
@@ -0,0 +1,72 @@
1
+ import { eventScopedReason, introHint, pairMatchReason, rankEventForPair, eventReasonSpecificity, romancePairFits, } from "../reasons.js";
2
+ describe("matching reasons", () => {
3
+ it("does not globally match two people who only both want friends", () => {
4
+ expect(pairMatchReason({ intents: ["Friends"], topics: ["jazz"], work: [] }, { intents: ["Friends"], topics: ["photography"], work: [] })).toBeNull();
5
+ });
6
+ it("matches friends who share a topic and explains it without a name", () => {
7
+ const reason = pairMatchReason({ intents: ["Friends"], topics: ["photography"], work: [] }, { intents: ["Friends"], topics: ["Photography"], work: [] });
8
+ expect(reason?.intent).toBe("Friends");
9
+ expect(introHint(reason?.codes ?? [])).toMatch(/photography/i);
10
+ expect(introHint(reason?.codes ?? [])).not.toMatch(/Alex|Jordan/);
11
+ });
12
+ it("matches a mentor with someone looking for one", () => {
13
+ expect(pairMatchReason({ intents: ["MentorSeek"], topics: [], work: [] }, { intents: ["MentorOffer"], topics: [], work: [] })?.intent).toBe("MentorSeek");
14
+ });
15
+ it("allows romance only at an event that permits it", () => {
16
+ const people = {
17
+ a: { intents: ["Romance"], topics: [], work: [] },
18
+ b: { intents: ["Romance"], topics: [], work: [] },
19
+ };
20
+ expect(eventScopedReason(people.a, people.b, false)).toBeNull();
21
+ expect(eventScopedReason(people.a, people.b, true)?.intent).toBe("Romance");
22
+ });
23
+ it("rejects a romance pair that misses an age or gender limit and accepts an empty seeking list", () => {
24
+ const older = {
25
+ consented: true,
26
+ dob: new Date("1980-01-01T00:00:00Z"),
27
+ gender: "Female",
28
+ seekingGenders: ["Male"],
29
+ ageMin: 30,
30
+ ageMax: 45,
31
+ };
32
+ const youngerMale = {
33
+ consented: true,
34
+ dob: new Date("2000-06-01T00:00:00Z"),
35
+ gender: "Male",
36
+ seekingGenders: [],
37
+ ageMin: null,
38
+ ageMax: null,
39
+ };
40
+ const fittingMale = {
41
+ ...youngerMale,
42
+ dob: new Date("1990-06-01T00:00:00Z"),
43
+ };
44
+ const now = new Date("2026-10-20T00:00:00Z");
45
+ const profiles = {
46
+ a: { intents: ["Romance"], topics: [], work: [] },
47
+ b: { intents: ["Romance"], topics: [], work: [] },
48
+ };
49
+ expect(romancePairFits(older, youngerMale, now)).toBe(false);
50
+ expect(romancePairFits(older, fittingMale, now)).toBe(true);
51
+ expect(romancePairFits(older, { ...fittingMale, gender: "Female" }, now)).toBe(false);
52
+ expect(eventScopedReason(profiles.a, profiles.b, true, { a: older, b: youngerMale }, now)).toBeNull();
53
+ expect(pairMatchReason(profiles.a, profiles.b, { a: older, b: fittingMale }, now)?.intent).toBe("Romance");
54
+ expect(eventScopedReason(profiles.a, profiles.b, true, { a: older, b: { ...fittingMale, gender: "Female" } }, now)).toBeNull();
55
+ expect(eventScopedReason(profiles.a, profiles.b, true, { a: { ...older, seekingGenders: [] }, b: { ...fittingMale, seekingGenders: [] } }, now)?.intent).toBe("Romance");
56
+ });
57
+ it("still matches two people who only both want friends at an event, behind a shared interest", () => {
58
+ const broad = eventScopedReason({ intents: ["Friends"], topics: ["jazz"], work: [] }, { intents: ["Friends"], topics: ["photography"], work: [] }, false);
59
+ const specific = eventScopedReason({ intents: ["Friends"], topics: ["photography"], work: [] }, { intents: ["Friends"], topics: ["Photography"], work: [] }, false);
60
+ expect(broad?.intent).toBe("Friends");
61
+ expect(specific && eventReasonSpecificity(specific)).toBeGreaterThan(broad ? eventReasonSpecificity(broad) : 0);
62
+ expect(eventReasonSpecificity({ intent: "MentorSeek", codes: ["INTENT:MentorSeek"] })).toBeGreaterThan(specific ? eventReasonSpecificity(specific) : 0);
63
+ });
64
+ it("prefers a bash whose type matches a shared interest", () => {
65
+ const id = rankEventForPair([
66
+ { id: "concert", eventType: "Music", city: "Salt Lake City" },
67
+ { id: "mixer", eventType: "photography workshop", city: "Provo" },
68
+ ], ["SHARED_TOPIC:photography"]);
69
+ expect(id).toBe("mixer");
70
+ });
71
+ });
72
+ //# sourceMappingURL=reasons.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reasons.test.js","sourceRoot":"","sources":["../../../src/intros/__tests__/reasons.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sharedNotes.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharedNotes.test.d.ts","sourceRoot":"","sources":["../../../src/intros/__tests__/sharedNotes.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,19 @@
1
+ import { describeSharedNote } from "../sharedNotes.js";
2
+ describe("notes visible after reveal", () => {
3
+ it("describes an allowed note without turning it into a score", () => {
4
+ const note = describeSharedNote("BigFive", {
5
+ openness: 10,
6
+ conscientiousness: 20,
7
+ extraversion: 80,
8
+ agreeableness: 40,
9
+ neuroticism: 50,
10
+ });
11
+ expect(note?.tier).toBe("Research-backed construct");
12
+ expect(note?.text).toMatch(/Extraversion 80/);
13
+ expect(JSON.stringify(note)).not.toMatch(/compatibility/);
14
+ });
15
+ it("ignores a kind this catalog does not support", () => {
16
+ expect(describeSharedNote("Enneagram", "4")).toBeNull();
17
+ });
18
+ });
19
+ //# sourceMappingURL=sharedNotes.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharedNotes.test.js","sourceRoot":"","sources":["../../../src/intros/__tests__/sharedNotes.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,IAAI,GAAG,kBAAkB,CAAC,SAAS,EAAE;YACzC,QAAQ,EAAE,EAAE;YACZ,iBAAiB,EAAE,EAAE;YACrB,YAAY,EAAE,EAAE;YAChB,aAAa,EAAE,EAAE;YACjB,WAAW,EAAE,EAAE;SAChB,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QACrD,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,kBAAkB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=transitions.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transitions.test.d.ts","sourceRoot":"","sources":["../../../src/intros/__tests__/transitions.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,43 @@
1
+ import { applyIntroductionAction } from "../transitions.js";
2
+ const openMystery = {
3
+ source: "BashSuggested",
4
+ mode: "Mystery",
5
+ state: "Open",
6
+ closedReason: null,
7
+ interestLow: "Pending",
8
+ interestHigh: "Pending",
9
+ };
10
+ describe("introduction transitions", () => {
11
+ it("treats mutual interest as the reveal consent without revealing yet", () => {
12
+ const one = applyIntroductionAction(openMystery, "low", "interested");
13
+ expect(one.ok && one.state).toBe("Open");
14
+ if (!one.ok)
15
+ return;
16
+ const both = applyIntroductionAction({ ...openMystery, interestLow: one.interestLow, interestHigh: one.interestHigh }, "high", "interested");
17
+ expect(both.ok && both.state).toBe("Mutual");
18
+ expect(both.ok && both.revealNow).toBe(false);
19
+ });
20
+ it("reveals a warm intro only when both accept", () => {
21
+ const one = applyIntroductionAction({ ...openMystery, source: "Warm" }, "low", "sounds_good");
22
+ expect(one.ok && one.state).toBe("Open");
23
+ if (!one.ok)
24
+ return;
25
+ const both = applyIntroductionAction({
26
+ ...openMystery,
27
+ source: "Warm",
28
+ interestLow: one.interestLow,
29
+ interestHigh: one.interestHigh,
30
+ }, "high", "sounds_good");
31
+ expect(both.ok && both.revealNow).toBe(true);
32
+ });
33
+ it("lets a withdrawal close an intro before reveal", () => {
34
+ const result = applyIntroductionAction({ ...openMystery, state: "Mutual", interestLow: "Interested", interestHigh: "Interested" }, "low", "withdraw");
35
+ expect(result.ok && result.state).toBe("Closed");
36
+ expect(result.ok && result.closedReason).toBe("Withdrawn");
37
+ });
38
+ it("rejects say hi before reveal", () => {
39
+ const result = applyIntroductionAction(openMystery, "low", "say_hi");
40
+ expect(result.ok).toBe(false);
41
+ });
42
+ });
43
+ //# sourceMappingURL=transitions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transitions.test.js","sourceRoot":"","sources":["../../../src/intros/__tests__/transitions.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,eAAwB;IAChC,IAAI,EAAE,SAAkB;IACxB,KAAK,EAAE,MAAe;IACtB,YAAY,EAAE,IAAI;IAClB,WAAW,EAAE,SAAS;IACtB,YAAY,EAAE,SAAS;CACxB,CAAC;AAEF,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,GAAG,GAAG,uBAAuB,CAAC,WAAW,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;QACtE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO;QACpB,MAAM,IAAI,GAAG,uBAAuB,CAClC,EAAE,GAAG,WAAW,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,EAChF,MAAM,EACN,YAAY,CACb,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,GAAG,GAAG,uBAAuB,CACjC,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,EAClC,KAAK,EACL,aAAa,CACd,CAAC;QACF,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO;QACpB,MAAM,IAAI,GAAG,uBAAuB,CAClC;YACE,GAAG,WAAW;YACd,MAAM,EAAE,MAAM;YACd,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,YAAY,EAAE,GAAG,CAAC,YAAY;SAC/B,EACD,MAAM,EACN,aAAa,CACd,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,MAAM,GAAG,uBAAuB,CACpC,EAAE,GAAG,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,EAC1F,KAAK,EACL,UAAU,CACX,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,MAAM,GAAG,uBAAuB,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QACrE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=warmDisclosure.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warmDisclosure.test.d.ts","sourceRoot":"","sources":["../../../src/intros/__tests__/warmDisclosure.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ import { warmInviteNamesOtherPerson } from "../validation.js";
2
+ describe("warm intro disclosure", () => {
3
+ it("hides the other person's name unless both chose named intros", () => {
4
+ expect(warmInviteNamesOtherPerson("Named", "Named")).toBe(true);
5
+ expect(warmInviteNamesOtherPerson("Named", "Anonymous")).toBe(false);
6
+ expect(warmInviteNamesOtherPerson(null, "Named")).toBe(false);
7
+ expect(warmInviteNamesOtherPerson("Off", "Off")).toBe(false);
8
+ });
9
+ });
10
+ //# sourceMappingURL=warmDisclosure.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warmDisclosure.test.js","sourceRoot":"","sources":["../../../src/intros/__tests__/warmDisclosure.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAE9D,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,0BAA0B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChE,MAAM,CAAC,0BAA0B,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrE,MAAM,CAAC,0BAA0B,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9D,MAAM,CAAC,0BAA0B,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const INTROS_MINIMUM_AGE = 18;
2
+ export declare function ageInYears(dob: Date, now?: Date): number;
3
+ export declare function isIntrosAdult(dob: Date | null | undefined, now?: Date): boolean;
4
+ //# sourceMappingURL=age.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"age.d.ts","sourceRoot":"","sources":["../../src/intros/age.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,wBAAgB,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,OAAa,GAAG,MAAM,CAK9D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,OAAa,GAAG,OAAO,CAGrF"}
@@ -0,0 +1,14 @@
1
+ export const INTROS_MINIMUM_AGE = 18;
2
+ export function ageInYears(dob, now = new Date()) {
3
+ let age = now.getUTCFullYear() - dob.getUTCFullYear();
4
+ const month = now.getUTCMonth() - dob.getUTCMonth();
5
+ if (month < 0 || (month === 0 && now.getUTCDate() < dob.getUTCDate()))
6
+ age -= 1;
7
+ return age;
8
+ }
9
+ export function isIntrosAdult(dob, now = new Date()) {
10
+ if (!dob)
11
+ return false;
12
+ return ageInYears(dob, now) >= INTROS_MINIMUM_AGE;
13
+ }
14
+ //# sourceMappingURL=age.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"age.js","sourceRoot":"","sources":["../../src/intros/age.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAErC,MAAM,UAAU,UAAU,CAAC,GAAS,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;IACpD,IAAI,GAAG,GAAG,GAAG,CAAC,cAAc,EAAE,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;IACtD,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IACpD,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC;QAAE,GAAG,IAAI,CAAC,CAAC;IAChF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAA4B,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;IAC1E,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,OAAO,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,kBAAkB,CAAC;AACpD,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare const CONFIRMED_TICKET_STATUSES: readonly ["Pending", "P2PConfirmed", "CheckedIn", "Attended"];
2
+ export declare function isConfirmedTicketStatus(status: string | null | undefined): boolean;
3
+ export type AttendanceTier = "Recommended" | "Interested" | "Registered" | "CheckedIn";
4
+ /** Strongest public wording without evidence and disclosure consent. */
5
+ export declare function attendanceCopy(tier: AttendanceTier, shareRegistration: boolean): string;
6
+ export declare function visibleAttendanceTier(args: {
7
+ checkedIn: boolean;
8
+ registered: boolean;
9
+ shareRegistration: boolean;
10
+ }): AttendanceTier;
11
+ //# sourceMappingURL=attendance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attendance.d.ts","sourceRoot":"","sources":["../../src/intros/attendance.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,+DAK5B,CAAC;AAEX,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAElF;AAED,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,YAAY,GAAG,YAAY,GAAG,WAAW,CAAC;AAEvF,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,IAAI,EAAE,cAAc,EACpB,iBAAiB,EAAE,OAAO,GACzB,MAAM,CAIR;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,OAAO,CAAC;CAC5B,GAAG,cAAc,CAKjB"}
@@ -0,0 +1,27 @@
1
+ export const CONFIRMED_TICKET_STATUSES = [
2
+ "Pending",
3
+ "P2PConfirmed",
4
+ "CheckedIn",
5
+ "Attended",
6
+ ];
7
+ export function isConfirmedTicketStatus(status) {
8
+ return CONFIRMED_TICKET_STATUSES.includes(status ?? "");
9
+ }
10
+ /** Strongest public wording without evidence and disclosure consent. */
11
+ export function attendanceCopy(tier, shareRegistration) {
12
+ if (tier === "CheckedIn" && shareRegistration)
13
+ return "Checked in.";
14
+ if (tier === "Registered" && shareRegistration)
15
+ return "Your match has a spot.";
16
+ return "Could be a good night to meet someone new.";
17
+ }
18
+ export function visibleAttendanceTier(args) {
19
+ if (!args.shareRegistration)
20
+ return "Recommended";
21
+ if (args.checkedIn)
22
+ return "CheckedIn";
23
+ if (args.registered)
24
+ return "Registered";
25
+ return "Recommended";
26
+ }
27
+ //# sourceMappingURL=attendance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attendance.js","sourceRoot":"","sources":["../../src/intros/attendance.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,SAAS;IACT,cAAc;IACd,WAAW;IACX,UAAU;CACF,CAAC;AAEX,MAAM,UAAU,uBAAuB,CAAC,MAAiC;IACvE,OAAQ,yBAA+C,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;AACjF,CAAC;AAID,wEAAwE;AACxE,MAAM,UAAU,cAAc,CAC5B,IAAoB,EACpB,iBAA0B;IAE1B,IAAI,IAAI,KAAK,WAAW,IAAI,iBAAiB;QAAE,OAAO,aAAa,CAAC;IACpE,IAAI,IAAI,KAAK,YAAY,IAAI,iBAAiB;QAAE,OAAO,wBAAwB,CAAC;IAChF,OAAO,4CAA4C,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAIrC;IACC,IAAI,CAAC,IAAI,CAAC,iBAAiB;QAAE,OAAO,aAAa,CAAC;IAClD,IAAI,IAAI,CAAC,SAAS;QAAE,OAAO,WAAW,CAAC;IACvC,IAAI,IAAI,CAAC,UAAU;QAAE,OAAO,YAAY,CAAC;IACzC,OAAO,aAAa,CAAC;AACvB,CAAC"}
@@ -0,0 +1,17 @@
1
+ export declare const INTROS_ATTRIBUTE_KINDS: readonly ["BigFive", "MyersBriggs", "LocusOfControl", "CliftonStrengths", "EmotionalIntelligence", "HumanDesign"];
2
+ export type IntrosAttributeKind = (typeof INTROS_ATTRIBUTE_KINDS)[number];
3
+ export type IntrosEvidenceTier = "ResearchBackedConstruct" | "SelfReportedTypology" | "Exploratory";
4
+ export declare const CLIFTON_THEMES: readonly ["Achiever", "Learner", "Relator", "Strategic", "Woo", "Empathy", "Focus", "Ideation"];
5
+ export declare const HUMAN_DESIGN_TYPES: readonly ["Manifestor", "Generator", "ManifestingGenerator", "Projector", "Reflector"];
6
+ export declare function isIntrosAttributeKind(value: string): value is IntrosAttributeKind;
7
+ export declare function attributeEvidenceTier(kind: IntrosAttributeKind): IntrosEvidenceTier;
8
+ export declare function attributeMayBeUsedInExperiments(kind: IntrosAttributeKind): boolean;
9
+ export type AttributeValidation = {
10
+ ok: true;
11
+ value: unknown;
12
+ } | {
13
+ ok: false;
14
+ error: string;
15
+ };
16
+ export declare function validateAttributeValue(kind: IntrosAttributeKind, raw: unknown): AttributeValidation;
17
+ //# sourceMappingURL=attributeCatalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attributeCatalog.d.ts","sourceRoot":"","sources":["../../src/intros/attributeCatalog.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,mHAOzB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,MAAM,MAAM,kBAAkB,GAC1B,yBAAyB,GACzB,sBAAsB,GACtB,aAAa,CAAC;AAElB,eAAO,MAAM,cAAc,iGASjB,CAAC;AAEX,eAAO,MAAM,kBAAkB,wFAMrB,CAAC;AAEX,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,mBAAmB,CAEjF;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,kBAAkB,CAInF;AAED,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAElF;AAED,MAAM,MAAM,mBAAmB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9F,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,mBAAmB,EACzB,GAAG,EAAE,OAAO,GACX,mBAAmB,CA0DrB"}
@@ -0,0 +1,96 @@
1
+ export const INTROS_ATTRIBUTE_KINDS = [
2
+ "BigFive",
3
+ "MyersBriggs",
4
+ "LocusOfControl",
5
+ "CliftonStrengths",
6
+ "EmotionalIntelligence",
7
+ "HumanDesign",
8
+ ];
9
+ export const CLIFTON_THEMES = [
10
+ "Achiever",
11
+ "Learner",
12
+ "Relator",
13
+ "Strategic",
14
+ "Woo",
15
+ "Empathy",
16
+ "Focus",
17
+ "Ideation",
18
+ ];
19
+ export const HUMAN_DESIGN_TYPES = [
20
+ "Manifestor",
21
+ "Generator",
22
+ "ManifestingGenerator",
23
+ "Projector",
24
+ "Reflector",
25
+ ];
26
+ export function isIntrosAttributeKind(value) {
27
+ return INTROS_ATTRIBUTE_KINDS.includes(value);
28
+ }
29
+ export function attributeEvidenceTier(kind) {
30
+ if (kind === "BigFive" || kind === "LocusOfControl")
31
+ return "ResearchBackedConstruct";
32
+ if (kind === "HumanDesign")
33
+ return "Exploratory";
34
+ return "SelfReportedTypology";
35
+ }
36
+ export function attributeMayBeUsedInExperiments(kind) {
37
+ return attributeEvidenceTier(kind) !== "Exploratory";
38
+ }
39
+ export function validateAttributeValue(kind, raw) {
40
+ if (kind === "MyersBriggs") {
41
+ if (typeof raw !== "string" || !/^[EI][SN][TF][JP]$/i.test(raw)) {
42
+ return { ok: false, error: "Enter a 4-letter type such as ENFP" };
43
+ }
44
+ return { ok: true, value: raw.toUpperCase() };
45
+ }
46
+ if (kind === "LocusOfControl") {
47
+ if (raw !== "internal" && raw !== "external" && raw !== "mixed") {
48
+ return { ok: false, error: "Choose internal, external, or mixed" };
49
+ }
50
+ return { ok: true, value: raw };
51
+ }
52
+ if (kind === "EmotionalIntelligence") {
53
+ if (typeof raw !== "number" || !Number.isInteger(raw) || raw < 1 || raw > 5) {
54
+ return { ok: false, error: "Choose a number from 1 to 5" };
55
+ }
56
+ return { ok: true, value: raw };
57
+ }
58
+ if (kind === "HumanDesign") {
59
+ if (typeof raw !== "string" || !HUMAN_DESIGN_TYPES.includes(raw)) {
60
+ return { ok: false, error: "Choose a Human Design type" };
61
+ }
62
+ return { ok: true, value: raw };
63
+ }
64
+ if (kind === "CliftonStrengths") {
65
+ if (!Array.isArray(raw) || raw.length < 1 || raw.length > 5) {
66
+ return { ok: false, error: "Choose up to 5 themes" };
67
+ }
68
+ const themes = raw.filter((item) => typeof item === "string");
69
+ if (themes.length !== raw.length ||
70
+ themes.some((theme) => !CLIFTON_THEMES.includes(theme))) {
71
+ return { ok: false, error: "Use theme names only" };
72
+ }
73
+ return { ok: true, value: themes };
74
+ }
75
+ if (raw == null || typeof raw !== "object" || Array.isArray(raw)) {
76
+ return { ok: false, error: "Big Five needs five scores" };
77
+ }
78
+ const record = raw;
79
+ const keys = [
80
+ "openness",
81
+ "conscientiousness",
82
+ "extraversion",
83
+ "agreeableness",
84
+ "neuroticism",
85
+ ];
86
+ const next = {};
87
+ for (const key of keys) {
88
+ const n = record[key];
89
+ if (typeof n !== "number" || !Number.isInteger(n) || n < 0 || n > 100) {
90
+ return { ok: false, error: "Each Big Five score is a whole number from 0 to 100" };
91
+ }
92
+ next[key] = n;
93
+ }
94
+ return { ok: true, value: next };
95
+ }
96
+ //# sourceMappingURL=attributeCatalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attributeCatalog.js","sourceRoot":"","sources":["../../src/intros/attributeCatalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export * from "./age.js";
2
+ export * from "./attendance.js";
3
+ export * from "./attributeCatalog.js";
4
+ export * from "./intents.js";
5
+ export * from "./psychExperiment.js";
6
+ export * from "./reasons.js";
7
+ export * from "./sharedNotes.js";
8
+ export * from "./transitions.js";
9
+ export * from "./validation.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/intros/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,10 @@
1
+ export * from "./age.js";
2
+ export * from "./attendance.js";
3
+ export * from "./attributeCatalog.js";
4
+ export * from "./intents.js";
5
+ export * from "./psychExperiment.js";
6
+ export * from "./reasons.js";
7
+ export * from "./sharedNotes.js";
8
+ export * from "./transitions.js";
9
+ export * from "./validation.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/intros/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const INTROS_INTENTS: readonly ["Friends", "Professional", "MentorSeek", "MentorOffer", "Collaborator", "Romance"];
2
+ export type IntrosIntent = (typeof INTROS_INTENTS)[number];
3
+ export declare const INTROS_INTENT_LABELS: Record<IntrosIntent, string>;
4
+ export declare function isIntrosIntent(value: string): value is IntrosIntent;
5
+ /** Complementary intents. Romance only matches Romance. */
6
+ export declare function intentsComplement(a: readonly string[], b: readonly string[]): IntrosIntent | null;
7
+ export declare function isRomanceIntent(intent: string | null | undefined): boolean;
8
+ //# sourceMappingURL=intents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intents.d.ts","sourceRoot":"","sources":["../../src/intros/intents.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,8FAOjB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAO7D,CAAC;AAEF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,YAAY,CAEnE;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,SAAS,MAAM,EAAE,EACpB,CAAC,EAAE,SAAS,MAAM,EAAE,GACnB,YAAY,GAAG,IAAI,CAgBrB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE1E"}
@@ -0,0 +1,44 @@
1
+ export const INTROS_INTENTS = [
2
+ "Friends",
3
+ "Professional",
4
+ "MentorSeek",
5
+ "MentorOffer",
6
+ "Collaborator",
7
+ "Romance",
8
+ ];
9
+ export const INTROS_INTENT_LABELS = {
10
+ Friends: "Making friends",
11
+ Professional: "Professional networking",
12
+ MentorSeek: "Finding a mentor",
13
+ MentorOffer: "Offering mentorship",
14
+ Collaborator: "Finding collaborators",
15
+ Romance: "Romance",
16
+ };
17
+ export function isIntrosIntent(value) {
18
+ return INTROS_INTENTS.includes(value);
19
+ }
20
+ /** Complementary intents. Romance only matches Romance. */
21
+ export function intentsComplement(a, b) {
22
+ const left = new Set(a.filter(isIntrosIntent));
23
+ const right = new Set(b.filter(isIntrosIntent));
24
+ if (left.has("Romance") && right.has("Romance"))
25
+ return "Romance";
26
+ if (left.has("MentorSeek") && right.has("MentorOffer"))
27
+ return "MentorSeek";
28
+ if (left.has("MentorOffer") && right.has("MentorSeek"))
29
+ return "MentorOffer";
30
+ if ((left.has("Collaborator") &&
31
+ (right.has("Collaborator") || right.has("Professional"))) ||
32
+ (left.has("Professional") && right.has("Collaborator"))) {
33
+ return "Collaborator";
34
+ }
35
+ if (left.has("Professional") && right.has("Professional"))
36
+ return "Professional";
37
+ if (left.has("Friends") && right.has("Friends"))
38
+ return "Friends";
39
+ return null;
40
+ }
41
+ export function isRomanceIntent(intent) {
42
+ return intent === "Romance";
43
+ }
44
+ //# sourceMappingURL=intents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intents.js","sourceRoot":"","sources":["../../src/intros/intents.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,SAAS;IACT,cAAc;IACd,YAAY;IACZ,aAAa;IACb,cAAc;IACd,SAAS;CACD,CAAC;AAIX,MAAM,CAAC,MAAM,oBAAoB,GAAiC;IAChE,OAAO,EAAE,gBAAgB;IACzB,YAAY,EAAE,yBAAyB;IACvC,UAAU,EAAE,kBAAkB;IAC9B,WAAW,EAAE,qBAAqB;IAClC,YAAY,EAAE,uBAAuB;IACrC,OAAO,EAAE,SAAS;CACnB,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAQ,cAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC/D,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,iBAAiB,CAC/B,CAAoB,EACpB,CAAoB;IAEpB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAChD,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAClE,IAAI,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC;QAAE,OAAO,YAAY,CAAC;IAC5E,IAAI,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC;QAAE,OAAO,aAAa,CAAC;IAC7E,IACE,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC;QACvB,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC;QAC3D,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,EACvD,CAAC;QACD,OAAO,cAAc,CAAC;IACxB,CAAC;IACD,IAAI,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC;QAAE,OAAO,cAAc,CAAC;IACjF,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAClE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAiC;IAC/D,OAAO,MAAM,KAAK,SAAS,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,29 @@
1
+ export type PsychAttributeConsent = {
2
+ kind: string;
3
+ allowExperimentalMatching: boolean;
4
+ value?: unknown;
5
+ };
6
+ export type PsychExperimentInput = {
7
+ experimentConsent: boolean;
8
+ attributes: readonly PsychAttributeConsent[];
9
+ };
10
+ export type ExperimentContribution = {
11
+ /** Privacy-safe codes. Never a score, type name, or theme name. */
12
+ codes: string[];
13
+ /** 0–2. Reorders people who already matched. It is not a compatibility score. */
14
+ rankBoost: number;
15
+ };
16
+ /**
17
+ * Separate from baseline intent and topic matching.
18
+ * Uses only attributes both people explicitly allowed, and only as a small reorder.
19
+ * Human Design is ignored. No score is returned.
20
+ */
21
+ export declare function experimentContribution(a: PsychExperimentInput, b: PsychExperimentInput): ExperimentContribution;
22
+ /** A shared experimental note. Never includes scores, types, or names. */
23
+ export declare function psychExperimentCode(a: PsychExperimentInput, b: PsychExperimentInput): "PSYCH_SHARED" | null;
24
+ export declare function appendPsychExperiment(codes: readonly string[], a: PsychExperimentInput, b: PsychExperimentInput, enabled: boolean): string[];
25
+ export declare function rankWithExperiment<T>(candidates: readonly T[], contributionFor: (item: T) => ExperimentContribution, enabled: boolean): Array<{
26
+ item: T;
27
+ contribution: ExperimentContribution;
28
+ }>;
29
+ //# sourceMappingURL=psychExperiment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"psychExperiment.d.ts","sourceRoot":"","sources":["../../src/intros/psychExperiment.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB,EAAE,OAAO,CAAC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,UAAU,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,mEAAmE;IACnE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AA2BF;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,CAAC,EAAE,oBAAoB,EACvB,CAAC,EAAE,oBAAoB,GACtB,sBAAsB,CA+CxB;AAED,0EAA0E;AAC1E,wBAAgB,mBAAmB,CACjC,CAAC,EAAE,oBAAoB,EACvB,CAAC,EAAE,oBAAoB,GACtB,cAAc,GAAG,IAAI,CAEvB;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,CAAC,EAAE,oBAAoB,EACvB,CAAC,EAAE,oBAAoB,EACvB,OAAO,EAAE,OAAO,GACf,MAAM,EAAE,CAGV;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,UAAU,EAAE,SAAS,CAAC,EAAE,EACxB,eAAe,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,sBAAsB,EACpD,OAAO,EAAE,OAAO,GACf,KAAK,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,YAAY,EAAE,sBAAsB,CAAA;CAAE,CAAC,CAO1D"}
@@ -0,0 +1,82 @@
1
+ const EMPTY = { codes: [], rankBoost: 0 };
2
+ const EXTRAVERSION_NEAR = 20;
3
+ function usable(person) {
4
+ if (!person.experimentConsent)
5
+ return [];
6
+ return person.attributes.filter((attribute) => attribute.allowExperimentalMatching && attribute.kind !== "HumanDesign");
7
+ }
8
+ function kind(person, name) {
9
+ return person.find((attribute) => attribute.kind === name);
10
+ }
11
+ function extraversion(value) {
12
+ if (value == null || typeof value !== "object" || Array.isArray(value))
13
+ return null;
14
+ const score = value.extraversion;
15
+ return typeof score === "number" ? score : null;
16
+ }
17
+ function themes(value) {
18
+ if (!Array.isArray(value))
19
+ return [];
20
+ return value.filter((item) => typeof item === "string");
21
+ }
22
+ /**
23
+ * Separate from baseline intent and topic matching.
24
+ * Uses only attributes both people explicitly allowed, and only as a small reorder.
25
+ * Human Design is ignored. No score is returned.
26
+ */
27
+ export function experimentContribution(a, b) {
28
+ const left = usable(a);
29
+ const right = usable(b);
30
+ if (left.length === 0 || right.length === 0)
31
+ return EMPTY;
32
+ const signals = [];
33
+ const leftExtra = extraversion(kind(left, "BigFive")?.value);
34
+ const rightExtra = extraversion(kind(right, "BigFive")?.value);
35
+ if (leftExtra != null && rightExtra != null && Math.abs(leftExtra - rightExtra) <= EXTRAVERSION_NEAR) {
36
+ signals.push("PSYCH_SIGNAL:similar_social_energy");
37
+ }
38
+ const leftLocus = kind(left, "LocusOfControl")?.value;
39
+ const rightLocus = kind(right, "LocusOfControl")?.value;
40
+ if ((leftLocus === "internal" || leftLocus === "external") &&
41
+ leftLocus === rightLocus) {
42
+ signals.push("PSYCH_SIGNAL:similar_outlook");
43
+ }
44
+ const sharedTheme = themes(kind(left, "CliftonStrengths")?.value).some((theme) => themes(kind(right, "CliftonStrengths")?.value).includes(theme));
45
+ if (sharedTheme)
46
+ signals.push("PSYCH_SIGNAL:shared_theme");
47
+ const leftType = kind(left, "MyersBriggs")?.value;
48
+ const rightType = kind(right, "MyersBriggs")?.value;
49
+ if (typeof leftType === "string" &&
50
+ typeof rightType === "string" &&
51
+ leftType.length === 4 &&
52
+ rightType.length === 4 &&
53
+ leftType[0]?.toUpperCase() === rightType[0]?.toUpperCase()) {
54
+ signals.push("PSYCH_SIGNAL:self_reported_social_style");
55
+ }
56
+ const leftEi = kind(left, "EmotionalIntelligence")?.value;
57
+ const rightEi = kind(right, "EmotionalIntelligence")?.value;
58
+ if (typeof leftEi === "number" && typeof rightEi === "number" && Math.abs(leftEi - rightEi) <= 1) {
59
+ signals.push("PSYCH_SIGNAL:self_reported_emotional_note");
60
+ }
61
+ if (signals.length === 0)
62
+ return EMPTY;
63
+ return { codes: ["PSYCH_SHARED", ...signals], rankBoost: Math.min(2, signals.length) };
64
+ }
65
+ /** A shared experimental note. Never includes scores, types, or names. */
66
+ export function psychExperimentCode(a, b) {
67
+ return experimentContribution(a, b).rankBoost > 0 ? "PSYCH_SHARED" : null;
68
+ }
69
+ export function appendPsychExperiment(codes, a, b, enabled) {
70
+ if (!enabled)
71
+ return [...codes];
72
+ return [...codes, ...experimentContribution(a, b).codes];
73
+ }
74
+ export function rankWithExperiment(candidates, contributionFor, enabled) {
75
+ if (!enabled) {
76
+ return candidates.map((item) => ({ item, contribution: EMPTY }));
77
+ }
78
+ return candidates
79
+ .map((item) => ({ item, contribution: contributionFor(item) }))
80
+ .sort((left, right) => right.contribution.rankBoost - left.contribution.rankBoost);
81
+ }
82
+ //# sourceMappingURL=psychExperiment.js.map