@ganju/utils 0.0.1

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.
Files changed (220) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +9 -0
  3. package/README.md +23 -0
  4. package/dist/apiError.d.ts +3 -0
  5. package/dist/apiError.d.ts.map +1 -0
  6. package/dist/apiError.js +36 -0
  7. package/dist/attachment.d.ts +33 -0
  8. package/dist/attachment.d.ts.map +1 -0
  9. package/dist/attachment.js +59 -0
  10. package/dist/base64.d.ts +10 -0
  11. package/dist/base64.d.ts.map +1 -0
  12. package/dist/base64.js +50 -0
  13. package/dist/channelDebounce.d.ts +26 -0
  14. package/dist/channelDebounce.d.ts.map +1 -0
  15. package/dist/channelDebounce.js +35 -0
  16. package/dist/channelNotifier.d.ts +9 -0
  17. package/dist/channelNotifier.d.ts.map +1 -0
  18. package/dist/channelNotifier.js +31 -0
  19. package/dist/chunking.d.ts +28 -0
  20. package/dist/chunking.d.ts.map +1 -0
  21. package/dist/chunking.js +97 -0
  22. package/dist/cliConstants.d.ts +9 -0
  23. package/dist/cliConstants.d.ts.map +1 -0
  24. package/dist/cliConstants.js +47 -0
  25. package/dist/coerce.d.ts +2 -0
  26. package/dist/coerce.d.ts.map +1 -0
  27. package/dist/coerce.js +13 -0
  28. package/dist/constants.d.ts +624 -0
  29. package/dist/constants.d.ts.map +1 -0
  30. package/dist/constants.js +2220 -0
  31. package/dist/crypto.d.ts +14 -0
  32. package/dist/crypto.d.ts.map +1 -0
  33. package/dist/crypto.js +93 -0
  34. package/dist/customCodeProject.d.ts +91 -0
  35. package/dist/customCodeProject.d.ts.map +1 -0
  36. package/dist/customCodeProject.js +154 -0
  37. package/dist/customCodeToken.d.ts +41 -0
  38. package/dist/customCodeToken.d.ts.map +1 -0
  39. package/dist/customCodeToken.js +115 -0
  40. package/dist/deadline.d.ts +6 -0
  41. package/dist/deadline.d.ts.map +1 -0
  42. package/dist/deadline.js +45 -0
  43. package/dist/discordSend.d.ts +25 -0
  44. package/dist/discordSend.d.ts.map +1 -0
  45. package/dist/discordSend.js +8 -0
  46. package/dist/embeddable.d.ts +2 -0
  47. package/dist/embeddable.d.ts.map +1 -0
  48. package/dist/embeddable.js +6 -0
  49. package/dist/exposedResource.d.ts +6 -0
  50. package/dist/exposedResource.d.ts.map +1 -0
  51. package/dist/exposedResource.js +18 -0
  52. package/dist/extractedDocument.d.ts +70 -0
  53. package/dist/extractedDocument.d.ts.map +1 -0
  54. package/dist/extractedDocument.js +2 -0
  55. package/dist/fetcher.d.ts +8 -0
  56. package/dist/fetcher.d.ts.map +1 -0
  57. package/dist/fetcher.js +68 -0
  58. package/dist/formatFilename.d.ts +2 -0
  59. package/dist/formatFilename.d.ts.map +1 -0
  60. package/dist/formatFilename.js +19 -0
  61. package/dist/formatRelative.d.ts +12 -0
  62. package/dist/formatRelative.d.ts.map +1 -0
  63. package/dist/formatRelative.js +28 -0
  64. package/dist/formatRelativeTime.d.ts +2 -0
  65. package/dist/formatRelativeTime.d.ts.map +1 -0
  66. package/dist/formatRelativeTime.js +49 -0
  67. package/dist/getEnv.d.ts +5 -0
  68. package/dist/getEnv.d.ts.map +1 -0
  69. package/dist/getEnv.js +11 -0
  70. package/dist/gmailSend.d.ts +24 -0
  71. package/dist/gmailSend.d.ts.map +1 -0
  72. package/dist/gmailSend.js +9 -0
  73. package/dist/index.d.ts +2839 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/index.js +155 -0
  76. package/dist/jsonSchemaToZodShape.d.ts +38 -0
  77. package/dist/jsonSchemaToZodShape.d.ts.map +1 -0
  78. package/dist/jsonSchemaToZodShape.js +117 -0
  79. package/dist/l2Normalize.d.ts +2 -0
  80. package/dist/l2Normalize.d.ts.map +1 -0
  81. package/dist/l2Normalize.js +25 -0
  82. package/dist/languageCookieDomain.d.ts +21 -0
  83. package/dist/languageCookieDomain.d.ts.map +1 -0
  84. package/dist/languageCookieDomain.js +39 -0
  85. package/dist/localizeZodIssue.d.ts +43 -0
  86. package/dist/localizeZodIssue.d.ts.map +1 -0
  87. package/dist/localizeZodIssue.js +90 -0
  88. package/dist/mailHeaders.d.ts +4 -0
  89. package/dist/mailHeaders.d.ts.map +1 -0
  90. package/dist/mailHeaders.js +11 -0
  91. package/dist/mcpProxy.d.ts +2 -0
  92. package/dist/mcpProxy.d.ts.map +1 -0
  93. package/dist/mcpProxy.js +21 -0
  94. package/dist/mimeMessage.d.ts +21 -0
  95. package/dist/mimeMessage.d.ts.map +1 -0
  96. package/dist/mimeMessage.js +58 -0
  97. package/dist/oauth.d.ts +21 -0
  98. package/dist/oauth.d.ts.map +1 -0
  99. package/dist/oauth.js +75 -0
  100. package/dist/oauthProviders.d.ts +12 -0
  101. package/dist/oauthProviders.d.ts.map +1 -0
  102. package/dist/oauthProviders.js +99 -0
  103. package/dist/outlookSend.d.ts +19 -0
  104. package/dist/outlookSend.d.ts.map +1 -0
  105. package/dist/outlookSend.js +9 -0
  106. package/dist/parseHttpError.d.ts +2 -0
  107. package/dist/parseHttpError.d.ts.map +1 -0
  108. package/dist/parseHttpError.js +23 -0
  109. package/dist/planLimitError.d.ts +18 -0
  110. package/dist/planLimitError.d.ts.map +1 -0
  111. package/dist/planLimitError.js +35 -0
  112. package/dist/processQueueBatch.d.ts +17 -0
  113. package/dist/processQueueBatch.d.ts.map +1 -0
  114. package/dist/processQueueBatch.js +32 -0
  115. package/dist/reservedToolName.d.ts +16 -0
  116. package/dist/reservedToolName.d.ts.map +1 -0
  117. package/dist/reservedToolName.js +25 -0
  118. package/dist/resourceUri.d.ts +2 -0
  119. package/dist/resourceUri.d.ts.map +1 -0
  120. package/dist/resourceUri.js +19 -0
  121. package/dist/retry.d.ts +10 -0
  122. package/dist/retry.d.ts.map +1 -0
  123. package/dist/retry.js +37 -0
  124. package/dist/sanitize.d.ts +7 -0
  125. package/dist/sanitize.d.ts.map +1 -0
  126. package/dist/sanitize.js +69 -0
  127. package/dist/schema.d.ts +2175 -0
  128. package/dist/schema.d.ts.map +1 -0
  129. package/dist/schema.js +1382 -0
  130. package/dist/sdkConstants.d.ts +15 -0
  131. package/dist/sdkConstants.d.ts.map +1 -0
  132. package/dist/sdkConstants.js +43 -0
  133. package/dist/slackSend.d.ts +38 -0
  134. package/dist/slackSend.d.ts.map +1 -0
  135. package/dist/slackSend.js +14 -0
  136. package/dist/slug.d.ts +5 -0
  137. package/dist/slug.d.ts.map +1 -0
  138. package/dist/slug.js +34 -0
  139. package/dist/slugifyTitle.d.ts +2 -0
  140. package/dist/slugifyTitle.d.ts.map +1 -0
  141. package/dist/slugifyTitle.js +11 -0
  142. package/dist/sources.d.ts +43 -0
  143. package/dist/sources.d.ts.map +1 -0
  144. package/dist/sources.js +73 -0
  145. package/dist/ssrf.d.ts +3 -0
  146. package/dist/ssrf.d.ts.map +1 -0
  147. package/dist/ssrf.js +46 -0
  148. package/dist/tallyUsageKinds.d.ts +9 -0
  149. package/dist/tallyUsageKinds.d.ts.map +1 -0
  150. package/dist/tallyUsageKinds.js +20 -0
  151. package/dist/telegramSend.d.ts +28 -0
  152. package/dist/telegramSend.d.ts.map +1 -0
  153. package/dist/telegramSend.js +9 -0
  154. package/dist/toolCatalog.d.ts +452 -0
  155. package/dist/toolCatalog.d.ts.map +1 -0
  156. package/dist/toolCatalog.js +552 -0
  157. package/dist/validateMessageVariables.d.ts +7 -0
  158. package/dist/validateMessageVariables.d.ts.map +1 -0
  159. package/dist/validateMessageVariables.js +16 -0
  160. package/dist/vendorError.d.ts +2 -0
  161. package/dist/vendorError.d.ts.map +1 -0
  162. package/dist/vendorError.js +25 -0
  163. package/dist/whatsappSend.d.ts +31 -0
  164. package/dist/whatsappSend.d.ts.map +1 -0
  165. package/dist/whatsappSend.js +11 -0
  166. package/package.json +76 -0
  167. package/src/apiError.ts +40 -0
  168. package/src/attachment.ts +97 -0
  169. package/src/base64.ts +60 -0
  170. package/src/channelDebounce.ts +76 -0
  171. package/src/channelNotifier.ts +39 -0
  172. package/src/chunking.ts +131 -0
  173. package/src/cliConstants.ts +50 -0
  174. package/src/coerce.ts +9 -0
  175. package/src/constants.ts +2542 -0
  176. package/src/crypto.ts +108 -0
  177. package/src/customCodeProject.ts +182 -0
  178. package/src/customCodeToken.ts +198 -0
  179. package/src/deadline.ts +43 -0
  180. package/src/discordSend.ts +41 -0
  181. package/src/embeddable.ts +4 -0
  182. package/src/exposedResource.ts +40 -0
  183. package/src/extractedDocument.ts +62 -0
  184. package/src/fetcher.ts +82 -0
  185. package/src/formatFilename.ts +19 -0
  186. package/src/formatRelative.ts +36 -0
  187. package/src/formatRelativeTime.ts +45 -0
  188. package/src/getEnv.ts +13 -0
  189. package/src/gmailSend.ts +34 -0
  190. package/src/index.ts +397 -0
  191. package/src/jsonSchemaToZodShape.ts +111 -0
  192. package/src/l2Normalize.ts +19 -0
  193. package/src/languageCookieDomain.ts +37 -0
  194. package/src/localizeZodIssue.ts +124 -0
  195. package/src/mailHeaders.ts +12 -0
  196. package/src/mcpProxy.ts +20 -0
  197. package/src/mimeMessage.ts +82 -0
  198. package/src/oauth.ts +103 -0
  199. package/src/oauthProviders.ts +118 -0
  200. package/src/outlookSend.ts +44 -0
  201. package/src/parseHttpError.ts +16 -0
  202. package/src/planLimitError.ts +50 -0
  203. package/src/processQueueBatch.ts +46 -0
  204. package/src/reservedToolName.ts +27 -0
  205. package/src/resourceUri.ts +17 -0
  206. package/src/retry.ts +43 -0
  207. package/src/sanitize.ts +67 -0
  208. package/src/schema.ts +1624 -0
  209. package/src/sdkConstants.ts +44 -0
  210. package/src/slackSend.ts +65 -0
  211. package/src/slug.ts +37 -0
  212. package/src/slugifyTitle.ts +8 -0
  213. package/src/sources.ts +117 -0
  214. package/src/ssrf.ts +34 -0
  215. package/src/tallyUsageKinds.ts +20 -0
  216. package/src/telegramSend.ts +39 -0
  217. package/src/toolCatalog.ts +635 -0
  218. package/src/validateMessageVariables.ts +18 -0
  219. package/src/vendorError.ts +19 -0
  220. package/src/whatsappSend.ts +47 -0
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildMimeMessage = exports.chunkBase64 = exports.formatFilenameHeader = exports.sanitizeFilename = void 0;
4
+ const mailHeaders_1 = require("./mailHeaders");
5
+ const sanitizeFilename = (name) => {
6
+ const cleaned = name.replace(/[\r\n"]/g, '').trim();
7
+ return cleaned || 'attachment';
8
+ };
9
+ exports.sanitizeFilename = sanitizeFilename;
10
+ const formatFilenameHeader = (name) => {
11
+ const safe = (0, exports.sanitizeFilename)(name);
12
+ if (/^[\x20-\x7E]+$/.test(safe)) {
13
+ return `filename="${safe.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
14
+ }
15
+ return `filename*=UTF-8''${encodeURIComponent(safe)}`;
16
+ };
17
+ exports.formatFilenameHeader = formatFilenameHeader;
18
+ const chunkBase64 = (b64) => b64.replace(/(.{76})/g, '$1\r\n');
19
+ exports.chunkBase64 = chunkBase64;
20
+ const buildMimeMessage = (input) => {
21
+ const headers = [];
22
+ headers.push(`To: ${(0, mailHeaders_1.formatMailHeader)(input.to)}`);
23
+ if (input.cc)
24
+ headers.push(`Cc: ${(0, mailHeaders_1.formatMailHeader)(input.cc)}`);
25
+ if (input.bcc)
26
+ headers.push(`Bcc: ${(0, mailHeaders_1.formatMailHeader)(input.bcc)}`);
27
+ headers.push(`Subject: ${(0, mailHeaders_1.formatMailHeader)(input.subject)}`);
28
+ if (input.inReplyTo)
29
+ headers.push(`In-Reply-To: ${(0, mailHeaders_1.sanitizeMailHeader)(input.inReplyTo)}`);
30
+ if (input.references)
31
+ headers.push(`References: ${(0, mailHeaders_1.sanitizeMailHeader)(input.references)}`);
32
+ headers.push('MIME-Version: 1.0');
33
+ const bodyContentType = input.contentType || 'text/html';
34
+ if (!input.attachments || input.attachments.length === 0) {
35
+ headers.push(`Content-Type: ${bodyContentType}; charset=utf-8`);
36
+ return `${headers.join('\r\n')}\r\n\r\n${input.body}`;
37
+ }
38
+ const boundary = `_ganju_${crypto.randomUUID().replace(/-/g, '')}`;
39
+ headers.push(`Content-Type: multipart/mixed; boundary="${boundary}"`);
40
+ const parts = [headers.join('\r\n'), ''];
41
+ parts.push(`--${boundary}`);
42
+ parts.push(`Content-Type: ${bodyContentType}; charset=utf-8`);
43
+ parts.push('Content-Transfer-Encoding: 7bit');
44
+ parts.push('');
45
+ parts.push(input.body);
46
+ for (const att of input.attachments) {
47
+ const safeName = (0, exports.sanitizeFilename)(att.filename);
48
+ parts.push(`--${boundary}`);
49
+ parts.push(`Content-Type: ${att.mimeType}; name="${safeName.replace(/"/g, '\\"')}"`);
50
+ parts.push('Content-Transfer-Encoding: base64');
51
+ parts.push(`Content-Disposition: attachment; ${(0, exports.formatFilenameHeader)(att.filename)}`);
52
+ parts.push('');
53
+ parts.push((0, exports.chunkBase64)(att.base64));
54
+ }
55
+ parts.push(`--${boundary}--`);
56
+ return parts.join('\r\n');
57
+ };
58
+ exports.buildMimeMessage = buildMimeMessage;
@@ -0,0 +1,21 @@
1
+ export interface RefreshOAuthTokenInput {
2
+ tokenUrl: string;
3
+ clientId: string;
4
+ clientSecret: string;
5
+ refreshToken: string;
6
+ }
7
+ export interface RefreshedOAuthToken {
8
+ accessToken: string;
9
+ refreshToken?: string;
10
+ expiresIn?: number;
11
+ scope?: string;
12
+ }
13
+ export declare class OAuthReauthRequiredError extends Error {
14
+ readonly code: string;
15
+ constructor(code: string);
16
+ }
17
+ export declare const refreshOAuthToken: (input: RefreshOAuthTokenInput) => Promise<RefreshedOAuthToken>;
18
+ export declare const buildReauthMetadata: (previous: Record<string, unknown> | null, reason: string) => Record<string, unknown>;
19
+ export declare const clearReauthMetadata: (previous: Record<string, unknown> | null) => Record<string, unknown> | null;
20
+ export declare const isCredentialNeedingReauth: (metadata: unknown) => boolean;
21
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +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,GACpC,UAAU,OAAO,KAChB,OAGF,CAAC"}
package/dist/oauth.js ADDED
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isCredentialNeedingReauth = exports.clearReauthMetadata = exports.buildReauthMetadata = exports.refreshOAuthToken = exports.OAuthReauthRequiredError = void 0;
4
+ const constants_1 = require("./constants");
5
+ class OAuthReauthRequiredError extends Error {
6
+ code;
7
+ constructor(code) {
8
+ super(`OAuth reauth required (${code})`);
9
+ this.name = 'OAuthReauthRequiredError';
10
+ this.code = code;
11
+ }
12
+ }
13
+ exports.OAuthReauthRequiredError = OAuthReauthRequiredError;
14
+ const parseErrorCode = (body) => {
15
+ try {
16
+ return JSON.parse(body)?.error;
17
+ }
18
+ catch {
19
+ return undefined;
20
+ }
21
+ };
22
+ const refreshOAuthToken = async (input) => {
23
+ const response = await fetch(input.tokenUrl, {
24
+ method: 'POST',
25
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
26
+ body: new URLSearchParams({
27
+ client_id: input.clientId,
28
+ client_secret: input.clientSecret,
29
+ grant_type: 'refresh_token',
30
+ refresh_token: input.refreshToken
31
+ })
32
+ });
33
+ if (!response.ok) {
34
+ const body = await response.text();
35
+ const code = parseErrorCode(body);
36
+ if (code && constants_1.constants.REAUTH_ERROR_CODES.includes(code)) {
37
+ throw new OAuthReauthRequiredError(code);
38
+ }
39
+ throw new Error(`oauth refresh failed (${response.status}): ${body}`);
40
+ }
41
+ const tokens = (await response.json());
42
+ if (!tokens.access_token) {
43
+ throw new Error('oauth refresh missing access_token');
44
+ }
45
+ return {
46
+ accessToken: tokens.access_token,
47
+ refreshToken: tokens.refresh_token,
48
+ expiresIn: tokens.expires_in,
49
+ scope: tokens.scope
50
+ };
51
+ };
52
+ exports.refreshOAuthToken = refreshOAuthToken;
53
+ const buildReauthMetadata = (previous, reason) => ({
54
+ ...(previous || {}),
55
+ needsReauth: true,
56
+ reauthReason: reason,
57
+ reauthAt: new Date().toISOString()
58
+ });
59
+ exports.buildReauthMetadata = buildReauthMetadata;
60
+ const clearReauthMetadata = (previous) => {
61
+ if (!previous)
62
+ return null;
63
+ const next = { ...previous };
64
+ delete next.needsReauth;
65
+ delete next.reauthReason;
66
+ delete next.reauthAt;
67
+ return Object.keys(next).length > 0 ? next : null;
68
+ };
69
+ exports.clearReauthMetadata = clearReauthMetadata;
70
+ const isCredentialNeedingReauth = (metadata) => {
71
+ if (!metadata || typeof metadata !== 'object')
72
+ return false;
73
+ return metadata.needsReauth === true;
74
+ };
75
+ exports.isCredentialNeedingReauth = isCredentialNeedingReauth;
@@ -0,0 +1,12 @@
1
+ export interface OAuthProviderConfig {
2
+ authUrl: string;
3
+ tokenUrl: string;
4
+ clientIdEnv: string;
5
+ clientSecretEnv: string;
6
+ defaultScopes: string[];
7
+ scopeParam?: 'scope' | 'user_scope';
8
+ tokenSource?: 'top' | 'authed_user';
9
+ omitGrantType?: boolean;
10
+ }
11
+ export declare const oauthProviders: Record<string, OAuthProviderConfig>;
12
+ //# sourceMappingURL=oauthProviders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauthProviders.d.ts","sourceRoot":"","sources":["../src/oauthProviders.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;IAIxB,UAAU,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;IAIpC,WAAW,CAAC,EAAE,KAAK,GAAG,aAAa,CAAC;IAKpC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAQD,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAwF9D,CAAC"}
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.oauthProviders = void 0;
4
+ const constants_1 = require("./constants");
5
+ // The managed OAuth apps we run. This lives in @ganju/utils rather than in
6
+ // apps/api because three workers now need it: apps/api (the authorization flow),
7
+ // and apps/tool-broker, which mints short-lived access tokens for user code and
8
+ // must refresh with the same client credentials against the same token URLs.
9
+ // Adding a provider in one place and not the other is exactly the drift this
10
+ // prevents.
11
+ exports.oauthProviders = {
12
+ [constants_1.constants.OAUTH_PROVIDER_GOOGLE_GMAIL]: {
13
+ authUrl: constants_1.constants.GOOGLE_OAUTH_AUTH_URL,
14
+ tokenUrl: constants_1.constants.GOOGLE_OAUTH_TOKEN_URL,
15
+ clientIdEnv: 'GOOGLE_CLIENT_ID',
16
+ clientSecretEnv: 'GOOGLE_CLIENT_SECRET',
17
+ defaultScopes: [
18
+ 'https://www.googleapis.com/auth/gmail.readonly',
19
+ 'https://www.googleapis.com/auth/gmail.send',
20
+ 'https://www.googleapis.com/auth/gmail.modify',
21
+ 'https://www.googleapis.com/auth/gmail.compose',
22
+ 'https://www.googleapis.com/auth/gmail.labels'
23
+ ]
24
+ },
25
+ [constants_1.constants.OAUTH_PROVIDER_GOOGLE_DRIVE]: {
26
+ authUrl: constants_1.constants.GOOGLE_OAUTH_AUTH_URL,
27
+ tokenUrl: constants_1.constants.GOOGLE_OAUTH_TOKEN_URL,
28
+ clientIdEnv: 'GOOGLE_CLIENT_ID',
29
+ clientSecretEnv: 'GOOGLE_CLIENT_SECRET',
30
+ defaultScopes: [
31
+ 'https://www.googleapis.com/auth/drive.readonly',
32
+ 'https://www.googleapis.com/auth/drive.metadata.readonly'
33
+ ]
34
+ },
35
+ [constants_1.constants.OAUTH_PROVIDER_GOOGLE_CALENDAR]: {
36
+ authUrl: constants_1.constants.GOOGLE_OAUTH_AUTH_URL,
37
+ tokenUrl: constants_1.constants.GOOGLE_OAUTH_TOKEN_URL,
38
+ clientIdEnv: 'GOOGLE_CLIENT_ID',
39
+ clientSecretEnv: 'GOOGLE_CLIENT_SECRET',
40
+ defaultScopes: [
41
+ 'https://www.googleapis.com/auth/calendar.events',
42
+ 'https://www.googleapis.com/auth/calendar.readonly'
43
+ ]
44
+ },
45
+ [constants_1.constants.OAUTH_PROVIDER_MICROSOFT_OUTLOOK]: {
46
+ authUrl: constants_1.constants.MICROSOFT_OAUTH_AUTH_URL,
47
+ tokenUrl: constants_1.constants.MICROSOFT_OAUTH_TOKEN_URL,
48
+ clientIdEnv: 'MICROSOFT_CLIENT_ID',
49
+ clientSecretEnv: 'MICROSOFT_CLIENT_SECRET',
50
+ defaultScopes: [
51
+ 'https://graph.microsoft.com/Mail.ReadWrite',
52
+ 'https://graph.microsoft.com/Mail.Send',
53
+ 'https://graph.microsoft.com/User.Read',
54
+ 'offline_access'
55
+ ]
56
+ },
57
+ [constants_1.constants.OAUTH_PROVIDER_ONE_DRIVE]: {
58
+ authUrl: constants_1.constants.MICROSOFT_OAUTH_AUTH_URL,
59
+ tokenUrl: constants_1.constants.MICROSOFT_OAUTH_TOKEN_URL,
60
+ clientIdEnv: 'MICROSOFT_CLIENT_ID',
61
+ clientSecretEnv: 'MICROSOFT_CLIENT_SECRET',
62
+ defaultScopes: [
63
+ 'https://graph.microsoft.com/Files.Read',
64
+ 'https://graph.microsoft.com/Files.Read.All',
65
+ 'offline_access'
66
+ ]
67
+ },
68
+ [constants_1.constants.OAUTH_PROVIDER_SLACK]: {
69
+ authUrl: constants_1.constants.SLACK_OAUTH_AUTH_URL,
70
+ tokenUrl: constants_1.constants.SLACK_OAUTH_TOKEN_URL,
71
+ clientIdEnv: 'SLACK_CLIENT_ID',
72
+ clientSecretEnv: 'SLACK_CLIENT_SECRET',
73
+ defaultScopes: [
74
+ 'chat:write',
75
+ 'channels:read',
76
+ 'groups:read',
77
+ 'mpim:read',
78
+ 'im:read',
79
+ 'users:read',
80
+ 'users:read.email',
81
+ 'files:write'
82
+ ],
83
+ omitGrantType: true
84
+ },
85
+ [constants_1.constants.OAUTH_PROVIDER_SLACK_USER]: {
86
+ authUrl: constants_1.constants.SLACK_OAUTH_AUTH_URL,
87
+ tokenUrl: constants_1.constants.SLACK_OAUTH_TOKEN_URL,
88
+ clientIdEnv: 'SLACK_CLIENT_ID',
89
+ clientSecretEnv: 'SLACK_CLIENT_SECRET',
90
+ // search.messages is the only Slack endpoint that needs a user (xoxp)
91
+ // token. Kept as its own provider so the OAuth flow stays generic —
92
+ // scopes are requested in the user_scope bucket, and the access_token
93
+ // is read from authed_user on callback.
94
+ defaultScopes: ['search:read'],
95
+ scopeParam: 'user_scope',
96
+ tokenSource: 'authed_user',
97
+ omitGrantType: true
98
+ }
99
+ };
@@ -0,0 +1,19 @@
1
+ export type OutlookOperation = 'send-email' | 'reply-email' | 'forward-email' | 'create-draft' | 'update-draft';
2
+ export interface OutlookSendRequest {
3
+ accessToken: string;
4
+ operation: OutlookOperation;
5
+ body: string;
6
+ contentType?: 'html' | 'text';
7
+ to?: string;
8
+ subject?: string;
9
+ cc?: string;
10
+ bcc?: string;
11
+ messageId?: string;
12
+ replyAll?: boolean;
13
+ draftId?: string;
14
+ }
15
+ export interface OutlookSendResponse {
16
+ id: string;
17
+ conversationId?: string;
18
+ }
19
+ //# sourceMappingURL=outlookSend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outlookSend.d.ts","sourceRoot":"","sources":["../src/outlookSend.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,aAAa,GACb,eAAe,GACf,cAAc,GACd,cAAc,CAAC;AAEnB,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IAEb,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAG9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IAGb,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAIlC,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ // Wire protocol shared between the MCP worker (which builds the request) and
3
+ // the resource-handler container (which talks to Microsoft Graph).
4
+ //
5
+ // The worker sends a multipart/form-data POST with one `metadata` field (JSON
6
+ // matching OutlookSendRequest) and zero-or-more `attachment` fields. The
7
+ // container decides per-attachment whether to inline it in the Graph message
8
+ // JSON (≤3MB) or upload it via createUploadSession with chunked PUTs.
9
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ export declare const parseHttpErrorMessage: (response: Response) => Promise<string>;
2
+ //# sourceMappingURL=parseHttpError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseHttpError.d.ts","sourceRoot":"","sources":["../src/parseHttpError.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,GAAU,UAAU,QAAQ,KAAG,OAAO,CAAC,MAAM,CAe9E,CAAC"}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseHttpErrorMessage = void 0;
4
+ const parseHttpErrorMessage = async (response) => {
5
+ const raw = await response.text();
6
+ if (!raw)
7
+ return `${response.status} ${response.statusText}`;
8
+ try {
9
+ const parsed = JSON.parse(raw);
10
+ if (parsed?.error?.message && typeof parsed.error.message === 'string') {
11
+ return parsed.error.message;
12
+ }
13
+ if (typeof parsed?.error === 'string')
14
+ return parsed.error;
15
+ if (typeof parsed?.message === 'string')
16
+ return parsed.message;
17
+ return raw;
18
+ }
19
+ catch {
20
+ return raw;
21
+ }
22
+ };
23
+ exports.parseHttpErrorMessage = parseHttpErrorMessage;
@@ -0,0 +1,18 @@
1
+ export interface PlanLimitDetails {
2
+ feature: string;
3
+ plan: string;
4
+ limit?: number | null;
5
+ used?: number | null;
6
+ }
7
+ export declare class PlanLimitError extends Error {
8
+ readonly status = 402;
9
+ readonly code: string;
10
+ readonly feature: string;
11
+ readonly plan: string;
12
+ readonly limit: number | null;
13
+ readonly used: number | null;
14
+ constructor(message: string, details: PlanLimitDetails);
15
+ toBody(): Record<string, unknown>;
16
+ }
17
+ export declare const isPlanLimitError: (error: unknown) => error is PlanLimitError;
18
+ //# sourceMappingURL=planLimitError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planLimitError.d.ts","sourceRoot":"","sources":["../src/planLimitError.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAE/B,OAAO,EAAE,MAAM,CAAC;IAEhB,IAAI,EAAE,MAAM,CAAC;IAEb,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,MAAM,OAAO;IACtB,QAAQ,CAAC,IAAI,SAAmC;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;gBAEjB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB;IAWtD,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAUlC;AAED,eAAO,MAAM,gBAAgB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,cAC1B,CAAC"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isPlanLimitError = exports.PlanLimitError = void 0;
4
+ const constants_1 = require("./constants");
5
+ class PlanLimitError extends Error {
6
+ status = 402;
7
+ code = constants_1.constants.PLAN_LIMIT_ERROR_CODE;
8
+ feature;
9
+ plan;
10
+ limit;
11
+ used;
12
+ constructor(message, details) {
13
+ super(message);
14
+ this.name = 'PlanLimitError';
15
+ this.feature = details.feature;
16
+ this.plan = details.plan;
17
+ this.limit = details.limit ?? null;
18
+ this.used = details.used ?? null;
19
+ }
20
+ // The extra fields merged into the JSON error body so clients get structured
21
+ // context alongside the message.
22
+ toBody() {
23
+ return {
24
+ code: this.code,
25
+ feature: this.feature,
26
+ plan: this.plan,
27
+ limit: this.limit,
28
+ used: this.used,
29
+ upgrade: true
30
+ };
31
+ }
32
+ }
33
+ exports.PlanLimitError = PlanLimitError;
34
+ const isPlanLimitError = (error) => error instanceof PlanLimitError;
35
+ exports.isPlanLimitError = isPlanLimitError;
@@ -0,0 +1,17 @@
1
+ export interface QueueMessageLike<T> {
2
+ body: T;
3
+ ack: () => void;
4
+ retry: (opts?: {
5
+ delaySeconds?: number;
6
+ }) => void;
7
+ }
8
+ export interface QueueBatchLike<T> {
9
+ queue: string;
10
+ messages: readonly QueueMessageLike<T>[];
11
+ }
12
+ export interface ProcessQueueBatchHandlers<T> {
13
+ process: (body: T) => Promise<void>;
14
+ onError: (error: unknown, body: T, queueName: string) => Promise<void>;
15
+ }
16
+ export declare const processQueueBatch: <T>(batch: QueueBatchLike<T>, handlers: ProcessQueueBatchHandlers<T>) => Promise<void>;
17
+ //# sourceMappingURL=processQueueBatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processQueueBatch.d.ts","sourceRoot":"","sources":["../src/processQueueBatch.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,IAAI,EAAE,CAAC,CAAC;IACR,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,yBAAyB,CAAC,CAAC;IAC1C,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AAED,eAAO,MAAM,iBAAiB,GAAU,CAAC,EACvC,OAAO,cAAc,CAAC,CAAC,CAAC,EACxB,UAAU,yBAAyB,CAAC,CAAC,CAAC,KACrC,OAAO,CAAC,IAAI,CAuBd,CAAC"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processQueueBatch = void 0;
4
+ const retry_1 = require("./retry");
5
+ const constants_1 = require("./constants");
6
+ const processQueueBatch = async (batch, handlers) => {
7
+ for (const message of batch.messages) {
8
+ try {
9
+ await handlers.process(message.body);
10
+ message.ack();
11
+ }
12
+ catch (error) {
13
+ if ((0, retry_1.isTransientInfraError)(error)) {
14
+ // Transient Cloudflare platform hiccup (e.g. a Durable Object /
15
+ // Container reset). The job itself is fine, so re-run it after a short
16
+ // backoff without reporting an error or marking the work failed.
17
+ message.retry({ delaySeconds: constants_1.constants.TRANSIENT_BACKOFF_SECONDS });
18
+ continue;
19
+ }
20
+ await handlers.onError(error, message.body, batch.queue);
21
+ if ((0, retry_1.isRateLimitError)(error)) {
22
+ message.retry({
23
+ delaySeconds: constants_1.constants.RATE_LIMIT_BACKOFF_SECONDS
24
+ });
25
+ }
26
+ else {
27
+ message.retry();
28
+ }
29
+ }
30
+ }
31
+ };
32
+ exports.processQueueBatch = processQueueBatch;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Is this MCP tool name reserved by the platform?
3
+ *
4
+ * Called on the WRITE path only — when a user names an `http-endpoint` tool or
5
+ * uploads a `custom-code` manifest. Deliberately NOT applied when reading a
6
+ * stored row back at boot: tightening this list must never stop an already
7
+ * installed tool from registering, which would be a silent failure the owner
8
+ * could only diagnose from logs. A legacy name that is reserved today keeps
9
+ * working; it simply loses the name to the native tool, because apps/mcp
10
+ * registers natives first.
11
+ *
12
+ * See RESERVED_TOOL_NAME_PREFIXES in constants.ts for why this reserves whole
13
+ * namespaces rather than the enumerated set of shipped keys.
14
+ */
15
+ export declare const isReservedToolName: (name: string) => boolean;
16
+ //# sourceMappingURL=reservedToolName.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reservedToolName.d.ts","sourceRoot":"","sources":["../src/reservedToolName.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,OAQjD,CAAC"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isReservedToolName = void 0;
4
+ const constants_1 = require("./constants");
5
+ const RESERVED = new Set(constants_1.constants.RESERVED_TOOL_NAMES);
6
+ /**
7
+ * Is this MCP tool name reserved by the platform?
8
+ *
9
+ * Called on the WRITE path only — when a user names an `http-endpoint` tool or
10
+ * uploads a `custom-code` manifest. Deliberately NOT applied when reading a
11
+ * stored row back at boot: tightening this list must never stop an already
12
+ * installed tool from registering, which would be a silent failure the owner
13
+ * could only diagnose from logs. A legacy name that is reserved today keeps
14
+ * working; it simply loses the name to the native tool, because apps/mcp
15
+ * registers natives first.
16
+ *
17
+ * See RESERVED_TOOL_NAME_PREFIXES in constants.ts for why this reserves whole
18
+ * namespaces rather than the enumerated set of shipped keys.
19
+ */
20
+ const isReservedToolName = (name) => {
21
+ const lower = name.toLowerCase();
22
+ return (RESERVED.has(lower) ||
23
+ constants_1.constants.RESERVED_TOOL_NAME_PREFIXES.some(prefix => lower.startsWith(prefix)));
24
+ };
25
+ exports.isReservedToolName = isReservedToolName;
@@ -0,0 +1,2 @@
1
+ export declare const resourceUriFromTitle: (title: string) => string;
2
+ //# sourceMappingURL=resourceUri.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resourceUri.d.ts","sourceRoot":"","sources":["../src/resourceUri.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,KAAG,MAIvB,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resourceUriFromTitle = void 0;
4
+ const constants_1 = require("./constants");
5
+ // The `resource://…` URI the dashboard generates from a title when the author
6
+ // doesn't type one, and the same one the broker derives for a script-created
7
+ // resource that arrives without a uri.
8
+ //
9
+ // Shared rather than duplicated because the two have to agree: a resource a
10
+ // tool writes should be addressable exactly like one a person uploaded, and a
11
+ // script asked to "replace the Q3 report" has to be able to name the row the
12
+ // dashboard created. Hyphens, not the underscores `slugifyTitle` produces —
13
+ // that one names MCP prompts and bot commands, where an underscore is legal and
14
+ // a hyphen isn't.
15
+ const resourceUriFromTitle = (title) => `${constants_1.constants.CUSTOM_CODE_RESOURCE_URI_PREFIX}${title
16
+ .toLowerCase()
17
+ .replace(/[^a-z0-9]+/g, '-')
18
+ .replace(/^-+|-+$/g, '')}`;
19
+ exports.resourceUriFromTitle = resourceUriFromTitle;
@@ -0,0 +1,10 @@
1
+ export declare const sleep: (ms: number) => Promise<void>;
2
+ export declare const isRateLimitError: (err: unknown) => boolean;
3
+ export declare const isTransientInfraError: (err: unknown) => boolean;
4
+ export interface RateLimitRetryOptions {
5
+ maxAttempts?: number;
6
+ baseDelayMs?: number;
7
+ maxDelayMs?: number;
8
+ }
9
+ export declare const withRateLimitRetry: <T>(fn: () => Promise<T>, options?: RateLimitRetryOptions) => Promise<T>;
10
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,KAAK,GAAI,IAAI,MAAM,KAAG,OAAO,CAAC,IAAI,CACQ,CAAC;AAExD,eAAO,MAAM,gBAAgB,GAAI,KAAK,OAAO,KAAG,OAG/C,CAAC;AAOF,eAAO,MAAM,qBAAqB,GAAI,KAAK,OAAO,KAAG,OAKpD,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,kBAAkB,GAAU,CAAC,EACxC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,UAAS,qBAA0B,KAClC,OAAO,CAAC,CAAC,CAaX,CAAC"}
package/dist/retry.js ADDED
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withRateLimitRetry = exports.isTransientInfraError = exports.isRateLimitError = exports.sleep = void 0;
4
+ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
5
+ exports.sleep = sleep;
6
+ const isRateLimitError = (err) => {
7
+ const msg = String(err?.message ?? err);
8
+ return /\b429\b|quota|RESOURCE_EXHAUSTED|rate.?limit/i.test(msg);
9
+ };
10
+ exports.isRateLimitError = isRateLimitError;
11
+ // Transient Cloudflare platform errors that are safe to retry as-is: a Durable
12
+ // Object / Container (e.g. the resource-handler) getting evicted or reset
13
+ // mid-request, a code-update eviction, or a dropped internal connection. These
14
+ // are infra hiccups, not job failures, so callers should re-run the job rather
15
+ // than report an error or mark the work failed.
16
+ const isTransientInfraError = (err) => {
17
+ const msg = String(err?.message ?? err);
18
+ return /object to be reset|Durable Object reset|code (?:was|has been) updated|cannot access storage|Network connection lost|internal error.*Durable Object|Durable Object.*internal error/i.test(msg);
19
+ };
20
+ exports.isTransientInfraError = isTransientInfraError;
21
+ const withRateLimitRetry = async (fn, options = {}) => {
22
+ const { maxAttempts = 5, baseDelayMs = 500, maxDelayMs = 10_000 } = options;
23
+ let attempt = 0;
24
+ while (true) {
25
+ try {
26
+ return await fn();
27
+ }
28
+ catch (err) {
29
+ attempt += 1;
30
+ if (attempt >= maxAttempts || !(0, exports.isRateLimitError)(err))
31
+ throw err;
32
+ const delay = Math.min(2 ** attempt * baseDelayMs, maxDelayMs);
33
+ await (0, exports.sleep)(delay);
34
+ }
35
+ }
36
+ };
37
+ exports.withRateLimitRetry = withRateLimitRetry;
@@ -0,0 +1,7 @@
1
+ export declare const decodeEntities: (value: string) => string;
2
+ export declare const escapeHtml: (value: string) => string;
3
+ export declare const parseOpenXmlProps: (xml: string) => Record<string, string>;
4
+ export declare const stripBase64Images: (text: string) => string;
5
+ export declare const sanitizeMetadataString: (value: string) => string;
6
+ export declare const serializeMetadataValue: (value: unknown) => unknown;
7
+ //# sourceMappingURL=sanitize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../src/sanitize.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,KAAG,MAMpB,CAAC;AAK5B,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,MAMhB,CAAC;AAE5B,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAUpE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,MAQtC,CAAC;AAEZ,eAAO,MAAM,sBAAsB,GAAI,OAAO,MAAM,KAAG,MAK5C,CAAC;AAEZ,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,KAAG,OAgBvD,CAAC"}