@btravstack/储存
对象存储端口用于
@btravstack/core页:1Storagea 一个 应用程序取决于一个内相适配器,一个S3相容的 预先签名的读取、写取和流出在有界限的内存中,以及跨度, a 计算和每次操作的日志行.
pnpm add @btravstack/storage @btravstack/core @btravstack/config @btravstack/di unthrown
4个同伴依赖关系,加 @aws-sdk/client-s3 财务报告和审定财务报表
@aws-sdk/s3-request-presigner ——可选的,并且只有在你写作时需要
S3适配器. 仪器不需要自己的同伴: Logger, (中文(简体) ), Tracer
财务报告和审定财务报表 Meter 这取决于是
内核的端口。 。 。 .
节点 >=22。 。 。 .
实例
保存文档,并通过不带的 URL 读取 全权证书:
import {
Port as InvoicePort,
Provider as InvoiceProvider,
} from "@btravstack/di";
import { Storage } from "@btravstack/storage";
import type { AsyncResult } from "unthrown";
class Invoices extends InvoicePort("ReadmeInvoices")<{
readonly store: (
tenantId: string,
id: string,
pdf: Uint8Array,
) => AsyncResult<void, never>;
readonly link: (
tenantId: string,
id: string,
) => AsyncResult<string | undefined, never>;
}> {}
// The tenant is in the key because the port has no slot for one — the same
// rule a cache key follows.
const keyFor = (tenantId: string, id: string) =>
`invoices/${tenantId}/${id}.pdf`;
export const invoices = InvoiceProvider(Invoices)({
inject: { storage: Storage },
sync: ({ storage }) => ({
store: (tenantId, id, pdf) =>
storage
.put(keyFor(tenantId, id), pdf, { contentType: "application/pdf" })
// A document that failed to store is YOUR decision to make; here it
// is swallowed because an observer already recorded it and
// counted it one layer down.
.recoverErrCases((matcher) =>
matcher.with(P.tag("StorageUnavailable"), P.tag("InvalidStorageOptions"), P.tag("ChecksumMismatch"), () => undefined),
),
// Serving bytes through your own process is the anti-pattern this arm
// exists to avoid: the caller fetches the object directly, for a minute.
link: (tenantId, id) =>
storage
.presignedUrl(keyFor(tenantId, id), { ttlMs: 60_000 })
.recoverErrCases((matcher) =>
matcher
.with(P.tag("StorageUnavailable"), () => undefined)
.with(P.tag("PresignNotSupported"), () => undefined),
),
}),
});
组成——适配器是唯一的决定, 在这里决定了,没有别的地方:
import { storage } from "@btravstack/storage";
import { s3Storage } from "@btravstack/storage/s3";
export const InvoicesApp = Module("InvoicesApp")({
imports: [
// Instrumented by default, which is why `observability()` and `otel()`
// Every call is reported through `Observers`. Drop the two modules
// below and this composition is unchanged — it just reports to nobody.
storage({ adapter: s3Storage() }),
observability(),
otel(),
],
provides: [invoices],
exports: [Invoices, Logger],
});
选项
| 选项 | 何处 | 这是什么 |
|---|---|---|
sha256 编号 : metadata | put 编号 : putIfAbsent 和流 | 校验写入摘要并解剖地描述对象 |
checksum 编号 : metadata | copy | 计算 SHA-256 服务器侧并替换描述 |
kmsKeyId | 写、复制和 presignedUpload | 选择每个对象 SSE- KMS; 上传客户端发送两个签名的加密信头 |
adapter | storage({ adapter }) | 适配器模块提供 StorageBackend 所需数额 |
STORAGE_S3_ENDPOINT | 环境,读作 s3Storage() | 商店的终点——需要 |
STORAGE_S3_BUCKET | 环境 | 所需桶 |
STORAGE_S3_ACCESS_KEY_ID 编号 : STORAGE_S3_SECRET_ACCESS_KEY | 环境 | 全权证书要求 |
STORAGE_S3_REGION | 环境 | 默认 us-east-1 |
STORAGE_S3_MAX_SOCKETS 编号 : maxSockets | 环境,或 s3Storage({...}) | 套接字每一次呼叫, 但不包含流出共享—— 默认 50,SDK's(SDK's |
STORAGE_S3_STREAM_MAX_SOCKETS 编号 : streamMaxSockets | 环境,或 s3Storage({...}) | 串行调用自有调用池, 及其约束- 默认 50 |
STORAGE_S3_CONNECTION_TIMEOUT_MS 编号 : connectionTimeoutMs | 环境,或 s3Storage({...}) | 尝试等待套接字多久——默认 0,无 |
STORAGE_S3_SOCKET_TIMEOUT_MS 编号 : socketTimeoutMs | 环境,或 s3Storage({...}) | 尝试的套接字可以保持闲置多久——默认 0,无 |
STORAGE_S3_REQUEST_TIMEOUT_MS 编号 : requestTimeoutMs | 环境,或 s3Storage({...}) | 尝试等待商店回答多久 — 默认 0,无 |
STORAGE_S3_STREAM_CONNECTION_TIMEOUT_MS 编号 : streamConnectionTimeoutMs | 环境,或 s3Storage({...}) | 流池自身的连接超时——默认 connectionTimeoutMs |
STORAGE_S3_STREAM_SOCKET_TIMEOUT_MS 编号 : streamSocketTimeoutMs | 环境,或 s3Storage({...}) | 流池自设套接字超时——默认 socketTimeoutMs |
STORAGE_S3_STREAM_REQUEST_TIMEOUT_MS 编号 : streamRequestTimeoutMs | 环境,或 s3Storage({...}) | 流池自身的请求超时——默认 requestTimeoutMs |
完整表——默认,语义和推理——活在 参考页, (中文(简体) ), 这张名单是详细的.
它决定什么,它没有
决定 失踪物体是普通的答案而不是过错
(计算) not_found,没有过错线),即持有的密钥下 putIfAbsent 是一个普通的答案( a)ObjectExists数字 exists),该 delete 是天能的,那个 copy 财务报告和审定财务报表 head 字节从不通过这个过程移动,写作可以验证SHA-256并解析地公布用户元数据,复制取代元数据并可以计算SHA-256服务器侧面,预先签名的上传可以要求每个对象KMS键,流出字节从不离开部分对象(多段上传,在任何故障上中止),流出传输有自有的套接字池并被拒绝()StreamPoolFull数字 saturated而不是排队 一旦它满了
签名前询问商店什么也没有—— 以及无法签名的适配器
而不是刻出只生产失败的 URL .
它没有决定 您的密钥长相, 是否失败的写入
无法满足您的请求, 或者链接应该存在多久 。 没有列名,没有
桶管理——每个原因都在
参考页, (中文(简体) ),
同样的推理是 AGENTS.md 用于贡献者.
许可证
麻省理工学院
接受指定下载 contentDisposition, (中文(简体) ), contentType 财务报告和审定财务报表 cacheControl
反应超过。 见 存储引用
用于签名和 Unicode 文件名语义.