@geekmidas/storage 10.0.0-alpha.118 → 10.0.0-alpha.119
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aws.cjs +34 -0
- package/dist/aws.cjs.map +1 -1
- package/dist/aws.d.cts +3 -2
- package/dist/aws.d.cts.map +1 -1
- package/dist/aws.d.mts +3 -2
- package/dist/aws.d.mts.map +1 -1
- package/dist/aws.mjs +34 -0
- package/dist/aws.mjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/{registry-ClEvHGpM.d.cts → registry-DyBOtv6n.d.cts} +44 -2
- package/dist/registry-DyBOtv6n.d.cts.map +1 -0
- package/dist/{registry-ClEvHGpM.d.mts → registry-DyBOtv6n.d.mts} +44 -2
- package/dist/registry-DyBOtv6n.d.mts.map +1 -0
- package/package.json +3 -3
- package/dist/registry-ClEvHGpM.d.cts.map +0 -1
- package/dist/registry-ClEvHGpM.d.mts.map +0 -1
package/dist/aws.cjs
CHANGED
|
@@ -130,6 +130,40 @@ var AmazonStorageClient = class AmazonStorageClient {
|
|
|
130
130
|
}))
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
|
+
async getUploadPost({ key, maxSize, contentType, expiresIn = 300 }) {
|
|
134
|
+
const fields = {};
|
|
135
|
+
const conditions = [[
|
|
136
|
+
"content-length-range",
|
|
137
|
+
0,
|
|
138
|
+
maxSize
|
|
139
|
+
]];
|
|
140
|
+
if (typeof contentType === "string") {
|
|
141
|
+
fields["Content-Type"] = contentType;
|
|
142
|
+
conditions.push([
|
|
143
|
+
"eq",
|
|
144
|
+
"$Content-Type",
|
|
145
|
+
contentType
|
|
146
|
+
]);
|
|
147
|
+
} else if (contentType) conditions.push([
|
|
148
|
+
"starts-with",
|
|
149
|
+
"$Content-Type",
|
|
150
|
+
contentType.startsWith
|
|
151
|
+
]);
|
|
152
|
+
const expiresAt = new Date(Date.now() + expiresIn * 1e3).toISOString();
|
|
153
|
+
const post = await this.traced("presign", () => (0, _aws_sdk_s3_presigned_post.createPresignedPost)(this.client, {
|
|
154
|
+
Bucket: this.bucket,
|
|
155
|
+
Key: key,
|
|
156
|
+
Expires: expiresIn,
|
|
157
|
+
Fields: fields,
|
|
158
|
+
Conditions: conditions
|
|
159
|
+
}), { "storage.presign.method": "POST" });
|
|
160
|
+
return {
|
|
161
|
+
url: post.url,
|
|
162
|
+
fields: post.fields,
|
|
163
|
+
key,
|
|
164
|
+
expiresAt
|
|
165
|
+
};
|
|
166
|
+
}
|
|
133
167
|
async upload(key, data, contentType) {
|
|
134
168
|
const Body = typeof data === "string" ? Buffer.from(data, "base64") : data;
|
|
135
169
|
const params = {
|
package/dist/aws.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws.cjs","names":["trace","SpanKind","SpanStatusCode","S3Client","GetObjectCommand","getSignedUrl","ListObjectVersionsCommand","PutObjectCommand","createPresignedPost","DeleteObjectCommand","parse"],"sources":["../src/telemetry.ts","../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"sourcesContent":["/**\n * A span per storage call, through the global OpenTelemetry tracer — a no-op\n * without a registered provider.\n *\n * `storage.presign`, `storage.put`, `storage.delete` and `storage.list`, with\n * the backend and the bucket. Never the object's key: keys often name a user.\n *\n * @module\n */\nimport {\n\ttype Attributes,\n\tSpanKind,\n\tSpanStatusCode,\n\ttrace,\n} from '@opentelemetry/api';\n\nexport type StorageOperation = 'presign' | 'put' | 'delete' | 'list';\n\n/** Run `fn` inside a `storage.<operation>` span. */\nexport async function traceStorage<T>(\n\toperation: StorageOperation,\n\tattributes: Attributes,\n\tfn: () => Promise<T>,\n): Promise<T> {\n\tconst span = trace\n\t\t.getTracer('@geekmidas/storage')\n\t\t.startSpan(`storage.${operation}`, {\n\t\t\tkind: SpanKind.CLIENT,\n\t\t\tattributes: { 'storage.operation': operation, ...attributes },\n\t\t});\n\ttry {\n\t\treturn await fn();\n\t} catch (error) {\n\t\tif (error instanceof Error) span.recordException(error);\n\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\tthrow error;\n\t} finally {\n\t\tspan.end();\n\t}\n}\n","import {\n\tDeleteObjectCommand,\n\tGetObjectCommand,\n\tListObjectVersionsCommand,\n\tPutObjectCommand,\n\tS3Client,\n} from '@aws-sdk/client-s3';\nimport { createPresignedPost } from '@aws-sdk/s3-presigned-post';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\n\nimport type { Cache } from '@geekmidas/cache';\nimport type { Attributes } from '@opentelemetry/api';\nimport {\n\ttype DocumentVersion,\n\ttype File,\n\ttype GetUploadParams,\n\ttype GetUploadResponse,\n\ttype StorageClient,\n\tStorageProvider,\n} from './StorageClient';\nimport { type StorageOperation, traceStorage } from './telemetry';\n\nexport class AmazonStorageClient implements StorageClient {\n\treadonly provider = StorageProvider.AWSS3;\n\n\tstatic create(\n\t\toptions: AmazonStorageClientCreateOptions,\n\t): AmazonStorageClient {\n\t\tconst {\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\taccessKeyId,\n\t\t\tacl,\n\t\t\tendpoint,\n\t\t\tsecretAccessKey,\n\t\t\tforcePathStyle = false,\n\t\t\tcache,\n\t\t} = options;\n\t\tconst hasCredentials = accessKeyId && secretAccessKey;\n\t\tconst credentials = hasCredentials\n\t\t\t? { accessKeyId, secretAccessKey }\n\t\t\t: undefined;\n\n\t\tconst client = new S3Client({\n\t\t\tregion,\n\t\t\tcredentials,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t});\n\n\t\treturn new AmazonStorageClient(client, bucket, acl, cache);\n\t}\n\tconstructor(\n\t\tprivate readonly client: S3Client,\n\t\tprivate readonly bucket: string,\n\t\tprivate readonly acl = AmazonCannedAccessControlList.AuthenticatedRead,\n\t\treadonly cache?: Cache,\n\t) {}\n\n\t/** A storage span on this bucket. */\n\tprivate traced<T>(\n\t\toperation: StorageOperation,\n\t\tfn: () => Promise<T>,\n\t\tattributes: Attributes = {},\n\t): Promise<T> {\n\t\treturn traceStorage(\n\t\t\toperation,\n\t\t\t{ 'storage.system': 's3', 'storage.bucket': this.bucket, ...attributes },\n\t\t\tfn,\n\t\t);\n\t}\n\n\tprivate createGetObjectCommand(\n\t\tfile: File,\n\t\toverrides?: { VersionId?: string },\n\t): GetObjectCommand {\n\t\tconst disposition =\n\t\t\tfile.disposition ?? (file.name ? 'attachment' : undefined);\n\t\tconst ResponseContentDisposition = disposition\n\t\t\t? file.name\n\t\t\t\t? `${disposition}; filename=${encodeURIComponent(file.name)}`\n\t\t\t\t: disposition\n\t\t\t: undefined;\n\n\t\treturn new GetObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: file.path,\n\t\t\tResponseContentDisposition,\n\t\t\tResponseContentType: file.responseContentType,\n\t\t\t...overrides,\n\t\t});\n\t}\n\n\tgetVersionDownloadURL(file: File, versionId: string): Promise<string> {\n\t\tconst command = this.createGetObjectCommand(file, { VersionId: versionId });\n\t\treturn this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn: 60 * 60 * 24 }),\n\t\t\t{ 'storage.presign.method': 'GET' },\n\t\t);\n\t}\n\n\tasync getVersions(key: string): Promise<DocumentVersion[]> {\n\t\tconst command = new ListObjectVersionsCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tPrefix: key,\n\t\t});\n\n\t\tconst { Versions = [] } = await this.traced('list', () =>\n\t\t\tthis.client.send(command),\n\t\t);\n\n\t\treturn Versions.map((version) => ({\n\t\t\tid: version.VersionId || '',\n\t\t\tcreatedAt: version.LastModified || new Date(),\n\t\t}));\n\t}\n\n\tasync getDownloadURL(file: File, expiresIn = 60 * 60): Promise<string> {\n\t\tconst cacheKey = `download-url:${file.path}`;\n\t\tconst cachedURL = await this.cache?.get<string>(cacheKey);\n\n\t\tif (cachedURL) {\n\t\t\treturn cachedURL;\n\t\t}\n\n\t\tconst command = this.createGetObjectCommand(file);\n\t\tconst url = await this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn }),\n\t\t\t{ 'storage.presign.method': 'GET' },\n\t\t);\n\t\tconst cacheExpiration = Math.max(expiresIn - 60, 0);\n\n\t\tif (cacheExpiration) {\n\t\t\tawait this.cache?.set(cacheKey, url, cacheExpiration);\n\t\t}\n\n\t\treturn url;\n\t}\n\n\tasync getUploadURL(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 60 * 60,\n\t): Promise<string> {\n\t\tconst command = new PutObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: params.path,\n\t\t\tContentType: params.contentType,\n\t\t\tContentLength: params.contentLength,\n\t\t});\n\n\t\treturn this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn }),\n\t\t\t{ 'storage.presign.method': 'PUT' },\n\t\t);\n\t}\n\n\tasync getUpload(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 5,\n\t): Promise<GetUploadResponse> {\n\t\tconst { path } = params;\n\t\tconst { fields: values, url } = await this.traced(\n\t\t\t'presign',\n\t\t\t() =>\n\t\t\t\tcreatePresignedPost(this.client, {\n\t\t\t\t\tExpires: expiresIn * 60,\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tFields: {\n\t\t\t\t\t\tacl: this.acl,\n\t\t\t\t\t},\n\t\t\t\t\tConditions: [\n\t\t\t\t\t\t// content length restrictions: 0-1MB]\n\t\t\t\t\t\t// ['content-length-range', 0, contentLength],\n\t\t\t\t\t\t// specify content-type to be more generic- images only\n\t\t\t\t\t\t// ['starts-with', '$Content-Type', 'image/'],\n\t\t\t\t\t\t// ['starts-with', '$Content-Type', contentType],\n\t\t\t\t\t],\n\t\t\t\t\tKey: path,\n\t\t\t\t}),\n\t\t\t{ 'storage.presign.method': 'POST' },\n\t\t);\n\n\t\tconst keys = Object.keys(values);\n\t\tconst fields = keys.map((key) => ({ key, value: values[key] || '' }));\n\n\t\treturn { url, fields };\n\t}\n\n\tasync upload(\n\t\tkey: string,\n\t\tdata: string | Buffer,\n\t\tcontentType: string,\n\t): Promise<void> {\n\t\tconst Body = typeof data === 'string' ? Buffer.from(data, 'base64') : data;\n\n\t\tconst params = {\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t\tBody,\n\t\t\tContentType: contentType,\n\t\t};\n\n\t\tconst command = new PutObjectCommand(params);\n\n\t\tawait this.traced('put', () => this.client.send(command), {\n\t\t\t'storage.object.size': Body.length,\n\t\t\t'storage.object.content_type': contentType,\n\t\t});\n\t}\n\n\tasync delete(key: string): Promise<void> {\n\t\tconst command = new DeleteObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t});\n\n\t\tawait this.traced('delete', () => this.client.send(command));\n\t}\n}\n\nexport enum AmazonCannedAccessControlList {\n\tAuthenticatedRead = 'authenticated-read',\n\tPrivate = 'private',\n\tPublicRead = 'public-read',\n\tPublicReadWrite = 'public-read-write',\n\tAwsExecRead = 'aws-exec-read',\n\tBucketOwnerRead = 'bucket-owner-read',\n\tBucketOwnerFullControl = 'bucket-owner-full-control',\n\tLogDeliveryWrite = 'log-delivery-write',\n}\n\ninterface AmazonStorageClientCreateOptions {\n\tbucket: string;\n\tregion?: string;\n\tacl?: AmazonCannedAccessControlList;\n\taccessKeyId?: string;\n\tsecretAccessKey?: string;\n\tendpoint?: string;\n\tforcePathStyle?: boolean;\n\tcache?: Cache;\n}\n","/**\n * The S3 driver — `s3://` URLs to an {@link AmazonStorageClient}.\n *\n * Registered by whoever assembles the application, so neutral code can build a\n * client from a URL without importing this file or the AWS SDK behind it.\n */\n\nimport { AmazonStorageClient } from './AmazonStorageClient';\nimport type { StorageDriver } from './registry';\nimport { parse } from './s3Url';\n\nexport const s3Driver: StorageDriver = {\n\tscheme: 's3:',\n\tcreate(url) {\n\t\t// The URL's own key pair, when it has one, wins over the SDK's default\n\t\t// chain; without one the client resolves credentials as it always has.\n\t\tconst {\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t\taccessKeyId,\n\t\t\tsecretAccessKey,\n\t\t} = parse(url);\n\t\treturn AmazonStorageClient.create({\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t\taccessKeyId,\n\t\t\tsecretAccessKey,\n\t\t});\n\t},\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"aws.cjs","names":["trace","SpanKind","SpanStatusCode","S3Client","GetObjectCommand","getSignedUrl","ListObjectVersionsCommand","PutObjectCommand","createPresignedPost","DeleteObjectCommand","parse"],"sources":["../src/telemetry.ts","../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"sourcesContent":["/**\n * A span per storage call, through the global OpenTelemetry tracer — a no-op\n * without a registered provider.\n *\n * `storage.presign`, `storage.put`, `storage.delete` and `storage.list`, with\n * the backend and the bucket. Never the object's key: keys often name a user.\n *\n * @module\n */\nimport {\n\ttype Attributes,\n\tSpanKind,\n\tSpanStatusCode,\n\ttrace,\n} from '@opentelemetry/api';\n\nexport type StorageOperation = 'presign' | 'put' | 'delete' | 'list';\n\n/** Run `fn` inside a `storage.<operation>` span. */\nexport async function traceStorage<T>(\n\toperation: StorageOperation,\n\tattributes: Attributes,\n\tfn: () => Promise<T>,\n): Promise<T> {\n\tconst span = trace\n\t\t.getTracer('@geekmidas/storage')\n\t\t.startSpan(`storage.${operation}`, {\n\t\t\tkind: SpanKind.CLIENT,\n\t\t\tattributes: { 'storage.operation': operation, ...attributes },\n\t\t});\n\ttry {\n\t\treturn await fn();\n\t} catch (error) {\n\t\tif (error instanceof Error) span.recordException(error);\n\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\tthrow error;\n\t} finally {\n\t\tspan.end();\n\t}\n}\n","import {\n\tDeleteObjectCommand,\n\tGetObjectCommand,\n\tListObjectVersionsCommand,\n\tPutObjectCommand,\n\tS3Client,\n} from '@aws-sdk/client-s3';\nimport {\n\tcreatePresignedPost,\n\ttype PresignedPostOptions,\n} from '@aws-sdk/s3-presigned-post';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\n\nimport type { Cache } from '@geekmidas/cache';\nimport type { Attributes } from '@opentelemetry/api';\nimport {\n\ttype DocumentVersion,\n\ttype File,\n\ttype GetUploadParams,\n\ttype GetUploadResponse,\n\ttype StorageClient,\n\tStorageProvider,\n\ttype UploadPost,\n\ttype UploadPostParams,\n} from './StorageClient';\nimport { type StorageOperation, traceStorage } from './telemetry';\n\nexport class AmazonStorageClient implements StorageClient {\n\treadonly provider = StorageProvider.AWSS3;\n\n\tstatic create(\n\t\toptions: AmazonStorageClientCreateOptions,\n\t): AmazonStorageClient {\n\t\tconst {\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\taccessKeyId,\n\t\t\tacl,\n\t\t\tendpoint,\n\t\t\tsecretAccessKey,\n\t\t\tforcePathStyle = false,\n\t\t\tcache,\n\t\t} = options;\n\t\tconst hasCredentials = accessKeyId && secretAccessKey;\n\t\tconst credentials = hasCredentials\n\t\t\t? { accessKeyId, secretAccessKey }\n\t\t\t: undefined;\n\n\t\tconst client = new S3Client({\n\t\t\tregion,\n\t\t\tcredentials,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t});\n\n\t\treturn new AmazonStorageClient(client, bucket, acl, cache);\n\t}\n\tconstructor(\n\t\tprivate readonly client: S3Client,\n\t\tprivate readonly bucket: string,\n\t\tprivate readonly acl = AmazonCannedAccessControlList.AuthenticatedRead,\n\t\treadonly cache?: Cache,\n\t) {}\n\n\t/** A storage span on this bucket. */\n\tprivate traced<T>(\n\t\toperation: StorageOperation,\n\t\tfn: () => Promise<T>,\n\t\tattributes: Attributes = {},\n\t): Promise<T> {\n\t\treturn traceStorage(\n\t\t\toperation,\n\t\t\t{ 'storage.system': 's3', 'storage.bucket': this.bucket, ...attributes },\n\t\t\tfn,\n\t\t);\n\t}\n\n\tprivate createGetObjectCommand(\n\t\tfile: File,\n\t\toverrides?: { VersionId?: string },\n\t): GetObjectCommand {\n\t\tconst disposition =\n\t\t\tfile.disposition ?? (file.name ? 'attachment' : undefined);\n\t\tconst ResponseContentDisposition = disposition\n\t\t\t? file.name\n\t\t\t\t? `${disposition}; filename=${encodeURIComponent(file.name)}`\n\t\t\t\t: disposition\n\t\t\t: undefined;\n\n\t\treturn new GetObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: file.path,\n\t\t\tResponseContentDisposition,\n\t\t\tResponseContentType: file.responseContentType,\n\t\t\t...overrides,\n\t\t});\n\t}\n\n\tgetVersionDownloadURL(file: File, versionId: string): Promise<string> {\n\t\tconst command = this.createGetObjectCommand(file, { VersionId: versionId });\n\t\treturn this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn: 60 * 60 * 24 }),\n\t\t\t{ 'storage.presign.method': 'GET' },\n\t\t);\n\t}\n\n\tasync getVersions(key: string): Promise<DocumentVersion[]> {\n\t\tconst command = new ListObjectVersionsCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tPrefix: key,\n\t\t});\n\n\t\tconst { Versions = [] } = await this.traced('list', () =>\n\t\t\tthis.client.send(command),\n\t\t);\n\n\t\treturn Versions.map((version) => ({\n\t\t\tid: version.VersionId || '',\n\t\t\tcreatedAt: version.LastModified || new Date(),\n\t\t}));\n\t}\n\n\tasync getDownloadURL(file: File, expiresIn = 60 * 60): Promise<string> {\n\t\tconst cacheKey = `download-url:${file.path}`;\n\t\tconst cachedURL = await this.cache?.get<string>(cacheKey);\n\n\t\tif (cachedURL) {\n\t\t\treturn cachedURL;\n\t\t}\n\n\t\tconst command = this.createGetObjectCommand(file);\n\t\tconst url = await this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn }),\n\t\t\t{ 'storage.presign.method': 'GET' },\n\t\t);\n\t\tconst cacheExpiration = Math.max(expiresIn - 60, 0);\n\n\t\tif (cacheExpiration) {\n\t\t\tawait this.cache?.set(cacheKey, url, cacheExpiration);\n\t\t}\n\n\t\treturn url;\n\t}\n\n\tasync getUploadURL(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 60 * 60,\n\t): Promise<string> {\n\t\tconst command = new PutObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: params.path,\n\t\t\tContentType: params.contentType,\n\t\t\tContentLength: params.contentLength,\n\t\t});\n\n\t\treturn this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn }),\n\t\t\t{ 'storage.presign.method': 'PUT' },\n\t\t);\n\t}\n\n\tasync getUpload(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 5,\n\t): Promise<GetUploadResponse> {\n\t\tconst { path } = params;\n\t\tconst { fields: values, url } = await this.traced(\n\t\t\t'presign',\n\t\t\t() =>\n\t\t\t\tcreatePresignedPost(this.client, {\n\t\t\t\t\tExpires: expiresIn * 60,\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tFields: {\n\t\t\t\t\t\tacl: this.acl,\n\t\t\t\t\t},\n\t\t\t\t\tConditions: [\n\t\t\t\t\t\t// content length restrictions: 0-1MB]\n\t\t\t\t\t\t// ['content-length-range', 0, contentLength],\n\t\t\t\t\t\t// specify content-type to be more generic- images only\n\t\t\t\t\t\t// ['starts-with', '$Content-Type', 'image/'],\n\t\t\t\t\t\t// ['starts-with', '$Content-Type', contentType],\n\t\t\t\t\t],\n\t\t\t\t\tKey: path,\n\t\t\t\t}),\n\t\t\t{ 'storage.presign.method': 'POST' },\n\t\t);\n\n\t\tconst keys = Object.keys(values);\n\t\tconst fields = keys.map((key) => ({ key, value: values[key] || '' }));\n\n\t\treturn { url, fields };\n\t}\n\n\tasync getUploadPost({\n\t\tkey,\n\t\tmaxSize,\n\t\tcontentType,\n\t\texpiresIn = 300,\n\t}: UploadPostParams): Promise<UploadPost> {\n\t\tconst fields: Record<string, string> = {};\n\t\tconst conditions: NonNullable<PresignedPostOptions['Conditions']> = [\n\t\t\t['content-length-range', 0, maxSize],\n\t\t];\n\t\tif (typeof contentType === 'string') {\n\t\t\tfields['Content-Type'] = contentType;\n\t\t\tconditions.push(['eq', '$Content-Type', contentType]);\n\t\t} else if (contentType) {\n\t\t\tconditions.push(['starts-with', '$Content-Type', contentType.startsWith]);\n\t\t}\n\n\t\t// Read before signing, so the timestamp is never later than the policy's.\n\t\tconst expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();\n\t\tconst post = await this.traced(\n\t\t\t'presign',\n\t\t\t() =>\n\t\t\t\tcreatePresignedPost(this.client, {\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: key,\n\t\t\t\t\tExpires: expiresIn,\n\t\t\t\t\tFields: fields,\n\t\t\t\t\tConditions: conditions,\n\t\t\t\t}),\n\t\t\t{ 'storage.presign.method': 'POST' },\n\t\t);\n\n\t\treturn { url: post.url, fields: post.fields, key, expiresAt };\n\t}\n\n\tasync upload(\n\t\tkey: string,\n\t\tdata: string | Buffer,\n\t\tcontentType: string,\n\t): Promise<void> {\n\t\tconst Body = typeof data === 'string' ? Buffer.from(data, 'base64') : data;\n\n\t\tconst params = {\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t\tBody,\n\t\t\tContentType: contentType,\n\t\t};\n\n\t\tconst command = new PutObjectCommand(params);\n\n\t\tawait this.traced('put', () => this.client.send(command), {\n\t\t\t'storage.object.size': Body.length,\n\t\t\t'storage.object.content_type': contentType,\n\t\t});\n\t}\n\n\tasync delete(key: string): Promise<void> {\n\t\tconst command = new DeleteObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t});\n\n\t\tawait this.traced('delete', () => this.client.send(command));\n\t}\n}\n\nexport enum AmazonCannedAccessControlList {\n\tAuthenticatedRead = 'authenticated-read',\n\tPrivate = 'private',\n\tPublicRead = 'public-read',\n\tPublicReadWrite = 'public-read-write',\n\tAwsExecRead = 'aws-exec-read',\n\tBucketOwnerRead = 'bucket-owner-read',\n\tBucketOwnerFullControl = 'bucket-owner-full-control',\n\tLogDeliveryWrite = 'log-delivery-write',\n}\n\ninterface AmazonStorageClientCreateOptions {\n\tbucket: string;\n\tregion?: string;\n\tacl?: AmazonCannedAccessControlList;\n\taccessKeyId?: string;\n\tsecretAccessKey?: string;\n\tendpoint?: string;\n\tforcePathStyle?: boolean;\n\tcache?: Cache;\n}\n","/**\n * The S3 driver — `s3://` URLs to an {@link AmazonStorageClient}.\n *\n * Registered by whoever assembles the application, so neutral code can build a\n * client from a URL without importing this file or the AWS SDK behind it.\n */\n\nimport { AmazonStorageClient } from './AmazonStorageClient';\nimport type { StorageDriver } from './registry';\nimport { parse } from './s3Url';\n\nexport const s3Driver: StorageDriver = {\n\tscheme: 's3:',\n\tcreate(url) {\n\t\t// The URL's own key pair, when it has one, wins over the SDK's default\n\t\t// chain; without one the client resolves credentials as it always has.\n\t\tconst {\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t\taccessKeyId,\n\t\t\tsecretAccessKey,\n\t\t} = parse(url);\n\t\treturn AmazonStorageClient.create({\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t\taccessKeyId,\n\t\t\tsecretAccessKey,\n\t\t});\n\t},\n};\n"],"mappings":"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"}
|
package/dist/aws.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as DocumentVersion, c as GetUploadResponse, l as StorageClient, o as File, s as GetUploadParams, t as StorageDriver, u as StorageProvider } from "./registry-
|
|
1
|
+
import { a as DocumentVersion, c as GetUploadResponse, d as UploadPost, f as UploadPostParams, l as StorageClient, o as File, s as GetUploadParams, t as StorageDriver, u as StorageProvider } from "./registry-DyBOtv6n.cjs";
|
|
2
2
|
import { S3Address, t as s3Url_d_exports } from "./s3Url.cjs";
|
|
3
3
|
import { S3Client } from "@aws-sdk/client-s3";
|
|
4
4
|
import { Cache } from "@geekmidas/cache";
|
|
@@ -19,6 +19,7 @@ export declare class AmazonStorageClient implements StorageClient {
|
|
|
19
19
|
getDownloadURL(file: File, expiresIn?: number): Promise<string>;
|
|
20
20
|
getUploadURL(params: GetUploadParams, expiresIn?: number): Promise<string>;
|
|
21
21
|
getUpload(params: GetUploadParams, expiresIn?: number): Promise<GetUploadResponse>;
|
|
22
|
+
getUploadPost({ key, maxSize, contentType, expiresIn }: UploadPostParams): Promise<UploadPost>;
|
|
22
23
|
upload(key: string, data: string | Buffer, contentType: string): Promise<void>;
|
|
23
24
|
delete(key: string): Promise<void>;
|
|
24
25
|
}
|
|
@@ -46,5 +47,5 @@ interface AmazonStorageClientCreateOptions {
|
|
|
46
47
|
//#region src/s3Driver.d.ts
|
|
47
48
|
export declare const s3Driver: StorageDriver;
|
|
48
49
|
//#endregion
|
|
49
|
-
export { type DocumentVersion, type File, type GetUploadParams, type GetUploadResponse, type S3Address, type StorageClient, s3Url_d_exports as s3Url };
|
|
50
|
+
export { type DocumentVersion, type File, type GetUploadParams, type GetUploadResponse, type S3Address, type StorageClient, type UploadPost, type UploadPostParams, s3Url_d_exports as s3Url };
|
|
50
51
|
//# sourceMappingURL=aws.d.cts.map
|
package/dist/aws.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws.d.cts","names":[],"sources":["../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"aws.d.cts","names":[],"sources":["../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"mappings":";;;;;qBA2Ba,+BAA+B;mBA+BzB;mBACA;mBACA;WACR,QAAQ;WAjCT,WAAQ,gBAAA;SAEV,OACN,SAAS,mCACP;EAyBH,YACkB,QAAQ,UACR,gBACA,MAAG,+BACX,QAAQ;;UAIV;UAYA;EAqBR,sBAAsB,MAAM,MAAM,oBAAoB;EAShD,YAAY,cAAc,QAAQ;EAgBlC,eAAe,MAAM,MAAM,qBAAsB;EAuBjD,aACL,QAAQ,iBACR,qBACE;EAeG,UACL,QAAQ,iBACR,qBACE,QAAQ;EA6BL,gBACL,KACA,SACA,aACA,aACE,mBAAmB,QAAQ;EA8BxB,OACL,aACA,eAAe,QACf,sBACE;EAkBG,OAAO,cAAc;;oBAUhB;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGS;EACT;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;EACA,QAAQ;;;;qBC/QI,UAAU"}
|
package/dist/aws.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as DocumentVersion, c as GetUploadResponse, l as StorageClient, o as File, s as GetUploadParams, t as StorageDriver, u as StorageProvider } from "./registry-
|
|
1
|
+
import { a as DocumentVersion, c as GetUploadResponse, d as UploadPost, f as UploadPostParams, l as StorageClient, o as File, s as GetUploadParams, t as StorageDriver, u as StorageProvider } from "./registry-DyBOtv6n.mjs";
|
|
2
2
|
import { S3Address, t as s3Url_d_exports } from "./s3Url.mjs";
|
|
3
3
|
import { S3Client } from "@aws-sdk/client-s3";
|
|
4
4
|
import { Cache } from "@geekmidas/cache";
|
|
@@ -19,6 +19,7 @@ export declare class AmazonStorageClient implements StorageClient {
|
|
|
19
19
|
getDownloadURL(file: File, expiresIn?: number): Promise<string>;
|
|
20
20
|
getUploadURL(params: GetUploadParams, expiresIn?: number): Promise<string>;
|
|
21
21
|
getUpload(params: GetUploadParams, expiresIn?: number): Promise<GetUploadResponse>;
|
|
22
|
+
getUploadPost({ key, maxSize, contentType, expiresIn }: UploadPostParams): Promise<UploadPost>;
|
|
22
23
|
upload(key: string, data: string | Buffer, contentType: string): Promise<void>;
|
|
23
24
|
delete(key: string): Promise<void>;
|
|
24
25
|
}
|
|
@@ -46,5 +47,5 @@ interface AmazonStorageClientCreateOptions {
|
|
|
46
47
|
//#region src/s3Driver.d.ts
|
|
47
48
|
export declare const s3Driver: StorageDriver;
|
|
48
49
|
//#endregion
|
|
49
|
-
export { type DocumentVersion, type File, type GetUploadParams, type GetUploadResponse, type S3Address, type StorageClient, s3Url_d_exports as s3Url };
|
|
50
|
+
export { type DocumentVersion, type File, type GetUploadParams, type GetUploadResponse, type S3Address, type StorageClient, type UploadPost, type UploadPostParams, s3Url_d_exports as s3Url };
|
|
50
51
|
//# sourceMappingURL=aws.d.mts.map
|
package/dist/aws.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws.d.mts","names":[],"sources":["../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"aws.d.mts","names":[],"sources":["../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"mappings":";;;;;qBA2Ba,+BAA+B;mBA+BzB;mBACA;mBACA;WACR,QAAQ;WAjCT,WAAQ,gBAAA;SAEV,OACN,SAAS,mCACP;EAyBH,YACkB,QAAQ,UACR,gBACA,MAAG,+BACX,QAAQ;;UAIV;UAYA;EAqBR,sBAAsB,MAAM,MAAM,oBAAoB;EAShD,YAAY,cAAc,QAAQ;EAgBlC,eAAe,MAAM,MAAM,qBAAsB;EAuBjD,aACL,QAAQ,iBACR,qBACE;EAeG,UACL,QAAQ,iBACR,qBACE,QAAQ;EA6BL,gBACL,KACA,SACA,aACA,aACE,mBAAmB,QAAQ;EA8BxB,OACL,aACA,eAAe,QACf,sBACE;EAkBG,OAAO,cAAc;;oBAUhB;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGS;EACT;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;EACA,QAAQ;;;;qBC/QI,UAAU"}
|
package/dist/aws.mjs
CHANGED
|
@@ -129,6 +129,40 @@ var AmazonStorageClient = class AmazonStorageClient {
|
|
|
129
129
|
}))
|
|
130
130
|
};
|
|
131
131
|
}
|
|
132
|
+
async getUploadPost({ key, maxSize, contentType, expiresIn = 300 }) {
|
|
133
|
+
const fields = {};
|
|
134
|
+
const conditions = [[
|
|
135
|
+
"content-length-range",
|
|
136
|
+
0,
|
|
137
|
+
maxSize
|
|
138
|
+
]];
|
|
139
|
+
if (typeof contentType === "string") {
|
|
140
|
+
fields["Content-Type"] = contentType;
|
|
141
|
+
conditions.push([
|
|
142
|
+
"eq",
|
|
143
|
+
"$Content-Type",
|
|
144
|
+
contentType
|
|
145
|
+
]);
|
|
146
|
+
} else if (contentType) conditions.push([
|
|
147
|
+
"starts-with",
|
|
148
|
+
"$Content-Type",
|
|
149
|
+
contentType.startsWith
|
|
150
|
+
]);
|
|
151
|
+
const expiresAt = new Date(Date.now() + expiresIn * 1e3).toISOString();
|
|
152
|
+
const post = await this.traced("presign", () => createPresignedPost(this.client, {
|
|
153
|
+
Bucket: this.bucket,
|
|
154
|
+
Key: key,
|
|
155
|
+
Expires: expiresIn,
|
|
156
|
+
Fields: fields,
|
|
157
|
+
Conditions: conditions
|
|
158
|
+
}), { "storage.presign.method": "POST" });
|
|
159
|
+
return {
|
|
160
|
+
url: post.url,
|
|
161
|
+
fields: post.fields,
|
|
162
|
+
key,
|
|
163
|
+
expiresAt
|
|
164
|
+
};
|
|
165
|
+
}
|
|
132
166
|
async upload(key, data, contentType) {
|
|
133
167
|
const Body = typeof data === "string" ? Buffer.from(data, "base64") : data;
|
|
134
168
|
const params = {
|
package/dist/aws.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws.mjs","names":[],"sources":["../src/telemetry.ts","../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"sourcesContent":["/**\n * A span per storage call, through the global OpenTelemetry tracer — a no-op\n * without a registered provider.\n *\n * `storage.presign`, `storage.put`, `storage.delete` and `storage.list`, with\n * the backend and the bucket. Never the object's key: keys often name a user.\n *\n * @module\n */\nimport {\n\ttype Attributes,\n\tSpanKind,\n\tSpanStatusCode,\n\ttrace,\n} from '@opentelemetry/api';\n\nexport type StorageOperation = 'presign' | 'put' | 'delete' | 'list';\n\n/** Run `fn` inside a `storage.<operation>` span. */\nexport async function traceStorage<T>(\n\toperation: StorageOperation,\n\tattributes: Attributes,\n\tfn: () => Promise<T>,\n): Promise<T> {\n\tconst span = trace\n\t\t.getTracer('@geekmidas/storage')\n\t\t.startSpan(`storage.${operation}`, {\n\t\t\tkind: SpanKind.CLIENT,\n\t\t\tattributes: { 'storage.operation': operation, ...attributes },\n\t\t});\n\ttry {\n\t\treturn await fn();\n\t} catch (error) {\n\t\tif (error instanceof Error) span.recordException(error);\n\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\tthrow error;\n\t} finally {\n\t\tspan.end();\n\t}\n}\n","import {\n\tDeleteObjectCommand,\n\tGetObjectCommand,\n\tListObjectVersionsCommand,\n\tPutObjectCommand,\n\tS3Client,\n} from '@aws-sdk/client-s3';\nimport { createPresignedPost } from '@aws-sdk/s3-presigned-post';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\n\nimport type { Cache } from '@geekmidas/cache';\nimport type { Attributes } from '@opentelemetry/api';\nimport {\n\ttype DocumentVersion,\n\ttype File,\n\ttype GetUploadParams,\n\ttype GetUploadResponse,\n\ttype StorageClient,\n\tStorageProvider,\n} from './StorageClient';\nimport { type StorageOperation, traceStorage } from './telemetry';\n\nexport class AmazonStorageClient implements StorageClient {\n\treadonly provider = StorageProvider.AWSS3;\n\n\tstatic create(\n\t\toptions: AmazonStorageClientCreateOptions,\n\t): AmazonStorageClient {\n\t\tconst {\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\taccessKeyId,\n\t\t\tacl,\n\t\t\tendpoint,\n\t\t\tsecretAccessKey,\n\t\t\tforcePathStyle = false,\n\t\t\tcache,\n\t\t} = options;\n\t\tconst hasCredentials = accessKeyId && secretAccessKey;\n\t\tconst credentials = hasCredentials\n\t\t\t? { accessKeyId, secretAccessKey }\n\t\t\t: undefined;\n\n\t\tconst client = new S3Client({\n\t\t\tregion,\n\t\t\tcredentials,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t});\n\n\t\treturn new AmazonStorageClient(client, bucket, acl, cache);\n\t}\n\tconstructor(\n\t\tprivate readonly client: S3Client,\n\t\tprivate readonly bucket: string,\n\t\tprivate readonly acl = AmazonCannedAccessControlList.AuthenticatedRead,\n\t\treadonly cache?: Cache,\n\t) {}\n\n\t/** A storage span on this bucket. */\n\tprivate traced<T>(\n\t\toperation: StorageOperation,\n\t\tfn: () => Promise<T>,\n\t\tattributes: Attributes = {},\n\t): Promise<T> {\n\t\treturn traceStorage(\n\t\t\toperation,\n\t\t\t{ 'storage.system': 's3', 'storage.bucket': this.bucket, ...attributes },\n\t\t\tfn,\n\t\t);\n\t}\n\n\tprivate createGetObjectCommand(\n\t\tfile: File,\n\t\toverrides?: { VersionId?: string },\n\t): GetObjectCommand {\n\t\tconst disposition =\n\t\t\tfile.disposition ?? (file.name ? 'attachment' : undefined);\n\t\tconst ResponseContentDisposition = disposition\n\t\t\t? file.name\n\t\t\t\t? `${disposition}; filename=${encodeURIComponent(file.name)}`\n\t\t\t\t: disposition\n\t\t\t: undefined;\n\n\t\treturn new GetObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: file.path,\n\t\t\tResponseContentDisposition,\n\t\t\tResponseContentType: file.responseContentType,\n\t\t\t...overrides,\n\t\t});\n\t}\n\n\tgetVersionDownloadURL(file: File, versionId: string): Promise<string> {\n\t\tconst command = this.createGetObjectCommand(file, { VersionId: versionId });\n\t\treturn this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn: 60 * 60 * 24 }),\n\t\t\t{ 'storage.presign.method': 'GET' },\n\t\t);\n\t}\n\n\tasync getVersions(key: string): Promise<DocumentVersion[]> {\n\t\tconst command = new ListObjectVersionsCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tPrefix: key,\n\t\t});\n\n\t\tconst { Versions = [] } = await this.traced('list', () =>\n\t\t\tthis.client.send(command),\n\t\t);\n\n\t\treturn Versions.map((version) => ({\n\t\t\tid: version.VersionId || '',\n\t\t\tcreatedAt: version.LastModified || new Date(),\n\t\t}));\n\t}\n\n\tasync getDownloadURL(file: File, expiresIn = 60 * 60): Promise<string> {\n\t\tconst cacheKey = `download-url:${file.path}`;\n\t\tconst cachedURL = await this.cache?.get<string>(cacheKey);\n\n\t\tif (cachedURL) {\n\t\t\treturn cachedURL;\n\t\t}\n\n\t\tconst command = this.createGetObjectCommand(file);\n\t\tconst url = await this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn }),\n\t\t\t{ 'storage.presign.method': 'GET' },\n\t\t);\n\t\tconst cacheExpiration = Math.max(expiresIn - 60, 0);\n\n\t\tif (cacheExpiration) {\n\t\t\tawait this.cache?.set(cacheKey, url, cacheExpiration);\n\t\t}\n\n\t\treturn url;\n\t}\n\n\tasync getUploadURL(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 60 * 60,\n\t): Promise<string> {\n\t\tconst command = new PutObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: params.path,\n\t\t\tContentType: params.contentType,\n\t\t\tContentLength: params.contentLength,\n\t\t});\n\n\t\treturn this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn }),\n\t\t\t{ 'storage.presign.method': 'PUT' },\n\t\t);\n\t}\n\n\tasync getUpload(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 5,\n\t): Promise<GetUploadResponse> {\n\t\tconst { path } = params;\n\t\tconst { fields: values, url } = await this.traced(\n\t\t\t'presign',\n\t\t\t() =>\n\t\t\t\tcreatePresignedPost(this.client, {\n\t\t\t\t\tExpires: expiresIn * 60,\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tFields: {\n\t\t\t\t\t\tacl: this.acl,\n\t\t\t\t\t},\n\t\t\t\t\tConditions: [\n\t\t\t\t\t\t// content length restrictions: 0-1MB]\n\t\t\t\t\t\t// ['content-length-range', 0, contentLength],\n\t\t\t\t\t\t// specify content-type to be more generic- images only\n\t\t\t\t\t\t// ['starts-with', '$Content-Type', 'image/'],\n\t\t\t\t\t\t// ['starts-with', '$Content-Type', contentType],\n\t\t\t\t\t],\n\t\t\t\t\tKey: path,\n\t\t\t\t}),\n\t\t\t{ 'storage.presign.method': 'POST' },\n\t\t);\n\n\t\tconst keys = Object.keys(values);\n\t\tconst fields = keys.map((key) => ({ key, value: values[key] || '' }));\n\n\t\treturn { url, fields };\n\t}\n\n\tasync upload(\n\t\tkey: string,\n\t\tdata: string | Buffer,\n\t\tcontentType: string,\n\t): Promise<void> {\n\t\tconst Body = typeof data === 'string' ? Buffer.from(data, 'base64') : data;\n\n\t\tconst params = {\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t\tBody,\n\t\t\tContentType: contentType,\n\t\t};\n\n\t\tconst command = new PutObjectCommand(params);\n\n\t\tawait this.traced('put', () => this.client.send(command), {\n\t\t\t'storage.object.size': Body.length,\n\t\t\t'storage.object.content_type': contentType,\n\t\t});\n\t}\n\n\tasync delete(key: string): Promise<void> {\n\t\tconst command = new DeleteObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t});\n\n\t\tawait this.traced('delete', () => this.client.send(command));\n\t}\n}\n\nexport enum AmazonCannedAccessControlList {\n\tAuthenticatedRead = 'authenticated-read',\n\tPrivate = 'private',\n\tPublicRead = 'public-read',\n\tPublicReadWrite = 'public-read-write',\n\tAwsExecRead = 'aws-exec-read',\n\tBucketOwnerRead = 'bucket-owner-read',\n\tBucketOwnerFullControl = 'bucket-owner-full-control',\n\tLogDeliveryWrite = 'log-delivery-write',\n}\n\ninterface AmazonStorageClientCreateOptions {\n\tbucket: string;\n\tregion?: string;\n\tacl?: AmazonCannedAccessControlList;\n\taccessKeyId?: string;\n\tsecretAccessKey?: string;\n\tendpoint?: string;\n\tforcePathStyle?: boolean;\n\tcache?: Cache;\n}\n","/**\n * The S3 driver — `s3://` URLs to an {@link AmazonStorageClient}.\n *\n * Registered by whoever assembles the application, so neutral code can build a\n * client from a URL without importing this file or the AWS SDK behind it.\n */\n\nimport { AmazonStorageClient } from './AmazonStorageClient';\nimport type { StorageDriver } from './registry';\nimport { parse } from './s3Url';\n\nexport const s3Driver: StorageDriver = {\n\tscheme: 's3:',\n\tcreate(url) {\n\t\t// The URL's own key pair, when it has one, wins over the SDK's default\n\t\t// chain; without one the client resolves credentials as it always has.\n\t\tconst {\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t\taccessKeyId,\n\t\t\tsecretAccessKey,\n\t\t} = parse(url);\n\t\treturn AmazonStorageClient.create({\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t\taccessKeyId,\n\t\t\tsecretAccessKey,\n\t\t});\n\t},\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"aws.mjs","names":[],"sources":["../src/telemetry.ts","../src/AmazonStorageClient.ts","../src/s3Driver.ts"],"sourcesContent":["/**\n * A span per storage call, through the global OpenTelemetry tracer — a no-op\n * without a registered provider.\n *\n * `storage.presign`, `storage.put`, `storage.delete` and `storage.list`, with\n * the backend and the bucket. Never the object's key: keys often name a user.\n *\n * @module\n */\nimport {\n\ttype Attributes,\n\tSpanKind,\n\tSpanStatusCode,\n\ttrace,\n} from '@opentelemetry/api';\n\nexport type StorageOperation = 'presign' | 'put' | 'delete' | 'list';\n\n/** Run `fn` inside a `storage.<operation>` span. */\nexport async function traceStorage<T>(\n\toperation: StorageOperation,\n\tattributes: Attributes,\n\tfn: () => Promise<T>,\n): Promise<T> {\n\tconst span = trace\n\t\t.getTracer('@geekmidas/storage')\n\t\t.startSpan(`storage.${operation}`, {\n\t\t\tkind: SpanKind.CLIENT,\n\t\t\tattributes: { 'storage.operation': operation, ...attributes },\n\t\t});\n\ttry {\n\t\treturn await fn();\n\t} catch (error) {\n\t\tif (error instanceof Error) span.recordException(error);\n\t\tspan.setStatus({ code: SpanStatusCode.ERROR });\n\t\tthrow error;\n\t} finally {\n\t\tspan.end();\n\t}\n}\n","import {\n\tDeleteObjectCommand,\n\tGetObjectCommand,\n\tListObjectVersionsCommand,\n\tPutObjectCommand,\n\tS3Client,\n} from '@aws-sdk/client-s3';\nimport {\n\tcreatePresignedPost,\n\ttype PresignedPostOptions,\n} from '@aws-sdk/s3-presigned-post';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\n\nimport type { Cache } from '@geekmidas/cache';\nimport type { Attributes } from '@opentelemetry/api';\nimport {\n\ttype DocumentVersion,\n\ttype File,\n\ttype GetUploadParams,\n\ttype GetUploadResponse,\n\ttype StorageClient,\n\tStorageProvider,\n\ttype UploadPost,\n\ttype UploadPostParams,\n} from './StorageClient';\nimport { type StorageOperation, traceStorage } from './telemetry';\n\nexport class AmazonStorageClient implements StorageClient {\n\treadonly provider = StorageProvider.AWSS3;\n\n\tstatic create(\n\t\toptions: AmazonStorageClientCreateOptions,\n\t): AmazonStorageClient {\n\t\tconst {\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\taccessKeyId,\n\t\t\tacl,\n\t\t\tendpoint,\n\t\t\tsecretAccessKey,\n\t\t\tforcePathStyle = false,\n\t\t\tcache,\n\t\t} = options;\n\t\tconst hasCredentials = accessKeyId && secretAccessKey;\n\t\tconst credentials = hasCredentials\n\t\t\t? { accessKeyId, secretAccessKey }\n\t\t\t: undefined;\n\n\t\tconst client = new S3Client({\n\t\t\tregion,\n\t\t\tcredentials,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t});\n\n\t\treturn new AmazonStorageClient(client, bucket, acl, cache);\n\t}\n\tconstructor(\n\t\tprivate readonly client: S3Client,\n\t\tprivate readonly bucket: string,\n\t\tprivate readonly acl = AmazonCannedAccessControlList.AuthenticatedRead,\n\t\treadonly cache?: Cache,\n\t) {}\n\n\t/** A storage span on this bucket. */\n\tprivate traced<T>(\n\t\toperation: StorageOperation,\n\t\tfn: () => Promise<T>,\n\t\tattributes: Attributes = {},\n\t): Promise<T> {\n\t\treturn traceStorage(\n\t\t\toperation,\n\t\t\t{ 'storage.system': 's3', 'storage.bucket': this.bucket, ...attributes },\n\t\t\tfn,\n\t\t);\n\t}\n\n\tprivate createGetObjectCommand(\n\t\tfile: File,\n\t\toverrides?: { VersionId?: string },\n\t): GetObjectCommand {\n\t\tconst disposition =\n\t\t\tfile.disposition ?? (file.name ? 'attachment' : undefined);\n\t\tconst ResponseContentDisposition = disposition\n\t\t\t? file.name\n\t\t\t\t? `${disposition}; filename=${encodeURIComponent(file.name)}`\n\t\t\t\t: disposition\n\t\t\t: undefined;\n\n\t\treturn new GetObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: file.path,\n\t\t\tResponseContentDisposition,\n\t\t\tResponseContentType: file.responseContentType,\n\t\t\t...overrides,\n\t\t});\n\t}\n\n\tgetVersionDownloadURL(file: File, versionId: string): Promise<string> {\n\t\tconst command = this.createGetObjectCommand(file, { VersionId: versionId });\n\t\treturn this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn: 60 * 60 * 24 }),\n\t\t\t{ 'storage.presign.method': 'GET' },\n\t\t);\n\t}\n\n\tasync getVersions(key: string): Promise<DocumentVersion[]> {\n\t\tconst command = new ListObjectVersionsCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tPrefix: key,\n\t\t});\n\n\t\tconst { Versions = [] } = await this.traced('list', () =>\n\t\t\tthis.client.send(command),\n\t\t);\n\n\t\treturn Versions.map((version) => ({\n\t\t\tid: version.VersionId || '',\n\t\t\tcreatedAt: version.LastModified || new Date(),\n\t\t}));\n\t}\n\n\tasync getDownloadURL(file: File, expiresIn = 60 * 60): Promise<string> {\n\t\tconst cacheKey = `download-url:${file.path}`;\n\t\tconst cachedURL = await this.cache?.get<string>(cacheKey);\n\n\t\tif (cachedURL) {\n\t\t\treturn cachedURL;\n\t\t}\n\n\t\tconst command = this.createGetObjectCommand(file);\n\t\tconst url = await this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn }),\n\t\t\t{ 'storage.presign.method': 'GET' },\n\t\t);\n\t\tconst cacheExpiration = Math.max(expiresIn - 60, 0);\n\n\t\tif (cacheExpiration) {\n\t\t\tawait this.cache?.set(cacheKey, url, cacheExpiration);\n\t\t}\n\n\t\treturn url;\n\t}\n\n\tasync getUploadURL(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 60 * 60,\n\t): Promise<string> {\n\t\tconst command = new PutObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: params.path,\n\t\t\tContentType: params.contentType,\n\t\t\tContentLength: params.contentLength,\n\t\t});\n\n\t\treturn this.traced(\n\t\t\t'presign',\n\t\t\t() => getSignedUrl(this.client, command, { expiresIn }),\n\t\t\t{ 'storage.presign.method': 'PUT' },\n\t\t);\n\t}\n\n\tasync getUpload(\n\t\tparams: GetUploadParams,\n\t\texpiresIn = 5,\n\t): Promise<GetUploadResponse> {\n\t\tconst { path } = params;\n\t\tconst { fields: values, url } = await this.traced(\n\t\t\t'presign',\n\t\t\t() =>\n\t\t\t\tcreatePresignedPost(this.client, {\n\t\t\t\t\tExpires: expiresIn * 60,\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tFields: {\n\t\t\t\t\t\tacl: this.acl,\n\t\t\t\t\t},\n\t\t\t\t\tConditions: [\n\t\t\t\t\t\t// content length restrictions: 0-1MB]\n\t\t\t\t\t\t// ['content-length-range', 0, contentLength],\n\t\t\t\t\t\t// specify content-type to be more generic- images only\n\t\t\t\t\t\t// ['starts-with', '$Content-Type', 'image/'],\n\t\t\t\t\t\t// ['starts-with', '$Content-Type', contentType],\n\t\t\t\t\t],\n\t\t\t\t\tKey: path,\n\t\t\t\t}),\n\t\t\t{ 'storage.presign.method': 'POST' },\n\t\t);\n\n\t\tconst keys = Object.keys(values);\n\t\tconst fields = keys.map((key) => ({ key, value: values[key] || '' }));\n\n\t\treturn { url, fields };\n\t}\n\n\tasync getUploadPost({\n\t\tkey,\n\t\tmaxSize,\n\t\tcontentType,\n\t\texpiresIn = 300,\n\t}: UploadPostParams): Promise<UploadPost> {\n\t\tconst fields: Record<string, string> = {};\n\t\tconst conditions: NonNullable<PresignedPostOptions['Conditions']> = [\n\t\t\t['content-length-range', 0, maxSize],\n\t\t];\n\t\tif (typeof contentType === 'string') {\n\t\t\tfields['Content-Type'] = contentType;\n\t\t\tconditions.push(['eq', '$Content-Type', contentType]);\n\t\t} else if (contentType) {\n\t\t\tconditions.push(['starts-with', '$Content-Type', contentType.startsWith]);\n\t\t}\n\n\t\t// Read before signing, so the timestamp is never later than the policy's.\n\t\tconst expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();\n\t\tconst post = await this.traced(\n\t\t\t'presign',\n\t\t\t() =>\n\t\t\t\tcreatePresignedPost(this.client, {\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: key,\n\t\t\t\t\tExpires: expiresIn,\n\t\t\t\t\tFields: fields,\n\t\t\t\t\tConditions: conditions,\n\t\t\t\t}),\n\t\t\t{ 'storage.presign.method': 'POST' },\n\t\t);\n\n\t\treturn { url: post.url, fields: post.fields, key, expiresAt };\n\t}\n\n\tasync upload(\n\t\tkey: string,\n\t\tdata: string | Buffer,\n\t\tcontentType: string,\n\t): Promise<void> {\n\t\tconst Body = typeof data === 'string' ? Buffer.from(data, 'base64') : data;\n\n\t\tconst params = {\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t\tBody,\n\t\t\tContentType: contentType,\n\t\t};\n\n\t\tconst command = new PutObjectCommand(params);\n\n\t\tawait this.traced('put', () => this.client.send(command), {\n\t\t\t'storage.object.size': Body.length,\n\t\t\t'storage.object.content_type': contentType,\n\t\t});\n\t}\n\n\tasync delete(key: string): Promise<void> {\n\t\tconst command = new DeleteObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: key,\n\t\t});\n\n\t\tawait this.traced('delete', () => this.client.send(command));\n\t}\n}\n\nexport enum AmazonCannedAccessControlList {\n\tAuthenticatedRead = 'authenticated-read',\n\tPrivate = 'private',\n\tPublicRead = 'public-read',\n\tPublicReadWrite = 'public-read-write',\n\tAwsExecRead = 'aws-exec-read',\n\tBucketOwnerRead = 'bucket-owner-read',\n\tBucketOwnerFullControl = 'bucket-owner-full-control',\n\tLogDeliveryWrite = 'log-delivery-write',\n}\n\ninterface AmazonStorageClientCreateOptions {\n\tbucket: string;\n\tregion?: string;\n\tacl?: AmazonCannedAccessControlList;\n\taccessKeyId?: string;\n\tsecretAccessKey?: string;\n\tendpoint?: string;\n\tforcePathStyle?: boolean;\n\tcache?: Cache;\n}\n","/**\n * The S3 driver — `s3://` URLs to an {@link AmazonStorageClient}.\n *\n * Registered by whoever assembles the application, so neutral code can build a\n * client from a URL without importing this file or the AWS SDK behind it.\n */\n\nimport { AmazonStorageClient } from './AmazonStorageClient';\nimport type { StorageDriver } from './registry';\nimport { parse } from './s3Url';\n\nexport const s3Driver: StorageDriver = {\n\tscheme: 's3:',\n\tcreate(url) {\n\t\t// The URL's own key pair, when it has one, wins over the SDK's default\n\t\t// chain; without one the client resolves credentials as it always has.\n\t\tconst {\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t\taccessKeyId,\n\t\t\tsecretAccessKey,\n\t\t} = parse(url);\n\t\treturn AmazonStorageClient.create({\n\t\t\tbucket,\n\t\t\tregion,\n\t\t\tendpoint,\n\t\t\tforcePathStyle,\n\t\t\taccessKeyId,\n\t\t\tsecretAccessKey,\n\t\t});\n\t},\n};\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as registeredStorageSchemes, l as StorageClient, n as createStorageClient, r as registerStorageDriver, t as StorageDriver } from "./registry-
|
|
1
|
+
import { d as UploadPost, f as UploadPostParams, i as registeredStorageSchemes, l as StorageClient, n as createStorageClient, r as registerStorageDriver, t as StorageDriver } from "./registry-DyBOtv6n.cjs";
|
|
2
2
|
//#region src/errors.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Storage errors — shared by every implementation, not just S3.
|
|
@@ -83,5 +83,5 @@ export declare class UnregisteredStorageScheme extends StorageUrlError {
|
|
|
83
83
|
constructor(url: string, scheme: string, registered: readonly string[]);
|
|
84
84
|
}
|
|
85
85
|
//#endregion
|
|
86
|
-
export { type StorageClient, type StorageDriver, createStorageClient, registerStorageDriver, registeredStorageSchemes };
|
|
86
|
+
export { type StorageClient, type StorageDriver, type UploadPost, type UploadPostParams, createStorageClient, registerStorageDriver, registeredStorageSchemes };
|
|
87
87
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as registeredStorageSchemes, l as StorageClient, n as createStorageClient, r as registerStorageDriver, t as StorageDriver } from "./registry-
|
|
1
|
+
import { d as UploadPost, f as UploadPostParams, i as registeredStorageSchemes, l as StorageClient, n as createStorageClient, r as registerStorageDriver, t as StorageDriver } from "./registry-DyBOtv6n.mjs";
|
|
2
2
|
//#region src/errors.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Storage errors — shared by every implementation, not just S3.
|
|
@@ -83,5 +83,5 @@ export declare class UnregisteredStorageScheme extends StorageUrlError {
|
|
|
83
83
|
constructor(url: string, scheme: string, registered: readonly string[]);
|
|
84
84
|
}
|
|
85
85
|
//#endregion
|
|
86
|
-
export { type StorageClient, type StorageDriver, createStorageClient, registerStorageDriver, registeredStorageSchemes };
|
|
86
|
+
export { type StorageClient, type StorageDriver, type UploadPost, type UploadPostParams, createStorageClient, registerStorageDriver, registeredStorageSchemes };
|
|
87
87
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -57,6 +57,17 @@ interface StorageClient {
|
|
|
57
57
|
* @param expiresIn - The number of minutes the URL should be valid for.
|
|
58
58
|
*/
|
|
59
59
|
getUpload(params: GetUploadParams, expiresIn?: number): Promise<GetUploadResponse>;
|
|
60
|
+
/**
|
|
61
|
+
* A signed form a browser posts one file to, straight into the bucket.
|
|
62
|
+
*
|
|
63
|
+
* The policy is the guard: the storage refuses a file larger than
|
|
64
|
+
* `maxSize`, or of a type the policy does not allow, so nothing the client
|
|
65
|
+
* sends past this call is trusted to the server that issued it.
|
|
66
|
+
*
|
|
67
|
+
* @param params - What may be uploaded, and where.
|
|
68
|
+
* @returns The form's action and fields, the key, and when it expires.
|
|
69
|
+
*/
|
|
70
|
+
getUploadPost(params: UploadPostParams): Promise<UploadPost>;
|
|
60
71
|
/**
|
|
61
72
|
* Delete a file from storage.
|
|
62
73
|
*
|
|
@@ -64,6 +75,37 @@ interface StorageClient {
|
|
|
64
75
|
*/
|
|
65
76
|
delete(key: string): Promise<void>;
|
|
66
77
|
}
|
|
78
|
+
/** What a signed upload form allows. */
|
|
79
|
+
interface UploadPostParams {
|
|
80
|
+
/** Where the object lands. */
|
|
81
|
+
key: string;
|
|
82
|
+
/** The largest file the storage accepts, in bytes. */
|
|
83
|
+
maxSize: number;
|
|
84
|
+
/**
|
|
85
|
+
* The type the file must be sent as: an exact `Content-Type`, fixed in the
|
|
86
|
+
* form's fields — or `{ startsWith }`, which the client sets itself
|
|
87
|
+
* (`image/` for any image). Absent, any type is accepted.
|
|
88
|
+
*/
|
|
89
|
+
contentType?: string | {
|
|
90
|
+
startsWith: string;
|
|
91
|
+
};
|
|
92
|
+
/** How long the form is valid, in seconds. Defaults to 300. */
|
|
93
|
+
expiresIn?: number;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A signed upload form. Post it as `multipart/form-data`: every field, then
|
|
97
|
+
* the file last, as `file`.
|
|
98
|
+
*/
|
|
99
|
+
interface UploadPost {
|
|
100
|
+
/** The form's action — where the browser posts. */
|
|
101
|
+
url: string;
|
|
102
|
+
/** Every field the post must carry, as signed. */
|
|
103
|
+
fields: Record<string, string>;
|
|
104
|
+
/** Where the object lands. */
|
|
105
|
+
key: string;
|
|
106
|
+
/** When the signature stops being accepted, as an ISO timestamp. */
|
|
107
|
+
expiresAt: string;
|
|
108
|
+
}
|
|
67
109
|
interface GetUploadParams {
|
|
68
110
|
path: string;
|
|
69
111
|
contentType: string;
|
|
@@ -117,5 +159,5 @@ declare function registeredStorageSchemes(): string[];
|
|
|
117
159
|
*/
|
|
118
160
|
declare function createStorageClient(url: string): StorageClient;
|
|
119
161
|
//#endregion
|
|
120
|
-
export { DocumentVersion as a, GetUploadResponse as c, registeredStorageSchemes as i, StorageClient as l, createStorageClient as n, File as o, registerStorageDriver as r, GetUploadParams as s, StorageDriver as t, StorageProvider as u };
|
|
121
|
-
//# sourceMappingURL=registry-
|
|
162
|
+
export { DocumentVersion as a, GetUploadResponse as c, UploadPost as d, UploadPostParams as f, registeredStorageSchemes as i, StorageClient as l, createStorageClient as n, File as o, registerStorageDriver as r, GetUploadParams as s, StorageDriver as t, StorageProvider as u };
|
|
163
|
+
//# sourceMappingURL=registry-DyBOtv6n.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-DyBOtv6n.d.cts","names":[],"sources":["../src/StorageClient.ts","../src/registry.ts"],"mappings":";;UACiB;EAChB;EACA,WAAW;;aAGA;EACX;EACA;EACA;;UAGgB;WACP,UAAU;WACV,QAAQ;;;;;;;;;EASjB,aAAa,QAAQ,iBAAiB,qBAAqB;;;;;;;;;EAU3D,eAAe,MAAM,MAAM,qBAAqB;;;;;;EAMhD,YAAY,cAAc,QAAQ;;;;;;;EAQlC,sBAAsB,MAAM,MAAM,oBAAoB;;;;;;;EAOtD,OACC,aACA,eAAe,QACf,sBACE;;;;;;;EAOH,UACC,QAAQ,iBACR,qBACE,QAAQ;;;;;;;;;;;EAWX,cAAc,QAAQ,mBAAmB,QAAQ;;;;;;EAMjD,OAAO,cAAc;;;UAIL;;EAEhB;;EAEA;;;;;;EAMA;IAAyB;;;EAEzB;;;;;;UAOgB;;EAEhB;;EAEA,QAAQ;;EAER;;EAEA;;UAGgB;EAChB;EACA;EACA;;KAGW;EACX;EACA;;KAGW;EACX;EACA,QAAQ;;UAGQ;EAChB;EACA;;;;;EAKA;;;;;;EAMA;;;;;;;;;;UC5HgB;;WAEP;EACT,OAAO,cAAc;;;iBAMN,sBAAsB,QAAQ;;iBAK9B;;;;;;;iBAUA,oBAAoB,cAAc"}
|
|
@@ -57,6 +57,17 @@ interface StorageClient {
|
|
|
57
57
|
* @param expiresIn - The number of minutes the URL should be valid for.
|
|
58
58
|
*/
|
|
59
59
|
getUpload(params: GetUploadParams, expiresIn?: number): Promise<GetUploadResponse>;
|
|
60
|
+
/**
|
|
61
|
+
* A signed form a browser posts one file to, straight into the bucket.
|
|
62
|
+
*
|
|
63
|
+
* The policy is the guard: the storage refuses a file larger than
|
|
64
|
+
* `maxSize`, or of a type the policy does not allow, so nothing the client
|
|
65
|
+
* sends past this call is trusted to the server that issued it.
|
|
66
|
+
*
|
|
67
|
+
* @param params - What may be uploaded, and where.
|
|
68
|
+
* @returns The form's action and fields, the key, and when it expires.
|
|
69
|
+
*/
|
|
70
|
+
getUploadPost(params: UploadPostParams): Promise<UploadPost>;
|
|
60
71
|
/**
|
|
61
72
|
* Delete a file from storage.
|
|
62
73
|
*
|
|
@@ -64,6 +75,37 @@ interface StorageClient {
|
|
|
64
75
|
*/
|
|
65
76
|
delete(key: string): Promise<void>;
|
|
66
77
|
}
|
|
78
|
+
/** What a signed upload form allows. */
|
|
79
|
+
interface UploadPostParams {
|
|
80
|
+
/** Where the object lands. */
|
|
81
|
+
key: string;
|
|
82
|
+
/** The largest file the storage accepts, in bytes. */
|
|
83
|
+
maxSize: number;
|
|
84
|
+
/**
|
|
85
|
+
* The type the file must be sent as: an exact `Content-Type`, fixed in the
|
|
86
|
+
* form's fields — or `{ startsWith }`, which the client sets itself
|
|
87
|
+
* (`image/` for any image). Absent, any type is accepted.
|
|
88
|
+
*/
|
|
89
|
+
contentType?: string | {
|
|
90
|
+
startsWith: string;
|
|
91
|
+
};
|
|
92
|
+
/** How long the form is valid, in seconds. Defaults to 300. */
|
|
93
|
+
expiresIn?: number;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A signed upload form. Post it as `multipart/form-data`: every field, then
|
|
97
|
+
* the file last, as `file`.
|
|
98
|
+
*/
|
|
99
|
+
interface UploadPost {
|
|
100
|
+
/** The form's action — where the browser posts. */
|
|
101
|
+
url: string;
|
|
102
|
+
/** Every field the post must carry, as signed. */
|
|
103
|
+
fields: Record<string, string>;
|
|
104
|
+
/** Where the object lands. */
|
|
105
|
+
key: string;
|
|
106
|
+
/** When the signature stops being accepted, as an ISO timestamp. */
|
|
107
|
+
expiresAt: string;
|
|
108
|
+
}
|
|
67
109
|
interface GetUploadParams {
|
|
68
110
|
path: string;
|
|
69
111
|
contentType: string;
|
|
@@ -117,5 +159,5 @@ declare function registeredStorageSchemes(): string[];
|
|
|
117
159
|
*/
|
|
118
160
|
declare function createStorageClient(url: string): StorageClient;
|
|
119
161
|
//#endregion
|
|
120
|
-
export { DocumentVersion as a, GetUploadResponse as c, registeredStorageSchemes as i, StorageClient as l, createStorageClient as n, File as o, registerStorageDriver as r, GetUploadParams as s, StorageDriver as t, StorageProvider as u };
|
|
121
|
-
//# sourceMappingURL=registry-
|
|
162
|
+
export { DocumentVersion as a, GetUploadResponse as c, UploadPost as d, UploadPostParams as f, registeredStorageSchemes as i, StorageClient as l, createStorageClient as n, File as o, registerStorageDriver as r, GetUploadParams as s, StorageDriver as t, StorageProvider as u };
|
|
163
|
+
//# sourceMappingURL=registry-DyBOtv6n.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-DyBOtv6n.d.mts","names":[],"sources":["../src/StorageClient.ts","../src/registry.ts"],"mappings":";;UACiB;EAChB;EACA,WAAW;;aAGA;EACX;EACA;EACA;;UAGgB;WACP,UAAU;WACV,QAAQ;;;;;;;;;EASjB,aAAa,QAAQ,iBAAiB,qBAAqB;;;;;;;;;EAU3D,eAAe,MAAM,MAAM,qBAAqB;;;;;;EAMhD,YAAY,cAAc,QAAQ;;;;;;;EAQlC,sBAAsB,MAAM,MAAM,oBAAoB;;;;;;;EAOtD,OACC,aACA,eAAe,QACf,sBACE;;;;;;;EAOH,UACC,QAAQ,iBACR,qBACE,QAAQ;;;;;;;;;;;EAWX,cAAc,QAAQ,mBAAmB,QAAQ;;;;;;EAMjD,OAAO,cAAc;;;UAIL;;EAEhB;;EAEA;;;;;;EAMA;IAAyB;;;EAEzB;;;;;;UAOgB;;EAEhB;;EAEA,QAAQ;;EAER;;EAEA;;UAGgB;EAChB;EACA;EACA;;KAGW;EACX;EACA;;KAGW;EACX;EACA,QAAQ;;UAGQ;EAChB;EACA;;;;;EAKA;;;;;;EAMA;;;;;;;;;;UC5HgB;;WAEP;EACT,OAAO,cAAc;;;iBAMN,sBAAsB,QAAQ;;iBAK9B;;;;;;;iBAUA,oBAAoB,cAAc"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geekmidas/storage",
|
|
3
|
-
"version": "10.0.0-alpha.
|
|
3
|
+
"version": "10.0.0-alpha.119",
|
|
4
4
|
"private": false,
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"@aws-sdk/client-s3": ">=3.1136.0",
|
|
55
55
|
"@aws-sdk/s3-presigned-post": ">=3.1136.0",
|
|
56
56
|
"@aws-sdk/s3-request-presigner": ">=3.1136.0",
|
|
57
|
-
"@geekmidas/cache": "^10.0.0-alpha.
|
|
57
|
+
"@geekmidas/cache": "^10.0.0-alpha.119"
|
|
58
58
|
},
|
|
59
59
|
"peerDependenciesMeta": {
|
|
60
60
|
"@geekmidas/cache": {
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@opentelemetry/sdk-trace-node": "~2.11.0",
|
|
78
|
-
"@geekmidas/cache": "^10.0.0-alpha.
|
|
78
|
+
"@geekmidas/cache": "^10.0.0-alpha.119"
|
|
79
79
|
},
|
|
80
80
|
"scripts": {
|
|
81
81
|
"build": "tsdown --config ../../tsdown.config.ts --filter ."
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registry-ClEvHGpM.d.cts","names":[],"sources":["../src/StorageClient.ts","../src/registry.ts"],"mappings":";;UACiB;EAChB;EACA,WAAW;;aAGA;EACX;EACA;EACA;;UAGgB;WACP,UAAU;WACV,QAAQ;;;;;;;;;EASjB,aAAa,QAAQ,iBAAiB,qBAAqB;;;;;;;;;EAU3D,eAAe,MAAM,MAAM,qBAAqB;;;;;;EAMhD,YAAY,cAAc,QAAQ;;;;;;;EAQlC,sBAAsB,MAAM,MAAM,oBAAoB;;;;;;;EAOtD,OACC,aACA,eAAe,QACf,sBACE;;;;;;;EAOH,UACC,QAAQ,iBACR,qBACE,QAAQ;;;;;;EAMX,OAAO,cAAc;;UAGL;EAChB;EACA;EACA;;KAGW;EACX;EACA;;KAGW;EACX;EACA,QAAQ;;UAGQ;EAChB;EACA;;;;;EAKA;;;;;;EAMA;;;;;;;;;;UClFgB;;WAEP;EACT,OAAO,cAAc;;;iBAMN,sBAAsB,QAAQ;;iBAK9B;;;;;;;iBAUA,oBAAoB,cAAc"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registry-ClEvHGpM.d.mts","names":[],"sources":["../src/StorageClient.ts","../src/registry.ts"],"mappings":";;UACiB;EAChB;EACA,WAAW;;aAGA;EACX;EACA;EACA;;UAGgB;WACP,UAAU;WACV,QAAQ;;;;;;;;;EASjB,aAAa,QAAQ,iBAAiB,qBAAqB;;;;;;;;;EAU3D,eAAe,MAAM,MAAM,qBAAqB;;;;;;EAMhD,YAAY,cAAc,QAAQ;;;;;;;EAQlC,sBAAsB,MAAM,MAAM,oBAAoB;;;;;;;EAOtD,OACC,aACA,eAAe,QACf,sBACE;;;;;;;EAOH,UACC,QAAQ,iBACR,qBACE,QAAQ;;;;;;EAMX,OAAO,cAAc;;UAGL;EAChB;EACA;EACA;;KAGW;EACX;EACA;;KAGW;EACX;EACA,QAAQ;;UAGQ;EAChB;EACA;;;;;EAKA;;;;;;EAMA;;;;;;;;;;UClFgB;;WAEP;EACT,OAAO,cAAc;;;iBAMN,sBAAsB,QAAQ;;iBAK9B;;;;;;;iBAUA,oBAAoB,cAAc"}
|