@mj-biz-apps/common-activity-sync 5.41.0 → 5.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ActivitySyncEngine.d.ts +59 -1
- package/dist/ActivitySyncEngine.d.ts.map +1 -1
- package/dist/ActivitySyncEngine.js +159 -6
- package/dist/ActivitySyncEngine.js.map +1 -1
- package/dist/attachments.d.ts +106 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +147 -0
- package/dist/attachments.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/participants.d.ts +30 -0
- package/dist/participants.d.ts.map +1 -1
- package/dist/participants.js +48 -0
- package/dist/participants.js.map +1 -1
- package/dist/providers/GraphCalendarTransport.d.ts +115 -0
- package/dist/providers/GraphCalendarTransport.d.ts.map +1 -0
- package/dist/providers/GraphCalendarTransport.js +139 -0
- package/dist/providers/GraphCalendarTransport.js.map +1 -0
- package/dist/providers/GraphCommunicationTransport.d.ts.map +1 -1
- package/dist/providers/GraphCommunicationTransport.js +18 -4
- package/dist/providers/GraphCommunicationTransport.js.map +1 -1
- package/dist/providers/GraphMessageMapper.d.ts +2 -0
- package/dist/providers/GraphMessageMapper.d.ts.map +1 -1
- package/dist/providers/GraphMessageMapper.js +3 -0
- package/dist/providers/GraphMessageMapper.js.map +1 -1
- package/dist/providers/MSGraphActivitySyncProvider.d.ts +39 -4
- package/dist/providers/MSGraphActivitySyncProvider.d.ts.map +1 -1
- package/dist/providers/MSGraphActivitySyncProvider.js +45 -10
- package/dist/providers/MSGraphActivitySyncProvider.js.map +1 -1
- package/dist/providers/MSGraphCalendarSyncProvider.d.ts +55 -14
- package/dist/providers/MSGraphCalendarSyncProvider.d.ts.map +1 -1
- package/dist/providers/MSGraphCalendarSyncProvider.js +112 -38
- package/dist/providers/MSGraphCalendarSyncProvider.js.map +1 -1
- package/dist/providers/MessageTransport.d.ts +90 -0
- package/dist/providers/MessageTransport.d.ts.map +1 -1
- package/dist/providers/MessageTransport.js +72 -0
- package/dist/providers/MessageTransport.js.map +1 -1
- package/dist/providers/RecordedMessageTransport.d.ts.map +1 -1
- package/dist/providers/RecordedMessageTransport.js +25 -11
- package/dist/providers/RecordedMessageTransport.js.map +1 -1
- package/dist/stages.d.ts +11 -0
- package/dist/stages.d.ts.map +1 -1
- package/dist/stages.js.map +1 -1
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which attachments an included activity should keep.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS. `ActivitySyncRule.IncludeAttachments` describes itself as "1 = also pull
|
|
5
|
+
* attachments into ActivityFile rows", `MaxAttachmentBytes` sits beside it, and the `ActivityFile`
|
|
6
|
+
* table with its `Kind` value list (Body / Attachment / Ics) is migrated and in metadata — and
|
|
7
|
+
* nothing anywhere read any of it. A rule that asked for attachments got none, silently. That is the
|
|
8
|
+
* same shape as the `CredentialsRef` and `InternalDomains` gaps: schema and documentation written
|
|
9
|
+
* ahead of the wiring, with every test passing because nothing exercised the unwired path.
|
|
10
|
+
*
|
|
11
|
+
* DECIDED AT WRITE TIME, FROM THE RULE THAT DECIDED. Rules are evaluated after the fetch, so the
|
|
12
|
+
* question "does this item want its attachments?" cannot be answered while fetching. The item
|
|
13
|
+
* carries only the cheap `HasAttachments` flag; this turns that plus the winning rule into an
|
|
14
|
+
* instruction, and the expensive per-message attachment call is paid only for items that were
|
|
15
|
+
* actually included by a rule that asked.
|
|
16
|
+
*
|
|
17
|
+
* @module @mj-biz-apps/common-activity-sync
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Turn the deciding rule plus the item's flag into an instruction.
|
|
21
|
+
*
|
|
22
|
+
* NO RULE MEANS NO ATTACHMENTS. An item can be included by the KnownParticipant stage or by a
|
|
23
|
+
* provider-type default policy rather than by a rule, and neither expresses an attachment choice.
|
|
24
|
+
* Defaulting to "fetch" there would pull every attachment in a mailbox on the strength of a decision
|
|
25
|
+
* nobody made about attachments — the expensive, surprising direction to be wrong in.
|
|
26
|
+
*/
|
|
27
|
+
export function AttachmentPolicyFor(rule, item) {
|
|
28
|
+
const wanted = rule?.IncludeAttachments === true;
|
|
29
|
+
// No point paying for a list when the source already said there is nothing to list.
|
|
30
|
+
const fetch = wanted && item?.HasAttachments === true;
|
|
31
|
+
const cap = rule?.MaxAttachmentBytes;
|
|
32
|
+
return {
|
|
33
|
+
Fetch: fetch,
|
|
34
|
+
// 0 and negative are treated as "no cap" rather than "keep nothing": a cap of zero is far
|
|
35
|
+
// more likely to be an unset column than a deliberate instruction to discard everything.
|
|
36
|
+
MaxBytes: typeof cap === 'number' && cap > 0 ? cap : null,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Choose which candidates to keep, and record why the rest were dropped.
|
|
41
|
+
*
|
|
42
|
+
* EVERY EXCLUSION IS REPORTED. Silently dropping a 30MB signed contract because it exceeded a cap is
|
|
43
|
+
* the failure this whole package keeps being written against: the sync reports success, the activity
|
|
44
|
+
* is filed, and the thing someone actually wanted is missing with nothing to show it ever existed.
|
|
45
|
+
*
|
|
46
|
+
* INLINE ATTACHMENTS ARE DROPPED BY DEFAULT. They are body furniture — signature logos, tracking
|
|
47
|
+
* pixels, embedded screenshots already visible in the body text — and `ActivityFile.Kind` has a
|
|
48
|
+
* separate `Body` for the body itself. Keeping them would fill file storage with corporate logos,
|
|
49
|
+
* one copy per email. They are still reported, so a deployment that wants them can see what it is
|
|
50
|
+
* missing rather than wonder.
|
|
51
|
+
*/
|
|
52
|
+
export function SelectAttachments(candidates, policy) {
|
|
53
|
+
const selection = { Keep: [], Skipped: [] };
|
|
54
|
+
if (!policy.Fetch)
|
|
55
|
+
return selection;
|
|
56
|
+
for (const candidate of candidates) {
|
|
57
|
+
if (candidate.IsInline === true) {
|
|
58
|
+
selection.Skipped.push({ Filename: candidate.Filename, Size: candidate.Size, Reason: 'inline' });
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
// A missing or nonsensical size with a cap in force cannot be checked. Keeping it would let
|
|
62
|
+
// exactly the oversize file the cap exists to stop through the one gap in the check.
|
|
63
|
+
if (policy.MaxBytes !== null && !(typeof candidate.Size === 'number' && candidate.Size >= 0)) {
|
|
64
|
+
selection.Skipped.push({ Filename: candidate.Filename, Size: -1, Reason: 'no-size' });
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (policy.MaxBytes !== null && candidate.Size > policy.MaxBytes) {
|
|
68
|
+
selection.Skipped.push({ Filename: candidate.Filename, Size: candidate.Size, Reason: 'too-large' });
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
selection.Keep.push(candidate);
|
|
72
|
+
}
|
|
73
|
+
return selection;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The human-readable account of what was dropped, or null when nothing was.
|
|
77
|
+
*
|
|
78
|
+
* One line per reason rather than per file: a message with forty inline logos should not produce
|
|
79
|
+
* forty issues and bury the one that says a contract was too large.
|
|
80
|
+
*/
|
|
81
|
+
export function AttachmentSkipReport(externalID, selection) {
|
|
82
|
+
if (selection.Skipped.length === 0)
|
|
83
|
+
return null;
|
|
84
|
+
const byReason = new Map();
|
|
85
|
+
for (const s of selection.Skipped) {
|
|
86
|
+
const list = byReason.get(s.Reason) ?? [];
|
|
87
|
+
list.push(s.Filename);
|
|
88
|
+
byReason.set(s.Reason, list);
|
|
89
|
+
}
|
|
90
|
+
const phrases = [];
|
|
91
|
+
const inline = byReason.get('inline');
|
|
92
|
+
if (inline)
|
|
93
|
+
phrases.push(`${inline.length} inline (body images, not filed as attachments)`);
|
|
94
|
+
const large = byReason.get('too-large');
|
|
95
|
+
if (large)
|
|
96
|
+
phrases.push(`${large.length} over the size cap: ${large.join(', ')}`);
|
|
97
|
+
const noSize = byReason.get('no-size');
|
|
98
|
+
if (noSize)
|
|
99
|
+
phrases.push(`${noSize.length} of unknown size, skipped because a cap is in force: ${noSize.join(', ')}`);
|
|
100
|
+
return `Message ${externalID}: attachments not stored — ${phrases.join('; ')}.`;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Where attachment bytes go.
|
|
104
|
+
*
|
|
105
|
+
* A SEAM, NOT AN IMPLEMENTATION, and for the same reason the transport is one: storing a file means
|
|
106
|
+
* MJ's `FileStorageEngine` plus a configured `FileStorageAccount`, and a host that syncs only
|
|
107
|
+
* metadata should need neither. The host that has them registers a sink; one that has not gets a
|
|
108
|
+
* reported refusal rather than activities quietly filed without the attachments their rule asked for.
|
|
109
|
+
*
|
|
110
|
+
* `ActivityFile` holds a `FileID` — a foreign key into `__mj.File` — not the bytes. So an
|
|
111
|
+
* implementation's job is to put the bytes wherever this deployment keeps files, create the `File`
|
|
112
|
+
* row, and hand back its id for linking.
|
|
113
|
+
*/
|
|
114
|
+
/**
|
|
115
|
+
* The sink this host stores attachment bytes through, if it has one.
|
|
116
|
+
*
|
|
117
|
+
* ── WHY A REGISTRY AND NOT ONLY A CONSTRUCTOR ARGUMENT ──────────────────────────────────────────
|
|
118
|
+
*
|
|
119
|
+
* `ActivitySyncEngine` takes a sink as its fourth constructor parameter, and the only production
|
|
120
|
+
* construction is `new ActivitySyncEngine()` with no arguments — in `sync-activities.action.ts`,
|
|
121
|
+
* which an Action framework calls, so there is nowhere for a host to pass one. A host that
|
|
122
|
+
* implemented `ActivityFileSink` exactly as documented had no supported way to hand it over, and
|
|
123
|
+
* `Store()` therefore had no caller on any real path.
|
|
124
|
+
*
|
|
125
|
+
* That is the same shape as the defects this package was just fixed for: a seam described in detail,
|
|
126
|
+
* exported, and reachable only through a door nothing opens. It needed the treatment
|
|
127
|
+
* `RegisterActivityTransportFactory` already gives the transport — a host registers once at
|
|
128
|
+
* bootstrap, and the engine asks.
|
|
129
|
+
*
|
|
130
|
+
* A sink passed to the CONSTRUCTOR still wins, for the same reason it does there: tests and the demo
|
|
131
|
+
* supply their own, and a process-wide registration must not reach in and replace it.
|
|
132
|
+
*/
|
|
133
|
+
let hostFileSink = null;
|
|
134
|
+
/**
|
|
135
|
+
* Register the sink this host stores attachment bytes through. Pass null to clear it.
|
|
136
|
+
*
|
|
137
|
+
* Idempotent and last-call-wins, matching the transport factory: a host that boots twice in one
|
|
138
|
+
* process must not end up with two, and there is no sensible way to merge them.
|
|
139
|
+
*/
|
|
140
|
+
export function RegisterActivityFileSink(sink) {
|
|
141
|
+
hostFileSink = sink;
|
|
142
|
+
}
|
|
143
|
+
/** The registered sink, or null when this host stores no attachment bytes. */
|
|
144
|
+
export function HostActivityFileSink() {
|
|
145
|
+
return hostFileSink;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=attachments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachments.js","sourceRoot":"","sources":["../src/attachments.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export * from './types.js';
|
|
|
11
11
|
export * from './watermark.js';
|
|
12
12
|
export * from './qualification.js';
|
|
13
13
|
export * from './participants.js';
|
|
14
|
+
export * from './attachments.js';
|
|
14
15
|
export * from './run.js';
|
|
15
16
|
export * from './BaseActivitySyncProvider.js';
|
|
16
17
|
export * from './BaseActivitySyncExtension.js';
|
|
@@ -28,5 +29,6 @@ export * from './providers/MSGraphCalendarSyncProvider.js';
|
|
|
28
29
|
export * from './providers/GraphMessageMapper.js';
|
|
29
30
|
export * from './providers/MessageTransport.js';
|
|
30
31
|
export * from './providers/GraphCommunicationTransport.js';
|
|
32
|
+
export * from './providers/GraphCalendarTransport.js';
|
|
31
33
|
export * from './providers/RecordedMessageTransport.js';
|
|
32
34
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,yCAAyC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,uCAAuC,CAAC;AACtD,cAAc,yCAAyC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export * from './types.js';
|
|
|
11
11
|
export * from './watermark.js';
|
|
12
12
|
export * from './qualification.js';
|
|
13
13
|
export * from './participants.js';
|
|
14
|
+
export * from './attachments.js';
|
|
14
15
|
export * from './run.js';
|
|
15
16
|
export * from './BaseActivitySyncProvider.js';
|
|
16
17
|
export * from './BaseActivitySyncExtension.js';
|
|
@@ -28,5 +29,6 @@ export * from './providers/MSGraphCalendarSyncProvider.js';
|
|
|
28
29
|
export * from './providers/GraphMessageMapper.js';
|
|
29
30
|
export * from './providers/MessageTransport.js';
|
|
30
31
|
export * from './providers/GraphCommunicationTransport.js';
|
|
32
|
+
export * from './providers/GraphCalendarTransport.js';
|
|
31
33
|
export * from './providers/RecordedMessageTransport.js';
|
|
32
34
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,yCAAyC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,uCAAuC,CAAC;AACtD,cAAc,yCAAyC,CAAC"}
|
package/dist/participants.d.ts
CHANGED
|
@@ -44,4 +44,34 @@ export declare function DomainOf(address: string): string | null;
|
|
|
44
44
|
* `Unknown` sides with external throughout, per the reasoning on {@link ClassifyParticipants}.
|
|
45
45
|
*/
|
|
46
46
|
export declare function MatchesParticipantScope(scope: ParticipantScope, c: ParticipantComposition): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* What `ActivitySyncRuleSet.InternalDomains` holds, parsed.
|
|
49
|
+
*
|
|
50
|
+
* The column documents itself as "Required for any rule using ParticipantScope" and stores a JSON
|
|
51
|
+
* array, e.g. `["bluecypress.io"]`. Nothing read it until now — the engine passed a hard-coded empty
|
|
52
|
+
* list — so every participant classified as External and every participant rule silently inverted.
|
|
53
|
+
*
|
|
54
|
+
* A parse failure is NOT degraded to an empty list. Empty is the dangerous value here: it makes
|
|
55
|
+
* `HasExternal` match the purely internal chatter it exists to exclude. "Internal" is a property of
|
|
56
|
+
* the deployment, so guessing it is worse than refusing to run.
|
|
57
|
+
*/
|
|
58
|
+
export type InternalDomainsParse = {
|
|
59
|
+
Ok: true;
|
|
60
|
+
Domains: string[];
|
|
61
|
+
} | {
|
|
62
|
+
Ok: false;
|
|
63
|
+
Issue: string;
|
|
64
|
+
};
|
|
65
|
+
/** Parse one rule set's `InternalDomains`. Blank and null are legitimately "none declared". */
|
|
66
|
+
export declare function ParseInternalDomains(raw: string | null | undefined, ruleSetName: string): InternalDomainsParse;
|
|
67
|
+
/**
|
|
68
|
+
* The warning for rules that test participants when no domain list exists.
|
|
69
|
+
*
|
|
70
|
+
* Returns null when there is nothing to say. This is a WARNING rather than a refusal because the run
|
|
71
|
+
* is still meaningful — the rules simply do not filter the way they read, and saying so is the
|
|
72
|
+
* difference between a surprising sync and an inexplicable one.
|
|
73
|
+
*/
|
|
74
|
+
export declare function ParticipantScopeWarning(rules: readonly {
|
|
75
|
+
ParticipantScope?: string | null;
|
|
76
|
+
}[], internalDomains: readonly string[]): string | null;
|
|
47
77
|
//# sourceMappingURL=participants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"participants.d.ts","sourceRoot":"","sources":["../src/participants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GACtB,KAAK,GACL,aAAa,GACb,aAAa,GACb,aAAa,GACb,aAAa,GACb,OAAO,CAAC;AAEd,oFAAoF;AACpF,MAAM,WAAW,sBAAsB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAChC,YAAY,EAAE,SAAS,eAAe,EAAE,EACxC,eAAe,EAAE,SAAS,MAAM,EAAE,GACnC,sBAAsB,CAexB;AAED,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOvD;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,gBAAgB,EAAE,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAgBnG"}
|
|
1
|
+
{"version":3,"file":"participants.d.ts","sourceRoot":"","sources":["../src/participants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GACtB,KAAK,GACL,aAAa,GACb,aAAa,GACb,aAAa,GACb,aAAa,GACb,OAAO,CAAC;AAEd,oFAAoF;AACpF,MAAM,WAAW,sBAAsB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAChC,YAAY,EAAE,SAAS,eAAe,EAAE,EACxC,eAAe,EAAE,SAAS,MAAM,EAAE,GACnC,sBAAsB,CAexB;AAED,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOvD;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,gBAAgB,EAAE,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAgBnG;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElG,+FAA+F;AAC/F,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,oBAAoB,CA2B9G;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACnC,KAAK,EAAE,SAAS;IAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAAE,EACtD,eAAe,EAAE,SAAS,MAAM,EAAE,GACnC,MAAM,GAAG,IAAI,CASf"}
|
package/dist/participants.js
CHANGED
|
@@ -56,4 +56,52 @@ export function MatchesParticipantScope(scope, c) {
|
|
|
56
56
|
return c.Internal > 0 && external > 0;
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
/** Parse one rule set's `InternalDomains`. Blank and null are legitimately "none declared". */
|
|
60
|
+
export function ParseInternalDomains(raw, ruleSetName) {
|
|
61
|
+
const text = (raw ?? '').trim();
|
|
62
|
+
if (!text)
|
|
63
|
+
return { Ok: true, Domains: [] };
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = JSON.parse(text);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return {
|
|
70
|
+
Ok: false,
|
|
71
|
+
Issue: `Rule set "${ruleSetName}" has InternalDomains that is not valid JSON. Expected an array like ["bluecypress.io"].`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (!Array.isArray(parsed)) {
|
|
75
|
+
return {
|
|
76
|
+
Ok: false,
|
|
77
|
+
Issue: `Rule set "${ruleSetName}" has InternalDomains that is not a JSON array. Expected e.g. ["bluecypress.io"].`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const domains = [];
|
|
81
|
+
for (const entry of parsed) {
|
|
82
|
+
// Normalised exactly as ClassifyParticipants normalises what it compares against, so a list
|
|
83
|
+
// written "@Bluecypress.IO" still matches an address at bluecypress.io.
|
|
84
|
+
const d = String(entry ?? '').trim().toLowerCase().replace(/^@/, '');
|
|
85
|
+
if (d && !domains.includes(d))
|
|
86
|
+
domains.push(d);
|
|
87
|
+
}
|
|
88
|
+
return { Ok: true, Domains: domains };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The warning for rules that test participants when no domain list exists.
|
|
92
|
+
*
|
|
93
|
+
* Returns null when there is nothing to say. This is a WARNING rather than a refusal because the run
|
|
94
|
+
* is still meaningful — the rules simply do not filter the way they read, and saying so is the
|
|
95
|
+
* difference between a surprising sync and an inexplicable one.
|
|
96
|
+
*/
|
|
97
|
+
export function ParticipantScopeWarning(rules, internalDomains) {
|
|
98
|
+
if (internalDomains.length > 0)
|
|
99
|
+
return null;
|
|
100
|
+
const scoped = rules.filter((r) => r.ParticipantScope && r.ParticipantScope !== 'Any');
|
|
101
|
+
if (scoped.length === 0)
|
|
102
|
+
return null;
|
|
103
|
+
return (`${scoped.length} rule(s) test ParticipantScope, but no bound rule set defines InternalDomains. ` +
|
|
104
|
+
'Every participant therefore counts as External, so those rules do not filter what they appear ' +
|
|
105
|
+
'to. Set InternalDomains on the rule set.');
|
|
106
|
+
}
|
|
59
107
|
//# sourceMappingURL=participants.js.map
|
package/dist/participants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"participants.js","sourceRoot":"","sources":["../src/participants.ts"],"names":[],"mappings":"AAoCA;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAChC,YAAwC,EACxC,eAAkC;IAElC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9F,MAAM,WAAW,GAA2B,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IAErF,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClB,WAAW,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC;aAAM,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,WAAW,CAAC,QAAQ,EAAE,CAAC;QAC3B,CAAC;aAAM,CAAC;YACJ,WAAW,CAAC,QAAQ,EAAE,CAAC;QAC3B,CAAC;IACL,CAAC;IACD,OAAO,WAAW,CAAC;AACvB,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,QAAQ,CAAC,OAAe;IACpC,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1D,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAuB,EAAE,CAAyB;IACtF,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC;IACxC,QAAQ,KAAK,EAAE,CAAC;QACZ,KAAK,KAAK;YACN,OAAO,IAAI,CAAC;QAChB,KAAK,aAAa;YACd,OAAO,CAAC,CAAC,QAAQ,GAAG,CAAC,IAAI,QAAQ,KAAK,CAAC,CAAC;QAC5C,KAAK,aAAa;YACd,OAAO,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC;QAC5C,KAAK,aAAa;YACd,OAAO,QAAQ,GAAG,CAAC,CAAC;QACxB,KAAK,aAAa;YACd,OAAO,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;QAC1B,KAAK,OAAO;YACR,OAAO,CAAC,CAAC,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC,CAAC;IAC9C,CAAC;AACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"participants.js","sourceRoot":"","sources":["../src/participants.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The live calendar transport: MJ's Communication MS Graph provider, with credentials from MJ's
|
|
3
|
+
* Credentials engine.
|
|
4
|
+
*
|
|
5
|
+
* WRAPS, DOES NOT REIMPLEMENT — and until recently there was nothing to wrap. `MSGraphProvider` could
|
|
6
|
+
* send, read, reply, forward, draft, move, archive, search and subscribe, and had no calendar API at
|
|
7
|
+
* all, while the piece that would have made one possible (`getGraphClient`, which owns token
|
|
8
|
+
* acquisition and the credential-keyed client cache) is private. Building a client here would have
|
|
9
|
+
* forked exactly the behaviour `BaseActivitySyncProvider` says to wrap. So calendar retrieval was
|
|
10
|
+
* added to MJ first and this wraps it.
|
|
11
|
+
*
|
|
12
|
+
* WHY IT READS SourceData RATHER THAN Events. `GetEventsResult.Events` is MJ's normalized shape and
|
|
13
|
+
* is deliberately thin; `MapGraphEvent` in this package is written against Graph's own `event`
|
|
14
|
+
* resource and reads fields the normalized form drops (`iCalUId`, attendee `type`, `bodyPreview`
|
|
15
|
+
* nuances). `SourceData` carries the payload verbatim, which is what `NormalizedItem.Raw` is meant to
|
|
16
|
+
* preserve. Same choice, for the same reason, as the message transport.
|
|
17
|
+
*
|
|
18
|
+
* THE CREDENTIAL IS NEVER HELD. Resolved per fetch and passed straight into the call. `clientSecret`
|
|
19
|
+
* is flagged `isSecret` on the "Azure Service Principal" credential type, so MJ decrypts it at load
|
|
20
|
+
* and it lives only for the duration of the request. Never logged, never cached on this object,
|
|
21
|
+
* never interpolated into an issue string.
|
|
22
|
+
*
|
|
23
|
+
* @module @mj-biz-apps/common-activity-sync
|
|
24
|
+
*/
|
|
25
|
+
import type { BaseCommunicationProvider } from '@memberjunction/communication-types';
|
|
26
|
+
import type { UserInfo } from '@memberjunction/core';
|
|
27
|
+
import type { ActivitySourceQuery, RawBatch } from '../types.js';
|
|
28
|
+
import type { ActivityMessageTransport } from './MessageTransport.js';
|
|
29
|
+
import { type GraphServicePrincipal } from './GraphCommunicationTransport.js';
|
|
30
|
+
/**
|
|
31
|
+
* How far back a FIRST run reaches when the connection has no calendar watermark.
|
|
32
|
+
*
|
|
33
|
+
* A bound is required rather than optional: `/calendarView` refuses a request without one, and the
|
|
34
|
+
* alternative endpoint returns series masters instead of occurrences. Thirty days is a starting
|
|
35
|
+
* point, not a rule — it is a constructor argument, and a run that falls back to it says so in its
|
|
36
|
+
* issues rather than letting an operator believe the whole calendar was read.
|
|
37
|
+
*/
|
|
38
|
+
export declare const DEFAULT_FIRST_RUN_LOOKBACK_DAYS = 30;
|
|
39
|
+
/**
|
|
40
|
+
* How far FORWARD a read reaches.
|
|
41
|
+
*
|
|
42
|
+
* Not zero, deliberately. `Activity.Status` includes `Scheduled`, so a meeting that has not happened
|
|
43
|
+
* yet is a thing this schema models, and a calendar sync that only ever looked backwards could not
|
|
44
|
+
* produce one.
|
|
45
|
+
*/
|
|
46
|
+
export declare const DEFAULT_FORWARD_HORIZON_DAYS = 30;
|
|
47
|
+
/** The slice of MJ's communication provider this uses. Structural, to avoid a hard runtime import. */
|
|
48
|
+
export interface GraphEventReader {
|
|
49
|
+
GetEvents(params: {
|
|
50
|
+
Identifier?: string;
|
|
51
|
+
NumEvents: number;
|
|
52
|
+
StartDateTime?: Date;
|
|
53
|
+
EndDateTime?: Date;
|
|
54
|
+
IncludeCancelled?: boolean;
|
|
55
|
+
ContextData?: Record<string, unknown>;
|
|
56
|
+
}, credentials?: unknown): Promise<{
|
|
57
|
+
Success: boolean;
|
|
58
|
+
Events?: unknown[];
|
|
59
|
+
SourceData?: unknown[];
|
|
60
|
+
ErrorMessage?: string;
|
|
61
|
+
RecurrenceExpanded?: boolean;
|
|
62
|
+
}>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* COMPILE-TIME PROOF THAT THE STRUCTURAL TYPE ABOVE IS NOT FICTION.
|
|
66
|
+
*
|
|
67
|
+
* Declared structurally so this package takes no runtime dependency on the Communication engine. The
|
|
68
|
+
* cost of that is that nothing checks the shape against MJ: the only value ever assigned to it in
|
|
69
|
+
* tests is a stub, and a stub cast with `as unknown as` bypasses checking entirely. Drift in MJ's
|
|
70
|
+
* `GetEvents` would then surface on the FIRST LIVE CALL and nowhere earlier.
|
|
71
|
+
*
|
|
72
|
+
* So the compiler checks it instead. `@memberjunction/communication-types` is already a declared peer
|
|
73
|
+
* and this is a TYPE-only import, so no runtime dependency is added and these lines emit no
|
|
74
|
+
* JavaScript. If MJ changes the signature, the BUILD breaks here rather than a live sync.
|
|
75
|
+
*/
|
|
76
|
+
type AssertTrue<T extends true> = T;
|
|
77
|
+
export type GraphEventReaderMatchesMJ = AssertTrue<BaseCommunicationProvider extends GraphEventReader ? true : false>;
|
|
78
|
+
/** How the two collaborators are obtained. Injected, so neither engine is a runtime dependency. */
|
|
79
|
+
export interface GraphCalendarTransportDeps {
|
|
80
|
+
ResolveCredential(): Promise<GraphServicePrincipal>;
|
|
81
|
+
ResolveProvider(): Promise<GraphEventReader>;
|
|
82
|
+
ContextUser?: UserInfo;
|
|
83
|
+
}
|
|
84
|
+
export declare class GraphCalendarTransport implements ActivityMessageTransport {
|
|
85
|
+
private readonly Deps;
|
|
86
|
+
private readonly LookbackDays;
|
|
87
|
+
private readonly ForwardDays;
|
|
88
|
+
/** Injectable so a test can pin the window without freezing global time. */
|
|
89
|
+
private readonly Now;
|
|
90
|
+
readonly Describe = "Microsoft Graph calendar (live, via MJ Communication)";
|
|
91
|
+
readonly IsLive = true;
|
|
92
|
+
constructor(Deps: GraphCalendarTransportDeps, LookbackDays?: number, ForwardDays?: number,
|
|
93
|
+
/** Injectable so a test can pin the window without freezing global time. */
|
|
94
|
+
Now?: () => Date);
|
|
95
|
+
Fetch(query: ActivitySourceQuery): Promise<RawBatch>;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Build the deps from MJ's engines, resolving both lazily.
|
|
99
|
+
*
|
|
100
|
+
* Separate from the class so the class stays testable with neither engine loaded — the tests inject
|
|
101
|
+
* their own deps, which is also how a recorded run avoids dragging the Credentials engine into a
|
|
102
|
+
* replay that has no credential to resolve.
|
|
103
|
+
*/
|
|
104
|
+
export declare function MJGraphCalendarTransportDeps(args: {
|
|
105
|
+
CredentialName: string;
|
|
106
|
+
ContextUser?: UserInfo;
|
|
107
|
+
GetCredentialEngine: () => {
|
|
108
|
+
getCredential<T>(name: string, options?: Record<string, unknown>): Promise<{
|
|
109
|
+
values: T;
|
|
110
|
+
}>;
|
|
111
|
+
};
|
|
112
|
+
GetCommunicationProvider: (name: string) => GraphEventReader | null | undefined;
|
|
113
|
+
}): GraphCalendarTransportDeps;
|
|
114
|
+
export {};
|
|
115
|
+
//# sourceMappingURL=GraphCalendarTransport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphCalendarTransport.d.ts","sourceRoot":"","sources":["../../src/providers/GraphCalendarTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAGtE,OAAO,EAGH,KAAK,qBAAqB,EAC7B,MAAM,kCAAkC,CAAC;AAE1C;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,KAAK,CAAC;AAElD;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC7B,SAAS,CACL,MAAM,EAAE;QACJ,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,CAAC,EAAE,IAAI,CAAC;QACrB,WAAW,CAAC,EAAE,IAAI,CAAC;QACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACzC,EACD,WAAW,CAAC,EAAE,OAAO,GACtB,OAAO,CAAC;QACP,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;QACnB,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;QACvB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;KAChC,CAAC,CAAC;CACN;AAED;;;;;;;;;;;GAWG;AACH,KAAK,UAAU,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;AACpC,MAAM,MAAM,yBAAyB,GAAG,UAAU,CAC9C,yBAAyB,SAAS,gBAAgB,GAAG,IAAI,GAAG,KAAK,CACpE,CAAC;AAEF,mGAAmG;AACnG,MAAM,WAAW,0BAA0B;IACvC,iBAAiB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACpD,eAAe,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC7C,WAAW,CAAC,EAAE,QAAQ,CAAC;CAC1B;AAED,qBAAa,sBAAuB,YAAW,wBAAwB;IAK/D,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,4EAA4E;IAC5E,OAAO,CAAC,QAAQ,CAAC,GAAG;IARxB,SAAgB,QAAQ,2DAA2D;IACnF,SAAgB,MAAM,QAAQ;gBAGT,IAAI,EAAE,0BAA0B,EAChC,YAAY,GAAE,MAAwC,EACtD,WAAW,GAAE,MAAqC;IACnE,4EAA4E;IAC3D,GAAG,GAAE,MAAM,IAAuB;IAG1C,KAAK,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC;CAkGpE;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,mBAAmB,EAAE,MAAM;QACvB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;YAAE,MAAM,EAAE,CAAC,CAAA;SAAE,CAAC,CAAC;KAC7F,CAAC;IACF,wBAAwB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,GAAG,SAAS,CAAC;CACnF,GAAG,0BAA0B,CAyB7B"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Reused, not redeclared: mail and calendar reach the SAME MJ provider under the same registration
|
|
2
|
+
// name and resolve the SAME credential type. Two copies could drift into naming different things.
|
|
3
|
+
import { GRAPH_COMMUNICATION_PROVIDER, GRAPH_CREDENTIAL_TYPE, } from './GraphCommunicationTransport.js';
|
|
4
|
+
/**
|
|
5
|
+
* How far back a FIRST run reaches when the connection has no calendar watermark.
|
|
6
|
+
*
|
|
7
|
+
* A bound is required rather than optional: `/calendarView` refuses a request without one, and the
|
|
8
|
+
* alternative endpoint returns series masters instead of occurrences. Thirty days is a starting
|
|
9
|
+
* point, not a rule — it is a constructor argument, and a run that falls back to it says so in its
|
|
10
|
+
* issues rather than letting an operator believe the whole calendar was read.
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_FIRST_RUN_LOOKBACK_DAYS = 30;
|
|
13
|
+
/**
|
|
14
|
+
* How far FORWARD a read reaches.
|
|
15
|
+
*
|
|
16
|
+
* Not zero, deliberately. `Activity.Status` includes `Scheduled`, so a meeting that has not happened
|
|
17
|
+
* yet is a thing this schema models, and a calendar sync that only ever looked backwards could not
|
|
18
|
+
* produce one.
|
|
19
|
+
*/
|
|
20
|
+
export const DEFAULT_FORWARD_HORIZON_DAYS = 30;
|
|
21
|
+
export class GraphCalendarTransport {
|
|
22
|
+
constructor(Deps, LookbackDays = DEFAULT_FIRST_RUN_LOOKBACK_DAYS, ForwardDays = DEFAULT_FORWARD_HORIZON_DAYS,
|
|
23
|
+
/** Injectable so a test can pin the window without freezing global time. */
|
|
24
|
+
Now = () => new Date()) {
|
|
25
|
+
this.Deps = Deps;
|
|
26
|
+
this.LookbackDays = LookbackDays;
|
|
27
|
+
this.ForwardDays = ForwardDays;
|
|
28
|
+
this.Now = Now;
|
|
29
|
+
this.Describe = 'Microsoft Graph calendar (live, via MJ Communication)';
|
|
30
|
+
this.IsLive = true;
|
|
31
|
+
}
|
|
32
|
+
async Fetch(query) {
|
|
33
|
+
const issues = [];
|
|
34
|
+
const credential = await this.Deps.ResolveCredential();
|
|
35
|
+
const missing = ['tenantId', 'clientId', 'clientSecret'].filter((k) => !String(credential?.[k] ?? '').trim());
|
|
36
|
+
if (missing.length > 0) {
|
|
37
|
+
// Field NAMES are reported, never values. The names are what an operator needs in order
|
|
38
|
+
// to fix it, and one of the values is a secret.
|
|
39
|
+
throw new Error(`The "${GRAPH_CREDENTIAL_TYPE}" credential is missing required field(s): ${missing.join(', ')}. ` +
|
|
40
|
+
'Complete it in MJ before enabling live fetch.');
|
|
41
|
+
}
|
|
42
|
+
const now = this.Now();
|
|
43
|
+
/**
|
|
44
|
+
* THE WINDOW IS ROLLING, AND DELIBERATELY IGNORES THE WATERMARK.
|
|
45
|
+
*
|
|
46
|
+
* `WatermarkBasisForKind('Calendar')` is `ObservationTime` — for a calendar the watermark
|
|
47
|
+
* records WHEN WE LAST LOOKED, not how far through the data we got. That basis is correct and
|
|
48
|
+
* the reason is in its own docblock: a meeting can be dated in the future, so an item-time
|
|
49
|
+
* watermark would skip straight past anything scheduled earlier than the newest thing seen.
|
|
50
|
+
*
|
|
51
|
+
* This used to pass that same value as `StartDateTime`, which filters on the EVENT'S OWN time.
|
|
52
|
+
* The two are different quantities and using one as the other loses data silently: run 1 at T0
|
|
53
|
+
* sets the watermark to T0, and a meeting that took place last week but is added to the
|
|
54
|
+
* calendar tomorrow starts before T0, so it falls outside run 2's window — and outside every
|
|
55
|
+
* later window, since each one starts later still. It is never read, on any run, with no issue
|
|
56
|
+
* raised and `Success = true`. Retroactive additions and back-dated invitations are ordinary
|
|
57
|
+
* calendar behaviour, not an edge case.
|
|
58
|
+
*
|
|
59
|
+
* So the window is always `[now - LookbackDays, now + ForwardDays]` and the same events are
|
|
60
|
+
* re-read every run. That is not waste: de-duplication is by `ExternalID` in the writer, so a
|
|
61
|
+
* re-read costs one lookup and writes nothing, while a missed event is unrecoverable.
|
|
62
|
+
*/
|
|
63
|
+
const start = new Date(now.getTime() - this.LookbackDays * 86_400_000);
|
|
64
|
+
const end = new Date(now.getTime() + this.ForwardDays * 86_400_000);
|
|
65
|
+
if (!query.Since) {
|
|
66
|
+
// Said out loud on the FIRST run only, because that is when someone expects full history.
|
|
67
|
+
// On later runs the same bound applies and saying so every time would be noise.
|
|
68
|
+
issues.push(`First calendar run for ${query.Mailbox}: the window starts ${this.LookbackDays} days ` +
|
|
69
|
+
`back (${start.toISOString()}). Anything older was not read.`);
|
|
70
|
+
}
|
|
71
|
+
const provider = await this.Deps.ResolveProvider();
|
|
72
|
+
const result = await provider.GetEvents({
|
|
73
|
+
Identifier: query.Mailbox,
|
|
74
|
+
NumEvents: query.Limit,
|
|
75
|
+
StartDateTime: start,
|
|
76
|
+
EndDateTime: end,
|
|
77
|
+
// A cancellation is a real thing that happened to a meeting somebody attended, and
|
|
78
|
+
// `MapGraphEvent` already carries `Cancelled` through to the Activity.
|
|
79
|
+
IncludeCancelled: true,
|
|
80
|
+
},
|
|
81
|
+
// Same MJ requirements as the message path, for the same reasons — see
|
|
82
|
+
// GraphCommunicationTransport: accountEmail is validated before any request and the
|
|
83
|
+
// credential type does not carry it, and disableEnvironmentFallback stops a gap being
|
|
84
|
+
// filled from AZURE_* on the host, which is the difference between failing on a missing
|
|
85
|
+
// field and reading a calendar nobody asked for.
|
|
86
|
+
{ ...credential, accountEmail: query.Mailbox, disableEnvironmentFallback: true });
|
|
87
|
+
if (!result?.Success) {
|
|
88
|
+
throw new Error(result?.ErrorMessage?.trim() || `Graph returned no calendar result for mailbox "${query.Mailbox}".`);
|
|
89
|
+
}
|
|
90
|
+
// BOTH BOUNDS WERE SENT, so MJ should have expanded recurrence. If it says otherwise the
|
|
91
|
+
// payloads are series MASTERS, and one row would be filed for a weekly meeting at whatever
|
|
92
|
+
// date the series began. That is wrong in a way no downstream check would catch, because a
|
|
93
|
+
// master and an occurrence look alike.
|
|
94
|
+
if (result.RecurrenceExpanded === false) {
|
|
95
|
+
issues.push('Graph did not expand recurring series despite a bounded window, so repeating meetings ' +
|
|
96
|
+
'are represented by their series master rather than by occurrences. Times for those ' +
|
|
97
|
+
'will be the start of the series.');
|
|
98
|
+
}
|
|
99
|
+
const payloads = (result.SourceData ?? []);
|
|
100
|
+
const capped = payloads.length >= query.Limit;
|
|
101
|
+
if (capped) {
|
|
102
|
+
issues.push(`The calendar read hit its limit of ${query.Limit} events for ${query.Mailbox}; ` +
|
|
103
|
+
'the window may hold more than this pass returned.');
|
|
104
|
+
}
|
|
105
|
+
return { Payloads: payloads, Issues: issues, Capped: capped };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Build the deps from MJ's engines, resolving both lazily.
|
|
110
|
+
*
|
|
111
|
+
* Separate from the class so the class stays testable with neither engine loaded — the tests inject
|
|
112
|
+
* their own deps, which is also how a recorded run avoids dragging the Credentials engine into a
|
|
113
|
+
* replay that has no credential to resolve.
|
|
114
|
+
*/
|
|
115
|
+
export function MJGraphCalendarTransportDeps(args) {
|
|
116
|
+
return {
|
|
117
|
+
ContextUser: args.ContextUser,
|
|
118
|
+
async ResolveCredential() {
|
|
119
|
+
const resolved = await args
|
|
120
|
+
.GetCredentialEngine()
|
|
121
|
+
.getCredential(args.CredentialName, { contextUser: args.ContextUser });
|
|
122
|
+
if (!resolved?.values) {
|
|
123
|
+
throw new Error(`Credential "${args.CredentialName}" resolved with no values.`);
|
|
124
|
+
}
|
|
125
|
+
return resolved.values;
|
|
126
|
+
},
|
|
127
|
+
async ResolveProvider() {
|
|
128
|
+
const provider = args.GetCommunicationProvider(GRAPH_COMMUNICATION_PROVIDER);
|
|
129
|
+
if (!provider) {
|
|
130
|
+
// A REGISTRATION problem, not a credential one. Saying which keeps an operator from
|
|
131
|
+
// hunting for a secret that is present and correct.
|
|
132
|
+
throw new Error(`MJ communication provider "${GRAPH_COMMUNICATION_PROVIDER}" is not registered. ` +
|
|
133
|
+
'Ensure @memberjunction/communication-ms-graph is loaded in this host.');
|
|
134
|
+
}
|
|
135
|
+
return provider;
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=GraphCalendarTransport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphCalendarTransport.js","sourceRoot":"","sources":["../../src/providers/GraphCalendarTransport.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GraphCommunicationTransport.d.ts","sourceRoot":"","sources":["../../src/providers/GraphCommunicationTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEtE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,4BAA4B,CAAC;AAE/D,qGAAqG;AACrG,eAAO,MAAM,4BAA4B,oBAAoB,CAAC;AAE9D,8DAA8D;AAC9D,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,sGAAsG;AACtG,MAAM,WAAW,kBAAkB;IAC/B,WAAW,CACP,MAAM,EAAE;QACJ,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACzC,EACD,WAAW,CAAC,EAAE,OAAO,GACtB,OAAO,CAAC;QACP,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;QACvB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,cAAc,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC,CAAC;CACN;AAED;;;;;;;;;;;;;GAaG;AACH,KAAK,UAAU,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;AACpC,MAAM,MAAM,2BAA2B,GAAG,UAAU,CAChD,yBAAyB,SAAS,kBAAkB,GAAG,IAAI,GAAG,KAAK,CACtE,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IAC/B,iBAAiB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACpD,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC/C,WAAW,CAAC,EAAE,QAAQ,CAAC;CAC1B;AAED,qBAAa,2BAA4B,YAAW,wBAAwB;IAIrD,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHxC,SAAgB,QAAQ,kDAAkD;IAC1E,SAAgB,MAAM,QAAQ;gBAEM,IAAI,EAAE,kBAAkB;IAE/C,KAAK,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"GraphCommunicationTransport.d.ts","sourceRoot":"","sources":["../../src/providers/GraphCommunicationTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEtE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,4BAA4B,CAAC;AAE/D,qGAAqG;AACrG,eAAO,MAAM,4BAA4B,oBAAoB,CAAC;AAE9D,8DAA8D;AAC9D,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,sGAAsG;AACtG,MAAM,WAAW,kBAAkB;IAC/B,WAAW,CACP,MAAM,EAAE;QACJ,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACzC,EACD,WAAW,CAAC,EAAE,OAAO,GACtB,OAAO,CAAC;QACP,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;QACvB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,cAAc,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC,CAAC;CACN;AAED;;;;;;;;;;;;;GAaG;AACH,KAAK,UAAU,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;AACpC,MAAM,MAAM,2BAA2B,GAAG,UAAU,CAChD,yBAAyB,SAAS,kBAAkB,GAAG,IAAI,GAAG,KAAK,CACtE,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IAC/B,iBAAiB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACpD,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC/C,WAAW,CAAC,EAAE,QAAQ,CAAC;CAC1B;AAED,qBAAa,2BAA4B,YAAW,wBAAwB;IAIrD,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHxC,SAAgB,QAAQ,kDAAkD;IAC1E,SAAgB,MAAM,QAAQ;gBAEM,IAAI,EAAE,kBAAkB;IAE/C,KAAK,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC;CAkFpE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,mBAAmB,EAAE,MAAM;QACvB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;YAAE,MAAM,EAAE,CAAC,CAAA;SAAE,CAAC,CAAC;KAC7F,CAAC;IACF,wBAAwB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,kBAAkB,GAAG,IAAI,GAAG,SAAS,CAAC;CACrF,GAAG,kBAAkB,CAyBrB"}
|
|
@@ -53,11 +53,25 @@ export class GraphCommunicationTransport {
|
|
|
53
53
|
throw new Error(result?.ErrorMessage?.trim() || `Graph returned no result for mailbox "${query.Mailbox}".`);
|
|
54
54
|
}
|
|
55
55
|
const payloads = (result.SourceData ?? []);
|
|
56
|
-
|
|
56
|
+
// A FULL PAGE MEANS THERE MAY BE MORE, WATERMARK OR NOT.
|
|
57
|
+
//
|
|
58
|
+
// This used to require `query.Since`, which left the FIRST run — the one most likely to
|
|
59
|
+
// overflow a page — unprotected. No date bound is sent, so Graph returns the newest `Limit`
|
|
60
|
+
// messages; `BaseActivitySyncProvider` then computes a high watermark from them and the next
|
|
61
|
+
// run asks for everything AFTER the newest. Every message older than that first page is
|
|
62
|
+
// skipped permanently, and the run reports Success with no issue. A mailbox with more history
|
|
63
|
+
// than one page silently loses all of it.
|
|
64
|
+
//
|
|
65
|
+
// `Capped` also withholds the watermark upstream, which is what actually prevents the loss;
|
|
66
|
+
// the issue below is how anyone finds out a re-run is needed.
|
|
67
|
+
const capped = payloads.length >= query.Limit;
|
|
57
68
|
if (capped) {
|
|
58
|
-
|
|
59
|
-
'so older items may remain unread
|
|
60
|
-
'
|
|
69
|
+
const context = query.Since
|
|
70
|
+
? 'while a watermark was set, so older items may remain unread'
|
|
71
|
+
: 'on a FIRST run with no watermark, so anything older than this page has not been read';
|
|
72
|
+
issues.push(`Fetched the maximum of ${query.Limit} message(s) for "${query.Mailbox}" ${context}. ` +
|
|
73
|
+
'The watermark is being withheld so nothing is skipped — re-run to continue, or raise ' +
|
|
74
|
+
'the limit. A server-side date bound (MemberJunction/MJ#4123) removes this entirely.');
|
|
61
75
|
}
|
|
62
76
|
// `Capped` is what actually protects the mail; the issue above only TELLS someone. Without
|
|
63
77
|
// it the watermark advanced to the newest item in a truncated batch and the remainder was
|