@krizaka/storage

中文文档
0.11.1发布于 2026/11/01Apache-2.0TypeScriptES Module构建来源已验证

每个Krizaka产品的一个端口后面的文件:放入内容哈希的名称,get, head, delete, list,签名和公共url;为HTTP对象存储和任何s3兼容的桶(签名V4,没有SDK)以及本地文件夹进行注入获取的适配器

中文使用文档

@ krizaka/storage

每个Krizaka产品的文件都在一个端口后面。端口是根据它的功能来命名的(ObjectStore),提供者是管理员选择的值。无供应商SDK (纯HTTP通过注入 fetch),没有环境变量,没有挂钟。

  • 港口。 put, get, head, delete, list(prefix), signedUrl(key, ttl) 对于私人区域, publicUrl(key) 当存在拉区或CDN时。
  • 适配器。 remoteStore (一个形状为Bunny Storage的HTTP区域: AccessKey 头, PUT/GET/DELETE,一个由其路径列出的带有尾部斜杠的目录,一个带有令牌签名链接的拉区), bucketStore (任何兼容s3的服务:签名V4,预签名GET, ListObjectsV2(没有SDK); folderStore (一个文件夹,用于开发、测试和Mac应用程序;密钥永远不会离开根目录), memoryObjectStore. 所有运行 objectStoreContract (@krizaka/storage/testkit)。
  • 每次上传都要遵守的规则 (createStorage):传入大小限制,前缀必须在a中声明 defineLayout (拒绝未知前缀),字节由幻数(sniffType: png, jpeg, gif, webp, pdf, mp4, webm, svg),从不通过扩展名,并且拒绝与字节相矛盾的声明类型。存储的名称是内容散列的, <name>.<sha10>.<ext>,所以URL永远不会改变内容。
  • 管理员选择 (@krizaka/storage/settings): storage.provider (local, http, s3), storage.maxMegabytes, storage.signedUrlSeconds,而非机密坐标(endpoint, region, bucket, zone, prefix, pullHostname, publicBaseUrl). 钥匙留在环境中; storeFromSettings 将它们作为参数,并在没有需要的情况下拒绝所选择的提供者,而不是退回到另一个。一个管理类型的S3端点通过 checkEndpoint (仅https,没有凭据,没有本地或私有地址)。
  • 静态加密,保险库,区域和 where. encryptedStore(inner, key) (AES-256-GCM ObjectStore;键是一个参数;提供者保存密文;没有链接), seal/open (数据库中的凭据, v1. 信封), COUNTRY_OF_REGION (一个地区表:未列出的地区永远不是一个国家; residencyOfConfig 只有在区域和端点一致的情况下才会显示“加拿大”,而不是兔形区域), where(kind, active, { fixed, devOnly }) 和 storageNotice (信息面板的句子键,来自配置)。
  • 环境管理 (@krizaka/storage/resolve)。 resolveStorage(env, admin) 提供各种类型的数据(文档,头像):传递各自的数据 DeploymentStorage):管理员的 storage.* 当管理员离开时,环境提供了秘密和退路 local. 如果环境说 none 然后管理员继续打开,它抛出 StorageError STORAGE_KEEPING_OFF (在保存设置时调用它来拒绝早期):保持在环境中打开,永远不要单独通过设置。 openResolved 生成存储,并在给出密钥时进行加密。
  • 供应商注册表 (adr - 005)。 PROVIDER_KINDS 类型表是否为数据(bunny, s3 预置DigitalOcean Spaces、AWS S3、OVHcloud和generic, dropbox、保留 google-drive/onedrive, folder, device):作用域、运行时、 devOnly、功能、坐标和凭据字段模式。 openProvider(kind, coordinates, credentials, { runtime, environment, fetch, clock }) (/node)是唯一的工厂,它拒绝(STORAGE_BAD_CONFIG) devOnly 类型在 prod, folder 外 dev,未知或未实现的类型和缺失的字段,并且永远不会回落。它返回store和a ResidencyLabel (PROVINCE_OF_REGION:«Canada (qubec)»,«Canada (Ontario)»…),以便在保存前显示屏幕。 testConnection (探测写、读、比较、删除)和 checkEndpointDns (书面形式加上DNS答案:拒绝私人地址)为每个产品提供服务。
  • 注册表打开OpenDAL类型和private类型 (ADR-005修正案,krizaka-ts#239)。 google-drive 和 onedrive 在用户范围内实现(通过 opendalStore 和 CLOUD_CONNECTORS:访问令牌从密封的刷新令牌更新,一个旋转的令牌返回 OpenContext.onRotate 并由服务部门再次密封); azblob, gcs, b2 和 webdav 它们的字段名是OpenDAL自己的选项 url 字段传递 checkEndpoint 和DNS检查)。 openProvider 现在是异步的。每种类型映射到表中的适配器(BUILT_IN_ADAPTERS),而不是树枝。私有包在不触及核心的情况下添加了一个类: defaultProviderRegistry.with({ kind, open }) (或 createProviderRegistry({ kinds, adapters }))返回一个新的注册表;传递给 openProvider(…, registry) 和 createProviderService({ registry }). 重复的名称被拒绝,秘密不能是坐标,凭证必须是 secret 字段(密封),以及运行时, devOnly、required-field和url规则适用于私有类型和内置类型。
  • Keyring 是一个港口 ({ keyId, wrap, unwrap, openLegacy? })。 localKeyring({ keyId, key, ring }) 是进程内默认值(旧的 Keyring 形状 { keys, legacy } 现在是 LocalKeys); sealWith, openWith 和 rewrapWith 取任何密匙环,因此KMS (AWS KMS ca-central-1, OVHcloud KMS, Vault transit)包装数据密钥,密钥永远不会到达应用程序。 createProviderService({ vault }) 要么是老的 { keyId, key, ring } 或者一个 Keyring. 存储 v2.<key_id>… 格式不变:移动到KMS是不变的 rotateVaultKey,而不是重返大气层。
  • 信封。 sealEnvelope/openEnvelope/rewrapEnvelope:每个密封值的数据密钥,由密钥加密密钥封装(MEDIA_VAULT_KEY)由 key_id (v2.<key_id>.<wrapped>.<sealed>); v1. 值仍然使用遗留键打开;旋转键只重新包装数据键。
  • 每租户信封加密 (ADR-020决定3,管理文件存储)。 KeyService 是KMS港口(currentKeyId, wrap, unwrap 绑定到a { tenant } 上下文,可选 rotate);根密钥永远不会离开KMS。适配器: memoryKeyService (测试和开发人员的机器:版本, rotate, destroy), cloudKeyService 用于 aws-kms (使用SigV4签名的KMS JSON API,加密上下文中的租户, RotateKeyOnDemand), okms (OVHcloud KMS服务密钥;访问证书骑在 fetch 产品通过;旋转=在设置中命名的新键,然后是重新包装作业),然后是注入的 fetch,没有SDK。 tenantVault({ kms, keys, clock, audit }) 每个租户和轮换保留一个KEK,封装在数据库(TenantKeyStore: dbTenantKeyStore 在 storageSchema v2, memoryTenantKeyStore),以及每个对象版本的新AES-256-GCM DEK。 tenantStore(inner, vault, tenantId) 是一个 ObjectStore 下 t/<tenantId>/,将完整键作为关联数据,因此另一个租户或重命名的对象永远不会打开。 rotateTenant + rewrapAll (只有头,没有字节)+ dropOldVersions; rewrapRoot 根变化后的; shredTenant 销毁密钥(墓碑优先,无种族)和每个副本,包括副本和备份,答案 STORAGE_TENANT_SHREDDED. 每个关键事件都是一条审计线。合同: keyServiceContract, tenantKeyStoreContract.
  • 托管提供程序 (ADR-020决定2和7)。 managed 是另一种注册表(管理范围):任何s3兼容的桶(预置OVHcloud与 bhs 和 ca-east-tor、AWS S3、谷歌云存储互操作性模式、DigitalOcean Spaces(用于本地S3服务器的通用)加上KMS (kms: okms, aws-kms,或者 local 仅在开发中(在生产中拒绝),每个密钥都是一个密封的凭证,管理员只输入一次,再也不会看到。 openProvider("managed", …, { managed: { keys, audit, mtlsFetch? } }) 返回 forTenant(tenantId) (一个加密 tenantStore 下 t/<tenantId>/)和探针存储,因此提供程序屏幕的“测试连接”证明桶,KMS和键表端到端; managedResidency 说“加拿大(quamesim);复制:加拿大(安大略省)»从管理员声明。管理员的控制(@krizaka/storage/settings): managedStorageSettings (开/关,允许的提供者 byo/managed/both,配额,最长链接,私有文件夹,设备缓存,垃圾,保留界限;全局和每个租户,由 @krizaka/settings), resolveManagedPolicy (租户>计划>产品>全球;自相矛盾的策略被拒绝), providerAllowed (一扇门) linkSeconds, MANAGED_PRICE_IDS (目录条目;未输入数量)。切换租户的提供商是 moveBatch + readDual 在任何两个存储之间,在真实的S3服务器上用两个桶证明。
  • 数据库中的提供者 (@krizaka/storage/provider-admin, ADR-005切片2)。 storageSchema (表 storage.provider 和 storage.default_provider), dbProviderStore/memoryProviderStore (合同: providerStoreContract), createProviderService:创建(a) draft(密封在信封里的秘密),测试(只有绿色测试验证), setDefault (仅经过验证;之前的默认值变为 retiring), changeKey (候选人先接受测试), disable/retire (当产品仍有物体时,拒绝使用), rotateVaultKey, bootstrap (进口旧的) MEDIA_* 环境曾经是 active 提供者, source: env). 秘密回来了 set/not set 只有;每个更改都被注入 audit 有秘密的领域 changed. moveBatch (get,检查SHA-256, put,回读和比较,然后切换产品事务中的行;返回失败,永远不会切换)和 readDual (行提供程序,然后是退休的)是移动和双读。
  • 用户自己的云 (ADR-005切片4)。 dropboxStore (dropbox 类型,用户范围):仅应用文件夹,上传会话超过150mb,没有签名或公共链接(Dropbox链接超过我们的900 s上限,所以应用程序流)。 pkcePair, dropboxAuthorizeUrl, exchangeDropboxCode, refreshDropboxToken, revokeDropbox 为OAuth 2 PKCE步骤;刷新令牌与任何凭证一样是密封的,并且一个已撤销或过期的令牌可以应答 STORAGE_DISCONNECTED (没有任何移动或删除)。用户自己的S3也是如此 s3 这种在 user:<id> 作用域,并对其端点进行DNS检查。
  • 每个经典云都通过图书馆 (ADR-005修正案,krizaka-ts#235)。 opendalStore (@krizaka/storage/opendal)是Apache OpenDAL的一个适配器,适用于谷歌Drive, OneDrive, Dropbox, Azure Blob, GCS, B2, Swift和WebDAV。只有服务 OPENDAL_SERVICES 开放; fs/memory 需要 allowLocal;类型化端点通过 checkEndpoint 首先是DNS检查。OpenDAL的错误映射到 STORAGE_* (PermissionDenied 在OAuth云上→ STORAGE_DISCONNECTED), readStream(key) 流式传输大文件。 opendal 是一个 可选的对等 (一个本地模块59-82 MB, glibc≥2.38或musl),第一次使用时加载。 CLOUD_CONNECTORS (/node)是用户云表(Dropbox,谷歌Drive, OneDrive:端点,最窄范围,撤销样式)。 startConnection, finishConnection, refreshConnection, revokeConnection 运行Arctic的授权码+ PKCE S256,并且 connectionAccessToken 提要 opendalStore 一个新的访问令牌,并将一个旋转的刷新令牌返回以重新密封。 dropboxStore 它的助手被取代,直到产品移动。
  • 签名。 SigV4是根据AWS发布的向量进行检查的。HTTP区域的签名链接的令牌形式(密钥+路径+过期的SHA-256, url安全的base64)是Yomizaka对Bunny的拉区运行的令牌形式;Bunny的文档没有为它发布预期的输出。
import { createStorage, defineLayout, folderStore } from "@krizaka/storage";
import { limitsOf, readStorageSettings, storeFromSettings } from "@krizaka/storage/settings";

const settings = await readStorageSettings((key) => service.get(key, ctx));
const storage = createStorage({
  store: storeFromSettings(settings, { accessKeyId: env.MEDIA_STORAGE_ACCESS_KEY_ID, secretAccessKey: env.MEDIA_STORAGE_SECRET }, { fetch, clock }),
  layout: defineLayout(["people/", "site/home/"]),
  limits: () => readStorageSettings(read).then(limitsOf),
});
const { key, url } = await storage.upload({ prefix: "people/", name: "ana.jpg", bytes, allow: ["image/jpeg", "image/png"], declaredType: file.type });

apache - 2.0。

版本与发布记录

@krizaka/storage 共发布 14 个版本,首次发布于 2026/10/27;过去 12 个月发布了 14 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.11.1latest2026/11/011 天前
0.11.02026/10/312 天前
0.10.02026/10/313 天前
0.9.02026/10/313 天前
0.8.12026/10/304 天前
0.8.02026/10/295 天前

关于 @krizaka/storage 的常见问题

@krizaka/storage 是什么?

每个Krizaka产品的一个端口后面的文件:放入内容哈希的名称,get, head, delete, list,签名和公共url;为HTTP对象存储和任何s3兼容的桶(签名V4,没有SDK)以及本地文件夹进行注入获取的适配器

如何安装 @krizaka/storage?

在项目目录运行 npm install @krizaka/storage,或使用 pnpm add / yarn add / bun add。

@krizaka/storage 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@krizaka/storage 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@krizaka/storage 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@krizaka/storage 可以商用吗?

@krizaka/storage 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@krizaka/storage 还在维护吗?

最新版本 0.11.1 发布于 2026/11/01(1 天前);至今共发布 14 个版本,其中过去 12 个月发布了 14 个;首次发布于 2026/10/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。