@bwi-mentorspaces/application-utils-npm 0.0.141 → 0.0.143
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/match-guidance/index.d.ts +6 -0
- package/match-guidance/index.js +19 -0
- package/match-guidance/index.js.map +1 -0
- package/match-guidance/invitation-history.d.ts +48 -0
- package/match-guidance/invitation-history.js +95 -0
- package/match-guidance/invitation-history.js.map +1 -0
- package/match-guidance/message-facts.d.ts +63 -0
- package/match-guidance/message-facts.js +139 -0
- package/match-guidance/message-facts.js.map +1 -0
- package/match-guidance/model.d.ts +53 -0
- package/match-guidance/model.js +35 -0
- package/match-guidance/model.js.map +1 -0
- package/match-guidance/next-step.d.ts +10 -0
- package/match-guidance/next-step.js +46 -0
- package/match-guidance/next-step.js.map +1 -0
- package/match-guidance/reporting-eligibility.d.ts +15 -0
- package/match-guidance/reporting-eligibility.js +69 -0
- package/match-guidance/reporting-eligibility.js.map +1 -0
- package/match-guidance/session-facts.d.ts +5 -0
- package/match-guidance/session-facts.js +234 -0
- package/match-guidance/session-facts.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
__exportStar(require("./model"), exports);
|
|
14
|
+
__exportStar(require("./next-step"), exports);
|
|
15
|
+
__exportStar(require("./session-facts"), exports);
|
|
16
|
+
__exportStar(require("./message-facts"), exports);
|
|
17
|
+
__exportStar(require("./invitation-history"), exports);
|
|
18
|
+
__exportStar(require("./reporting-eligibility"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../match-guidance/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,0CAAwB;AACxB,8CAA4B;AAC5B,kDAAgC;AAChC,kDAAgC;AAChC,uDAAqC;AACrC,0DAAwC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read an established origin; only an original invitation can infer a missing origin.
|
|
3
|
+
*
|
|
4
|
+
* @param {unknown} value Stored history.
|
|
5
|
+
* @param {Date} createdOn Session creation occurrence.
|
|
6
|
+
* @returns {Date | null} Verified origin or unknown.
|
|
7
|
+
*/
|
|
8
|
+
export declare function sessionInvitationOrigin(value: unknown, createdOn: Date): Date | null;
|
|
9
|
+
/**
|
|
10
|
+
* Stamp a server-generated invitation and its known or unknown episode origin.
|
|
11
|
+
*
|
|
12
|
+
* @param {unknown} value Stored history, never client-owned metadata.
|
|
13
|
+
* @param {Date} occurredOn New invitation occurrence.
|
|
14
|
+
* @param {Date | null} since Origin of the uninterrupted invitation episode.
|
|
15
|
+
* @returns {string} Existing JSON history representation.
|
|
16
|
+
*/
|
|
17
|
+
export declare function stampUnansweredInvitationHistory(value: unknown, occurredOn: Date, since: Date | null): string;
|
|
18
|
+
/**
|
|
19
|
+
* Keep internal maintenance metadata out of existing public status maps.
|
|
20
|
+
*
|
|
21
|
+
* @param {T} history Parsed status map.
|
|
22
|
+
* @returns {T} Existing public entries without internal metadata.
|
|
23
|
+
*/
|
|
24
|
+
export declare function publicSessionInvitationHistory<T extends object>(history: T): T;
|
|
25
|
+
/**
|
|
26
|
+
* Existing invitation histories contain one map, either native JSON or a JSON string.
|
|
27
|
+
*
|
|
28
|
+
* @param {unknown} value Value to validate or normalize.
|
|
29
|
+
* @returns {Record<string, unknown>} Calculated result.
|
|
30
|
+
*/
|
|
31
|
+
export declare function readSessionInvitationHistory(value: unknown): Record<string, unknown>;
|
|
32
|
+
/**
|
|
33
|
+
* Zero and missing history entries are existing representations of no such action.
|
|
34
|
+
*
|
|
35
|
+
* @param {Record<string, unknown>} history Server invitation history.
|
|
36
|
+
* @param {string} status Invitation action status.
|
|
37
|
+
* @returns {Date | null} Calculated result.
|
|
38
|
+
*/
|
|
39
|
+
export declare function sessionInvitationDate(history: Record<string, unknown>, status: string): Date | null;
|
|
40
|
+
/**
|
|
41
|
+
* Preserve server history and stamp only the authenticated action being performed.
|
|
42
|
+
*
|
|
43
|
+
* @param {unknown} value Value to validate or normalize.
|
|
44
|
+
* @param {string} status Invitation action status.
|
|
45
|
+
* @param {Date} occurredOn Server action occurrence timestamp.
|
|
46
|
+
* @returns {string} Calculated result.
|
|
47
|
+
*/
|
|
48
|
+
export declare function stampSessionInvitationHistory(value: unknown, status: string, occurredOn: Date): string;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stampSessionInvitationHistory = exports.sessionInvitationDate = exports.readSessionInvitationHistory = exports.publicSessionInvitationHistory = exports.stampUnansweredInvitationHistory = exports.sessionInvitationOrigin = void 0;
|
|
4
|
+
const core_1 = require("../core");
|
|
5
|
+
/** Server-owned origin, separate from the latest invited status timestamp. */
|
|
6
|
+
const invitationOriginKey = "unansweredInvitationSince";
|
|
7
|
+
/**
|
|
8
|
+
* Read an established origin; only an original invitation can infer a missing origin.
|
|
9
|
+
*
|
|
10
|
+
* @param {unknown} value Stored history.
|
|
11
|
+
* @param {Date} createdOn Session creation occurrence.
|
|
12
|
+
* @returns {Date | null} Verified origin or unknown.
|
|
13
|
+
*/
|
|
14
|
+
function sessionInvitationOrigin(value, createdOn) {
|
|
15
|
+
const history = readSessionInvitationHistory(value);
|
|
16
|
+
if (Object.prototype.hasOwnProperty.call(history, invitationOriginKey))
|
|
17
|
+
return sessionInvitationDate(history, invitationOriginKey);
|
|
18
|
+
const invited = sessionInvitationDate(history, "invited");
|
|
19
|
+
return (invited === null || invited === void 0 ? void 0 : invited.getTime()) === Math.floor(createdOn.getTime() / 1000) * 1000 ? invited : null;
|
|
20
|
+
}
|
|
21
|
+
exports.sessionInvitationOrigin = sessionInvitationOrigin;
|
|
22
|
+
/**
|
|
23
|
+
* Stamp a server-generated invitation and its known or unknown episode origin.
|
|
24
|
+
*
|
|
25
|
+
* @param {unknown} value Stored history, never client-owned metadata.
|
|
26
|
+
* @param {Date} occurredOn New invitation occurrence.
|
|
27
|
+
* @param {Date | null} since Origin of the uninterrupted invitation episode.
|
|
28
|
+
* @returns {string} Existing JSON history representation.
|
|
29
|
+
*/
|
|
30
|
+
function stampUnansweredInvitationHistory(value, occurredOn, since) {
|
|
31
|
+
var _a;
|
|
32
|
+
return JSON.stringify([
|
|
33
|
+
Object.assign(Object.assign({}, readSessionInvitationHistory(value)), { invited: occurredOn.toISOString(), [invitationOriginKey]: (_a = since === null || since === void 0 ? void 0 : since.toISOString()) !== null && _a !== void 0 ? _a : null })
|
|
34
|
+
]);
|
|
35
|
+
}
|
|
36
|
+
exports.stampUnansweredInvitationHistory = stampUnansweredInvitationHistory;
|
|
37
|
+
/**
|
|
38
|
+
* Keep internal maintenance metadata out of existing public status maps.
|
|
39
|
+
*
|
|
40
|
+
* @param {T} history Parsed status map.
|
|
41
|
+
* @returns {T} Existing public entries without internal metadata.
|
|
42
|
+
*/
|
|
43
|
+
function publicSessionInvitationHistory(history) {
|
|
44
|
+
const publicHistory = Object.assign({}, history);
|
|
45
|
+
Reflect.deleteProperty(publicHistory, invitationOriginKey);
|
|
46
|
+
return publicHistory;
|
|
47
|
+
}
|
|
48
|
+
exports.publicSessionInvitationHistory = publicSessionInvitationHistory;
|
|
49
|
+
/**
|
|
50
|
+
* Existing invitation histories contain one map, either native JSON or a JSON string.
|
|
51
|
+
*
|
|
52
|
+
* @param {unknown} value Value to validate or normalize.
|
|
53
|
+
* @returns {Record<string, unknown>} Calculated result.
|
|
54
|
+
*/
|
|
55
|
+
function readSessionInvitationHistory(value) {
|
|
56
|
+
const parsed = typeof value === "string" ? JSON.parse(value) : value;
|
|
57
|
+
if (parsed == null)
|
|
58
|
+
return {};
|
|
59
|
+
if (!Array.isArray(parsed) || parsed.length !== 1 || !parsed[0] || typeof parsed[0] !== "object") {
|
|
60
|
+
throw new core_1.ApiError(500 /* InternalServerError */, "Session invitation history is invalid.");
|
|
61
|
+
}
|
|
62
|
+
return Object.assign({}, parsed[0]);
|
|
63
|
+
}
|
|
64
|
+
exports.readSessionInvitationHistory = readSessionInvitationHistory;
|
|
65
|
+
/**
|
|
66
|
+
* Zero and missing history entries are existing representations of no such action.
|
|
67
|
+
*
|
|
68
|
+
* @param {Record<string, unknown>} history Server invitation history.
|
|
69
|
+
* @param {string} status Invitation action status.
|
|
70
|
+
* @returns {Date | null} Calculated result.
|
|
71
|
+
*/
|
|
72
|
+
function sessionInvitationDate(history, status) {
|
|
73
|
+
const value = history[status];
|
|
74
|
+
if (value == null || value === 0 || value === "0")
|
|
75
|
+
return null;
|
|
76
|
+
const date = value instanceof Date ? value : typeof value === "string" ? new Date(value) : null;
|
|
77
|
+
if (!date || !Number.isFinite(date.getTime())) {
|
|
78
|
+
throw new core_1.ApiError(500 /* InternalServerError */, "Session invitation history contains an invalid timestamp.");
|
|
79
|
+
}
|
|
80
|
+
return new Date(Math.floor(date.getTime() / 1000) * 1000);
|
|
81
|
+
}
|
|
82
|
+
exports.sessionInvitationDate = sessionInvitationDate;
|
|
83
|
+
/**
|
|
84
|
+
* Preserve server history and stamp only the authenticated action being performed.
|
|
85
|
+
*
|
|
86
|
+
* @param {unknown} value Value to validate or normalize.
|
|
87
|
+
* @param {string} status Invitation action status.
|
|
88
|
+
* @param {Date} occurredOn Server action occurrence timestamp.
|
|
89
|
+
* @returns {string} Calculated result.
|
|
90
|
+
*/
|
|
91
|
+
function stampSessionInvitationHistory(value, status, occurredOn) {
|
|
92
|
+
return JSON.stringify([Object.assign(Object.assign({}, readSessionInvitationHistory(value)), { [status]: occurredOn.toISOString() })]);
|
|
93
|
+
}
|
|
94
|
+
exports.stampSessionInvitationHistory = stampSessionInvitationHistory;
|
|
95
|
+
//# sourceMappingURL=invitation-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invitation-history.js","sourceRoot":"","sources":["../../match-guidance/invitation-history.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { IGuidanceContext, IGuidanceConnection, IGuidanceSql } from "./model";
|
|
2
|
+
/** Narrow, validated projection shared by webhook and historical chat reads. */
|
|
3
|
+
export interface IHumanActivityMessage {
|
|
4
|
+
user?: {
|
|
5
|
+
id?: string;
|
|
6
|
+
};
|
|
7
|
+
user_id?: string;
|
|
8
|
+
type?: string;
|
|
9
|
+
text?: string;
|
|
10
|
+
attachments?: unknown[];
|
|
11
|
+
silent?: boolean;
|
|
12
|
+
deleted_at?: string | Date | null;
|
|
13
|
+
created_at?: string | Date;
|
|
14
|
+
custom?: unknown;
|
|
15
|
+
customData?: unknown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Exclude automated messages from human activity.
|
|
19
|
+
*
|
|
20
|
+
* @param {IHumanActivityMessage} message Candidate source message.
|
|
21
|
+
* @returns {boolean} Calculated result.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isHumanActivityMessage(message: IHumanActivityMessage): boolean;
|
|
24
|
+
/** Minimal transport boundary compatible with the application's installed Stream SDK. */
|
|
25
|
+
export interface IGuidanceMessageSource {
|
|
26
|
+
available: (cids: string[]) => Promise<boolean>;
|
|
27
|
+
search: (request: {
|
|
28
|
+
cids: string[];
|
|
29
|
+
author: string;
|
|
30
|
+
start: Date;
|
|
31
|
+
end: Date;
|
|
32
|
+
direction: 1 | -1;
|
|
33
|
+
next?: string;
|
|
34
|
+
limit: number;
|
|
35
|
+
}) => Promise<{
|
|
36
|
+
results: {
|
|
37
|
+
message: IHumanActivityMessage;
|
|
38
|
+
}[];
|
|
39
|
+
next?: string;
|
|
40
|
+
results_warning?: unknown;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
/** Share bounded source metadata reads without depending on a particular Stream SDK version. */
|
|
44
|
+
export declare function createGuidanceMessageReader(source: IGuidanceMessageSource): {
|
|
45
|
+
assertSearchableChannels: (cids: string[]) => Promise<void>;
|
|
46
|
+
searchMessage: (cids: string[], author: string, start: Date | null, end: Date, direction: 1 | -1) => Promise<Date | null>;
|
|
47
|
+
latestPublishedMessages: (contexts: IGuidanceContext[], channels: Map<string, {
|
|
48
|
+
StreamRef: string;
|
|
49
|
+
}[]>, now: Date) => Promise<{
|
|
50
|
+
messages: Map<number, Map<string, Date>>;
|
|
51
|
+
cids: string[];
|
|
52
|
+
}>;
|
|
53
|
+
};
|
|
54
|
+
/** Match only historical 1:1 channels with exactly these two participants. */
|
|
55
|
+
export declare function readGuidanceChannels<TSql, TChannel extends {
|
|
56
|
+
Id: number;
|
|
57
|
+
StreamRef: string;
|
|
58
|
+
}>(adapter: IGuidanceSql<TSql>, connection: IGuidanceConnection<TSql>, pairs: {
|
|
59
|
+
firstUserId: number;
|
|
60
|
+
firstUserRef: string;
|
|
61
|
+
secondUserId: number;
|
|
62
|
+
secondUserRef: string;
|
|
63
|
+
}[]): Promise<Map<string, TChannel[]>>;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.readGuidanceChannels = exports.createGuidanceMessageReader = exports.isHumanActivityMessage = void 0;
|
|
13
|
+
const core_1 = require("../core");
|
|
14
|
+
// Automated notifications use silent delivery and/or the custom notification envelope.
|
|
15
|
+
/**
|
|
16
|
+
* Exclude automated messages from human activity.
|
|
17
|
+
*
|
|
18
|
+
* @param {IHumanActivityMessage} message Candidate source message.
|
|
19
|
+
* @returns {boolean} Calculated result.
|
|
20
|
+
*/
|
|
21
|
+
function isHumanActivityMessage(message) {
|
|
22
|
+
return (!message.silent &&
|
|
23
|
+
!message.deleted_at &&
|
|
24
|
+
(message.type === "regular" || message.type === "reply") &&
|
|
25
|
+
[message.custom, message.customData].every((metadata) => metadata == null || (typeof metadata === "object" && Object.keys(metadata).length === 0)) &&
|
|
26
|
+
((typeof message.text === "string" && !!message.text.trim()) ||
|
|
27
|
+
(Array.isArray(message.attachments) && message.attachments.length > 0)));
|
|
28
|
+
}
|
|
29
|
+
exports.isHumanActivityMessage = isHumanActivityMessage;
|
|
30
|
+
/** Share bounded source metadata reads without depending on a particular Stream SDK version. */
|
|
31
|
+
function createGuidanceMessageReader(source) {
|
|
32
|
+
function assertSearchableChannels(cids) {
|
|
33
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
34
|
+
for (let offset = 0; offset < cids.length; offset += 100) {
|
|
35
|
+
if (!(yield source.available(cids.slice(offset, offset + 100))))
|
|
36
|
+
throw new core_1.ApiError(500 /* InternalServerError */, "Chat history is unavailable for one or more match channels.");
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function searchMessage(cids, author, start, end, direction) {
|
|
41
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
if (!start || start >= end || !cids.length)
|
|
43
|
+
return null;
|
|
44
|
+
const pageSize = 100;
|
|
45
|
+
if (cids.length > pageSize) {
|
|
46
|
+
let selected = null;
|
|
47
|
+
for (let offset = 0; offset < cids.length; offset += pageSize) {
|
|
48
|
+
const candidate = yield searchMessage(cids.slice(offset, offset + pageSize), author, start, end, direction);
|
|
49
|
+
if (candidate && (!selected || (direction === 1 ? candidate < selected : candidate > selected)))
|
|
50
|
+
selected = candidate;
|
|
51
|
+
}
|
|
52
|
+
return selected;
|
|
53
|
+
}
|
|
54
|
+
let next;
|
|
55
|
+
do {
|
|
56
|
+
const response = yield source.search({ cids, author, start, end, direction, next, limit: pageSize });
|
|
57
|
+
if (response.results_warning)
|
|
58
|
+
throw new core_1.ApiError(500 /* InternalServerError */, "Chat history search was incomplete.");
|
|
59
|
+
for (const result of response.results) {
|
|
60
|
+
if (isHumanActivityMessage(result.message) && result.message.created_at) {
|
|
61
|
+
const date = new Date(result.message.created_at);
|
|
62
|
+
if (!Number.isFinite(date.getTime()))
|
|
63
|
+
throw new core_1.ApiError(500 /* InternalServerError */, "Invalid chat occurrence time.");
|
|
64
|
+
return date;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (response.next && response.next === next)
|
|
68
|
+
throw new core_1.ApiError(500 /* InternalServerError */, "Chat history cursor did not advance.");
|
|
69
|
+
next = response.next;
|
|
70
|
+
} while (next);
|
|
71
|
+
return null;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function latestPublishedMessages(contexts, channels, now) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
const messages = new Map();
|
|
77
|
+
const channelsByMatch = new Map();
|
|
78
|
+
for (const context of contexts) {
|
|
79
|
+
messages.set(context.Id, new Map());
|
|
80
|
+
const pair = channels.get([context.MentorRef, context.MenteeRef].sort().join(":"));
|
|
81
|
+
if (!(pair === null || pair === void 0 ? void 0 : pair.length))
|
|
82
|
+
throw new core_1.ApiError(500 /* InternalServerError */, "Match chat history is unavailable.");
|
|
83
|
+
channelsByMatch.set(context.Id, [...new Set(pair.map((channel) => `team:${channel.StreamRef}`))].sort());
|
|
84
|
+
}
|
|
85
|
+
const cids = [...new Set([...channelsByMatch.values()].flat())];
|
|
86
|
+
yield assertSearchableChannels(cids);
|
|
87
|
+
const searches = new Map();
|
|
88
|
+
for (const context of contexts) {
|
|
89
|
+
const matchChannels = channelsByMatch.get(context.Id);
|
|
90
|
+
const result = messages.get(context.Id);
|
|
91
|
+
if (!matchChannels || !result)
|
|
92
|
+
throw new Error("Missing initialized message facts");
|
|
93
|
+
const end = context.EndDate && context.EndDate < now ? context.EndDate : now;
|
|
94
|
+
yield Promise.all([context.MentorRef, context.MenteeRef].map((author) => __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
const key = JSON.stringify([matchChannels, author, context.PublishedOn, end]);
|
|
96
|
+
if (!searches.has(key))
|
|
97
|
+
searches.set(key, searchMessage(matchChannels, author, context.PublishedOn, end, -1));
|
|
98
|
+
const date = yield searches.get(key);
|
|
99
|
+
if (date)
|
|
100
|
+
result.set(author.toLowerCase(), date);
|
|
101
|
+
})));
|
|
102
|
+
}
|
|
103
|
+
return { messages, cids };
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return { assertSearchableChannels, searchMessage, latestPublishedMessages };
|
|
107
|
+
}
|
|
108
|
+
exports.createGuidanceMessageReader = createGuidanceMessageReader;
|
|
109
|
+
/** Match only historical 1:1 channels with exactly these two participants. */
|
|
110
|
+
function readGuidanceChannels(adapter, connection, pairs) {
|
|
111
|
+
var _a;
|
|
112
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
113
|
+
const result = new Map();
|
|
114
|
+
if (!pairs.length)
|
|
115
|
+
return result;
|
|
116
|
+
const rows = yield connection.$queryRaw(adapter.sql `
|
|
117
|
+
SELECT DISTINCT c.*, p.firstRef, p.secondRef
|
|
118
|
+
FROM JSON_TABLE(${JSON.stringify(pairs)}, '$[*]' COLUMNS (
|
|
119
|
+
firstId INT PATH '$.firstUserId', secondId INT PATH '$.secondUserId',
|
|
120
|
+
firstRef CHAR(36) PATH '$.firstUserRef', secondRef CHAR(36) PATH '$.secondUserRef')) p
|
|
121
|
+
JOIN member a ON a.UserId = p.firstId
|
|
122
|
+
JOIN channel c ON c.Id = a.ChannelId AND c.Type = ${"1:1"}
|
|
123
|
+
JOIN member b ON b.ChannelId = c.Id AND b.UserId = p.secondId
|
|
124
|
+
WHERE NOT EXISTS (SELECT 1 FROM member other JOIN user u ON u.Id = other.UserId
|
|
125
|
+
WHERE other.ChannelId = c.Id AND BINARY u.Ref <> BINARY p.firstRef AND BINARY u.Ref <> BINARY p.secondRef)
|
|
126
|
+
ORDER BY c.CreatedOn, c.Id`);
|
|
127
|
+
for (const row of rows) {
|
|
128
|
+
const key = [row.firstRef, row.secondRef].sort().join(":");
|
|
129
|
+
const values = (_a = result.get(key)) !== null && _a !== void 0 ? _a : [];
|
|
130
|
+
Reflect.deleteProperty(row, "firstRef");
|
|
131
|
+
Reflect.deleteProperty(row, "secondRef");
|
|
132
|
+
values.push(row);
|
|
133
|
+
result.set(key, values);
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
exports.readGuidanceChannels = readGuidanceChannels;
|
|
139
|
+
//# sourceMappingURL=message-facts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-facts.js","sourceRoot":"","sources":["../../match-guidance/message-facts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Participant-specific Home guidance, independent of report grades. */
|
|
2
|
+
export declare type HomeMatchNextStep = "ATTEND" | "RESPOND" | "REPLY" | "PREPARE" | "RECOVER" | "SCHEDULE_NEXT" | "SCHEDULE_FIRST" | "INTRODUCE" | "WAITING_INVITATION" | "WAITING_REPLY" | "UNAVAILABLE";
|
|
3
|
+
/** Minimal retained session facts needed by the deterministic resolver. */
|
|
4
|
+
export interface IHomeMatchSession {
|
|
5
|
+
id: number;
|
|
6
|
+
start: Date;
|
|
7
|
+
end: Date | null;
|
|
8
|
+
completed: boolean;
|
|
9
|
+
}
|
|
10
|
+
/** Bounded aggregates for a single match. */
|
|
11
|
+
export interface IHomeMatchFacts {
|
|
12
|
+
historyAvailable: boolean;
|
|
13
|
+
incomingMessage: Date | null;
|
|
14
|
+
outgoingMessage: Date | null;
|
|
15
|
+
latestAcceptance: Date | null;
|
|
16
|
+
latestCompletion: Date | null;
|
|
17
|
+
totalSessions: number;
|
|
18
|
+
hasRecordedScheduling: boolean;
|
|
19
|
+
latestEnded: IHomeMatchSession | null;
|
|
20
|
+
ongoing: IHomeMatchSession | null;
|
|
21
|
+
incomingInvitation: IHomeMatchSession | null;
|
|
22
|
+
accepted: IHomeMatchSession | null;
|
|
23
|
+
outgoingInvitation: IHomeMatchSession | null;
|
|
24
|
+
}
|
|
25
|
+
/** Minimal source context; callers retain authorization ownership. */
|
|
26
|
+
export interface IGuidanceContext {
|
|
27
|
+
Id: number;
|
|
28
|
+
MentorUserId: number;
|
|
29
|
+
MenteeUserId: number;
|
|
30
|
+
MentorRef: string;
|
|
31
|
+
MenteeRef: string;
|
|
32
|
+
PublishedOn: Date | null;
|
|
33
|
+
EndDate: Date | null;
|
|
34
|
+
TimeZone?: string | null;
|
|
35
|
+
}
|
|
36
|
+
/** One authorized participant whose Home guidance is required. */
|
|
37
|
+
export interface IGuidanceRecipient extends IGuidanceContext {
|
|
38
|
+
recipientRef: string;
|
|
39
|
+
}
|
|
40
|
+
/** Caller-owned SQL construction and database connection. */
|
|
41
|
+
export interface IGuidanceSql<TSql> {
|
|
42
|
+
sql: (strings: TemplateStringsArray, ...values: unknown[]) => TSql;
|
|
43
|
+
join: (values: readonly unknown[], separator?: string) => TSql;
|
|
44
|
+
}
|
|
45
|
+
export interface IGuidanceConnection<TSql> {
|
|
46
|
+
$queryRaw: <T>(query: TSql) => Promise<T>;
|
|
47
|
+
}
|
|
48
|
+
/** Stable request-local lookup key, not a stored identifier. */
|
|
49
|
+
export declare function guidanceKey(matchId: number, recipientRef: string): string;
|
|
50
|
+
/** Initialize the same neutral facts for both Home and notification selection. */
|
|
51
|
+
export declare function emptyGuidanceFacts(hasRecordedScheduling: boolean): IHomeMatchFacts;
|
|
52
|
+
/** Require a fact row already initialized by the authorized caller. */
|
|
53
|
+
export declare function requireGuidanceFacts(facts: Map<string, IHomeMatchFacts>, matchId: number, recipientRef: string): IHomeMatchFacts;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.requireGuidanceFacts = exports.emptyGuidanceFacts = exports.guidanceKey = void 0;
|
|
4
|
+
/** Stable request-local lookup key, not a stored identifier. */
|
|
5
|
+
function guidanceKey(matchId, recipientRef) {
|
|
6
|
+
return `${matchId}:${recipientRef.toLowerCase()}`;
|
|
7
|
+
}
|
|
8
|
+
exports.guidanceKey = guidanceKey;
|
|
9
|
+
/** Initialize the same neutral facts for both Home and notification selection. */
|
|
10
|
+
function emptyGuidanceFacts(hasRecordedScheduling) {
|
|
11
|
+
return {
|
|
12
|
+
historyAvailable: true,
|
|
13
|
+
incomingMessage: null,
|
|
14
|
+
outgoingMessage: null,
|
|
15
|
+
latestAcceptance: null,
|
|
16
|
+
latestCompletion: null,
|
|
17
|
+
totalSessions: 0,
|
|
18
|
+
hasRecordedScheduling,
|
|
19
|
+
latestEnded: null,
|
|
20
|
+
ongoing: null,
|
|
21
|
+
incomingInvitation: null,
|
|
22
|
+
accepted: null,
|
|
23
|
+
outgoingInvitation: null
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
exports.emptyGuidanceFacts = emptyGuidanceFacts;
|
|
27
|
+
/** Require a fact row already initialized by the authorized caller. */
|
|
28
|
+
function requireGuidanceFacts(facts, matchId, recipientRef) {
|
|
29
|
+
const value = facts.get(guidanceKey(matchId, recipientRef));
|
|
30
|
+
if (!value)
|
|
31
|
+
throw new Error("Missing initialized match guidance facts");
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
exports.requireGuidanceFacts = requireGuidanceFacts;
|
|
35
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../match-guidance/model.ts"],"names":[],"mappings":";;;AA6DA,gEAAgE;AAChE,SAAgB,WAAW,CAAC,OAAe,EAAE,YAAoB;IAC7D,OAAO,GAAG,OAAO,IAAI,YAAY,CAAC,WAAW,EAAE,EAAE,CAAC;AACtD,CAAC;AAFD,kCAEC;AACD,kFAAkF;AAClF,SAAgB,kBAAkB,CAAC,qBAA8B;IAC7D,OAAO;QACH,gBAAgB,EAAE,IAAI;QACtB,eAAe,EAAE,IAAI;QACrB,eAAe,EAAE,IAAI;QACrB,gBAAgB,EAAE,IAAI;QACtB,gBAAgB,EAAE,IAAI;QACtB,aAAa,EAAE,CAAC;QAChB,qBAAqB;QACrB,WAAW,EAAE,IAAI;QACjB,OAAO,EAAE,IAAI;QACb,kBAAkB,EAAE,IAAI;QACxB,QAAQ,EAAE,IAAI;QACd,kBAAkB,EAAE,IAAI;KAC3B,CAAC;AACN,CAAC;AAfD,gDAeC;AAED,uEAAuE;AACvE,SAAgB,oBAAoB,CAChC,KAAmC,EACnC,OAAe,EACf,YAAoB;IAEpB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;IAC5D,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACxE,OAAO,KAAK,CAAC;AACjB,CAAC;AARD,oDAQC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HomeMatchNextStep, IHomeMatchFacts } from "./model";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the approved display precedence using authoritative participant facts.
|
|
4
|
+
*
|
|
5
|
+
* @param {IHomeMatchFacts} facts Aggregated source facts.
|
|
6
|
+
* @returns {HomeMatchNextStep} One next step, without inventing missing history.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveHomeMatchNextStep(facts: IHomeMatchFacts): HomeMatchNextStep;
|
|
9
|
+
/** The same optional reporting action on Home and engagement emails. */
|
|
10
|
+
export declare function canReportOffline(facts: IHomeMatchFacts, behind: boolean, hasCommunication: boolean): boolean;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.canReportOffline = exports.resolveHomeMatchNextStep = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the approved display precedence using authoritative participant facts.
|
|
6
|
+
*
|
|
7
|
+
* @param {IHomeMatchFacts} facts Aggregated source facts.
|
|
8
|
+
* @returns {HomeMatchNextStep} One next step, without inventing missing history.
|
|
9
|
+
*/
|
|
10
|
+
function resolveHomeMatchNextStep(facts) {
|
|
11
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
12
|
+
if (facts.ongoing)
|
|
13
|
+
return "ATTEND";
|
|
14
|
+
if (facts.incomingInvitation)
|
|
15
|
+
return "RESPOND";
|
|
16
|
+
// Unknown messaging can outrank preparation: do not silently treat it as empty.
|
|
17
|
+
if (!facts.historyAvailable)
|
|
18
|
+
return "UNAVAILABLE";
|
|
19
|
+
const incoming = (_b = (_a = facts.incomingMessage) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : 0;
|
|
20
|
+
const superseded = Math.max((_d = (_c = facts.outgoingMessage) === null || _c === void 0 ? void 0 : _c.getTime()) !== null && _d !== void 0 ? _d : 0, (_f = (_e = facts.latestAcceptance) === null || _e === void 0 ? void 0 : _e.getTime()) !== null && _f !== void 0 ? _f : 0, (_h = (_g = facts.latestCompletion) === null || _g === void 0 ? void 0 : _g.getTime()) !== null && _h !== void 0 ? _h : 0);
|
|
21
|
+
if (incoming > superseded)
|
|
22
|
+
return "REPLY";
|
|
23
|
+
if (facts.accepted)
|
|
24
|
+
return "PREPARE";
|
|
25
|
+
if (facts.outgoingInvitation)
|
|
26
|
+
return "WAITING_INVITATION";
|
|
27
|
+
if (facts.latestEnded)
|
|
28
|
+
return facts.latestEnded.completed ? "SCHEDULE_NEXT" : "RECOVER";
|
|
29
|
+
if (facts.totalSessions > 0)
|
|
30
|
+
return "SCHEDULE_NEXT";
|
|
31
|
+
if (facts.incomingMessage && facts.outgoingMessage)
|
|
32
|
+
return "SCHEDULE_FIRST";
|
|
33
|
+
// A canceled/deleted booking can still have positive scheduling evidence.
|
|
34
|
+
if (!facts.incomingMessage && !facts.outgoingMessage)
|
|
35
|
+
return facts.hasRecordedScheduling ? "SCHEDULE_NEXT" : "INTRODUCE";
|
|
36
|
+
return "WAITING_REPLY";
|
|
37
|
+
}
|
|
38
|
+
exports.resolveHomeMatchNextStep = resolveHomeMatchNextStep;
|
|
39
|
+
/** The same optional reporting action on Home and engagement emails. */
|
|
40
|
+
function canReportOffline(facts, behind, hasCommunication) {
|
|
41
|
+
return (behind &&
|
|
42
|
+
["RECOVER", "SCHEDULE_NEXT", "SCHEDULE_FIRST", "WAITING_REPLY"].includes(resolveHomeMatchNextStep(facts)) &&
|
|
43
|
+
(!!facts.latestCompletion || !!facts.incomingMessage || !!facts.outgoingMessage || hasCommunication));
|
|
44
|
+
}
|
|
45
|
+
exports.canReportOffline = canReportOffline;
|
|
46
|
+
//# sourceMappingURL=next-step.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"next-step.js","sourceRoot":"","sources":["../../match-guidance/next-step.ts"],"names":[],"mappings":";;;AAEA;;;;;GAKG;AACH,SAAgB,wBAAwB,CAAC,KAAsB;;IAC3D,IAAI,KAAK,CAAC,OAAO;QAAE,OAAO,QAAQ,CAAC;IACnC,IAAI,KAAK,CAAC,kBAAkB;QAAE,OAAO,SAAS,CAAC;IAC/C,gFAAgF;IAChF,IAAI,CAAC,KAAK,CAAC,gBAAgB;QAAE,OAAO,aAAa,CAAC;IAClD,MAAM,QAAQ,GAAG,MAAA,MAAA,KAAK,CAAC,eAAe,0CAAE,OAAO,EAAE,mCAAI,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CACvB,MAAA,MAAA,KAAK,CAAC,eAAe,0CAAE,OAAO,EAAE,mCAAI,CAAC,EACrC,MAAA,MAAA,KAAK,CAAC,gBAAgB,0CAAE,OAAO,EAAE,mCAAI,CAAC,EACtC,MAAA,MAAA,KAAK,CAAC,gBAAgB,0CAAE,OAAO,EAAE,mCAAI,CAAC,CACzC,CAAC;IACF,IAAI,QAAQ,GAAG,UAAU;QAAE,OAAO,OAAO,CAAC;IAC1C,IAAI,KAAK,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IACrC,IAAI,KAAK,CAAC,kBAAkB;QAAE,OAAO,oBAAoB,CAAC;IAC1D,IAAI,KAAK,CAAC,WAAW;QAAE,OAAO,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC;IACxF,IAAI,KAAK,CAAC,aAAa,GAAG,CAAC;QAAE,OAAO,eAAe,CAAC;IACpD,IAAI,KAAK,CAAC,eAAe,IAAI,KAAK,CAAC,eAAe;QAAE,OAAO,gBAAgB,CAAC;IAC5E,0EAA0E;IAC1E,IAAI,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,eAAe;QAChD,OAAO,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,WAAW,CAAC;IACvE,OAAO,eAAe,CAAC;AAC3B,CAAC;AArBD,4DAqBC;AAED,wEAAwE;AACxE,SAAgB,gBAAgB,CAAC,KAAsB,EAAE,MAAe,EAAE,gBAAyB;IAC/F,OAAO,CACH,MAAM;QACN,CAAC,SAAS,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC;QACzG,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,CAAC,KAAK,CAAC,eAAe,IAAI,gBAAgB,CAAC,CACvG,CAAC;AACN,CAAC;AAND,4CAMC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IGuidanceSql } from "./model";
|
|
2
|
+
/** Trusted aliases for already-joined match eligibility records. */
|
|
3
|
+
export interface IProgramMatchEligibilityAliases<TSql> {
|
|
4
|
+
match: TSql;
|
|
5
|
+
mentor: TSql;
|
|
6
|
+
mentee: TSql;
|
|
7
|
+
mentorMember: TSql;
|
|
8
|
+
menteeMember: TSql;
|
|
9
|
+
}
|
|
10
|
+
/** Bind the existing program reporting eligibility rules to the caller's SQL implementation. */
|
|
11
|
+
export declare function createReportingEligibility<TSql>(adapter: IGuidanceSql<TSql>): {
|
|
12
|
+
buildAdminProgramMemberEligibilityCondition: (programMemberAlias: TSql, userAlias: TSql) => TSql;
|
|
13
|
+
programMatchEligibilityConditionSql: (programRef: string, evaluatedAt: Date, aliases: IProgramMatchEligibilityAliases<TSql>) => TSql;
|
|
14
|
+
eligibleProgramMatchesSql: (programRef: string, evaluatedAt: Date) => TSql;
|
|
15
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createReportingEligibility = void 0;
|
|
4
|
+
/** Bind the existing program reporting eligibility rules to the caller's SQL implementation. */
|
|
5
|
+
function createReportingEligibility(adapter) {
|
|
6
|
+
/**
|
|
7
|
+
* Build participant eligibility for admin program data and recommendations.
|
|
8
|
+
* Callers provide static SQL aliases and retain their own program scoping.
|
|
9
|
+
*
|
|
10
|
+
* @param {TSql} programMemberAlias Trusted program-member SQL alias
|
|
11
|
+
* @param {TSql} userAlias Trusted user SQL alias
|
|
12
|
+
* @returns {TSql} Parameterized participant eligibility predicate
|
|
13
|
+
*/
|
|
14
|
+
function buildAdminProgramMemberEligibilityCondition(programMemberAlias, userAlias) {
|
|
15
|
+
return adapter.sql `(
|
|
16
|
+
${programMemberAlias}.Status = ${"active"}
|
|
17
|
+
AND ${programMemberAlias}.IsOnboarded = TRUE
|
|
18
|
+
AND ${userAlias}.Role <> ${"MSA"}
|
|
19
|
+
)`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Evaluate reporting eligibility against existing joins without fetching them again.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} programRef Owning program
|
|
25
|
+
* @param {Date} evaluatedAt Single request timestamp
|
|
26
|
+
* @param {IProgramMatchEligibilityAliases} aliases Trusted SQL aliases
|
|
27
|
+
* @returns {TSql} Shared reporting eligibility predicate
|
|
28
|
+
*/
|
|
29
|
+
function programMatchEligibilityConditionSql(programRef, evaluatedAt, aliases) {
|
|
30
|
+
const { match, mentor, mentee, mentorMember, menteeMember } = aliases;
|
|
31
|
+
return adapter.sql `(${match}.ProgramRef = ${programRef} AND ${match}.Status = ${"active"}
|
|
32
|
+
AND ${match}.PublishedOn IS NOT NULL AND ${match}.PublishedOn <= ${evaluatedAt}
|
|
33
|
+
AND ${mentor}.Status = ${"active"} AND ${mentee}.Status = ${"active"}
|
|
34
|
+
AND ${mentor}.IsOnboarded = TRUE AND ${mentee}.IsOnboarded = TRUE
|
|
35
|
+
AND ${mentorMember}.Role = 'Mentor' AND ${menteeMember}.Role = 'Mentee'
|
|
36
|
+
AND ${buildAdminProgramMemberEligibilityCondition(mentorMember, mentor)}
|
|
37
|
+
AND ${buildAdminProgramMemberEligibilityCondition(menteeMember, mentee)})`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Shared joins and eligibility predicates for match count and page retrieval.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} programRef Owning program
|
|
43
|
+
* @param {Date} evaluatedAt Single request timestamp
|
|
44
|
+
* @returns {TSql} Parameterized FROM and WHERE fragment
|
|
45
|
+
*/
|
|
46
|
+
function eligibleProgramMatchesSql(programRef, evaluatedAt) {
|
|
47
|
+
return adapter.sql `
|
|
48
|
+
FROM \`match\` m
|
|
49
|
+
INNER JOIN user mentor ON mentor.Id = m.MentorUserId
|
|
50
|
+
INNER JOIN user mentee ON mentee.Id = m.MenteeUserId
|
|
51
|
+
INNER JOIN programmember mentorMember ON mentorMember.ProgramRef = m.ProgramRef AND mentorMember.UserRef = mentor.Ref
|
|
52
|
+
INNER JOIN programmember menteeMember ON menteeMember.ProgramRef = m.ProgramRef AND menteeMember.UserRef = mentee.Ref
|
|
53
|
+
WHERE ${programMatchEligibilityConditionSql(programRef, evaluatedAt, {
|
|
54
|
+
match: adapter.sql `m`,
|
|
55
|
+
mentor: adapter.sql `mentor`,
|
|
56
|
+
mentee: adapter.sql `mentee`,
|
|
57
|
+
mentorMember: adapter.sql `mentorMember`,
|
|
58
|
+
menteeMember: adapter.sql `menteeMember`
|
|
59
|
+
})}
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
buildAdminProgramMemberEligibilityCondition,
|
|
64
|
+
programMatchEligibilityConditionSql,
|
|
65
|
+
eligibleProgramMatchesSql
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
exports.createReportingEligibility = createReportingEligibility;
|
|
69
|
+
//# sourceMappingURL=reporting-eligibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporting-eligibility.js","sourceRoot":"","sources":["../../match-guidance/reporting-eligibility.ts"],"names":[],"mappings":";;;AAWA,gGAAgG;AAChG,SAAgB,0BAA0B,CAAO,OAA2B;IACxE;;;;;;;OAOG;IACH,SAAS,2CAA2C,CAAC,kBAAwB,EAAE,SAAe;QAC1F,OAAO,OAAO,CAAC,GAAG,CAAA;UAChB,kBAAkB,aAAa,QAAQ;cACnC,kBAAkB;cAClB,SAAS,YAAY,KAAK;MAClC,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,SAAS,mCAAmC,CACxC,UAAkB,EAClB,WAAiB,EACjB,OAA8C;QAE9C,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,GAA0C,OAAO,CAAC;QAC7G,OAAO,OAAO,CAAC,GAAG,CAAA,IAAI,KAAK,iBAAiB,UAAU,QAAQ,KAAK,aAAa,QAAQ;cAClF,KAAK,gCAAgC,KAAK,mBAAmB,WAAW;cACxE,MAAM,aAAa,QAAQ,QAAQ,MAAM,aAAa,QAAQ;cAC9D,MAAM,2BAA2B,MAAM;cACvC,YAAY,wBAAwB,YAAY;cAChD,2CAA2C,CAAC,YAAY,EAAE,MAAM,CAAC;cACjE,2CAA2C,CAAC,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC;IAC/E,CAAC;IAED;;;;;;OAMG;IACH,SAAS,yBAAyB,CAAC,UAAkB,EAAE,WAAiB;QACpE,OAAO,OAAO,CAAC,GAAG,CAAA;;;;;;gBAMV,mCAAmC,CAAC,UAAU,EAAE,WAAW,EAAE;YACjE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAA,GAAG;YACrB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAA,QAAQ;YAC3B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAA,QAAQ;YAC3B,YAAY,EAAE,OAAO,CAAC,GAAG,CAAA,cAAc;YACvC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAA,cAAc;SAC1C,CAAC;KACL,CAAC;IACF,CAAC;IAED,OAAO;QACH,2CAA2C;QAC3C,mCAAmC;QACnC,yBAAyB;KAC5B,CAAC;AACN,CAAC;AArED,gEAqEC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IGuidanceSql, IGuidanceConnection, IGuidanceRecipient, IHomeMatchFacts } from "./model";
|
|
2
|
+
/** Bind existing batched Home queries to the caller's Prisma SQL implementation. */
|
|
3
|
+
export declare function createGuidanceQueries<TSql>(adapter: IGuidanceSql<TSql>): {
|
|
4
|
+
readHomeMatchSessionFacts: (connection: IGuidanceConnection<TSql>, contexts: IGuidanceRecipient[], now: Date, facts: Map<string, IHomeMatchFacts>) => Promise<number>;
|
|
5
|
+
};
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.createGuidanceQueries = void 0;
|
|
13
|
+
const luxon_1 = require("luxon");
|
|
14
|
+
const period_1 = require("../program-engagement/period");
|
|
15
|
+
const invitation_history_1 = require("./invitation-history");
|
|
16
|
+
const model_1 = require("./model");
|
|
17
|
+
/** Bind existing batched Home queries to the caller's Prisma SQL implementation. */
|
|
18
|
+
function createGuidanceQueries(adapter) {
|
|
19
|
+
/**
|
|
20
|
+
* Recognize only canonical UTC strings whose calendar fields can be aggregated without coercion.
|
|
21
|
+
* Other existing values remain the responsibility of sessionInvitationDate.
|
|
22
|
+
*
|
|
23
|
+
* @param {TSql} value JSON timestamp expression.
|
|
24
|
+
* @returns {TSql} Strict canonical timestamp predicate.
|
|
25
|
+
*/
|
|
26
|
+
function canonicalTimestamp(value) {
|
|
27
|
+
const text = adapter.sql `JSON_UNQUOTE(${value})`;
|
|
28
|
+
return adapter.sql `(JSON_TYPE(${value}) = 'STRING'
|
|
29
|
+
AND REGEXP_LIKE(${text}, '^[1-9][0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9][.][0-9]{3}Z$', 'c')
|
|
30
|
+
AND SUBSTRING(${text}, 9, 2) <= DAY(LAST_DAY(CONCAT(SUBSTRING(${text}, 1, 7), '-01'))))`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Normalize supported JSON storage without changing shared parser acceptance or error behavior.
|
|
34
|
+
*
|
|
35
|
+
* @param {TSql} scope Already authorized match/participant rows.
|
|
36
|
+
* @returns {TSql} Reusable invitation-history CTEs.
|
|
37
|
+
*/
|
|
38
|
+
function acceptanceHistory(scope) {
|
|
39
|
+
const invited = adapter.sql `JSON_EXTRACT(document, '$[0].invited')`;
|
|
40
|
+
const accepted = adapter.sql `JSON_EXTRACT(document, '$[0].attending')`;
|
|
41
|
+
const safeInvited = canonicalTimestamp(invited);
|
|
42
|
+
const safeAccepted = canonicalTimestamp(accepted);
|
|
43
|
+
return adapter.sql `WITH scoped_matches AS (${scope}), raw_history AS (
|
|
44
|
+
SELECT DISTINCT a.Id AS id, s.MatchId AS matchId, a.InvitationStatus AS history,
|
|
45
|
+
CASE WHEN JSON_TYPE(a.InvitationStatus) = 'STRING'
|
|
46
|
+
THEN JSON_UNQUOTE(a.InvitationStatus) ELSE a.InvitationStatus END AS rawHistory
|
|
47
|
+
FROM scoped_matches m
|
|
48
|
+
JOIN session s ON s.MatchId = m.matchId AND s.Type = ${"ONEONONE"}
|
|
49
|
+
JOIN sessionattendance a ON a.SessionRef = s.Ref
|
|
50
|
+
AND (BINARY a.UserRef = BINARY m.mentorRef OR BINARY a.UserRef = BINARY m.menteeRef)
|
|
51
|
+
), decoded_history AS (
|
|
52
|
+
SELECT *, CASE WHEN JSON_VALID(rawHistory) THEN CAST(rawHistory AS JSON) ELSE NULL END AS document
|
|
53
|
+
FROM raw_history
|
|
54
|
+
), classified_history AS (
|
|
55
|
+
SELECT *, COALESCE((rawHistory IS NULL OR JSON_TYPE(document) = 'NULL'
|
|
56
|
+
OR (JSON_TYPE(document) = 'ARRAY' AND JSON_LENGTH(document) = 1
|
|
57
|
+
AND JSON_TYPE(JSON_EXTRACT(document, '$[0]')) IN ('OBJECT', 'ARRAY')))
|
|
58
|
+
AND (${invited} IS NULL OR JSON_TYPE(${invited}) = 'NULL' OR JSON_UNQUOTE(${invited}) = '0' OR ${safeInvited})
|
|
59
|
+
AND (${accepted} IS NULL OR JSON_TYPE(${accepted}) = 'NULL' OR JSON_UNQUOTE(${accepted}) = '0' OR ${safeAccepted}), 0) AS canonical,
|
|
60
|
+
CASE WHEN ${safeInvited} THEN STR_TO_DATE(SUBSTRING(JSON_UNQUOTE(${invited}), 1, 19), '%Y-%m-%dT%H:%i:%s') END AS invitedOn,
|
|
61
|
+
CASE WHEN ${safeAccepted} THEN STR_TO_DATE(SUBSTRING(JSON_UNQUOTE(${accepted}), 1, 19), '%Y-%m-%dT%H:%i:%s') END AS acceptedOn
|
|
62
|
+
FROM decoded_history
|
|
63
|
+
)`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Populate Home facts with batched summaries and ranked candidates, never full session histories.
|
|
67
|
+
*
|
|
68
|
+
* @param {IGuidanceConnection<TSql>} connection Existing database connection.
|
|
69
|
+
* @param {IGuidanceRecipient[]} contexts Already authorized match identities.
|
|
70
|
+
* @param {Date} now Stable evaluation timestamp.
|
|
71
|
+
* @param {Map<string, IHomeMatchFacts>} facts Request-local facts to populate.
|
|
72
|
+
* @returns {Promise<number>} Earliest future session transition, or Infinity.
|
|
73
|
+
*/
|
|
74
|
+
function readHomeMatchSessionFacts(connection, contexts, now, facts) {
|
|
75
|
+
var _a, _b, _c;
|
|
76
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
+
if (!contexts.length)
|
|
78
|
+
return Infinity;
|
|
79
|
+
const scope = adapter.sql `SELECT * FROM JSON_TABLE(${JSON.stringify(contexts.map((context) => ({
|
|
80
|
+
matchId: context.Id,
|
|
81
|
+
mentorRef: context.MentorRef,
|
|
82
|
+
menteeRef: context.MenteeRef,
|
|
83
|
+
recipientRef: context.recipientRef
|
|
84
|
+
})))}, '$[*]' COLUMNS(matchId INT PATH '$.matchId', mentorRef CHAR(36) PATH '$.mentorRef', menteeRef CHAR(36) PATH '$.menteeRef', recipientRef CHAR(36) PATH '$.recipientRef')) AS authorized`;
|
|
85
|
+
const matchIds = adapter.join(contexts.map((context) => context.Id));
|
|
86
|
+
const summaries = yield connection.$queryRaw(adapter.sql `
|
|
87
|
+
WITH scoped_sessions AS (
|
|
88
|
+
SELECT Id, MatchId, StartTime, EndTime, IsCompleted, IsOffline FROM session
|
|
89
|
+
WHERE MatchId IN (${matchIds}) AND Type = ${"ONEONONE"}
|
|
90
|
+
), summary AS (
|
|
91
|
+
SELECT MatchId, COUNT(*) AS total,
|
|
92
|
+
MAX(CASE WHEN IsOffline = 1 AND IsCompleted = 1 THEN StartTime END) AS offlineCompletedOn,
|
|
93
|
+
MAX(CASE WHEN EndTime > ${now} AND (IsCompleted IS NULL OR IsCompleted <> 1) THEN 1 ELSE 0 END) AS hasUpcoming,
|
|
94
|
+
MAX(CASE WHEN IsCompleted = 1 THEN CASE WHEN IsOffline = 1 THEN StartTime
|
|
95
|
+
WHEN EndTime <= ${now} THEN EndTime END END) AS completedOn
|
|
96
|
+
FROM scoped_sessions GROUP BY MatchId
|
|
97
|
+
), ended AS (
|
|
98
|
+
SELECT *, ROW_NUMBER() OVER (PARTITION BY MatchId ORDER BY CASE WHEN IsOffline = 1 THEN StartTime ELSE EndTime END DESC, Id DESC) AS position
|
|
99
|
+
FROM scoped_sessions WHERE EndTime <= ${now} OR (IsOffline = 1 AND IsCompleted = 1)
|
|
100
|
+
)
|
|
101
|
+
SELECT summary.MatchId AS matchId, summary.total, summary.completedOn, summary.hasUpcoming, summary.offlineCompletedOn,
|
|
102
|
+
ended.Id AS id, ended.StartTime AS startsOn, ended.EndTime AS endsOn, ended.IsCompleted AS completed
|
|
103
|
+
FROM summary LEFT JOIN ended ON ended.MatchId = summary.MatchId AND ended.position = 1
|
|
104
|
+
`);
|
|
105
|
+
if (!summaries.length)
|
|
106
|
+
return Infinity;
|
|
107
|
+
for (const row of summaries) {
|
|
108
|
+
const values = contexts
|
|
109
|
+
.filter((context) => context.Id === row.matchId)
|
|
110
|
+
.map((context) => (0, model_1.requireGuidanceFacts)(facts, context.Id, context.recipientRef));
|
|
111
|
+
for (const value of values) {
|
|
112
|
+
value.totalSessions = Number(row.total);
|
|
113
|
+
value.latestCompletion = row.completedOn;
|
|
114
|
+
if (row.offlineCompletedOn) {
|
|
115
|
+
const zone = (_a = contexts.find((context) => context.Id === row.matchId)) === null || _a === void 0 ? void 0 : _a.TimeZone;
|
|
116
|
+
const offlineZone = { zone: (0, period_1.isValidTimeZone)(zone) ? zone : "UTC" };
|
|
117
|
+
const offlineDay = luxon_1.DateTime.fromISO(row.offlineCompletedOn.toISOString().slice(0, 10), offlineZone)
|
|
118
|
+
.endOf("day")
|
|
119
|
+
.toJSDate();
|
|
120
|
+
if (!value.latestCompletion || offlineDay > value.latestCompletion)
|
|
121
|
+
value.latestCompletion = offlineDay;
|
|
122
|
+
}
|
|
123
|
+
if (row.id !== null)
|
|
124
|
+
value.latestEnded = {
|
|
125
|
+
id: row.id,
|
|
126
|
+
start: row.startsOn,
|
|
127
|
+
end: row.endsOn,
|
|
128
|
+
completed: row.completed === 1
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const acceptedStatuses = ["attending", "attended"];
|
|
133
|
+
const acceptedValues = adapter.join(acceptedStatuses);
|
|
134
|
+
const candidates = summaries.some((row) => Boolean(row.hasUpcoming))
|
|
135
|
+
? yield connection.$queryRaw(adapter.sql `
|
|
136
|
+
WITH scoped_matches AS (${scope}), upcoming AS (
|
|
137
|
+
SELECT m.recipientRef, s.MatchId AS matchId, s.Id AS id, s.StartTime AS startsOn, s.EndTime AS endsOn,
|
|
138
|
+
currentAttendance.CurrentAttendanceStatus AS currentStatus,
|
|
139
|
+
partnerAttendance.CurrentAttendanceStatus AS partnerStatus
|
|
140
|
+
FROM scoped_matches m
|
|
141
|
+
JOIN session s ON s.MatchId = m.matchId AND s.Type = ${"ONEONONE"}
|
|
142
|
+
AND s.EndTime > ${now} AND (s.IsCompleted IS NULL OR s.IsCompleted <> 1)
|
|
143
|
+
JOIN sessionattendance currentAttendance ON currentAttendance.SessionRef = s.Ref
|
|
144
|
+
AND BINARY currentAttendance.UserRef = BINARY m.recipientRef
|
|
145
|
+
JOIN sessionattendance partnerAttendance ON partnerAttendance.SessionRef = s.Ref
|
|
146
|
+
AND BINARY partnerAttendance.UserRef <> BINARY currentAttendance.UserRef
|
|
147
|
+
AND BINARY partnerAttendance.UserRef = BINARY CASE WHEN BINARY m.mentorRef = BINARY m.recipientRef THEN m.menteeRef ELSE m.mentorRef END
|
|
148
|
+
), ranked AS (
|
|
149
|
+
SELECT *, ROW_NUMBER() OVER (PARTITION BY matchId, recipientRef, BINARY currentStatus, BINARY partnerStatus, (startsOn <= ${now}) ORDER BY startsOn, id) AS statusRank,
|
|
150
|
+
ROW_NUMBER() OVER (PARTITION BY matchId, recipientRef ORDER BY startsOn, id) AS firstRank,
|
|
151
|
+
MIN(CASE WHEN startsOn > ${now} THEN startsOn END) OVER (PARTITION BY matchId, recipientRef) AS nextStart,
|
|
152
|
+
MIN(endsOn) OVER (PARTITION BY matchId, recipientRef) AS nextEnd
|
|
153
|
+
FROM upcoming
|
|
154
|
+
)
|
|
155
|
+
SELECT recipientRef, matchId, id, startsOn, endsOn, currentStatus, partnerStatus, nextStart, nextEnd FROM ranked
|
|
156
|
+
WHERE firstRank = 1 OR (statusRank = 1 AND (
|
|
157
|
+
(BINARY currentStatus IN (${acceptedValues}) AND BINARY partnerStatus IN (${acceptedValues}))
|
|
158
|
+
OR (BINARY currentStatus = ${"invited"} AND BINARY partnerStatus IN (${acceptedValues}))
|
|
159
|
+
OR (BINARY currentStatus IN (${acceptedValues}) AND BINARY partnerStatus IN (${"invited"}, ${"requested"}))
|
|
160
|
+
))
|
|
161
|
+
`)
|
|
162
|
+
: [];
|
|
163
|
+
let nextTransition = Infinity;
|
|
164
|
+
for (const row of candidates) {
|
|
165
|
+
const value = (0, model_1.requireGuidanceFacts)(facts, row.matchId, row.recipientRef);
|
|
166
|
+
nextTransition = Math.min(nextTransition, (_c = (_b = row.nextStart) === null || _b === void 0 ? void 0 : _b.getTime()) !== null && _c !== void 0 ? _c : Infinity, row.nextEnd.getTime());
|
|
167
|
+
const candidate = { id: row.id, start: row.startsOn, end: row.endsOn, completed: false };
|
|
168
|
+
const keys = [];
|
|
169
|
+
const currentAccepted = acceptedStatuses.includes(row.currentStatus);
|
|
170
|
+
const partnerAccepted = acceptedStatuses.includes(row.partnerStatus);
|
|
171
|
+
if (currentAccepted && partnerAccepted) {
|
|
172
|
+
keys.push("accepted");
|
|
173
|
+
if (row.startsOn <= now)
|
|
174
|
+
keys.push("ongoing");
|
|
175
|
+
}
|
|
176
|
+
else if (row.currentStatus === "invited" && partnerAccepted)
|
|
177
|
+
keys.push("incomingInvitation");
|
|
178
|
+
else if (currentAccepted && ["invited", "requested"].includes(row.partnerStatus))
|
|
179
|
+
keys.push("outgoingInvitation");
|
|
180
|
+
for (const key of keys) {
|
|
181
|
+
const previous = value[key];
|
|
182
|
+
if (!previous ||
|
|
183
|
+
candidate.start < previous.start ||
|
|
184
|
+
(candidate.start.getTime() === previous.start.getTime() && candidate.id < previous.id))
|
|
185
|
+
value[key] = candidate;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const history = acceptanceHistory(scope);
|
|
189
|
+
const acceptances = yield connection.$queryRaw(adapter.sql `
|
|
190
|
+
${history}
|
|
191
|
+
SELECT matchId, MAX(CASE WHEN canonical = 1 AND invitedOn IS NOT NULL
|
|
192
|
+
AND acceptedOn >= invitedOn AND acceptedOn <= ${now} THEN acceptedOn END) AS acceptedOn,
|
|
193
|
+
MAX(canonical = 0) AS needsFallback
|
|
194
|
+
FROM classified_history GROUP BY matchId
|
|
195
|
+
`);
|
|
196
|
+
for (const row of acceptances)
|
|
197
|
+
for (const context of contexts.filter((item) => item.Id === row.matchId))
|
|
198
|
+
(0, model_1.requireGuidanceFacts)(facts, context.Id, context.recipientRef).latestAcceptance = row.acceptedOn;
|
|
199
|
+
if (acceptances.some((row) => Boolean(row.needsFallback))) {
|
|
200
|
+
let afterId = 0;
|
|
201
|
+
while (true) {
|
|
202
|
+
const page = yield connection.$queryRaw(adapter.sql `
|
|
203
|
+
${history}
|
|
204
|
+
SELECT id, matchId, history FROM classified_history
|
|
205
|
+
WHERE canonical = 0 AND id > ${afterId} ORDER BY id LIMIT 100
|
|
206
|
+
`);
|
|
207
|
+
if (!page.length)
|
|
208
|
+
break;
|
|
209
|
+
for (const row of page) {
|
|
210
|
+
const parsed = (0, invitation_history_1.readSessionInvitationHistory)(row.history);
|
|
211
|
+
const invited = (0, invitation_history_1.sessionInvitationDate)(parsed, "invited");
|
|
212
|
+
const accepted = (0, invitation_history_1.sessionInvitationDate)(parsed, "attending");
|
|
213
|
+
for (const context of contexts.filter((item) => item.Id === row.matchId)) {
|
|
214
|
+
const value = (0, model_1.requireGuidanceFacts)(facts, context.Id, context.recipientRef);
|
|
215
|
+
if (invited &&
|
|
216
|
+
accepted &&
|
|
217
|
+
accepted >= invited &&
|
|
218
|
+
accepted <= now &&
|
|
219
|
+
(!value.latestAcceptance || accepted > value.latestAcceptance))
|
|
220
|
+
value.latestAcceptance = accepted;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
afterId = page[page.length - 1].id;
|
|
224
|
+
if (page.length < 100)
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return nextTransition;
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return { readHomeMatchSessionFacts };
|
|
232
|
+
}
|
|
233
|
+
exports.createGuidanceQueries = createGuidanceQueries;
|
|
234
|
+
//# sourceMappingURL=session-facts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-facts.js","sourceRoot":"","sources":["../../match-guidance/session-facts.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bwi-mentorspaces/application-utils-npm",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.143",
|
|
4
4
|
"description": "Mentor Spaces npm packages for reusable models, utils, and abstracted, commonly used processes for DB Repo, Logging, etc.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mentor Spaces",
|