@5ss/ai-tools 2.11.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.
- package/CHANGELOG.md +112 -0
- package/LICENSE +21 -0
- package/README.md +221 -0
- package/dist/ai-sdk/index.d.ts +15 -0
- package/dist/ai-sdk/index.d.ts.map +1 -0
- package/dist/ai-sdk/index.js +24 -0
- package/dist/ai-sdk/index.js.map +1 -0
- package/dist/artifact-D064mHfK.js +44 -0
- package/dist/artifact-D064mHfK.js.map +1 -0
- package/dist/artifacts-O8g-40Pw.js +404 -0
- package/dist/artifacts-O8g-40Pw.js.map +1 -0
- package/dist/aws-json-CecFqzqX.js +23 -0
- package/dist/aws-json-CecFqzqX.js.map +1 -0
- package/dist/aws-service-msttbPrz.js +58 -0
- package/dist/aws-service-msttbPrz.js.map +1 -0
- package/dist/batch-BMM5dXqL.d.ts +22 -0
- package/dist/batch-BMM5dXqL.d.ts.map +1 -0
- package/dist/batch-Co1ujeAW.js +67 -0
- package/dist/batch-Co1ujeAW.js.map +1 -0
- package/dist/bedrock-agentcore-browser-a_qOs-NR.js +182 -0
- package/dist/bedrock-agentcore-browser-a_qOs-NR.js.map +1 -0
- package/dist/bedrock-agentcore-code-interpreter-MWK-8RhA.js +357 -0
- package/dist/bedrock-agentcore-code-interpreter-MWK-8RhA.js.map +1 -0
- package/dist/bytes-BxpimpQx.js +45 -0
- package/dist/bytes-BxpimpQx.js.map +1 -0
- package/dist/client-CCKGsTeI.js +743 -0
- package/dist/client-CCKGsTeI.js.map +1 -0
- package/dist/cloudflare/index.d.ts +37 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +41 -0
- package/dist/cloudflare/index.js.map +1 -0
- package/dist/cloudflare-browser-B6Yolpin.js +428 -0
- package/dist/cloudflare-browser-B6Yolpin.js.map +1 -0
- package/dist/cloudflare-email-Dy0KHeDf.js +197 -0
- package/dist/cloudflare-email-Dy0KHeDf.js.map +1 -0
- package/dist/cloudflare-sandbox-Dp_uNaqW.js +982 -0
- package/dist/cloudflare-sandbox-Dp_uNaqW.js.map +1 -0
- package/dist/content-type-CORxaxcv.js +49 -0
- package/dist/content-type-CORxaxcv.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +204 -0
- package/dist/core/index.js.map +1 -0
- package/dist/define-CvpJ_pNP.js +115 -0
- package/dist/define-CvpJ_pNP.js.map +1 -0
- package/dist/errors-DoSpNHvs.js +20 -0
- package/dist/errors-DoSpNHvs.js.map +1 -0
- package/dist/errors-aKhko9T1.d.ts +18 -0
- package/dist/errors-aKhko9T1.d.ts.map +1 -0
- package/dist/eventbridge-scheduler-Bh6GqZY2.js +349 -0
- package/dist/eventbridge-scheduler-Bh6GqZY2.js.map +1 -0
- package/dist/framework-context-DVIIY8ZO.js +24 -0
- package/dist/framework-context-DVIIY8ZO.js.map +1 -0
- package/dist/gotenberg-NuJjxyln.js +291 -0
- package/dist/gotenberg-NuJjxyln.js.map +1 -0
- package/dist/http/index.d.ts +47 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +3 -0
- package/dist/http-service-DDNCO1s4.js +254 -0
- package/dist/http-service-DDNCO1s4.js.map +1 -0
- package/dist/http-service-T7E5UjP8.d.ts +80 -0
- package/dist/http-service-T7E5UjP8.d.ts.map +1 -0
- package/dist/imessage-BSAFOI8Z.js +154 -0
- package/dist/imessage-BSAFOI8Z.js.map +1 -0
- package/dist/index-BU4gmYO8.d.ts +254 -0
- package/dist/index-BU4gmYO8.d.ts.map +1 -0
- package/dist/index-CCivzmxO.d.ts +188 -0
- package/dist/index-CCivzmxO.d.ts.map +1 -0
- package/dist/index-CLmTrcu5.d.ts +22 -0
- package/dist/index-CLmTrcu5.d.ts.map +1 -0
- package/dist/index-CZX5OeOF.d.ts +235 -0
- package/dist/index-CZX5OeOF.d.ts.map +1 -0
- package/dist/index-CdFmEfZO.d.ts +359 -0
- package/dist/index-CdFmEfZO.d.ts.map +1 -0
- package/dist/index-Cuh6eMWc.d.ts +285 -0
- package/dist/index-Cuh6eMWc.d.ts.map +1 -0
- package/dist/index-DuOGj7vc.d.ts +107 -0
- package/dist/index-DuOGj7vc.d.ts.map +1 -0
- package/dist/index-ccZ1XOHw.d.ts +69 -0
- package/dist/index-ccZ1XOHw.d.ts.map +1 -0
- package/dist/index-n8JTpNf1.d.ts +247 -0
- package/dist/index-n8JTpNf1.d.ts.map +1 -0
- package/dist/index-pwW1OsOx.d.ts +134 -0
- package/dist/index-pwW1OsOx.d.ts.map +1 -0
- package/dist/index-zK1ZwS4m.d.ts +347 -0
- package/dist/index-zK1ZwS4m.d.ts.map +1 -0
- package/dist/limits-hjrO8zUG.js +80 -0
- package/dist/limits-hjrO8zUG.js.map +1 -0
- package/dist/mastra/index.d.ts +14 -0
- package/dist/mastra/index.d.ts.map +1 -0
- package/dist/mastra/index.js +26 -0
- package/dist/mastra/index.js.map +1 -0
- package/dist/mastra-vector-Dhc6XZ8l.js +234 -0
- package/dist/mastra-vector-Dhc6XZ8l.js.map +1 -0
- package/dist/mcp/index.d.ts +80 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +97 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/modules/artifacts/index.d.ts +337 -0
- package/dist/modules/artifacts/index.d.ts.map +1 -0
- package/dist/modules/artifacts/index.js +348 -0
- package/dist/modules/artifacts/index.js.map +1 -0
- package/dist/modules/browser/index.d.ts +516 -0
- package/dist/modules/browser/index.d.ts.map +1 -0
- package/dist/modules/browser/index.js +475 -0
- package/dist/modules/browser/index.js.map +1 -0
- package/dist/modules/calendar/index.d.ts +93 -0
- package/dist/modules/calendar/index.d.ts.map +1 -0
- package/dist/modules/calendar/index.js +131 -0
- package/dist/modules/calendar/index.js.map +1 -0
- package/dist/modules/code-sandbox/index.d.ts +317 -0
- package/dist/modules/code-sandbox/index.d.ts.map +1 -0
- package/dist/modules/code-sandbox/index.js +537 -0
- package/dist/modules/code-sandbox/index.js.map +1 -0
- package/dist/modules/content-type/index.d.ts +22 -0
- package/dist/modules/content-type/index.d.ts.map +1 -0
- package/dist/modules/content-type/index.js +66 -0
- package/dist/modules/content-type/index.js.map +1 -0
- package/dist/modules/crypto/index.d.ts +115 -0
- package/dist/modules/crypto/index.d.ts.map +1 -0
- package/dist/modules/crypto/index.js +139 -0
- package/dist/modules/crypto/index.js.map +1 -0
- package/dist/modules/document/index.d.ts +575 -0
- package/dist/modules/document/index.d.ts.map +1 -0
- package/dist/modules/document/index.js +444 -0
- package/dist/modules/document/index.js.map +1 -0
- package/dist/modules/document-extract/index.d.ts +438 -0
- package/dist/modules/document-extract/index.d.ts.map +1 -0
- package/dist/modules/document-extract/index.js +127 -0
- package/dist/modules/document-extract/index.js.map +1 -0
- package/dist/modules/document-render/index.d.ts +336 -0
- package/dist/modules/document-render/index.d.ts.map +1 -0
- package/dist/modules/document-render/index.js +155 -0
- package/dist/modules/document-render/index.js.map +1 -0
- package/dist/modules/email/index.d.ts +311 -0
- package/dist/modules/email/index.d.ts.map +1 -0
- package/dist/modules/email/index.js +167 -0
- package/dist/modules/email/index.js.map +1 -0
- package/dist/modules/email-message/index.d.ts +95 -0
- package/dist/modules/email-message/index.d.ts.map +1 -0
- package/dist/modules/email-message/index.js +264 -0
- package/dist/modules/email-message/index.js.map +1 -0
- package/dist/modules/file-convert/index.d.ts +273 -0
- package/dist/modules/file-convert/index.d.ts.map +1 -0
- package/dist/modules/file-convert/index.js +103 -0
- package/dist/modules/file-convert/index.js.map +1 -0
- package/dist/modules/files/index.d.ts +452 -0
- package/dist/modules/files/index.d.ts.map +1 -0
- package/dist/modules/files/index.js +733 -0
- package/dist/modules/files/index.js.map +1 -0
- package/dist/modules/image/index.d.ts +342 -0
- package/dist/modules/image/index.d.ts.map +1 -0
- package/dist/modules/image/index.js +281 -0
- package/dist/modules/image/index.js.map +1 -0
- package/dist/modules/messaging/index.d.ts +608 -0
- package/dist/modules/messaging/index.d.ts.map +1 -0
- package/dist/modules/messaging/index.js +1067 -0
- package/dist/modules/messaging/index.js.map +1 -0
- package/dist/modules/pdf/index.d.ts +287 -0
- package/dist/modules/pdf/index.d.ts.map +1 -0
- package/dist/modules/pdf/index.js +259 -0
- package/dist/modules/pdf/index.js.map +1 -0
- package/dist/modules/presentation/index.d.ts +247 -0
- package/dist/modules/presentation/index.d.ts.map +1 -0
- package/dist/modules/presentation/index.js +12657 -0
- package/dist/modules/presentation/index.js.map +1 -0
- package/dist/modules/queue/index.d.ts +129 -0
- package/dist/modules/queue/index.d.ts.map +1 -0
- package/dist/modules/queue/index.js +131 -0
- package/dist/modules/queue/index.js.map +1 -0
- package/dist/modules/rag/index.d.ts +250 -0
- package/dist/modules/rag/index.d.ts.map +1 -0
- package/dist/modules/rag/index.js +366 -0
- package/dist/modules/rag/index.js.map +1 -0
- package/dist/modules/scheduler/index.d.ts +216 -0
- package/dist/modules/scheduler/index.d.ts.map +1 -0
- package/dist/modules/scheduler/index.js +153 -0
- package/dist/modules/scheduler/index.js.map +1 -0
- package/dist/modules/skills/index.d.ts +205 -0
- package/dist/modules/skills/index.d.ts.map +1 -0
- package/dist/modules/skills/index.js +203 -0
- package/dist/modules/skills/index.js.map +1 -0
- package/dist/modules/tasks/index.d.ts +287 -0
- package/dist/modules/tasks/index.d.ts.map +1 -0
- package/dist/modules/tasks/index.js +207 -0
- package/dist/modules/tasks/index.js.map +1 -0
- package/dist/modules/vector-store/index.d.ts +3 -0
- package/dist/modules/vector-store/index.js +3 -0
- package/dist/modules/web-fetch/index.d.ts +99 -0
- package/dist/modules/web-fetch/index.d.ts.map +1 -0
- package/dist/modules/web-fetch/index.js +242 -0
- package/dist/modules/web-fetch/index.js.map +1 -0
- package/dist/object-artifact-store-CMTzCm_G.d.ts +7 -0
- package/dist/object-artifact-store-CMTzCm_G.d.ts.map +1 -0
- package/dist/object-artifact-store-wZ2j9cto.js +28 -0
- package/dist/object-artifact-store-wZ2j9cto.js.map +1 -0
- package/dist/pinecone-umY4t6OF.js +190 -0
- package/dist/pinecone-umY4t6OF.js.map +1 -0
- package/dist/provider-CgDAlg6K.js +34 -0
- package/dist/provider-CgDAlg6K.js.map +1 -0
- package/dist/qdrant-DMp4NhKR.js +253 -0
- package/dist/qdrant-DMp4NhKR.js.map +1 -0
- package/dist/resend-BAC38_dA.js +155 -0
- package/dist/resend-BAC38_dA.js.map +1 -0
- package/dist/s3-CsOaPWMP.js +955 -0
- package/dist/s3-CsOaPWMP.js.map +1 -0
- package/dist/schemas-ChOAhdo9.js +192 -0
- package/dist/schemas-ChOAhdo9.js.map +1 -0
- package/dist/slack-Di5BBNpt.js +1455 -0
- package/dist/slack-Di5BBNpt.js.map +1 -0
- package/dist/sqs-DCwS1i2N.js +225 -0
- package/dist/sqs-DCwS1i2N.js.map +1 -0
- package/dist/supabase-vector-Dpp9mmJR.js +218 -0
- package/dist/supabase-vector-Dpp9mmJR.js.map +1 -0
- package/dist/tanstack/index.d.ts +15 -0
- package/dist/tanstack/index.d.ts.map +1 -0
- package/dist/tanstack/index.js +28 -0
- package/dist/tanstack/index.js.map +1 -0
- package/dist/teams-DYAHNb39.js +835 -0
- package/dist/teams-DYAHNb39.js.map +1 -0
- package/dist/telegram-DDXWzkfL.js +734 -0
- package/dist/telegram-DDXWzkfL.js.map +1 -0
- package/dist/textract-CPLiB22H.js +554 -0
- package/dist/textract-CPLiB22H.js.map +1 -0
- package/dist/transport-B4vn-XiQ.js +157 -0
- package/dist/transport-B4vn-XiQ.js.map +1 -0
- package/dist/transport-i96ACAI_.d.ts +46 -0
- package/dist/transport-i96ACAI_.d.ts.map +1 -0
- package/dist/types-Ccb0DXY9.d.ts +150 -0
- package/dist/types-Ccb0DXY9.d.ts.map +1 -0
- package/dist/unique-EwBH1JPB.js +19 -0
- package/dist/unique-EwBH1JPB.js.map +1 -0
- package/dist/vector-store-C3nEO80e.js +193 -0
- package/dist/vector-store-C3nEO80e.js.map +1 -0
- package/dist/vendors/amazon-sp-api/index.d.ts +526 -0
- package/dist/vendors/amazon-sp-api/index.d.ts.map +1 -0
- package/dist/vendors/amazon-sp-api/index.js +975 -0
- package/dist/vendors/amazon-sp-api/index.js.map +1 -0
- package/dist/vendors/bedrock-agentcore-browser/index.d.ts +2 -0
- package/dist/vendors/bedrock-agentcore-browser/index.js +2 -0
- package/dist/vendors/bedrock-agentcore-code-interpreter/index.d.ts +228 -0
- package/dist/vendors/bedrock-agentcore-code-interpreter/index.d.ts.map +1 -0
- package/dist/vendors/bedrock-agentcore-code-interpreter/index.js +2 -0
- package/dist/vendors/cloudflare-browser/index.d.ts +2 -0
- package/dist/vendors/cloudflare-browser/index.js +2 -0
- package/dist/vendors/cloudflare-email/index.d.ts +260 -0
- package/dist/vendors/cloudflare-email/index.d.ts.map +1 -0
- package/dist/vendors/cloudflare-email/index.js +3 -0
- package/dist/vendors/cloudflare-sandbox/index.d.ts +565 -0
- package/dist/vendors/cloudflare-sandbox/index.d.ts.map +1 -0
- package/dist/vendors/cloudflare-sandbox/index.js +2 -0
- package/dist/vendors/eventbridge-scheduler/index.d.ts +2 -0
- package/dist/vendors/eventbridge-scheduler/index.js +2 -0
- package/dist/vendors/gotenberg/index.d.ts +306 -0
- package/dist/vendors/gotenberg/index.d.ts.map +1 -0
- package/dist/vendors/gotenberg/index.js +2 -0
- package/dist/vendors/imessage/index.d.ts +420 -0
- package/dist/vendors/imessage/index.d.ts.map +1 -0
- package/dist/vendors/imessage/index.js +4 -0
- package/dist/vendors/katana/index.d.ts +1570 -0
- package/dist/vendors/katana/index.d.ts.map +1 -0
- package/dist/vendors/katana/index.js +1639 -0
- package/dist/vendors/katana/index.js.map +1 -0
- package/dist/vendors/mastra-vector/index.d.ts +120 -0
- package/dist/vendors/mastra-vector/index.d.ts.map +1 -0
- package/dist/vendors/mastra-vector/index.js +3 -0
- package/dist/vendors/pinecone/index.d.ts +75 -0
- package/dist/vendors/pinecone/index.d.ts.map +1 -0
- package/dist/vendors/pinecone/index.js +3 -0
- package/dist/vendors/qdrant/index.d.ts +75 -0
- package/dist/vendors/qdrant/index.d.ts.map +1 -0
- package/dist/vendors/qdrant/index.js +3 -0
- package/dist/vendors/resend/index.d.ts +3 -0
- package/dist/vendors/resend/index.js +3 -0
- package/dist/vendors/s3/index.d.ts +2 -0
- package/dist/vendors/s3/index.js +2 -0
- package/dist/vendors/slack/index.d.ts +576 -0
- package/dist/vendors/slack/index.d.ts.map +1 -0
- package/dist/vendors/slack/index.js +3 -0
- package/dist/vendors/sqs/index.d.ts +2 -0
- package/dist/vendors/sqs/index.js +2 -0
- package/dist/vendors/supabase-vector/index.d.ts +89 -0
- package/dist/vendors/supabase-vector/index.d.ts.map +1 -0
- package/dist/vendors/supabase-vector/index.js +3 -0
- package/dist/vendors/teams/index.d.ts +303 -0
- package/dist/vendors/teams/index.d.ts.map +1 -0
- package/dist/vendors/teams/index.js +3 -0
- package/dist/vendors/telegram/index.d.ts +319 -0
- package/dist/vendors/telegram/index.d.ts.map +1 -0
- package/dist/vendors/telegram/index.js +3 -0
- package/dist/vendors/textract/index.d.ts +2 -0
- package/dist/vendors/textract/index.js +2 -0
- package/dist/vendors/woocommerce/index.d.ts +1700 -0
- package/dist/vendors/woocommerce/index.d.ts.map +1 -0
- package/dist/vendors/woocommerce/index.js +1427 -0
- package/dist/vendors/woocommerce/index.js.map +1 -0
- package/dist/with-auth-CpKqTrGK.js +240 -0
- package/dist/with-auth-CpKqTrGK.js.map +1 -0
- package/logos/LUCIDE-ATTRIBUTION.txt +4 -0
- package/logos/README.md +89 -0
- package/logos/amazon.svg +6 -0
- package/logos/artifacts.svg +9 -0
- package/logos/browser.svg +9 -0
- package/logos/calendar.svg +15 -0
- package/logos/cloudflare-browser.svg +5 -0
- package/logos/cloudflare-email.svg +5 -0
- package/logos/cloudflare.svg +4 -0
- package/logos/code-sandbox.svg +8 -0
- package/logos/content-type.svg +10 -0
- package/logos/crypto.svg +7 -0
- package/logos/document-extract.svg +12 -0
- package/logos/document-render.svg +8 -0
- package/logos/document.svg +10 -0
- package/logos/email-message.svg +8 -0
- package/logos/email.svg +7 -0
- package/logos/file-convert.svg +9 -0
- package/logos/files.svg +6 -0
- package/logos/gotenberg.svg +340 -0
- package/logos/image.svg +8 -0
- package/logos/imessage.svg +7 -0
- package/logos/katana.svg +13 -0
- package/logos/mastra.svg +7 -0
- package/logos/messaging.svg +7 -0
- package/logos/pack-logos.json +48 -0
- package/logos/pdf.svg +10 -0
- package/logos/pinecone.svg +25 -0
- package/logos/presentation.svg +8 -0
- package/logos/qdrant.svg +4 -0
- package/logos/queue.svg +11 -0
- package/logos/rag.svg +18 -0
- package/logos/resend.svg +5 -0
- package/logos/scheduler.svg +7 -0
- package/logos/skills.svg +10 -0
- package/logos/slack.svg +14 -0
- package/logos/supabase.svg +4 -0
- package/logos/tasks.svg +10 -0
- package/logos/teams.svg +6 -0
- package/logos/telegram.svg +10 -0
- package/logos/textract.svg +5 -0
- package/logos/vector-store.svg +8 -0
- package/logos/web-fetch.svg +8 -0
- package/logos/woocommerce.svg +4 -0
- package/package.json +373 -0
|
@@ -0,0 +1,955 @@
|
|
|
1
|
+
import { n as isToolError, t as ToolError } from "./errors-DoSpNHvs.js";
|
|
2
|
+
import { n as defineModule, r as defineTool } from "./define-CvpJ_pNP.js";
|
|
3
|
+
import { n as requireAuth } from "./provider-CgDAlg6K.js";
|
|
4
|
+
import { t as AwsService } from "./aws-service-msttbPrz.js";
|
|
5
|
+
import { a as toArrayBuffer, i as encodeObjectKeyPath, n as bytesToBase64, o as utf8ToBytes, r as bytesToUtf8, t as base64ToBytes } from "./bytes-BxpimpQx.js";
|
|
6
|
+
import { t as batchResultSchema } from "./batch-Co1ujeAW.js";
|
|
7
|
+
import { isNil, isNumber, isPlainObject, isString } from "es-toolkit";
|
|
8
|
+
import { isArray } from "es-toolkit/compat";
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
import { XMLParser } from "fast-xml-parser";
|
|
11
|
+
//#region src/vendors/_storage/keys.ts
|
|
12
|
+
/**
|
|
13
|
+
* Object-key prefix helpers for storage vendors (S3, Textract DocumentLocation, …).
|
|
14
|
+
* Logical keys are prefix-relative; wire keys include key_prefix when set.
|
|
15
|
+
*/
|
|
16
|
+
/** S3 object key maximum length (bytes, UTF-8). */
|
|
17
|
+
const MAX_OBJECT_KEY_BYTES = 1024;
|
|
18
|
+
function utf8ByteLength(value) {
|
|
19
|
+
return new TextEncoder().encode(value).byteLength;
|
|
20
|
+
}
|
|
21
|
+
function assertKeyByteLimit(wireKey) {
|
|
22
|
+
const bytes = utf8ByteLength(wireKey);
|
|
23
|
+
if (bytes > 1024) throw new ToolError(`Object key exceeds ${MAX_OBJECT_KEY_BYTES} bytes`, {
|
|
24
|
+
code: "bad_input",
|
|
25
|
+
details: {
|
|
26
|
+
max_bytes: MAX_OBJECT_KEY_BYTES,
|
|
27
|
+
key_bytes: bytes
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Split a logical path into segments. Rejects parent segments and leading absolute form.
|
|
33
|
+
* Allows names like `report..final.pdf` (only a segment equal to `..` is rejected).
|
|
34
|
+
*/
|
|
35
|
+
function keySegments(value, options = {}) {
|
|
36
|
+
const trimmed = value.trim().replaceAll("\\", "/");
|
|
37
|
+
if (trimmed.startsWith("/")) throw new ToolError("Object key must not be absolute (no leading /)", { code: "bad_input" });
|
|
38
|
+
const trailingSlash = trimmed.endsWith("/");
|
|
39
|
+
if (trailingSlash && options.allowTrailingSlash !== true) throw new ToolError("Object key must not end with /", { code: "bad_input" });
|
|
40
|
+
const segments = trimmed.split("/").filter((segment) => segment.length > 0 && segment !== ".");
|
|
41
|
+
for (const segment of segments) if (segment === "..") throw new ToolError("Object key must not contain parent-directory segments", { code: "bad_input" });
|
|
42
|
+
if (segments.length === 0 && !options.allowEmpty && !trailingSlash) throw new ToolError("Object key is required", { code: "bad_input" });
|
|
43
|
+
return {
|
|
44
|
+
segments,
|
|
45
|
+
trailingSlash
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function joinSegments(segments, trailingSlash) {
|
|
49
|
+
const joined = segments.join("/");
|
|
50
|
+
if (trailingSlash) return joined.length > 0 ? `${joined}/` : "";
|
|
51
|
+
return joined;
|
|
52
|
+
}
|
|
53
|
+
function remapAuthError(error) {
|
|
54
|
+
if (isToolError(error) && error.code === "bad_input") throw new ToolError(error.message.replace(/^Object key/, "key_prefix"), {
|
|
55
|
+
code: "bad_auth",
|
|
56
|
+
...error.details !== void 0 && { details: error.details },
|
|
57
|
+
cause: error
|
|
58
|
+
});
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
/** Normalize key_prefix from auth: non-absolute, no `..` segments, always ends with `/`. */
|
|
62
|
+
function normalizeKeyPrefix(keyPrefix) {
|
|
63
|
+
try {
|
|
64
|
+
const { segments } = keySegments(keyPrefix, {
|
|
65
|
+
allowEmpty: false,
|
|
66
|
+
allowTrailingSlash: true
|
|
67
|
+
});
|
|
68
|
+
if (segments.length === 0) throw new ToolError("key_prefix must not be empty", { code: "bad_auth" });
|
|
69
|
+
const root = `${segments.join("/")}/`;
|
|
70
|
+
assertKeyByteLimit(root);
|
|
71
|
+
return root;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
remapAuthError(error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Resolve a logical object key to a wire key.
|
|
78
|
+
* - No prefix: validated logical key (normalized segments).
|
|
79
|
+
* - With prefix: relative keys are rooted; keys already under the prefix are accepted as-is.
|
|
80
|
+
*/
|
|
81
|
+
function resolveObjectKey(logicalKey, keyPrefix) {
|
|
82
|
+
const { segments } = keySegments(logicalKey, { allowEmpty: false });
|
|
83
|
+
const logical = joinSegments(segments, false);
|
|
84
|
+
if (!keyPrefix) {
|
|
85
|
+
assertKeyByteLimit(logical);
|
|
86
|
+
return logical;
|
|
87
|
+
}
|
|
88
|
+
const wire = logical.startsWith(keyPrefix) ? logical : `${keyPrefix}${logical}`;
|
|
89
|
+
assertKeyByteLimit(wire);
|
|
90
|
+
return wire;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Resolve a list prefix filter under optional key_prefix.
|
|
94
|
+
* Empty / omitted relative → bound prefix root (or undefined when unbound).
|
|
95
|
+
*/
|
|
96
|
+
function resolveListPrefix(relativePrefix, keyPrefix) {
|
|
97
|
+
if (relativePrefix === void 0 || relativePrefix.trim().length === 0) return keyPrefix;
|
|
98
|
+
const { segments, trailingSlash } = keySegments(relativePrefix, {
|
|
99
|
+
allowEmpty: true,
|
|
100
|
+
allowTrailingSlash: true
|
|
101
|
+
});
|
|
102
|
+
const logical = joinSegments(segments, trailingSlash);
|
|
103
|
+
if (!keyPrefix) {
|
|
104
|
+
if (logical.length === 0) return void 0;
|
|
105
|
+
assertKeyByteLimit(logical);
|
|
106
|
+
return logical;
|
|
107
|
+
}
|
|
108
|
+
if (logical.length === 0 || logical === keyPrefix.slice(0, -1) || logical === keyPrefix) return keyPrefix;
|
|
109
|
+
if (logical.startsWith(keyPrefix)) {
|
|
110
|
+
assertKeyByteLimit(logical);
|
|
111
|
+
return logical;
|
|
112
|
+
}
|
|
113
|
+
const wire = `${keyPrefix}${logical}`;
|
|
114
|
+
assertKeyByteLimit(wire);
|
|
115
|
+
return wire;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Map a wire key back to a logical (public) key.
|
|
119
|
+
* Returns undefined when the wire key is outside key_prefix (caller should skip/filter).
|
|
120
|
+
*/
|
|
121
|
+
function toPublicKey(wireKey, keyPrefix) {
|
|
122
|
+
if (!keyPrefix) return wireKey;
|
|
123
|
+
if (!wireKey.startsWith(keyPrefix)) return void 0;
|
|
124
|
+
return wireKey.slice(keyPrefix.length);
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region src/vendors/_storage/schemas.ts
|
|
128
|
+
/**
|
|
129
|
+
* Shared object-store I/O schemas for the s3 vendor pack (and nested S3 bindings).
|
|
130
|
+
* Not published — `_storage` is skipped by codegen.
|
|
131
|
+
*/
|
|
132
|
+
const MAX_OBJECT_BYTES = 5 * 1024 * 1024;
|
|
133
|
+
const DEFAULT_SIGNED_URL_SECONDS = 3600;
|
|
134
|
+
const MAX_SIGNED_URL_SECONDS = 168 * 3600;
|
|
135
|
+
const MAX_MULTIPART_PART_BYTES = 25 * 1024 * 1024;
|
|
136
|
+
const listedObjectSchema = z.object({
|
|
137
|
+
key: z.string(),
|
|
138
|
+
size: z.number().optional(),
|
|
139
|
+
last_modified: z.string().optional(),
|
|
140
|
+
etag: z.string().optional()
|
|
141
|
+
});
|
|
142
|
+
const listObjectsInputSchema = z.object({
|
|
143
|
+
prefix: z.string().optional().describe("Key prefix filter"),
|
|
144
|
+
delimiter: z.string().optional().describe("Delimiter for common prefixes (folders), for example /"),
|
|
145
|
+
cursor: z.string().min(1).optional().describe("Pagination cursor from a prior list call"),
|
|
146
|
+
limit: z.int().min(1).max(1e3).optional().describe("Maximum keys to return (1-1000)")
|
|
147
|
+
});
|
|
148
|
+
const listObjectsOutputSchema = z.object({
|
|
149
|
+
keys: z.array(z.string()).describe("Object keys (convenience list)"),
|
|
150
|
+
items: z.array(listedObjectSchema).describe("Objects with size, last_modified, and etag when present"),
|
|
151
|
+
common_prefixes: z.array(z.string()).optional().describe("Common prefixes when delimiter is set"),
|
|
152
|
+
next_cursor: z.string().optional().describe("Pass as cursor to fetch the next page"),
|
|
153
|
+
truncated: z.boolean().describe("Whether more results exist")
|
|
154
|
+
});
|
|
155
|
+
const getObjectInputSchema = z.object({
|
|
156
|
+
key: z.string().min(1).describe("Object key to download"),
|
|
157
|
+
encoding: z.enum(["base64", "utf8"]).optional().describe("Body encoding. Defaults to base64 for binary safety")
|
|
158
|
+
});
|
|
159
|
+
const getObjectOutputSchema = z.object({
|
|
160
|
+
key: z.string(),
|
|
161
|
+
content_type: z.string().optional(),
|
|
162
|
+
content_length: z.number().optional(),
|
|
163
|
+
body: z.string().describe("Object body encoded per encoding input"),
|
|
164
|
+
encoding: z.enum(["base64", "utf8"])
|
|
165
|
+
});
|
|
166
|
+
const putObjectInputSchema = z.object({
|
|
167
|
+
key: z.string().min(1).describe("Object key to write"),
|
|
168
|
+
body: z.string().describe("Object body as utf8 text or base64 (see body_encoding)"),
|
|
169
|
+
body_encoding: z.enum(["utf8", "base64"]).optional().describe("How to interpret body. Defaults to utf8"),
|
|
170
|
+
content_type: z.string().optional().describe("Content-Type header to store")
|
|
171
|
+
});
|
|
172
|
+
const putObjectOutputSchema = z.object({
|
|
173
|
+
key: z.string(),
|
|
174
|
+
etag: z.string().optional(),
|
|
175
|
+
content_length: z.number().describe("Decoded body byte length uploaded")
|
|
176
|
+
});
|
|
177
|
+
const deleteObjectInputSchema = z.object({ key: z.string().min(1).describe("Object key to delete") });
|
|
178
|
+
const deleteObjectOutputSchema = z.object({
|
|
179
|
+
key: z.string(),
|
|
180
|
+
deleted: z.boolean()
|
|
181
|
+
});
|
|
182
|
+
const headObjectInputSchema = z.object({ key: z.string().min(1).describe("Object key to inspect") });
|
|
183
|
+
const headObjectOutputSchema = z.object({
|
|
184
|
+
key: z.string(),
|
|
185
|
+
exists: z.boolean(),
|
|
186
|
+
content_type: z.string().optional(),
|
|
187
|
+
content_length: z.number().optional(),
|
|
188
|
+
etag: z.string().optional()
|
|
189
|
+
});
|
|
190
|
+
const copyObjectInputSchema = z.object({
|
|
191
|
+
source_key: z.string().min(1).describe("Source object key to copy from"),
|
|
192
|
+
destination_key: z.string().min(1).describe("Destination object key to copy to"),
|
|
193
|
+
source_bucket: z.string().min(1).optional().describe("Optional source bucket when different from the configured default bucket")
|
|
194
|
+
});
|
|
195
|
+
const copyObjectOutputSchema = z.object({
|
|
196
|
+
source_key: z.string(),
|
|
197
|
+
destination_key: z.string(),
|
|
198
|
+
etag: z.string().optional()
|
|
199
|
+
});
|
|
200
|
+
const signedUrlInputSchema = z.object({
|
|
201
|
+
key: z.string().min(1).describe("Object key to sign"),
|
|
202
|
+
method: z.enum([
|
|
203
|
+
"GET",
|
|
204
|
+
"PUT",
|
|
205
|
+
"HEAD",
|
|
206
|
+
"DELETE"
|
|
207
|
+
]).optional().describe("HTTP method the URL authorizes. Defaults to GET"),
|
|
208
|
+
expires_in: z.int().min(1).max(MAX_SIGNED_URL_SECONDS).optional().describe("URL lifetime in seconds (1 to 604800). Defaults to 3600")
|
|
209
|
+
});
|
|
210
|
+
const signedUrlOutputSchema = z.object({
|
|
211
|
+
url: z.url().describe("Presigned URL"),
|
|
212
|
+
method: z.enum([
|
|
213
|
+
"GET",
|
|
214
|
+
"PUT",
|
|
215
|
+
"HEAD",
|
|
216
|
+
"DELETE"
|
|
217
|
+
]),
|
|
218
|
+
expires_in: z.int().describe("Lifetime in seconds used when signing")
|
|
219
|
+
});
|
|
220
|
+
const createMultipartUploadInputSchema = z.object({
|
|
221
|
+
key: z.string().min(1).describe("Object key to create via multipart upload"),
|
|
222
|
+
content_type: z.string().optional().describe("Content-Type stored on the completed object")
|
|
223
|
+
});
|
|
224
|
+
const createMultipartUploadOutputSchema = z.object({
|
|
225
|
+
key: z.string(),
|
|
226
|
+
upload_id: z.string().min(1).describe("Upload id required for subsequent part/complete/abort calls")
|
|
227
|
+
});
|
|
228
|
+
const uploadPartInputSchema = z.object({
|
|
229
|
+
key: z.string().min(1).describe("Object key for the in-progress multipart upload"),
|
|
230
|
+
upload_id: z.string().min(1).describe("Upload id from createMultipartUpload"),
|
|
231
|
+
part_number: z.int().min(1).max(1e4).describe("Part number (1-10000). Must be unique within the upload"),
|
|
232
|
+
body: z.string().describe("Part body as utf8 text or base64 (see body_encoding)"),
|
|
233
|
+
body_encoding: z.enum(["utf8", "base64"]).optional().describe("How to interpret body. Defaults to utf8")
|
|
234
|
+
});
|
|
235
|
+
const uploadPartOutputSchema = z.object({
|
|
236
|
+
key: z.string(),
|
|
237
|
+
upload_id: z.string(),
|
|
238
|
+
part_number: z.int(),
|
|
239
|
+
etag: z.string().min(1).describe("Part ETag required when completing the multipart upload"),
|
|
240
|
+
content_length: z.number().describe("Decoded part byte length uploaded")
|
|
241
|
+
});
|
|
242
|
+
const multipartUploadedPartSchema = z.object({
|
|
243
|
+
part_number: z.int().min(1).max(1e4).describe("Uploaded part number from s3-upload-part"),
|
|
244
|
+
etag: z.string().min(1).describe("ETag returned by uploadPart (with or without surrounding quotes)")
|
|
245
|
+
});
|
|
246
|
+
const completeMultipartUploadInputSchema = z.object({
|
|
247
|
+
key: z.string().min(1).describe("Object key for the in-progress multipart upload"),
|
|
248
|
+
upload_id: z.string().min(1).describe("Upload id from createMultipartUpload"),
|
|
249
|
+
parts: z.array(multipartUploadedPartSchema).min(1).max(1e4).describe("Uploaded parts with part_number and etag, in any order (sorted before complete)")
|
|
250
|
+
});
|
|
251
|
+
const completeMultipartUploadOutputSchema = z.object({
|
|
252
|
+
key: z.string(),
|
|
253
|
+
upload_id: z.string(),
|
|
254
|
+
etag: z.string().optional().describe("Final object ETag when the store returns one")
|
|
255
|
+
});
|
|
256
|
+
const abortMultipartUploadInputSchema = z.object({
|
|
257
|
+
key: z.string().min(1).describe("Object key for the in-progress multipart upload"),
|
|
258
|
+
upload_id: z.string().min(1).describe("Upload id from createMultipartUpload")
|
|
259
|
+
});
|
|
260
|
+
const abortMultipartUploadOutputSchema = z.object({
|
|
261
|
+
key: z.string(),
|
|
262
|
+
upload_id: z.string(),
|
|
263
|
+
aborted: z.boolean()
|
|
264
|
+
});
|
|
265
|
+
z.object({
|
|
266
|
+
keys: z.array(z.string().min(1)).min(1).max(25).describe("Object keys to download"),
|
|
267
|
+
encoding: z.enum(["base64", "utf8"]).optional().describe("Body encoding for each item. Defaults to base64")
|
|
268
|
+
});
|
|
269
|
+
z.object({ objects: z.array(putObjectInputSchema).min(1).max(25).describe("Objects to upload") });
|
|
270
|
+
z.object({ keys: z.array(z.string().min(1)).min(1).max(25).describe("Object keys to delete") });
|
|
271
|
+
batchResultSchema(getObjectOutputSchema);
|
|
272
|
+
batchResultSchema(putObjectOutputSchema);
|
|
273
|
+
batchResultSchema(deleteObjectOutputSchema);
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/vendors/s3/contracts.ts
|
|
276
|
+
/**
|
|
277
|
+
* S3 / S3-compatible vendor auth + re-exports of shared object-store I/O.
|
|
278
|
+
*/
|
|
279
|
+
const s3AuthSchema = z.object({
|
|
280
|
+
access_key_id: z.string().min(1).describe("S3 access key id"),
|
|
281
|
+
secret_access_key: z.string().min(1).describe("S3 secret access key"),
|
|
282
|
+
region: z.string().min(1).describe("AWS region, or auto / us-east-1 for R2 S3 endpoint"),
|
|
283
|
+
bucket: z.string().min(1).describe("Default bucket name"),
|
|
284
|
+
endpoint: z.url().optional().describe("S3-compatible endpoint when not AWS (R2: https://<account_id>.r2.cloudflarestorage.com, MinIO, …)"),
|
|
285
|
+
session_token: z.string().min(1).optional().describe("Optional session token for temporary credentials"),
|
|
286
|
+
key_prefix: z.string().min(1).optional().describe("Optional object-key root for this binding (no leading slash). Logical keys are relative to this prefix; wire keys include it. Host tenant scoping binds once here.")
|
|
287
|
+
});
|
|
288
|
+
//#endregion
|
|
289
|
+
//#region src/vendors/s3/domain.ts
|
|
290
|
+
/**
|
|
291
|
+
* S3 URL building + XML response parse (fast-xml-parser).
|
|
292
|
+
*/
|
|
293
|
+
const listParser = new XMLParser({
|
|
294
|
+
ignoreAttributes: true,
|
|
295
|
+
trimValues: true,
|
|
296
|
+
isArray: (name) => name === "Contents" || name === "CommonPrefixes"
|
|
297
|
+
});
|
|
298
|
+
const genericParser = new XMLParser({
|
|
299
|
+
ignoreAttributes: true,
|
|
300
|
+
trimValues: true
|
|
301
|
+
});
|
|
302
|
+
function objectUrl(auth, key, query) {
|
|
303
|
+
const encodedKey = encodeObjectKeyPath(key);
|
|
304
|
+
const base = auth.endpoint ? `${auth.endpoint.replace(/\/+$/, "")}/${encodeURIComponent(auth.bucket)}/${encodedKey}` : `https://${auth.bucket}.s3.${auth.region}.amazonaws.com/${encodedKey}`;
|
|
305
|
+
return query ? `${base}?${query}` : base;
|
|
306
|
+
}
|
|
307
|
+
function listUrl(auth, params) {
|
|
308
|
+
const base = auth.endpoint ? `${auth.endpoint.replace(/\/+$/, "")}/${encodeURIComponent(auth.bucket)}` : `https://${auth.bucket}.s3.${auth.region}.amazonaws.com`;
|
|
309
|
+
const qs = params.toString();
|
|
310
|
+
return qs ? `${base}?${qs}` : base;
|
|
311
|
+
}
|
|
312
|
+
function copySourceHeader(auth, sourceKey, sourceBucket) {
|
|
313
|
+
const bucket = sourceBucket ?? auth.bucket;
|
|
314
|
+
return `/${encodeURIComponent(bucket)}/${encodeObjectKeyPath(sourceKey)}`;
|
|
315
|
+
}
|
|
316
|
+
function stripEtagQuotes(etag) {
|
|
317
|
+
return etag.replaceAll("\"", "");
|
|
318
|
+
}
|
|
319
|
+
/** Parse `Content-Range: bytes start-end/total` → total object size when known. */
|
|
320
|
+
function contentRangeTotal(header) {
|
|
321
|
+
if (header === null || header.length === 0) return void 0;
|
|
322
|
+
const slash = header.lastIndexOf("/");
|
|
323
|
+
if (slash < 0) return void 0;
|
|
324
|
+
const totalRaw = header.slice(slash + 1).trim();
|
|
325
|
+
if (totalRaw === "*" || totalRaw.length === 0) return void 0;
|
|
326
|
+
const total = Number.parseInt(totalRaw, 10);
|
|
327
|
+
return Number.isFinite(total) ? total : void 0;
|
|
328
|
+
}
|
|
329
|
+
function asArray(value) {
|
|
330
|
+
if (value === void 0 || value === null) return [];
|
|
331
|
+
return isArray(value) ? value : [value];
|
|
332
|
+
}
|
|
333
|
+
function textValue(value) {
|
|
334
|
+
if (isString(value) && value.length > 0) return value;
|
|
335
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
336
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
337
|
+
}
|
|
338
|
+
function numberValue(value) {
|
|
339
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
340
|
+
if (isString(value) && value.length > 0) {
|
|
341
|
+
const n = Number.parseInt(value, 10);
|
|
342
|
+
return Number.isFinite(n) ? n : void 0;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/** Parse ListObjectsV2 XML into list items + pagination. */
|
|
346
|
+
function parseListResult(xml) {
|
|
347
|
+
const doc = listParser.parse(xml);
|
|
348
|
+
const root = isPlainObject(doc) && isPlainObject(doc["ListBucketResult"]) ? doc["ListBucketResult"] : isPlainObject(doc) ? doc : null;
|
|
349
|
+
if (!root) return {
|
|
350
|
+
items: [],
|
|
351
|
+
truncated: false
|
|
352
|
+
};
|
|
353
|
+
const items = [];
|
|
354
|
+
for (const row of asArray(root["Contents"])) {
|
|
355
|
+
if (!isPlainObject(row)) continue;
|
|
356
|
+
const key = textValue(row["Key"]);
|
|
357
|
+
if (!key) continue;
|
|
358
|
+
const size = numberValue(row["Size"]);
|
|
359
|
+
const last_modified = textValue(row["LastModified"]);
|
|
360
|
+
const etagRaw = textValue(row["ETag"]);
|
|
361
|
+
const etag = etagRaw ? stripEtagQuotes(etagRaw) : void 0;
|
|
362
|
+
items.push({
|
|
363
|
+
key,
|
|
364
|
+
...size !== void 0 && { size },
|
|
365
|
+
...last_modified && { last_modified },
|
|
366
|
+
...etag && { etag }
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
const truncatedRaw = root["IsTruncated"];
|
|
370
|
+
const truncated = truncatedRaw === true || truncatedRaw === "true" || isString(truncatedRaw) && truncatedRaw.toLowerCase() === "true";
|
|
371
|
+
const next = textValue(root["NextContinuationToken"]);
|
|
372
|
+
const common_prefixes = [];
|
|
373
|
+
for (const row of asArray(root["CommonPrefixes"])) {
|
|
374
|
+
if (!isPlainObject(row)) continue;
|
|
375
|
+
const prefix = textValue(row["Prefix"]);
|
|
376
|
+
if (prefix) common_prefixes.push(prefix);
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
items,
|
|
380
|
+
truncated,
|
|
381
|
+
...next && { next_cursor: next },
|
|
382
|
+
...common_prefixes.length > 0 && { common_prefixes }
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
/** First text value for a tag anywhere in a small S3 XML body (ETag, UploadId, …). */
|
|
386
|
+
function firstXmlText(xml, tag) {
|
|
387
|
+
return findTagText(genericParser.parse(xml), tag);
|
|
388
|
+
}
|
|
389
|
+
function findTagText(node, tag) {
|
|
390
|
+
if (!isPlainObject(node)) return void 0;
|
|
391
|
+
if (Object.hasOwn(node, tag)) {
|
|
392
|
+
const direct = textValue(node[tag]);
|
|
393
|
+
if (direct) return direct;
|
|
394
|
+
}
|
|
395
|
+
for (const value of Object.values(node)) {
|
|
396
|
+
const found = findTagText(value, tag);
|
|
397
|
+
if (found) return found;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
//#endregion
|
|
401
|
+
//#region src/vendors/s3/client.ts
|
|
402
|
+
/**
|
|
403
|
+
* S3 / S3-compatible object-store client (AwsService SigV4).
|
|
404
|
+
* Host: `new S3Client(auth)`. Agent tools: `fromContext(ctx)`.
|
|
405
|
+
*
|
|
406
|
+
* When auth.key_prefix is set, public API keys are logical (prefix-relative);
|
|
407
|
+
* wire keys always include the prefix. Resolve once; private methods take wire keys.
|
|
408
|
+
*/
|
|
409
|
+
function objectNotFound() {
|
|
410
|
+
throw new ToolError("Object not found", { code: "not_found" });
|
|
411
|
+
}
|
|
412
|
+
function remapNotFound(error) {
|
|
413
|
+
if (isToolError(error) && error.code === "not_found") objectNotFound();
|
|
414
|
+
throw error;
|
|
415
|
+
}
|
|
416
|
+
function tooLarge(maxBytes, contentLength, message, cause) {
|
|
417
|
+
throw new ToolError(message, {
|
|
418
|
+
code: "too_large",
|
|
419
|
+
details: {
|
|
420
|
+
max_bytes: maxBytes,
|
|
421
|
+
content_length: contentLength
|
|
422
|
+
},
|
|
423
|
+
...cause !== void 0 && { cause }
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
function assertByteLimit(maxBytes) {
|
|
427
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) throw new ToolError("Download limit must be a non-negative safe integer", { code: "bad_input" });
|
|
428
|
+
}
|
|
429
|
+
var S3Client = class S3Client {
|
|
430
|
+
#auth;
|
|
431
|
+
#aws;
|
|
432
|
+
/** Normalized key_prefix with trailing `/`, or undefined when unbound. */
|
|
433
|
+
#keyPrefix;
|
|
434
|
+
constructor(auth, options = {}) {
|
|
435
|
+
const parsed = s3AuthSchema.safeParse(auth);
|
|
436
|
+
if (!parsed.success) throw new ToolError("Invalid S3 auth credentials", {
|
|
437
|
+
code: "bad_auth",
|
|
438
|
+
details: { issues: parsed.error.issues.map((issue) => issue.message) }
|
|
439
|
+
});
|
|
440
|
+
this.#auth = parsed.data;
|
|
441
|
+
this.#keyPrefix = parsed.data.key_prefix !== void 0 ? normalizeKeyPrefix(parsed.data.key_prefix) : void 0;
|
|
442
|
+
const awsOptions = {
|
|
443
|
+
accessKeyId: this.#auth.access_key_id,
|
|
444
|
+
secretAccessKey: this.#auth.secret_access_key,
|
|
445
|
+
region: this.#auth.region,
|
|
446
|
+
service: "s3",
|
|
447
|
+
label: "S3"
|
|
448
|
+
};
|
|
449
|
+
if (options.fetch) awsOptions.fetch = options.fetch;
|
|
450
|
+
if (options.signal) awsOptions.signal = options.signal;
|
|
451
|
+
if (this.#auth.session_token) awsOptions.sessionToken = this.#auth.session_token;
|
|
452
|
+
this.#aws = new AwsService(awsOptions);
|
|
453
|
+
}
|
|
454
|
+
static fromContext(ctx) {
|
|
455
|
+
const auth = requireAuth(ctx, s3AuthSchema);
|
|
456
|
+
const options = {};
|
|
457
|
+
if (ctx.fetch) options.fetch = ctx.fetch;
|
|
458
|
+
if (ctx.signal) options.signal = ctx.signal;
|
|
459
|
+
return new S3Client(auth, options);
|
|
460
|
+
}
|
|
461
|
+
#resolve(logicalKey) {
|
|
462
|
+
return resolveObjectKey(logicalKey, this.#keyPrefix);
|
|
463
|
+
}
|
|
464
|
+
#publicKey(wireKey) {
|
|
465
|
+
const publicKey = toPublicKey(wireKey, this.#keyPrefix);
|
|
466
|
+
if (publicKey === void 0) throw new ToolError("Object key is outside the bound key_prefix", { code: "bad_input" });
|
|
467
|
+
return publicKey;
|
|
468
|
+
}
|
|
469
|
+
/** Source key for copy: scoped only when same bucket as this client. */
|
|
470
|
+
#resolveCopySourceKey(sourceKey, sourceBucket) {
|
|
471
|
+
if (sourceBucket === void 0 || sourceBucket === this.#auth.bucket) return this.#resolve(sourceKey);
|
|
472
|
+
return resolveObjectKey(sourceKey, void 0);
|
|
473
|
+
}
|
|
474
|
+
async list(input) {
|
|
475
|
+
const prefix = resolveListPrefix(input.prefix, this.#keyPrefix);
|
|
476
|
+
const params = new URLSearchParams({ "list-type": "2" });
|
|
477
|
+
if (prefix !== void 0) params.set("prefix", prefix);
|
|
478
|
+
if (input.delimiter) params.set("delimiter", input.delimiter);
|
|
479
|
+
if (input.cursor) params.set("continuation-token", input.cursor);
|
|
480
|
+
if (input.limit !== void 0) params.set("max-keys", String(input.limit));
|
|
481
|
+
const { bytes } = await this.#aws.bytes("GET", listUrl(this.#auth, params), { label: "S3 list" });
|
|
482
|
+
const listed = parseListResult(bytesToUtf8(bytes));
|
|
483
|
+
const items = [];
|
|
484
|
+
const keys = [];
|
|
485
|
+
for (const obj of listed.items) {
|
|
486
|
+
const publicKey = toPublicKey(obj.key, this.#keyPrefix);
|
|
487
|
+
if (publicKey === void 0) continue;
|
|
488
|
+
keys.push(publicKey);
|
|
489
|
+
items.push({
|
|
490
|
+
key: publicKey,
|
|
491
|
+
...obj.size !== void 0 && { size: obj.size },
|
|
492
|
+
...obj.last_modified && { last_modified: obj.last_modified },
|
|
493
|
+
...obj.etag && { etag: obj.etag }
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
const out = {
|
|
497
|
+
keys,
|
|
498
|
+
items,
|
|
499
|
+
truncated: listed.truncated
|
|
500
|
+
};
|
|
501
|
+
if (listed.common_prefixes && listed.common_prefixes.length > 0) {
|
|
502
|
+
const common = [];
|
|
503
|
+
for (const folderAbs of listed.common_prefixes) {
|
|
504
|
+
const publicPrefix = toPublicKey(folderAbs, this.#keyPrefix);
|
|
505
|
+
if (publicPrefix !== void 0) common.push(publicPrefix);
|
|
506
|
+
}
|
|
507
|
+
if (common.length > 0) out.common_prefixes = common;
|
|
508
|
+
}
|
|
509
|
+
if (listed.next_cursor) out.next_cursor = listed.next_cursor;
|
|
510
|
+
return out;
|
|
511
|
+
}
|
|
512
|
+
/** HEAD size gate plus a bounded Range GET (wire key only). */
|
|
513
|
+
async #getBoundedWire(wireKey, maxBytes, limitMessage) {
|
|
514
|
+
assertByteLimit(maxBytes);
|
|
515
|
+
const head = await this.#headWire(wireKey);
|
|
516
|
+
if (!head.exists) objectNotFound();
|
|
517
|
+
if (!isNil(head.content_length) && head.content_length > maxBytes) tooLarge(maxBytes, head.content_length, limitMessage);
|
|
518
|
+
if (head.content_length === 0) {
|
|
519
|
+
const headers = new Headers({ "content-length": "0" });
|
|
520
|
+
if (head.content_type) headers.set("content-type", head.content_type);
|
|
521
|
+
if (head.etag) headers.set("etag", `"${head.etag}"`);
|
|
522
|
+
return {
|
|
523
|
+
bytes: /* @__PURE__ */ new Uint8Array(),
|
|
524
|
+
headers,
|
|
525
|
+
head
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
const headers = { Range: `bytes=0-${maxBytes}` };
|
|
529
|
+
if (head.etag) headers["If-Match"] = head.etag.startsWith("\"") ? head.etag : `"${head.etag}"`;
|
|
530
|
+
let response;
|
|
531
|
+
try {
|
|
532
|
+
response = await this.#aws.bytes("GET", objectUrl(this.#auth, wireKey), {
|
|
533
|
+
label: "S3 get",
|
|
534
|
+
headers,
|
|
535
|
+
maxBytes
|
|
536
|
+
});
|
|
537
|
+
} catch (error) {
|
|
538
|
+
if (isToolError(error) && error.code === "too_large") {
|
|
539
|
+
const observed = error.details?.["content_length"];
|
|
540
|
+
tooLarge(maxBytes, isNumber(observed) && Number.isFinite(observed) ? observed : maxBytes + 1, limitMessage, error);
|
|
541
|
+
}
|
|
542
|
+
if (isToolError(error) && error.details?.["status"] === 412) throw new ToolError("Object changed during download", {
|
|
543
|
+
code: "upstream",
|
|
544
|
+
details: {
|
|
545
|
+
status: 412,
|
|
546
|
+
key: this.#publicKey(wireKey)
|
|
547
|
+
},
|
|
548
|
+
cause: error
|
|
549
|
+
});
|
|
550
|
+
remapNotFound(error);
|
|
551
|
+
}
|
|
552
|
+
const total = contentRangeTotal(response.headers.get("content-range"));
|
|
553
|
+
if (total !== void 0 && total > maxBytes) tooLarge(maxBytes, total, limitMessage);
|
|
554
|
+
return {
|
|
555
|
+
bytes: response.bytes,
|
|
556
|
+
headers: response.headers,
|
|
557
|
+
head
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
async #headWire(wireKey) {
|
|
561
|
+
const response = await this.#aws.head(objectUrl(this.#auth, wireKey), {
|
|
562
|
+
label: "S3 head",
|
|
563
|
+
allowStatuses: [404]
|
|
564
|
+
});
|
|
565
|
+
const publicKey = this.#publicKey(wireKey);
|
|
566
|
+
if (response.status === 404) return {
|
|
567
|
+
key: publicKey,
|
|
568
|
+
exists: false
|
|
569
|
+
};
|
|
570
|
+
const contentType = response.headers.get("content-type");
|
|
571
|
+
const lengthHeader = response.headers.get("content-length");
|
|
572
|
+
const etag = response.headers.get("etag");
|
|
573
|
+
const contentLength = isString(lengthHeader) ? Number.parseInt(lengthHeader, 10) : void 0;
|
|
574
|
+
const out = {
|
|
575
|
+
key: publicKey,
|
|
576
|
+
exists: true
|
|
577
|
+
};
|
|
578
|
+
if (isString(contentType)) out.content_type = contentType;
|
|
579
|
+
if (!isNil(contentLength) && Number.isFinite(contentLength)) out.content_length = contentLength;
|
|
580
|
+
if (isString(etag)) out.etag = stripEtagQuotes(etag);
|
|
581
|
+
return out;
|
|
582
|
+
}
|
|
583
|
+
async get(input) {
|
|
584
|
+
const wireKey = this.#resolve(input.key);
|
|
585
|
+
const { bytes: bodyBytes, headers: responseHeaders, head } = await this.#getBoundedWire(wireKey, MAX_OBJECT_BYTES, "Object exceeds 5 MiB download limit");
|
|
586
|
+
const encoding = input.encoding ?? "base64";
|
|
587
|
+
const body = encoding === "utf8" ? bytesToUtf8(bodyBytes) : bytesToBase64(bodyBytes);
|
|
588
|
+
const contentType = responseHeaders.get("content-type") ?? head.content_type;
|
|
589
|
+
const lengthHeader = responseHeaders.get("content-length");
|
|
590
|
+
const contentLength = isString(lengthHeader) ? Number.parseInt(lengthHeader, 10) : head.content_length;
|
|
591
|
+
const out = {
|
|
592
|
+
key: this.#publicKey(wireKey),
|
|
593
|
+
body,
|
|
594
|
+
encoding
|
|
595
|
+
};
|
|
596
|
+
if (isString(contentType)) out.content_type = contentType;
|
|
597
|
+
out.content_length = !isNil(head.content_length) && Number.isFinite(head.content_length) ? head.content_length : isNil(contentLength) || !Number.isFinite(contentLength) ? bodyBytes.byteLength : contentLength;
|
|
598
|
+
return out;
|
|
599
|
+
}
|
|
600
|
+
async put(input) {
|
|
601
|
+
const wireKey = this.#resolve(input.key);
|
|
602
|
+
const bodyBytes = (input.body_encoding ?? "utf8") === "base64" ? base64ToBytes(input.body) : utf8ToBytes(input.body);
|
|
603
|
+
if (bodyBytes.byteLength > 5242880) throw new ToolError("Object exceeds 5 MiB upload limit", {
|
|
604
|
+
code: "too_large",
|
|
605
|
+
details: {
|
|
606
|
+
max_bytes: MAX_OBJECT_BYTES,
|
|
607
|
+
content_length: bodyBytes.byteLength
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
const headers = {};
|
|
611
|
+
if (input.content_type) headers["Content-Type"] = input.content_type;
|
|
612
|
+
const etag = (await this.#aws.put(objectUrl(this.#auth, wireKey), toArrayBuffer(bodyBytes), {
|
|
613
|
+
label: "S3 put",
|
|
614
|
+
headers
|
|
615
|
+
})).headers.get("etag");
|
|
616
|
+
const out = {
|
|
617
|
+
key: this.#publicKey(wireKey),
|
|
618
|
+
content_length: bodyBytes.byteLength
|
|
619
|
+
};
|
|
620
|
+
if (isString(etag)) out.etag = stripEtagQuotes(etag);
|
|
621
|
+
return out;
|
|
622
|
+
}
|
|
623
|
+
async delete(input) {
|
|
624
|
+
const wireKey = this.#resolve(input.key);
|
|
625
|
+
await this.#aws.delete(objectUrl(this.#auth, wireKey), {
|
|
626
|
+
label: "S3 delete",
|
|
627
|
+
allowStatuses: [404]
|
|
628
|
+
});
|
|
629
|
+
return {
|
|
630
|
+
key: this.#publicKey(wireKey),
|
|
631
|
+
deleted: true
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
async head(input) {
|
|
635
|
+
return this.#headWire(this.#resolve(input.key));
|
|
636
|
+
}
|
|
637
|
+
async copy(input) {
|
|
638
|
+
const destWire = this.#resolve(input.destination_key);
|
|
639
|
+
const sourceWire = this.#resolveCopySourceKey(input.source_key, input.source_bucket);
|
|
640
|
+
const response = await this.#aws.bytes("PUT", objectUrl(this.#auth, destWire), {
|
|
641
|
+
label: "S3 copy",
|
|
642
|
+
headers: { "x-amz-copy-source": copySourceHeader(this.#auth, sourceWire, input.source_bucket) }
|
|
643
|
+
});
|
|
644
|
+
const etagRaw = firstXmlText(bytesToUtf8(response.bytes), "ETag");
|
|
645
|
+
const headerEtag = response.headers.get("etag");
|
|
646
|
+
const etag = etagRaw ? stripEtagQuotes(etagRaw) : isString(headerEtag) ? stripEtagQuotes(headerEtag) : void 0;
|
|
647
|
+
const out = {
|
|
648
|
+
source_key: input.source_bucket === void 0 || input.source_bucket === this.#auth.bucket ? this.#publicKey(sourceWire) : sourceWire,
|
|
649
|
+
destination_key: this.#publicKey(destWire)
|
|
650
|
+
};
|
|
651
|
+
if (etag) out.etag = etag;
|
|
652
|
+
return out;
|
|
653
|
+
}
|
|
654
|
+
async createSignedUrl(input) {
|
|
655
|
+
const wireKey = this.#resolve(input.key);
|
|
656
|
+
const method = input.method ?? "GET";
|
|
657
|
+
const expiresIn = input.expires_in ?? 3600;
|
|
658
|
+
const url = objectUrl(this.#auth, wireKey, `X-Amz-Expires=${expiresIn}`);
|
|
659
|
+
return {
|
|
660
|
+
url: (await this.#aws.sign(url, {
|
|
661
|
+
method,
|
|
662
|
+
signQuery: true
|
|
663
|
+
})).url,
|
|
664
|
+
method,
|
|
665
|
+
expires_in: expiresIn
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
async createMultipartUpload(input) {
|
|
669
|
+
const wireKey = this.#resolve(input.key);
|
|
670
|
+
const headers = {};
|
|
671
|
+
if (input.content_type) headers["Content-Type"] = input.content_type;
|
|
672
|
+
const { bytes } = await this.#aws.bytes("POST", objectUrl(this.#auth, wireKey, "uploads"), {
|
|
673
|
+
label: "S3 create multipart upload",
|
|
674
|
+
headers
|
|
675
|
+
});
|
|
676
|
+
const uploadIdRaw = firstXmlText(bytesToUtf8(bytes), "UploadId");
|
|
677
|
+
if (!uploadIdRaw) throw new ToolError("S3 create multipart upload returned no UploadId", { code: "upstream" });
|
|
678
|
+
return {
|
|
679
|
+
key: this.#publicKey(wireKey),
|
|
680
|
+
upload_id: uploadIdRaw
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
async uploadPart(input) {
|
|
684
|
+
const wireKey = this.#resolve(input.key);
|
|
685
|
+
const bodyBytes = (input.body_encoding ?? "utf8") === "base64" ? base64ToBytes(input.body) : utf8ToBytes(input.body);
|
|
686
|
+
if (bodyBytes.byteLength > 26214400) throw new ToolError("Multipart part exceeds 25 MiB upload limit", {
|
|
687
|
+
code: "too_large",
|
|
688
|
+
details: {
|
|
689
|
+
max_bytes: MAX_MULTIPART_PART_BYTES,
|
|
690
|
+
content_length: bodyBytes.byteLength
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
if (bodyBytes.byteLength === 0) throw new ToolError("Multipart part body must not be empty", { code: "bad_input" });
|
|
694
|
+
const query = new URLSearchParams({
|
|
695
|
+
partNumber: String(input.part_number),
|
|
696
|
+
uploadId: input.upload_id
|
|
697
|
+
});
|
|
698
|
+
const etagHeader = (await this.#aws.put(objectUrl(this.#auth, wireKey, query.toString()), toArrayBuffer(bodyBytes), { label: "S3 upload part" })).headers.get("etag");
|
|
699
|
+
if (!isString(etagHeader) || etagHeader.length === 0) throw new ToolError("S3 upload part returned no ETag", { code: "upstream" });
|
|
700
|
+
return {
|
|
701
|
+
key: this.#publicKey(wireKey),
|
|
702
|
+
upload_id: input.upload_id,
|
|
703
|
+
part_number: input.part_number,
|
|
704
|
+
etag: stripEtagQuotes(etagHeader),
|
|
705
|
+
content_length: bodyBytes.byteLength
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
async completeMultipartUpload(input) {
|
|
709
|
+
const wireKey = this.#resolve(input.key);
|
|
710
|
+
const body = `<CompleteMultipartUpload>${[...input.parts].sort((a, b) => a.part_number - b.part_number).map((part) => {
|
|
711
|
+
const etag = stripEtagQuotes(part.etag);
|
|
712
|
+
return `<Part><PartNumber>${part.part_number}</PartNumber><ETag>"${etag}"</ETag></Part>`;
|
|
713
|
+
}).join("")}</CompleteMultipartUpload>`;
|
|
714
|
+
const query = new URLSearchParams({ uploadId: input.upload_id });
|
|
715
|
+
const response = await this.#aws.bytes("POST", objectUrl(this.#auth, wireKey, query.toString()), {
|
|
716
|
+
label: "S3 complete multipart upload",
|
|
717
|
+
body,
|
|
718
|
+
headers: { "Content-Type": "application/xml" }
|
|
719
|
+
});
|
|
720
|
+
const etagRaw = firstXmlText(bytesToUtf8(response.bytes), "ETag");
|
|
721
|
+
const headerEtag = response.headers.get("etag");
|
|
722
|
+
const etag = etagRaw ? stripEtagQuotes(etagRaw) : isString(headerEtag) ? stripEtagQuotes(headerEtag) : void 0;
|
|
723
|
+
const out = {
|
|
724
|
+
key: this.#publicKey(wireKey),
|
|
725
|
+
upload_id: input.upload_id
|
|
726
|
+
};
|
|
727
|
+
if (etag) out.etag = etag;
|
|
728
|
+
return out;
|
|
729
|
+
}
|
|
730
|
+
async abortMultipartUpload(input) {
|
|
731
|
+
const wireKey = this.#resolve(input.key);
|
|
732
|
+
const query = new URLSearchParams({ uploadId: input.upload_id });
|
|
733
|
+
await this.#aws.delete(objectUrl(this.#auth, wireKey, query.toString()), {
|
|
734
|
+
label: "S3 abort multipart upload",
|
|
735
|
+
allowStatuses: [404]
|
|
736
|
+
});
|
|
737
|
+
return {
|
|
738
|
+
key: this.#publicKey(wireKey),
|
|
739
|
+
upload_id: input.upload_id,
|
|
740
|
+
aborted: true
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
/** Host-facing raw download. Pass `maxBytes` to enforce a hard download cap. Logical key when key_prefix is set. */
|
|
744
|
+
async getBytes(key, options = {}) {
|
|
745
|
+
const wireKey = this.#resolve(key);
|
|
746
|
+
const maxBytes = options.maxBytes;
|
|
747
|
+
if (maxBytes !== void 0) {
|
|
748
|
+
const { bytes } = await this.#getBoundedWire(wireKey, maxBytes, "Object exceeds download limit");
|
|
749
|
+
return bytes;
|
|
750
|
+
}
|
|
751
|
+
try {
|
|
752
|
+
const { bytes } = await this.#aws.bytes("GET", objectUrl(this.#auth, wireKey), { label: "S3 get" });
|
|
753
|
+
return bytes;
|
|
754
|
+
} catch (error) {
|
|
755
|
+
remapNotFound(error);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
async getBytesRange(key, range) {
|
|
759
|
+
const wireKey = this.#resolve(key);
|
|
760
|
+
const requestedBytes = range.end_byte - range.start_byte + 1;
|
|
761
|
+
if (!Number.isSafeInteger(range.start_byte) || !Number.isSafeInteger(range.end_byte) || range.start_byte < 0 || requestedBytes < 1) throw new ToolError("Byte range must use non-negative inclusive offsets with end_byte >= start_byte", { code: "bad_input" });
|
|
762
|
+
if (requestedBytes > 5242880) tooLarge(MAX_OBJECT_BYTES, requestedBytes, "Byte range exceeds download limit");
|
|
763
|
+
const head = await this.#headWire(wireKey);
|
|
764
|
+
if (!head.exists) objectNotFound();
|
|
765
|
+
if (head.content_length !== void 0 && range.start_byte >= head.content_length) throw new ToolError("Byte range starts beyond the end of the object", {
|
|
766
|
+
code: "bad_input",
|
|
767
|
+
details: {
|
|
768
|
+
start_byte: range.start_byte,
|
|
769
|
+
content_length: head.content_length
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
const headers = { Range: `bytes=${range.start_byte}-${range.end_byte}` };
|
|
773
|
+
if (head.etag) headers["If-Match"] = head.etag.startsWith("\"") ? head.etag : `"${head.etag}"`;
|
|
774
|
+
let response;
|
|
775
|
+
try {
|
|
776
|
+
response = await this.#aws.bytes("GET", objectUrl(this.#auth, wireKey), {
|
|
777
|
+
label: "S3 range get",
|
|
778
|
+
headers,
|
|
779
|
+
maxBytes: requestedBytes
|
|
780
|
+
});
|
|
781
|
+
} catch (error) {
|
|
782
|
+
if (isToolError(error) && error.details?.["status"] === 412) throw new ToolError("Object changed during download", {
|
|
783
|
+
code: "upstream",
|
|
784
|
+
details: {
|
|
785
|
+
status: 412,
|
|
786
|
+
key: this.#publicKey(wireKey)
|
|
787
|
+
},
|
|
788
|
+
cause: error
|
|
789
|
+
});
|
|
790
|
+
remapNotFound(error);
|
|
791
|
+
}
|
|
792
|
+
const out = {
|
|
793
|
+
bytes: response.bytes,
|
|
794
|
+
start_byte: range.start_byte,
|
|
795
|
+
end_byte: range.start_byte + response.bytes.byteLength - 1
|
|
796
|
+
};
|
|
797
|
+
const totalBytes = contentRangeTotal(response.headers.get("content-range")) ?? head.content_length;
|
|
798
|
+
const contentType = response.headers.get("content-type") ?? head.content_type;
|
|
799
|
+
if (totalBytes !== void 0) out.total_bytes = totalBytes;
|
|
800
|
+
if (contentType) out.content_type = contentType;
|
|
801
|
+
return out;
|
|
802
|
+
}
|
|
803
|
+
/** Host-facing raw upload. Logical key when key_prefix is set. */
|
|
804
|
+
async putBytes(key, bytes, contentType) {
|
|
805
|
+
const wireKey = this.#resolve(key);
|
|
806
|
+
const headers = {};
|
|
807
|
+
if (isString(contentType) && contentType.length > 0) headers["Content-Type"] = contentType;
|
|
808
|
+
await this.#aws.put(objectUrl(this.#auth, wireKey), toArrayBuffer(bytes), {
|
|
809
|
+
label: "S3 put",
|
|
810
|
+
headers
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
//#endregion
|
|
815
|
+
//#region src/vendors/s3/module.ts
|
|
816
|
+
const s3ListObjectsTool = defineTool({
|
|
817
|
+
id: "s3-list-objects",
|
|
818
|
+
name: "s3ListObjects",
|
|
819
|
+
description: "List objects in the bound S3 bucket. Use prefix, delimiter, cursor, and limit for filtered pagination. Returns keys, items with metadata, next_cursor, and truncated.",
|
|
820
|
+
inputSchema: listObjectsInputSchema,
|
|
821
|
+
outputSchema: listObjectsOutputSchema,
|
|
822
|
+
sideEffect: "read",
|
|
823
|
+
runtime: "both",
|
|
824
|
+
execute: async (input, ctx) => S3Client.fromContext(ctx).list(input)
|
|
825
|
+
});
|
|
826
|
+
const s3GetObjectTool = defineTool({
|
|
827
|
+
id: "s3-get-object",
|
|
828
|
+
name: "s3GetObject",
|
|
829
|
+
description: "Download one object by key from S3. Bodies larger than 5 MiB fail. Returns body as base64 by default or utf8 when requested.",
|
|
830
|
+
inputSchema: getObjectInputSchema,
|
|
831
|
+
outputSchema: getObjectOutputSchema,
|
|
832
|
+
sideEffect: "read",
|
|
833
|
+
runtime: "both",
|
|
834
|
+
execute: async (input, ctx) => S3Client.fromContext(ctx).get(input)
|
|
835
|
+
});
|
|
836
|
+
const s3PutObjectTool = defineTool({
|
|
837
|
+
id: "s3-put-object",
|
|
838
|
+
name: "s3PutObject",
|
|
839
|
+
description: "Upload or replace one object by key in S3. Provide utf8 text or base64 body. Bodies larger than 5 MiB fail.",
|
|
840
|
+
inputSchema: putObjectInputSchema,
|
|
841
|
+
outputSchema: putObjectOutputSchema,
|
|
842
|
+
sideEffect: "write",
|
|
843
|
+
runtime: "both",
|
|
844
|
+
execute: async (input, ctx) => S3Client.fromContext(ctx).put(input)
|
|
845
|
+
});
|
|
846
|
+
const s3DeleteObjectTool = defineTool({
|
|
847
|
+
id: "s3-delete-object",
|
|
848
|
+
name: "s3DeleteObject",
|
|
849
|
+
description: "Delete one object by key in S3. Idempotent for missing keys (404 treated as success).",
|
|
850
|
+
inputSchema: deleteObjectInputSchema,
|
|
851
|
+
outputSchema: deleteObjectOutputSchema,
|
|
852
|
+
sideEffect: "delete",
|
|
853
|
+
runtime: "both",
|
|
854
|
+
execute: async (input, ctx) => S3Client.fromContext(ctx).delete(input)
|
|
855
|
+
});
|
|
856
|
+
const s3HeadObjectTool = defineTool({
|
|
857
|
+
id: "s3-head-object",
|
|
858
|
+
name: "s3HeadObject",
|
|
859
|
+
description: "Inspect S3 object metadata by key without downloading the body. Returns exists flag plus content type, length, and ETag when present.",
|
|
860
|
+
inputSchema: headObjectInputSchema,
|
|
861
|
+
outputSchema: headObjectOutputSchema,
|
|
862
|
+
sideEffect: "read",
|
|
863
|
+
runtime: "both",
|
|
864
|
+
execute: async (input, ctx) => S3Client.fromContext(ctx).head(input)
|
|
865
|
+
});
|
|
866
|
+
const s3CopyObjectTool = defineTool({
|
|
867
|
+
id: "s3-copy-object",
|
|
868
|
+
name: "s3CopyObject",
|
|
869
|
+
description: "Copy one S3 object to a new key. Set source_bucket only for an allowed cross-bucket copy; otherwise the configured bucket is used.",
|
|
870
|
+
inputSchema: copyObjectInputSchema,
|
|
871
|
+
outputSchema: copyObjectOutputSchema,
|
|
872
|
+
sideEffect: "write",
|
|
873
|
+
runtime: "both",
|
|
874
|
+
execute: async (input, ctx) => S3Client.fromContext(ctx).copy(input)
|
|
875
|
+
});
|
|
876
|
+
const s3CreateSignedUrlTool = defineTool({
|
|
877
|
+
id: "s3-create-signed-url",
|
|
878
|
+
name: "s3CreateSignedUrl",
|
|
879
|
+
description: "Create a time-limited presigned S3 URL for one object key. Defaults to GET for 3600 seconds.",
|
|
880
|
+
inputSchema: signedUrlInputSchema,
|
|
881
|
+
outputSchema: signedUrlOutputSchema,
|
|
882
|
+
sideEffect: "none",
|
|
883
|
+
runtime: "both",
|
|
884
|
+
execute: async (input, ctx) => S3Client.fromContext(ctx).createSignedUrl(input)
|
|
885
|
+
});
|
|
886
|
+
const s3CreateMultipartUploadTool = defineTool({
|
|
887
|
+
id: "s3-create-multipart-upload",
|
|
888
|
+
name: "s3CreateMultipartUpload",
|
|
889
|
+
description: "Start an S3 multipart upload for one object key. Returns upload_id for uploadPart/complete/abort. Use for objects larger than the single put limit.",
|
|
890
|
+
inputSchema: createMultipartUploadInputSchema,
|
|
891
|
+
outputSchema: createMultipartUploadOutputSchema,
|
|
892
|
+
sideEffect: "write",
|
|
893
|
+
runtime: "both",
|
|
894
|
+
execute: async (input, ctx) => S3Client.fromContext(ctx).createMultipartUpload(input)
|
|
895
|
+
});
|
|
896
|
+
const s3UploadPartTool = defineTool({
|
|
897
|
+
id: "s3-upload-part",
|
|
898
|
+
name: "s3UploadPart",
|
|
899
|
+
description: "Upload one part of an in-progress S3 multipart upload. Part bodies up to 25 MiB. S3 requires each part except the last to be at least 5 MiB. Returns etag required for completeMultipartUpload.",
|
|
900
|
+
inputSchema: uploadPartInputSchema,
|
|
901
|
+
outputSchema: uploadPartOutputSchema,
|
|
902
|
+
sideEffect: "write",
|
|
903
|
+
runtime: "both",
|
|
904
|
+
execute: async (input, ctx) => S3Client.fromContext(ctx).uploadPart(input)
|
|
905
|
+
});
|
|
906
|
+
const s3CompleteMultipartUploadTool = defineTool({
|
|
907
|
+
id: "s3-complete-multipart-upload",
|
|
908
|
+
name: "s3CompleteMultipartUpload",
|
|
909
|
+
description: "Finish an S3 multipart upload by assembling uploaded parts (part_number + etag). Parts may be supplied in any order; they are sorted by part_number before complete.",
|
|
910
|
+
inputSchema: completeMultipartUploadInputSchema,
|
|
911
|
+
outputSchema: completeMultipartUploadOutputSchema,
|
|
912
|
+
sideEffect: "write",
|
|
913
|
+
runtime: "both",
|
|
914
|
+
execute: async (input, ctx) => S3Client.fromContext(ctx).completeMultipartUpload(input)
|
|
915
|
+
});
|
|
916
|
+
const s3AbortMultipartUploadTool = defineTool({
|
|
917
|
+
id: "s3-abort-multipart-upload",
|
|
918
|
+
name: "s3AbortMultipartUpload",
|
|
919
|
+
description: "Abort an in-progress S3 multipart upload and discard uploaded parts for that upload_id.",
|
|
920
|
+
inputSchema: abortMultipartUploadInputSchema,
|
|
921
|
+
outputSchema: abortMultipartUploadOutputSchema,
|
|
922
|
+
sideEffect: "delete",
|
|
923
|
+
runtime: "both",
|
|
924
|
+
execute: async (input, ctx) => S3Client.fromContext(ctx).abortMultipartUpload(input)
|
|
925
|
+
});
|
|
926
|
+
const s3Module = defineModule({
|
|
927
|
+
id: "s3",
|
|
928
|
+
title: "S3 / S3-compatible",
|
|
929
|
+
description: "Store and retrieve objects with S3-compatible storage. Use for object listing, reads, writes, metadata, copies, deletion, signed URLs, and multipart uploads.",
|
|
930
|
+
runtime: "both",
|
|
931
|
+
auth: {
|
|
932
|
+
type: "custom",
|
|
933
|
+
schema: s3AuthSchema
|
|
934
|
+
},
|
|
935
|
+
categories: ["storage", "aws"],
|
|
936
|
+
classification: "pii",
|
|
937
|
+
tags: ["object-store"],
|
|
938
|
+
tools: [
|
|
939
|
+
s3ListObjectsTool,
|
|
940
|
+
s3GetObjectTool,
|
|
941
|
+
s3PutObjectTool,
|
|
942
|
+
s3DeleteObjectTool,
|
|
943
|
+
s3HeadObjectTool,
|
|
944
|
+
s3CopyObjectTool,
|
|
945
|
+
s3CreateSignedUrlTool,
|
|
946
|
+
s3CreateMultipartUploadTool,
|
|
947
|
+
s3UploadPartTool,
|
|
948
|
+
s3CompleteMultipartUploadTool,
|
|
949
|
+
s3AbortMultipartUploadTool
|
|
950
|
+
]
|
|
951
|
+
});
|
|
952
|
+
//#endregion
|
|
953
|
+
export { getObjectOutputSchema as A, uploadPartOutputSchema as B, copyObjectInputSchema as C, deleteObjectInputSchema as D, createMultipartUploadOutputSchema as E, putObjectInputSchema as F, resolveObjectKey as H, putObjectOutputSchema as I, signedUrlInputSchema as L, headObjectOutputSchema as M, listObjectsInputSchema as N, deleteObjectOutputSchema as O, listObjectsOutputSchema as P, signedUrlOutputSchema as R, completeMultipartUploadOutputSchema as S, createMultipartUploadInputSchema as T, normalizeKeyPrefix as V, MAX_OBJECT_BYTES as _, s3CreateSignedUrlTool as a, abortMultipartUploadOutputSchema as b, s3HeadObjectTool as c, s3PutObjectTool as d, s3UploadPartTool as f, MAX_MULTIPART_PART_BYTES as g, DEFAULT_SIGNED_URL_SECONDS as h, s3CreateMultipartUploadTool as i, headObjectInputSchema as j, getObjectInputSchema as k, s3ListObjectsTool as l, s3AuthSchema as m, s3CompleteMultipartUploadTool as n, s3DeleteObjectTool as o, S3Client as p, s3CopyObjectTool as r, s3GetObjectTool as s, s3AbortMultipartUploadTool as t, s3Module as u, MAX_SIGNED_URL_SECONDS as v, copyObjectOutputSchema as w, completeMultipartUploadInputSchema as x, abortMultipartUploadInputSchema as y, uploadPartInputSchema as z };
|
|
954
|
+
|
|
955
|
+
//# sourceMappingURL=s3-CsOaPWMP.js.map
|