Repository navigation
feat: add S3 / object storage action (#38) - #85
raphael-goetz wants to merge 6 commits into
Conversation
New centaurus action exposing AWS S3 (and any S3-compatible provider, via a custom endpoint) as Hercules runtime functions: putObject, getObject, deleteObject, listObjects, and createPresignedUrl. Refs #38
Avoids returning a stale client with the old secret after credential rotation that keeps the same access key ID, region, and endpoint. Refs #38
Brings two design decisions over from an earlier WIP attempt at this action (origin/#38-s3-action, same author, never finished — it doesn't typecheck against the current hercules SDK): - putObject/getObject now exchange content as hercules' standard FILE value (base64 + content type) instead of UTF-8 text only, so binary objects work and files interop with other flow functions. - access_key_id/secret_access_key are now optional, falling back to the AWS SDK's default credential provider chain (env vars, shared config, or an IAM role) when unset. Also adds StorageClass to listObjects results and an explicit Deleted flag to deleteObject's result, both present in that WIP. Refs #38
Signed-off-by: Raphael Götz <[email protected]>
GitLab Pipeline ActionGeneral informationLink to pipeline: https://gitlab.com/code0-tech/development/centaurus/-/pipelines/3018518499 Status: Passed Job summariesdocs:previewDocumentation preview available at https://code0-tech.gitlab.io/-/development/telescopium/-/jobs/17670073741/artifacts/out/index.html |
nicosammito
left a comment
There was a problem hiding this comment.
The put function should be able to upload multiply files
|
|
||
| @Identifier("putObject") | ||
| @DisplayIcon("simple:amazons3") | ||
| @Signature("(Key: string, File: FILE, Bucket?: string): S3_OBJECT") |
There was a problem hiding this comment.
FILE is wrongly declared should be FILE<"/">
There was a problem hiding this comment.
Fixed — the parameter is now declared as FILE<"*/*">[] (also switched to accepting multiple files, see below).
Address review feedback on #85: - putObject now accepts `Files: FILE<"*/*">[]` and uploads each file, returning `S3_OBJECT[]`. Each object's key is derived from the file's own name, optionally under an optional `KeyPrefix` (folder). - Fix the FILE parameter type: `FILE` -> `FILE<"*/*">`. - Add a `resolveObjectKey` helper (prefix + file name joining) with tests. Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
Addressed the requested changes (@nicosammito):
Also added a |
nicosammito
left a comment
There was a problem hiding this comment.
The icon used does not exist: simple:amazons3. We are using simple-icon here.
Also it should not be named object but instead upload files, delete file, list file, etc.
| optional: true, | ||
| }) | ||
| export class PutObjectFunction { | ||
| async run(context: FunctionContext, Files: File<"*/*">[], KeyPrefix?: string, Bucket?: string): Promise<S3Object[]> { |
There was a problem hiding this comment.
It should File also in the signature. This function should not be named Upload objects but upload files. Also there is no such icon simple:amazons3
| * S3-compatible provider (MinIO, Cloudflare R2, DigitalOcean Spaces, ...) by | ||
| * pointing `endpoint` at that provider. | ||
| */ | ||
| let cached: { accessKeyId: string; secretAccessKey: string; region: string; endpoint: string; client: S3Client } | null = |
There was a problem hiding this comment.
You can't cache clients. This is generally not possible. Because you have infinite possible client connections.
I would disagree with that. S3 (and object storage in general) has no concept of a file. It only knows objects. There are no directories, objects can only have a key with a prefix. S3 Files does exist, but that is a separate service which provides a filesystem backed by a S3 bucket. Naming things as "file" here could create confusion. |
Partially agree here, I would prefer functions for managing files and data. So e.g. Upload data and Upload files |
- Replace invalid `simple:amazons3` icon (AWS icons were pulled from Simple Icons) with `tabler:bucket`. - Stop caching the S3 client: a single action process serves many flows with different matched configs, so build a fresh client per call. - Split the functions into two mirrored sets (per review): an object set (raw data at an explicit key) and a file set (hercules FILE values keyed by file name), each with upload/download/delete/list/presigned. Adds the S3_OBJECT_DATA data type for raw-text object bodies. - Update README and tests accordingly. Co-Authored-By: Claude Opus 4.8 <[email protected]>
What
Adds a new
s3-actionto the monorepo, exposing AWS S3 (or any S3-compatible provider, via a customendpoint) as Hercules runtime functions:putObject,getObject,deleteObject,listObjects, andcreatePresignedUrl. Object content is exchanged as hercules' standardFILEvalue (base64 + content type), so files interop with other flow functions.Why
Closes #38.
How
actions/s3-action/src/index.ts— action definition, config (access_key_id/secret_access_keyoptional, falling back to the AWS SDK's default credential provider chain;region,endpoint,bucket), data types and function registration.actions/s3-action/src/helpers.ts— cachedS3Clientfactory, bucket resolution, error mapping.actions/s3-action/src/functions/*— the five runtime functions, backed by@aws-sdk/client-s3/@aws-sdk/s3-request-presigner.actions/s3-action/src/data_types/*— zod schemas forS3_OBJECT,S3_OBJECT_CONTENT(wraps the standardFILEtype),S3_DELETE_RESULT,S3_OBJECT_LIST,S3_PRESIGNED_URL..gitlab-ci.yml— addeds3-actionto the.node-actionsmatrix so it's typechecked/tested/built/published like the other Node actions.FILE, optional credentials) were cross-checked against an earlier abandoned WIP attempt at this same issue (#38-s3-action), which didn't typecheck against the current SDK; the sound parts of its design were carried over and fixed up.Testing
npm run typecheck— cleannpm run test(vitest) — 10/10 passingnpm run build(vite) — buildsdist/index.jshercules exportCLI: all 5 functions, 5 data types, and 5 configs register and serialize correctlynode scripts/for-each-action.mjs typecheck|testfrom repo root — all 7 Node actions pass