@ayepi/aws 0.4.1 → 0.5.0

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/ayepi-aws.md CHANGED
@@ -55,7 +55,7 @@ interface S3FilesOptions extends ResilientOptions {
55
55
  /** @internal Upload seam (default: `@aws-sdk/lib-storage` multipart `Upload`) — injectable for tests. */
56
56
  readonly upload?: (key: string, body: FileBody, contentType?: string, metadata?: Record<string, string>) => Promise<void>;
57
57
  /** @internal Presign seam (default: `@aws-sdk/s3-request-presigner`) — injectable for tests. */
58
- readonly presign?: (kind: 'get' | 'put', key: string, expiresIn: number, contentType?: string) => Promise<string>;
58
+ readonly presign?: (kind: 'get' | 'put', key: string, expiresIn: number, contentType?: string, sha256?: string) => Promise<string>;
59
59
  }
60
60
  ```
61
61
 
@@ -110,7 +110,9 @@ Behavior of each method:
110
110
  `modifiedAt` but **no `contentType`** (ListObjectsV2 doesn't return it).
111
111
  - **`presignDownload(key, opts?)`** — a presigned `GET` URL (default expiry **900 s**).
112
112
  - **`presignUpload(key, opts?)`** — a presigned `PUT` URL (default expiry **900 s**); `opts.contentType`
113
- pins the `Content-Type` the upload must use.
113
+ pins the `Content-Type` the upload must use; `opts.sha256` (hex) is signed as the object's
114
+ `x-amz-checksum-sha256`, so S3 refuses bytes that hash otherwise. A presigned `PUT` cannot cap a
115
+ body, so `opts.maxSize` rejects (use the files server, or a size check after upload).
114
116
 
115
117
  **Not-found handling.** S3 surfaces a missing key differently per op (`NoSuchKey` on GET,
116
118
  `NotFound` on HEAD). The store treats an error as not-found when its `name` is `NoSuchKey` or
package/dist/s3.cjs CHANGED
@@ -53,13 +53,14 @@ function s3Files(opts) {
53
53
  Metadata: metadata
54
54
  }
55
55
  }).done().then(() => void 0);
56
- const sdkPresign = (kind, key, expiresIn, contentType) => (0, _aws_sdk_s3_request_presigner.getSignedUrl)(client, kind === "get" ? new _aws_sdk_client_s3.GetObjectCommand({
56
+ const sdkPresign = (kind, key, expiresIn, contentType, sha256) => (0, _aws_sdk_s3_request_presigner.getSignedUrl)(client, kind === "get" ? new _aws_sdk_client_s3.GetObjectCommand({
57
57
  Bucket: bucket,
58
58
  Key: k(key)
59
59
  }) : new _aws_sdk_client_s3.PutObjectCommand({
60
60
  Bucket: bucket,
61
61
  Key: k(key),
62
- ContentType: contentType
62
+ ContentType: contentType,
63
+ ChecksumSHA256: sha256 === void 0 ? void 0 : Buffer.from(sha256, "hex").toString("base64")
63
64
  }), { expiresIn });
64
65
  /* v8 ignore stop */
65
66
  const upload = opts.upload ?? sdkUpload;
@@ -131,7 +132,10 @@ function s3Files(opts) {
131
132
  };
132
133
  }),
133
134
  presignDownload: (key, o) => presign("get", key, o?.expiresIn ?? DEFAULT_EXPIRES_IN),
134
- presignUpload: (key, o) => presign("put", key, o?.expiresIn ?? DEFAULT_EXPIRES_IN, o?.contentType)
135
+ presignUpload: (key, o) => {
136
+ if (o?.maxSize !== void 0) return Promise.reject(/* @__PURE__ */ new Error("s3Files: a presigned PUT cannot cap the upload size (maxSize)"));
137
+ return presign("put", key, o?.expiresIn ?? DEFAULT_EXPIRES_IN, o?.contentType, o?.sha256?.toLowerCase());
138
+ }
135
139
  };
136
140
  }
137
141
  //#endregion
package/dist/s3.d.cts CHANGED
@@ -15,7 +15,7 @@ interface S3FilesOptions extends ResilientOptions {
15
15
  /** @internal Upload seam (default: `@aws-sdk/lib-storage` multipart `Upload`) — injectable for tests. */
16
16
  readonly upload?: (key: string, body: FileBody, contentType?: string, metadata?: Record<string, string>) => Promise<void>;
17
17
  /** @internal Presign seam (default: `@aws-sdk/s3-request-presigner`) — injectable for tests. */
18
- readonly presign?: (kind: 'get' | 'put', key: string, expiresIn: number, contentType?: string) => Promise<string>;
18
+ readonly presign?: (kind: 'get' | 'put', key: string, expiresIn: number, contentType?: string, sha256?: string) => Promise<string>;
19
19
  }
20
20
  /**
21
21
  * Create an S3-backed {@link FileStore} (and {@link Presigner}). Pass a configured `S3Client`
package/dist/s3.d.ts CHANGED
@@ -15,7 +15,7 @@ interface S3FilesOptions extends ResilientOptions {
15
15
  /** @internal Upload seam (default: `@aws-sdk/lib-storage` multipart `Upload`) — injectable for tests. */
16
16
  readonly upload?: (key: string, body: FileBody, contentType?: string, metadata?: Record<string, string>) => Promise<void>;
17
17
  /** @internal Presign seam (default: `@aws-sdk/s3-request-presigner`) — injectable for tests. */
18
- readonly presign?: (kind: 'get' | 'put', key: string, expiresIn: number, contentType?: string) => Promise<string>;
18
+ readonly presign?: (kind: 'get' | 'put', key: string, expiresIn: number, contentType?: string, sha256?: string) => Promise<string>;
19
19
  }
20
20
  /**
21
21
  * Create an S3-backed {@link FileStore} (and {@link Presigner}). Pass a configured `S3Client`
package/dist/s3.js CHANGED
@@ -52,13 +52,14 @@ function s3Files(opts) {
52
52
  Metadata: metadata
53
53
  }
54
54
  }).done().then(() => void 0);
55
- const sdkPresign = (kind, key, expiresIn, contentType) => getSignedUrl(client, kind === "get" ? new GetObjectCommand({
55
+ const sdkPresign = (kind, key, expiresIn, contentType, sha256) => getSignedUrl(client, kind === "get" ? new GetObjectCommand({
56
56
  Bucket: bucket,
57
57
  Key: k(key)
58
58
  }) : new PutObjectCommand({
59
59
  Bucket: bucket,
60
60
  Key: k(key),
61
- ContentType: contentType
61
+ ContentType: contentType,
62
+ ChecksumSHA256: sha256 === void 0 ? void 0 : Buffer.from(sha256, "hex").toString("base64")
62
63
  }), { expiresIn });
63
64
  /* v8 ignore stop */
64
65
  const upload = opts.upload ?? sdkUpload;
@@ -130,7 +131,10 @@ function s3Files(opts) {
130
131
  };
131
132
  }),
132
133
  presignDownload: (key, o) => presign("get", key, o?.expiresIn ?? DEFAULT_EXPIRES_IN),
133
- presignUpload: (key, o) => presign("put", key, o?.expiresIn ?? DEFAULT_EXPIRES_IN, o?.contentType)
134
+ presignUpload: (key, o) => {
135
+ if (o?.maxSize !== void 0) return Promise.reject(/* @__PURE__ */ new Error("s3Files: a presigned PUT cannot cap the upload size (maxSize)"));
136
+ return presign("put", key, o?.expiresIn ?? DEFAULT_EXPIRES_IN, o?.contentType, o?.sha256?.toLowerCase());
137
+ }
134
138
  };
135
139
  }
136
140
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ayepi/aws",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "AWS backends for ayepi — an SQS @ayepi/work queue (large payloads offloaded to S3) and an S3 @ayepi/files store, all retry-wrapped for throttle resilience",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -73,9 +73,9 @@
73
73
  "@aws-sdk/lib-storage": "^3",
74
74
  "@aws-sdk/s3-request-presigner": "^3",
75
75
  "@smithy/node-http-handler": "^4",
76
- "@ayepi/core": "^0.4.1",
77
- "@ayepi/files": "^0.4.1",
78
- "@ayepi/work": "^0.4.1"
76
+ "@ayepi/core": "^0.5.0",
77
+ "@ayepi/files": "^0.5.0",
78
+ "@ayepi/work": "^0.5.0"
79
79
  },
80
80
  "peerDependenciesMeta": {
81
81
  "@ayepi/work": {
@@ -111,10 +111,10 @@
111
111
  "testcontainers": "^10.13.0",
112
112
  "tsdown": "^0.12.0",
113
113
  "vitest": "^2.1.8",
114
- "zod": "^4.4.3",
115
- "@ayepi/core": "0.4.1",
116
- "@ayepi/work": "0.4.1",
117
- "@ayepi/files": "0.4.1"
114
+ "zod": "^4.6.7",
115
+ "@ayepi/work": "0.5.0",
116
+ "@ayepi/files": "0.5.0",
117
+ "@ayepi/core": "0.5.0"
118
118
  },
119
119
  "keywords": [
120
120
  "ayepi",