@agent-native/scheduling 0.2.52 → 0.2.53-nightly-20261105200106
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/server/availability-engine.d.ts +24 -0
- package/dist/server/availability-engine.d.ts.map +1 -1
- package/dist/server/availability-engine.js +73 -5
- package/dist/server/availability-engine.js.map +1 -1
- package/dist/server/providers/errors.d.ts +22 -0
- package/dist/server/providers/errors.d.ts.map +1 -0
- package/dist/server/providers/errors.js +53 -0
- package/dist/server/providers/errors.js.map +1 -0
- package/dist/server/providers/google-calendar.d.ts +0 -11
- package/dist/server/providers/google-calendar.d.ts.map +1 -1
- package/dist/server/providers/google-calendar.js +57 -3
- package/dist/server/providers/google-calendar.js.map +1 -1
- package/dist/server/providers/index.d.ts +1 -0
- package/dist/server/providers/index.d.ts.map +1 -1
- package/dist/server/providers/index.js +1 -0
- package/dist/server/providers/index.js.map +1 -1
- package/dist/server/providers/office365.d.ts.map +1 -1
- package/dist/server/providers/office365.js +87 -25
- package/dist/server/providers/office365.js.map +1 -1
- package/docs/llms-full.txt +29 -8
- package/docs/providers.md +10 -0
- package/docs/skills/integrations/SKILL.md +19 -8
- package/package.json +4 -4
- package/src/server/availability-engine.test.ts +459 -23
- package/src/server/availability-engine.ts +110 -10
- package/src/server/providers/calendar-busy.test.ts +417 -0
- package/src/server/providers/errors.ts +66 -0
- package/src/server/providers/google-calendar.ts +71 -4
- package/src/server/providers/index.ts +1 -0
- package/src/server/providers/office365.ts +111 -33
|
@@ -1,8 +1,32 @@
|
|
|
1
|
+
import { ActionContractError } from "@agent-native/core/action";
|
|
1
2
|
import type { EventType, BusyInterval, Slot } from "../shared/index.js";
|
|
2
3
|
export declare class SlotConflictError extends Error {
|
|
3
4
|
statusCode: number;
|
|
4
5
|
constructor(message?: string);
|
|
5
6
|
}
|
|
7
|
+
export type CalendarBusyFailureReason = "lookup_failed" | "provider_not_registered" | "credential_invalid";
|
|
8
|
+
export interface CalendarBusyFailure {
|
|
9
|
+
credentialId: string;
|
|
10
|
+
provider: string;
|
|
11
|
+
providerLabel: string;
|
|
12
|
+
calendarExternalIds: string[];
|
|
13
|
+
reason: CalendarBusyFailureReason;
|
|
14
|
+
cause?: string;
|
|
15
|
+
/** Set when the provider throttled the lookup (rate or quota limit). */
|
|
16
|
+
throttled?: true;
|
|
17
|
+
/** Set when a throttling provider said when to retry. */
|
|
18
|
+
retryAfterSeconds?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A selected calendar could not be read, so its busy times are unknown.
|
|
22
|
+
* `details` is echoed to callers (including public booking pages), so it
|
|
23
|
+
* carries only provider names and reasons; the raw provider error stays in
|
|
24
|
+
* `failures` on the server.
|
|
25
|
+
*/
|
|
26
|
+
export declare class CalendarAvailabilityUnavailableError extends ActionContractError {
|
|
27
|
+
readonly failures: CalendarBusyFailure[];
|
|
28
|
+
constructor(failures: CalendarBusyFailure[]);
|
|
29
|
+
}
|
|
6
30
|
export interface AssertSlotAvailableInput {
|
|
7
31
|
hostEmail: string;
|
|
8
32
|
startTime: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"availability-engine.d.ts","sourceRoot":"","sources":["../../src/server/availability-engine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"availability-engine.d.ts","sourceRoot":"","sources":["../../src/server/availability-engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAQhE,OAAO,KAAK,EACV,SAAS,EAET,YAAY,EACZ,IAAI,EACL,MAAM,oBAAoB,CAAC;AAW5B,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,UAAU,SAAO;IACjB,YAAY,OAAO,SAA0C,EAG5D;CACF;AAED,MAAM,MAAM,yBAAyB,GACjC,eAAe,GACf,yBAAyB,GACzB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,MAAM,EAAE,yBAAyB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,yDAAyD;IACzD,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;GAKG;AACH,qBAAa,oCAAqC,SAAQ,mBAAmB;IAC3E,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAEzC,YAAY,QAAQ,EAAE,mBAAmB,EAAE,EA8B1C;CACF;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,IAAI,CAAC;IACjB,QAAQ,EAAE,IAAI,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAyC7E;AAmBD,wBAAsB,aAAa,CAAC,KAAK,EAAE;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,IAAI,CAAC;IACjB,QAAQ,EAAE,IAAI,CAAC;CAChB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAyH1B"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { ActionContractError } from "@agent-native/core/action";
|
|
1
2
|
import { eq, gte, lt, and, inArray } from "drizzle-orm";
|
|
2
3
|
import { expandSlotForConflictCheck } from "../core/buffers.js";
|
|
3
4
|
import { hasConflict } from "../core/conflicts.js";
|
|
4
5
|
import { bucketKeysForSlot } from "../core/limits.js";
|
|
5
6
|
import { computeAvailableSlots } from "../core/slots.js";
|
|
6
7
|
import { getSchedulingContext } from "./context.js";
|
|
8
|
+
import { isCalendarCredentialInvalidError, isCalendarLookupRateLimitedError, } from "./providers/errors.js";
|
|
7
9
|
import { getCalendarProvider } from "./providers/registry.js";
|
|
8
10
|
import { getScheduleById } from "./schedules-repo.js";
|
|
9
11
|
const MAX_CALENDAR_BUSY_CONCURRENCY = 4;
|
|
@@ -14,6 +16,41 @@ export class SlotConflictError extends Error {
|
|
|
14
16
|
this.name = "SlotConflictError";
|
|
15
17
|
}
|
|
16
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* A selected calendar could not be read, so its busy times are unknown.
|
|
21
|
+
* `details` is echoed to callers (including public booking pages), so it
|
|
22
|
+
* carries only provider names and reasons; the raw provider error stays in
|
|
23
|
+
* `failures` on the server.
|
|
24
|
+
*/
|
|
25
|
+
export class CalendarAvailabilityUnavailableError extends ActionContractError {
|
|
26
|
+
failures;
|
|
27
|
+
constructor(failures) {
|
|
28
|
+
const labels = Array.from(new Set(failures.map((f) => f.providerLabel)));
|
|
29
|
+
const retryAfters = failures.flatMap((f) => f.retryAfterSeconds === undefined ? [] : [f.retryAfterSeconds]);
|
|
30
|
+
super(`Couldn't check ${labels.join(", ")}, so availability can't be confirmed. Try again shortly.`, {
|
|
31
|
+
errorCode: "calendar_availability_unavailable",
|
|
32
|
+
// Purely throttled lookups are a 429; the action route sends
|
|
33
|
+
// Retry-After from details.retryAfterSeconds only on a 429. Any other
|
|
34
|
+
// failure in the mix makes it a 503.
|
|
35
|
+
statusCode: failures.every((f) => f.throttled) ? 429 : 503,
|
|
36
|
+
details: {
|
|
37
|
+
calendars: failures.map((f) => ({
|
|
38
|
+
provider: f.provider,
|
|
39
|
+
providerLabel: f.providerLabel,
|
|
40
|
+
reason: f.reason,
|
|
41
|
+
...(f.retryAfterSeconds === undefined
|
|
42
|
+
? {}
|
|
43
|
+
: { retryAfterSeconds: f.retryAfterSeconds }),
|
|
44
|
+
})),
|
|
45
|
+
...(retryAfters.length === 0
|
|
46
|
+
? {}
|
|
47
|
+
: { retryAfterSeconds: Math.max(...retryAfters) }),
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
this.name = "CalendarAvailabilityUnavailableError";
|
|
51
|
+
this.failures = failures;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
17
54
|
export async function assertSlotAvailable(input) {
|
|
18
55
|
const expanded = expandSlotForConflictCheck(new Date(input.startTime), new Date(input.endTime), input.beforeEventBuffer ?? 0, input.afterEventBuffer ?? 0);
|
|
19
56
|
const busy = await aggregateBusy({
|
|
@@ -91,10 +128,12 @@ export async function aggregateBusy(input) {
|
|
|
91
128
|
source: `booking:${b.uid}`,
|
|
92
129
|
});
|
|
93
130
|
}
|
|
131
|
+
// Invalid credentials are read too: one whose calendars are still selected
|
|
132
|
+
// is a calendar we can't check, not one that has no events.
|
|
94
133
|
const creds = await db
|
|
95
134
|
.select()
|
|
96
135
|
.from(schema.schedulingCredentials)
|
|
97
|
-
.where(
|
|
136
|
+
.where(eq(schema.schedulingCredentials.userEmail, input.userEmail));
|
|
98
137
|
if (creds.length === 0)
|
|
99
138
|
return busy;
|
|
100
139
|
const selected = await db
|
|
@@ -111,6 +150,9 @@ export async function aggregateBusy(input) {
|
|
|
111
150
|
externalIdsByCredential.set(calendar.credentialId, externalIds);
|
|
112
151
|
}
|
|
113
152
|
const providerBusy = Array.from({ length: creds.length }, () => []);
|
|
153
|
+
const failures = Array.from({
|
|
154
|
+
length: creds.length,
|
|
155
|
+
});
|
|
114
156
|
let nextCredentialIndex = 0;
|
|
115
157
|
async function worker() {
|
|
116
158
|
while (nextCredentialIndex < creds.length) {
|
|
@@ -120,8 +162,22 @@ export async function aggregateBusy(input) {
|
|
|
120
162
|
if (!externalIds?.length)
|
|
121
163
|
continue;
|
|
122
164
|
const provider = getCalendarProvider(cred.type);
|
|
123
|
-
|
|
165
|
+
const failure = (reason, cause) => ({
|
|
166
|
+
credentialId: cred.id,
|
|
167
|
+
provider: cred.type,
|
|
168
|
+
providerLabel: provider?.label ?? cred.type,
|
|
169
|
+
calendarExternalIds: externalIds,
|
|
170
|
+
reason,
|
|
171
|
+
...(cause === undefined ? {} : { cause }),
|
|
172
|
+
});
|
|
173
|
+
if (!provider) {
|
|
174
|
+
failures[credentialIndex] = failure("provider_not_registered");
|
|
124
175
|
continue;
|
|
176
|
+
}
|
|
177
|
+
if (cred.invalid) {
|
|
178
|
+
failures[credentialIndex] = failure("credential_invalid");
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
125
181
|
try {
|
|
126
182
|
providerBusy[credentialIndex] = await provider.getBusy({
|
|
127
183
|
credentialId: cred.id,
|
|
@@ -130,14 +186,26 @@ export async function aggregateBusy(input) {
|
|
|
130
186
|
end: input.rangeEnd,
|
|
131
187
|
});
|
|
132
188
|
}
|
|
133
|
-
catch {
|
|
134
|
-
|
|
135
|
-
|
|
189
|
+
catch (error) {
|
|
190
|
+
const lookupFailure = failure(isCalendarCredentialInvalidError(error)
|
|
191
|
+
? "credential_invalid"
|
|
192
|
+
: "lookup_failed", error instanceof Error ? error.message : String(error));
|
|
193
|
+
if (isCalendarLookupRateLimitedError(error)) {
|
|
194
|
+
lookupFailure.throttled = true;
|
|
195
|
+
if (error.retryAfterSeconds !== undefined) {
|
|
196
|
+
lookupFailure.retryAfterSeconds = error.retryAfterSeconds;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
failures[credentialIndex] = lookupFailure;
|
|
136
200
|
}
|
|
137
201
|
}
|
|
138
202
|
}
|
|
139
203
|
const workerCount = Math.min(MAX_CALENDAR_BUSY_CONCURRENCY, creds.length);
|
|
140
204
|
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
205
|
+
const unreadable = failures.filter((f) => f !== undefined);
|
|
206
|
+
if (unreadable.length > 0) {
|
|
207
|
+
throw new CalendarAvailabilityUnavailableError(unreadable);
|
|
208
|
+
}
|
|
141
209
|
busy.push(...providerBusy.flat());
|
|
142
210
|
return busy;
|
|
143
211
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"availability-engine.js","sourceRoot":"","sources":["../../src/server/availability-engine.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"availability-engine.js","sourceRoot":"","sources":["../../src/server/availability-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by a calendar provider when the provider rejected the credential
|
|
3
|
+
* (401/403), so the host has to reconnect rather than retry.
|
|
4
|
+
*/
|
|
5
|
+
export declare class CalendarCredentialInvalidError extends Error {
|
|
6
|
+
readonly calendarCredentialInvalid = true;
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Thrown by a calendar provider when it throttled the request (rate or quota
|
|
11
|
+
* limit). The credential is still good; the lookup can be retried.
|
|
12
|
+
*/
|
|
13
|
+
export declare class CalendarLookupRateLimitedError extends Error {
|
|
14
|
+
readonly calendarLookupRateLimited = true;
|
|
15
|
+
readonly retryAfterSeconds?: number;
|
|
16
|
+
constructor(message: string, retryAfterSeconds?: number);
|
|
17
|
+
}
|
|
18
|
+
export declare function isCalendarLookupRateLimitedError(error: unknown): error is CalendarLookupRateLimitedError;
|
|
19
|
+
/** Seconds from a `Retry-After` header (delta-seconds or HTTP date). */
|
|
20
|
+
export declare function parseRetryAfterSeconds(header: string | null, now?: number): number | undefined;
|
|
21
|
+
export declare function isCalendarCredentialInvalidError(error: unknown): error is CalendarCredentialInvalidError;
|
|
22
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/server/providers/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,QAAQ,CAAC,yBAAyB,QAAQ;IAE1C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED;;;GAGG;AACH,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,QAAQ,CAAC,yBAAyB,QAAQ;IAC1C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAEpC,YAAY,OAAO,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,EAMtD;CACF;AAED,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,8BAA8B,CAQzC;AAED,wEAAwE;AACxE,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,GAAG,GAAE,MAAmB,GACvB,MAAM,GAAG,SAAS,CAOpB;AAED,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,8BAA8B,CAQzC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by a calendar provider when the provider rejected the credential
|
|
3
|
+
* (401/403), so the host has to reconnect rather than retry.
|
|
4
|
+
*/
|
|
5
|
+
export class CalendarCredentialInvalidError extends Error {
|
|
6
|
+
calendarCredentialInvalid = true;
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "CalendarCredentialInvalidError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Thrown by a calendar provider when it throttled the request (rate or quota
|
|
14
|
+
* limit). The credential is still good; the lookup can be retried.
|
|
15
|
+
*/
|
|
16
|
+
export class CalendarLookupRateLimitedError extends Error {
|
|
17
|
+
calendarLookupRateLimited = true;
|
|
18
|
+
retryAfterSeconds;
|
|
19
|
+
constructor(message, retryAfterSeconds) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = "CalendarLookupRateLimitedError";
|
|
22
|
+
if (retryAfterSeconds !== undefined) {
|
|
23
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function isCalendarLookupRateLimitedError(error) {
|
|
28
|
+
return (error instanceof CalendarLookupRateLimitedError ||
|
|
29
|
+
(!!error &&
|
|
30
|
+
typeof error === "object" &&
|
|
31
|
+
error
|
|
32
|
+
.calendarLookupRateLimited === true));
|
|
33
|
+
}
|
|
34
|
+
/** Seconds from a `Retry-After` header (delta-seconds or HTTP date). */
|
|
35
|
+
export function parseRetryAfterSeconds(header, now = Date.now()) {
|
|
36
|
+
if (!header)
|
|
37
|
+
return undefined;
|
|
38
|
+
const trimmed = header.trim();
|
|
39
|
+
if (/^\d+$/.test(trimmed))
|
|
40
|
+
return Number(trimmed);
|
|
41
|
+
const at = Date.parse(trimmed);
|
|
42
|
+
if (Number.isNaN(at))
|
|
43
|
+
return undefined;
|
|
44
|
+
return Math.max(0, Math.ceil((at - now) / 1000));
|
|
45
|
+
}
|
|
46
|
+
export function isCalendarCredentialInvalidError(error) {
|
|
47
|
+
return (error instanceof CalendarCredentialInvalidError ||
|
|
48
|
+
(!!error &&
|
|
49
|
+
typeof error === "object" &&
|
|
50
|
+
error
|
|
51
|
+
.calendarCredentialInvalid === true));
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/server/providers/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,8BAA+B,SAAQ,KAAK;IAC9C,yBAAyB,GAAG,IAAI,CAAC;IAE1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gCAAgC,CAAC;IAC/C,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,8BAA+B,SAAQ,KAAK;IAC9C,yBAAyB,GAAG,IAAI,CAAC;IACjC,iBAAiB,CAAU;IAEpC,YAAY,OAAe,EAAE,iBAA0B;QACrD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gCAAgC,CAAC;QAC7C,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC7C,CAAC;IACH,CAAC;CACF;AAED,MAAM,UAAU,gCAAgC,CAC9C,KAAc;IAEd,OAAO,CACL,KAAK,YAAY,8BAA8B;QAC/C,CAAC,CAAC,CAAC,KAAK;YACN,OAAO,KAAK,KAAK,QAAQ;YACxB,KAAiD;iBAC/C,yBAAyB,KAAK,IAAI,CAAC,CACzC,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,sBAAsB,CACpC,MAAqB,EACrB,GAAG,GAAW,IAAI,CAAC,GAAG,EAAE;IAExB,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;IAClD,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAAE,OAAO,SAAS,CAAC;IACvC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,gCAAgC,CAC9C,KAAc;IAEd,OAAO,CACL,KAAK,YAAY,8BAA8B;QAC/C,CAAC,CAAC,CAAC,KAAK;YACN,OAAO,KAAK,KAAK,QAAQ;YACxB,KAAiD;iBAC/C,yBAAyB,KAAK,IAAI,CAAC,CACzC,CAAC;AACJ,CAAC"}
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Google Calendar provider.
|
|
3
|
-
*
|
|
4
|
-
* Thin adapter over the Google Calendar API. Consumers wire it up by
|
|
5
|
-
* calling `createGoogleCalendarProvider()` with accessors that return
|
|
6
|
-
* OAuth tokens from their preferred store (typically core's oauth_tokens).
|
|
7
|
-
*
|
|
8
|
-
* This lives in the package rather than the template because the logic is
|
|
9
|
-
* the same for every scheduling consumer. Custom token stores are supported
|
|
10
|
-
* via the `getAccessToken` callback.
|
|
11
|
-
*/
|
|
12
1
|
import type { CalendarProvider } from "./types.js";
|
|
13
2
|
export interface GoogleCalendarProviderConfig {
|
|
14
3
|
clientId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-calendar.d.ts","sourceRoot":"","sources":["../../../src/server/providers/google-calendar.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"google-calendar.d.ts","sourceRoot":"","sources":["../../../src/server/providers/google-calendar.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA+BnD,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,YAAY,CAAC,EAAE,CACb,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,IAAI,CAAA;KAAE,KACrE,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAOD,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,4BAA4B,GACnC,gBAAgB,CAuOlB"}
|
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Calendar provider.
|
|
3
|
+
*
|
|
4
|
+
* Thin adapter over the Google Calendar API. Consumers wire it up by
|
|
5
|
+
* calling `createGoogleCalendarProvider()` with accessors that return
|
|
6
|
+
* OAuth tokens from their preferred store (typically core's oauth_tokens).
|
|
7
|
+
*
|
|
8
|
+
* This lives in the package rather than the template because the logic is
|
|
9
|
+
* the same for every scheduling consumer. Custom token stores are supported
|
|
10
|
+
* via the `getAccessToken` callback.
|
|
11
|
+
*/
|
|
12
|
+
import { CalendarCredentialInvalidError, CalendarLookupRateLimitedError, parseRetryAfterSeconds, } from "./errors.js";
|
|
13
|
+
const GOOGLE_RATE_LIMIT_REASONS = new Set([
|
|
14
|
+
"rateLimitExceeded",
|
|
15
|
+
"userRateLimitExceeded",
|
|
16
|
+
"quotaExceeded",
|
|
17
|
+
"dailyLimitExceeded",
|
|
18
|
+
]);
|
|
19
|
+
function googleRateLimitReason(body) {
|
|
20
|
+
let parsed;
|
|
21
|
+
try {
|
|
22
|
+
parsed = JSON.parse(body);
|
|
23
|
+
// coercion-ok: a non-JSON 403 names no throttle reason, so the caller still treats it as an authorization failure
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const errors = parsed
|
|
29
|
+
.error?.errors;
|
|
30
|
+
if (!Array.isArray(errors))
|
|
31
|
+
return undefined;
|
|
32
|
+
for (const entry of errors) {
|
|
33
|
+
if (typeof entry.reason === "string" &&
|
|
34
|
+
GOOGLE_RATE_LIMIT_REASONS.has(entry.reason)) {
|
|
35
|
+
return entry.reason;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
1
40
|
const SCOPES = [
|
|
2
41
|
"https://www.googleapis.com/auth/calendar",
|
|
3
42
|
"https://www.googleapis.com/auth/calendar.events",
|
|
@@ -12,9 +51,16 @@ export function createGoogleCalendarProvider(config) {
|
|
|
12
51
|
...init,
|
|
13
52
|
headers,
|
|
14
53
|
});
|
|
15
|
-
if (res.status === 401 || res.status === 403) {
|
|
54
|
+
if (res.status === 401 || res.status === 403 || res.status === 429) {
|
|
55
|
+
const body = await res.text();
|
|
56
|
+
// Google sends rate and quota limits as 403 (or 429); those are
|
|
57
|
+
// throttles on a good credential and must not force a reconnect.
|
|
58
|
+
const reason = googleRateLimitReason(body);
|
|
59
|
+
if (res.status === 429 || reason) {
|
|
60
|
+
throw new CalendarLookupRateLimitedError(`Google Calendar: rate limited (${res.status} ${reason ?? "rateLimitExceeded"})`, parseRetryAfterSeconds(res.headers.get("retry-after")));
|
|
61
|
+
}
|
|
16
62
|
await config.markInvalid?.(credentialId);
|
|
17
|
-
throw new
|
|
63
|
+
throw new CalendarCredentialInvalidError(`Google Calendar: credential invalid (${res.status})`);
|
|
18
64
|
}
|
|
19
65
|
if (!res.ok) {
|
|
20
66
|
const body = await res.text();
|
|
@@ -92,8 +138,16 @@ export function createGoogleCalendarProvider(config) {
|
|
|
92
138
|
items: calendarExternalIds.map((id) => ({ id })),
|
|
93
139
|
}),
|
|
94
140
|
});
|
|
141
|
+
// freeBusy answers 200 with an empty `busy` and an `errors` entry for a
|
|
142
|
+
// calendar it couldn't read; that must not count as a free calendar.
|
|
95
143
|
const out = [];
|
|
96
|
-
for (const
|
|
144
|
+
for (const calId of calendarExternalIds) {
|
|
145
|
+
const data = resp.calendars?.[calId] ??
|
|
146
|
+
Object.entries(resp.calendars ?? {}).find(([key]) => key.toLowerCase() === calId.toLowerCase())?.[1];
|
|
147
|
+
if (!data || data.errors?.length || !Array.isArray(data.busy)) {
|
|
148
|
+
const reason = data?.errors?.[0]?.reason ?? "missing from response";
|
|
149
|
+
throw new Error(`Google Calendar free/busy failed for ${calId}: ${reason}`);
|
|
150
|
+
}
|
|
97
151
|
for (const b of data.busy) {
|
|
98
152
|
out.push({ start: b.start, end: b.end, source: calId });
|
|
99
153
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-calendar.js","sourceRoot":"","sources":["../../../src/server/providers/google-calendar.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"google-calendar.js","sourceRoot":"","sources":["../../../src/server/providers/google-calendar.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./types.js";
|
|
2
2
|
export * from "./registry.js";
|
|
3
|
+
export * from "./errors.js";
|
|
3
4
|
export { createGoogleCalendarProvider } from "./google-calendar.js";
|
|
4
5
|
export { createOffice365Provider } from "./office365.js";
|
|
5
6
|
export { createZoomProvider, ZoomProviderError } from "./zoom.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./types.js";
|
|
2
2
|
export * from "./registry.js";
|
|
3
|
+
export * from "./errors.js";
|
|
3
4
|
export { createGoogleCalendarProvider } from "./google-calendar.js";
|
|
4
5
|
export { createOffice365Provider } from "./office365.js";
|
|
5
6
|
export { createZoomProvider, ZoomProviderError } from "./zoom.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"office365.d.ts","sourceRoot":"","sources":["../../../src/server/providers/office365.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"office365.d.ts","sourceRoot":"","sources":["../../../src/server/providers/office365.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,YAAY,CAAC,EAAE,CACb,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,IAAI,CAAA;KAAE,KACrE,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAoBD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,uBAAuB,GAC9B,gBAAgB,CA8OlB"}
|
|
@@ -1,4 +1,21 @@
|
|
|
1
|
+
import { CalendarCredentialInvalidError, CalendarLookupRateLimitedError, parseRetryAfterSeconds, } from "./errors.js";
|
|
1
2
|
const SCOPES = ["offline_access", "Calendars.ReadWrite", "User.Read"];
|
|
3
|
+
const MAX_CALENDAR_VIEW_CONCURRENCY = 4;
|
|
4
|
+
const GRAPH_TOKEN_ERROR_CODES = new Set([
|
|
5
|
+
"InvalidAuthenticationToken",
|
|
6
|
+
"AuthenticationError",
|
|
7
|
+
]);
|
|
8
|
+
function graphErrorCode(body) {
|
|
9
|
+
try {
|
|
10
|
+
const code = JSON.parse(body).error
|
|
11
|
+
?.code;
|
|
12
|
+
return typeof code === "string" ? code : "";
|
|
13
|
+
// coercion-ok: a non-JSON error body has no Graph error code, so it is not a token error
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
2
19
|
export function createOffice365Provider(config) {
|
|
3
20
|
const tenant = config.tenant ?? "common";
|
|
4
21
|
async function graph(credentialId, path, init) {
|
|
@@ -6,16 +23,31 @@ export function createOffice365Provider(config) {
|
|
|
6
23
|
const headers = new Headers(init?.headers);
|
|
7
24
|
headers.set("authorization", `Bearer ${token}`);
|
|
8
25
|
headers.set("content-type", "application/json");
|
|
9
|
-
|
|
26
|
+
// Paging links are absolute; never send the token anywhere but Graph.
|
|
27
|
+
const url = path.startsWith("/")
|
|
28
|
+
? `https://graph.microsoft.com/v1.0${path}`
|
|
29
|
+
: path;
|
|
30
|
+
if (!url.startsWith("https://graph.microsoft.com/")) {
|
|
31
|
+
throw new Error(`Refusing to call a non-Graph URL: ${url}`);
|
|
32
|
+
}
|
|
33
|
+
const res = await fetch(url, {
|
|
10
34
|
...init,
|
|
11
35
|
headers,
|
|
12
36
|
});
|
|
13
|
-
if (res.status ===
|
|
14
|
-
|
|
15
|
-
throw new Error(`Office 365 credential invalid (${res.status})`);
|
|
37
|
+
if (res.status === 429) {
|
|
38
|
+
throw new CalendarLookupRateLimitedError("Graph: rate limited (429)", parseRetryAfterSeconds(res.headers.get("retry-after")));
|
|
16
39
|
}
|
|
17
40
|
if (!res.ok) {
|
|
18
|
-
|
|
41
|
+
const body = await res.text();
|
|
42
|
+
// A 403 is usually about one resource (a shared calendar this account
|
|
43
|
+
// can't read), not the token; only token errors invalidate the credential.
|
|
44
|
+
if (res.status === 401 ||
|
|
45
|
+
(res.status === 403 &&
|
|
46
|
+
GRAPH_TOKEN_ERROR_CODES.has(graphErrorCode(body)))) {
|
|
47
|
+
await config.markInvalid?.(credentialId);
|
|
48
|
+
throw new CalendarCredentialInvalidError(`Office 365 credential invalid (${res.status})`);
|
|
49
|
+
}
|
|
50
|
+
throw new Error(`Graph ${res.status}: ${body}`);
|
|
19
51
|
}
|
|
20
52
|
if (res.status === 204)
|
|
21
53
|
return undefined;
|
|
@@ -80,29 +112,59 @@ export function createOffice365Provider(config) {
|
|
|
80
112
|
primary: c.isDefaultCalendar,
|
|
81
113
|
}));
|
|
82
114
|
},
|
|
115
|
+
// Selected calendars are stored by Graph calendar id, which getSchedule
|
|
116
|
+
// does not accept (it takes SMTP addresses), so read each calendar's
|
|
117
|
+
// calendarView. Times come back in UTC without an offset.
|
|
83
118
|
async getBusy({ credentialId, calendarExternalIds, start, end }) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
119
|
+
// One unreadable calendar fails the whole lookup, so stop the rest.
|
|
120
|
+
const stop = new AbortController();
|
|
121
|
+
async function readCalendar(calendarId) {
|
|
122
|
+
const out = [];
|
|
123
|
+
const params = new URLSearchParams({
|
|
124
|
+
startDateTime: start.toISOString(),
|
|
125
|
+
endDateTime: end.toISOString(),
|
|
126
|
+
$select: "start,end,showAs,isCancelled",
|
|
127
|
+
$top: "250",
|
|
128
|
+
});
|
|
129
|
+
let path = `/me/calendars/${encodeURIComponent(calendarId)}/calendarView?${params}`;
|
|
130
|
+
while (path) {
|
|
131
|
+
const page = await graph(credentialId, path, { signal: stop.signal });
|
|
132
|
+
if (!Array.isArray(page.value)) {
|
|
133
|
+
throw new Error(`Graph calendarView returned no events list for ${calendarId}`);
|
|
134
|
+
}
|
|
135
|
+
for (const event of page.value) {
|
|
136
|
+
if (event.isCancelled || event.showAs === "free")
|
|
137
|
+
continue;
|
|
138
|
+
out.push({
|
|
139
|
+
start: event.start.dateTime + "Z",
|
|
140
|
+
end: event.end.dateTime + "Z",
|
|
141
|
+
source: calendarId,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
path = page["@odata.nextLink"];
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
const perCalendar = [];
|
|
149
|
+
const queue = calendarExternalIds.map((calendarId, index) => ({
|
|
150
|
+
calendarId,
|
|
151
|
+
index,
|
|
152
|
+
}));
|
|
153
|
+
async function worker() {
|
|
154
|
+
for (let item = queue.shift(); item; item = queue.shift()) {
|
|
155
|
+
try {
|
|
156
|
+
perCalendar[item.index] = await readCalendar(item.calendarId);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
queue.length = 0;
|
|
160
|
+
stop.abort();
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
103
163
|
}
|
|
104
164
|
}
|
|
105
|
-
|
|
165
|
+
const workerCount = Math.min(MAX_CALENDAR_VIEW_CONCURRENCY, calendarExternalIds.length);
|
|
166
|
+
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
167
|
+
return perCalendar.flat();
|
|
106
168
|
},
|
|
107
169
|
async createEvent({ credentialId, calendarExternalId, booking }) {
|
|
108
170
|
const body = {
|