@ganju/utils 0.0.5 → 0.0.6
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/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/vendorTimeZone.d.ts +57 -0
- package/dist/vendorTimeZone.d.ts.map +1 -0
- package/dist/vendorTimeZone.js +165 -0
- package/package.json +1 -1
- package/src/constants.ts +2 -0
- package/src/index.ts +14 -0
- package/src/vendorTimeZone.ts +171 -0
package/dist/constants.d.ts
CHANGED
|
@@ -451,6 +451,7 @@ export declare const constants: {
|
|
|
451
451
|
CALCOM_API_VERSION_EVENT_TYPES: string;
|
|
452
452
|
CALCOM_API_VERSION_SLOTS: string;
|
|
453
453
|
CALCOM_API_VERSION_BOOKINGS: string;
|
|
454
|
+
CALCOM_API_VERSION_ME: string;
|
|
454
455
|
CALCOM_TOOL_KEY_PREFIX: string;
|
|
455
456
|
TAVILY_API_BASE: string;
|
|
456
457
|
TAVILY_SEARCH_DEPTH_BASIC: "basic";
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AA6JA,QAAA,MAAM,yBAAyB,EAAiB,UAAU,CAAC;AAC3D,QAAA,MAAM,+BAA+B,EAAuB,gBAAgB,CAAC;AAC7E,QAAA,MAAM,8BAA8B,EAAsB,eAAe,CAAC;AAC1E,QAAA,MAAM,wBAAwB,EAAgB,SAAS,CAAC;AAuCxD,QAAA,MAAM,sBAAsB,EAAiB,UAAU,CAAC;AACxD,QAAA,MAAM,4BAA4B,EAAuB,gBAAgB,CAAC;AAC1E,QAAA,MAAM,oBAAoB,EAAe,QAAQ,CAAC;AAClD,QAAA,MAAM,oBAAoB,EAAe,QAAQ,CAAC;AAmYlD,QAAA,MAAM,sBAAsB,EAAkB,WAAW,CAAC;AAC1D,QAAA,MAAM,mBAAmB,EAAe,QAAQ,CAAC;AAGjD,QAAA,MAAM,mBAAmB,EAAe,QAAQ,CAAC;AAkTjD,MAAM,MAAM,mBAAmB,GAC3B;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GACD;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GACD;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
|
package/dist/constants.js
CHANGED
|
@@ -877,6 +877,7 @@ const CALCOM_API_BASE = 'https://api.cal.com/v2';
|
|
|
877
877
|
const CALCOM_API_VERSION_EVENT_TYPES = '2024-06-14';
|
|
878
878
|
const CALCOM_API_VERSION_SLOTS = '2024-09-04';
|
|
879
879
|
const CALCOM_API_VERSION_BOOKINGS = '2026-02-25';
|
|
880
|
+
const CALCOM_API_VERSION_ME = '2024-06-14';
|
|
880
881
|
const CALCOM_TOOL_KEY_PREFIX = 'calcom-';
|
|
881
882
|
// Tavily web search. The key is validated against the live API before it is
|
|
882
883
|
// persisted (a minimal 1-result search), then stored as an artifact_credential
|
|
@@ -2140,6 +2141,7 @@ exports.constants = {
|
|
|
2140
2141
|
CALCOM_API_VERSION_EVENT_TYPES,
|
|
2141
2142
|
CALCOM_API_VERSION_SLOTS,
|
|
2142
2143
|
CALCOM_API_VERSION_BOOKINGS,
|
|
2144
|
+
CALCOM_API_VERSION_ME,
|
|
2143
2145
|
CALCOM_TOOL_KEY_PREFIX,
|
|
2144
2146
|
TAVILY_API_BASE,
|
|
2145
2147
|
TAVILY_SEARCH_DEPTH_BASIC,
|
package/dist/index.d.ts
CHANGED
|
@@ -2161,6 +2161,7 @@ export declare const utils: {
|
|
|
2161
2161
|
CALCOM_API_VERSION_EVENT_TYPES: string;
|
|
2162
2162
|
CALCOM_API_VERSION_SLOTS: string;
|
|
2163
2163
|
CALCOM_API_VERSION_BOOKINGS: string;
|
|
2164
|
+
CALCOM_API_VERSION_ME: string;
|
|
2164
2165
|
CALCOM_TOOL_KEY_PREFIX: string;
|
|
2165
2166
|
TAVILY_API_BASE: string;
|
|
2166
2167
|
TAVILY_SEARCH_DEPTH_BASIC: "basic";
|
|
@@ -2878,6 +2879,12 @@ export declare const utils: {
|
|
|
2878
2879
|
buildReauthMetadata: (previous: Record<string, unknown> | null, reason: string) => Record<string, unknown>;
|
|
2879
2880
|
clearReauthMetadata: (previous: Record<string, unknown> | null) => Record<string, unknown> | null;
|
|
2880
2881
|
isCredentialNeedingReauth: (metadata: unknown) => boolean;
|
|
2882
|
+
isValidTimeZone: (value: unknown) => value is string;
|
|
2883
|
+
readCredentialTimeZone: (metadata: unknown) => string | null;
|
|
2884
|
+
credentialTimeZoneIsStale: (metadata: unknown, now?: number) => boolean;
|
|
2885
|
+
writeCredentialTimeZone: (previous: unknown, timeZone: string | null, now?: Date) => Record<string, unknown>;
|
|
2886
|
+
fetchGoogleCalendarTimeZone: (accessToken: string) => Promise<string | null>;
|
|
2887
|
+
fetchCalcomTimeZone: (apiKey: string) => Promise<string | null>;
|
|
2881
2888
|
PlanLimitError: typeof PlanLimitError;
|
|
2882
2889
|
isPlanLimitError: (error: unknown) => error is PlanLimitError;
|
|
2883
2890
|
};
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,EACzB,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAyCvD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,EAClC,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,8BAA8B,EAC/B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,gCAAgC,EACjC,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,EAClC,MAAM,gBAAgB,CAAC;AAKxB,OAAO,EACL,UAAU,EAGX,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAU9D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAG5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAW3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACxB,MAAM,cAAc,CAAC;AActB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AASvD,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,YAAY,EACZ,OAAO,EACR,MAAM,eAAe,CAAC;AAiBvB,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAI1E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAErD,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,yBAAyB,EAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EACV,iBAAiB,EACjB,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAM1E,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAS3B,OAAO,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC1E,OAAO,EAEL,wBAAwB,EAIzB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aApHf,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;kBAhHiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBA0DF,CAAC;oBAEd,CAAC;;;;aA0BkB,CAAC;mBAA8B,CAAC;WACvC,CAAC;gBACf,CAAC;gBAA4B,CAAA;;;mBAoBK,CAAC;oBACjC,CAAC;;;;;;;;;;;;;;;kBA3Dc,CAAC;;;;;;;sBAqCR,CAAC;;;;;;;;;;;;;;;CAoQf,CAAC;AAEF,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,YAAY,EACZ,OAAO,EACP,mBAAmB,EACnB,UAAU,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,8BAA8B,EAC9B,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,EACjC,kBAAkB,EAClB,mBAAmB,EACnB,gCAAgC,EAChC,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,EACjC,SAAS,EACT,SAAS,EACT,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,yBAAyB,EACzB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,MAAM,EACN,kBAAkB,EAClB,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACX,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,7 @@ const channelNotifier_1 = require("./channelNotifier");
|
|
|
45
45
|
const channelDebounce_1 = require("./channelDebounce");
|
|
46
46
|
const sources_1 = require("./sources");
|
|
47
47
|
const oauth_1 = require("./oauth");
|
|
48
|
+
const vendorTimeZone_1 = require("./vendorTimeZone");
|
|
48
49
|
const planLimitError_1 = require("./planLimitError");
|
|
49
50
|
exports.utils = {
|
|
50
51
|
Schema: schema_1.Schema,
|
|
@@ -157,6 +158,12 @@ exports.utils = {
|
|
|
157
158
|
buildReauthMetadata: oauth_1.buildReauthMetadata,
|
|
158
159
|
clearReauthMetadata: oauth_1.clearReauthMetadata,
|
|
159
160
|
isCredentialNeedingReauth: oauth_1.isCredentialNeedingReauth,
|
|
161
|
+
isValidTimeZone: vendorTimeZone_1.isValidTimeZone,
|
|
162
|
+
readCredentialTimeZone: vendorTimeZone_1.readCredentialTimeZone,
|
|
163
|
+
credentialTimeZoneIsStale: vendorTimeZone_1.credentialTimeZoneIsStale,
|
|
164
|
+
writeCredentialTimeZone: vendorTimeZone_1.writeCredentialTimeZone,
|
|
165
|
+
fetchGoogleCalendarTimeZone: vendorTimeZone_1.fetchGoogleCalendarTimeZone,
|
|
166
|
+
fetchCalcomTimeZone: vendorTimeZone_1.fetchCalcomTimeZone,
|
|
160
167
|
PlanLimitError: planLimitError_1.PlanLimitError,
|
|
161
168
|
isPlanLimitError: planLimitError_1.isPlanLimitError
|
|
162
169
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is this a time zone the runtime actually knows?
|
|
3
|
+
*
|
|
4
|
+
* Everything downstream — `Intl.DateTimeFormat`, Google's `start.timeZone`,
|
|
5
|
+
* Cal.com's `attendee.timeZone` — throws or 400s on a name it cannot resolve.
|
|
6
|
+
* A vendor returning something unexpected must degrade to "we don't know"
|
|
7
|
+
* rather than poison every later call with a value that cannot be used.
|
|
8
|
+
*/
|
|
9
|
+
export declare const isValidTimeZone: (value: unknown) => value is string;
|
|
10
|
+
/** The cached zone on a credential's metadata, or null. */
|
|
11
|
+
export declare const readCredentialTimeZone: (metadata: unknown) => string | null;
|
|
12
|
+
/**
|
|
13
|
+
* Should we ask the vendor again?
|
|
14
|
+
*
|
|
15
|
+
* True when there is nothing cached, when the stamp is missing or unreadable,
|
|
16
|
+
* or when the TTL has passed. A cache with no stamp is treated as stale rather
|
|
17
|
+
* than as fresh-forever — the conservative direction, since the only cost is
|
|
18
|
+
* one request.
|
|
19
|
+
*/
|
|
20
|
+
export declare const credentialTimeZoneIsStale: (metadata: unknown, now?: number) => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Merge a freshly read zone into a credential's metadata.
|
|
23
|
+
*
|
|
24
|
+
* Merges rather than replaces, because this column also carries the reauth
|
|
25
|
+
* markers — writing a bare `{ timeZone }` here would clear `needsReauth` and
|
|
26
|
+
* silently re-enable a connection the refresh path had flagged as broken.
|
|
27
|
+
*
|
|
28
|
+
* A null zone (the vendor could not tell us) still stamps the check, so a
|
|
29
|
+
* provider that never reports one is asked once a day rather than on every
|
|
30
|
+
* single call.
|
|
31
|
+
*/
|
|
32
|
+
export declare const writeCredentialTimeZone: (previous: unknown, timeZone: string | null, now?: Date) => Record<string, unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* The zone Google Calendar is configured in, from the primary calendar.
|
|
35
|
+
*
|
|
36
|
+
* Deliberately NOT `GET /users/me/settings/timezone`, which is the more
|
|
37
|
+
* direct answer to "what did the user configure" and needs
|
|
38
|
+
* `calendar.settings.readonly` — a scope we do not request and could not add
|
|
39
|
+
* without sending every already-connected user back through consent. The
|
|
40
|
+
* primary calendar's zone is the same value in every case that matters, and
|
|
41
|
+
* `calendar.readonly` already covers it.
|
|
42
|
+
*
|
|
43
|
+
* Returns null on any failure. Not knowing the zone is a state the callers
|
|
44
|
+
* handle; a throw here would take a tool call or a chat turn with it.
|
|
45
|
+
*/
|
|
46
|
+
export declare const fetchGoogleCalendarTimeZone: (accessToken: string) => Promise<string | null>;
|
|
47
|
+
/**
|
|
48
|
+
* The zone on the connected Cal.com profile.
|
|
49
|
+
*
|
|
50
|
+
* This is the host's zone — the one their availability is written in — which
|
|
51
|
+
* is what "9am" means when the artifact owner or their bot says it. It is not
|
|
52
|
+
* the attendee's zone; see the booking handler for why we use it there anyway.
|
|
53
|
+
*
|
|
54
|
+
* Same null-on-failure contract as the Google reader above.
|
|
55
|
+
*/
|
|
56
|
+
export declare const fetchCalcomTimeZone: (apiKey: string) => Promise<string | null>;
|
|
57
|
+
//# sourceMappingURL=vendorTimeZone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendorTimeZone.d.ts","sourceRoot":"","sources":["../src/vendorTimeZone.ts"],"names":[],"mappings":"AAiCA;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAQzD,CAAC;AAEF,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,GAAI,UAAU,OAAO,KAAG,MAAM,GAAG,IAInE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,GACpC,UAAU,OAAO,EACjB,MAAK,MAAmB,KACvB,OAOF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,GAClC,UAAU,OAAO,EACjB,UAAU,MAAM,GAAG,IAAI,EACvB,MAAK,IAAiB,KACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAYxB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,GACtC,aAAa,MAAM,KAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAiBvB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,MAAM,KACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAkBvB,CAAC"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// The time zone the user configured with the vendor, and where we keep it.
|
|
3
|
+
//
|
|
4
|
+
// Every scheduling question the model answers is a time-zone question first:
|
|
5
|
+
// "tomorrow at 9" is not an instant until you know whose 9 it is. We had two
|
|
6
|
+
// sources for that and neither worked. `artifact_tool.config.defaultTimeZone`
|
|
7
|
+
// is only written when the owner opens a dropdown and changes it, so in
|
|
8
|
+
// practice it is empty. The fallbacks underneath it were `undefined` (Google
|
|
9
|
+
// then uses the calendar's own zone, which only helps when the timestamp has no
|
|
10
|
+
// offset) and the string 'UTC' (Cal.com, which books the attendee in UTC and
|
|
11
|
+
// tells nobody).
|
|
12
|
+
//
|
|
13
|
+
// But the user already answered this question — in Google Calendar's settings,
|
|
14
|
+
// and in their Cal.com profile. So we ask the vendor instead of asking the
|
|
15
|
+
// owner again, and the answer becomes the default under any explicit choice.
|
|
16
|
+
//
|
|
17
|
+
// It is cached on `artifact_credential.metadata` because that is what it is a
|
|
18
|
+
// property of: the connected account, not the tool row. One artifact can have
|
|
19
|
+
// six calendar tools installed and they all share one connection, so the
|
|
20
|
+
// connection is the only place the answer belongs exactly once.
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.fetchCalcomTimeZone = exports.fetchGoogleCalendarTimeZone = exports.writeCredentialTimeZone = exports.credentialTimeZoneIsStale = exports.readCredentialTimeZone = exports.isValidTimeZone = void 0;
|
|
23
|
+
const constants_1 = require("./constants");
|
|
24
|
+
// Metadata keys on artifact_credential. Namespaced with a prefix that will not
|
|
25
|
+
// collide with the reauth markers written by the OAuth refresh path.
|
|
26
|
+
const TIME_ZONE_KEY = 'timeZone';
|
|
27
|
+
const TIME_ZONE_CHECKED_AT_KEY = 'timeZoneCheckedAt';
|
|
28
|
+
// How long a cached zone is trusted. A day, because this changes when somebody
|
|
29
|
+
// moves or travels — rarely, and never urgently. The cost of being briefly
|
|
30
|
+
// stale is one meeting in the old zone; the cost of a shorter TTL is a vendor
|
|
31
|
+
// round trip on the path of a tool call.
|
|
32
|
+
const TIME_ZONE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
33
|
+
/**
|
|
34
|
+
* Is this a time zone the runtime actually knows?
|
|
35
|
+
*
|
|
36
|
+
* Everything downstream — `Intl.DateTimeFormat`, Google's `start.timeZone`,
|
|
37
|
+
* Cal.com's `attendee.timeZone` — throws or 400s on a name it cannot resolve.
|
|
38
|
+
* A vendor returning something unexpected must degrade to "we don't know"
|
|
39
|
+
* rather than poison every later call with a value that cannot be used.
|
|
40
|
+
*/
|
|
41
|
+
const isValidTimeZone = (value) => {
|
|
42
|
+
if (typeof value !== 'string' || !value.trim())
|
|
43
|
+
return false;
|
|
44
|
+
try {
|
|
45
|
+
new Intl.DateTimeFormat('en-US', { timeZone: value.trim() });
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
exports.isValidTimeZone = isValidTimeZone;
|
|
53
|
+
/** The cached zone on a credential's metadata, or null. */
|
|
54
|
+
const readCredentialTimeZone = (metadata) => {
|
|
55
|
+
if (!metadata || typeof metadata !== 'object')
|
|
56
|
+
return null;
|
|
57
|
+
const value = metadata[TIME_ZONE_KEY];
|
|
58
|
+
return (0, exports.isValidTimeZone)(value) ? value.trim() : null;
|
|
59
|
+
};
|
|
60
|
+
exports.readCredentialTimeZone = readCredentialTimeZone;
|
|
61
|
+
/**
|
|
62
|
+
* Should we ask the vendor again?
|
|
63
|
+
*
|
|
64
|
+
* True when there is nothing cached, when the stamp is missing or unreadable,
|
|
65
|
+
* or when the TTL has passed. A cache with no stamp is treated as stale rather
|
|
66
|
+
* than as fresh-forever — the conservative direction, since the only cost is
|
|
67
|
+
* one request.
|
|
68
|
+
*/
|
|
69
|
+
const credentialTimeZoneIsStale = (metadata, now = Date.now()) => {
|
|
70
|
+
if (!(0, exports.readCredentialTimeZone)(metadata))
|
|
71
|
+
return true;
|
|
72
|
+
const raw = metadata[TIME_ZONE_CHECKED_AT_KEY];
|
|
73
|
+
if (typeof raw !== 'string')
|
|
74
|
+
return true;
|
|
75
|
+
const checkedAt = Date.parse(raw);
|
|
76
|
+
if (!Number.isFinite(checkedAt))
|
|
77
|
+
return true;
|
|
78
|
+
return now - checkedAt >= TIME_ZONE_TTL_MS;
|
|
79
|
+
};
|
|
80
|
+
exports.credentialTimeZoneIsStale = credentialTimeZoneIsStale;
|
|
81
|
+
/**
|
|
82
|
+
* Merge a freshly read zone into a credential's metadata.
|
|
83
|
+
*
|
|
84
|
+
* Merges rather than replaces, because this column also carries the reauth
|
|
85
|
+
* markers — writing a bare `{ timeZone }` here would clear `needsReauth` and
|
|
86
|
+
* silently re-enable a connection the refresh path had flagged as broken.
|
|
87
|
+
*
|
|
88
|
+
* A null zone (the vendor could not tell us) still stamps the check, so a
|
|
89
|
+
* provider that never reports one is asked once a day rather than on every
|
|
90
|
+
* single call.
|
|
91
|
+
*/
|
|
92
|
+
const writeCredentialTimeZone = (previous, timeZone, now = new Date()) => {
|
|
93
|
+
const base = previous && typeof previous === 'object'
|
|
94
|
+
? { ...previous }
|
|
95
|
+
: {};
|
|
96
|
+
if ((0, exports.isValidTimeZone)(timeZone)) {
|
|
97
|
+
base[TIME_ZONE_KEY] = timeZone.trim();
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
delete base[TIME_ZONE_KEY];
|
|
101
|
+
}
|
|
102
|
+
base[TIME_ZONE_CHECKED_AT_KEY] = now.toISOString();
|
|
103
|
+
return base;
|
|
104
|
+
};
|
|
105
|
+
exports.writeCredentialTimeZone = writeCredentialTimeZone;
|
|
106
|
+
/**
|
|
107
|
+
* The zone Google Calendar is configured in, from the primary calendar.
|
|
108
|
+
*
|
|
109
|
+
* Deliberately NOT `GET /users/me/settings/timezone`, which is the more
|
|
110
|
+
* direct answer to "what did the user configure" and needs
|
|
111
|
+
* `calendar.settings.readonly` — a scope we do not request and could not add
|
|
112
|
+
* without sending every already-connected user back through consent. The
|
|
113
|
+
* primary calendar's zone is the same value in every case that matters, and
|
|
114
|
+
* `calendar.readonly` already covers it.
|
|
115
|
+
*
|
|
116
|
+
* Returns null on any failure. Not knowing the zone is a state the callers
|
|
117
|
+
* handle; a throw here would take a tool call or a chat turn with it.
|
|
118
|
+
*/
|
|
119
|
+
const fetchGoogleCalendarTimeZone = async (accessToken) => {
|
|
120
|
+
try {
|
|
121
|
+
const response = await fetch(`${constants_1.constants.GOOGLE_CALENDAR_API_BASE}/calendars/primary`, {
|
|
122
|
+
headers: {
|
|
123
|
+
Authorization: `Bearer ${accessToken}`,
|
|
124
|
+
Accept: 'application/json'
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
if (!response.ok)
|
|
128
|
+
return null;
|
|
129
|
+
const payload = (await response.json());
|
|
130
|
+
return (0, exports.isValidTimeZone)(payload?.timeZone) ? payload.timeZone.trim() : null;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
exports.fetchGoogleCalendarTimeZone = fetchGoogleCalendarTimeZone;
|
|
137
|
+
/**
|
|
138
|
+
* The zone on the connected Cal.com profile.
|
|
139
|
+
*
|
|
140
|
+
* This is the host's zone — the one their availability is written in — which
|
|
141
|
+
* is what "9am" means when the artifact owner or their bot says it. It is not
|
|
142
|
+
* the attendee's zone; see the booking handler for why we use it there anyway.
|
|
143
|
+
*
|
|
144
|
+
* Same null-on-failure contract as the Google reader above.
|
|
145
|
+
*/
|
|
146
|
+
const fetchCalcomTimeZone = async (apiKey) => {
|
|
147
|
+
try {
|
|
148
|
+
const response = await fetch(`${constants_1.constants.CALCOM_API_BASE}/me`, {
|
|
149
|
+
headers: {
|
|
150
|
+
Authorization: `Bearer ${apiKey}`,
|
|
151
|
+
'cal-api-version': constants_1.constants.CALCOM_API_VERSION_ME,
|
|
152
|
+
Accept: 'application/json'
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
if (!response.ok)
|
|
156
|
+
return null;
|
|
157
|
+
const payload = (await response.json());
|
|
158
|
+
const value = payload?.data?.timeZone;
|
|
159
|
+
return (0, exports.isValidTimeZone)(value) ? value.trim() : null;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
exports.fetchCalcomTimeZone = fetchCalcomTimeZone;
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -1054,6 +1054,7 @@ const CALCOM_API_BASE = 'https://api.cal.com/v2';
|
|
|
1054
1054
|
const CALCOM_API_VERSION_EVENT_TYPES = '2024-06-14';
|
|
1055
1055
|
const CALCOM_API_VERSION_SLOTS = '2024-09-04';
|
|
1056
1056
|
const CALCOM_API_VERSION_BOOKINGS = '2026-02-25';
|
|
1057
|
+
const CALCOM_API_VERSION_ME = '2024-06-14';
|
|
1057
1058
|
|
|
1058
1059
|
const CALCOM_TOOL_KEY_PREFIX = 'calcom-';
|
|
1059
1060
|
|
|
@@ -2478,6 +2479,7 @@ export const constants = {
|
|
|
2478
2479
|
CALCOM_API_VERSION_EVENT_TYPES,
|
|
2479
2480
|
CALCOM_API_VERSION_SLOTS,
|
|
2480
2481
|
CALCOM_API_VERSION_BOOKINGS,
|
|
2482
|
+
CALCOM_API_VERSION_ME,
|
|
2481
2483
|
CALCOM_TOOL_KEY_PREFIX,
|
|
2482
2484
|
TAVILY_API_BASE,
|
|
2483
2485
|
TAVILY_SEARCH_DEPTH_BASIC,
|
package/src/index.ts
CHANGED
|
@@ -218,6 +218,14 @@ import {
|
|
|
218
218
|
isCredentialNeedingReauth
|
|
219
219
|
} from './oauth';
|
|
220
220
|
import type { RefreshOAuthTokenInput, RefreshedOAuthToken } from './oauth';
|
|
221
|
+
import {
|
|
222
|
+
isValidTimeZone,
|
|
223
|
+
readCredentialTimeZone,
|
|
224
|
+
credentialTimeZoneIsStale,
|
|
225
|
+
writeCredentialTimeZone,
|
|
226
|
+
fetchGoogleCalendarTimeZone,
|
|
227
|
+
fetchCalcomTimeZone
|
|
228
|
+
} from './vendorTimeZone';
|
|
221
229
|
import { PlanLimitError, isPlanLimitError } from './planLimitError';
|
|
222
230
|
import type { PlanLimitDetails } from './planLimitError';
|
|
223
231
|
import type { PlanLimits } from './constants';
|
|
@@ -333,6 +341,12 @@ export const utils = {
|
|
|
333
341
|
buildReauthMetadata,
|
|
334
342
|
clearReauthMetadata,
|
|
335
343
|
isCredentialNeedingReauth,
|
|
344
|
+
isValidTimeZone,
|
|
345
|
+
readCredentialTimeZone,
|
|
346
|
+
credentialTimeZoneIsStale,
|
|
347
|
+
writeCredentialTimeZone,
|
|
348
|
+
fetchGoogleCalendarTimeZone,
|
|
349
|
+
fetchCalcomTimeZone,
|
|
336
350
|
PlanLimitError,
|
|
337
351
|
isPlanLimitError
|
|
338
352
|
};
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// The time zone the user configured with the vendor, and where we keep it.
|
|
2
|
+
//
|
|
3
|
+
// Every scheduling question the model answers is a time-zone question first:
|
|
4
|
+
// "tomorrow at 9" is not an instant until you know whose 9 it is. We had two
|
|
5
|
+
// sources for that and neither worked. `artifact_tool.config.defaultTimeZone`
|
|
6
|
+
// is only written when the owner opens a dropdown and changes it, so in
|
|
7
|
+
// practice it is empty. The fallbacks underneath it were `undefined` (Google
|
|
8
|
+
// then uses the calendar's own zone, which only helps when the timestamp has no
|
|
9
|
+
// offset) and the string 'UTC' (Cal.com, which books the attendee in UTC and
|
|
10
|
+
// tells nobody).
|
|
11
|
+
//
|
|
12
|
+
// But the user already answered this question — in Google Calendar's settings,
|
|
13
|
+
// and in their Cal.com profile. So we ask the vendor instead of asking the
|
|
14
|
+
// owner again, and the answer becomes the default under any explicit choice.
|
|
15
|
+
//
|
|
16
|
+
// It is cached on `artifact_credential.metadata` because that is what it is a
|
|
17
|
+
// property of: the connected account, not the tool row. One artifact can have
|
|
18
|
+
// six calendar tools installed and they all share one connection, so the
|
|
19
|
+
// connection is the only place the answer belongs exactly once.
|
|
20
|
+
|
|
21
|
+
import { constants } from './constants';
|
|
22
|
+
|
|
23
|
+
// Metadata keys on artifact_credential. Namespaced with a prefix that will not
|
|
24
|
+
// collide with the reauth markers written by the OAuth refresh path.
|
|
25
|
+
const TIME_ZONE_KEY = 'timeZone';
|
|
26
|
+
const TIME_ZONE_CHECKED_AT_KEY = 'timeZoneCheckedAt';
|
|
27
|
+
|
|
28
|
+
// How long a cached zone is trusted. A day, because this changes when somebody
|
|
29
|
+
// moves or travels — rarely, and never urgently. The cost of being briefly
|
|
30
|
+
// stale is one meeting in the old zone; the cost of a shorter TTL is a vendor
|
|
31
|
+
// round trip on the path of a tool call.
|
|
32
|
+
const TIME_ZONE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Is this a time zone the runtime actually knows?
|
|
36
|
+
*
|
|
37
|
+
* Everything downstream — `Intl.DateTimeFormat`, Google's `start.timeZone`,
|
|
38
|
+
* Cal.com's `attendee.timeZone` — throws or 400s on a name it cannot resolve.
|
|
39
|
+
* A vendor returning something unexpected must degrade to "we don't know"
|
|
40
|
+
* rather than poison every later call with a value that cannot be used.
|
|
41
|
+
*/
|
|
42
|
+
export const isValidTimeZone = (value: unknown): value is string => {
|
|
43
|
+
if (typeof value !== 'string' || !value.trim()) return false;
|
|
44
|
+
try {
|
|
45
|
+
new Intl.DateTimeFormat('en-US', { timeZone: value.trim() });
|
|
46
|
+
return true;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** The cached zone on a credential's metadata, or null. */
|
|
53
|
+
export const readCredentialTimeZone = (metadata: unknown): string | null => {
|
|
54
|
+
if (!metadata || typeof metadata !== 'object') return null;
|
|
55
|
+
const value = (metadata as Record<string, unknown>)[TIME_ZONE_KEY];
|
|
56
|
+
return isValidTimeZone(value) ? value.trim() : null;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Should we ask the vendor again?
|
|
61
|
+
*
|
|
62
|
+
* True when there is nothing cached, when the stamp is missing or unreadable,
|
|
63
|
+
* or when the TTL has passed. A cache with no stamp is treated as stale rather
|
|
64
|
+
* than as fresh-forever — the conservative direction, since the only cost is
|
|
65
|
+
* one request.
|
|
66
|
+
*/
|
|
67
|
+
export const credentialTimeZoneIsStale = (
|
|
68
|
+
metadata: unknown,
|
|
69
|
+
now: number = Date.now()
|
|
70
|
+
): boolean => {
|
|
71
|
+
if (!readCredentialTimeZone(metadata)) return true;
|
|
72
|
+
const raw = (metadata as Record<string, unknown>)[TIME_ZONE_CHECKED_AT_KEY];
|
|
73
|
+
if (typeof raw !== 'string') return true;
|
|
74
|
+
const checkedAt = Date.parse(raw);
|
|
75
|
+
if (!Number.isFinite(checkedAt)) return true;
|
|
76
|
+
return now - checkedAt >= TIME_ZONE_TTL_MS;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Merge a freshly read zone into a credential's metadata.
|
|
81
|
+
*
|
|
82
|
+
* Merges rather than replaces, because this column also carries the reauth
|
|
83
|
+
* markers — writing a bare `{ timeZone }` here would clear `needsReauth` and
|
|
84
|
+
* silently re-enable a connection the refresh path had flagged as broken.
|
|
85
|
+
*
|
|
86
|
+
* A null zone (the vendor could not tell us) still stamps the check, so a
|
|
87
|
+
* provider that never reports one is asked once a day rather than on every
|
|
88
|
+
* single call.
|
|
89
|
+
*/
|
|
90
|
+
export const writeCredentialTimeZone = (
|
|
91
|
+
previous: unknown,
|
|
92
|
+
timeZone: string | null,
|
|
93
|
+
now: Date = new Date()
|
|
94
|
+
): Record<string, unknown> => {
|
|
95
|
+
const base =
|
|
96
|
+
previous && typeof previous === 'object'
|
|
97
|
+
? { ...(previous as Record<string, unknown>) }
|
|
98
|
+
: {};
|
|
99
|
+
if (isValidTimeZone(timeZone)) {
|
|
100
|
+
base[TIME_ZONE_KEY] = timeZone.trim();
|
|
101
|
+
} else {
|
|
102
|
+
delete base[TIME_ZONE_KEY];
|
|
103
|
+
}
|
|
104
|
+
base[TIME_ZONE_CHECKED_AT_KEY] = now.toISOString();
|
|
105
|
+
return base;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The zone Google Calendar is configured in, from the primary calendar.
|
|
110
|
+
*
|
|
111
|
+
* Deliberately NOT `GET /users/me/settings/timezone`, which is the more
|
|
112
|
+
* direct answer to "what did the user configure" and needs
|
|
113
|
+
* `calendar.settings.readonly` — a scope we do not request and could not add
|
|
114
|
+
* without sending every already-connected user back through consent. The
|
|
115
|
+
* primary calendar's zone is the same value in every case that matters, and
|
|
116
|
+
* `calendar.readonly` already covers it.
|
|
117
|
+
*
|
|
118
|
+
* Returns null on any failure. Not knowing the zone is a state the callers
|
|
119
|
+
* handle; a throw here would take a tool call or a chat turn with it.
|
|
120
|
+
*/
|
|
121
|
+
export const fetchGoogleCalendarTimeZone = async (
|
|
122
|
+
accessToken: string
|
|
123
|
+
): Promise<string | null> => {
|
|
124
|
+
try {
|
|
125
|
+
const response = await fetch(
|
|
126
|
+
`${constants.GOOGLE_CALENDAR_API_BASE}/calendars/primary`,
|
|
127
|
+
{
|
|
128
|
+
headers: {
|
|
129
|
+
Authorization: `Bearer ${accessToken}`,
|
|
130
|
+
Accept: 'application/json'
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
if (!response.ok) return null;
|
|
135
|
+
const payload = (await response.json()) as { timeZone?: unknown };
|
|
136
|
+
return isValidTimeZone(payload?.timeZone) ? payload.timeZone.trim() : null;
|
|
137
|
+
} catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The zone on the connected Cal.com profile.
|
|
144
|
+
*
|
|
145
|
+
* This is the host's zone — the one their availability is written in — which
|
|
146
|
+
* is what "9am" means when the artifact owner or their bot says it. It is not
|
|
147
|
+
* the attendee's zone; see the booking handler for why we use it there anyway.
|
|
148
|
+
*
|
|
149
|
+
* Same null-on-failure contract as the Google reader above.
|
|
150
|
+
*/
|
|
151
|
+
export const fetchCalcomTimeZone = async (
|
|
152
|
+
apiKey: string
|
|
153
|
+
): Promise<string | null> => {
|
|
154
|
+
try {
|
|
155
|
+
const response = await fetch(`${constants.CALCOM_API_BASE}/me`, {
|
|
156
|
+
headers: {
|
|
157
|
+
Authorization: `Bearer ${apiKey}`,
|
|
158
|
+
'cal-api-version': constants.CALCOM_API_VERSION_ME,
|
|
159
|
+
Accept: 'application/json'
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
if (!response.ok) return null;
|
|
163
|
+
const payload = (await response.json()) as {
|
|
164
|
+
data?: { timeZone?: unknown };
|
|
165
|
+
};
|
|
166
|
+
const value = payload?.data?.timeZone;
|
|
167
|
+
return isValidTimeZone(value) ? value.trim() : null;
|
|
168
|
+
} catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
};
|