@bwi-mentorspaces/application-utils-npm 0.0.137 → 0.0.139
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/chat/stream/enum/index.d.ts +2 -0
- package/chat/stream/enum/index.js +2 -0
- package/chat/stream/enum/index.js.map +1 -1
- package/chat/stream/models/_/event.data.d.ts +11 -0
- package/package.json +3 -1
- package/program-engagement/index.d.ts +3 -0
- package/program-engagement/index.js +16 -0
- package/program-engagement/index.js.map +1 -0
- package/program-engagement/model.d.ts +93 -0
- package/program-engagement/model.js +6 -0
- package/program-engagement/model.js.map +1 -0
- package/program-engagement/period.d.ts +50 -0
- package/program-engagement/period.js +193 -0
- package/program-engagement/period.js.map +1 -0
- package/program-engagement/query.d.ts +11 -0
- package/program-engagement/query.js +129 -0
- package/program-engagement/query.js.map +1 -0
- package/meet/index.d.ts +0 -36
- package/meet/index.js +0 -74
- package/meet/index.js.map +0 -1
- package/meet/tests/unit/twilio/twilio.room.test.d.ts +0 -1
- package/meet/tests/unit/twilio/twilio.room.test.js +0 -33
- package/meet/tests/unit/twilio/twilio.room.test.js.map +0 -1
- package/meet/twilio/enum/index.d.ts +0 -6
- package/meet/twilio/enum/index.js +0 -11
- package/meet/twilio/enum/index.js.map +0 -1
- package/meet/twilio/index.d.ts +0 -5
- package/meet/twilio/index.js +0 -32
- package/meet/twilio/index.js.map +0 -1
- package/meet/twilio/models/_/room.data.d.ts +0 -6
- package/meet/twilio/models/_/room.data.js +0 -3
- package/meet/twilio/models/_/room.data.js.map +0 -1
- package/meet/twilio/models/_/twilio.config.d.ts +0 -29
- package/meet/twilio/models/_/twilio.config.js +0 -3
- package/meet/twilio/models/_/twilio.config.js.map +0 -1
- package/meet/twilio/models/index.d.ts +0 -3
- package/meet/twilio/models/index.js +0 -3
- package/meet/twilio/models/index.js.map +0 -1
- package/meet/twilio/twilio.api.d.ts +0 -28
- package/meet/twilio/twilio.api.js +0 -46
- package/meet/twilio/twilio.api.js.map +0 -1
- package/meet/twilio/twilio.auth.d.ts +0 -55
- package/meet/twilio/twilio.auth.js +0 -116
- package/meet/twilio/twilio.auth.js.map +0 -1
- package/meet/twilio/twilio.base.d.ts +0 -41
- package/meet/twilio/twilio.base.js +0 -54
- package/meet/twilio/twilio.base.js.map +0 -1
- package/meet/twilio/twilio.room.d.ts +0 -58
- package/meet/twilio/twilio.room.js +0 -173
- package/meet/twilio/twilio.room.js.map +0 -1
|
@@ -44,6 +44,8 @@ export declare enum CustomEventType {
|
|
|
44
44
|
MatchCreated = "match_created",
|
|
45
45
|
AdminMatchCreated = "admin_match_created",
|
|
46
46
|
AdminMatchRemoved = "admin_match_removed",
|
|
47
|
+
MatchRemovalRequested = "match_removal_requested",
|
|
48
|
+
MatchRemovalDeclined = "match_removal_declined",
|
|
47
49
|
ProgramMemberRemoved = "program_member_removed",
|
|
48
50
|
SurveyPrompt = "program_survey_prompt",
|
|
49
51
|
ProgramAnnouncement = "program_announcement",
|
|
@@ -52,6 +52,8 @@ var CustomEventType;
|
|
|
52
52
|
CustomEventType["MatchCreated"] = "match_created";
|
|
53
53
|
CustomEventType["AdminMatchCreated"] = "admin_match_created";
|
|
54
54
|
CustomEventType["AdminMatchRemoved"] = "admin_match_removed";
|
|
55
|
+
CustomEventType["MatchRemovalRequested"] = "match_removal_requested";
|
|
56
|
+
CustomEventType["MatchRemovalDeclined"] = "match_removal_declined";
|
|
55
57
|
CustomEventType["ProgramMemberRemoved"] = "program_member_removed";
|
|
56
58
|
CustomEventType["SurveyPrompt"] = "program_survey_prompt";
|
|
57
59
|
CustomEventType["ProgramAnnouncement"] = "program_announcement";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../chat/stream/enum/index.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,IAAY,UAGX;AAHD,WAAY,UAAU;IAClB,+BAAiB,CAAA;IACjB,+BAAiB,CAAA;AACrB,CAAC,EAHW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QAGrB;AAED;;GAEG;AACH,IAAY,YAEX;AAFD,WAAY,YAAY;IACpB,gEAAiB,CAAA;AACrB,CAAC,EAFW,YAAY,GAAZ,oBAAY,KAAZ,oBAAY,QAEvB;AAED;;GAEG;AACH,IAAY,WAGX;AAHD,WAAY,WAAW;IACnB,4BAAa,CAAA;IACb,sCAAuB,CAAA;AAC3B,CAAC,EAHW,WAAW,GAAX,mBAAW,KAAX,mBAAW,QAGtB;AAED;;GAEG;AACH,IAAY,QAKX;AALD,WAAY,QAAQ;IAChB,yBAAa,CAAA;IACb,2BAAe,CAAA;IACf,mCAAuB,CAAA;IACvB,2BAAe,CAAA;AACnB,CAAC,EALW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAKnB;AAED;;GAEG;AACH,IAAY,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../chat/stream/enum/index.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,IAAY,UAGX;AAHD,WAAY,UAAU;IAClB,+BAAiB,CAAA;IACjB,+BAAiB,CAAA;AACrB,CAAC,EAHW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QAGrB;AAED;;GAEG;AACH,IAAY,YAEX;AAFD,WAAY,YAAY;IACpB,gEAAiB,CAAA;AACrB,CAAC,EAFW,YAAY,GAAZ,oBAAY,KAAZ,oBAAY,QAEvB;AAED;;GAEG;AACH,IAAY,WAGX;AAHD,WAAY,WAAW;IACnB,4BAAa,CAAA;IACb,sCAAuB,CAAA;AAC3B,CAAC,EAHW,WAAW,GAAX,mBAAW,KAAX,mBAAW,QAGtB;AAED;;GAEG;AACH,IAAY,QAKX;AALD,WAAY,QAAQ;IAChB,yBAAa,CAAA;IACb,2BAAe,CAAA;IACf,mCAAuB,CAAA;IACvB,2BAAe,CAAA;AACnB,CAAC,EALW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAKnB;AAED;;GAEG;AACH,IAAY,eAoBX;AApBD,WAAY,eAAe;IACvB,qDAAkC,CAAA;IAClC,qDAAkC,CAAA;IAClC,sEAAmD,CAAA;IACnD,qDAAkC,CAAA;IAClC,qEAAkD,CAAA;IAClD,uEAAoD,CAAA;IACpD,+CAA4B,CAAA;IAC5B,uDAAoC,CAAA;IACpC,uDAAoC,CAAA;IACpC,qDAAkC,CAAA;IAClC,iDAA8B,CAAA;IAC9B,4DAAyC,CAAA;IACzC,4DAAyC,CAAA;IACzC,oEAAiD,CAAA;IACjD,kEAA+C,CAAA;IAC/C,kEAA+C,CAAA;IAC/C,yDAAsC,CAAA;IACtC,+DAA4C,CAAA;IAC5C,8EAA2D,CAAA;AAC/D,CAAC,EApBW,eAAe,GAAf,uBAAe,KAAf,uBAAe,QAoB1B"}
|
|
@@ -205,6 +205,17 @@ export interface IEventTypesData {
|
|
|
205
205
|
mentorRef: string;
|
|
206
206
|
menteeRef: string;
|
|
207
207
|
};
|
|
208
|
+
[CustomEventType.MatchRemovalRequested]: {
|
|
209
|
+
programRef: string;
|
|
210
|
+
programName: string;
|
|
211
|
+
matchRef: string;
|
|
212
|
+
memberName: string;
|
|
213
|
+
};
|
|
214
|
+
[CustomEventType.MatchRemovalDeclined]: {
|
|
215
|
+
programRef: string;
|
|
216
|
+
programName: string;
|
|
217
|
+
declineExplanation: string;
|
|
218
|
+
};
|
|
208
219
|
[CustomEventType.ProgramMemberRemoved]: {
|
|
209
220
|
programRef: string;
|
|
210
221
|
programName: string;
|
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.139",
|
|
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",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"@types/crypto-js": "^4.1.0",
|
|
22
22
|
"@types/express": "^4.17.13",
|
|
23
23
|
"@types/jest": "^27.4.0",
|
|
24
|
+
"@types/luxon": "^3.7.6",
|
|
24
25
|
"@types/node": "^17.0.8",
|
|
25
26
|
"@types/supertest": "^2.0.11",
|
|
26
27
|
"@types/uuid": "^8.3.4",
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
"crypto-js": "^4.1.1",
|
|
46
47
|
"express": "^4.17.2",
|
|
47
48
|
"guid-typescript": "^1.0.9",
|
|
49
|
+
"luxon": "^3.7.2",
|
|
48
50
|
"reflect-metadata": "^0.1.13",
|
|
49
51
|
"serverless-http": "^2.7.0",
|
|
50
52
|
"stream-chat": "^6.6.0",
|
|
@@ -0,0 +1,16 @@
|
|
|
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("./period"), exports);
|
|
15
|
+
__exportStar(require("./query"), exports);
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../program-engagement/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,0CAAwB;AACxB,2CAAyB;AACzB,0CAAwB"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** Program fields needed for engagement, reusable by callers with an existing program. */
|
|
2
|
+
export interface IEngagementProgram {
|
|
3
|
+
Ref: string;
|
|
4
|
+
StartDate: Date | null;
|
|
5
|
+
EndDate: Date | null;
|
|
6
|
+
TimeZone: string | null;
|
|
7
|
+
EngagementType: "MEETINGS" | "MINUTES" | null;
|
|
8
|
+
EngagementAmount: number | null;
|
|
9
|
+
EngagementInterval: number | null;
|
|
10
|
+
EngagementPeriodUnit: "DAY" | "WEEK" | "MONTH" | null;
|
|
11
|
+
}
|
|
12
|
+
/** Validated, complete program engagement configuration. */
|
|
13
|
+
export interface IEngagementConfiguration {
|
|
14
|
+
timeZone: string;
|
|
15
|
+
type: NonNullable<IEngagementProgram["EngagementType"]>;
|
|
16
|
+
amount: number;
|
|
17
|
+
interval: number;
|
|
18
|
+
periodUnit: NonNullable<IEngagementProgram["EngagementPeriodUnit"]>;
|
|
19
|
+
}
|
|
20
|
+
/** Calendar boundaries and program-clipped boundaries; end timestamps are exclusive. */
|
|
21
|
+
export interface IEngagementPeriod {
|
|
22
|
+
calendarStart: Date;
|
|
23
|
+
calendarEndExclusive: Date;
|
|
24
|
+
start: Date;
|
|
25
|
+
endExclusive: Date;
|
|
26
|
+
fullIntervalDays: number;
|
|
27
|
+
}
|
|
28
|
+
/** Program-level periods resolved using one request timestamp. */
|
|
29
|
+
export interface IEngagementPeriods {
|
|
30
|
+
previous: IEngagementPeriod | null;
|
|
31
|
+
current: IEngagementPeriod | null;
|
|
32
|
+
}
|
|
33
|
+
/** Eligible match and participant identity. */
|
|
34
|
+
export interface IEngagementMatch {
|
|
35
|
+
id: number;
|
|
36
|
+
ref: string;
|
|
37
|
+
publishedOn: Date;
|
|
38
|
+
mentorRef: string;
|
|
39
|
+
menteeRef: string;
|
|
40
|
+
}
|
|
41
|
+
/** Invitation classification for incomplete sessions. */
|
|
42
|
+
export declare type EngagementInvitationState = "accepted" | "pending" | "declined" | "unclassified";
|
|
43
|
+
/** Incomplete sessions grouped by their position relative to the evaluation timestamp. */
|
|
44
|
+
export declare type EngagementSessionTiming = "future" | "underway" | "endedIncomplete";
|
|
45
|
+
/** Count and scheduled duration, without counting these sessions as completed engagement. */
|
|
46
|
+
export interface IEngagementSessionMeasure {
|
|
47
|
+
meetings: number;
|
|
48
|
+
scheduledMinutes: number;
|
|
49
|
+
}
|
|
50
|
+
/** Activity facts for one eligible match-period intersection. */
|
|
51
|
+
export interface IEngagementSessionFacts {
|
|
52
|
+
completedMeetings: number;
|
|
53
|
+
completedOfflineMeetings: number;
|
|
54
|
+
completedMinutes: number;
|
|
55
|
+
incomplete: Record<EngagementSessionTiming, Record<EngagementInvitationState, IEngagementSessionMeasure>>;
|
|
56
|
+
}
|
|
57
|
+
/** Calculated engagement for one match in one period. */
|
|
58
|
+
export interface IMatchPeriodEngagement {
|
|
59
|
+
classification: EngagementClassification | null;
|
|
60
|
+
status: "MET" | "SHORTFALL" | "IN_PROGRESS" | "NOT_APPLICABLE";
|
|
61
|
+
start: Date | null;
|
|
62
|
+
endExclusive: Date | null;
|
|
63
|
+
eligibleDays: number;
|
|
64
|
+
elapsedEligibleDays: number;
|
|
65
|
+
remainingEligibleDays: number;
|
|
66
|
+
requirement: number | null;
|
|
67
|
+
creditedAmount: number;
|
|
68
|
+
remainingAmount: number | null;
|
|
69
|
+
requirementSatisfied: boolean | null;
|
|
70
|
+
sessions: IEngagementSessionFacts;
|
|
71
|
+
}
|
|
72
|
+
/** Independent engagement results for one match. */
|
|
73
|
+
export interface IMatchEngagement extends IEngagementMatch {
|
|
74
|
+
previous: IMatchPeriodEngagement | null;
|
|
75
|
+
current: IMatchPeriodEngagement | null;
|
|
76
|
+
}
|
|
77
|
+
/** Approved session progress states, evaluated independently from member activity. */
|
|
78
|
+
export declare const ENGAGEMENT_CLASSIFICATIONS: readonly ["GREEN", "YELLOW", "RED", "NO_ACTIVITY"];
|
|
79
|
+
/** One supported session progress classification. */
|
|
80
|
+
export declare type EngagementClassification = typeof ENGAGEMENT_CLASSIFICATIONS[number];
|
|
81
|
+
/** One program-local calendar day, serialized as UTC for parameterized SQL. */
|
|
82
|
+
export interface IEngagementCalendarDay {
|
|
83
|
+
period: "previous" | "current";
|
|
84
|
+
periodStart: string;
|
|
85
|
+
endTime: string;
|
|
86
|
+
dayStart: string;
|
|
87
|
+
dayEnd: string;
|
|
88
|
+
offlineStart: string;
|
|
89
|
+
offlineEnd: string;
|
|
90
|
+
eligibleDays: number;
|
|
91
|
+
elapsedDays: number;
|
|
92
|
+
fullIntervalDays: number;
|
|
93
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ENGAGEMENT_CLASSIFICATIONS = void 0;
|
|
4
|
+
/** Approved session progress states, evaluated independently from member activity. */
|
|
5
|
+
exports.ENGAGEMENT_CLASSIFICATIONS = ["GREEN", "YELLOW", "RED", "NO_ACTIVITY"];
|
|
6
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../program-engagement/model.ts"],"names":[],"mappings":";;;AAuFA,sFAAsF;AACzE,QAAA,0BAA0B,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,CAAU,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { IEngagementProgram, IEngagementConfiguration, IEngagementPeriods, IEngagementCalendarDay } from "./model";
|
|
2
|
+
/**
|
|
3
|
+
* Determine whether a value is a valid IANA timezone identifier.
|
|
4
|
+
*
|
|
5
|
+
* @param {unknown} value Potential timezone identifier
|
|
6
|
+
* @returns {value is string} Whether the value is a valid timezone identifier
|
|
7
|
+
*/
|
|
8
|
+
export declare function isValidTimeZone(value: unknown): value is string;
|
|
9
|
+
/**
|
|
10
|
+
* Determine whether the program's exclusive end boundary has been reached.
|
|
11
|
+
*
|
|
12
|
+
* @param {Pick<IEngagementProgram, "EndDate">} program Loaded program dates
|
|
13
|
+
* @param {Date} evaluatedAt Shared request timestamp
|
|
14
|
+
* @returns {boolean} Whether the program has ended
|
|
15
|
+
*/
|
|
16
|
+
export declare function hasProgramEnded(program: Pick<IEngagementProgram, "EndDate">, evaluatedAt: Date): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Validate populated settings and distinguish programs that are not configured yet.
|
|
19
|
+
*
|
|
20
|
+
* @param {IEngagementProgram} program Already-loaded program
|
|
21
|
+
* @returns {IEngagementConfiguration | null} Complete configuration or null
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveEngagementConfiguration(program: IEngagementProgram): IEngagementConfiguration | null;
|
|
24
|
+
/**
|
|
25
|
+
* Count calendar days touched by a nonempty half-open timestamp interval.
|
|
26
|
+
*
|
|
27
|
+
* @param {Date} start Inclusive lower bound
|
|
28
|
+
* @param {Date} endExclusive Exclusive upper bound
|
|
29
|
+
* @param {string} timeZone Program timezone
|
|
30
|
+
* @returns {number} Whole calendar days; a partial day counts as one
|
|
31
|
+
*/
|
|
32
|
+
export declare function engagementCalendarDays(start: Date, endExclusive: Date, timeZone: string): number;
|
|
33
|
+
/**
|
|
34
|
+
* Parameterize calendar-day boundaries once per program, including daylight-saving changes.
|
|
35
|
+
*
|
|
36
|
+
* @param {IEngagementPeriods} periods Program-clipped periods
|
|
37
|
+
* @param {string} timeZone Program timezone
|
|
38
|
+
* @param {Date} evaluatedAt Shared evaluation instant
|
|
39
|
+
* @returns {IEngagementCalendarDay[]} UTC boundaries and whole-day counts
|
|
40
|
+
*/
|
|
41
|
+
export declare function engagementCalendarRows(periods: IEngagementPeriods, timeZone: string, evaluatedAt: Date): IEngagementCalendarDay[];
|
|
42
|
+
/**
|
|
43
|
+
* Resolve only the current and immediately preceding program periods.
|
|
44
|
+
*
|
|
45
|
+
* @param {IEngagementProgram} program Already-loaded program with a start date
|
|
46
|
+
* @param {IEngagementConfiguration} configuration Validated settings
|
|
47
|
+
* @param {Date} evaluatedAt Single request timestamp
|
|
48
|
+
* @returns {IEngagementPeriods} Calendar periods clipped to program dates
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveEngagementPeriods(program: IEngagementProgram, configuration: IEngagementConfiguration, evaluatedAt: Date): IEngagementPeriods;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveEngagementPeriods = exports.engagementCalendarRows = exports.engagementCalendarDays = exports.resolveEngagementConfiguration = exports.hasProgramEnded = exports.isValidTimeZone = void 0;
|
|
4
|
+
const luxon_1 = require("luxon");
|
|
5
|
+
const core_1 = require("../core");
|
|
6
|
+
/**
|
|
7
|
+
* Determine whether a value is a valid IANA timezone identifier.
|
|
8
|
+
*
|
|
9
|
+
* @param {unknown} value Potential timezone identifier
|
|
10
|
+
* @returns {value is string} Whether the value is a valid timezone identifier
|
|
11
|
+
*/
|
|
12
|
+
function isValidTimeZone(value) {
|
|
13
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
new Intl.DateTimeFormat("en-US", { timeZone: value.trim() }).format();
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
catch (_a) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.isValidTimeZone = isValidTimeZone;
|
|
25
|
+
/**
|
|
26
|
+
* Determine whether the program's exclusive end boundary has been reached.
|
|
27
|
+
*
|
|
28
|
+
* @param {Pick<IEngagementProgram, "EndDate">} program Loaded program dates
|
|
29
|
+
* @param {Date} evaluatedAt Shared request timestamp
|
|
30
|
+
* @returns {boolean} Whether the program has ended
|
|
31
|
+
*/
|
|
32
|
+
function hasProgramEnded(program, evaluatedAt) {
|
|
33
|
+
return program.EndDate != null && evaluatedAt >= program.EndDate;
|
|
34
|
+
}
|
|
35
|
+
exports.hasProgramEnded = hasProgramEnded;
|
|
36
|
+
/**
|
|
37
|
+
* Validate populated settings and distinguish programs that are not configured yet.
|
|
38
|
+
*
|
|
39
|
+
* @param {IEngagementProgram} program Already-loaded program
|
|
40
|
+
* @returns {IEngagementConfiguration | null} Complete configuration or null
|
|
41
|
+
*/
|
|
42
|
+
function resolveEngagementConfiguration(program) {
|
|
43
|
+
const validInteger = (value) => value == null || (Number.isInteger(value) && value >= 1 && value <= 65535);
|
|
44
|
+
if ((program.TimeZone != null && !isValidTimeZone(program.TimeZone)) ||
|
|
45
|
+
(program.EngagementType != null && !["MEETINGS", "MINUTES"].includes(program.EngagementType)) ||
|
|
46
|
+
(program.EngagementPeriodUnit != null && !["DAY", "WEEK", "MONTH"].includes(program.EngagementPeriodUnit)) ||
|
|
47
|
+
!validInteger(program.EngagementAmount) ||
|
|
48
|
+
!validInteger(program.EngagementInterval) ||
|
|
49
|
+
(program.StartDate != null && !Number.isFinite(program.StartDate.getTime())) ||
|
|
50
|
+
(program.EndDate != null && !Number.isFinite(program.EndDate.getTime())) ||
|
|
51
|
+
(program.StartDate != null && program.EndDate != null && program.EndDate <= program.StartDate)) {
|
|
52
|
+
throw new core_1.ApiError(500 /* InternalServerError */, "Invalid program engagement configuration or program dates.");
|
|
53
|
+
}
|
|
54
|
+
if (program.TimeZone == null ||
|
|
55
|
+
program.EngagementType == null ||
|
|
56
|
+
program.EngagementAmount == null ||
|
|
57
|
+
program.EngagementInterval == null ||
|
|
58
|
+
program.EngagementPeriodUnit == null)
|
|
59
|
+
return null;
|
|
60
|
+
return {
|
|
61
|
+
timeZone: program.TimeZone.trim(),
|
|
62
|
+
type: program.EngagementType,
|
|
63
|
+
amount: program.EngagementAmount,
|
|
64
|
+
interval: program.EngagementInterval,
|
|
65
|
+
periodUnit: program.EngagementPeriodUnit
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
exports.resolveEngagementConfiguration = resolveEngagementConfiguration;
|
|
69
|
+
/**
|
|
70
|
+
* Count calendar days touched by a nonempty half-open timestamp interval.
|
|
71
|
+
*
|
|
72
|
+
* @param {Date} start Inclusive lower bound
|
|
73
|
+
* @param {Date} endExclusive Exclusive upper bound
|
|
74
|
+
* @param {string} timeZone Program timezone
|
|
75
|
+
* @returns {number} Whole calendar days; a partial day counts as one
|
|
76
|
+
*/
|
|
77
|
+
function engagementCalendarDays(start, endExclusive, timeZone) {
|
|
78
|
+
if (endExclusive <= start)
|
|
79
|
+
return 0;
|
|
80
|
+
const firstDay = luxon_1.DateTime.fromJSDate(start, { zone: timeZone }).startOf("day");
|
|
81
|
+
const lastDay = luxon_1.DateTime.fromJSDate(endExclusive, { zone: timeZone }).minus({ milliseconds: 1 }).startOf("day");
|
|
82
|
+
return Math.round(lastDay.diff(firstDay, "days").days) + 1;
|
|
83
|
+
}
|
|
84
|
+
exports.engagementCalendarDays = engagementCalendarDays;
|
|
85
|
+
/**
|
|
86
|
+
* Parameterize calendar-day boundaries once per program, including daylight-saving changes.
|
|
87
|
+
*
|
|
88
|
+
* @param {IEngagementPeriods} periods Program-clipped periods
|
|
89
|
+
* @param {string} timeZone Program timezone
|
|
90
|
+
* @param {Date} evaluatedAt Shared evaluation instant
|
|
91
|
+
* @returns {IEngagementCalendarDay[]} UTC boundaries and whole-day counts
|
|
92
|
+
*/
|
|
93
|
+
function engagementCalendarRows(periods, timeZone, evaluatedAt) {
|
|
94
|
+
const rows = [];
|
|
95
|
+
const today = luxon_1.DateTime.fromJSDate(evaluatedAt, { zone: timeZone }).startOf("day").toJSDate();
|
|
96
|
+
const sqlDate = (value) => value.toISOString().slice(0, 19).replace("T", " ");
|
|
97
|
+
for (const key of ["previous", "current"]) {
|
|
98
|
+
const period = periods[key];
|
|
99
|
+
if (!period)
|
|
100
|
+
continue;
|
|
101
|
+
let day = luxon_1.DateTime.fromJSDate(period.start, { zone: timeZone }).startOf("day");
|
|
102
|
+
while (day.toMillis() < period.endExclusive.getTime()) {
|
|
103
|
+
const next = day.plus({ days: 1 });
|
|
104
|
+
const start = new Date(Math.max(day.toMillis(), period.start.getTime()));
|
|
105
|
+
const eligibleDays = engagementCalendarDays(start, period.endExclusive, timeZone);
|
|
106
|
+
rows.push({
|
|
107
|
+
period: key,
|
|
108
|
+
periodStart: sqlDate(period.start),
|
|
109
|
+
endTime: sqlDate(period.endExclusive),
|
|
110
|
+
dayStart: sqlDate(start),
|
|
111
|
+
dayEnd: sqlDate(new Date(Math.min(next.toMillis(), period.endExclusive.getTime()))),
|
|
112
|
+
offlineStart: day.toFormat("yyyy-MM-dd HH:mm:ss"),
|
|
113
|
+
offlineEnd: luxon_1.DateTime.fromJSDate(period.endExclusive, { zone: timeZone })
|
|
114
|
+
.minus({ milliseconds: 1 })
|
|
115
|
+
.startOf("day")
|
|
116
|
+
.plus({ days: 1 })
|
|
117
|
+
.toFormat("yyyy-MM-dd HH:mm:ss"),
|
|
118
|
+
eligibleDays,
|
|
119
|
+
elapsedDays: key === "previous"
|
|
120
|
+
? eligibleDays
|
|
121
|
+
: engagementCalendarDays(start, new Date(Math.min(today.getTime(), period.endExclusive.getTime())), timeZone),
|
|
122
|
+
fullIntervalDays: period.fullIntervalDays
|
|
123
|
+
});
|
|
124
|
+
day = next;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return rows;
|
|
128
|
+
}
|
|
129
|
+
exports.engagementCalendarRows = engagementCalendarRows;
|
|
130
|
+
/**
|
|
131
|
+
* Resolve only the current and immediately preceding program periods.
|
|
132
|
+
*
|
|
133
|
+
* @param {IEngagementProgram} program Already-loaded program with a start date
|
|
134
|
+
* @param {IEngagementConfiguration} configuration Validated settings
|
|
135
|
+
* @param {Date} evaluatedAt Single request timestamp
|
|
136
|
+
* @returns {IEngagementPeriods} Calendar periods clipped to program dates
|
|
137
|
+
*/
|
|
138
|
+
function resolveEngagementPeriods(program, configuration, evaluatedAt) {
|
|
139
|
+
if (!program.StartDate || evaluatedAt < program.StartDate)
|
|
140
|
+
return { previous: null, current: null };
|
|
141
|
+
const start = luxon_1.DateTime.fromJSDate(program.StartDate, { zone: configuration.timeZone });
|
|
142
|
+
const startDay = start.startOf("day");
|
|
143
|
+
const unit = configuration.periodUnit;
|
|
144
|
+
const interval = configuration.interval;
|
|
145
|
+
const advance = (date, count) => unit === "MONTH"
|
|
146
|
+
? date.plus({ months: count * interval })
|
|
147
|
+
: date.plus({ days: count * interval * (unit === "WEEK" ? 7 : 1) });
|
|
148
|
+
const containingStart = unit === "MONTH"
|
|
149
|
+
? startDay.startOf("month")
|
|
150
|
+
: unit === "WEEK"
|
|
151
|
+
? startDay.minus({ days: startDay.weekday % 7 })
|
|
152
|
+
: startDay;
|
|
153
|
+
const hasStub = containingStart.toMillis() !== startDay.toMillis();
|
|
154
|
+
const firstFullStart = !hasStub
|
|
155
|
+
? containingStart
|
|
156
|
+
: unit === "MONTH"
|
|
157
|
+
? containingStart.plus({ months: 1 })
|
|
158
|
+
: containingStart.plus({ weeks: 1 });
|
|
159
|
+
const ended = hasProgramEnded(program, evaluatedAt);
|
|
160
|
+
// The instant before an exclusive end belongs to the final ended period.
|
|
161
|
+
const reference = luxon_1.DateTime.fromJSDate(ended ? program.EndDate : evaluatedAt, { zone: configuration.timeZone });
|
|
162
|
+
const anchor = ended ? reference.minus({ milliseconds: 1 }) : reference;
|
|
163
|
+
const months = (anchor.year - firstFullStart.year) * 12 + anchor.month - firstFullStart.month;
|
|
164
|
+
const index = anchor < firstFullStart
|
|
165
|
+
? -1
|
|
166
|
+
: unit === "MONTH"
|
|
167
|
+
? Math.floor(months / interval)
|
|
168
|
+
: Math.floor(anchor.startOf("day").diff(firstFullStart, "days").days / (interval * (unit === "WEEK" ? 7 : 1)));
|
|
169
|
+
const periodAt = (periodIndex) => {
|
|
170
|
+
var _a, _b;
|
|
171
|
+
if (periodIndex < -1 || (periodIndex === -1 && !hasStub))
|
|
172
|
+
return null;
|
|
173
|
+
const nominalStart = periodIndex === -1 ? containingStart : advance(firstFullStart, periodIndex);
|
|
174
|
+
const nominalEnd = advance(nominalStart, 1);
|
|
175
|
+
const calendarEnd = periodIndex === -1 ? firstFullStart : nominalEnd;
|
|
176
|
+
const lower = Math.max(program.StartDate.getTime(), nominalStart.toMillis());
|
|
177
|
+
const upper = Math.min((_b = (_a = program.EndDate) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : Infinity, calendarEnd.toMillis());
|
|
178
|
+
if (upper <= lower)
|
|
179
|
+
return null;
|
|
180
|
+
return {
|
|
181
|
+
calendarStart: nominalStart.toJSDate(),
|
|
182
|
+
calendarEndExclusive: calendarEnd.toJSDate(),
|
|
183
|
+
start: new Date(lower),
|
|
184
|
+
endExclusive: new Date(upper),
|
|
185
|
+
fullIntervalDays: Math.round(nominalEnd.diff(nominalStart, "days").days)
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
return ended
|
|
189
|
+
? { previous: periodAt(index), current: null }
|
|
190
|
+
: { previous: periodAt(index - 1), current: periodAt(index) };
|
|
191
|
+
}
|
|
192
|
+
exports.resolveEngagementPeriods = resolveEngagementPeriods;
|
|
193
|
+
//# sourceMappingURL=period.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"period.js","sourceRoot":"","sources":["../../program-engagement/period.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IEngagementConfiguration, IEngagementPeriods } from "./model";
|
|
2
|
+
/** Parameterized SQL supplied by the consumer's Prisma client. */
|
|
3
|
+
export interface IEngagementSqlAdapter<TSql> {
|
|
4
|
+
sql: (strings: TemplateStringsArray, ...values: unknown[]) => TSql;
|
|
5
|
+
empty: TSql;
|
|
6
|
+
}
|
|
7
|
+
/** Bind the shared progress queries to a consumer's SQL implementation. */
|
|
8
|
+
export declare function createEngagementQueries<TSql>(adapter: IEngagementSqlAdapter<TSql>): {
|
|
9
|
+
engagementSetSql: (programRef: string, programStartDate: Date, matches: TSql, periods: IEngagementPeriods, configuration: IEngagementConfiguration, evaluatedAt: Date, includeFacts?: boolean) => TSql;
|
|
10
|
+
matchSessionAcceptedSql: (menteeStatus: TSql, mentorStatus: TSql) => TSql;
|
|
11
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEngagementQueries = void 0;
|
|
4
|
+
const luxon_1 = require("luxon");
|
|
5
|
+
const period_1 = require("./period");
|
|
6
|
+
/** Bind the shared progress queries to a consumer's SQL implementation. */
|
|
7
|
+
function createEngagementQueries(adapter) {
|
|
8
|
+
/** Require accepted participation from both members. */
|
|
9
|
+
function matchSessionAcceptedSql(menteeStatus, mentorStatus) {
|
|
10
|
+
return adapter.sql `(${menteeStatus} IN (${"attending"}, ${"attended"})
|
|
11
|
+
AND ${mentorStatus} IN (${"attending"}, ${"attended"}))`;
|
|
12
|
+
}
|
|
13
|
+
const SESSION_PROGRESS_STARTUP_GRACE_DAYS = 7;
|
|
14
|
+
/**
|
|
15
|
+
* Build reusable CTEs for period facts and classification before filtering or pagination.
|
|
16
|
+
* The input relation supplies id, publishedOn, mentorRef and menteeRef for eligible matches.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} programRef Owning program
|
|
19
|
+
* @param {Date} programStartDate Official program start, independent of reporting periods
|
|
20
|
+
* @param {TSql} matches Eligible match relation, optionally restricted to a page
|
|
21
|
+
* @param {IEngagementPeriods} periods Program-clipped periods
|
|
22
|
+
* @param {IEngagementConfiguration} configuration Validated requirement
|
|
23
|
+
* @param {Date} evaluatedAt Shared request timestamp
|
|
24
|
+
* @param {boolean} includeFacts Include grouped supporting facts for the engagement API
|
|
25
|
+
* @returns {TSql} CTE definitions without a leading WITH
|
|
26
|
+
*/
|
|
27
|
+
function engagementSetSql(programRef, programStartDate, matches, periods, configuration, evaluatedAt, includeFacts = false) {
|
|
28
|
+
const calendar = JSON.stringify((0, period_1.engagementCalendarRows)(periods, configuration.timeZone, evaluatedAt));
|
|
29
|
+
// Relationship starts on or after this boundary are still within their first seven calendar days.
|
|
30
|
+
const startupGraceCutoff = luxon_1.DateTime.fromJSDate(evaluatedAt, { zone: configuration.timeZone })
|
|
31
|
+
.startOf("day")
|
|
32
|
+
.minus({ days: SESSION_PROGRESS_STARTUP_GRACE_DAYS - 1 })
|
|
33
|
+
.toJSDate();
|
|
34
|
+
const duration = configuration.type === "MINUTES";
|
|
35
|
+
const unit = duration ? 60 : 1;
|
|
36
|
+
const measure = duration ? adapter.sql `seconds` : adapter.sql `meetings`;
|
|
37
|
+
return adapter.sql `
|
|
38
|
+
engagement_matches AS (${matches}),
|
|
39
|
+
engagement_days AS (
|
|
40
|
+
SELECT d.* FROM JSON_TABLE(${calendar}, '$[*]' COLUMNS (
|
|
41
|
+
period VARCHAR(8) PATH '$.period',
|
|
42
|
+
periodStart DATETIME PATH '$.periodStart', endTime DATETIME PATH '$.endTime',
|
|
43
|
+
dayStart DATETIME PATH '$.dayStart', dayEnd DATETIME PATH '$.dayEnd',
|
|
44
|
+
offlineStart DATETIME PATH '$.offlineStart', offlineEnd DATETIME PATH '$.offlineEnd',
|
|
45
|
+
eligibleDays INT PATH '$.eligibleDays', elapsedDays INT PATH '$.elapsedDays',
|
|
46
|
+
fullIntervalDays INT PATH '$.fullIntervalDays'
|
|
47
|
+
)) d
|
|
48
|
+
),
|
|
49
|
+
engagement_windows AS (
|
|
50
|
+
SELECT m.id AS matchId, m.mentorRef, m.menteeRef, d.period,
|
|
51
|
+
GREATEST(m.publishedOn, d.periodStart) AS startTime, d.endTime,
|
|
52
|
+
GREATEST(m.publishedOn, ${programStartDate}) >= ${startupGraceCutoff} AS inStartupGrace,
|
|
53
|
+
d.eligibleDays, d.elapsedDays, d.offlineStart, d.offlineEnd,
|
|
54
|
+
ROUND(CAST(${configuration.amount} AS DECIMAL(30, 12)) * d.eligibleDays / d.fullIntervalDays) AS requirement
|
|
55
|
+
FROM engagement_matches m JOIN engagement_days d
|
|
56
|
+
ON GREATEST(m.publishedOn, d.periodStart) >= d.dayStart
|
|
57
|
+
AND GREATEST(m.publishedOn, d.periodStart) < d.dayEnd
|
|
58
|
+
),
|
|
59
|
+
engagement_session_facts AS (
|
|
60
|
+
SELECT /*+ NO_MERGE(w) */ w.matchId, w.period,
|
|
61
|
+
CASE WHEN s.IsCompleted = 1 THEN 'completed'
|
|
62
|
+
WHEN s.StartTime > ${evaluatedAt} THEN 'future'
|
|
63
|
+
WHEN s.EndTime > ${evaluatedAt} THEN 'underway'
|
|
64
|
+
ELSE 'endedIncomplete' END AS timing,
|
|
65
|
+
CASE WHEN s.IsCompleted = 1 THEN 'unclassified'
|
|
66
|
+
WHEN ma.CurrentAttendanceStatus = ${"declined"}
|
|
67
|
+
OR ea.CurrentAttendanceStatus = ${"declined"} THEN 'declined'
|
|
68
|
+
WHEN ma.CurrentAttendanceStatus IN (${"invited"}, ${"requested"})
|
|
69
|
+
OR ea.CurrentAttendanceStatus IN (${"invited"}, ${"requested"}) THEN 'pending'
|
|
70
|
+
WHEN ${matchSessionAcceptedSql(adapter.sql `ea.CurrentAttendanceStatus`, adapter.sql `ma.CurrentAttendanceStatus`)} THEN 'accepted'
|
|
71
|
+
ELSE 'unclassified' END AS invitation,
|
|
72
|
+
CASE WHEN s.IsCompleted = 1 THEN COALESCE(s.DurationSeconds, TIMESTAMPDIFF(SECOND, s.StartTime, s.EndTime))
|
|
73
|
+
ELSE TIMESTAMPDIFF(SECOND, s.StartTime, s.EndTime) END AS seconds, 0 AS offline
|
|
74
|
+
FROM engagement_windows w
|
|
75
|
+
JOIN session s ON s.MatchId = w.matchId AND s.ProgramRef = ${programRef}
|
|
76
|
+
AND s.IsOffline = FALSE AND s.Type = ${"ONEONONE"} AND s.StartTime >= w.startTime AND s.StartTime < w.endTime
|
|
77
|
+
LEFT JOIN sessionattendance ma ON ma.SessionRef = s.Ref AND ma.UserRef = w.mentorRef
|
|
78
|
+
LEFT JOIN sessionattendance ea ON ea.SessionRef = s.Ref AND ea.UserRef = w.menteeRef
|
|
79
|
+
UNION ALL
|
|
80
|
+
SELECT /*+ NO_MERGE(w) */ w.matchId, w.period, 'completed', 'unclassified', 0, 1
|
|
81
|
+
FROM engagement_windows w
|
|
82
|
+
JOIN session s ON s.MatchId = w.matchId AND s.ProgramRef = ${programRef}
|
|
83
|
+
AND s.IsOffline = TRUE AND s.IsCompleted = 1 AND s.Type = ${"ONEONONE"}
|
|
84
|
+
AND s.StartTime >= w.offlineStart AND s.StartTime < w.offlineEnd
|
|
85
|
+
),
|
|
86
|
+
engagement_aggregates AS (
|
|
87
|
+
SELECT matchId, period, timing, invitation, COUNT(*) AS meetings, SUM(seconds) AS seconds, SUM(offline) AS offlineMeetings,
|
|
88
|
+
SUM(CASE WHEN seconds < 0 THEN 1 ELSE 0 END) AS invalidDurations
|
|
89
|
+
FROM engagement_session_facts GROUP BY matchId, period, timing, invitation
|
|
90
|
+
),
|
|
91
|
+
engagement_totals AS (
|
|
92
|
+
SELECT matchId, period,
|
|
93
|
+
SUM(CASE WHEN timing = 'completed' THEN ${measure} ELSE 0 END) AS completedMeasure,
|
|
94
|
+
SUM(CASE WHEN timing = 'future' AND invitation = 'accepted' THEN ${measure} ELSE 0 END) AS futureMeasure,
|
|
95
|
+
SUM(CASE WHEN timing = 'completed' OR (timing = 'future' AND invitation = 'accepted')
|
|
96
|
+
THEN meetings ELSE 0 END) AS positiveSessions,
|
|
97
|
+
SUM(invalidDurations) AS invalidDurations, SUM(offlineMeetings) AS completedOfflineMeetings
|
|
98
|
+
${includeFacts
|
|
99
|
+
? adapter.sql `, JSON_ARRAYAGG(JSON_OBJECT('timing', timing, 'invitation', invitation,
|
|
100
|
+
'meetings', meetings, 'seconds', seconds)) AS aggregates`
|
|
101
|
+
: adapter.empty}
|
|
102
|
+
FROM engagement_aggregates GROUP BY matchId, period
|
|
103
|
+
),
|
|
104
|
+
engagement_values AS (
|
|
105
|
+
SELECT /*+ NO_MERGE(w) */ w.*, COALESCE(t.completedMeasure, 0) AS completedMeasure,
|
|
106
|
+
COALESCE(t.positiveSessions, 0) AS positiveSessions,
|
|
107
|
+
COALESCE(t.completedOfflineMeetings, 0) AS completedOfflineMeetings,
|
|
108
|
+
COALESCE(t.futureMeasure, 0) AS futureMeasure, COALESCE(t.invalidDurations, 0) AS invalidDurations
|
|
109
|
+
${includeFacts ? adapter.sql `, COALESCE(t.aggregates, JSON_ARRAY()) AS aggregates` : adapter.empty}
|
|
110
|
+
FROM engagement_windows w LEFT JOIN engagement_totals t ON t.matchId = w.matchId AND t.period = w.period
|
|
111
|
+
),
|
|
112
|
+
engagement_classified AS (
|
|
113
|
+
SELECT v.*, CASE
|
|
114
|
+
WHEN period = 'current' AND inStartupGrace AND positiveSessions = 0 THEN 'NO_ACTIVITY'
|
|
115
|
+
WHEN completedMeasure >= requirement * ${unit} THEN 'GREEN'
|
|
116
|
+
WHEN period = 'previous' THEN CASE WHEN completedMeasure > 0 THEN 'YELLOW' ELSE 'RED' END
|
|
117
|
+
WHEN completedMeasure + futureMeasure >= requirement * ${unit} THEN 'GREEN'
|
|
118
|
+
WHEN inStartupGrace THEN 'YELLOW'
|
|
119
|
+
WHEN elapsedDays * 2 <= eligibleDays THEN 'YELLOW'
|
|
120
|
+
WHEN completedMeasure = 0 THEN 'RED'
|
|
121
|
+
WHEN completedMeasure >= ROUND(CAST(requirement AS DECIMAL(30, 12)) * elapsedDays / eligibleDays) * ${unit} THEN 'GREEN'
|
|
122
|
+
ELSE 'YELLOW' END AS classification
|
|
123
|
+
FROM engagement_values v
|
|
124
|
+
)`;
|
|
125
|
+
}
|
|
126
|
+
return { engagementSetSql, matchSessionAcceptedSql };
|
|
127
|
+
}
|
|
128
|
+
exports.createEngagementQueries = createEngagementQueries;
|
|
129
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../program-engagement/query.ts"],"names":[],"mappings":";;;AAAA,iCAAiC;AAEjC,qCAAkD;AAQlD,2EAA2E;AAC3E,SAAgB,uBAAuB,CAAO,OAAoC;IAC9E,wDAAwD;IACxD,SAAS,uBAAuB,CAAC,YAAkB,EAAE,YAAkB;QACnE,OAAO,OAAO,CAAC,GAAG,CAAA,IAAI,YAAY,QAAQ,WAAW,KAAK,UAAU;kBAC1D,YAAY,QAAQ,WAAW,KAAK,UAAU,IAAI,CAAC;IACjE,CAAC;IACD,MAAM,mCAAmC,GAAG,CAAC,CAAC;IAE9C;;;;;;;;;;;;OAYG;IACH,SAAS,gBAAgB,CACrB,UAAkB,EAClB,gBAAsB,EACtB,OAAa,EACb,OAA2B,EAC3B,aAAuC,EACvC,WAAiB,EACjB,eAAwB,KAAK;QAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,+BAAsB,EAAC,OAAO,EAAE,aAAa,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;QACtG,kGAAkG;QAClG,MAAM,kBAAkB,GAAG,gBAAQ,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,QAAQ,EAAE,CAAC;aACxF,OAAO,CAAC,KAAK,CAAC;aACd,KAAK,CAAC,EAAE,IAAI,EAAE,mCAAmC,GAAG,CAAC,EAAE,CAAC;aACxD,QAAQ,EAAE,CAAC;QAChB,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,KAAK,SAAS,CAAC;QAClD,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAA,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAA,UAAU,CAAC;QACxE,OAAO,OAAO,CAAC,GAAG,CAAA;iCACO,OAAO;;yCAEC,QAAQ;;;;;;;;;;;;0CAYP,gBAAgB,QAAQ,kBAAkB;;6BAGhE,aAAa,CAAC,MAClB;;;;;;;;yCAQyB,WAAW;uCACb,WAAW;;;wDAGM,UAAU;0DACR,UAAU;0DACV,SAAS,KAAK,WAAW;4DACvB,SAAS,KAAK,WAAW;2BAC1D,uBAAuB,CAC1B,OAAO,CAAC,GAAG,CAAA,4BAA4B,EACvC,OAAO,CAAC,GAAG,CAAA,4BAA4B,CAC1C;;;;;yEAKoD,UAAU;uDAC5B,UAAU;;;;;;yEAMQ,UAAU;4EACP,UAAU;;;;;;;;;;0DAU5B,OAAO;mFACkB,OAAO;;;;kBAKtE,YAAY;YACR,CAAC,CAAC,OAAO,CAAC,GAAG,CAAA;6EACwC;YACrD,CAAC,CAAC,OAAO,CAAC,KAClB;;;;;;;;kBAQE,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAA,sDAAsD,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK;;;;;;yDAMzD,IAAI;;yEAEY,IAAI;;;;sHAIyC,IAAI;;;UAGhH,CAAC;IACP,CAAC;IAED,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,CAAC;AACzD,CAAC;AAzID,0DAyIC"}
|
package/meet/index.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { ClientType } from "./twilio/enum";
|
|
2
|
-
import { IMeetConfig } from "./twilio/models/_/twilio.config";
|
|
3
|
-
/**
|
|
4
|
-
* Meet declarations
|
|
5
|
-
*/
|
|
6
|
-
interface IMeet<T> {
|
|
7
|
-
client: T;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Meet implementation
|
|
11
|
-
*/
|
|
12
|
-
export declare class Meet<T> implements IMeet<T> {
|
|
13
|
-
private _client;
|
|
14
|
-
private _config;
|
|
15
|
-
private _clientType;
|
|
16
|
-
/**
|
|
17
|
-
* Meet constructor
|
|
18
|
-
*
|
|
19
|
-
* @param {ClientType} clientType client type
|
|
20
|
-
* @param {IMeetConfig} config meet configuration
|
|
21
|
-
*/
|
|
22
|
-
constructor(clientType: ClientType, config: IMeetConfig);
|
|
23
|
-
/**
|
|
24
|
-
* getter for client
|
|
25
|
-
*
|
|
26
|
-
* @returns {T} client of type T
|
|
27
|
-
*/
|
|
28
|
-
get client(): T;
|
|
29
|
-
/**
|
|
30
|
-
* initialize method
|
|
31
|
-
*
|
|
32
|
-
* @returns {void} promise of type void
|
|
33
|
-
*/
|
|
34
|
-
private init;
|
|
35
|
-
}
|
|
36
|
-
export {};
|