@ganju/utils 0.0.5 → 0.0.8
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/attachment.d.ts.map +1 -1
- package/dist/chunking.d.ts.map +1 -1
- package/dist/chunking.js +9 -3
- package/dist/coerce.d.ts.map +1 -1
- package/dist/coerce.js +4 -1
- package/dist/constants.d.ts +25 -3
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +131 -12
- package/dist/containmentToken.d.ts +25 -0
- package/dist/containmentToken.d.ts.map +1 -0
- package/dist/containmentToken.js +81 -0
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +4 -1
- package/dist/getEnv.d.ts.map +1 -1
- package/dist/index.d.ts +33 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/oauth.d.ts.map +1 -1
- package/dist/parseHttpError.d.ts.map +1 -1
- package/dist/sources.d.ts.map +1 -1
- package/dist/vendorError.d.ts.map +1 -1
- 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/attachment.ts +2 -1
- package/src/chunking.ts +9 -3
- package/src/coerce.ts +4 -1
- package/src/constants.ts +148 -12
- package/src/containmentToken.ts +146 -0
- package/src/crypto.ts +6 -2
- package/src/getEnv.ts +1 -4
- package/src/index.ts +22 -0
- package/src/oauth.ts +1 -3
- package/src/parseHttpError.ts +3 -1
- package/src/slackSend.ts +10 -10
- package/src/sources.ts +7 -2
- package/src/vendorError.ts +4 -1
- package/src/vendorTimeZone.ts +171 -0
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ const validateMessageVariables_1 = require("./validateMessageVariables");
|
|
|
18
18
|
const jsonSchemaToZodShape_1 = require("./jsonSchemaToZodShape");
|
|
19
19
|
const mcpProxy_1 = require("./mcpProxy");
|
|
20
20
|
const customCodeToken_1 = require("./customCodeToken");
|
|
21
|
+
const containmentToken_1 = require("./containmentToken");
|
|
21
22
|
const oauthProviders_1 = require("./oauthProviders");
|
|
22
23
|
const attachment_1 = require("./attachment");
|
|
23
24
|
const exposedResource_1 = require("./exposedResource");
|
|
@@ -45,6 +46,7 @@ const channelNotifier_1 = require("./channelNotifier");
|
|
|
45
46
|
const channelDebounce_1 = require("./channelDebounce");
|
|
46
47
|
const sources_1 = require("./sources");
|
|
47
48
|
const oauth_1 = require("./oauth");
|
|
49
|
+
const vendorTimeZone_1 = require("./vendorTimeZone");
|
|
48
50
|
const planLimitError_1 = require("./planLimitError");
|
|
49
51
|
exports.utils = {
|
|
50
52
|
Schema: schema_1.Schema,
|
|
@@ -92,6 +94,8 @@ exports.utils = {
|
|
|
92
94
|
customCodePreviewScriptName: customCodeToken_1.customCodePreviewScriptName,
|
|
93
95
|
customCodeUploadName: customCodeToken_1.customCodeUploadName,
|
|
94
96
|
customCodePreviewUploadName: customCodeToken_1.customCodePreviewUploadName,
|
|
97
|
+
mintContainmentToken: containmentToken_1.mintContainmentToken,
|
|
98
|
+
verifyContainmentToken: containmentToken_1.verifyContainmentToken,
|
|
95
99
|
oauthProviders: oauthProviders_1.oauthProviders,
|
|
96
100
|
resolveAttachment: attachment_1.resolveAttachment,
|
|
97
101
|
isExposedResource: exposedResource_1.isExposedResource,
|
|
@@ -157,6 +161,12 @@ exports.utils = {
|
|
|
157
161
|
buildReauthMetadata: oauth_1.buildReauthMetadata,
|
|
158
162
|
clearReauthMetadata: oauth_1.clearReauthMetadata,
|
|
159
163
|
isCredentialNeedingReauth: oauth_1.isCredentialNeedingReauth,
|
|
164
|
+
isValidTimeZone: vendorTimeZone_1.isValidTimeZone,
|
|
165
|
+
readCredentialTimeZone: vendorTimeZone_1.readCredentialTimeZone,
|
|
166
|
+
credentialTimeZoneIsStale: vendorTimeZone_1.credentialTimeZoneIsStale,
|
|
167
|
+
writeCredentialTimeZone: vendorTimeZone_1.writeCredentialTimeZone,
|
|
168
|
+
fetchGoogleCalendarTimeZone: vendorTimeZone_1.fetchGoogleCalendarTimeZone,
|
|
169
|
+
fetchCalcomTimeZone: vendorTimeZone_1.fetchCalcomTimeZone,
|
|
160
170
|
PlanLimitError: planLimitError_1.PlanLimitError,
|
|
161
171
|
isPlanLimitError: planLimitError_1.isPlanLimitError
|
|
162
172
|
};
|
package/dist/oauth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM;CAKzB;AAUD,eAAO,MAAM,iBAAiB,GAC5B,OAAO,sBAAsB,KAC5B,OAAO,CAAC,mBAAmB,CAsC7B,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACxC,QAAQ,MAAM,KACb,MAAM,CAAC,MAAM,EAAE,OAAO,CAKvB,CAAC;AAEH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,KACvC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAO5B,CAAC;AAEF,eAAO,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM;CAKzB;AAUD,eAAO,MAAM,iBAAiB,GAC5B,OAAO,sBAAsB,KAC5B,OAAO,CAAC,mBAAmB,CAsC7B,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACxC,QAAQ,MAAM,KACb,MAAM,CAAC,MAAM,EAAE,OAAO,CAKvB,CAAC;AAEH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,KACvC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAO5B,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,UAAU,OAAO,KAAG,OAG7D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseHttpError.d.ts","sourceRoot":"","sources":["../src/parseHttpError.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"parseHttpError.d.ts","sourceRoot":"","sources":["../src/parseHttpError.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,GAChC,UAAU,QAAQ,KACjB,OAAO,CAAC,MAAM,CAehB,CAAC"}
|
package/dist/sources.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sources.d.ts","sourceRoot":"","sources":["../src/sources.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"sources.d.ts","sourceRoot":"","sources":["../src/sources.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,GAC/B,YAAY,MAAM,CAAC,YAAY,CAAC,KAC/B,OAEwD,CAAC;AAE5D,eAAO,MAAM,uBAAuB,GAClC,UAAU;IAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,KAC1D,OAEwB,CAAC;AAE5B,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAGnD,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,KAAK,kBAAkB,EACvB,YAAY,MAAM,EAClB,aAAa,MAAM,KAClB,MAGF,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAKD,eAAO,MAAM,sBAAsB,GACjC,SAAS,MAAM,EAAE,EACjB,KAAK,kBAAkB,EACvB,UAAU;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,KACpC,YAAY,EA2Bd,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,SAAS,MAAM,EAAE,EACjB,KAAK,kBAAkB,KACtB,MAmBF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vendorError.d.ts","sourceRoot":"","sources":["../src/vendorError.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"vendorError.d.ts","sourceRoot":"","sources":["../src/vendorError.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,mBAAmB,GAC9B,MAAM,OAAO,EACb,UAAU,MAAM,KACf,MASF,CAAC"}
|
|
@@ -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/attachment.ts
CHANGED
|
@@ -28,7 +28,8 @@ export interface ResolvedAttachment {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export type ResolveAttachmentResult =
|
|
31
|
-
{ ok: true; attachment: ResolvedAttachment }
|
|
31
|
+
| { ok: true; attachment: ResolvedAttachment }
|
|
32
|
+
| { ok: false; error: string };
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* Resolve one resource's attachment bytes.
|
package/src/chunking.ts
CHANGED
|
@@ -37,7 +37,9 @@ export const splitRecursive = (
|
|
|
37
37
|
}
|
|
38
38
|
if (current) chunks.push(current);
|
|
39
39
|
return chunks.flatMap(chunk =>
|
|
40
|
-
chunk.length > target
|
|
40
|
+
chunk.length > target
|
|
41
|
+
? splitRecursive(chunk, target, separators)
|
|
42
|
+
: [chunk]
|
|
41
43
|
);
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -104,7 +106,9 @@ export const prepareChunks = (
|
|
|
104
106
|
if (documents && documents.length > 0) {
|
|
105
107
|
const out: PreparedChunk[] = [];
|
|
106
108
|
documents.forEach((doc, docIndex) => {
|
|
107
|
-
const body = (doc.pageContent || '')
|
|
109
|
+
const body = (doc.pageContent || '')
|
|
110
|
+
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '')
|
|
111
|
+
.trim();
|
|
108
112
|
if (!body) return;
|
|
109
113
|
const text = docIndex === 0 && header ? `${header}\n\n${body}` : body;
|
|
110
114
|
const pieces = chunkText(text, options);
|
|
@@ -122,7 +126,9 @@ export const prepareChunks = (
|
|
|
122
126
|
return out;
|
|
123
127
|
}
|
|
124
128
|
|
|
125
|
-
const body = (fallbackContent || '')
|
|
129
|
+
const body = (fallbackContent || '')
|
|
130
|
+
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '')
|
|
131
|
+
.trim();
|
|
126
132
|
const fullText = [header, body].filter(Boolean).join('\n\n');
|
|
127
133
|
return chunkText(fullText, options).map(content => ({
|
|
128
134
|
content,
|
package/src/coerce.ts
CHANGED
|
@@ -3,7 +3,10 @@ export const toStringArray = (input: unknown): string[] => {
|
|
|
3
3
|
return input.map(s => String(s).trim()).filter(Boolean);
|
|
4
4
|
}
|
|
5
5
|
if (typeof input === 'string' && input.trim()) {
|
|
6
|
-
return input
|
|
6
|
+
return input
|
|
7
|
+
.split(',')
|
|
8
|
+
.map(s => s.trim())
|
|
9
|
+
.filter(Boolean);
|
|
7
10
|
}
|
|
8
11
|
return [];
|
|
9
12
|
};
|
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
|
|
|
@@ -1810,7 +1811,8 @@ const PLAN_PRO = 'PRO' as 'PRO';
|
|
|
1810
1811
|
const PLAN_ENTERPRISE = 'ENTERPRISE' as 'ENTERPRISE';
|
|
1811
1812
|
const PLANS = [PLAN_FREE, PLAN_PRO, PLAN_ENTERPRISE];
|
|
1812
1813
|
|
|
1813
|
-
//
|
|
1814
|
+
// The provider's subscription statuses, mirrored so the webhook can store them
|
|
1815
|
+
// verbatim.
|
|
1814
1816
|
const SUBSCRIPTION_STATUS_ACTIVE = 'active' as 'active';
|
|
1815
1817
|
const SUBSCRIPTION_STATUS_TRIALING = 'trialing' as 'trialing';
|
|
1816
1818
|
const SUBSCRIPTION_STATUS_PAST_DUE = 'past_due' as 'past_due';
|
|
@@ -1890,6 +1892,30 @@ const PRICING_SHARED_KEY_HARD_CAP = 100_000;
|
|
|
1890
1892
|
// so $2 is now roughly break-even. Raising CHUNK_TARGET_CHARS would tip it
|
|
1891
1893
|
// positive without touching this number.
|
|
1892
1894
|
const PRICING_EMBEDDED_PER_GB_USD = 2;
|
|
1895
|
+
// Custom-tool invocations included per month, and the rate beyond them.
|
|
1896
|
+
//
|
|
1897
|
+
// "Tool call" here means one dispatch into a user's own script on Workers for
|
|
1898
|
+
// Platforms — NOT a call to a shipped integration or a proxied server. Those
|
|
1899
|
+
// cost us one screened fetch from a Worker we already pay for, which is why they
|
|
1900
|
+
// stay bundled; this one runs the customer's code on our infrastructure, and is
|
|
1901
|
+
// the first cost axis a user can turn against us rather than merely consume.
|
|
1902
|
+
//
|
|
1903
|
+
// Cloudflare bills the whole chain (dispatcher → user script → outbound worker)
|
|
1904
|
+
// as ONE request and counts CPU across all three, so a call costs ~$2.30 per
|
|
1905
|
+
// million at the per-script CPU ceiling. $5/M is ~2x that, and 1,000,000 is far
|
|
1906
|
+
// past any real month: the heaviest worked customer in the cost model makes
|
|
1907
|
+
// 800,000, and a single artifact pinned at its rate limit for a full month
|
|
1908
|
+
// manages ~2.6 million.
|
|
1909
|
+
const PRICING_INCLUDED_TOOL_CALLS = 1_000_000;
|
|
1910
|
+
const PRICING_TOOL_CALL_PER_M_USD = 5;
|
|
1911
|
+
// Abuse backstop on custom-tool invocations — the compute analogue of
|
|
1912
|
+
// PRICING_SHARED_KEY_HARD_CAP, and needed for the same reason: past a point,
|
|
1913
|
+
// usage stops looking like a customer and starts looking like a runaway loop or
|
|
1914
|
+
// a stolen credential. 20x the included allowance is ~$46 of compute against
|
|
1915
|
+
// ~$95 billed, and takes eight artifacts held at their rate limit for a month to
|
|
1916
|
+
// reach. Enterprise is null — the cost model's own enterprise example makes 20
|
|
1917
|
+
// million calls a month, so a fixed ceiling there would fight a real customer.
|
|
1918
|
+
const PRICING_TOOL_CALL_HARD_CAP = 20_000_000;
|
|
1893
1919
|
const PRICING_CUSTOM_DOMAIN_USD = 15;
|
|
1894
1920
|
|
|
1895
1921
|
interface PlanLimits {
|
|
@@ -1933,6 +1959,20 @@ interface PlanLimits {
|
|
|
1933
1959
|
// keeps that from becoming an unbounded tool list on the plan that runs on our
|
|
1934
1960
|
// model key. `null` = no limit.
|
|
1935
1961
|
maxHttpEndpointsPerArtifact: number | null;
|
|
1962
|
+
// Monthly allowance of CUSTOM-TOOL invocations — dispatches into the org's own
|
|
1963
|
+
// code. A billing threshold like includedSharedMessages, not a block: past it
|
|
1964
|
+
// paid plans keep running and meter at the per-million rate.
|
|
1965
|
+
//
|
|
1966
|
+
// Only custom code counts. A shipped integration or a proxied server costs one
|
|
1967
|
+
// screened fetch, so metering those would bill a customer for something that
|
|
1968
|
+
// rounds to zero and make the tool list a thing to ration.
|
|
1969
|
+
includedToolCalls: number;
|
|
1970
|
+
// Absolute stop on custom-tool invocations, regardless of billing. The
|
|
1971
|
+
// compute-side twin of sharedKeyHardCap, and the only limit on this axis that
|
|
1972
|
+
// an infinite loop inside someone's tool actually meets — the per-script CPU
|
|
1973
|
+
// ceiling bounds one call, the per-artifact rate limiter bounds calls per
|
|
1974
|
+
// minute, and this bounds the month. `null` = no backstop.
|
|
1975
|
+
toolCallHardCap: number | null;
|
|
1936
1976
|
// Display-only allowances included in the plan (what overage is measured
|
|
1937
1977
|
// against). Not used for blocking.
|
|
1938
1978
|
includedMessages: number;
|
|
@@ -1966,6 +2006,15 @@ const PLAN_LIMITS: Record<
|
|
|
1966
2006
|
canUseCustomLlm: false,
|
|
1967
2007
|
canUseCustomCode: false,
|
|
1968
2008
|
maxHttpEndpointsPerArtifact: 3,
|
|
2009
|
+
// Free can't deploy custom code, so the only way to have a running script on
|
|
2010
|
+
// this plan is to have DOWNGRADED with one already published — a paid org
|
|
2011
|
+
// keeps its versions and their bundles. Those tools go on serving, because
|
|
2012
|
+
// killing a customer's live integrations the moment a card fails is a worse
|
|
2013
|
+
// failure than serving a bounded number of calls while they fix it. This is
|
|
2014
|
+
// that bound: real breathing room, ~$0.02 of compute, and no overage path
|
|
2015
|
+
// off Free to turn it into a bill.
|
|
2016
|
+
includedToolCalls: 0,
|
|
2017
|
+
toolCallHardCap: 10_000,
|
|
1969
2018
|
includedMessages: 100,
|
|
1970
2019
|
includedEmbeddedBytes: 5 * MB
|
|
1971
2020
|
},
|
|
@@ -1987,6 +2036,8 @@ const PLAN_LIMITS: Record<
|
|
|
1987
2036
|
canUseCustomLlm: true,
|
|
1988
2037
|
canUseCustomCode: true,
|
|
1989
2038
|
maxHttpEndpointsPerArtifact: null,
|
|
2039
|
+
includedToolCalls: PRICING_INCLUDED_TOOL_CALLS,
|
|
2040
|
+
toolCallHardCap: PRICING_TOOL_CALL_HARD_CAP,
|
|
1990
2041
|
includedMessages: PRICING_INCLUDED_MESSAGES,
|
|
1991
2042
|
includedEmbeddedBytes: PRICING_INCLUDED_EMBEDDED_GB * GB
|
|
1992
2043
|
},
|
|
@@ -2004,6 +2055,12 @@ const PLAN_LIMITS: Record<
|
|
|
2004
2055
|
canUseCustomLlm: true,
|
|
2005
2056
|
canUseCustomCode: true,
|
|
2006
2057
|
maxHttpEndpointsPerArtifact: null,
|
|
2058
|
+
includedToolCalls: PRICING_INCLUDED_TOOL_CALLS,
|
|
2059
|
+
// No backstop: an Enterprise contract is negotiated against real volume, and
|
|
2060
|
+
// the reference deal in the cost model runs 20 million calls a month — the
|
|
2061
|
+
// exact number a Pro-shaped ceiling would refuse. Raise the ceiling by
|
|
2062
|
+
// contract; don't make one plan's abuse limit another plan's product limit.
|
|
2063
|
+
toolCallHardCap: null,
|
|
2007
2064
|
includedMessages: PRICING_INCLUDED_MESSAGES,
|
|
2008
2065
|
includedEmbeddedBytes: PRICING_INCLUDED_EMBEDDED_GB * GB
|
|
2009
2066
|
}
|
|
@@ -2023,21 +2080,46 @@ const PLAN_FEATURE_HTTP_ENDPOINT = 'httpEndpoint' as 'httpEndpoint';
|
|
|
2023
2080
|
const PLAN_FEATURE_RAW_STORAGE = 'rawStorage' as 'rawStorage';
|
|
2024
2081
|
const PLAN_FEATURE_EMBEDDED_STORAGE = 'embeddedStorage' as 'embeddedStorage';
|
|
2025
2082
|
const PLAN_FEATURE_MESSAGE = 'message' as 'message';
|
|
2083
|
+
const PLAN_FEATURE_TOOL_CALL = 'toolCall' as 'toolCall';
|
|
2026
2084
|
|
|
2027
2085
|
// Stable code returned on a quota block so clients can branch on it (402).
|
|
2028
2086
|
const PLAN_LIMIT_ERROR_CODE = 'PLAN_LIMIT_EXCEEDED';
|
|
2029
2087
|
|
|
2030
|
-
//
|
|
2031
|
-
//
|
|
2032
|
-
//
|
|
2033
|
-
//
|
|
2088
|
+
// Billing meter event names. The metering cron reports per-period OVERAGE
|
|
2089
|
+
// (usage above the plan's included allowance) to these meters; the meters'
|
|
2090
|
+
// prices on the subscribed product turn that into charges. Embedded storage is
|
|
2091
|
+
// reported in whole MB, messages as a raw count.
|
|
2092
|
+
//
|
|
2093
|
+
// Each name must match the filter on its meter exactly. A mismatch is not an
|
|
2094
|
+
// error at either end — the event is accepted, matches no meter, and the usage
|
|
2095
|
+
// is silently unbilled.
|
|
2034
2096
|
//
|
|
2035
2097
|
// Messages report to two separate meters because the two kinds of turn bill at
|
|
2036
2098
|
// different rates — a turn on the org's own key is a platform fee, a turn on our
|
|
2037
2099
|
// model is inference we bought. One meter can't price both.
|
|
2038
|
-
const
|
|
2039
|
-
const
|
|
2040
|
-
const
|
|
2100
|
+
const BILLING_METER_MESSAGES = 'ganju_channel_messages';
|
|
2101
|
+
const BILLING_METER_SHARED_MESSAGES = 'ganju_shared_messages';
|
|
2102
|
+
const BILLING_METER_EMBEDDED = 'ganju_embedded_storage';
|
|
2103
|
+
// Custom-tool invocations, reported as a raw count of the calls above the
|
|
2104
|
+
// included allowance and priced per call at $5/1,000,000. Metered prices are
|
|
2105
|
+
// per single unit, so a partial block is billed as the fraction it is — a
|
|
2106
|
+
// customer 2.5 million past the allowance owes $12.50, which is what every page
|
|
2107
|
+
// of ours quotes.
|
|
2108
|
+
const BILLING_METER_TOOL_CALLS = 'ganju_custom_tool_calls';
|
|
2109
|
+
|
|
2110
|
+
// The metadata property every meter aggregates (`sum` over it). Ingested events
|
|
2111
|
+
// carry the increment under this key, so it has to agree with the aggregation
|
|
2112
|
+
// configured on all four meters — which is why it lives beside their names
|
|
2113
|
+
// rather than at the call site.
|
|
2114
|
+
const BILLING_METER_UNITS_KEY = 'units';
|
|
2115
|
+
|
|
2116
|
+
// Polar API hosts. Sandbox is a separate host rather than a mode flag, so the
|
|
2117
|
+
// account, products, meters and webhook secret there are all distinct from
|
|
2118
|
+
// production's — which is what `POLAR_SERVER` selects between.
|
|
2119
|
+
const POLAR_API_BASE = 'https://api.polar.sh';
|
|
2120
|
+
const POLAR_SANDBOX_API_BASE = 'https://sandbox-api.polar.sh';
|
|
2121
|
+
const POLAR_SERVER_SANDBOX = 'sandbox' as 'sandbox';
|
|
2122
|
+
const POLAR_SERVER_PRODUCTION = 'production' as 'production';
|
|
2041
2123
|
|
|
2042
2124
|
// Legal documents a user accepts, and the version they're on. Bump the version
|
|
2043
2125
|
// when the document changes materially — existing users are then re-prompted,
|
|
@@ -2046,7 +2128,7 @@ const STRIPE_METER_EMBEDDED = 'ganju_embedded_storage';
|
|
|
2046
2128
|
const CONSENT_DOCUMENT_TERMS = 'terms' as 'terms';
|
|
2047
2129
|
const CONSENT_DOCUMENT_PRIVACY = 'privacy' as 'privacy';
|
|
2048
2130
|
const CONSENT_DOCUMENTS = [CONSENT_DOCUMENT_TERMS, CONSENT_DOCUMENT_PRIVACY];
|
|
2049
|
-
const CONSENT_CURRENT_VERSION = '2026-08-
|
|
2131
|
+
const CONSENT_CURRENT_VERSION = '2026-08-31';
|
|
2050
2132
|
|
|
2051
2133
|
const CONSENT_SOURCE_SIGNUP = 'signup' as 'signup';
|
|
2052
2134
|
const CONSENT_SOURCE_REACCEPT = 'reaccept' as 'reaccept';
|
|
@@ -2086,6 +2168,40 @@ const CRON_HOURLY = '0 * * * *';
|
|
|
2086
2168
|
const CRON_ERROR_ALERTS = '*/15 * * * *';
|
|
2087
2169
|
|
|
2088
2170
|
const ALERT_STATE_KEY_ERROR_LOG = 'error_log';
|
|
2171
|
+
// Custom-tool usage alerting, keyed per organization as `tool_calls:<id>`. The
|
|
2172
|
+
// monthly hard cap bounds what abuse can spend; these thresholds are what say
|
|
2173
|
+
// something is happening NOW, while there is still a month left to spend.
|
|
2174
|
+
const ALERT_STATE_KEY_TOOL_CALLS = 'tool_calls';
|
|
2175
|
+
// Calls in a single hour. The per-tool rate limit allows 3,600/hour, and a month
|
|
2176
|
+
// of the included million sustained is ~1,370/hour — so five figures in one hour
|
|
2177
|
+
// is either many artifacts at full tilt or something that should be looked at.
|
|
2178
|
+
const ALERT_TOOL_CALL_SURGE = 10_000;
|
|
2179
|
+
// The share of the abuse backstop at which the wall is close enough to warn
|
|
2180
|
+
// about. Half a month's ceiling reached is worth an email even if the rate is
|
|
2181
|
+
// unremarkable, because the alternative is a customer meeting it silently.
|
|
2182
|
+
const ALERT_TOOL_CALL_CAP_FRACTION = 0.5;
|
|
2183
|
+
// How long to stay quiet about one organization after alerting on it. Without
|
|
2184
|
+
// this a busy month is an hourly email, and an hourly email is a muted one.
|
|
2185
|
+
const ALERT_TOOL_CALL_COOLDOWN_HOURS = 6;
|
|
2186
|
+
// Organizations itemised in one digest.
|
|
2187
|
+
const ALERT_TOOL_CALL_MAX_ROWS = 25;
|
|
2188
|
+
|
|
2189
|
+
// The "stop these tools" link the usage digest carries.
|
|
2190
|
+
//
|
|
2191
|
+
// It exists because the alert travels and the response did not: every other
|
|
2192
|
+
// containment step needs a shell holding the production database URL, so an
|
|
2193
|
+
// abuse notice arriving away from a desk was one nobody could act on for hours.
|
|
2194
|
+
//
|
|
2195
|
+
// Narrow on purpose. It disables the organization's custom-code installs — the
|
|
2196
|
+
// tools stop registering at boot, the code, versions and settings all survive,
|
|
2197
|
+
// and any owner can switch them back on. It cannot delete a script, touch a
|
|
2198
|
+
// credential, or reach anything else.
|
|
2199
|
+
const CONTAINMENT_TOKEN_VERSION = '1';
|
|
2200
|
+
const CONTAINMENT_PURPOSE_DISABLE_CUSTOM_CODE = 'disable-custom-code';
|
|
2201
|
+
// Long enough to still work when the mail is read a few hours late, short enough
|
|
2202
|
+
// that a forwarded thread or an archived inbox is not a way in.
|
|
2203
|
+
const CONTAINMENT_TOKEN_TTL_MS = 12 * 60 * 60 * 1000;
|
|
2204
|
+
const CONTAINMENT_PATH = '/containment';
|
|
2089
2205
|
// Only alert on genuine server failures. 4xx rows are expected client errors
|
|
2090
2206
|
// (validation, not-found, quota) and would drown the signal.
|
|
2091
2207
|
const ALERT_MIN_STATUS = 500;
|
|
@@ -2130,6 +2246,9 @@ export const constants = {
|
|
|
2130
2246
|
PRICING_INCLUDED_EMBEDDED_GB,
|
|
2131
2247
|
PRICING_MESSAGE_PER_1K_USD,
|
|
2132
2248
|
PRICING_EMBEDDED_PER_GB_USD,
|
|
2249
|
+
PRICING_INCLUDED_TOOL_CALLS,
|
|
2250
|
+
PRICING_TOOL_CALL_PER_M_USD,
|
|
2251
|
+
PRICING_TOOL_CALL_HARD_CAP,
|
|
2133
2252
|
PRICING_CUSTOM_DOMAIN_USD,
|
|
2134
2253
|
PLAN_FEATURE_ORGANIZATION,
|
|
2135
2254
|
PLAN_FEATURE_PROJECT,
|
|
@@ -2143,10 +2262,17 @@ export const constants = {
|
|
|
2143
2262
|
PLAN_FEATURE_RAW_STORAGE,
|
|
2144
2263
|
PLAN_FEATURE_EMBEDDED_STORAGE,
|
|
2145
2264
|
PLAN_FEATURE_MESSAGE,
|
|
2265
|
+
PLAN_FEATURE_TOOL_CALL,
|
|
2146
2266
|
PLAN_LIMIT_ERROR_CODE,
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2267
|
+
BILLING_METER_MESSAGES,
|
|
2268
|
+
BILLING_METER_SHARED_MESSAGES,
|
|
2269
|
+
BILLING_METER_EMBEDDED,
|
|
2270
|
+
BILLING_METER_TOOL_CALLS,
|
|
2271
|
+
BILLING_METER_UNITS_KEY,
|
|
2272
|
+
POLAR_API_BASE,
|
|
2273
|
+
POLAR_SANDBOX_API_BASE,
|
|
2274
|
+
POLAR_SERVER_SANDBOX,
|
|
2275
|
+
POLAR_SERVER_PRODUCTION,
|
|
2150
2276
|
CONSENT_DOCUMENT_TERMS,
|
|
2151
2277
|
CONSENT_DOCUMENT_PRIVACY,
|
|
2152
2278
|
CONSENT_DOCUMENTS,
|
|
@@ -2160,6 +2286,15 @@ export const constants = {
|
|
|
2160
2286
|
CRON_HOURLY,
|
|
2161
2287
|
CRON_ERROR_ALERTS,
|
|
2162
2288
|
ALERT_STATE_KEY_ERROR_LOG,
|
|
2289
|
+
ALERT_STATE_KEY_TOOL_CALLS,
|
|
2290
|
+
ALERT_TOOL_CALL_SURGE,
|
|
2291
|
+
ALERT_TOOL_CALL_CAP_FRACTION,
|
|
2292
|
+
ALERT_TOOL_CALL_COOLDOWN_HOURS,
|
|
2293
|
+
ALERT_TOOL_CALL_MAX_ROWS,
|
|
2294
|
+
CONTAINMENT_TOKEN_VERSION,
|
|
2295
|
+
CONTAINMENT_PURPOSE_DISABLE_CUSTOM_CODE,
|
|
2296
|
+
CONTAINMENT_TOKEN_TTL_MS,
|
|
2297
|
+
CONTAINMENT_PATH,
|
|
2163
2298
|
ALERT_MIN_STATUS,
|
|
2164
2299
|
ALERT_MAX_ROWS,
|
|
2165
2300
|
ALERT_MAX_GROUPS,
|
|
@@ -2478,6 +2613,7 @@ export const constants = {
|
|
|
2478
2613
|
CALCOM_API_VERSION_EVENT_TYPES,
|
|
2479
2614
|
CALCOM_API_VERSION_SLOTS,
|
|
2480
2615
|
CALCOM_API_VERSION_BOOKINGS,
|
|
2616
|
+
CALCOM_API_VERSION_ME,
|
|
2481
2617
|
CALCOM_TOOL_KEY_PREFIX,
|
|
2482
2618
|
TAVILY_API_BASE,
|
|
2483
2619
|
TAVILY_SEARCH_DEPTH_BASIC,
|